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:
Luke Parker 2022-10-13 00:38:36 -04:00
parent b334c96906
commit a0a54eb0de
No known key found for this signature in database
GPG key ID: F9F1386DB1E119B6
19 changed files with 491 additions and 257 deletions

2
Cargo.lock generated
View file

@ -4578,8 +4578,10 @@ dependencies = [
"multiexp",
"p256",
"rand_core 0.6.4",
"serde_json",
"sha2 0.10.6",
"sha3 0.10.5",
"subtle",
"thiserror",
"zeroize",
]

View file

@ -18,6 +18,7 @@ thiserror = "1"
rand_core = "0.6"
zeroize = { version = "1.5", features = ["zeroize_derive"] }
subtle = "2"
hex = "0.4"
@ -44,6 +45,7 @@ dleq = { path = "../dleq", version = "0.1", features = ["serialize"] }
[dev-dependencies]
sha2 = "0.10"
dalek-ff-group = { path = "../dalek-ff-group", version = "^0.1.2" }
serde_json = "1"
[features]
dalek = ["sha2", "dalek-ff-group"]

View file

@ -74,7 +74,7 @@ dalek_curve!(
IetfRistrettoHram,
RistrettoPoint,
b"ristretto",
b"FROST-RISTRETTO255-SHA512-v10",
b"FROST-RISTRETTO255-SHA512-v11",
b"chal",
);
@ -85,6 +85,6 @@ dalek_curve!(
IetfEd25519Hram,
EdwardsPoint,
b"edwards25519",
b"FROST-ED25519-SHA512-v10",
b"FROST-ED25519-SHA512-v11",
b"",
);

View file

