mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-09 04:39:24 +00:00
Move FROST to HashMaps
Honestly, the borrowed keys are frustrating, and this probably reduces performance while no longer offering an order when iterating. That said, they enable full u16 indexing and should mildly improve the API. Cleans the Proof of Knowledge handling present in key gen.
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
#![cfg(feature = "multisig")]
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use rand::rngs::OsRng;
|
||||
|
||||
use ff::Field;
|
||||
@@ -7,102 +9,87 @@ use dalek_ff_group::{ED25519_BASEPOINT_TABLE, Scalar};
|
||||
|
||||
pub use frost::{
|
||||
FrostError, MultisigParams, MultisigKeys,
|
||||
key_gen, algorithm::Algorithm, sign::{self, lagrange}
|
||||
lagrange, key_gen, algorithm::Algorithm, sign
|
||||
};
|
||||
|
||||
use monero_serai::frost::Ed25519;
|
||||
|
||||
pub const THRESHOLD: usize = 3;
|
||||
pub const PARTICIPANTS: usize = 5;
|
||||
pub const THRESHOLD: u16 = 3;
|
||||
pub const PARTICIPANTS: u16 = 5;
|
||||
|
||||
pub fn generate_keys() -> (Vec<MultisigKeys<Ed25519>>, Scalar) {
|
||||
let mut params = vec![];
|
||||
let mut machines = vec![];
|
||||
let mut commitments = vec![vec![]];
|
||||
fn clone_without<K: Clone + std::cmp::Eq + std::hash::Hash, V: Clone>(
|
||||
map: &HashMap<K, V>,
|
||||
without: &K
|
||||
) -> HashMap<K, V> {
|
||||
let mut res = map.clone();
|
||||
res.remove(without).unwrap();
|
||||
res
|
||||
}
|
||||
|
||||
pub fn generate_keys() -> (HashMap<u16, MultisigKeys<Ed25519>>, Scalar) {
|
||||
let mut params = HashMap::new();
|
||||
let mut machines = HashMap::new();
|
||||
let mut commitments = HashMap::new();
|
||||
for i in 1 ..= PARTICIPANTS {
|
||||
params.push(
|
||||
params.insert(
|
||||
i,
|
||||
MultisigParams::new(THRESHOLD, PARTICIPANTS, i).unwrap()
|
||||
);
|
||||
machines.push(
|
||||
machines.insert(
|
||||
i,
|
||||
key_gen::StateMachine::<Ed25519>::new(
|
||||
params[i - 1],
|
||||
params[&i],
|
||||
"monero-sign-rs test suite".to_string()
|
||||
)
|
||||
);
|
||||
commitments.push(machines[i - 1].generate_coefficients(&mut OsRng).unwrap());
|
||||
commitments.insert(i, machines.get_mut(&i).unwrap().generate_coefficients(&mut OsRng).unwrap());
|
||||
}
|
||||
|
||||
let mut secret_shares = vec![];
|
||||
for i in 1 ..= PARTICIPANTS {
|
||||
secret_shares.push(
|
||||
machines[i - 1].generate_secret_shares(
|
||||
&mut OsRng,
|
||||
commitments
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(idx, commitments)| if idx == i { vec![] } else { commitments.to_vec() })
|
||||
.collect()
|
||||
).unwrap()
|
||||
let mut secret_shares = HashMap::new();
|
||||
for (i, machine) in machines.iter_mut() {
|
||||
secret_shares.insert(
|
||||
*i,
|
||||
machine.generate_secret_shares(&mut OsRng, clone_without(&commitments, i)).unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
let mut keys = vec![];
|
||||
for i in 1 ..= PARTICIPANTS {
|
||||
let mut our_secret_shares = vec![vec![]];
|
||||
our_secret_shares.extend(
|
||||
secret_shares.iter().map(|shares| shares[i].clone()).collect::<Vec<Vec<u8>>>()
|
||||
);
|
||||
keys.push(machines[i - 1].complete(our_secret_shares).unwrap().clone());
|
||||
let mut keys = HashMap::new();
|
||||
for (i, machine) in machines.iter_mut() {
|
||||
let mut our_secret_shares = HashMap::new();
|
||||
for (l, shares) in &secret_shares {
|
||||
if i == l {
|
||||
continue;
|
||||
}
|
||||
our_secret_shares.insert(*l, shares[&i].clone());
|
||||
}
|
||||
keys.insert(*i, machine.complete(our_secret_shares).unwrap().clone());
|
||||
}
|
||||
|
||||
let mut group_private = Scalar::zero();
|
||||
for i in 1 ..= THRESHOLD {
|
||||
group_private += keys[i - 1].secret_share() * lagrange::<Scalar>(
|
||||
i,
|
||||
&(1 ..= THRESHOLD).collect::<Vec<usize>>()
|
||||
);
|
||||
group_private += keys[&i].secret_share() * lagrange::<Scalar>(i, &(1 ..= THRESHOLD).collect::<Vec<_>>());
|
||||
}
|
||||
assert_eq!(&ED25519_BASEPOINT_TABLE * group_private, keys[0].group_key());
|
||||
assert_eq!(&ED25519_BASEPOINT_TABLE * group_private, keys[&1].group_key());
|
||||
|
||||
(keys, group_private)
|
||||
}
|
||||
|
||||
#[allow(dead_code)] // Currently has some false positive
|
||||
pub fn sign<S, M: sign::StateMachine<Signature = S>>(machines: &mut Vec<M>, msg: &[u8]) -> Vec<S> {
|
||||
assert!(machines.len() >= THRESHOLD);
|
||||
pub fn sign<S, M: sign::StateMachine<Signature = S>>(machines: &mut HashMap<u16, M>, msg: &[u8]) -> Vec<S> {
|
||||
assert!(machines.len() >= THRESHOLD.into());
|
||||
|
||||
let mut commitments = Vec::with_capacity(PARTICIPANTS + 1);
|
||||
commitments.resize(PARTICIPANTS + 1, None);
|
||||
for i in 1 ..= THRESHOLD {
|
||||
commitments[i] = Some(machines[i - 1].preprocess(&mut OsRng).unwrap());
|
||||
let mut commitments = HashMap::new();
|
||||
for (i, machine) in machines.iter_mut() {
|
||||
commitments.insert(*i, machine.preprocess(&mut OsRng).unwrap());
|
||||
}
|
||||
|
||||
let mut shares = Vec::with_capacity(PARTICIPANTS + 1);
|
||||
shares.resize(PARTICIPANTS + 1, None);
|
||||
for i in 1 ..= THRESHOLD {
|
||||
shares[i] = Some(
|
||||
machines[i - 1].sign(
|
||||
&commitments
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(idx, value)| if idx == i { None } else { value.to_owned() })
|
||||
.collect::<Vec<Option<Vec<u8>>>>(),
|
||||
msg
|
||||
).unwrap()
|
||||
);
|
||||
let mut shares = HashMap::new();
|
||||
for (i, machine) in machines.iter_mut() {
|
||||
shares.insert(*i, machine.sign(clone_without(&commitments, i), msg).unwrap());
|
||||
}
|
||||
|
||||
let mut res = Vec::with_capacity(THRESHOLD);
|
||||
for i in 1 ..= THRESHOLD {
|
||||
res.push(
|
||||
machines[i - 1].complete(
|
||||
&shares
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(idx, value)| if idx == i { None } else { value.to_owned() })
|
||||
.collect::<Vec<Option<Vec<u8>>>>()
|
||||
).unwrap()
|
||||
);
|
||||
let mut res = vec![];
|
||||
for (i, machine) in machines.iter_mut() {
|
||||
res.push(machine.complete(clone_without(&shares, i)).unwrap())
|
||||
}
|
||||
res
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user