Skip to content

Commit

Permalink
WIP of removing the identifier in structs that are communicated. Work…
Browse files Browse the repository at this point in the history
…ing for SigningCommitments for ristretto255
  • Loading branch information
conradoplg committed Jun 16, 2023
1 parent 84a3923 commit d983da3
Show file tree
Hide file tree
Showing 7 changed files with 48 additions and 68 deletions.
9 changes: 3 additions & 6 deletions frost-core/src/benches.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Ciphersuite-generic benchmark functions.

use std::collections::HashMap;
use std::collections::{BTreeMap, HashMap};

use criterion::{BenchmarkId, Criterion, Throughput};
use rand_core::{CryptoRng, RngCore};
Expand Down Expand Up @@ -116,7 +116,6 @@ pub fn bench_sign<C: Ciphersuite, R: RngCore + CryptoRng + Clone>(
b.iter(|| {
let participant_identifier = 1u16.try_into().expect("should be nonzero");
frost::round1::commit(
participant_identifier,
key_packages
.get(&participant_identifier)
.unwrap()
Expand All @@ -128,12 +127,11 @@ pub fn bench_sign<C: Ciphersuite, R: RngCore + CryptoRng + Clone>(
);

let mut nonces: HashMap<_, _> = HashMap::new();
let mut commitments: HashMap<_, _> = HashMap::new();
let mut commitments: BTreeMap<_, _> = BTreeMap::new();

for participant_index in 1..=min_signers {
let participant_identifier = participant_index.try_into().expect("should be nonzero");
let (nonce, commitment) = frost::round1::commit(
participant_identifier,
key_packages
.get(&participant_identifier)
.unwrap()
Expand All @@ -145,8 +143,7 @@ pub fn bench_sign<C: Ciphersuite, R: RngCore + CryptoRng + Clone>(
}

let message = "message to sign".as_bytes();
let comms = commitments.clone().into_values().collect();
let signing_package = frost::SigningPackage::new(comms, message.to_vec());
let signing_package = frost::SigningPackage::new(commitments, message.to_vec());

group.bench_with_input(
BenchmarkId::new("Round 2", min_signers),
Expand Down
38 changes: 16 additions & 22 deletions frost-core/src/frost.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
//! Sharing, where shares are generated using Shamir Secret Sharing.

use std::{
collections::{BTreeMap, HashMap},
collections::BTreeMap,
fmt::{self, Debug},
ops::Index,
};
Expand Down Expand Up @@ -161,14 +161,14 @@ fn derive_interpolating_value<C: Ciphersuite>(
// Ala the sorting of B, just always sort by identifier in ascending order
//
// https://github.com/cfrg/draft-irtf-cfrg-frost/blob/master/draft-irtf-cfrg-frost.md#encoding-operations-dep-encoding
for commitment in signing_package.signing_commitments() {
if commitment.identifier == *signer_id {
for commitment_identifier in signing_package.signing_commitments().keys() {
if *commitment_identifier == *signer_id {
continue;
}

num *= commitment.identifier;
num *= *commitment_identifier;

den *= commitment.identifier - *signer_id;
den *= *commitment_identifier - *signer_id;
}

if den == zero {
Expand All @@ -187,7 +187,7 @@ fn derive_interpolating_value<C: Ciphersuite>(
pub struct SigningPackage<C: Ciphersuite> {
/// The set of commitments participants published in the first round of the
/// protocol.
signing_commitments: HashMap<Identifier<C>, round1::SigningCommitments<C>>,
signing_commitments: BTreeMap<Identifier<C>, round1::SigningCommitments<C>>,
/// Message which each participant will sign.
///
/// Each signer should perform protocol-specific verification on the
Expand All @@ -203,14 +203,11 @@ where
///
/// The `signing_commitments` are sorted by participant `identifier`.
pub fn new(
signing_commitments: Vec<round1::SigningCommitments<C>>,
signing_commitments: BTreeMap<Identifier<C>, round1::SigningCommitments<C>>,
message: Vec<u8>,
) -> SigningPackage<C> {
SigningPackage {
signing_commitments: signing_commitments
.into_iter()
.map(|s| (s.identifier, s))
.collect(),
signing_commitments,
message,
}
}
Expand All @@ -221,11 +218,8 @@ where
}

/// Get the signing commitments, sorted by the participant indices
pub fn signing_commitments(&self) -> Vec<round1::SigningCommitments<C>> {
let mut signing_commitments: Vec<round1::SigningCommitments<C>> =
self.signing_commitments.values().cloned().collect();
signing_commitments.sort_by_key(|a| a.identifier);
signing_commitments
pub fn signing_commitments(&self) -> &BTreeMap<Identifier<C>, round1::SigningCommitments<C>> {
&self.signing_commitments
}

/// Get the message to be signed
Expand All @@ -249,13 +243,13 @@ where
binding_factor_input_prefix.extend_from_slice(additional_prefix);

self.signing_commitments()
.iter()
.map(|c| {
.keys()
.map(|identifier| {
let mut binding_factor_input = vec![];

binding_factor_input.extend_from_slice(&binding_factor_input_prefix);
binding_factor_input.extend_from_slice(c.identifier.serialize().as_ref());
(c.identifier, binding_factor_input)
binding_factor_input.extend_from_slice(identifier.serialize().as_ref());
(*identifier, binding_factor_input)
})
.collect()
}
Expand Down Expand Up @@ -313,14 +307,14 @@ where
// Ala the sorting of B, just always sort by identifier in ascending order
//
// https://github.com/cfrg/draft-irtf-cfrg-frost/blob/master/draft-irtf-cfrg-frost.md#encoding-operations-dep-encoding
for commitment in signing_package.signing_commitments() {
for (commitment_identifier, commitment) in signing_package.signing_commitments() {
// The following check prevents a party from accidentally revealing their share.
// Note that the '&&' operator would be sufficient.
if identity == commitment.binding.0 || identity == commitment.hiding.0 {
return Err(Error::IdentityCommitment);
}

let binding_factor = binding_factor_list[commitment.identifier].clone();
let binding_factor = binding_factor_list[*commitment_identifier].clone();

// Collect the binding commitments and their binding factors for one big
// multiscalar multiplication at the end.
Expand Down
31 changes: 11 additions & 20 deletions frost-core/src/frost/round1.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
//! FROST Round 1 functionality and types

use std::fmt::{self, Debug};
use std::{
collections::BTreeMap,
fmt::{self, Debug},
};

#[cfg(any(test, feature = "test-impl"))]
use hex::FromHex;
Expand Down Expand Up @@ -221,8 +224,6 @@ where
/// SigningCommitment can be used for exactly *one* signature.
#[derive(Copy, Clone)]
pub struct SigningCommitments<C: Ciphersuite> {
/// The participant identifier.
pub identifier: Identifier<C>,
/// Commitment to the hiding [`Nonce`].
pub hiding: NonceCommitment<C>,
/// Commitment to the binding [`Nonce`].
Expand Down Expand Up @@ -255,13 +256,12 @@ where
}
}

impl<C> From<(Identifier<C>, &SigningNonces<C>)> for SigningCommitments<C>
impl<C> From<&SigningNonces<C>> for SigningCommitments<C>
where
C: Ciphersuite,
{
fn from((identifier, nonces): (Identifier<C>, &SigningNonces<C>)) -> Self {
fn from(nonces: &SigningNonces<C>) -> Self {
Self {
identifier,
hiding: nonces.hiding.clone().into(),
binding: nonces.binding.clone().into(),
}
Expand All @@ -288,18 +288,12 @@ pub struct GroupCommitmentShare<C: Ciphersuite>(pub(super) Element<C>);
///
/// [`encode_group_commitment_list()`]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-11.html#name-list-operations
pub(super) fn encode_group_commitments<C: Ciphersuite>(
signing_commitments: Vec<SigningCommitments<C>>,
signing_commitments: &BTreeMap<Identifier<C>, SigningCommitments<C>>,
) -> Vec<u8> {
// B MUST be sorted in ascending order by signer identifier.
//
// TODO: AtLeastOne or other explicitly Sorted wrapper types?
let mut sorted_signing_commitments = signing_commitments;
sorted_signing_commitments.sort_by_key(|a| a.identifier);

let mut bytes = vec![];

for item in sorted_signing_commitments {
bytes.extend_from_slice(item.identifier.serialize().as_ref());
for (item_identifier, item) in signing_commitments {
bytes.extend_from_slice(item_identifier.serialize().as_ref());
bytes.extend_from_slice(<C::Group>::serialize(&item.hiding.0).as_ref());
bytes.extend_from_slice(<C::Group>::serialize(&item.binding.0).as_ref());
}
Expand All @@ -324,7 +318,6 @@ pub(super) fn encode_group_commitments<C: Ciphersuite>(
// https://github.com/ZcashFoundation/redjubjub/issues/111
pub fn preprocess<C, R>(
num_nonces: u8,
participant_identifier: Identifier<C>,
secret: &SigningShare<C>,
rng: &mut R,
) -> (Vec<SigningNonces<C>>, Vec<SigningCommitments<C>>)
Expand All @@ -338,7 +331,7 @@ where

for _ in 0..num_nonces {
let nonces = SigningNonces::new(secret, rng);
signing_commitments.push(SigningCommitments::from((participant_identifier, &nonces)));
signing_commitments.push(SigningCommitments::from(&nonces));
signing_nonces.push(nonces);
}

Expand All @@ -354,16 +347,14 @@ where
///
/// [`commit`]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-11.html#name-round-one-commitment
pub fn commit<C, R>(
participant_identifier: Identifier<C>,
secret: &SigningShare<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_identifier, secret, rng);
let (mut vec_signing_nonces, mut vec_signing_commitments) = preprocess(1, secret, rng);
(
vec_signing_nonces.pop().expect("must have 1 element"),
vec_signing_commitments.pop().expect("must have 1 element"),
Expand Down
13 changes: 7 additions & 6 deletions frost-core/src/tests/ciphersuite_generic.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
//! Ciphersuite-generic test functions.
use std::{collections::HashMap, convert::TryFrom};
use std::{
collections::{BTreeMap, HashMap},
convert::TryFrom,
};

use crate::{
frost::{self},
Expand Down Expand Up @@ -84,8 +87,8 @@ fn check_sign<C: Ciphersuite + PartialEq, R: RngCore + CryptoRng>(
pubkeys: frost::keys::PublicKeyPackage<C>,
) -> (Vec<u8>, Signature<C>, VerifyingKey<C>) {
let mut nonces: HashMap<frost::Identifier<C>, frost::round1::SigningNonces<C>> = HashMap::new();
let mut commitments: HashMap<frost::Identifier<C>, frost::round1::SigningCommitments<C>> =
HashMap::new();
let mut commitments: BTreeMap<frost::Identifier<C>, frost::round1::SigningCommitments<C>> =
BTreeMap::new();

////////////////////////////////////////////////////////////////////////////
// Round 1: generating nonces and signing commitments for each participant
Expand All @@ -96,7 +99,6 @@ fn check_sign<C: Ciphersuite + PartialEq, R: RngCore + CryptoRng>(
// Generate one (1) nonce and one SigningCommitments instance for each
// participant, up to _min_signers_.
let (nonce, commitment) = frost::round1::commit(
participant_identifier,
key_packages
.get(&participant_identifier)
.unwrap()
Expand All @@ -112,8 +114,7 @@ fn check_sign<C: Ciphersuite + PartialEq, R: RngCore + CryptoRng>(
// - take one (unused) commitment per signing participant
let mut signature_shares = Vec::new();
let message = "message to sign".as_bytes();
let comms = commitments.clone().into_values().collect();
let signing_package = frost::SigningPackage::new(comms, message.to_vec());
let signing_package = frost::SigningPackage::new(commitments, message.to_vec());

////////////////////////////////////////////////////////////////////////////
// Round 2: each participant generates their signature share
Expand Down
14 changes: 7 additions & 7 deletions frost-core/src/tests/vectors.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
//! Helper function for testing with test vectors.
use std::{collections::HashMap, str::FromStr};
use std::{
collections::{BTreeMap, HashMap},
str::FromStr,
};

use debugless_unwrap::DebuglessUnwrap;
use hex::{self, FromHex};
Expand All @@ -20,7 +23,7 @@ pub struct TestVectors<C: Ciphersuite> {
hiding_nonces_randomness: HashMap<Identifier<C>, Vec<u8>>,
binding_nonces_randomness: HashMap<Identifier<C>, Vec<u8>>,
signer_nonces: HashMap<Identifier<C>, SigningNonces<C>>,
signer_commitments: HashMap<Identifier<C>, SigningCommitments<C>>,
signer_commitments: BTreeMap<Identifier<C>, SigningCommitments<C>>,
binding_factor_inputs: HashMap<Identifier<C>, Vec<u8>>,
binding_factors: HashMap<Identifier<C>, BindingFactor<C>>,
signature_shares: HashMap<Identifier<C>, SignatureShare<C>>,
Expand Down Expand Up @@ -83,7 +86,7 @@ pub fn parse_test_vectors<C: Ciphersuite>(json_vectors: &Value) -> TestVectors<C
let mut hiding_nonces_randomness: HashMap<Identifier<C>, Vec<u8>> = HashMap::new();
let mut binding_nonces_randomness: HashMap<Identifier<C>, Vec<u8>> = HashMap::new();
let mut signer_nonces: HashMap<Identifier<C>, SigningNonces<C>> = HashMap::new();
let mut signer_commitments: HashMap<Identifier<C>, SigningCommitments<C>> = HashMap::new();
let mut signer_commitments: BTreeMap<Identifier<C>, SigningCommitments<C>> = BTreeMap::new();
let mut binding_factor_inputs: HashMap<Identifier<C>, Vec<u8>> = HashMap::new();
let mut binding_factors: HashMap<Identifier<C>, BindingFactor<C>> = HashMap::new();

Expand All @@ -110,7 +113,6 @@ pub fn parse_test_vectors<C: Ciphersuite>(json_vectors: &Value) -> TestVectors<C
signer_nonces.insert(identifier, signing_nonces);

let signing_commitments = SigningCommitments::<C> {
identifier,
hiding: NonceCommitment::from_hex(signer["hiding_nonce_commitment"].as_str().unwrap())
.unwrap(),
binding: NonceCommitment::from_hex(
Expand Down Expand Up @@ -273,9 +275,7 @@ pub fn check_sign_with_test_vectors<C: Ciphersuite>(json_vectors: &Value) {
// Round 2: each participant generates their signature share
/////////////////////////////////////////////////////////////////////////////

let signer_commitments_vec = signer_commitments.into_values().collect();

let signing_package = frost::SigningPackage::new(signer_commitments_vec, message_bytes);
let signing_package = frost::SigningPackage::new(signer_commitments, message_bytes);

for (identifier, input) in signing_package.binding_factor_preimages(&[]).iter() {
assert_eq!(*input, binding_factor_inputs[identifier]);
Expand Down
8 changes: 3 additions & 5 deletions frost-ristretto255/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ scenario in a single thread and it abstracts away any communication between peer
```rust
use frost_ristretto255 as frost;
use rand::thread_rng;
use std::collections::HashMap;
use std::collections::{BTreeMap, HashMap};

let mut rng = thread_rng();
let max_signers = 5;
Expand All @@ -29,7 +29,7 @@ for (k, v) in shares {
}

let mut nonces = HashMap::new();
let mut commitments = HashMap::new();
let mut commitments = BTreeMap::new();

////////////////////////////////////////////////////////////////////////////
// Round 1: generating nonces and signing commitments for each participant
Expand All @@ -41,7 +41,6 @@ for participant_index in 1..(min_signers as u16 + 1) {
// Generate one (1) nonce and one SigningCommitments instance for each
// participant, up to _threshold_.
let (nonce, commitment) = frost::round1::commit(
participant_identifier,
key_packages[&participant_identifier].secret_share(),
&mut rng,
);
Expand All @@ -57,11 +56,10 @@ for participant_index in 1..(min_signers as u16 + 1) {
// - take one (unused) commitment per signing participant
let mut signature_shares = Vec::new();
let message = "message to sign".as_bytes();
let comms = commitments.clone().into_values().collect();
// In practice, the SigningPackage must be sent to all participants
// involved in the current signing (at least min_signers participants),
// using an authenticate channel (and confidential if the message is secret).
let signing_package = frost::SigningPackage::new(comms, message.to_vec());
let signing_package = frost::SigningPackage::new(commitments, message.to_vec());

////////////////////////////////////////////////////////////////////////////
// Round 2: each participant generates their signature share
Expand Down
3 changes: 1 addition & 2 deletions frost-ristretto255/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,14 +301,13 @@ pub mod round1 {
/// Generates the signing nonces and commitments to be used in the signing
/// operation.
pub fn commit<RNG>(
participant_identifier: frost::Identifier<R>,
secret: &SigningShare<R>,
rng: &mut RNG,
) -> (SigningNonces, SigningCommitments)
where
RNG: CryptoRng + RngCore,
{
frost::round1::commit::<R, RNG>(participant_identifier, secret, rng)
frost::round1::commit::<R, RNG>(secret, rng)
}
}

Expand Down

0 comments on commit d983da3

Please sign in to comment.