diff --git a/src/frost.rs b/src/frost.rs index 984bb0e7..bce76cd7 100644 --- a/src/frost.rs +++ b/src/frost.rs @@ -248,6 +248,8 @@ fn generate_shares( threshold: u8, mut rng: R, ) -> Result, &'static str> { + use std::convert::TryInto; + if threshold < 1 { return Err("Threshold cannot be 0"); } @@ -284,22 +286,37 @@ fn generate_shares( commitment.0.push(Commitment(SpendAuth::basepoint() * c)); } + // Participants' identifiers are 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 hash is finalized in the loop that follows. + let mut hasher = HStar::default(); + hasher + .update("FROST_id".as_bytes()) + .update(jubjub::AffinePoint::from(SpendAuth::basepoint() * secret.0).to_bytes()); + // Evaluate the polynomial with `secret` as the constant term // 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); + // The actual identifier consists of the first 64 bits of the resulting hash. + let id_bytes = hasher.update(index.to_be_bytes()).finalize().to_bytes(); + let id = u64::from_be_bytes(id_bytes[0..8].try_into().expect("slice of incorrect size")); + + 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(), }); diff --git a/tests/frost.rs b/tests/frost.rs index 84971e94..457ac232 100644 --- a/tests/frost.rs +++ b/tests/frost.rs @@ -15,11 +15,12 @@ fn check_sign_with_dealer() { let mut commitments: Vec = Vec::with_capacity(threshold as usize); // Round 1, generating nonces and signing commitments for each participant. - for participant_index in 1..(threshold + 1) { + // Participants are represented by shares. + 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]); }