@ -7,7 +7,7 @@ use minimal_ed448::{scalar::Scalar, point::Point};
use crate::{curve::Curve, algorithm::Hram};
const CONTEXT: &[u8] = b"FROST-ED448-SHAKE256-v10";
const CONTEXT: &[u8] = b"FROST-ED448-SHAKE256-v11";
#[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize)]
pub struct Ed448;
@ -53,8 +53,8 @@ impl Ietf8032Ed448Hram {
}
#[derive(Copy, Clone)]
pub struct NonIetfEd448Hram;
impl Hram<Ed448> for NonIetfEd448Hram {
pub struct IetfEd448Hram;
impl Hram<Ed448> for IetfEd448Hram {
#[allow(non_snake_case)]
fn hram(R: &Point, A: &Point, m: &[u8]) -> Scalar {
Ietf8032Ed448Hram::hram(&[], R, A, m)

View file

@ -92,7 +92,7 @@ macro_rules! kp_curve {
}
#[cfg(feature = "p256")]
kp_curve!("p256", p256, P256, IetfP256Hram, b"P-256", b"FROST-P256-SHA256-v10");
kp_curve!("p256", p256, P256, IetfP256Hram, b"P-256", b"FROST-P256-SHA256-v11");
#[cfg(feature = "secp256k1")]
kp_curve!(
@ -101,5 +101,5 @@ kp_curve!(
Secp256k1,
IetfSecp256k1Hram,
b"secp256k1",
b"FROST-secp256k1-SHA256-v10"
b"FROST-secp256k1-SHA256-v11"
);

View file

@ -6,8 +6,9 @@ use thiserror::Error;
use rand_core::{RngCore, CryptoRng};
use zeroize::Zeroize;
use subtle::ConstantTimeEq;
use ff::{PrimeField, PrimeFieldBits};
use ff::{Field, PrimeField, PrimeFieldBits};
use group::{Group, GroupOps, GroupEncoding, prime::PrimeGroup};
#[cfg(any(test, feature = "dalek"))]
@ -27,7 +28,7 @@ pub use kp256::{P256, IetfP256Hram};
#[cfg(feature = "ed448")]
mod ed448;
#[cfg(feature = "ed448")]
pub use ed448::{Ed448, Ietf8032Ed448Hram, NonIetfEd448Hram};
pub use ed448::{Ed448, Ietf8032Ed448Hram, IetfEd448Hram};
/// Set of errors for curve-related operations, namely encoding and decoding.
#[derive(Clone, Error, Debug)]
@ -49,7 +50,7 @@ pub trait Curve: Clone + Copy + PartialEq + Eq + Debug + Zeroize {
// This is available via G::Scalar yet `C::G::Scalar` is ambiguous, forcing horrific accesses
type F: PrimeField + PrimeFieldBits + Zeroize;
/// Group element type.
type G: Group<Scalar = Self::F> + GroupOps + PrimeGroup + Zeroize;
type G: Group<Scalar = Self::F> + GroupOps + PrimeGroup + Zeroize + ConstantTimeEq;
/// ID for this curve.
const ID: &'static [u8];
@ -81,6 +82,16 @@ pub trait Curve: Clone + Copy + PartialEq + Eq + Debug + Zeroize {
Self::hash_to_F(b"rho", binding)
}
#[allow(non_snake_case)]
fn random_F<R: RngCore + CryptoRng>(rng: &mut R) -> Self::F {
let mut res;
while {
res = Self::F::random(&mut *rng);
res.ct_eq(&Self::F::zero()).into()
} {}
res
}
/// Securely generate a random nonce. H3 from the IETF draft.
fn random_nonce<R: RngCore + CryptoRng>(mut secret: Self::F, rng: &mut R) -> Self::F {
let mut seed = vec![0; 32];
@ -89,12 +100,18 @@ pub trait Curve: Clone + Copy + PartialEq + Eq + Debug + Zeroize {
let mut repr = secret.to_repr();
secret.zeroize();
seed.extend(repr.as_ref());
let mut res;
while {
seed.extend(repr.as_ref());
res = Self::hash_to_F(b"nonce", &seed);
res.ct_eq(&Self::F::zero()).into()
} {
rng.fill_bytes(&mut seed);
}
for i in repr.as_mut() {
i.zeroize();
}
let res = Self::hash_to_F(b"nonce", &seed);
seed.zeroize();
res
}

View file

@ -48,7 +48,7 @@ fn generate_key_r1<R: RngCore + CryptoRng, C: Curve>(
for i in 0 .. t {
// Step 1: Generate t random values to form a polynomial with
coefficients.push(C::F::random(&mut *rng));
coefficients.push(C::random_F(&mut *rng));
// Step 3: Generate public commitments
commitments.push(C::generator() * coefficients[i]);
// Serialize them for publication
@ -56,7 +56,7 @@ fn generate_key_r1<R: RngCore + CryptoRng, C: Curve>(
}
// Step 2: Provide a proof of knowledge
let mut r = C::F::random(rng);
let mut r = C::random_F(rng);
serialized.extend(
schnorr::sign::<C>(
coefficients[0],

View file

@ -7,6 +7,7 @@ use std::{
use rand_core::{RngCore, CryptoRng};
use zeroize::{Zeroize, ZeroizeOnDrop};
use subtle::ConstantTimeEq;
use transcript::Transcript;
@ -97,8 +98,6 @@ impl<C: Curve> Drop for PreprocessPackage<C> {
}
impl<C: Curve> ZeroizeOnDrop for PreprocessPackage<C> {}
// This library unifies the preprocessing step with signing due to security concerns and to provide
// a simpler UX
fn preprocess<R: RngCore + CryptoRng, C: Curve, A: Algorithm<C>>(
rng: &mut R,
params: &mut Params<C, A>,
@ -202,14 +201,20 @@ fn sign_with_share<Re: Read, C: Curve, A: Algorithm<C>>(
// consistency. While this is suboptimal, it maintains IETF compliance, and Algorithm is
// documented accordingly
let transcript = |t: &mut A::Transcript, commitments: [C::G; 2]| {
if commitments[0].ct_eq(&C::G::identity()).into() ||
commitments[1].ct_eq(&C::G::identity()).into()
{
Err(FrostError::InvalidCommitment(*l))?;
}
t.append_message(b"commitment_D", commitments[0].to_bytes().as_ref());
t.append_message(b"commitment_E", commitments[1].to_bytes().as_ref());
Ok(())
};
if *l == params.keys.params().i {
for nonce_commitments in &our_preprocess.commitments {
for commitments in nonce_commitments {
transcript(params.algorithm.transcript(), *commitments);
transcript(params.algorithm.transcript(), *commitments).unwrap();
}
}
@ -227,7 +232,7 @@ fn sign_with_share<Re: Read, C: Curve, A: Algorithm<C>>(
commitments.push(Vec::with_capacity(nonce_generators.len()));
for _ in 0 .. nonce_generators.len() {
commitments[n].push(read_D_E::<_, C>(&mut cursor, *l)?);
transcript(params.algorithm.transcript(), commitments[n][commitments[n].len() - 1]);
transcript(params.algorithm.transcript(), commitments[n][commitments[n].len() - 1])?;
}
if nonce_generators.len() >= 2 {

View file

@ -2,7 +2,7 @@ use std::io::Cursor;
use rand_core::{RngCore, CryptoRng};
use group::{ff::Field, Group};
use group::Group;
use crate::{Curve, FrostCore, tests::core_gen};
@ -27,7 +27,7 @@ pub fn test_multiexp<R: RngCore + CryptoRng, C: Curve>(rng: &mut R) {
let mut sum = C::G::identity();
for _ in 0 .. 10 {
for _ in 0 .. 100 {
pairs.push((C::F::random(&mut *rng), C::generator() * C::F::random(&mut *rng)));
pairs.push((C::random_F(&mut *rng), C::generator() * C::random_F(&mut *rng)));
sum += pairs[pairs.len() - 1].1 * pairs[pairs.len() - 1].0;
}
assert_eq!(multiexp::multiexp(&pairs), sum);

View file

@ -10,35 +10,12 @@ use crate::{
fn ristretto_vectors() {
test_with_vectors::<_, curve::Ristretto, curve::IetfRistrettoHram>(
&mut OsRng,
Vectors {
threshold: 2,
shares: &[
"5c3430d391552f6e60ecdc093ff9f6f4488756aa6cebdbad75a768010b8f830e",
"b06fc5eac20b4f6e1b271d9df2343d843e1e1fb03c4cbb673f2872d459ce6f01",
"f17e505f0e2581c6acfe54d3846a622834b5e7b50cad9a2109a97ba7a80d5c04",
],
group_secret: "1b25a55e463cfd15cf14a5d3acc3d15053f08da49c8afcf3ab265f2ebc4f970b",
group_key: "e2a62f39eede11269e3bd5a7d97554f5ca384f9f6d3dd9c3c0d05083c7254f57",
msg: "74657374",
included: &[1, 3],
nonces: &[
[
"de3e8f526dcb51a1b9b48cc284aeca27c385aa3ba1a92a0c8440d51e1a1d2f00",
"fa8dca5ec7a05d5a7b782be847ba3dde1509de1dbcf0569fc980cff795db5404",
],
[
"e07061a9ab6735de9a75b0c64f086c5b999894611d0cdc03f85c4e87c8aae602",
"38b17578e8e6ad4077071ce6b0bf9cb85ac35fee7868dcb6d9bfa97f0e153e0e",
],
],
sig_shares: &[
"a5f046916a6a111672111e47f9825586e1188da8a0f3b7c61f2b6b432c636e07",
"4c175c7e43bd197980c2021774036eb288f54179f079fbf21b7d2f9f52846401",
],
sig: "94b11def3f919503c3544452ad2a59f198f64cc323bd758bb1c65b42032a7473".to_owned() +
"f107a30fae272b8ff2d3205e6d86c3386a0ecf21916db3b93ba89ae27ee7d208",
},
Vectors::from(
serde_json::from_str::<serde_json::Value>(include_str!(
"vectors/frost-ristretto255-sha512.json"
))
.unwrap(),
),
);
}
@ -47,34 +24,9 @@ fn ristretto_vectors() {
fn ed25519_vectors() {
test_with_vectors::<_, curve::Ed25519, curve::IetfEd25519Hram>(
&mut OsRng,
Vectors {
threshold: 2,
shares: &[
"929dcc590407aae7d388761cddb0c0db6f5627aea8e217f4a033f2ec83d93509",
"a91e66e012e4364ac9aaa405fcafd370402d9859f7b6685c07eed76bf409e80d",
"d3cb090a075eb154e82fdb4b3cb507f110040905468bb9c46da8bdea643a9a02",
],
group_secret: "7b1c33d3f5291d85de664833beb1ad469f7fb6025a0ec78b3a790c6e13a98304",
group_key: "15d21ccd7ee42959562fc8aa63224c8851fb3ec85a3faf66040d380fb9738673",
msg: "74657374",
included: &[1, 3],
nonces: &[
[
"4e64f59e90a3b9cdce346fae68eb0e459532c8ca1ad59a566c3ee2c67bf0100b",
"470c660895c6db164ee6564120eec71023fa5297f09c663bb8171646c5632d00",
],
[
"6fc516495dbb364b807cdd0c2e5e3f58aa4914a53fed33cc340033979bb07304",
"0837e770a88147d41ff39138ca23b35d6cf303a4f148294755ede4b7e760d701",
],
],
sig_shares: &[
"3f2eb12735e5b39da97e884a6caadf6bb83f1efcec709d6f66333d0d67ebe707",
"79e572b8632fbb928519dd2eff793de8784a56d582ae48c807d39b0dc5b93509",
],
sig: "e31e69a4e10d5ca2307c4a0d12cd86e3fceee550e55cb5b3f47c7ad6dbb38884".to_owned() +
"cb3f2e837eb15cd858fb6dd68c2a3e3f318a74d16f1fe6376e06d91a2ca51d01",
},
Vectors::from(
serde_json::from_str::<serde_json::Value>(include_str!("vectors/frost-ed25519-sha512.json"))
.unwrap(),
),
);
}

View file

@ -3,7 +3,7 @@ use std::io::Cursor;
use rand_core::OsRng;
use crate::{
curve::{Curve, Ed448, Ietf8032Ed448Hram, NonIetfEd448Hram},
curve::{Curve, Ed448, Ietf8032Ed448Hram, IetfEd448Hram},
schnorr::{SchnorrSignature, verify},
tests::vectors::{Vectors, test_with_vectors},
};
@ -48,88 +48,12 @@ fn ed448_8032_vector() {
}
#[test]
fn ed448_non_ietf() {
test_with_vectors::<_, Ed448, NonIetfEd448Hram>(
fn ed448_vectors() {
test_with_vectors::<_, Ed448, IetfEd448Hram>(
&mut OsRng,
Vectors {
threshold: 2,
shares: &[
concat!(
"4a2b2f5858a932ad3d3b18bd16e76ced3070d72fd79ae4402df201f5",
"25e754716a1bc1b87a502297f2a99d89ea054e0018eb55d39562fd01",
"00"
),
concat!(
"2503d56c4f516444a45b080182b8a2ebbe4d9b2ab509f25308c88c0e",
"a7ccdc44e2ef4fc4f63403a11b116372438a1e287265cadeff1fcb07",
"00"
),
concat!(
"00db7a8146f995db0a7cf844ed89d8e94c2b5f259378ff66e39d1728",
"28b264185ac4decf7219e4aa4478285b9c0eef4fccdf3eea69dd980d",
"00"
),
],
group_secret: concat!(
"6298e1eef3c379392caaed061ed8a31033c9e9e3420726f23b404158",
"a401cd9df24632adfe6b418dc942d8a091817dd8bd70e1c72ba52f3c",
"00"
),
group_key: concat!(
"3832f82fda00ff5365b0376df705675b63d2a93c24c6e81d40801ba2",
"65632be10f443f95968fadb70d10786827f30dc001c8d0f9b7c1d1b0",
"00"
),
msg: "74657374",
included: &[1, 3],
nonces: &[
[
concat!(
"06f2e15b05d29a50f0686a890259f4dcf66147a80809ed9e50926f5f",
"173fe23a0627561efa003724dc270effc47a30bc4d80aba30725401d",
"00"
),
concat!(
"e0482e611c34f191d1c13a09bc8bbf4bda68db4de32aa7908849b02b",
"a912cfba46c805e2d8560ab9437e343e1dde6b481a2bae527e111b2c",
"00"
),
],
[
concat!(
"295c56447c070157e6bc3c83ed2afca194569e07d0ad27d28a40dec2",
"c4107c07d507db20da1be62ea6976b8e53ab5d26e225c663f2e71511",
"00"
),
concat!(
"b97303a6c5ab12b6ad310834361033a19d99dfdf93109da721da35c3",
"abbc5f29df33b3402692bef9f005bb8ea00af5ba20cc688360fd8831",
"00"
),
],
],
sig_shares: &[
concat!(
"5b65641e27007ec71509c6af5cf8527eb01fee5b2b07d8beecf6646e",
"b7e7e27d85119b74f895b56ba7561834a1b0c42639b122160a0b6208",
"00"
),
concat!(
"821b7ac04d7c01d970b0b3ba4ae8f737a5bac934aed1600b1cad7601",
"1c240629bce6a4671a1b6f572cec708ec161a72a5ca04e50eabdfc25",
"00"
),
],
sig: concat!(
"c7ad7ad9fcfeef9d1492361ba641400bd3a3c8335a83cdffbdd8867d",
"2849bb4419dcc3e594baa731081a1a00cd3dea9219a81ecba4646e95",
"00",
"dd80dede747c7fa086b9796aa7e04ab655dab790d9d838ca08a4db6f",
"d30be9a641f83fdc12b124c3d34289c262126c5195517166f4c85e2e",
"00"
)
.to_string(),
},
Vectors::from(
serde_json::from_str::<serde_json::Value>(include_str!("vectors/frost-ed448-shake256.json"))
.unwrap(),
),
);
}

View file

@ -13,35 +13,12 @@ use crate::curve::{P256, IetfP256Hram};
fn secp256k1_vectors() {
test_with_vectors::<_, Secp256k1, IetfSecp256k1Hram>(
&mut OsRng,
Vectors {
threshold: 2,
shares: &[
"08f89ffe80ac94dcb920c26f3f46140bfc7f95b493f8310f5fc1ea2b01f4254c",
"04f0feac2edcedc6ce1253b7fab8c86b856a797f44d83d82a385554e6e401984",
"00e95d59dd0d46b0e303e500b62b7ccb0e555d49f5b849f5e748c071da8c0dbc",
],
group_secret: "0d004150d27c3bf2a42f312683d35fac7394b1e9e318249c1bfe7f0795a83114",
group_key: "02f37c34b66ced1fb51c34a90bdae006901f10625cc06c4f64663b0eae87d87b4f",
msg: "74657374",
included: &[1, 3],
nonces: &[
[
"36d5c4185c40b02b5e4673e2531a10e6ff9883840a68ec08dbeb896467e21355",
"7b3f573ca0a28f9f94522be4748df0ed04de8a83085aff4be7b01aa53fb6ac1b",
],
[
"ba4f8b8e587b2c9fc61a6156885f0bc67654b5e068c9e7749f75c09a98f17c13",
"316de06639051ac7869e5ac4458eda1fef90ce93fa3c490556c4192e4fa550d0",
],
],
sig_shares: &[
"f9ee00d5ac0c746b751dde99f71d86f8f0300a81bd0336ca6649ef597239e13f",
"61048ca334ac6a6cb59d6b3ea2b25b7098e204adc09e2f88b024531b081d1d6f",
],
sig: "023cf76388f92d403aa937af2e3cb3e7a2350e40400c16a282e330af2c60eeb85a".to_owned() +
"5af28d78e0b8ded82abb49d899cfe26ace633248ce58c617569be3e7aa20bd6d",
},
Vectors::from(
serde_json::from_str::<serde_json::Value>(include_str!(
"vectors/frost-secp256k1-sha256.json"
))
.unwrap(),
),
);
}
@ -50,34 +27,9 @@ fn secp256k1_vectors() {
fn p256_vectors() {
test_with_vectors::<_, P256, IetfP256Hram>(
&mut OsRng,
Vectors {
threshold: 2,
shares: &[
"0c9c1a0fe806c184add50bbdcac913dda73e482daf95dcb9f35dbb0d8a9f7731",
"8d8e787bef0ff6c2f494ca45f4dad198c6bee01212d6c84067159c52e1863ad5",
"0e80d6e8f6192c003b5488ce1eec8f5429587d48cf001541e713b2d53c09d928",
],
group_secret: "8ba9bba2e0fd8c4767154d35a0b7562244a4aaf6f36c8fb8735fa48b301bd8de",
group_key: "023a309ad94e9fe8a7ba45dfc58f38bf091959d3c99cfbd02b4dc00585ec45ab70",
msg: "74657374",
included: &[1, 3],
nonces: &[
[
"9aa66350b0f72b27ce4668323b4280cd49709177ed8373977c22a75546c9995d",
"bd8b05d7fd0ff5a5ed65b1f105478f7718a981741fa8fa9b55ac6d3c8fc59a05",
],
[
"4c1aec8e84c496b80af98415fada2e6a4b1f902d4bc6c9682699b8aeffd97419",
"eeaf5ef7af01e55050fb8acafc9c9306ef1cc13214677ba33e7bc51e8677e892",
],
],
sig_shares: &[
"ec5b8ab47d55903698492a07bb322ab6e7d3cf32581dcedf43c4fa18b46f3e10",
"c97da3580560e88725a8e393d46fee18ecd2e00148e5e303d4a510fae9c11da5",
],
sig: "036b3eba585ff5d40df29893fb6f60572803aef97800cfaaaa5cf0f0f19d8237f7".to_owned() +
"b5d92e0d82b678bcbdf20d9b8fa218d017bfb485f9ec135e24b04050a1cd3664",
},
Vectors::from(
serde_json::from_str::<serde_json::Value>(include_str!("vectors/frost-p256-sha256.json"))
.unwrap(),
),
);
}

View file

@ -0,0 +1,68 @@
{
"config": {
"MAX_PARTICIPANTS": "3",
"NUM_PARTICIPANTS": "2",
"MIN_PARTICIPANTS": "2",
"name": "FROST(Ed25519, SHA-512)",
"group": "ed25519",
"hash": "SHA-512"
},
"inputs": {
"group_secret_key": "7b1c33d3f5291d85de664833beb1ad469f7fb6025a0ec78b3a790c6e13a98304",
"group_public_key": "15d21ccd7ee42959562fc8aa63224c8851fb3ec85a3faf66040d380fb9738673",
"message": "74657374",
"share_polynomial_coefficients": [
"178199860edd8c62f5212ee91eff1295d0d670ab4ed4506866bae57e7030b204"
],
"participants": {
"1": {
"participant_share": "929dcc590407aae7d388761cddb0c0db6f5627aea8e217f4a033f2ec83d93509"
},
"2": {
"participant_share": "a91e66e012e4364ac9aaa405fcafd370402d9859f7b6685c07eed76bf409e80d"
},
"3": {
"participant_share": "d3cb090a075eb154e82fdb4b3cb507f110040905468bb9c46da8bdea643a9a02"
}
}
},
"round_one_outputs": {
"participant_list": "1,3",
"participants": {
"1": {
"hiding_nonce_randomness": "9d06a6381c7a4493929761a73692776772b274236fb5cfcc7d1b48ac3a9c249f",
"binding_nonce_randomness": "db184d7bc01a3417fe1f2eb3cf5479bb027145e6369a5f879f32d334ab256b23",
"hiding_nonce": "70652da3e8d7533a0e4b9e9104f01b48c396b5b553717784ed8d05c6a36b9609",
"binding_nonce": "4f9e1ad260b5c0e4fe0e0719c6324f89fecd053758f77c957f56967e634a710e",
"hiding_nonce_commitment": "44105304351ceddc58e15ddea35b2cb48e60ced54ceb22c3b0e5d42d098aa1d8",
"binding_nonce_commitment": "b8274b18a12f2cef74ae42f876cec1e31daab5cb162f95a56cd2487409c9d1dd",
"binding_factor_input": "c5b95020cba31a9035835f074f718d0c3af02a318d6b4723bbd1c088f4889dd7b9ff8e79f9a67a9d27605144259a7af18b7cca2539ffa5c4f1366a98645da8f4e077d604fff64f20e2377a37e5a10ce152194d62fe856ef4cd935d4f1cb0088c2083a2722ad3f5a84d778e257da0df2a7cadb004b1f5528352af778b94ee1c2a0100000000000000000000000000000000000000000000000000000000000000",
"binding_factor": "2d5630c36d33258b1208c4205fa759b762d09bfa06b29cf792cf98758c0b3305"
},
"3": {
"hiding_nonce_randomness": "31ca9b07936d6b342a43d97f23b7bec5a5f5a09575a075393868dd8df5c05a54",
"binding_nonce_randomness": "c1db96a85d8b593e14fdb869c0955625478afa6a987ad217e7f2261dcab26819",
"hiding_nonce": "233adcb0ec0eddba5f1cc5268f3f4e6fc1dd97fb1e4a1754e6ddc92ed834ca0b",
"binding_nonce": "b59fc8a32fe02ec0a44c4671f3d1f82ea3924b7c7c0179398fc9137e82757803",
"hiding_nonce_commitment": "d31bd81ce216b1c83912803a574a0285796275cb8b14f6dc92c8b09a6951f0a2",
"binding_nonce_commitment": "e1c863cfd08df775b6747ef2456e9bf9a03cc281a479a95261dc39137fcf0967",
"binding_factor_input": "c5b95020cba31a9035835f074f718d0c3af02a318d6b4723bbd1c088f4889dd7b9ff8e79f9a67a9d27605144259a7af18b7cca2539ffa5c4f1366a98645da8f4e077d604fff64f20e2377a37e5a10ce152194d62fe856ef4cd935d4f1cb0088c2083a2722ad3f5a84d778e257da0df2a7cadb004b1f5528352af778b94ee1c2a0300000000000000000000000000000000000000000000000000000000000000",
"binding_factor": "1137be5cdf3d18e44367acee8485e9a66c3164077af80619b6291e3943bbef04"
}
}
},
"round_two_outputs": {
"participant_list": "1,3",
"participants": {
"1": {
"sig_share": "c4b26af1e91fbc8440a0dad253e72620da624553c5b625fd51e6ea179fc09f05"
},
"3": {
"sig_share": "9369640967d0cb98f4dedfde58a845e0e18e0a7164396358439060ed282b4e08"
}
}
},
"final_output": {
"sig": "ae11c539fdc709b78fef5ee1f5a2250297e3e1b62a86a86c26d93c389934ba0e571ccffa50f0871d357fbab1ac8f6c00bcf14fc429f0885595764b05c8ebed0d"
}
}

View file

@ -0,0 +1,68 @@
{
"config": {
"MAX_PARTICIPANTS": "3",
"NUM_PARTICIPANTS": "2",
"MIN_PARTICIPANTS": "2",
"name": "FROST(Ed448, SHAKE256)",
"group": "ed448",
"hash": "SHAKE256"
},
"inputs": {
"group_secret_key": "6298e1eef3c379392caaed061ed8a31033c9e9e3420726f23b404158a401cd9df24632adfe6b418dc942d8a091817dd8bd70e1c72ba52f3c00",
"group_public_key": "3832f82fda00ff5365b0376df705675b63d2a93c24c6e81d40801ba265632be10f443f95968fadb70d10786827f30dc001c8d0f9b7c1d1b000",
"message": "74657374",
"share_polynomial_coefficients": [
"dbd7a514f7a731976620f0436bd135fe8dddc3fadd6e0d13dbd58a1981e587d377d48e0b7ce4e0092967c5e85884d0275a7a740b6abdcd0500"
],
"participants": {
"1": {
"participant_share": "4a2b2f5858a932ad3d3b18bd16e76ced3070d72fd79ae4402df201f525e754716a1bc1b87a502297f2a99d89ea054e0018eb55d39562fd0100"
},
"2": {
"participant_share": "2503d56c4f516444a45b080182b8a2ebbe4d9b2ab509f25308c88c0ea7ccdc44e2ef4fc4f63403a11b116372438a1e287265cadeff1fcb0700"
},
"3": {
"participant_share": "00db7a8146f995db0a7cf844ed89d8e94c2b5f259378ff66e39d172828b264185ac4decf7219e4aa4478285b9c0eef4fccdf3eea69dd980d00"
}
}
},
"round_one_outputs": {
"participant_list": "1,3",
"participants": {
"1": {
"hiding_nonce_randomness": "89bf16040081ff2990336b200613787937ebe1f024b8cdff90eb6f1c741d91c1",
"binding_nonce_randomness": "cd646348bb98fd2a4b2f27fb7d6da18201c161847352576b4bf125190e965483",
"hiding_nonce": "67a6f023e77361707c6e894c625e809e80f33fdb310810053ae29e28e7011f3193b9020e73c183a98cc3a519160ed759376dd92c9483162200",
"binding_nonce": "4812e8d7c8b7a50ced80b507902d074ef8647bc1146979683da8d0fecd93fa3c8230cade2fb4344600aa04bd4b7a21d046c5b63ee865b12a00",
"hiding_nonce_commitment": "649c6a53b109897d962d033f23d01fd4e1053dddf3746d2ddce9bd66aea38ccfc3df061df03ca399eb806312ab3037c0c31523142956ada780",
"binding_nonce_commitment": "0064cc729a8e2fcf417e43788ecec37b10e9e1dcb3ae90854efbfaad00a0ef3cdd52e18d56f073c8ff0947cb71ff0bb17c3d45d096409ddb00",
"binding_factor_input": "106dadce87ca867018702d69a02effd165e1ac1a511c957cff1897ceff2e34ca212fe798d84f0bde6054bf0fa77fd4cd4bc4853d6dc8dbd19d340923f0ebbbb35172df4ab865a45d55af31fa0e6606ea97cf8513022b2b133d0f9f6b8d3be184221fc4592bf12bd7fb4127bb67e51a6dc9e5f1ed5243362fb46a6da552418ca967d43d9bc811a21917a3018de58f11c25f6b9ad8bec3699e06b87dd3ab67a7326c30878c7c55ec1a45802af65da193ce99634158539e38c232a627895c5f14e2e20d487382ccc9c99cd0a0df266a292f283bb9b6854e344ecc32d5e1852fdde5fde77798010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"binding_factor": "3412ac894a91a6bc0e3e7c790f3e8ef5d1288e54de780aba384cbb3081b602dd188010e5b0c9ac2b5dca0aae54cfd0f5c391cece8092131d00"
},
"3": {
"hiding_nonce_randomness": "3718dabb4fd3d7dd9adad4878c6de8b33c8841cfe7cc95a85592952a2c9c554d",
"binding_nonce_randomness": "3becbc90798211a0f52543dd1f24869a143fdf743409581af4db30f045773d64",
"hiding_nonce": "4f2666770317d14ec9f7fd6690c075c34b4cde7f6d9bceda9e9433ec8c0f2dc983ff1622c3a54916ce7c161381d263fad62539cddab2101600",
"binding_nonce": "88f66df8bb66389932721a40de4aa5754f632cac114abc1052688104d19f3b1a010880ebcd0c4c0f8cf567d887e5b0c3c0dc78821166550f00",
"hiding_nonce_commitment": "8dcf049167e28d5f53fa7ebbbd136abcaf2be9f2c02448c8979002f92577b22027640def7ddd5b98f9540c2280f36a92d4747bbade0b0c4280",
"binding_nonce_commitment": "12e837b89a2c085481fcf0ca640a17a24b6fc96b032d40e4301c78e7232a9f49ffdcad2c21acbc992e79dfc3c6c07cb94e4680b3dcc9935580",
"binding_factor_input": "106dadce87ca867018702d69a02effd165e1ac1a511c957cff1897ceff2e34ca212fe798d84f0bde6054bf0fa77fd4cd4bc4853d6dc8dbd19d340923f0ebbbb35172df4ab865a45d55af31fa0e6606ea97cf8513022b2b133d0f9f6b8d3be184221fc4592bf12bd7fb4127bb67e51a6dc9e5f1ed5243362fb46a6da552418ca967d43d9bc811a21917a3018de58f11c25f6b9ad8bec3699e06b87dd3ab67a7326c30878c7c55ec1a45802af65da193ce99634158539e38c232a627895c5f14e2e20d487382ccc9c99cd0a0df266a292f283bb9b6854e344ecc32d5e1852fdde5fde77798030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"binding_factor": "6aa48a3635d7b962489283ee1ccda8ea66e5677b1e17f2f475eb565e3ae8ea73360f24c04e3775dadd1f2923adcda3d105536ad28c3c561100"
}
}
},
"round_two_outputs": {
"participant_list": "1,3",
"participants": {
"1": {
"sig_share": "c5057c80d13e565545dac6f3aa333065c809a14a94fea3c8e4e87e386a9cb89602de7355c5d19ebb09d553b100ef1858104fc7c43992d83400"
},
"3": {
"sig_share": "2b490ea08411f78c620c668fff8ba70b25b7c89436f20cc45419213de70f93fb6c9094c79293697d72e741b68d2e493446005145d0b7fc3500"
}
}
},
"final_output": {
"sig": "83ac141d289a5171bc894b058aee2890316280719a870fc5c1608b77403023155d7a9dc15a2b7920bb5826dd540bf76336be99536cebe36280fd093275c38dd4be525767f537fd6a4f5d8a9330811562c84fded5f851ac4b926f6e081d586508397cbc95678e1d628c564f180a0a4ad52a00"
}
}

View file

@ -0,0 +1,68 @@
{
"config": {
"MAX_PARTICIPANTS": "3",
"NUM_PARTICIPANTS": "2",
"MIN_PARTICIPANTS": "2",
"name": "FROST(P-256, SHA-256)",
"group": "P-256",
"hash": "SHA-256"
},
"inputs": {
"group_secret_key": "8ba9bba2e0fd8c4767154d35a0b7562244a4aaf6f36c8fb8735fa48b301bd8de",
"group_public_key": "023a309ad94e9fe8a7ba45dfc58f38bf091959d3c99cfbd02b4dc00585ec45ab70",
"message": "74657374",
"share_polynomial_coefficients": [
"80f25e6c0709353e46bfbe882a11bdbb1f8097e46340eb8673b7e14556e6c3a4"
],
"participants": {
"1": {
"participant_share": "0c9c1a0fe806c184add50bbdcac913dda73e482daf95dcb9f35dbb0d8a9f7731"
},
"2": {
"participant_share": "8d8e787bef0ff6c2f494ca45f4dad198c6bee01212d6c84067159c52e1863ad5"
},
"3": {
"participant_share": "0e80d6e8f6192c003b5488ce1eec8f5429587d48cf001541e713b2d53c09d928"
}
}
},
"round_one_outputs": {
"participant_list": "1,3",
"participants": {
"1": {
"hiding_nonce_randomness": "f4e8cf80aec3f888d997900ac7e3e349944b5a6b47649fc32186d2f1238103c6",
"binding_nonce_randomness": "a7f220770b6f10ff54ec6afa55f99bd08cc92fa1a488c86e9bf493e9cb894cdf",
"hiding_nonce": "f871dfcf6bcd199342651adc361b92c941cb6a0d8c8c1a3b91d79e2c1bf3722d",
"binding_nonce": "bd3ece3634a1b303dea0586ed67a91fe68510f11ebe66e8868309b1551ef2388",
"hiding_nonce_commitment": "03987febbc67a8ed735affdff4d3a5adf22c05c80f97f311ab7437a3027372deb3",
"binding_nonce_commitment": "02a1960477d139035b986d6adcb06491378beb92ccd097ad94e76291c52343849d",
"binding_factor_input": "350c8b523feea9bb35720e9fbe0405ed48d78caa4fb60869f34367e144c68bb0fc77bf512409ad8b91e2ace4909229891a446c45683f5eb2f843dbec224527dc0000000000000000000000000000000000000000000000000000000000000001",
"binding_factor": "cb415dd1d866493ee7d2db7cb33929d7e430e84d80c58070e2bbb1fdbf76a9c8"
},
"3": {
"hiding_nonce_randomness": "1b6149d252a0a0a6618b8d22a1c49897f9b0d23a48f19598e191e05dc7b7ae33",
"binding_nonce_randomness": "e13994bb75aafe337c32afdbfd08ae60dd108fc768845edaa871992044cabf1b",
"hiding_nonce": "802e9321f9f63688c6c1a9681a4a4661f71770e0cef92b8a5997155d18fb82ef",
"binding_nonce": "8b6b692ae634a24536f45dda95b2398af71cd605fb7a0bbdd9408d211ab99eba",
"hiding_nonce_commitment": "0212cac45ebd4100c97506939391f9be4ffc3ca2960e2ef95aeaa38abdede204ca",
"binding_nonce_commitment": "03017ce754d310eabda0f5681e61ce3d713cdd337070faa6a68471af49694a4e7e",
"binding_factor_input": "350c8b523feea9bb35720e9fbe0405ed48d78caa4fb60869f34367e144c68bb0fc77bf512409ad8b91e2ace4909229891a446c45683f5eb2f843dbec224527dc0000000000000000000000000000000000000000000000000000000000000003",
"binding_factor": "dfd82467569334e952edecb10d92adf85b8e299db0b40be3131a12efdfa3e796"
}
}
},
"round_two_outputs": {
"participant_list": "1,3",
"participants": {
"1": {
"sig_share": "c5acd980310aaf87cb7a9a90428698ef3e6b1e5860f7fb06329bc0efe3f14ca5"
},
"3": {
"sig_share": "1e064fbd35467377eb3fe161ff975e9ec3ed8e2e0d4c73f3a6b0a023777e1264"
}
}
},
"final_output": {
"sig": "029e07d4171dbf9a730ed95e9d95bda06fa4db76c88c519f7f3ca5483019f46cb0e3b3293d665122ffb6ba7bf2421df78e0258ac866e446ef9d94c61135b6f5f09"
}
}

View file

@ -0,0 +1,68 @@
{
"config": {
"MAX_PARTICIPANTS": "3",
"NUM_PARTICIPANTS": "2",
"MIN_PARTICIPANTS": "2",
"name": "FROST(ristretto255, SHA-512)",
"group": "ristretto255",
"hash": "SHA-512"
},
"inputs": {
"group_secret_key": "1b25a55e463cfd15cf14a5d3acc3d15053f08da49c8afcf3ab265f2ebc4f970b",
"group_public_key": "e2a62f39eede11269e3bd5a7d97554f5ca384f9f6d3dd9c3c0d05083c7254f57",
"message": "74657374",
"share_polynomial_coefficients": [
"410f8b744b19325891d73736923525a4f596c805d060dfb9c98009d34e3fec02"
],
"participants": {
"1": {
"participant_share": "5c3430d391552f6e60ecdc093ff9f6f4488756aa6cebdbad75a768010b8f830e"
},
"2": {
"participant_share": "b06fc5eac20b4f6e1b271d9df2343d843e1e1fb03c4cbb673f2872d459ce6f01"
},
"3": {
"participant_share": "f17e505f0e2581c6acfe54d3846a622834b5e7b50cad9a2109a97ba7a80d5c04"
}
}
},
"round_one_outputs": {
"participant_list": "1,3",
"participants": {
"1": {
"hiding_nonce_randomness": "81800157bb554f299fe0b6bd658e4c4591d74168b5177bf55e8dceed59dc80c7",
"binding_nonce_randomness": "e9b37de02fde28f601f09051ed9a277b02ac81c803a5c72492d58635001fe355",
"hiding_nonce": "40f58e8df202b21c94f826e76e4647efdb0ea3ca7ae7e3689bc0cbe2e2f6660c",
"binding_nonce": "373dd42b5fe80e88edddf82e03744b6a12d59256f546de612d4bbd91a6b1df06",
"hiding_nonce_commitment": "b8c7319a56b296537436e5a6f509a871a3c74eff1534ec1e2f539ccd8b322411",
"binding_nonce_commitment": "7af5d4bece8763ce3630370adbd978699402f624fd3a7d2c71ea5839efc3cf54",
"binding_factor_input": "9c245d5fc2e451c5c5a617cc6f2a20629fb317d9b1c1915ab4bfa319d4ebf922c54dd1a5b3b754550c72734ac9255db8107a2b01f361754d9f13f428c2f6de9e4f609ae0dbe8bd1f95bee9f9ea219154d567ef174390bac737bb67ee1787c8a34279728d4aa99a6de2d5ce6deb86afe6bc68178f01223bb5eb934c8a23b6354e0100000000000000000000000000000000000000000000000000000000000000",
"binding_factor": "607df5e2e3a8b5e2704716693e18f548100a32b86a5685d3932a774c3f107e06"
},
"3": {
"hiding_nonce_randomness": "daeb223c4a913943cff2fb0b0e638dfcc281e1e8936ee6c3fef4d49ad9cbfaa0",
"binding_nonce_randomness": "c425768d952ab8f18b9720c54b93e612ba2cca170bb7518cac080896efa7429b",
"hiding_nonce": "491477c9dbe8717c77c6c1e2c5f4cec636c7c154313a44c91fea63e309f3e100",
"binding_nonce": "3ae1bba7d6f2076f81596912dd916efae5b3c2ef896956321194fdd2e52ebc0f",
"hiding_nonce_commitment": "e4466b7670ac4f9d9b7b67655860dd1ab341be18a654bb1966df53c76c85d511",
"binding_nonce_commitment": "ce47cd595d25d7effc3c095efa2a687a1728a5ecab402b39e0c0ad9a525ea54f",
"binding_factor_input": "9c245d5fc2e451c5c5a617cc6f2a20629fb317d9b1c1915ab4bfa319d4ebf922c54dd1a5b3b754550c72734ac9255db8107a2b01f361754d9f13f428c2f6de9e4f609ae0dbe8bd1f95bee9f9ea219154d567ef174390bac737bb67ee1787c8a34279728d4aa99a6de2d5ce6deb86afe6bc68178f01223bb5eb934c8a23b6354e0300000000000000000000000000000000000000000000000000000000000000",
"binding_factor": "2bd27271c28746eb93e2114d6778c12b44c9287d84b85dc780eb08da6f689900"
}
}
},
"round_two_outputs": {
"participant_list": "1,3",
"participants": {
"1": {
"sig_share": "c38f438c325ce6bfa4272b37e7707caaeb57fa8c7ddcc05e0725acb8a7d9cd0c"
},
"3": {
"sig_share": "4cb9917be3bd53f1d60f1c3d1a3ff563565fa15a391133e7f980e55d3aeb7904"
}
}
},
"final_output": {
"sig": "204d5d93aa486192ecf2f64ce7dbc1db76948fb1077d1a719ae1ecca6143501e2275dfaafbb62759a59a4fd122b692f941b79be7b6edf34501a69116e2c44701"
}
}

View file

@ -0,0 +1,68 @@
{
"config": {
"MAX_PARTICIPANTS": "3",
"NUM_PARTICIPANTS": "2",
"MIN_PARTICIPANTS": "2",
"name": "FROST(secp256k1, SHA-256)",
"group": "secp256k1",
"hash": "SHA-256"
},
"inputs": {
"group_secret_key": "0d004150d27c3bf2a42f312683d35fac7394b1e9e318249c1bfe7f0795a83114",
"group_public_key": "02f37c34b66ced1fb51c34a90bdae006901f10625cc06c4f64663b0eae87d87b4f",
"message": "74657374",
"share_polynomial_coefficients": [
"fbf85eadae3058ea14f19148bb72b45e4399c0b16028acaf0395c9b03c823579"
],
"participants": {
"1": {
"participant_share": "08f89ffe80ac94dcb920c26f3f46140bfc7f95b493f8310f5fc1ea2b01f4254c"
},
"2": {
"participant_share": "04f0feac2edcedc6ce1253b7fab8c86b856a797f44d83d82a385554e6e401984"
},
"3": {
"participant_share": "00e95d59dd0d46b0e303e500b62b7ccb0e555d49f5b849f5e748c071da8c0dbc"
}
}
},
"round_one_outputs": {
"participant_list": "1,3",
"participants": {
"1": {
"hiding_nonce_randomness": "80cbea5e405d169999d8c4b30b755fedb26ab07ec8198cda4873ed8ce5e16773",
"binding_nonce_randomness": "f6d5b38197843046b68903048c1feba433e3500145281fa8bb1e26fdfeef5e7f",
"hiding_nonce": "acc83278035223c1ba464e2d11bfacfc872b2b23e1041cf5f6130da21e4d8068",
"binding_nonce": "c3ef169995bc3d2c2d48f30b83d0c63751e67ceb057695bcb2a6aa40ed5d926b",
"hiding_nonce_commitment": "036673d68a928793c33ae07776908eae8ea15dd947ed81284e939aaba118573a5e",
"binding_nonce_commitment": "03d2a96dd4ec1ee29dc22067109d1290dabd8016cb41856ee8ff9281c3fa1baffd",
"binding_factor_input": "a645d8249457bbcac34fa7b740f66bcce08fc39506b8bbf1a1c81092f6272eda82ae39234d714f87a7b91dd67d124a06561a36817c1ecaa255c3527d694fc4f10000000000000000000000000000000000000000000000000000000000000001",
"binding_factor": "d7bcbd29408dedc9e138262d99b09d8b5705d76eb5de2369d9103e4423f8ac79"
},
"3": {
"hiding_nonce_randomness": "b9794047604beda0c5c0529ac9dfd83c0a80399a7bdf4c3e23cef2faf69cdcc3",
"binding_nonce_randomness": "c28ce6252631620b84c2702b34774fab365e286ebc77030a112ebccccbffa78b",
"hiding_nonce": "cb3387defef07fc9010c0564ba6495ed41876626ed86b886ca26cbbd3566ffbc",
"binding_nonce": "4559459735eb68e8c16319a9fd9a14016053957cb8cea273a24b7c7bc1ee26f6",
"hiding_nonce_commitment": "030278e6e6055fb963b40e0c3c37099f803f3f38930fc89092517f8ce1b47e8d6b",
"binding_nonce_commitment": "028eb6d238c6c0fc6216906706ad0ff9943c6c1d6079cdf74f674481ebb2485db3",
"binding_factor_input": "a645d8249457bbcac34fa7b740f66bcce08fc39506b8bbf1a1c81092f6272eda82ae39234d714f87a7b91dd67d124a06561a36817c1ecaa255c3527d694fc4f10000000000000000000000000000000000000000000000000000000000000003",
"binding_factor": "ecc057259f3c8b195308c9b73aaaf840660a37eb264ebce342412c58102ee437"
}
}
},
"round_two_outputs": {
"participant_list": "1,3",
"participants": {
"1": {
"sig_share": "1750b2a314a81b66fd81366583617aaafcffa68f14495204795aa0434b907aa3"
},
"3": {
"sig_share": "e4dbbbbbcb035eb3512918b0368c4ab2c836a92dccff3251efa7a4aacc7d3790"
}
}
},
"final_output": {
"sig": "0259696aac722558e8638485d252bb2556f6241a7adfdf284c8c87a3428d46448dfc2c6e5edfab7a1a4eaa4f15b9edc55dc5364fbce1488456690244ee180db233"
}
}

View file

@ -12,9 +12,9 @@ use crate::{
};
pub(crate) fn core_sign<R: RngCore + CryptoRng, C: Curve>(rng: &mut R) {
let private_key = C::F::random(&mut *rng);
let nonce = C::F::random(&mut *rng);
let challenge = C::F::random(rng); // Doesn't bother to craft an HRAM
let private_key = C::random_F(&mut *rng);
let nonce = C::random_F(&mut *rng);
let challenge = C::random_F(rng); // Doesn't bother to craft an HRAm
assert!(schnorr::verify::<C>(
C::generator() * private_key,
challenge,
@ -27,8 +27,8 @@ pub(crate) fn core_sign<R: RngCore + CryptoRng, C: Curve>(rng: &mut R) {
// random
pub(crate) fn core_verify<R: RngCore + CryptoRng, C: Curve>(rng: &mut R) {
assert!(!schnorr::verify::<C>(
C::generator() * C::F::random(&mut *rng),
C::F::random(rng),
C::generator() * C::random_F(&mut *rng),
C::random_F(rng),
&SchnorrSignature { R: C::G::identity(), s: C::F::zero() }
));
}
@ -39,9 +39,9 @@ pub(crate) fn core_batch_verify<R: RngCore + CryptoRng, C: Curve>(rng: &mut R) {
let mut challenges = vec![];
let mut sigs = vec![];
for i in 0 .. 5 {
keys.push(C::F::random(&mut *rng));
challenges.push(C::F::random(&mut *rng));
sigs.push(schnorr::sign::<C>(keys[i], C::F::random(&mut *rng), challenges[i]));
keys.push(C::random_F(&mut *rng));
challenges.push(C::random_F(&mut *rng));
sigs.push(schnorr::sign::<C>(keys[i], C::random_F(&mut *rng), challenges[i]));
}
// Batch verify
@ -66,7 +66,7 @@ pub(crate) fn core_batch_verify<R: RngCore + CryptoRng, C: Curve>(rng: &mut R) {
// Make sure a completely invalid signature fails when included
for i in 0 .. 5 {
let mut triplets = triplets.clone();
triplets[i].3.s = C::F::random(&mut *rng);
triplets[i].3.s = C::random_F(&mut *rng);
if let Err(blame) = schnorr::batch_verify(rng, &triplets) {
assert_eq!(blame, u16::try_from(i + 1).unwrap());
} else {

View file

@ -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);