* add commit(), use it instead of preprocess()

* use a single scalarmul in compute_group_commitment per v5 spec

* add nonce_generate() from the spec and use it

* remove Order() from Group trait since it's not used

* style: carriage return

* use Secret instead of KeyPackage in some methods

* change commit to take explicit params and not return vectors

* removed unused import

Co-authored-by: Conrado Gouvea <conradoplg@gmail.com>
This commit is contained in:
Deirdre Connolly 2022-07-19 16:17:20 -04:00 committed by GitHub
parent af2839f6dc
commit 4cb11ec393
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 311 additions and 216 deletions

View File

@ -61,7 +61,7 @@ let mut commitments: HashMap<u16, Vec<frost::round1::SigningCommitments>> = Hash
for participant_index in 1..(threshold + 1) {
// Generate one (1) nonce and one SigningCommitments instance for each
// participant, up to _threshold_.
let (nonce, commitment) = frost::round1::preprocess(1, participant_index as u16, &mut rng);
let (nonce, commitment) = frost::round1::commit(participant_index as u16, &mut rng);
nonces.insert(participant_index as u16, nonce);
commitments.insert(participant_index as u16, commitment);
}

View File

@ -247,7 +247,8 @@ where
let identity = <C::Group as Group>::identity();
let mut accumulator = <C::Group as Group>::identity();
let mut group_hiding_commitment = <C::Group as Group>::identity();
let mut group_binding_commitment = <C::Group as Group>::identity();
// Ala the sorting of B, just always sort by index in ascending order
//
@ -258,11 +259,13 @@ where
if identity == commitment.binding.0 || identity == commitment.hiding.0 {
return Err("Commitment equals the identity.");
}
accumulator = accumulator + (commitment.hiding.0 + (commitment.binding.0 * rho.0))
group_hiding_commitment = group_hiding_commitment + commitment.hiding.0;
group_binding_commitment = group_binding_commitment + commitment.binding.0;
}
Ok(GroupCommitment(accumulator))
Ok(GroupCommitment(
group_hiding_commitment + group_binding_commitment * rho.0,
))
}
}

View File

@ -203,7 +203,7 @@ where
///
/// An implementation of `vss_verify()` from the [spec].
///
/// [spec]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-04.html#appendix-B.2-4
/// [spec]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-05.html#appendix-B.2-5
pub fn verify(&self) -> Result<(), &'static str> {
let f_result = <C::Group as Group>::generator() * self.value.0;

View File

