Replace indices by "id"s.
The previous implementation was using an "index" to refer to a particular FROST participant. These references are handled in a different manner now, so they were changed to "id"s (identifiers).
This commit is contained in:
parent
55cca1b3ba
commit
4ff263fa62
93
src/frost.rs
93
src/frost.rs
|
@ -62,11 +62,12 @@ impl From<jubjub::ExtendedPoint> for Public {
|
||||||
/// reconstruct the secret; in this case we use Shamir's secret sharing.
|
/// reconstruct the secret; in this case we use Shamir's secret sharing.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Share {
|
pub struct Share {
|
||||||
receiver_index: u64,
|
/// The receiver id.
|
||||||
|
receiver_id: u64,
|
||||||
/// Secret Key.
|
/// Secret Key.
|
||||||
pub(crate) value: Secret,
|
value: Secret,
|
||||||
/// The commitments to be distributed among signers.
|
/// The commitments to be distributed among signers.
|
||||||
pub(crate) commitment: ShareCommitment,
|
commitment: ShareCommitment,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A Jubjub point that is a commitment to one coefficient of our secret
|
/// A Jubjub point that is a commitment to one coefficient of our secret
|
||||||
|
@ -105,8 +106,8 @@ pub struct GroupCommitment(pub(crate) jubjub::AffinePoint);
|
||||||
pub struct SharePackage {
|
pub struct SharePackage {
|
||||||
/// The public signing key that represents the entire group.
|
/// The public signing key that represents the entire group.
|
||||||
pub(crate) group_public: VerificationKey<SpendAuth>,
|
pub(crate) group_public: VerificationKey<SpendAuth>,
|
||||||
/// Denotes the participant index each share is owned by.
|
/// Denotes the participant id each share is owned by.
|
||||||
pub index: u64,
|
pub id: u64,
|
||||||
/// This participant's public key.
|
/// This participant's public key.
|
||||||
pub(crate) public: Public,
|
pub(crate) public: Public,
|
||||||
/// This participant's share.
|
/// This participant's share.
|
||||||
|
@ -128,7 +129,7 @@ impl TryFrom<SharePackage> for KeyPackage {
|
||||||
verify_share(&sharepackage.share)?;
|
verify_share(&sharepackage.share)?;
|
||||||
|
|
||||||
Ok(KeyPackage {
|
Ok(KeyPackage {
|
||||||
index: sharepackage.index,
|
id: sharepackage.id,
|
||||||
secret_share: sharepackage.share.value,
|
secret_share: sharepackage.share.value,
|
||||||
public: sharepackage.public,
|
public: sharepackage.public,
|
||||||
group_public: sharepackage.group_public,
|
group_public: sharepackage.group_public,
|
||||||
|
@ -144,7 +145,7 @@ impl TryFrom<SharePackage> for KeyPackage {
|
||||||
/// [`KeyPackage`]s, which they store to later use during signing.
|
/// [`KeyPackage`]s, which they store to later use during signing.
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub struct KeyPackage {
|
pub struct KeyPackage {
|
||||||
index: u64,
|
id: u64,
|
||||||
secret_share: Secret,
|
secret_share: Secret,
|
||||||
public: Public,
|
public: Public,
|
||||||
group_public: VerificationKey<SpendAuth>,
|
group_public: VerificationKey<SpendAuth>,
|
||||||
|
@ -189,13 +190,13 @@ pub fn keygen_with_dealer<R: RngCore + CryptoRng>(
|
||||||
for share in shares {
|
for share in shares {
|
||||||
let signer_public = Public(SpendAuth::basepoint() * share.value.0);
|
let signer_public = Public(SpendAuth::basepoint() * share.value.0);
|
||||||
sharepackages.push(SharePackage {
|
sharepackages.push(SharePackage {
|
||||||
index: share.receiver_index,
|
id: share.receiver_id,
|
||||||
share: share.clone(),
|
share: share.clone(),
|
||||||
public: signer_public,
|
public: signer_public,
|
||||||
group_public,
|
group_public,
|
||||||
});
|
});
|
||||||
|
|
||||||
signer_pubkeys.insert(share.receiver_index, signer_public);
|
signer_pubkeys.insert(share.receiver_id, signer_public);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
|
@ -216,7 +217,7 @@ pub fn keygen_with_dealer<R: RngCore + CryptoRng>(
|
||||||
fn verify_share(share: &Share) -> Result<(), &'static str> {
|
fn verify_share(share: &Share) -> Result<(), &'static str> {
|
||||||
let f_result = SpendAuth::basepoint() * share.value.0;
|
let f_result = SpendAuth::basepoint() * share.value.0;
|
||||||
|
|
||||||
let x = Scalar::from(share.receiver_index as u64);
|
let x = Scalar::from(share.receiver_id as u64);
|
||||||
|
|
||||||
let (_, result) = share.commitment.0.iter().fold(
|
let (_, result) = share.commitment.0.iter().fold(
|
||||||
(Scalar::one(), jubjub::ExtendedPoint::identity()),
|
(Scalar::one(), jubjub::ExtendedPoint::identity()),
|
||||||
|
@ -328,7 +329,7 @@ fn generate_shares<R: RngCore + CryptoRng>(
|
||||||
value += secret.0;
|
value += secret.0;
|
||||||
|
|
||||||
shares.push(Share {
|
shares.push(Share {
|
||||||
receiver_index: id,
|
receiver_id: id,
|
||||||
value: Secret(value),
|
value: Secret(value),
|
||||||
commitment: commitment.clone(),
|
commitment: commitment.clone(),
|
||||||
});
|
});
|
||||||
|
@ -390,19 +391,19 @@ impl SigningNonces {
|
||||||
/// SigningCommitment can be used for exactly *one* signature.
|
/// SigningCommitment can be used for exactly *one* signature.
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub struct SigningCommitments {
|
pub struct SigningCommitments {
|
||||||
/// The participant index
|
/// The participant id.
|
||||||
pub(crate) index: u64,
|
id: u64,
|
||||||
/// The hiding point.
|
/// The hiding point.
|
||||||
pub(crate) hiding: jubjub::ExtendedPoint,
|
hiding: jubjub::ExtendedPoint,
|
||||||
/// The binding point.
|
/// The binding point.
|
||||||
pub(crate) binding: jubjub::ExtendedPoint,
|
binding: jubjub::ExtendedPoint,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<(u64, &SigningNonces)> for SigningCommitments {
|
impl From<(u64, &SigningNonces)> for SigningCommitments {
|
||||||
/// For SpendAuth signatures only, not Binding signatures, in RedJubjub/Zcash.
|
/// For SpendAuth signatures only, not Binding signatures, in RedJubjub/Zcash.
|
||||||
fn from((index, nonces): (u64, &SigningNonces)) -> Self {
|
fn from((id, nonces): (u64, &SigningNonces)) -> Self {
|
||||||
Self {
|
Self {
|
||||||
index,
|
id,
|
||||||
hiding: SpendAuth::basepoint() * nonces.hiding,
|
hiding: SpendAuth::basepoint() * nonces.hiding,
|
||||||
binding: SpendAuth::basepoint() * nonces.binding,
|
binding: SpendAuth::basepoint() * nonces.binding,
|
||||||
}
|
}
|
||||||
|
@ -429,8 +430,8 @@ pub struct SignatureResponse(pub(crate) Scalar);
|
||||||
/// with all other signer's shares into the joint signature.
|
/// with all other signer's shares into the joint signature.
|
||||||
#[derive(Clone, Copy, Default)]
|
#[derive(Clone, Copy, Default)]
|
||||||
pub struct SignatureShare {
|
pub struct SignatureShare {
|
||||||
/// Represents the participant index.
|
/// Represents the participant id.
|
||||||
pub(crate) index: u64,
|
pub(crate) id: u64,
|
||||||
/// This participant's signature over the message.
|
/// This participant's signature over the message.
|
||||||
pub(crate) signature: SignatureResponse,
|
pub(crate) signature: SignatureResponse,
|
||||||
}
|
}
|
||||||
|
@ -467,18 +468,14 @@ impl SignatureShare {
|
||||||
/// perform the first round. Batching entails generating more than one
|
/// perform the first round. Batching entails generating more than one
|
||||||
/// nonce/commitment pair at a time. Nonces should be stored in secret storage
|
/// nonce/commitment pair at a time. Nonces should be stored in secret storage
|
||||||
/// for later use, whereas the commitments are published.
|
/// for later use, whereas the commitments are published.
|
||||||
<<<<<<< HEAD
|
|
||||||
|
|
||||||
=======
|
|
||||||
///
|
///
|
||||||
>>>>>>> 316082b (Change the type of the identifiers from u8 to u64)
|
|
||||||
/// The number of nonces is limited to 255. This limit can be increased if it
|
/// The number of nonces is limited to 255. This limit can be increased if it
|
||||||
/// turns out to be too conservative.
|
/// turns out to be too conservative.
|
||||||
// TODO: Make sure the above is a correct statement, fix if needed in:
|
// TODO: Make sure the above is a correct statement, fix if needed in:
|
||||||
// https://github.com/ZcashFoundation/redjubjub/issues/111
|
// https://github.com/ZcashFoundation/redjubjub/issues/111
|
||||||
pub fn preprocess<R>(
|
pub fn preprocess<R>(
|
||||||
num_nonces: u8,
|
num_nonces: u8,
|
||||||
participant_index: u64,
|
participant_id: u64,
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
) -> (Vec<SigningNonces>, Vec<SigningCommitments>)
|
) -> (Vec<SigningNonces>, Vec<SigningCommitments>)
|
||||||
where
|
where
|
||||||
|
@ -489,7 +486,7 @@ where
|
||||||
|
|
||||||
for _ in 0..num_nonces {
|
for _ in 0..num_nonces {
|
||||||
let nonces = SigningNonces::new(rng);
|
let nonces = SigningNonces::new(rng);
|
||||||
signing_commitments.push(SigningCommitments::from((participant_index, &nonces)));
|
signing_commitments.push(SigningCommitments::from((participant_id, &nonces)));
|
||||||
signing_nonces.push(nonces);
|
signing_nonces.push(nonces);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -498,7 +495,7 @@ where
|
||||||
|
|
||||||
/// Generates the binding factor that ensures each signature share is strongly
|
/// Generates the binding factor that ensures each signature share is strongly
|
||||||
/// bound to a signing set, specific set of commitments, and a specific message.
|
/// bound to a signing set, specific set of commitments, and a specific message.
|
||||||
fn gen_rho_i(index: u64, signing_package: &SigningPackage) -> Scalar {
|
fn gen_rho_i(id: u64, signing_package: &SigningPackage) -> Scalar {
|
||||||
// Hash signature message with HStar before deriving the binding factor.
|
// Hash signature message with HStar before deriving the binding factor.
|
||||||
//
|
//
|
||||||
// To avoid a collision with other inputs to the hash that generates the
|
// To avoid a collision with other inputs to the hash that generates the
|
||||||
|
@ -512,11 +509,11 @@ fn gen_rho_i(index: u64, signing_package: &SigningPackage) -> Scalar {
|
||||||
let mut hasher = HStar::default();
|
let mut hasher = HStar::default();
|
||||||
hasher
|
hasher
|
||||||
.update("FROST_rho".as_bytes())
|
.update("FROST_rho".as_bytes())
|
||||||
.update(index.to_be_bytes())
|
.update(id.to_be_bytes())
|
||||||
.update(message_hash.to_bytes());
|
.update(message_hash.to_bytes());
|
||||||
|
|
||||||
for item in signing_package.signing_commitments.iter() {
|
for item in signing_package.signing_commitments.iter() {
|
||||||
hasher.update(item.index.to_be_bytes());
|
hasher.update(item.id.to_be_bytes());
|
||||||
let hiding_bytes = jubjub::AffinePoint::from(item.hiding).to_bytes();
|
let hiding_bytes = jubjub::AffinePoint::from(item.hiding).to_bytes();
|
||||||
hasher.update(hiding_bytes);
|
hasher.update(hiding_bytes);
|
||||||
let binding_bytes = jubjub::AffinePoint::from(item.binding).to_bytes();
|
let binding_bytes = jubjub::AffinePoint::from(item.binding).to_bytes();
|
||||||
|
@ -543,8 +540,8 @@ fn gen_group_commitment(
|
||||||
}
|
}
|
||||||
|
|
||||||
let rho_i = bindings
|
let rho_i = bindings
|
||||||
.get(&commitment.index)
|
.get(&commitment.id)
|
||||||
.ok_or("No matching commitment index")?;
|
.ok_or("No matching commitment id")?;
|
||||||
accumulator += commitment.hiding + (commitment.binding * rho_i)
|
accumulator += commitment.hiding + (commitment.binding * rho_i)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -568,17 +565,17 @@ fn gen_challenge(
|
||||||
|
|
||||||
/// Generates the lagrange coefficient for the i'th participant.
|
/// Generates the lagrange coefficient for the i'th participant.
|
||||||
fn gen_lagrange_coeff(
|
fn gen_lagrange_coeff(
|
||||||
signer_index: u64,
|
signer_id: u64,
|
||||||
signing_package: &SigningPackage,
|
signing_package: &SigningPackage,
|
||||||
) -> Result<Scalar, &'static str> {
|
) -> Result<Scalar, &'static str> {
|
||||||
let mut num = Scalar::one();
|
let mut num = Scalar::one();
|
||||||
let mut den = Scalar::one();
|
let mut den = Scalar::one();
|
||||||
for commitment in signing_package.signing_commitments.iter() {
|
for commitment in signing_package.signing_commitments.iter() {
|
||||||
if commitment.index == signer_index {
|
if commitment.id == signer_id {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
num *= Scalar::from(commitment.index as u64);
|
num *= Scalar::from(commitment.id as u64);
|
||||||
den *= Scalar::from(commitment.index as u64) - Scalar::from(signer_index as u64);
|
den *= Scalar::from(commitment.id as u64) - Scalar::from(signer_id as u64);
|
||||||
}
|
}
|
||||||
|
|
||||||
if den == Scalar::zero() {
|
if den == Scalar::zero() {
|
||||||
|
@ -608,11 +605,11 @@ pub fn sign(
|
||||||
HashMap::with_capacity(signing_package.signing_commitments.len());
|
HashMap::with_capacity(signing_package.signing_commitments.len());
|
||||||
|
|
||||||
for comm in signing_package.signing_commitments.iter() {
|
for comm in signing_package.signing_commitments.iter() {
|
||||||
let rho_i = gen_rho_i(comm.index, &signing_package);
|
let rho_i = gen_rho_i(comm.id, &signing_package);
|
||||||
bindings.insert(comm.index, rho_i);
|
bindings.insert(comm.id, rho_i);
|
||||||
}
|
}
|
||||||
|
|
||||||
let lambda_i = gen_lagrange_coeff(share_package.index, &signing_package)?;
|
let lambda_i = gen_lagrange_coeff(share_package.id, &signing_package)?;
|
||||||
|
|
||||||
let group_commitment = gen_group_commitment(&signing_package, &bindings)?;
|
let group_commitment = gen_group_commitment(&signing_package, &bindings)?;
|
||||||
|
|
||||||
|
@ -623,7 +620,7 @@ pub fn sign(
|
||||||
);
|
);
|
||||||
|
|
||||||
let participant_rho_i = bindings
|
let participant_rho_i = bindings
|
||||||
.get(&share_package.index)
|
.get(&share_package.id)
|
||||||
.ok_or("No matching binding!")?;
|
.ok_or("No matching binding!")?;
|
||||||
|
|
||||||
// The Schnorr signature share
|
// The Schnorr signature share
|
||||||
|
@ -632,7 +629,7 @@ pub fn sign(
|
||||||
+ (lambda_i * share_package.share.value.0 * challenge);
|
+ (lambda_i * share_package.share.value.0 * challenge);
|
||||||
|
|
||||||
Ok(SignatureShare {
|
Ok(SignatureShare {
|
||||||
index: share_package.index,
|
id: share_package.id,
|
||||||
signature: SignatureResponse(signature),
|
signature: SignatureResponse(signature),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -661,8 +658,8 @@ pub fn aggregate(
|
||||||
HashMap::with_capacity(signing_package.signing_commitments.len());
|
HashMap::with_capacity(signing_package.signing_commitments.len());
|
||||||
|
|
||||||
for comm in signing_package.signing_commitments.iter() {
|
for comm in signing_package.signing_commitments.iter() {
|
||||||
let rho_i = gen_rho_i(comm.index, &signing_package);
|
let rho_i = gen_rho_i(comm.id, &signing_package);
|
||||||
bindings.insert(comm.index, rho_i);
|
bindings.insert(comm.id, rho_i);
|
||||||
}
|
}
|
||||||
|
|
||||||
let group_commitment = gen_group_commitment(&signing_package, &bindings)?;
|
let group_commitment = gen_group_commitment(&signing_package, &bindings)?;
|
||||||
|
@ -670,16 +667,16 @@ pub fn aggregate(
|
||||||
let challenge = gen_challenge(&signing_package, &group_commitment, &pubkeys.group_public);
|
let challenge = gen_challenge(&signing_package, &group_commitment, &pubkeys.group_public);
|
||||||
|
|
||||||
for signing_share in signing_shares {
|
for signing_share in signing_shares {
|
||||||
let signer_pubkey = pubkeys.signer_pubkeys[&signing_share.index];
|
let signer_pubkey = pubkeys.signer_pubkeys[&signing_share.id];
|
||||||
let lambda_i = gen_lagrange_coeff(signing_share.index, &signing_package)?;
|
let lambda_i = gen_lagrange_coeff(signing_share.id, &signing_package)?;
|
||||||
let signer_commitment = signing_package
|
let signer_commitment = signing_package
|
||||||
.signing_commitments
|
.signing_commitments
|
||||||
.iter()
|
.iter()
|
||||||
.find(|comm| comm.index == signing_share.index)
|
.find(|comm| comm.id == signing_share.id)
|
||||||
.ok_or("No matching signing commitment for signer")?;
|
.ok_or("No matching signing commitment for signer")?;
|
||||||
|
|
||||||
let commitment_i =
|
let commitment_i =
|
||||||
signer_commitment.hiding + (signer_commitment.binding * bindings[&signing_share.index]);
|
signer_commitment.hiding + (signer_commitment.binding * bindings[&signing_share.id]);
|
||||||
|
|
||||||
signing_share.check_is_valid(&signer_pubkey, lambda_i, commitment_i, challenge)?;
|
signing_share.check_is_valid(&signer_pubkey, lambda_i, commitment_i, challenge)?;
|
||||||
}
|
}
|
||||||
|
@ -719,9 +716,9 @@ mod tests {
|
||||||
if j == i {
|
if j == i {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
num *= Scalar::from(shares[j].receiver_index as u64);
|
num *= Scalar::from(shares[j].receiver_id as u64);
|
||||||
den *= Scalar::from(shares[j].receiver_index as u64)
|
den *= Scalar::from(shares[j].receiver_id as u64)
|
||||||
- Scalar::from(shares[i].receiver_index as u64);
|
- Scalar::from(shares[i].receiver_id as u64);
|
||||||
}
|
}
|
||||||
if den == Scalar::zero() {
|
if den == Scalar::zero() {
|
||||||
return Err("Duplicate shares provided");
|
return Err("Duplicate shares provided");
|
||||||
|
|
|
@ -19,8 +19,8 @@ fn check_sign_with_dealer() {
|
||||||
for share in &shares {
|
for share in &shares {
|
||||||
// Generate one (1) nonce and one SigningCommitments instance for each
|
// Generate one (1) nonce and one SigningCommitments instance for each
|
||||||
// participant, up to _threshold_.
|
// participant, up to _threshold_.
|
||||||
let (nonce, commitment) = frost::preprocess(1, share.index, &mut rng);
|
let (nonce, commitment) = frost::preprocess(1, share.id, &mut rng);
|
||||||
nonces.insert(share.index, nonce);
|
nonces.insert(share.id, nonce);
|
||||||
commitments.push(commitment[0]);
|
commitments.push(commitment[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,10 +35,10 @@ fn check_sign_with_dealer() {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Round 2: each participant generates their signature share
|
// Round 2: each participant generates their signature share
|
||||||
for (participant_index, nonce) in nonces {
|
for (participant_id, nonce) in nonces {
|
||||||
let share_package = shares
|
let share_package = shares
|
||||||
.iter()
|
.iter()
|
||||||
.find(|share| participant_index == share.index)
|
.find(|share| participant_id == share.id)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let nonce_to_use = nonce[0];
|
let nonce_to_use = nonce[0];
|
||||||
// Each participant generates their signature share.
|
// Each participant generates their signature share.
|
||||||
|
|
Loading…
Reference in New Issue