Update to FROST v10

Further expands documentation to near-completion.
This commit is contained in:
Luke Parker 2022-09-29 07:08:20 -04:00
parent 7870084b9e
commit 2b7c9378c0
No known key found for this signature in database
GPG key ID: F9F1386DB1E119B6
16 changed files with 95 additions and 65 deletions

2
Cargo.lock generated
View file

@ -4541,7 +4541,7 @@ dependencies = [
[[package]] [[package]]
name = "modular-frost" name = "modular-frost"
version = "0.2.2" version = "0.2.3"
dependencies = [ dependencies = [
"dalek-ff-group", "dalek-ff-group",
"dleq", "dleq",

View file

@ -1,6 +1,6 @@
[package] [package]
name = "modular-frost" name = "modular-frost"
version = "0.2.2" version = "0.2.3"
description = "Modular implementation of FROST over ff/group" description = "Modular implementation of FROST over ff/group"
license = "MIT" license = "MIT"
repository = "https://github.com/serai-dex/serai" repository = "https://github.com/serai-dex/serai"

View file

@ -10,4 +10,4 @@ integrating with existing systems.
This library offers ciphersuites compatible with the This library offers ciphersuites compatible with the
[IETF draft](https://github.com/cfrg/draft-irtf-cfrg-frost). Currently, version [IETF draft](https://github.com/cfrg/draft-irtf-cfrg-frost). Currently, version
8 is supported. 10 is supported.

View file

@ -8,8 +8,10 @@ use transcript::Transcript;
use crate::{Curve, FrostError, FrostView, schnorr}; use crate::{Curve, FrostError, FrostView, schnorr};
pub use schnorr::SchnorrSignature; pub use schnorr::SchnorrSignature;
/// Algorithm to use FROST with. /// Algorithm trait usable by the FROST signing machine to produce signatures..
pub trait Algorithm<C: Curve>: Clone { pub trait Algorithm<C: Curve>: Clone {
/// The transcript format this algorithm uses. This likely should NOT be the IETF-compatible
/// transcript included in this crate.
type Transcript: Transcript + Clone + Debug; type Transcript: Transcript + Clone + Debug;
/// The resulting type of the signatures this algorithm will produce. /// The resulting type of the signatures this algorithm will produce.
type Signature: Clone + PartialEq + Debug; type Signature: Clone + PartialEq + Debug;
@ -58,7 +60,8 @@ pub trait Algorithm<C: Curve>: Clone {
fn verify_share(&self, verification_share: C::G, nonces: &[Vec<C::G>], share: C::F) -> bool; fn verify_share(&self, verification_share: C::G, nonces: &[Vec<C::G>], share: C::F) -> bool;
} }
// Transcript which will create an IETF compliant serialization for the binding factor /// IETF-compliant transcript. This is incredibly naive and should not be used within larger
/// protocols.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct IetfTranscript(Vec<u8>); pub struct IetfTranscript(Vec<u8>);
impl Transcript for IetfTranscript { impl Transcript for IetfTranscript {
@ -83,13 +86,15 @@ impl Transcript for IetfTranscript {
} }
} }
/// HRAm usable by the included Schnorr signature algorithm to generate challenges.
pub trait Hram<C: Curve>: Clone { pub trait Hram<C: Curve>: Clone {
/// HRAM function to generate a challenge. /// HRAm function to generate a challenge.
/// H2 from the IETF draft, despite having a different argument set (not being pre-formatted). /// H2 from the IETF draft, despite having a different argument set (not being pre-formatted).
#[allow(non_snake_case)] #[allow(non_snake_case)]
fn hram(R: &C::G, A: &C::G, m: &[u8]) -> C::F; fn hram(R: &C::G, A: &C::G, m: &[u8]) -> C::F;
} }
/// IETF-compliant Schnorr signature algorithm ((R, s) where s = r + cx).
#[derive(Clone)] #[derive(Clone)]
pub struct Schnorr<C: Curve, H: Hram<C>> { pub struct Schnorr<C: Curve, H: Hram<C>> {
transcript: IetfTranscript, transcript: IetfTranscript,
@ -109,7 +114,6 @@ impl<C: Curve, H: Hram<C>> Schnorr<C, H> {
} }
} }
/// Implementation of Schnorr signatures for use with FROST.
impl<C: Curve, H: Hram<C>> Algorithm<C> for Schnorr<C, H> { impl<C: Curve, H: Hram<C>> Algorithm<C> for Schnorr<C, H> {
type Transcript = IetfTranscript; type Transcript = IetfTranscript;
type Signature = SchnorrSignature<C>; type Signature = SchnorrSignature<C>;

View file

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

View file

@ -7,7 +7,7 @@ use minimal_ed448::{scalar::Scalar, point::Point};
use crate::{curve::Curve, algorithm::Hram}; use crate::{curve::Curve, algorithm::Hram};
const CONTEXT: &[u8] = b"FROST-ED448-SHAKE256-v8"; const CONTEXT: &[u8] = b"FROST-ED448-SHAKE256-v10";
#[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize)] #[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize)]
pub struct Ed448; pub struct Ed448;

View file

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

View file

@ -249,12 +249,14 @@ fn complete_r2<Re: Read, R: RngCore + CryptoRng, C: Curve>(
Ok(FrostCore { params, secret_share, group_key: stripes[0], verification_shares }) Ok(FrostCore { params, secret_share, group_key: stripes[0], verification_shares })
} }
/// State machine to begin the key generation protocol.
pub struct KeyGenMachine<C: Curve> { pub struct KeyGenMachine<C: Curve> {
params: FrostParams, params: FrostParams,
context: String, context: String,
_curve: PhantomData<C>, _curve: PhantomData<C>,
} }
/// Advancement of the key generation state machine.
#[derive(Zeroize)] #[derive(Zeroize)]
pub struct SecretShareMachine<C: Curve> { pub struct SecretShareMachine<C: Curve> {
#[zeroize(skip)] #[zeroize(skip)]
@ -272,6 +274,7 @@ impl<C: Curve> Drop for SecretShareMachine<C> {
} }
impl<C: Curve> ZeroizeOnDrop for SecretShareMachine<C> {} impl<C: Curve> ZeroizeOnDrop for SecretShareMachine<C> {}
/// Final step of the key generation protocol.
#[derive(Zeroize)] #[derive(Zeroize)]
pub struct KeyMachine<C: Curve> { pub struct KeyMachine<C: Curve> {
#[zeroize(skip)] #[zeroize(skip)]

View file

@ -11,7 +11,7 @@
//! //!
//! This library offers ciphersuites compatible with the //! This library offers ciphersuites compatible with the
//! [IETF draft](https://github.com/cfrg/draft-irtf-cfrg-frost). Currently, version //! [IETF draft](https://github.com/cfrg/draft-irtf-cfrg-frost). Currently, version
//! 8 is supported. //! 10 is supported.
use core::fmt::{self, Debug}; use core::fmt::{self, Debug};
use std::{io::Read, sync::Arc, collections::HashMap}; use std::{io::Read, sync::Arc, collections::HashMap};
@ -111,6 +111,7 @@ impl FrostParams {
} }
} }
/// Various errors possible during key generation/signing.
#[derive(Copy, Clone, Error, Debug)] #[derive(Copy, Clone, Error, Debug)]
pub enum FrostError { pub enum FrostError {
#[error("a parameter was 0 (required {0}, participants {1})")] #[error("a parameter was 0 (required {0}, participants {1})")]

View file

@ -60,6 +60,7 @@ fn transcript<G: GroupEncoding>(key: G, i: u16) -> RecommendedTranscript {
transcript transcript
} }
/// Proof of valid promotion to another generator.
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub struct GeneratorProof<C: Curve> { pub struct GeneratorProof<C: Curve> {
share: C::G, share: C::G,
@ -80,18 +81,21 @@ impl<C: Curve> GeneratorProof<C> {
} }
} }
/// Promote a set of keys from one curve to another, where the elliptic curve is the same.
/// Since the Curve trait additionally specifies a generator, this provides an O(n) way to update
/// the generator used with keys. The key generation protocol itself is exponential.
pub struct GeneratorPromotion<C1: Curve, C2: Curve> { pub struct GeneratorPromotion<C1: Curve, C2: Curve> {
base: FrostKeys<C1>, base: FrostKeys<C1>,
proof: GeneratorProof<C1>, proof: GeneratorProof<C1>,
_c2: PhantomData<C2>, _c2: PhantomData<C2>,
} }
/// Promote a set of keys from one generator to another.
// The linear DLEq proofs are much more efficient than an exponential key gen
impl<C1: Curve, C2: Curve> GeneratorPromotion<C1, C2> impl<C1: Curve, C2: Curve> GeneratorPromotion<C1, C2>
where where
C2: Curve<F = C1::F, G = C1::G>, C2: Curve<F = C1::F, G = C1::G>,
{ {
/// Begin promoting keys from one curve to another. Returns a proof this share was properly
/// promoted.
pub fn promote<R: RngCore + CryptoRng>( pub fn promote<R: RngCore + CryptoRng>(
rng: &mut R, rng: &mut R,
base: FrostKeys<C1>, base: FrostKeys<C1>,
@ -110,6 +114,7 @@ where
(GeneratorPromotion { base, proof, _c2: PhantomData::<C2> }, proof) (GeneratorPromotion { base, proof, _c2: PhantomData::<C2> }, proof)
} }
/// Complete promotion by taking in the proofs from all other participants.
pub fn complete( pub fn complete(
self, self,
proofs: &HashMap<u16, GeneratorProof<C1>>, proofs: &HashMap<u16, GeneratorProof<C1>>,

View file

@ -11,6 +11,7 @@ use multiexp::BatchVerifier;
use crate::Curve; use crate::Curve;
/// A Schnorr signature of the form (R, s) where s = r + cx.
#[allow(non_snake_case)] #[allow(non_snake_case)]
#[derive(Clone, Copy, PartialEq, Eq, Debug)] #[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct SchnorrSignature<C: Curve> { pub struct SchnorrSignature<C: Curve> {

View file

@ -191,7 +191,10 @@ fn sign_with_share<Re: Read, C: Curve, A: Algorithm<C>>(
// Parse the commitments // Parse the commitments
for l in &params.view.included { for l in &params.view.included {
{ {
params.algorithm.transcript().append_message(b"participant", &l.to_be_bytes()); params
.algorithm
.transcript()
.append_message(b"participant", C::F::from(u64::from(*l)).to_repr().as_ref());
} }
// While this doesn't note which nonce/basepoint this is for, those are expected to be // While this doesn't note which nonce/basepoint this is for, those are expected to be
@ -274,7 +277,7 @@ fn sign_with_share<Re: Read, C: Curve, A: Algorithm<C>>(
// Generate the per-signer binding factors // Generate the per-signer binding factors
for (l, commitments) in B.iter_mut() { for (l, commitments) in B.iter_mut() {
let mut rho_transcript = rho_transcript.clone(); let mut rho_transcript = rho_transcript.clone();
rho_transcript.append_message(b"participant", &l.to_be_bytes()); rho_transcript.append_message(b"participant", C::F::from(u64::from(*l)).to_repr().as_ref());
commitments.1 = C::hash_binding_factor(rho_transcript.challenge(b"rho").as_ref()); commitments.1 = C::hash_binding_factor(rho_transcript.challenge(b"rho").as_ref());
} }
@ -365,6 +368,7 @@ fn complete<Re: Read, C: Curve, A: Algorithm<C>>(
Err(FrostError::InternalError("everyone had a valid share yet the signature was still invalid")) Err(FrostError::InternalError("everyone had a valid share yet the signature was still invalid"))
} }
/// Trait for the initial state machine of a two-round signing protocol.
pub trait PreprocessMachine { pub trait PreprocessMachine {
type Signature: Clone + PartialEq + fmt::Debug; type Signature: Clone + PartialEq + fmt::Debug;
type SignMachine: SignMachine<Self::Signature>; type SignMachine: SignMachine<Self::Signature>;
@ -374,6 +378,7 @@ pub trait PreprocessMachine {
fn preprocess<R: RngCore + CryptoRng>(self, rng: &mut R) -> (Self::SignMachine, Vec<u8>); fn preprocess<R: RngCore + CryptoRng>(self, rng: &mut R) -> (Self::SignMachine, Vec<u8>);
} }
/// Trait for the second machine of a two-round signing protocol.
pub trait SignMachine<S> { pub trait SignMachine<S> {
type SignatureMachine: SignatureMachine<S>; type SignatureMachine: SignatureMachine<S>;
@ -387,6 +392,7 @@ pub trait SignMachine<S> {
) -> Result<(Self::SignatureMachine, Vec<u8>), FrostError>; ) -> Result<(Self::SignatureMachine, Vec<u8>), FrostError>;
} }
/// Trait for the final machine of a two-round signing protocol.
pub trait SignatureMachine<S> { pub trait SignatureMachine<S> {
/// Complete signing. /// Complete signing.
/// Takes in everyone elses' shares. Returns the signature. /// Takes in everyone elses' shares. Returns the signature.
@ -398,11 +404,13 @@ pub struct AlgorithmMachine<C: Curve, A: Algorithm<C>> {
params: Params<C, A>, params: Params<C, A>,
} }
/// Next step of the state machine for the signing process.
pub struct AlgorithmSignMachine<C: Curve, A: Algorithm<C>> { pub struct AlgorithmSignMachine<C: Curve, A: Algorithm<C>> {
params: Params<C, A>, params: Params<C, A>,
preprocess: PreprocessPackage<C>, preprocess: PreprocessPackage<C>,
} }
/// Final step of the state machine for the signing process.
pub struct AlgorithmSignatureMachine<C: Curve, A: Algorithm<C>> { pub struct AlgorithmSignatureMachine<C: Curve, A: Algorithm<C>> {
params: Params<C, A>, params: Params<C, A>,
sign: Package<C>, sign: Package<C>,

View file

@ -24,20 +24,20 @@ fn ristretto_vectors() {
included: &[1, 3], included: &[1, 3],
nonces: &[ nonces: &[
[ [
"1eaee906e0554a5e533415e971eefa909f3c614c7c75e27f381b0270a9afe308", "de3e8f526dcb51a1b9b48cc284aeca27c385aa3ba1a92a0c8440d51e1a1d2f00",
"16175fc2e7545baf7180e8f5b6e1e73c4f2769323cc76754bdd79fe93ab0bd0b", "fa8dca5ec7a05d5a7b782be847ba3dde1509de1dbcf0569fc980cff795db5404",
], ],
[ [
"48d78b8c2de1a515513f9d3fc464a19a72304fac522f17cc647706cb22c21403", "e07061a9ab6735de9a75b0c64f086c5b999894611d0cdc03f85c4e87c8aae602",
"5c0f10966b3f1386660a87de0fafd69decbe9ffae1a152a88b7d83bb4fb1c908", "38b17578e8e6ad4077071ce6b0bf9cb85ac35fee7868dcb6d9bfa97f0e153e0e",
], ],
], ],
sig_shares: &[ sig_shares: &[
"5ae13621ebeef844e39454eb3478a50c4531d25939e1065f44f5b04a8535090e", "a5f046916a6a111672111e47f9825586e1188da8a0f3b7c61f2b6b432c636e07",
"aa432dcf274a9441c205e76fe43497be99efe374f9853477bd5add2075f6970c", "4c175c7e43bd197980c2021774036eb288f54179f079fbf21b7d2f9f52846401",
], ],
sig: "9c407badb8cacf10f306d94e31fb2a71d6a8398039802b4d80a1278472397206".to_owned() + sig: "94b11def3f919503c3544452ad2a59f198f64cc323bd758bb1c65b42032a7473".to_owned() +
"17516e93f8d57a2ecffd43b83ab35db6de20b6ce32673bd601508e6bfa2ba10a", "f107a30fae272b8ff2d3205e6d86c3386a0ecf21916db3b93ba89ae27ee7d208",
}, },
); );
} }
@ -61,20 +61,20 @@ fn ed25519_vectors() {
included: &[1, 3], included: &[1, 3],
nonces: &[ nonces: &[
[ [
"1c406170127e33142b8611bc02bf14d5909e49d5cb87150eff3ec9804212920c", "4e64f59e90a3b9cdce346fae68eb0e459532c8ca1ad59a566c3ee2c67bf0100b",
"5be4edde8b7acd79528721191626810c94fbc2bcc814b7a67d301fbd7fc16e07", "470c660895c6db164ee6564120eec71023fa5297f09c663bb8171646c5632d00",
], ],
[ [
"795f87122f05b7efc4b1a52f435c3d28597411b1a6fec198ce9c818c5451c401", "6fc516495dbb364b807cdd0c2e5e3f58aa4914a53fed33cc340033979bb07304",
"c9193aaef37bc074ea3286d0361c815f7201bf764cd9e7d8bb4eb5ecca840a09", "0837e770a88147d41ff39138ca23b35d6cf303a4f148294755ede4b7e760d701",
], ],
], ],
sig_shares: &[ sig_shares: &[
"1f16a3989b4aa2cc3782a503331b9a21d7ba56c9c5455d06981b5425306c9d01", "3f2eb12735e5b39da97e884a6caadf6bb83f1efcec709d6f66333d0d67ebe707",
"4c8f33c301c05871b434a686847d5818417a01e50a59e9e7fddaefde7d244207", "79e572b8632fbb928519dd2eff793de8784a56d582ae48c807d39b0dc5b93509",
], ],
sig: "1aff2259ecb59cfcbb36ae77e02a9b134422abeae47cf7ff56c85fdf90932b18".to_owned() + sig: "e31e69a4e10d5ca2307c4a0d12cd86e3fceee550e55cb5b3f47c7ad6dbb38884".to_owned() +
"6ba5d65b9d0afb3decb64b8ab798f239183558aed09e46ee95f64304ae90df08", "cb3f2e837eb15cd858fb6dd68c2a3e3f318a74d16f1fe6376e06d91a2ca51d01",
}, },
); );
} }

View file

@ -86,47 +86,47 @@ fn ed448_non_ietf() {
nonces: &[ nonces: &[
[ [
concat!( concat!(
"f770bcb22f3c0acac7f09d3b757f13f31b53489776ede2cff944b4c0", "06f2e15b05d29a50f0686a890259f4dcf66147a80809ed9e50926f5f",
"cd28bb7dfbd33809e87201e152beeb552292eb748efa5267fa2dcd20", "173fe23a0627561efa003724dc270effc47a30bc4d80aba30725401d",
"00" "00"
), ),
concat!( concat!(
"d3196c7f14b1a99f1715053c00fa3a30b0fe9cbeb461068c262b1714", "e0482e611c34f191d1c13a09bc8bbf4bda68db4de32aa7908849b02b",
"78458a15598cc1c33cd415a766577996a6efcc520c411abf0280c816", "a912cfba46c805e2d8560ab9437e343e1dde6b481a2bae527e111b2c",
"00" "00"
), ),
], ],
[ [
concat!( concat!(
"9172a7cea56b7f564ed93116adf078ee013e4160e2687489ea580bc6", "295c56447c070157e6bc3c83ed2afca194569e07d0ad27d28a40dec2",
"f034f10e58db0b0cdf98bf1d3c85b2eb1f30b8b6df57b3611d205d2e", "c4107c07d507db20da1be62ea6976b8e53ab5d26e225c663f2e71511",
"00" "00"
), ),
concat!( concat!(
"3b60b4dc036b21441620a36c84b0ec780267a9275b411a495b182dc6", "b97303a6c5ab12b6ad310834361033a19d99dfdf93109da721da35c3",
"bfc812d1a21d93142d375b7ed80314d1693b61c1f42e20c575a4530e", "abbc5f29df33b3402692bef9f005bb8ea00af5ba20cc688360fd8831",
"00" "00"
), ),
], ],
], ],
sig_shares: &[ sig_shares: &[
concat!( concat!(
"95aeb18a46bac9e239d8eb51a7168da25a000d8a6938e26446c36e5d", "5b65641e27007ec71509c6af5cf8527eb01fee5b2b07d8beecf6646e",
"b88eff9523e0b09934558ddc8b2679bf2f10ed66415df1eb6e38a507", "b7e7e27d85119b74f895b56ba7561834a1b0c42639b122160a0b6208",
"00" "00"
), ),
concat!( concat!(
"521672ae547cd95b94a9be55b72a0dfb6938715230304d39017f5a54", "821b7ac04d7c01d970b0b3ba4ae8f737a5bac934aed1600b1cad7601",
"f1333a96da50a0759eea78bdb6b670c8243dbe706cd388763fe4c50b", "1c240629bce6a4671a1b6f572cec708ec161a72a5ca04e50eabdfc25",
"00" "00"
), ),
], ],
sig: concat!( sig: concat!(
"f1c2605fc0b724696dff10d2df0ac28939f40dc3d9ba864605462355", "c7ad7ad9fcfeef9d1492361ba641400bd3a3c8335a83cdffbdd8867d",
"c139229de643a6580e5807994cfcab0796644571c501cab00e85056a", "2849bb4419dcc3e594baa731081a1a00cd3dea9219a81ecba4646e95",
"00", "00",
"e7c423399b36a33ece81aaa75e419a9dc4387edc99682f9e4742c9b1", "dd80dede747c7fa086b9796aa7e04ab655dab790d9d838ca08a4db6f",
"a9c2392cfe30510fd33f069a42dde987544dabd7ad307a62ae1c6b13", "d30be9a641f83fdc12b124c3d34289c262126c5195517166f4c85e2e",
"00" "00"
) )
.to_string(), .to_string(),

View file

@ -27,20 +27,20 @@ fn secp256k1_vectors() {
included: &[1, 3], included: &[1, 3],
nonces: &[ nonces: &[
[ [
"95f352cf568508bce96ef3cb816bf9229eb521ca9c2aff6a4fe8b86bf49ae16f", "36d5c4185c40b02b5e4673e2531a10e6ff9883840a68ec08dbeb896467e21355",
"c675aea50ff2510ae6b0fcb55432b97ad0b55a28b959bacb0e8b466dbf43dd26", "7b3f573ca0a28f9f94522be4748df0ed04de8a83085aff4be7b01aa53fb6ac1b",
], ],
[ [
"b5089ebf363630d3477711005173c1419f4f40514f7287b4ca6ff110967a2d70", "ba4f8b8e587b2c9fc61a6156885f0bc67654b5e068c9e7749f75c09a98f17c13",
"5e50ce9975cfc6164e85752f52094b11091fdbca846a9c245fdbfa4bab1ae28c", "316de06639051ac7869e5ac4458eda1fef90ce93fa3c490556c4192e4fa550d0",
], ],
], ],
sig_shares: &[ sig_shares: &[
"280c44c6c37cd64c7f5a552ae8416a57d21c115cab524dbff5fbcebbf5c0019d", "f9ee00d5ac0c746b751dde99f71d86f8f0300a81bd0336ca6649ef597239e13f",
"e372bca35133a80ca140dcac2125c966b763a934678f40e09fb8b0ae9d4aee1b", "61048ca334ac6a6cb59d6b3ea2b25b7098e204adc09e2f88b024531b081d1d6f",
], ],
sig: "0364b02292a4b0e61f849f4d6fac0e67c2f698a21e1cba9e4a5b8fa535f2f9310d".to_owned() + sig: "023cf76388f92d403aa937af2e3cb3e7a2350e40400c16a282e330af2c60eeb85a".to_owned() +
"0b7f016a14b07e59209b31d7096733bfced0ddaa6398ee64d5e220ddc2d4ae77", "5af28d78e0b8ded82abb49d899cfe26ace633248ce58c617569be3e7aa20bd6d",
}, },
); );
} }
@ -64,20 +64,20 @@ fn p256_vectors() {
included: &[1, 3], included: &[1, 3],
nonces: &[ nonces: &[
[ [
"e9165dad654fc20a9e31ca6f32ac032ec327b551a50e8ac5cf25f5c4c9e20757", "9aa66350b0f72b27ce4668323b4280cd49709177ed8373977c22a75546c9995d",
"e9059a232598a0fba0e495a687580e624ab425337c3221246fb2c716905bc9e7", "bd8b05d7fd0ff5a5ed65b1f105478f7718a981741fa8fa9b55ac6d3c8fc59a05",
], ],
[ [
"b9d136e29eb758bd77cb83c317ac4e336cf8cda830c089deddf6d5ec81da9884", "4c1aec8e84c496b80af98415fada2e6a4b1f902d4bc6c9682699b8aeffd97419",
"5261e2d00ce227e67bb9b38990294e2c82970f335b2e6d9f1d07a72ba43d01f0", "eeaf5ef7af01e55050fb8acafc9c9306ef1cc13214677ba33e7bc51e8677e892",
], ],
], ],
sig_shares: &[ sig_shares: &[
"bdaa275f10ca57e3a3a9a7a0d95aeabb517897d8482873a8f9713d458f94756f", "ec5b8ab47d55903698492a07bb322ab6e7d3cf32581dcedf43c4fa18b46f3e10",
"0e8fd85386939e8974a8748e66641df0fe043323c52487a2b10b8a397897de21", "c97da3580560e88725a8e393d46fee18ecd2e00148e5e303d4a510fae9c11da5",
], ],
sig: "03c41521412528dce484c35b6b9b7cc8150102ab3e4bdf858d702270c05098e6c6".to_owned() + sig: "036b3eba585ff5d40df29893fb6f60572803aef97800cfaaaa5cf0f0f19d8237f7".to_owned() +
"cc39ffb2975df66d18521c2f3fbf08ac4f7ccafc0d4cfb4baa7cc77f082c5390", "b5d92e0d82b678bcbdf20d9b8fa218d017bfb485f9ec135e24b04050a1cd3664",
}, },
); );
} }