@ -8,6 +8,8 @@ use zeroize::Zeroize;
use crate::{frost, Ciphersuite, Error, Field, Group};
use super::keys::Secret;
/// A scalar that is a signing nonce.
#[derive(Clone, PartialEq, Zeroize)]
pub struct Nonce<C: Ciphersuite>(pub(super) <<C::Group as Group>::Field as Field>::Scalar);
@ -16,21 +18,32 @@ impl<C> Nonce<C>
where
C: Ciphersuite,
{
/// Generates a new uniformly random signing nonce.
/// Generates a new uniformly random signing nonce by sourcing fresh
/// randomness and combining with the secret key, to hedge against a bad
/// RNG.
///
/// Each participant generates signing nonces before performing a signing
/// operation.
///
/// An implementation of `RandomNonzeroScalar()` from the [spec].
/// An implementation of `nonce_generate(secret)` from the [spec].
///
/// [spec]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-04.html#section-3.1-3.4
pub fn random<R>(rng: &mut R) -> Self
/// [spec]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-05.html#name-nonce-generation
pub fn new<R>(secret: &Secret<C>, rng: &mut R) -> Self
where
R: CryptoRng + RngCore,
{
// The values of 'hiding' and 'binding' nonces must be non-zero so that commitments are
// not the identity.
Self(<<C::Group as Group>::Field as Field>::random_nonzero(rng))
let mut k_enc = [0; 32];
rng.fill_bytes(&mut k_enc[..]);
let secret_enc = <<C::Group as Group>::Field as Field>::serialize(&secret.0);
let input: Vec<u8> = k_enc
.iter()
.chain(secret_enc.as_ref().iter())
.cloned()
.collect();
Self(C::H4(input.as_slice()))
}
/// Deserialize [`Nonce`] from bytes
@ -154,14 +167,14 @@ where
///
/// Each participant generates signing nonces before performing a signing
/// operation.
pub fn new<R>(rng: &mut R) -> Self
pub fn new<R>(secret: &Secret<C>, rng: &mut R) -> Self
where
R: CryptoRng + RngCore,
{
// The values of 'hiding' and 'binding' must be non-zero so that commitments are
// not the identity.
let hiding = Nonce::<C>::random(rng);
let binding = Nonce::<C>::random(rng);
let hiding = Nonce::<C>::new(secret, rng);
let binding = Nonce::<C>::new(secret, rng);
Self { hiding, binding }
}
@ -273,6 +286,9 @@ pub(super) fn encode_group_commitments<C: Ciphersuite>(
/// Done once by each participant, to generate _their_ nonces and commitments
/// that are then used during signing.
///
/// This is only needed if pre-processing is needed (for 1-round FROST). For
/// regular 2-round FROST, use [`commit`].
///
/// When performing signing using two rounds, num_nonces would equal 1, to
/// perform the first round. Batching entails generating more than one
/// nonce/commitment pair at a time. Nonces should be stored in secret storage
@ -285,6 +301,7 @@ pub(super) fn encode_group_commitments<C: Ciphersuite>(
pub fn preprocess<C, R>(
num_nonces: u8,
participant_index: u16,
secret: &Secret<C>,
rng: &mut R,
) -> (Vec<SigningNonces<C>>, Vec<SigningCommitments<C>>)
where
@ -296,10 +313,35 @@ where
Vec::with_capacity(num_nonces as usize);
for _ in 0..num_nonces {
let nonces = SigningNonces::new(rng);
let nonces = SigningNonces::new(secret, rng);
signing_commitments.push(SigningCommitments::from((participant_index, &nonces)));
signing_nonces.push(nonces);
}
(signing_nonces, signing_commitments)
}
/// Performed once by each participant selected for the signing operation.
///
/// Implements [`commit`] from the spec.
///
/// Generates the signing nonces and commitments to be used in the signing
/// operation.
///
/// [`commit`]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-05.html#section-5.1
pub fn commit<C, R>(
participant_index: u16,
secret: &Secret<C>,
rng: &mut R,
) -> (SigningNonces<C>, SigningCommitments<C>)
where
C: Ciphersuite,
R: CryptoRng + RngCore,
{
let (mut vec_signing_nonces, mut vec_signing_commitments) =
preprocess(1, participant_index, secret, rng);
(
vec_signing_nonces.pop().expect("must have 1 element"),
vec_signing_commitments.pop().expect("must have 1 element"),
)
}

View File

@ -58,18 +58,18 @@ pub trait Field: Copy + Clone {
/// Generate a random scalar from the entire space [0, l-1]
///
/// <https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-04.html#section-3.1-3.3>
/// <https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-05.html#section-3.1-3.3>
fn random<R: RngCore + CryptoRng>(rng: &mut R) -> Self::Scalar;
/// Generate a random scalar from the entire space [1, l-1]
///
/// <https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-04.html#section-3.1-3.4>
/// <https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-05.html#section-3.1-3.4>
fn random_nonzero<R: RngCore + CryptoRng>(rng: &mut R) -> Self::Scalar;
/// A member function of a group _G_ that maps an [`Element`] to a unique byte array buf of
/// fixed length Ne.
///
/// <https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-04.html#section-3.1-3.5>
/// <https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-05.html#section-3.1-3.7>
fn serialize(scalar: &Self::Scalar) -> Self::Serialization;
/// A member function of a [`Group`] that attempts to map a byte array `buf` to an [`Element`].
@ -78,7 +78,7 @@ pub trait Field: Copy + Clone {
/// [`Group`]. This function can raise a [`DeserializeError`] if deserialization fails or if the
/// resulting [`Element`] is the identity element of the group
///
/// <https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-04.html#section-3.1-3.6>
/// <https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-05.html#section-3.1-3.8>
fn deserialize(buf: &Self::Serialization) -> Result<Self::Scalar, Error>;
}
@ -111,11 +111,6 @@ pub trait Group: Copy + Clone {
/// Little-endian!
type Serialization: AsRef<[u8]> + TryFrom<Vec<u8>>;
/// Outputs the order of G (i.e. p)
///
/// <https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-04.html#section-3.1-3.1>
fn order() -> <Self::Field as Field>::Scalar;
/// The order of the the quotient group when the prime order subgroup divides the order of the
/// full curve group.
///
@ -126,19 +121,19 @@ pub trait Group: Copy + Clone {
/// Additive [identity] of the prime order group.
///
/// [identity]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-04.html#section-3.1-3.2
/// [identity]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-05.html#section-3.1-3.2
fn identity() -> Self::Element;
/// The fixed generator element of the prime order group.
///
/// The 'base' of [`ScalarBaseMult()`] from the spec.
/// [`ScalarBaseMult()`]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-04.html#section-3.1
/// [`ScalarBaseMult()`]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-05.html#section-3.1
fn generator() -> Self::Element;
/// A member function of a group _G_ that maps an [`Element`] to a unique byte array buf of
/// fixed length Ne.
///
/// <https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-04.html#section-3.1-3.5>
/// <https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-05.html#section-3.1-3.5>
fn serialize(element: &Self::Element) -> Self::Serialization;
/// A member function of a [`Group`] that attempts to map a byte array `buf` to an [`Element`].
@ -147,7 +142,7 @@ pub trait Group: Copy + Clone {
/// [`Group`]. This function can raise a [`DeserializeError`] if deserialization fails or if the
/// resulting [`Element`] is the identity element of the group
///
/// <https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-04.html#section-3.1-3.6>
/// <https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-05.html#section-3.1-3.6>
fn deserialize(buf: &Self::Serialization) -> Result<Self::Element, Error>;
}
@ -157,7 +152,7 @@ pub type Element<C> = <<C as Ciphersuite>::Group as Group>::Element;
/// A [FROST ciphersuite] specifies the underlying prime-order group details and cryptographic hash
/// function.
///
/// [FROST ciphersuite]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-04.html#name-ciphersuites
/// [FROST ciphersuite]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-05.html#name-ciphersuites
pub trait Ciphersuite: Copy + Clone {
/// The prime order group (or subgroup) that this ciphersuite operates over.
type Group: Group;
@ -189,11 +184,18 @@ pub trait Ciphersuite: Copy + Clone {
///
/// [spec]: https://github.com/cfrg/draft-irtf-cfrg-frost/blob/master/draft-irtf-cfrg-frost.md#cryptographic-hash
fn H3(m: &[u8]) -> Self::HashOutput;
/// [H4] for a FROST ciphersuite.
///
/// Maps arbitrary inputs to non-zero `Self::Scalar` elements of the prime-order group scalar field.
///
/// [H4]: https://github.com/cfrg/draft-irtf-cfrg-frost/blob/master/draft-irtf-cfrg-frost.md#cryptographic-hash
fn H4(m: &[u8]) -> <<Self::Group as Group>::Field as Field>::Scalar;
}
/// A type refinement for the scalar field element representing the per-message _[challenge]_.
///
/// [challenge]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-04.html#name-signature-challenge-computa
/// [challenge]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-05.html#name-signature-challenge-computa
#[derive(Clone)]
pub struct Challenge<C: Ciphersuite>(
pub(crate) <<<C as Ciphersuite>::Group as Group>::Field as Field>::Scalar,
@ -219,8 +221,8 @@ where
///
/// This is the only invocation of the H2 hash function from the [RFC].
///
/// [FROST]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-04.html#section-4.6
/// [RFC]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-04.html#section-3.2
/// [FROST]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-05.html#section-4.7
/// [RFC]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-05.html#section-3.2
fn challenge<C>(
R: &<C::Group as Group>::Element,
verifying_key: &<C::Group as Group>::Element,

View File

@ -1,7 +1,7 @@
#![allow(non_snake_case)]
use curve25519_dalek::{
constants::{BASEPOINT_ORDER, RISTRETTO_BASEPOINT_POINT},
constants::RISTRETTO_BASEPOINT_POINT,
ristretto::{CompressedRistretto, RistrettoPoint},
scalar::Scalar,
traits::Identity,
@ -74,10 +74,6 @@ impl Group for RistrettoGroup {
type Serialization = [u8; 32];
fn order() -> <Self::Field as Field>::Scalar {
BASEPOINT_ORDER
}
fn cofactor() -> <Self::Field as Field>::Scalar {
Scalar::one()
}
@ -102,10 +98,10 @@ impl Group for RistrettoGroup {
}
}
/// Context string 'FROST-RISTRETTO255-SHA512' from the ciphersuite in the [spec]
/// Context string 'FROST-RISTRETTO255-SHA512-v5' from the ciphersuite in the [spec]
///
/// [spec]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-04.txt
const CONTEXT_STRING: &str = "FROST-RISTRETTO255-SHA512";
/// [spec]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-05.html#section-6.2-1
const CONTEXT_STRING: &str = "FROST-RISTRETTO255-SHA512-v5";
#[derive(Clone, Copy, PartialEq)]
pub struct Ristretto255Sha512;
@ -158,6 +154,17 @@ impl Ciphersuite for Ristretto255Sha512 {
output.copy_from_slice(h.finalize().as_slice());
output
}
fn H4(m: &[u8]) -> <<Self::Group as Group>::Field as Field>::Scalar {
let h = Sha512::new()
.chain(CONTEXT_STRING.as_bytes())
.chain("nonce")
.chain(m);
let mut output = [0u8; 64];
output.copy_from_slice(h.finalize().as_slice());
<<Self::Group as Group>::Field as Field>::Scalar::from_bytes_mod_order_wide(&output)
}
}
#[test]

View File

@ -1,59 +1,59 @@
{
"config": {
"MAX_SIGNERS": "3",
"NUM_SIGNERS": "2",
"THRESHOLD_LIMIT": "2",
"name": "FROST(ristretto255, SHA-512)",
"group": "ristretto255",
"hash": "SHA-512"
},
"inputs": {
"group_secret_key": "b120be204b5e758960458ca9c4675b56b12a8faff2be9c94891d5e1cd75c880e",
"group_public_key": "563b80013f337deaa2a282af7b281bd70d2f501928a89c1aa48b379a5ac4202b",
"message": "74657374",
"signers": {
"1": {
"signer_share": "94ae65bb90030a89507fa00fff08dfed841cf996de5a0c574f1f4693ddcb6705"
},
"2": {
"signer_share": "641003b3f00bb1e01656ac1818a4419a580e637ecaf67b1915212e0ae43a470c"
},
"3": {
"signer_share": "479eaa4d36b145e00690c07e5245c5312c00cd65b692ebdbda221681eaa92603"
}
"config": {
"MAX_SIGNERS": "3",
"NUM_SIGNERS": "2",
"MIN_SIGNERS": "2",
"name": "FROST(ristretto255, SHA-512)",
"group": "ristretto255",
"hash": "SHA-512"
},
"inputs": {
"group_secret_key": "1b25a55e463cfd15cf14a5d3acc3d15053f08da49c8afcf3ab265f2ebc4f970b",
"group_public_key": "e2a62f39eede11269e3bd5a7d97554f5ca384f9f6d3dd9c3c0d05083c7254f57",
"message": "74657374",
"signers": {
"1": {
"signer_share": "5c3430d391552f6e60ecdc093ff9f6f4488756aa6cebdbad75a768010b8f830e"
},
"2": {
"signer_share": "b06fc5eac20b4f6e1b271d9df2343d843e1e1fb03c4cbb673f2872d459ce6f01"
},
"3": {
"signer_share": "f17e505f0e2581c6acfe54d3846a622834b5e7b50cad9a2109a97ba7a80d5c04"
}
},
"round_one_outputs": {
"participants": "1,2",
"group_binding_factor_input": "0001824e9eddddf02b2a9caf5859825e999d791ca094f65b814a8bca6013d9cc312774c7e1271d2939a84a9a867e3a06579b4d25659b427439ccf0d745b43f75b76600028013834ff4d48e7d6b76c2e732bc611f54720ef8933c4ca4de7eaaa77ff5cd125e056ecc4f7c4657d3a742354430d768f945db229c335d258e9622ad99f3e7582d07b35bd9849ce4af6ad403090d69a7d0eb88bba669a9f985175d70cd15ad5f1ef5b734c98a32b4aab7b43a57e93fc09281f2e7a207076b31e416ba63f53d9d",
"group_binding_factor": "f00ae6007f2d74a1507c962cf30006be77596106db28f2d5443fd66d755e780c",
"signers": {
"1": {
"hiding_nonce": "349b3bb8464a1d87f7d6b56f4559a3f9a6335261a3266089a9b12d9d6f6ce209",
"binding_nonce": "ce7406016a854be4291f03e7d24fe30e77994c3465de031515a4c116f22ca901",
"hiding_nonce_commitment": "824e9eddddf02b2a9caf5859825e999d791ca094f65b814a8bca6013d9cc3127",
"binding_nonce_commitment": "74c7e1271d2939a84a9a867e3a06579b4d25659b427439ccf0d745b43f75b766"
},
"2": {
"hiding_nonce": "4d66d319f20a728ec3d491cbf260cc6be687bd87cc2b5fdb4d5f528f65fd650d",
"binding_nonce": "278b9b1e04632e6af3f1a3c144d07922ffcf5efd3a341b47abc19c43f48ce306",
"hiding_nonce_commitment": "8013834ff4d48e7d6b76c2e732bc611f54720ef8933c4ca4de7eaaa77ff5cd12",
"binding_nonce_commitment": "5e056ecc4f7c4657d3a742354430d768f945db229c335d258e9622ad99f3e758"
}
}
},
"round_two_outputs": {
"participants": "1,2",
"signers": {
"1": {
"sig_share": "ec6b075f17c5670e80b1fda8f6de1cfe3c79db06a852f8d5650fb71eaad69501"
},
"2": {
"sig_share": "87ceccc477069aa9b751b307f25955daaf943a3abc51f214a114781de0f58e03"
}
}
},
"final_output": {
"sig": "7e92309bf40993141acd5f2c7680a302cc5aa5dd291a833906da8e35bc39b03e733ad4238fcb01b83703b1b0e83872d8ec0d164164a4eaea06242f3c8acc2405"
}
},
"round_one_outputs": {
"participants": "1,3",
"group_binding_factor_input": "00015c01341bd0a948e71fe1b9bf09f8b8ee258bfcf3abddee42ef74c8068e0b224584a209c6c3e812283378fb6a15e4b9a64aa9eed51f7ae405d09b56ee56bc58500003c0fc5ffaf124fa69206a9ed77bd57fa1d8ca505f6139794f82778ce15ee0be3cb6718f8139e49d08741ab9f030da29e557451eab58bc770c0c05ef4e2ff8001e678630bf982c566949d7f22d2aefb94f252c664216d332f34e2c8fdcd7045f207f854504d0daa534a5b31dbdf4183be30eb4fdba4f962d8a6b69cf20c2734043",
"group_binding_factor": "af4288aad52765341b2238007777ea2bb2d0dfb4e92423b0646d4bec426e3d0d",
"signers": {
"1": {
"hiding_nonce": "b358743151e33d84bf00c12f71808f4103957c3e2cabab7b895c436b5e70f90c",
"binding_nonce": "7bd112153b9ae1ab9b31f5e78f61f5c4ca9ee67b7ea6d1181799c409d14c350c",
"hiding_nonce_commitment": "5c01341bd0a948e71fe1b9bf09f8b8ee258bfcf3abddee42ef74c8068e0b2245",
"binding_nonce_commitment": "84a209c6c3e812283378fb6a15e4b9a64aa9eed51f7ae405d09b56ee56bc5850"
},
"3": {
"hiding_nonce": "22acad88478e0d0373a991092a322ebd1b9a2dad90451a976d0db3215426af0e",
"binding_nonce": "9155e3d7bcf7cd468b980c7e20b2c77cbdfbe33a1dcae031fd8bc6b1403f4b04",
"hiding_nonce_commitment": "c0fc5ffaf124fa69206a9ed77bd57fa1d8ca505f6139794f82778ce15ee0be3c",
"binding_nonce_commitment": "b6718f8139e49d08741ab9f030da29e557451eab58bc770c0c05ef4e2ff8001e"
}
}
},
"round_two_outputs": {
"participants": "1,3",
"signers": {
"1": {
"sig_share": "ff801b4e0839faa67f16dee4127b9f7fbcf5fd007900257b0e2bbc02cbe5e709"
},
"3": {
"sig_share": "afdf5481023c855bf3411a5c8a5fafa92357296a078c3b80dc168f294cb4f504"
}
}
},
"final_output": {
"sig": "deae61af10e8ee48ba492573592fba547f5debeff6bd6e2024e8673584746f5eae6070cf0a757f027358f8409dda4e29e04c276b808c60fbea414b2c179add0e"
}
}

View File

@ -26,8 +26,8 @@ fn check_sign_with_dealer() {
.map(|share| frost::keys::KeyPackage::try_from(share).unwrap())
.collect();
let mut nonces: HashMap<u16, Vec<frost::round1::SigningNonces<R>>> = HashMap::new();
let mut commitments: HashMap<u16, Vec<frost::round1::SigningCommitments<R>>> = HashMap::new();
let mut nonces: HashMap<u16, frost::round1::SigningNonces<R>> = HashMap::new();
let mut commitments: HashMap<u16, frost::round1::SigningCommitments<R>> = HashMap::new();
////////////////////////////////////////////////////////////////////////////
// Round 1: generating nonces and signing commitments for each participant
@ -36,7 +36,14 @@ fn check_sign_with_dealer() {
for participant_index in 1..(threshold + 1) {
// Generate one (1) nonce and one SigningCommitments instance for each
// participant, up to _threshold_.
let (nonce, commitment) = frost::round1::preprocess(1, participant_index as u16, &mut rng);
let (nonce, commitment) = frost::round1::commit(
participant_index as u16,
key_packages
.get((participant_index - 1) as usize)
.unwrap()
.secret_share(),
&mut rng,
);
nonces.insert(participant_index as u16, nonce);
commitments.insert(participant_index as u16, commitment);
}
@ -46,7 +53,7 @@ fn check_sign_with_dealer() {
// - take one (unused) commitment per signing participant
let mut signature_shares: Vec<frost::round2::SignatureShare<R>> = Vec::new();
let message = "message to sign".as_bytes();
let comms = commitments.clone().into_values().flatten().collect();
let comms = commitments.clone().into_values().collect();
let signing_package = frost::SigningPackage::new(comms, message.to_vec());
////////////////////////////////////////////////////////////////////////////
@ -59,7 +66,7 @@ fn check_sign_with_dealer() {
.find(|key_package| *participant_index == key_package.index)
.unwrap();
let nonces_to_use = &nonces.get(participant_index).unwrap()[0];
let nonces_to_use = &nonces.get(participant_index).unwrap();
// Each participant generates their signature share.
let signature_share =

View File

@ -94,11 +94,6 @@ impl Group for P256Group {
/// [1]: https://secg.org/sec1-v2.pdf
type Serialization = [u8; 33];
fn order() -> <Self::Field as Field>::Scalar {
// TODO: rethink this, no way to represent the order in `Scalar`
Scalar::zero()
}
fn cofactor() -> <Self::Field as Field>::Scalar {
Scalar::one()
}
@ -141,8 +136,8 @@ impl Group for P256Group {
/// Context string from the ciphersuite in the [spec]
///
/// [spec]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-04.txt
const CONTEXT_STRING: &str = "FROST-P256-SHA256";
/// [spec]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-05.html#section-6.4-1
const CONTEXT_STRING: &str = "FROST-P256-SHA256-v5";
#[derive(Clone, Copy, PartialEq)]
/// An implementation of the FROST ciphersuite FROST(P-256, SHA-256).
@ -157,7 +152,7 @@ impl Ciphersuite for P256Sha256 {
/// H1 for FROST(P-256, SHA-256)
///
/// [spec]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-04.html#name-frostp-256-sha-256
/// [spec]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-05.html#section-6.4-2.2.2.1
fn H1(m: &[u8]) -> <<Self::Group as Group>::Field as Field>::Scalar {
let mut u = [P256ScalarField::zero()];
let dst = CONTEXT_STRING.to_owned() + "rho";
@ -168,7 +163,7 @@ impl Ciphersuite for P256Sha256 {
/// H2 for FROST(P-256, SHA-256)
///
/// [spec]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-04.html#name-frostp-256-sha-256
/// [spec]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-05.html#section-6.4-2.2.2.2
fn H2(m: &[u8]) -> <<Self::Group as Group>::Field as Field>::Scalar {
let mut u = [P256ScalarField::zero()];
let dst = CONTEXT_STRING.to_owned() + "chal";
@ -179,7 +174,7 @@ impl Ciphersuite for P256Sha256 {
/// H3 for FROST(P-256, SHA-256)
///
/// [spec]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-04.html#name-frostp-256-sha-256
/// [spec]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-05.html#section-6.4-2.2.2.3
fn H3(m: &[u8]) -> Self::HashOutput {
let h = Sha256::new()
.chain(CONTEXT_STRING.as_bytes())
@ -190,6 +185,17 @@ impl Ciphersuite for P256Sha256 {
output.copy_from_slice(h.finalize().as_slice());
output
}
/// H4 for FROST(P-256, SHA-256)
///
/// [spec]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-05.html#section-6.4-2.2.2.4
fn H4(m: &[u8]) -> <<Self::Group as Group>::Field as Field>::Scalar {
let mut u = [P256ScalarField::zero()];
let dst = CONTEXT_STRING.to_owned() + "nonce";
hash_to_field::<ExpandMsgXmd<Sha256>, Scalar>(&vec![m], dst.as_bytes(), &mut u)
.expect("should never return error according to error cases described in ExpandMsgXmd");
u[0]
}
}
// Shorthand alias for the ciphersuite
@ -220,6 +226,8 @@ pub mod keys {
///
pub mod round1 {
use frost_core::frost::keys::{Secret};
use super::*;
///
pub type SigningNonces = frost::round1::SigningNonces<P>;
@ -228,15 +236,15 @@ pub mod round1 {
pub type SigningCommitments = frost::round1::SigningCommitments<P>;
///
pub fn preprocess<RNG>(
num_nonces: u8,
pub fn commit<RNG>(
participant_index: u16,
secret: &Secret<P>,
rng: &mut RNG,
) -> (Vec<SigningNonces>, Vec<SigningCommitments>)
) -> (SigningNonces, SigningCommitments)
where
RNG: CryptoRng + RngCore,
{
frost::round1::preprocess::<P, RNG>(num_nonces, participant_index, rng)
frost::round1::commit::<P, RNG>(participant_index, secret, rng)
}
}

View File

@ -2,58 +2,58 @@
"config": {
"MAX_SIGNERS": "3",
"NUM_SIGNERS": "2",
"THRESHOLD_LIMIT": "2",
"MIN_SIGNERS": "2",
"name": "FROST(P-256, SHA-256)",
"group": "P-256",
"hash": "SHA-256"
},
"inputs": {
"group_secret_key": "6f090d1393ff53bbcbba036c00b8830ab4546c251dece199eb03a6a51a5a5929",
"group_public_key": "03db0945167b62e6472ad46373b6cbbca88e2a9a4883071f0b3fde4b2b6d7b6ba6",
"group_secret_key": "8ba9bba2e0fd8c4767154d35a0b7562244a4aaf6f36c8fb8735fa48b301bd8de",
"group_public_key": "023a309ad94e9fe8a7ba45dfc58f38bf091959d3c99cfbd02b4dc00585ec45ab70",
"message": "74657374",
"signers": {
"1": {
"signer_share": "738552e18ea4f2090597aca6c23c1666845c21c676813f9e26786f1e410dcecf"
"signer_share": "0c9c1a0fe806c184add50bbdcac913dda73e482daf95dcb9f35dbb0d8a9f7731"
},
"2": {
"signer_share": "780198af894a90563f7555e183bfa9c25463d767cf159da261ed379767c14475"
"signer_share": "8d8e787bef0ff6c2f494ca45f4dad198c6bee01212d6c84067159c52e1863ad5"
},
"3": {
"signer_share": "7c7dde7d83f02ea37952ff1c45433d1e246b8d0927a9fba69d6200108e74ba1b"
"signer_share": "0e80d6e8f6192c003b5488ce1eec8f5429587d48cf001541e713b2d53c09d928"
}
}
},
"round_one_outputs": {
"participants": "1,2",
"group_binding_factor_input": "000102f34caab210d59324e12ba41f0802d9545f7f702906930766b86c462bb8ff7f3402b724640ea9e262469f401c9006991ba3247c2c91b97cdb1f0eeab1a777e24e1e0002037f8a998dfc2e60a7ad63bc987cb27b8abf78a68bd924ec6adb9f251850cbe711024a4e90422a19dd8463214e997042206c39d3df56168b458592462090c89dbcf84efca0c54f70a585d6aae28679482b4aed03ae5d38297b9092ab3376d46fdf55",
"group_binding_factor": "9df349a9f34bf01627f6b4f8b376e8c8261d55508d1cac2919cdaf7f9cb20e70",
"participants": "1,3",
"group_binding_factor_input": "000102688facca4e2540ef303734c5aee8e7cdba0bc7ab94abfe63d05ebc68dde0f4c702ae64b6f0506acc3395fecd4bc70a9eb9f8e5394264c2d2aa0c8faff857ea3058000303c21b8ee50b6478ac845c0687504db6792873f5a327ff6a3115558070b517299302f3c73c912838f707f549bf4d63432f1fbe128fa35ec8ba6eca849ebd248aa46a7a753fed12531fbcd151e1d84702927c39063e780e91c01f02bd11b60d7632bf",
"group_binding_factor": "cf7ffe4b8ad6edb6237efaa8cbfb2dfb2fd08d163b6ad9063720f14779a9e143",
"signers": {
"1": {
"hiding_nonce": "3da92a503cf7e3f72f62dabedbb3ffcc9f555f1c1e78527940fe3fed6d45e56f",
"binding_nonce": "ec97c41fc77ae7e795067976b2edd8b679f792abb062e4d0c33f0f37d2e363eb",
"hiding_nonce_commitment": "02f34caab210d59324e12ba41f0802d9545f7f702906930766b86c462bb8ff7f34",
"binding_nonce_commitment": "02b724640ea9e262469f401c9006991ba3247c2c91b97cdb1f0eeab1a777e24e1e"
"hiding_nonce": "081617b24375e069b39f649d4c4ce2fba6e38b73e7c16759de0b6079a22c4c7e",
"binding_nonce": "4de5fb77d99f03a2491a83a6a4cb91ca3c82a3f34ce94cec939174f47c9f95dd",
"hiding_nonce_commitment": "02688facca4e2540ef303734c5aee8e7cdba0bc7ab94abfe63d05ebc68dde0f4c7",
"binding_nonce_commitment": "02ae64b6f0506acc3395fecd4bc70a9eb9f8e5394264c2d2aa0c8faff857ea3058"
},
"2": {
"hiding_nonce": "06cb4425031e695d1f8ac61320717d63918d3edc7a02fcd3f23ade47532b1fd9",
"binding_nonce": "2d965a4ea73115b8065c98c1d95c7085db247168012a834d8285a7c02f11e3e0",
"hiding_nonce_commitment": "037f8a998dfc2e60a7ad63bc987cb27b8abf78a68bd924ec6adb9f251850cbe711",
"binding_nonce_commitment": "024a4e90422a19dd8463214e997042206c39d3df56168b458592462090c89dbcf8"
"3": {
"hiding_nonce": "d186ea92593f83ea83181b184d41aa93493301ac2bc5b4b1767e94d2db943e38",
"binding_nonce": "486e2ee25a3fbc8e6399d748b077a2755fde99fa85cc24fa647ea4ebf5811a15",
"hiding_nonce_commitment": "03c21b8ee50b6478ac845c0687504db6792873f5a327ff6a3115558070b5172993",
"binding_nonce_commitment": "02f3c73c912838f707f549bf4d63432f1fbe128fa35ec8ba6eca849ebd248aa46a"
}
}
},
"round_two_outputs": {
"participants": "1,2",
"participants": "1,3",
"signers": {
"1": {
"sig_share": "120a8ef8a5936444d8087cb10df5648629895e94582720760a10c8c217e3417b"
"sig_share": "9e4d8865faf8c7b3193a3b35eda3d9e12118447114b1e7d5b4809ea28067f8a9"
},
"2": {
"sig_share": "2a7ff42d849f1bcc0e5f75d5810900a3e8f68ab717ff10d7a6da89f8bb0c16aa"
"3": {
"sig_share": "b7d094eab6305ae74daeed1acd31abba9ab81f638d38b72c132cb25a5dfae1fc"
}
}
},
"final_output": {
"sig": "035cfbd148da711bbc823455b682ed01a1be3c5415cf692f4a91b7fe22d1dec3453c8a83262a328010e667f2868efe652a127fe94b7026314db0eb52bad2ef5825"
"sig": "0342c14c77f9d4ef9b8bd64fb0d7bbfdb9f8216a44e5f7bbe6ac0f3ed5e1a57367561e1d51b129229966e92850bad5859bfee96926fad3007cd3f38639e1ffb554"
}
}

View File

@ -21,8 +21,8 @@ fn check_sign_with_dealer() {
.map(|share| keys::KeyPackage::try_from(share).unwrap())
.collect();
let mut nonces: HashMap<u16, Vec<round1::SigningNonces>> = HashMap::new();
let mut commitments: HashMap<u16, Vec<round1::SigningCommitments>> = HashMap::new();
let mut nonces: HashMap<u16, round1::SigningNonces> = HashMap::new();
let mut commitments: HashMap<u16, round1::SigningCommitments> = HashMap::new();
////////////////////////////////////////////////////////////////////////////
// Round 1: generating nonces and signing commitments for each participant
@ -31,7 +31,14 @@ fn check_sign_with_dealer() {
for participant_index in 1..(threshold + 1) {
// Generate one (1) nonce and one SigningCommitments instance for each
// participant, up to _threshold_.
let (nonce, commitment) = round1::preprocess(1, participant_index as u16, &mut rng);
let (nonce, commitment) = round1::commit(
participant_index as u16,
key_packages
.get((participant_index - 1) as usize)
.unwrap()
.secret_share(),
&mut rng,
);
nonces.insert(participant_index as u16, nonce);
commitments.insert(participant_index as u16, commitment);
}
@ -41,7 +48,7 @@ fn check_sign_with_dealer() {
// - take one (unused) commitment per signing participant
let mut signature_shares: Vec<round2::SignatureShare> = Vec::new();
let message = "message to sign".as_bytes();
let comms = commitments.clone().into_values().flatten().collect();
let comms = commitments.clone().into_values().collect();
let signing_package = SigningPackage::new(comms, message.to_vec());
////////////////////////////////////////////////////////////////////////////
@ -54,7 +61,7 @@ fn check_sign_with_dealer() {
.find(|key_package| *participant_index == key_package.index)
.unwrap();
let nonces_to_use = &nonces.get(participant_index).unwrap()[0];
let nonces_to_use = &nonces.get(participant_index).unwrap();
// Each participant generates their signature share.
let signature_share = round2::sign(&signing_package, nonces_to_use, key_package).unwrap();

View File

@ -3,7 +3,7 @@
#![doc = include_str!("../README.md")]
use curve25519_dalek::{
constants::{BASEPOINT_ORDER, RISTRETTO_BASEPOINT_POINT},
constants::RISTRETTO_BASEPOINT_POINT,
ristretto::{CompressedRistretto, RistrettoPoint},
scalar::Scalar,
traits::Identity,
@ -83,10 +83,6 @@ impl Group for RistrettoGroup {
type Serialization = [u8; 32];
fn order() -> <Self::Field as Field>::Scalar {
BASEPOINT_ORDER
}
fn cofactor() -> <Self::Field as Field>::Scalar {
Scalar::one()
}
@ -111,10 +107,10 @@ impl Group for RistrettoGroup {
}
}
/// Context string 'FROST-RISTRETTO255-SHA512' from the ciphersuite in the [spec]
/// Context string 'FROST-RISTRETTO255-SHA512-v5' from the ciphersuite in the [spec]
///
/// [spec]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-04.txt
const CONTEXT_STRING: &str = "FROST-RISTRETTO255-SHA512";
/// [spec]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-05.html#section-6.2-1
const CONTEXT_STRING: &str = "FROST-RISTRETTO255-SHA512-v5";
#[derive(Clone, Copy, PartialEq)]
/// An implementation of the FROST ciphersuite Ristretto255-SHA512.
@ -168,6 +164,20 @@ impl Ciphersuite for Ristretto255Sha512 {
output.copy_from_slice(h.finalize().as_slice());
output
}
/// H4 for FROST(ristretto255, SHA-512)
///
/// [spec]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-05.html#name-frostristretto255-sha-512
fn H4(m: &[u8]) -> <<Self::Group as Group>::Field as Field>::Scalar {
let h = Sha512::new()
.chain(CONTEXT_STRING.as_bytes())
.chain("nonce")
.chain(m);
let mut output = [0u8; 64];
output.copy_from_slice(h.finalize().as_slice());
<<Self::Group as Group>::Field as Field>::Scalar::from_bytes_mod_order_wide(&output)
}
}
type R = Ristretto255Sha512;
@ -197,6 +207,8 @@ pub mod keys {
///
pub mod round1 {
use frost_core::frost::keys::Secret;
use super::*;
///
pub type SigningNonces = frost::round1::SigningNonces<R>;
@ -205,15 +217,15 @@ pub mod round1 {
pub type SigningCommitments = frost::round1::SigningCommitments<R>;
///
pub fn preprocess<RNG>(
num_nonces: u8,
pub fn commit<RNG>(
participant_index: u16,
secret: &Secret<R>,
rng: &mut RNG,
) -> (Vec<SigningNonces>, Vec<SigningCommitments>)
) -> (SigningNonces, SigningCommitments)
where
RNG: CryptoRng + RngCore,
{
frost::round1::preprocess::<R, RNG>(num_nonces, participant_index, rng)
frost::round1::commit::<R, RNG>(participant_index, secret, rng)
}
}

View File

@ -1,59 +1,59 @@
{
"config": {
"MAX_SIGNERS": "3",
"NUM_SIGNERS": "2",
"THRESHOLD_LIMIT": "2",
"name": "FROST(ristretto255, SHA-512)",
"group": "ristretto255",
"hash": "SHA-512"
},
"inputs": {
"group_secret_key": "b120be204b5e758960458ca9c4675b56b12a8faff2be9c94891d5e1cd75c880e",
"group_public_key": "563b80013f337deaa2a282af7b281bd70d2f501928a89c1aa48b379a5ac4202b",
"message": "74657374",
"signers": {
"1": {
"signer_share": "94ae65bb90030a89507fa00fff08dfed841cf996de5a0c574f1f4693ddcb6705"
},
"2": {
"signer_share": "641003b3f00bb1e01656ac1818a4419a580e637ecaf67b1915212e0ae43a470c"
},
"3": {
"signer_share": "479eaa4d36b145e00690c07e5245c5312c00cd65b692ebdbda221681eaa92603"
}
"config": {
"MAX_SIGNERS": "3",
"NUM_SIGNERS": "2",
"MIN_SIGNERS": "2",
"name": "FROST(ristretto255, SHA-512)",
"group": "ristretto255",
"hash": "SHA-512"
},
"inputs": {
"group_secret_key": "1b25a55e463cfd15cf14a5d3acc3d15053f08da49c8afcf3ab265f2ebc4f970b",
"group_public_key": "e2a62f39eede11269e3bd5a7d97554f5ca384f9f6d3dd9c3c0d05083c7254f57",
"message": "74657374",
"signers": {
"1": {
"signer_share": "5c3430d391552f6e60ecdc093ff9f6f4488756aa6cebdbad75a768010b8f830e"
},
"2": {
"signer_share": "b06fc5eac20b4f6e1b271d9df2343d843e1e1fb03c4cbb673f2872d459ce6f01"
},
"3": {
"signer_share": "f17e505f0e2581c6acfe54d3846a622834b5e7b50cad9a2109a97ba7a80d5c04"
}
},
"round_one_outputs": {
"participants": "1,2",
"group_binding_factor_input": "0001824e9eddddf02b2a9caf5859825e999d791ca094f65b814a8bca6013d9cc312774c7e1271d2939a84a9a867e3a06579b4d25659b427439ccf0d745b43f75b76600028013834ff4d48e7d6b76c2e732bc611f54720ef8933c4ca4de7eaaa77ff5cd125e056ecc4f7c4657d3a742354430d768f945db229c335d258e9622ad99f3e7582d07b35bd9849ce4af6ad403090d69a7d0eb88bba669a9f985175d70cd15ad5f1ef5b734c98a32b4aab7b43a57e93fc09281f2e7a207076b31e416ba63f53d9d",
"group_binding_factor": "f00ae6007f2d74a1507c962cf30006be77596106db28f2d5443fd66d755e780c",
"signers": {
"1": {
"hiding_nonce": "349b3bb8464a1d87f7d6b56f4559a3f9a6335261a3266089a9b12d9d6f6ce209",
"binding_nonce": "ce7406016a854be4291f03e7d24fe30e77994c3465de031515a4c116f22ca901",
"hiding_nonce_commitment": "824e9eddddf02b2a9caf5859825e999d791ca094f65b814a8bca6013d9cc3127",
"binding_nonce_commitment": "74c7e1271d2939a84a9a867e3a06579b4d25659b427439ccf0d745b43f75b766"
},
"2": {
"hiding_nonce": "4d66d319f20a728ec3d491cbf260cc6be687bd87cc2b5fdb4d5f528f65fd650d",
"binding_nonce": "278b9b1e04632e6af3f1a3c144d07922ffcf5efd3a341b47abc19c43f48ce306",
"hiding_nonce_commitment": "8013834ff4d48e7d6b76c2e732bc611f54720ef8933c4ca4de7eaaa77ff5cd12",
"binding_nonce_commitment": "5e056ecc4f7c4657d3a742354430d768f945db229c335d258e9622ad99f3e758"
}
}
},
"round_two_outputs": {
"participants": "1,2",
"signers": {
"1": {
"sig_share": "ec6b075f17c5670e80b1fda8f6de1cfe3c79db06a852f8d5650fb71eaad69501"
},
"2": {
"sig_share": "87ceccc477069aa9b751b307f25955daaf943a3abc51f214a114781de0f58e03"
}
}
},
"final_output": {
"sig": "7e92309bf40993141acd5f2c7680a302cc5aa5dd291a833906da8e35bc39b03e733ad4238fcb01b83703b1b0e83872d8ec0d164164a4eaea06242f3c8acc2405"
}
},
"round_one_outputs": {
"participants": "1,3",
"group_binding_factor_input": "00015c01341bd0a948e71fe1b9bf09f8b8ee258bfcf3abddee42ef74c8068e0b224584a209c6c3e812283378fb6a15e4b9a64aa9eed51f7ae405d09b56ee56bc58500003c0fc5ffaf124fa69206a9ed77bd57fa1d8ca505f6139794f82778ce15ee0be3cb6718f8139e49d08741ab9f030da29e557451eab58bc770c0c05ef4e2ff8001e678630bf982c566949d7f22d2aefb94f252c664216d332f34e2c8fdcd7045f207f854504d0daa534a5b31dbdf4183be30eb4fdba4f962d8a6b69cf20c2734043",
"group_binding_factor": "af4288aad52765341b2238007777ea2bb2d0dfb4e92423b0646d4bec426e3d0d",
"signers": {
"1": {
"hiding_nonce": "b358743151e33d84bf00c12f71808f4103957c3e2cabab7b895c436b5e70f90c",
"binding_nonce": "7bd112153b9ae1ab9b31f5e78f61f5c4ca9ee67b7ea6d1181799c409d14c350c",
"hiding_nonce_commitment": "5c01341bd0a948e71fe1b9bf09f8b8ee258bfcf3abddee42ef74c8068e0b2245",
"binding_nonce_commitment": "84a209c6c3e812283378fb6a15e4b9a64aa9eed51f7ae405d09b56ee56bc5850"
},
"3": {
"hiding_nonce": "22acad88478e0d0373a991092a322ebd1b9a2dad90451a976d0db3215426af0e",
"binding_nonce": "9155e3d7bcf7cd468b980c7e20b2c77cbdfbe33a1dcae031fd8bc6b1403f4b04",
"hiding_nonce_commitment": "c0fc5ffaf124fa69206a9ed77bd57fa1d8ca505f6139794f82778ce15ee0be3c",
"binding_nonce_commitment": "b6718f8139e49d08741ab9f030da29e557451eab58bc770c0c05ef4e2ff8001e"
}
}
},
"round_two_outputs": {
"participants": "1,3",
"signers": {
"1": {
"sig_share": "ff801b4e0839faa67f16dee4127b9f7fbcf5fd007900257b0e2bbc02cbe5e709"
},
"3": {
"sig_share": "afdf5481023c855bf3411a5c8a5fafa92357296a078c3b80dc168f294cb4f504"
}
}
},
"final_output": {
"sig": "deae61af10e8ee48ba492573592fba547f5debeff6bd6e2024e8673584746f5eae6070cf0a757f027358f8409dda4e29e04c276b808c60fbea414b2c179add0e"
}
}

View File

@ -21,8 +21,8 @@ fn check_sign_with_dealer() {
.map(|share| keys::KeyPackage::try_from(share).unwrap())
.collect();
let mut nonces: HashMap<u16, Vec<round1::SigningNonces>> = HashMap::new();
let mut commitments: HashMap<u16, Vec<round1::SigningCommitments>> = HashMap::new();
let mut nonces: HashMap<u16, round1::SigningNonces> = HashMap::new();
let mut commitments: HashMap<u16, round1::SigningCommitments> = HashMap::new();
////////////////////////////////////////////////////////////////////////////
// Round 1: generating nonces and signing commitments for each participant
@ -31,7 +31,14 @@ fn check_sign_with_dealer() {
for participant_index in 1..(threshold + 1) {
// Generate one (1) nonce and one SigningCommitments instance for each
// participant, up to _threshold_.
let (nonce, commitment) = round1::preprocess(1, participant_index as u16, &mut rng);
let (nonce, commitment) = round1::commit(
participant_index as u16,
key_packages
.get((participant_index - 1) as usize)
.unwrap()
.secret_share(),
&mut rng,
);
nonces.insert(participant_index as u16, nonce);
commitments.insert(participant_index as u16, commitment);
}
@ -41,7 +48,7 @@ fn check_sign_with_dealer() {
// - take one (unused) commitment per signing participant
let mut signature_shares: Vec<round2::SignatureShare> = Vec::new();
let message = "message to sign".as_bytes();
let comms = commitments.clone().into_values().flatten().collect();
let comms = commitments.clone().into_values().collect();
let signing_package = SigningPackage::new(comms, message.to_vec());
////////////////////////////////////////////////////////////////////////////
@ -54,7 +61,7 @@ fn check_sign_with_dealer() {
.find(|key_package| *participant_index == key_package.index)
.unwrap();
let nonces_to_use = &nonces.get(participant_index).unwrap()[0];
let nonces_to_use = &nonces.get(participant_index).unwrap();
// Each participant generates their signature share.
let signature_share = round2::sign(&signing_package, nonces_to_use, key_package).unwrap();