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:
Luke Parker
2022-05-24 21:41:14 -04:00
parent 5ff65bd268
commit d10c6e16dc
12 changed files with 585 additions and 747 deletions

View File

@@ -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
}