View file

@ -24,9 +24,12 @@ pub mod vectors;
#[cfg(test)] #[cfg(test)]
mod literal; mod literal;
/// Constant amount of participants to use when testing.
pub const PARTICIPANTS: u16 = 5; pub const PARTICIPANTS: u16 = 5;
/// Constant threshold of participants to use when signing.
pub const THRESHOLD: u16 = ((PARTICIPANTS / 3) * 2) + 1; pub const THRESHOLD: u16 = ((PARTICIPANTS / 3) * 2) + 1;
/// Clone a map without a specific value.
pub fn clone_without<K: Clone + std::cmp::Eq + std::hash::Hash, V: Clone>( pub fn clone_without<K: Clone + std::cmp::Eq + std::hash::Hash, V: Clone>(
map: &HashMap<K, V>, map: &HashMap<K, V>,
without: &K, without: &K,
@ -36,6 +39,7 @@ pub fn clone_without<K: Clone + std::cmp::Eq + std::hash::Hash, V: Clone>(
res res
} }
/// Generate FROST keys (as FrostCore objects) for tests.
pub fn core_gen<R: RngCore + CryptoRng, C: Curve>(rng: &mut R) -> HashMap<u16, FrostCore<C>> { pub fn core_gen<R: RngCore + CryptoRng, C: Curve>(rng: &mut R) -> HashMap<u16, FrostCore<C>> {
let mut machines = HashMap::new(); let mut machines = HashMap::new();
let mut commitments = HashMap::new(); let mut commitments = HashMap::new();
@ -91,10 +95,12 @@ pub fn core_gen<R: RngCore + CryptoRng, C: Curve>(rng: &mut R) -> HashMap<u16, F
.collect::<HashMap<_, _>>() .collect::<HashMap<_, _>>()
} }
/// Generate FROST keys for tests.
pub fn key_gen<R: RngCore + CryptoRng, C: Curve>(rng: &mut R) -> HashMap<u16, FrostKeys<C>> { pub fn key_gen<R: RngCore + CryptoRng, C: Curve>(rng: &mut R) -> HashMap<u16, FrostKeys<C>> {
core_gen(rng).drain().map(|(i, core)| (i, FrostKeys::new(core))).collect() core_gen(rng).drain().map(|(i, core)| (i, FrostKeys::new(core))).collect()
} }
/// Recover the secret from a collection of keys.
pub fn recover<C: Curve>(keys: &HashMap<u16, FrostKeys<C>>) -> C::F { pub fn recover<C: Curve>(keys: &HashMap<u16, FrostKeys<C>>) -> C::F {
let first = keys.values().next().expect("no keys provided"); let first = keys.values().next().expect("no keys provided");
assert!(keys.len() >= first.params().t().into(), "not enough keys provided"); assert!(keys.len() >= first.params().t().into(), "not enough keys provided");
@ -107,6 +113,7 @@ pub fn recover<C: Curve>(keys: &HashMap<u16, FrostKeys<C>>) -> C::F {
group_private group_private
} }
/// Spawn algorithm machines for a random selection of signers, each executing the given algorithm.
pub fn algorithm_machines<R: RngCore, C: Curve, A: Algorithm<C>>( pub fn algorithm_machines<R: RngCore, C: Curve, A: Algorithm<C>>(
rng: &mut R, rng: &mut R,
algorithm: A, algorithm: A,
@ -136,6 +143,7 @@ pub fn algorithm_machines<R: RngCore, C: Curve, A: Algorithm<C>>(
.collect() .collect()
} }
/// Execute the signing protocol.
pub fn sign<R: RngCore + CryptoRng, M: PreprocessMachine>( pub fn sign<R: RngCore + CryptoRng, M: PreprocessMachine>(
rng: &mut R, rng: &mut R,
mut machines: HashMap<u16, M>, mut machines: HashMap<u16, M>,