mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-08 12:19:24 +00:00
Update to FROST v11
Ensures random functions never return zero. This, combined with a check commitments aren't 0, causes no serialized elements to be 0. Also directly reads their vectors.
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
use std::{io::Cursor, collections::HashMap};
|
||||
#[cfg(test)]
|
||||
use std::str::FromStr;
|
||||
|
||||
use rand_core::{RngCore, CryptoRng};
|
||||
|
||||
@@ -16,17 +18,61 @@ use crate::{
|
||||
|
||||
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 group_secret: String,
|
||||
pub group_key: String,
|
||||
pub shares: Vec<String>,
|
||||
|
||||
pub msg: String,
|
||||
pub included: Vec<u16>,
|
||||
pub nonces: Vec<[String; 2]>,
|
||||
|
||||
pub sig_shares: Vec<String>,
|
||||
|
||||
pub sig: String,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl From<serde_json::Value> for Vectors {
|
||||
fn from(value: serde_json::Value) -> Vectors {
|
||||
let to_str = |value: &serde_json::Value| dbg!(value).as_str().unwrap().to_string();
|
||||
Vectors {
|
||||
threshold: u16::from_str(value["config"]["NUM_PARTICIPANTS"].as_str().unwrap()).unwrap(),
|
||||
|
||||
group_secret: to_str(&value["inputs"]["group_secret_key"]),
|
||||
group_key: to_str(&value["inputs"]["group_public_key"]),
|
||||
shares: value["inputs"]["participants"]
|
||||
.as_object()
|
||||
.unwrap()
|
||||
.values()
|
||||
.map(|share| to_str(&share["participant_share"]))
|
||||
.collect(),
|
||||
|
||||
msg: to_str(&value["inputs"]["message"]),
|
||||
included: to_str(&value["round_one_outputs"]["participant_list"])
|
||||
.split(",")
|
||||
.map(u16::from_str)
|
||||
.collect::<Result<_, _>>()
|
||||
.unwrap(),
|
||||
nonces: value["round_one_outputs"]["participants"]
|
||||
.as_object()
|
||||
.unwrap()
|
||||
.values()
|
||||
.map(|value| [to_str(&value["hiding_nonce"]), to_str(&value["binding_nonce"])])
|
||||
.collect(),
|
||||
|
||||
sig_shares: value["round_two_outputs"]["participants"]
|
||||
.as_object()
|
||||
.unwrap()
|
||||
.values()
|
||||
.map(|value| to_str(&value["sig_share"]))
|
||||
.collect(),
|
||||
|
||||
sig: to_str(&value["final_output"]["sig"]),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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>> {
|
||||
let shares = vectors
|
||||
@@ -54,7 +100,7 @@ fn vectors_to_multisig_keys<C: Curve>(vectors: &Vectors) -> HashMap<u16, FrostKe
|
||||
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)]);
|
||||
assert_eq!(&hex::encode(these_keys.group_key().to_bytes().as_ref()), vectors.group_key);
|
||||
assert_eq!(hex::encode(these_keys.group_key().to_bytes().as_ref()), vectors.group_key);
|
||||
keys.insert(i, FrostKeys::new(these_keys));
|
||||
}
|
||||
|
||||
@@ -67,26 +113,20 @@ pub fn test_with_vectors<R: RngCore + CryptoRng, C: Curve, H: Hram<C>>(
|
||||
) {
|
||||
// Do basic tests before trying the vectors
|
||||
test_curve::<_, C>(&mut *rng);
|
||||
test_schnorr::<_, C>(rng);
|
||||
test_schnorr::<_, C>(&mut *rng);
|
||||
test_promotion::<_, C>(rng);
|
||||
|
||||
// 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();
|
||||
assert_eq!(
|
||||
C::generator() *
|
||||
C::read_F(&mut Cursor::new(hex::decode(vectors.group_secret).unwrap())).unwrap(),
|
||||
group_key
|
||||
);
|
||||
assert_eq!(
|
||||
recover(&keys),
|
||||
C::read_F(&mut Cursor::new(hex::decode(vectors.group_secret).unwrap())).unwrap()
|
||||
);
|
||||
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();
|
||||
assert_eq!(C::generator() * secret, group_key);
|
||||
assert_eq!(recover(&keys), secret);
|
||||
|
||||
let mut machines = vec![];
|
||||
for i in vectors.included {
|
||||
for i in &vectors.included {
|
||||
machines.push((
|
||||
*i,
|
||||
i,
|
||||
AlgorithmMachine::new(
|
||||
Schnorr::<C, H>::new(),
|
||||
keys[i].clone(),
|
||||
@@ -102,8 +142,8 @@ 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(&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 += 1;
|
||||
let these_commitments = vec![[C::generator() * nonces[0], C::generator() * nonces[1]]];
|
||||
@@ -114,7 +154,7 @@ pub fn test_with_vectors<R: RngCore + CryptoRng, C: Curve, H: Hram<C>>(
|
||||
});
|
||||
|
||||
commitments.insert(
|
||||
i,
|
||||
*i,
|
||||
Cursor::new(
|
||||
[
|
||||
these_commitments[0][0].to_bytes().as_ref(),
|
||||
@@ -134,18 +174,18 @@ pub fn test_with_vectors<R: RngCore + CryptoRng, C: Curve, H: Hram<C>>(
|
||||
.drain(..)
|
||||
.map(|(i, machine)| {
|
||||
let (machine, share) =
|
||||
machine.sign(clone_without(&commitments, &i), &hex::decode(vectors.msg).unwrap()).unwrap();
|
||||
machine.sign(clone_without(&commitments, i), &hex::decode(&vectors.msg).unwrap()).unwrap();
|
||||
|
||||
assert_eq!(share, hex::decode(vectors.sig_shares[c]).unwrap());
|
||||
assert_eq!(share, hex::decode(&vectors.sig_shares[c]).unwrap());
|
||||
c += 1;
|
||||
|
||||
shares.insert(i, Cursor::new(share));
|
||||
shares.insert(*i, Cursor::new(share));
|
||||
(i, machine)
|
||||
})
|
||||
.collect::<HashMap<_, _>>();
|
||||
|
||||
for (i, machine) in machines.drain() {
|
||||
let sig = machine.complete(clone_without(&shares, &i)).unwrap();
|
||||
let sig = machine.complete(clone_without(&shares, i)).unwrap();
|
||||
let mut serialized = sig.R.to_bytes().as_ref().to_vec();
|
||||
serialized.extend(sig.s.to_repr().as_ref());
|
||||
assert_eq!(hex::encode(serialized), vectors.sig);
|
||||
|
||||
Reference in New Issue
Block a user