Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change participant identifiers in Trusted Dealer variant #108

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 28 additions & 4 deletions src/frost.rs
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,29 @@ fn verify_share(share: &Share) -> Result<(), &'static str> {
Ok(())
}

/// Generates the identifier for a given participant.
///
/// The identifier is generated as follows:
/// id = H("FROST_id", g^s, i), where:
/// - g is the basepoint,
/// - s is the secret chosen by the dealer, and
/// - i is the index of the participant.
///
/// The actual identifier consists of the first 64 bits of the resulting hash.
fn generate_id(secret: &Secret, index: u8) -> u64 {
use std::convert::TryInto;

let mut hasher = HStar::default();

hasher
.update("FROST_id".as_bytes())
.update(jubjub::AffinePoint::from(SpendAuth::basepoint() * secret.0).to_bytes())
.update(index.to_le_bytes());

let id_bytes = hasher.finalize().to_bytes();

u64::from_le_bytes(id_bytes[0..8].try_into().expect("slice of incorrect size"))
}
/// Creates secret shares for a given secret.
///
/// This function accepts a secret from which shares are generated. While in
Expand Down Expand Up @@ -293,18 +316,19 @@ fn generate_shares<R: RngCore + CryptoRng>(
// and `coeffs` as the other coefficients at the point x=share_index,
// using Horner's method.
for index in 1..numshares + 1 {
let scalar_index = Scalar::from(index as u64);
let id = generate_id(secret, index);
let scalar_id = Scalar::from(id);
let mut value = Scalar::zero();

// Polynomial evaluation, for this index
for i in (0..numcoeffs).rev() {
value += &coefficients[i as usize];
value *= scalar_index;
value *= scalar_id;
}
value += secret.0;

shares.push(Share {
receiver_index: index as u64,
receiver_index: id,
value: Secret(value),
commitment: commitment.clone(),
});
Expand Down Expand Up @@ -443,7 +467,7 @@ impl SignatureShare {
/// perform the first round. Batching entails generating more than one
/// nonce/commitment pair at a time. Nonces should be stored in secret storage
/// for later use, whereas the commitments are published.

///
/// The number of nonces is limited to 255. This limit can be increased if it
/// turns out to be too conservative.
// TODO: Make sure the above is a correct statement, fix if needed in:
Expand Down
105 changes: 52 additions & 53 deletions src/messages/tests/integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::{
};
use rand::thread_rng;
use serde_json;
use std::convert::TryFrom;
use std::{collections::HashMap, convert::TryFrom};

#[test]
fn validate_version() {
Expand Down Expand Up @@ -69,8 +69,8 @@ fn validate_sharepackage() {

let payload = Payload::SharePackage(SharePackage {
group_public,
secret_share: secret_share,
share_commitment: share_commitment,
secret_share,
share_commitment,
});
let validate_payload = Validate::validate(&payload);
let valid_payload = validate_payload.expect("a valid payload").clone();
Expand Down Expand Up @@ -101,7 +101,7 @@ fn validate_sharepackage() {
// change the payload to have only 1 commitment
let payload = Payload::SharePackage(SharePackage {
group_public,
secret_share: secret_share,
secret_share,
share_commitment: share_commitment.clone(),
});
let validate_payload = Validate::validate(&payload);
Expand Down Expand Up @@ -151,7 +151,7 @@ fn serialize_sharepackage() {
});

let message = Message {
header: header,
header,
payload: payload.clone(),
};

Expand Down Expand Up @@ -246,7 +246,7 @@ fn serialize_signingcommitments() {
let payload = Payload::SigningCommitments(SigningCommitments { hiding, binding });

let message = Message {
header: header,
header,
payload: payload.clone(),
};

Expand Down Expand Up @@ -341,7 +341,7 @@ fn validate_signingpackage() {
let header = create_valid_header(setup.aggregator, setup.dealer);

let message = Message {
header: header,
header,
payload: payload.clone(),
};

Expand Down Expand Up @@ -377,7 +377,7 @@ fn serialize_signingpackage() {
});

let message = Message {
header: header,
header,
payload: payload.clone(),
};

Expand Down Expand Up @@ -421,25 +421,8 @@ fn serialize_signingpackage() {
fn validate_signatureshare() {
let mut setup = basic_setup();

// signers and aggregator should have this data from `SharePackage`
let (shares, _pubkeys) =
frost::keygen_with_dealer(setup.num_signers, setup.threshold, setup.rng.clone()).unwrap();

// create a signing package, this is done in the aggregator side.
// the signrs should have this data from `SigningPackage`
let (nonce1, commitment1) = frost::preprocess(1, u64::from(setup.signer1), &mut setup.rng);
let (_nonce2, commitment2) = frost::preprocess(1, u64::from(setup.signer2), &mut setup.rng);
let commitments = vec![commitment1[0], commitment2[0]];
let participants = vec![setup.signer1, setup.signer2];
let signing_commitments = create_signing_commitments(commitments, participants);

let signing_package = frost::SigningPackage::from(SigningPackage {
signing_commitments: signing_commitments.clone(),
message: "hola".as_bytes().to_vec(),
});

// here we get started with the `SignatureShare` message.
let signature_share = frost::sign(&signing_package, nonce1[0], &shares[0]).unwrap();
let signature_share = generate_signature_share(&mut setup);

// this header is invalid
let header = create_valid_header(setup.aggregator, setup.signer1);
Expand Down Expand Up @@ -479,25 +462,8 @@ fn validate_signatureshare() {
fn serialize_signatureshare() {
let mut setup = basic_setup();

// signers and aggregator should have this data from `SharePackage`
let (shares, _pubkeys) =
frost::keygen_with_dealer(setup.num_signers, setup.threshold, setup.rng.clone()).unwrap();

// create a signing package, this is done in the aggregator side.
// the signers should have this data from `SigningPackage`
let (nonce1, commitment1) = frost::preprocess(1, u64::from(setup.signer1), &mut setup.rng);
let (_nonce2, commitment2) = frost::preprocess(1, u64::from(setup.signer2), &mut setup.rng);
let commitments = vec![commitment1[0], commitment2[0]];
let participants = vec![setup.signer1, setup.signer2];
let signing_commitments = create_signing_commitments(commitments, participants);

let signing_package = frost::SigningPackage::from(SigningPackage {
signing_commitments: signing_commitments.clone(),
message: "hola".as_bytes().to_vec(),
});

// here we get started with the `SignatureShare` message.
let signature_share = frost::sign(&signing_package, nonce1[0], &shares[0]).unwrap();
let signature_share = generate_signature_share(&mut setup);

// valid header
let header = create_valid_header(setup.signer1, setup.aggregator);
Expand All @@ -506,7 +472,7 @@ fn serialize_signatureshare() {
let payload = Payload::SignatureShare(SignatureShare { signature });

let message = Message {
header: header,
header,
payload: payload.clone(),
};

Expand Down Expand Up @@ -656,8 +622,8 @@ fn btreemap() {
fn create_valid_header(sender: ParticipantId, receiver: ParticipantId) -> Header {
Validate::validate(&Header {
version: constants::BASIC_FROST_SERIALIZATION,
sender: sender,
receiver: receiver,
sender,
receiver,
})
.expect("always a valid header")
.clone()
Expand Down Expand Up @@ -731,22 +697,26 @@ fn full_setup() -> (Setup, signature::Signature<SpendAuth>) {
let (shares, pubkeys) =
frost::keygen_with_dealer(setup.num_signers, setup.threshold, setup.rng.clone()).unwrap();

let mut nonces: std::collections::HashMap<u64, Vec<frost::SigningNonces>> =
std::collections::HashMap::with_capacity(setup.threshold as usize);
let mut nonces: HashMap<u64, Vec<frost::SigningNonces>> =
HashMap::with_capacity(setup.threshold as usize);
let mut commitments: Vec<frost::SigningCommitments> =
Vec::with_capacity(setup.threshold as usize);

// aggregator generates nonces and signing commitments for each participant.
for participant_index in 1..(setup.threshold + 1) {
let (nonce, commitment) = frost::preprocess(1, participant_index as u64, &mut setup.rng);
nonces.insert(participant_index as u64, nonce);
// Shares represent participants.
// The aggregator generates nonces and signing commitments for each participant.
for share in &shares {
// Generate one nonce and one SigningCommitments instance for each participant.
let (nonce, commitment) = frost::preprocess(1, share.index, &mut setup.rng);
nonces.insert(share.index, nonce);
commitments.push(commitment[0]);
}

// aggregator generates a signing package
let mut signature_shares: Vec<frost::SignatureShare> =
Vec::with_capacity(setup.threshold as usize);

let message = "message to sign".as_bytes().to_vec();

let signing_package = frost::SigningPackage {
message: message.clone(),
signing_commitments: commitments,
Expand Down Expand Up @@ -803,3 +773,32 @@ fn create_signing_commitments(
})
.collect()
}

fn generate_signature_share(setup: &mut Setup) -> frost::SignatureShare {
// signers and aggregator should have this data from `SharePackage`
let (shares, _pubkeys) =
frost::keygen_with_dealer(setup.num_signers, setup.threshold, setup.rng.clone()).unwrap();

let mut nonces: HashMap<u64, Vec<frost::SigningNonces>> =
HashMap::with_capacity(setup.threshold as usize);
let mut commitments: Vec<frost::SigningCommitments> =
Vec::with_capacity(setup.threshold as usize);

// Shares represent participants.
for share in &shares {
// Generate one nonce and one SigningCommitments instance for each participant.
let (nonce, commitment) = frost::preprocess(1, share.index, &mut setup.rng);
nonces.insert(share.index, nonce);
commitments.push(commitment[0]);
}

let signing_package = frost::SigningPackage {
message: "message to sign".as_bytes().to_vec(),
signing_commitments: commitments,
};

let signing_share = &shares[0];
let signing_nonce = nonces[&signing_share.index][0];

frost::sign(&signing_package, signing_nonce, &signing_share).unwrap()
}
7 changes: 4 additions & 3 deletions tests/frost.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,12 @@ fn check_sign_with_dealer() {
let mut commitments: Vec<frost::SigningCommitments> = Vec::with_capacity(threshold as usize);

// Round 1, generating nonces and signing commitments for each participant.
for participant_index in 1..(threshold + 1) {
// Shares represent participants.
for share in &shares {
// Generate one (1) nonce and one SigningCommitments instance for each
// participant, up to _threshold_.
let (nonce, commitment) = frost::preprocess(1, participant_index as u64, &mut rng);
nonces.insert(participant_index as u64, nonce);
let (nonce, commitment) = frost::preprocess(1, share.index, &mut rng);
nonces.insert(share.index, nonce);
commitments.push(commitment[0]);
}

Expand Down