2022-07-13 02:38:29 -04:00
|
|
|
use std::{io::Cursor, sync::Arc, collections::HashMap};
|
2022-06-03 01:25:46 -04:00
|
|
|
|
2022-06-06 04:22:49 -04:00
|
|
|
use rand_core::{RngCore, CryptoRng};
|
|
|
|
|
|
2022-06-28 01:25:26 -04:00
|
|
|
use group::{ff::PrimeField, GroupEncoding};
|
|
|
|
|
|
2022-06-03 01:25:46 -04:00
|
|
|
use crate::{
|
2022-07-13 02:38:29 -04:00
|
|
|
curve::Curve, FrostKeys,
|
2022-06-03 01:25:46 -04:00
|
|
|
algorithm::{Schnorr, Hram},
|
2022-06-24 08:40:14 -04:00
|
|
|
sign::{PreprocessPackage, SignMachine, SignatureMachine, AlgorithmMachine},
|
2022-07-13 02:38:29 -04:00
|
|
|
tests::{clone_without, curve::test_curve, schnorr::test_schnorr, recover}
|
2022-06-03 01:25:46 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
pub struct Vectors {
|
|
|
|
|
pub threshold: u16,
|
|
|
|
|
pub shares: &'static [&'static str],
|
|
|
|
|
pub group_secret: &'static str,
|
|
|
|
|
pub group_key: &'static str,
|
|
|
|
|
|
|
|
|
|
pub msg: &'static str,
|
|
|
|
|
pub included: &'static [u16],
|
|
|
|
|
pub nonces: &'static [[&'static str; 2]],
|
|
|
|
|
pub sig_shares: &'static [&'static str],
|
|
|
|
|
pub sig: String
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-28 00:06:12 -04:00
|
|
|
// Load these vectors into FrostKeys using a custom serialization it'll deserialize
|
|
|
|
|
fn vectors_to_multisig_keys<C: Curve>(vectors: &Vectors) -> HashMap<u16, FrostKeys<C>> {
|
2022-06-03 01:25:46 -04:00
|
|
|
let shares = vectors.shares.iter().map(
|
2022-07-13 02:38:29 -04:00
|
|
|
|secret| C::read_F(&mut Cursor::new(hex::decode(secret).unwrap())).unwrap()
|
2022-06-03 01:25:46 -04:00
|
|
|
).collect::<Vec<_>>();
|
|
|
|
|
let verification_shares = shares.iter().map(
|
2022-06-03 23:22:08 -04:00
|
|
|
|secret| C::GENERATOR * secret
|
2022-06-03 01:25:46 -04:00
|
|
|
).collect::<Vec<_>>();
|
|
|
|
|
|
|
|
|
|
let mut keys = HashMap::new();
|
|
|
|
|
for i in 1 ..= u16::try_from(shares.len()).unwrap() {
|
|
|
|
|
let mut serialized = vec![];
|
2022-07-13 02:38:29 -04:00
|
|
|
serialized.extend(u32::try_from(C::ID.len()).unwrap().to_be_bytes());
|
2022-06-03 23:22:08 -04:00
|
|
|
serialized.extend(C::ID);
|
2022-06-03 01:25:46 -04:00
|
|
|
serialized.extend(vectors.threshold.to_be_bytes());
|
|
|
|
|
serialized.extend(u16::try_from(shares.len()).unwrap().to_be_bytes());
|
|
|
|
|
serialized.extend(i.to_be_bytes());
|
2022-06-28 01:25:26 -04:00
|
|
|
serialized.extend(shares[usize::from(i) - 1].to_repr().as_ref());
|
2022-06-03 01:25:46 -04:00
|
|
|
serialized.extend(&hex::decode(vectors.group_key).unwrap());
|
|
|
|
|
for share in &verification_shares {
|
2022-06-28 01:25:26 -04:00
|
|
|
serialized.extend(share.to_bytes().as_ref());
|
2022-06-03 01:25:46 -04:00
|
|
|
}
|
|
|
|
|
|
2022-07-13 02:38:29 -04:00
|
|
|
let these_keys = FrostKeys::<C>::deserialize(&mut Cursor::new(serialized)).unwrap();
|
2022-06-03 01:25:46 -04:00
|
|
|
assert_eq!(these_keys.params().t(), vectors.threshold);
|
|
|
|
|
assert_eq!(usize::from(these_keys.params().n()), shares.len());
|
|
|
|
|
assert_eq!(these_keys.params().i(), i);
|
|
|
|
|
assert_eq!(these_keys.secret_share(), shares[usize::from(i - 1)]);
|
2022-06-28 01:25:26 -04:00
|
|
|
assert_eq!(&hex::encode(these_keys.group_key().to_bytes().as_ref()), vectors.group_key);
|
2022-06-03 01:25:46 -04:00
|
|
|
keys.insert(i, these_keys);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
keys
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-06 04:22:49 -04:00
|
|
|
pub fn test_with_vectors<
|
|
|
|
|
R: RngCore + CryptoRng,
|
|
|
|
|
C: Curve,
|
|
|
|
|
H: Hram<C>
|
|
|
|
|
>(rng: &mut R, vectors: Vectors) {
|
|
|
|
|
// Do basic tests before trying the vectors
|
|
|
|
|
test_curve::<_, C>(&mut *rng);
|
|
|
|
|
test_schnorr::<_, C>(rng);
|
|
|
|
|
|
|
|
|
|
// Test against the vectors
|
2022-06-03 01:25:46 -04:00
|
|
|
let keys = vectors_to_multisig_keys::<C>(&vectors);
|
2022-07-13 02:38:29 -04:00
|
|
|
let group_key = C::read_G(&mut Cursor::new(hex::decode(vectors.group_key).unwrap())).unwrap();
|
2022-06-03 01:25:46 -04:00
|
|
|
assert_eq!(
|
2022-07-13 02:38:29 -04:00
|
|
|
C::GENERATOR * C::read_F(&mut Cursor::new(hex::decode(vectors.group_secret).unwrap())).unwrap(),
|
2022-06-03 01:25:46 -04:00
|
|
|
group_key
|
|
|
|
|
);
|
|
|
|
|
assert_eq!(
|
|
|
|
|
recover(&keys),
|
2022-07-13 02:38:29 -04:00
|
|
|
C::read_F(&mut Cursor::new(hex::decode(vectors.group_secret).unwrap())).unwrap()
|
2022-06-03 01:25:46 -04:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
let mut machines = vec![];
|
|
|
|
|
for i in vectors.included {
|
|
|
|
|
machines.push((
|
|
|
|
|
*i,
|
|
|
|
|
AlgorithmMachine::new(
|
|
|
|
|
Schnorr::<C, H>::new(),
|
2022-06-05 07:33:15 -04:00
|
|
|
Arc::new(keys[i].clone()),
|
2022-06-03 01:25:46 -04:00
|
|
|
vectors.included.clone()
|
|
|
|
|
).unwrap()
|
|
|
|
|
));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let mut commitments = HashMap::new();
|
|
|
|
|
let mut c = 0;
|
2022-06-24 08:40:14 -04:00
|
|
|
let mut machines = machines.drain(..).map(|(i, machine)| {
|
2022-06-03 01:25:46 -04:00
|
|
|
let nonces = [
|
2022-07-13 02:38:29 -04:00
|
|
|
C::read_F(&mut Cursor::new(hex::decode(vectors.nonces[c][0]).unwrap())).unwrap(),
|
|
|
|
|
C::read_F(&mut Cursor::new(hex::decode(vectors.nonces[c][1]).unwrap())).unwrap()
|
2022-06-03 01:25:46 -04:00
|
|
|
];
|
2022-06-24 08:40:14 -04:00
|
|
|
c += 1;
|
2022-07-13 02:38:29 -04:00
|
|
|
let these_commitments = vec![[C::GENERATOR * nonces[0], C::GENERATOR * nonces[1]]];
|
|
|
|
|
let machine = machine.unsafe_override_preprocess(
|
|
|
|
|
PreprocessPackage {
|
|
|
|
|
nonces: vec![nonces],
|
|
|
|
|
commitments: vec![these_commitments.clone()],
|
|
|
|
|
addendum: vec![]
|
|
|
|
|
}
|
2022-06-03 01:25:46 -04:00
|
|
|
);
|
|
|
|
|
|
2022-07-13 02:38:29 -04:00
|
|
|
commitments.insert(
|
|
|
|
|
i,
|
|
|
|
|
Cursor::new(
|
|
|
|
|
[
|
|
|
|
|
these_commitments[0][0].to_bytes().as_ref(),
|
|
|
|
|
these_commitments[0][1].to_bytes().as_ref()
|
|
|
|
|
].concat().to_vec()
|
|
|
|
|
)
|
|
|
|
|
);
|
2022-06-24 08:40:14 -04:00
|
|
|
(i, machine)
|
|
|
|
|
}).collect::<Vec<_>>();
|
2022-06-03 01:25:46 -04:00
|
|
|
|
|
|
|
|
let mut shares = HashMap::new();
|
|
|
|
|
c = 0;
|
2022-06-24 08:40:14 -04:00
|
|
|
let mut machines = machines.drain(..).map(|(i, machine)| {
|
|
|
|
|
let (machine, share) = machine.sign(
|
2022-07-13 02:38:29 -04:00
|
|
|
clone_without(&commitments, &i),
|
2022-06-24 08:40:14 -04:00
|
|
|
&hex::decode(vectors.msg).unwrap()
|
|
|
|
|
).unwrap();
|
|
|
|
|
|
2022-06-03 01:25:46 -04:00
|
|
|
assert_eq!(share, hex::decode(vectors.sig_shares[c]).unwrap());
|
|
|
|
|
c += 1;
|
|
|
|
|
|
2022-07-13 02:38:29 -04:00
|
|
|
shares.insert(i, Cursor::new(share));
|
2022-06-24 08:40:14 -04:00
|
|
|
(i, machine)
|
|
|
|
|
}).collect::<HashMap<_, _>>();
|
|
|
|
|
|
2022-07-13 02:38:29 -04:00
|
|
|
for (i, machine) in machines.drain() {
|
|
|
|
|
let sig = machine.complete(clone_without(&shares, &i)).unwrap();
|
2022-06-28 01:25:26 -04:00
|
|
|
let mut serialized = sig.R.to_bytes().as_ref().to_vec();
|
|
|
|
|
serialized.extend(sig.s.to_repr().as_ref());
|
2022-06-03 01:25:46 -04:00
|
|
|
assert_eq!(hex::encode(serialized), vectors.sig);
|
|
|
|
|
}
|
|
|
|
|
}
|