Create dedicated message structures for FROST messages (#140)

* Create message types for FROST key gen

Taking in reader borrows absolutely wasn't feasible. Now, proper types
which can be read (and then passed directly, without a mutable borrow)
exist for key_gen. sign coming next.

* Move FROST signing to messages, not Readers/Writers/Vec<u8>

Also takes the nonce handling code and makes a dedicated file for it, 
aiming to resolve complex types and make the code more legible by 
replacing its previously inlined state.

* clippy

* Update FROST tests

* read_signature_share

* Update the Monero library to the new FROST packages

* Update processor to latest FROST

* Tweaks to terminology and documentation
This commit is contained in:
Luke Parker
2022-10-25 23:17:25 -05:00
committed by GitHub
parent ccdb834e6e
commit cbceaff678
26 changed files with 874 additions and 591 deletions

View File

@@ -1,5 +1,3 @@
use std::io::Cursor;
use rand_core::{RngCore, CryptoRng};
use group::Group;
@@ -15,7 +13,10 @@ fn key_generation<R: RngCore + CryptoRng, C: Curve>(rng: &mut R) {
// Test serialization of generated keys
fn keys_serialization<R: RngCore + CryptoRng, C: Curve>(rng: &mut R) {
for (_, keys) in core_gen::<_, C>(rng) {
assert_eq!(&FrostCore::<C>::deserialize(&mut Cursor::new(keys.serialize())).unwrap(), &keys);
assert_eq!(
&FrostCore::<C>::deserialize::<&[u8]>(&mut keys.serialize().as_ref()).unwrap(),
&keys
);
}
}

View File

@@ -1,5 +1,3 @@
use std::io::Cursor;
use rand_core::OsRng;
use crate::{
@@ -13,32 +11,31 @@ fn ed448_8032_vector() {
let context = hex::decode("666f6f").unwrap();
#[allow(non_snake_case)]
let A = Ed448::read_G(&mut Cursor::new(
hex::decode(
let A = Ed448::read_G::<&[u8]>(
&mut hex::decode(
"43ba28f430cdff456ae531545f7ecd0ac834a55d9358c0372bfa0c6c".to_owned() +
"6798c0866aea01eb00742802b8438ea4cb82169c235160627b4c3a94" +
"80",
)
.unwrap(),
))
.unwrap()
.as_ref(),
)
.unwrap();
let msg = hex::decode("03").unwrap();
let mut sig = Cursor::new(
hex::decode(
"d4f8f6131770dd46f40867d6fd5d5055de43541f8c5e35abbcd001b3".to_owned() +
"2a89f7d2151f7647f11d8ca2ae279fb842d607217fce6e042f6815ea" +
"00" +
"0c85741de5c8da1144a6a1aba7f96de42505d7a7298524fda538fccb" +
"bb754f578c1cad10d54d0d5428407e85dcbc98a49155c13764e66c3c" +
"00",
)
.unwrap(),
);
let sig = hex::decode(
"d4f8f6131770dd46f40867d6fd5d5055de43541f8c5e35abbcd001b3".to_owned() +
"2a89f7d2151f7647f11d8ca2ae279fb842d607217fce6e042f6815ea" +
"00" +
"0c85741de5c8da1144a6a1aba7f96de42505d7a7298524fda538fccb" +
"bb754f578c1cad10d54d0d5428407e85dcbc98a49155c13764e66c3c" +
"00",
)
.unwrap();
#[allow(non_snake_case)]
let R = Ed448::read_G(&mut sig).unwrap();
let s = Ed448::read_F(&mut sig).unwrap();
let R = Ed448::read_G::<&[u8]>(&mut sig.as_ref()).unwrap();
let s = Ed448::read_F::<&[u8]>(&mut &sig[57 ..]).unwrap();
assert!(verify(
A,

View File

@@ -1,4 +1,4 @@
use std::{io::Cursor, collections::HashMap};
use std::collections::HashMap;
use rand_core::{RngCore, CryptoRng};
@@ -6,9 +6,9 @@ use group::ff::Field;
use crate::{
Curve, FrostParams, FrostCore, FrostKeys, lagrange,
key_gen::KeyGenMachine,
key_gen::{SecretShare, Commitments as KGCommitments, KeyGenMachine},
algorithm::Algorithm,
sign::{PreprocessMachine, SignMachine, SignatureMachine, AlgorithmMachine},
sign::{Writable, PreprocessMachine, SignMachine, SignatureMachine, AlgorithmMachine},
};
/// Curve tests.
@@ -50,15 +50,32 @@ pub fn core_gen<R: RngCore + CryptoRng, C: Curve>(rng: &mut R) -> HashMap<u16, F
);
let (machine, these_commitments) = machine.generate_coefficients(rng);
machines.insert(i, machine);
commitments.insert(i, Cursor::new(these_commitments));
commitments.insert(i, {
let mut buf = vec![];
these_commitments.write(&mut buf).unwrap();
KGCommitments::read::<&[u8]>(
&mut buf.as_ref(),
FrostParams { t: THRESHOLD, n: PARTICIPANTS, i: 1 },
)
.unwrap()
});
}
let mut secret_shares = HashMap::new();
let mut machines = machines
.drain()
.map(|(l, machine)| {
let (machine, shares) =
let (machine, mut shares) =
machine.generate_secret_shares(rng, clone_without(&commitments, &l)).unwrap();
let shares = shares
.drain()
.map(|(l, share)| {
let mut buf = vec![];
share.write(&mut buf).unwrap();
(l, SecretShare::<C>::read::<&[u8]>(&mut buf.as_ref()).unwrap())
})
.collect::<HashMap<_, _>>();
secret_shares.insert(l, shares);
(l, machine)
})
@@ -74,7 +91,7 @@ pub fn core_gen<R: RngCore + CryptoRng, C: Curve>(rng: &mut R) -> HashMap<u16, F
if i == *l {
continue;
}
our_secret_shares.insert(*l, Cursor::new(shares[&i].clone()));
our_secret_shares.insert(*l, shares[&i].clone());
}
let these_keys = machine.complete(rng, our_secret_shares).unwrap();
@@ -154,7 +171,11 @@ pub fn sign<R: RngCore + CryptoRng, M: PreprocessMachine>(
.drain()
.map(|(i, machine)| {
let (machine, preprocess) = machine.preprocess(rng);
commitments.insert(i, Cursor::new(preprocess));
commitments.insert(i, {
let mut buf = vec![];
preprocess.write(&mut buf).unwrap();
machine.read_preprocess::<&[u8]>(&mut buf.as_ref()).unwrap()
});
(i, machine)
})
.collect::<HashMap<_, _>>();
@@ -164,7 +185,11 @@ pub fn sign<R: RngCore + CryptoRng, M: PreprocessMachine>(
.drain()
.map(|(i, machine)| {
let (machine, share) = machine.sign(clone_without(&commitments, &i), msg).unwrap();
shares.insert(i, Cursor::new(share));
shares.insert(i, {
let mut buf = vec![];
share.write(&mut buf).unwrap();
machine.read_share::<&[u8]>(&mut buf.as_ref()).unwrap()
});
(i, machine)
})
.collect::<HashMap<_, _>>();

View File

@@ -1,4 +1,4 @@
use std::{io::Cursor, collections::HashMap};
use std::collections::HashMap;
#[cfg(test)]
use std::str::FromStr;
@@ -10,7 +10,10 @@ use crate::{
curve::Curve,
FrostCore, FrostKeys,
algorithm::{Schnorr, Hram},
sign::{PreprocessPackage, SignMachine, SignatureMachine, AlgorithmMachine},
sign::{
Nonce, GeneratorCommitments, NonceCommitments, Commitments, Writable, Preprocess,
PreprocessData, SignMachine, SignatureMachine, AlgorithmMachine,
},
tests::{
clone_without, curve::test_curve, schnorr::test_schnorr, promote::test_promotion, recover,
},
@@ -78,12 +81,13 @@ fn vectors_to_multisig_keys<C: Curve>(vectors: &Vectors) -> HashMap<u16, FrostKe
let shares = vectors
.shares
.iter()
.map(|secret| C::read_F(&mut Cursor::new(hex::decode(secret).unwrap())).unwrap())
.map(|secret| C::read_F::<&[u8]>(&mut hex::decode(secret).unwrap().as_ref()).unwrap())
.collect::<Vec<_>>();
let verification_shares = shares.iter().map(|secret| C::generator() * secret).collect::<Vec<_>>();
let mut keys = HashMap::new();
for i in 1 ..= u16::try_from(shares.len()).unwrap() {
// Manually re-implement the serialization for FrostCore to import this data
let mut serialized = vec![];
serialized.extend(u32::try_from(C::ID.len()).unwrap().to_be_bytes());
serialized.extend(C::ID);
@@ -95,7 +99,7 @@ fn vectors_to_multisig_keys<C: Curve>(vectors: &Vectors) -> HashMap<u16, FrostKe
serialized.extend(share.to_bytes().as_ref());
}
let these_keys = FrostCore::<C>::deserialize(&mut Cursor::new(serialized)).unwrap();
let these_keys = FrostCore::<C>::deserialize::<&[u8]>(&mut serialized.as_ref()).unwrap();
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);
@@ -118,8 +122,10 @@ pub fn test_with_vectors<R: RngCore + CryptoRng, C: Curve, H: Hram<C>>(
// Test against the vectors
let keys = vectors_to_multisig_keys::<C>(&vectors);
let group_key = C::read_G(&mut Cursor::new(hex::decode(&vectors.group_key).unwrap())).unwrap();
let secret = C::read_F(&mut Cursor::new(hex::decode(&vectors.group_secret).unwrap())).unwrap();
let group_key =
C::read_G::<&[u8]>(&mut hex::decode(&vectors.group_key).unwrap().as_ref()).unwrap();
let secret =
C::read_F::<&[u8]>(&mut hex::decode(&vectors.group_secret).unwrap().as_ref()).unwrap();
assert_eq!(C::generator() * secret, group_key);
assert_eq!(recover(&keys), secret);
@@ -142,27 +148,36 @@ pub fn test_with_vectors<R: RngCore + CryptoRng, C: Curve, H: Hram<C>>(
.drain(..)
.map(|(i, machine)| {
let nonces = [
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(),
C::read_F::<&[u8]>(&mut hex::decode(&vectors.nonces[c][0]).unwrap().as_ref()).unwrap(),
C::read_F::<&[u8]>(&mut hex::decode(&vectors.nonces[c][1]).unwrap().as_ref()).unwrap(),
];
c += 1;
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![],
let these_commitments = [C::generator() * nonces[0], C::generator() * nonces[1]];
let machine = machine.unsafe_override_preprocess(PreprocessData {
nonces: vec![Nonce(nonces)],
preprocess: Preprocess {
commitments: Commitments {
nonces: vec![NonceCommitments {
generators: vec![GeneratorCommitments(these_commitments)],
dleqs: None,
}],
},
addendum: (),
},
});
commitments.insert(
*i,
Cursor::new(
[
these_commitments[0][0].to_bytes().as_ref(),
these_commitments[0][1].to_bytes().as_ref(),
]
.concat()
.to_vec(),
),
machine
.read_preprocess::<&[u8]>(
&mut [
these_commitments[0].to_bytes().as_ref(),
these_commitments[1].to_bytes().as_ref(),
]
.concat()
.as_ref(),
)
.unwrap(),
);
(i, machine)
})
@@ -176,10 +191,15 @@ pub fn test_with_vectors<R: RngCore + CryptoRng, C: Curve, H: Hram<C>>(
let (machine, share) =
machine.sign(clone_without(&commitments, i), &hex::decode(&vectors.msg).unwrap()).unwrap();
let share = {
let mut buf = vec![];
share.write(&mut buf).unwrap();
buf
};
assert_eq!(share, hex::decode(&vectors.sig_shares[c]).unwrap());
c += 1;
shares.insert(*i, Cursor::new(share));
shares.insert(*i, machine.read_share::<&[u8]>(&mut share.as_ref()).unwrap());
(i, machine)
})
.collect::<HashMap<_, _>>();