From 52d022fdea978bc363639063db8ba4c67934867e Mon Sep 17 00:00:00 2001 From: Zhen Lu Date: Wed, 25 Sep 2024 12:35:15 -0700 Subject: [PATCH 1/6] Add sign_spark function for round 2 --- frost-core/src/round2.rs | 70 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/frost-core/src/round2.rs b/frost-core/src/round2.rs index dd9b069..3417dd1 100644 --- a/frost-core/src/round2.rs +++ b/frost-core/src/round2.rs @@ -239,3 +239,73 @@ pub fn sign( Ok(signature_share) } + +/// Performed once by each participant selected for the signing operation. +pub fn sign_spark( + signing_package: &SigningPackage, + signer_nonces: &round1::SigningNonces, + key_package: &frost::keys::KeyPackage, + inner_coef_set_x: &BTreeSet>, + outer_coef_set_x: Option<&BTreeSet>>, + outer_signer_id: Option<&Identifier>, + verifying_key: &VerifyingKey, +) -> Result, Error> { + if signing_package.signing_commitments().len() < key_package.min_signers as usize { + return Err(Error::IncorrectNumberOfCommitments); + } + + // Validate the signer's commitment is present in the signing package + let commitment = signing_package + .signing_commitments + .get(&key_package.identifier) + .ok_or(Error::MissingCommitment)?; + + // Validate if the signer's commitment exists + if &signer_nonces.commitments != commitment { + return Err(Error::IncorrectCommitment); + } + + // Encodes the signing commitment list produced in round one as part of generating [`BindingFactor`], the + // binding factor. + let binding_factor_list: BindingFactorList = + compute_binding_factor_list(signing_package, &verifying_key, &[]); + let binding_factor: frost::BindingFactor = binding_factor_list + .get(&key_package.identifier) + .ok_or(Error::UnknownIdentifier)? + .clone(); + + // Compute the group commitment from signing commitments produced in round one. + let group_commitment = compute_group_commitment(signing_package, &binding_factor_list)?; + + // Compute Lagrange coefficient. + let inner_lambda_i = + frost::compute_lagrange_coefficient(inner_coef_set_x, None, *key_package.identifier())?; + + let outer_lambda_i = match (outer_coef_set_x, outer_signer_id) { + (Some(outer_coef_set_x), Some(outer_signer_id)) => { + // If the user's key is a SSS shard, we need to compute the outer lambda_i + frost::compute_lagrange_coefficient(outer_coef_set_x, None, *outer_signer_id)? + } + // Otherwise, we use additive approach for user's key and SO's keys. + _ => <::Field>::one(), + }; + + let lambda_i = inner_lambda_i * outer_lambda_i; + // Compute the per-message challenge. + let challenge = challenge::( + &group_commitment.0, + &verifying_key, + signing_package.message(), + ); + + // Compute the Schnorr signature share. + let signature_share = compute_signature_share( + signer_nonces, + binding_factor, + lambda_i, + key_package, + challenge, + ); + + Ok(signature_share) +} From 6845a636b7bb9a795bb862b602f2fb253d94ed3d Mon Sep 17 00:00:00 2001 From: Zhen Lu Date: Wed, 25 Sep 2024 12:41:51 -0700 Subject: [PATCH 2/6] Aggregation and api functions --- frost-core/src/lib.rs | 55 +++++++++++++++++++++++++++++++++++ frost-secp256k1-tr/src/lib.rs | 30 +++++++++++++++++++ 2 files changed, 85 insertions(+) diff --git a/frost-core/src/lib.rs b/frost-core/src/lib.rs index e1e07b7..1163b82 100644 --- a/frost-core/src/lib.rs +++ b/frost-core/src/lib.rs @@ -697,3 +697,58 @@ where Ok(signature) } + +/// signature aggreation +pub fn aggregate_spark( + signing_package: &SigningPackage, + signature_shares: &BTreeMap, round2::SignatureShare>, + verifying_key: &VerifyingKey, +) -> Result, Error> +where + C: Ciphersuite, +{ + // Check if signing_package.signing_commitments and signature_shares have + // the same set of identifiers, and if they are all in pubkeys.verifying_shares. + if signing_package.signing_commitments().len() != signature_shares.len() { + return Err(Error::UnknownIdentifier); + } + + // if !signing_package.signing_commitments().keys().all(|id| { + // #[cfg(feature = "cheater-detection")] + // return signature_shares.contains_key(id) && pubkeys.verifying_shares().contains_key(id); + // #[cfg(not(feature = "cheater-detection"))] + // return signature_shares.contains_key(id); + // }) { + // return Err(Error::UnknownIdentifier); + // } + + // Encodes the signing commitment list produced in round one as part of generating [`BindingFactor`], the + // binding factor. + let binding_factor_list: BindingFactorList = + compute_binding_factor_list(signing_package, &verifying_key, &[]); + // Compute the group commitment from signing commitments produced in round one. + let group_commitment = compute_group_commitment(signing_package, &binding_factor_list)?; + + // The aggregation of the signature shares by summing them up, resulting in + // a plain Schnorr signature. + // + // Implements [`aggregate`] from the spec. + // + // [`aggregate`]: https://datatracker.ietf.org/doc/html/rfc9591#name-signature-share-aggregation + let mut z = <::Field>::zero(); + + for signature_share in signature_shares.values() { + z = z + signature_share.share; + } + + let signature = Signature { + R: group_commitment.0, + z, + }; + + // Verify the aggregate signature + let verification_result = verifying_key.verify(signing_package.message(), &signature); + verification_result?; + + Ok(signature) +} diff --git a/frost-secp256k1-tr/src/lib.rs b/frost-secp256k1-tr/src/lib.rs index b9f4962..b8e9b83 100644 --- a/frost-secp256k1-tr/src/lib.rs +++ b/frost-secp256k1-tr/src/lib.rs @@ -720,6 +720,27 @@ pub mod round2 { ) -> Result { frost::round2::sign(signing_package, signer_nonces, key_package) } + + /// Spark custom signing operation. + pub fn sign_spark( + signing_package: &SigningPackage, + signer_nonces: &round1::SigningNonces, + key_package: &keys::KeyPackage, + inner_coef_set_x: &std::collections::BTreeSet, + outer_coef_set_x: Option<&std::collections::BTreeSet>, + outer_signer_id: Option<&Identifier>, + verifiying_key: &VerifyingKey, + ) -> Result { + frost::round2::sign_spark( + signing_package, + signer_nonces, + key_package, + inner_coef_set_x, + outer_coef_set_x, + outer_signer_id, + verifiying_key, + ) + } } /// A Schnorr signature on FROST(secp256k1, SHA-256). @@ -748,6 +769,15 @@ pub fn aggregate( frost::aggregate(signing_package, signature_shares, pubkeys) } +/// Spark +pub fn aggregate_spark( + signing_package: &SigningPackage, + signature_shares: &BTreeMap, + verifying_key: &VerifyingKey, +) -> Result { + frost::aggregate_spark(signing_package, signature_shares, verifying_key) +} + /// A signing key for a Schnorr signature on FROST(secp256k1, SHA-256). pub type SigningKey = frost_core::SigningKey; From cbc140e1b715282164b15c13a99301cc8d9bcd68 Mon Sep 17 00:00:00 2001 From: Zhen Lu Date: Tue, 1 Oct 2024 10:00:15 -0700 Subject: [PATCH 3/6] Fix challenge --- frost-core/src/round2.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frost-core/src/round2.rs b/frost-core/src/round2.rs index 3417dd1..2cd6a0f 100644 --- a/frost-core/src/round2.rs +++ b/frost-core/src/round2.rs @@ -292,10 +292,10 @@ pub fn sign_spark( let lambda_i = inner_lambda_i * outer_lambda_i; // Compute the per-message challenge. - let challenge = challenge::( + let challenge = ::challenge( &group_commitment.0, &verifying_key, - signing_package.message(), + &signing_package.sig_target, ); // Compute the Schnorr signature share. From cb3dc006852b4d6cd3c376d62325cb5b5d30146d Mon Sep 17 00:00:00 2001 From: Zhen Lu Date: Tue, 1 Oct 2024 15:06:05 -0700 Subject: [PATCH 4/6] Add the functions to frost-secp256k1 --- frost-secp256k1/src/lib.rs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/frost-secp256k1/src/lib.rs b/frost-secp256k1/src/lib.rs index a67634c..625b4c0 100644 --- a/frost-secp256k1/src/lib.rs +++ b/frost-secp256k1/src/lib.rs @@ -418,6 +418,27 @@ pub mod round2 { ) -> Result { frost::round2::sign(signing_package, signer_nonces, key_package) } + + /// Spark custom signing operation. + pub fn sign_spark( + signing_package: &SigningPackage, + signer_nonces: &round1::SigningNonces, + key_package: &keys::KeyPackage, + inner_coef_set_x: &std::collections::BTreeSet, + outer_coef_set_x: Option<&std::collections::BTreeSet>, + outer_signer_id: Option<&Identifier>, + verifiying_key: &VerifyingKey, + ) -> Result { + frost::round2::sign_spark( + signing_package, + signer_nonces, + key_package, + inner_coef_set_x, + outer_coef_set_x, + outer_signer_id, + verifiying_key, + ) + } } /// A Schnorr signature on FROST(secp256k1, SHA-256). @@ -446,6 +467,15 @@ pub fn aggregate( frost::aggregate(signing_package, signature_shares, pubkeys) } +/// Spark +pub fn aggregate_spark( + signing_package: &SigningPackage, + signature_shares: &BTreeMap, + verifying_key: &VerifyingKey, +) -> Result { + frost::aggregate_spark(signing_package, signature_shares, verifying_key) +} + /// A signing key for a Schnorr signature on FROST(secp256k1, SHA-256). pub type SigningKey = frost_core::SigningKey; From 50f205156755c7412aacbddfda1a0bb1887f9b92 Mon Sep 17 00:00:00 2001 From: Zhen Lu Date: Tue, 1 Oct 2024 19:19:39 -0700 Subject: [PATCH 5/6] Make it work with secp256k1-tr --- frost-core/src/lib.rs | 8 ++++---- frost-core/src/round2.rs | 6 +++++- frost-core/src/traits.rs | 1 + frost-secp256k1-tr/src/lib.rs | 3 ++- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/frost-core/src/lib.rs b/frost-core/src/lib.rs index 1163b82..aa67832 100644 --- a/frost-core/src/lib.rs +++ b/frost-core/src/lib.rs @@ -741,10 +741,10 @@ where z = z + signature_share.share; } - let signature = Signature { - R: group_commitment.0, - z, - }; + let R = ::effective_nonce_element(group_commitment.0); + + let signature: Signature = + ::aggregate_sig_finalize(z, R, &verifying_key, &signing_package.sig_target); // Verify the aggregate signature let verification_result = verifying_key.verify(signing_package.message(), &signature); diff --git a/frost-core/src/round2.rs b/frost-core/src/round2.rs index 2cd6a0f..b72607b 100644 --- a/frost-core/src/round2.rs +++ b/frost-core/src/round2.rs @@ -233,6 +233,7 @@ pub fn sign( group_commitment, lambda_i, key_package, + key_package.verifying_key(), challenge, &signing_package.sig_target.sig_params, ); @@ -299,12 +300,15 @@ pub fn sign_spark( ); // Compute the Schnorr signature share. - let signature_share = compute_signature_share( + let signature_share = ::compute_signature_share( signer_nonces, binding_factor, + group_commitment, lambda_i, key_package, + verifying_key, challenge, + &signing_package.sig_target.sig_params, ); Ok(signature_share) diff --git a/frost-core/src/traits.rs b/frost-core/src/traits.rs index 14620cc..11be22e 100644 --- a/frost-core/src/traits.rs +++ b/frost-core/src/traits.rs @@ -375,6 +375,7 @@ pub trait Ciphersuite: Copy + Clone + PartialEq + Debug { _group_commitment: GroupCommitment, lambda_i: <::Field as Field>::Scalar, key_package: &KeyPackage, + _verifying_key: &VerifyingKey, challenge: Challenge, _sig_params: &Self::SigningParameters, ) -> round2::SignatureShare { diff --git a/frost-secp256k1-tr/src/lib.rs b/frost-secp256k1-tr/src/lib.rs index b8e9b83..e12958c 100644 --- a/frost-secp256k1-tr/src/lib.rs +++ b/frost-secp256k1-tr/src/lib.rs @@ -429,6 +429,7 @@ impl Ciphersuite for Secp256K1Sha256 { group_commitment: GroupCommitment, lambda_i: <::Field as Field>::Scalar, key_package: &frost::keys::KeyPackage, + verifying_key: &VerifyingKey, challenge: Challenge, sig_params: &SigningParameters, ) -> round2::SignatureShare { @@ -438,7 +439,7 @@ impl Ciphersuite for Secp256K1Sha256 { } let mut kp = key_package.clone(); - let public_key = key_package.verifying_key(); + let public_key = verifying_key; let pubkey_is_odd: bool = public_key.y_is_odd(); let tweaked_pubkey_is_odd: bool = tweaked_public_key(public_key, sig_params.tapscript_merkle_root.as_ref()) From 115983a0d2c825f7ce65729ccdcbaff242c45c4a Mon Sep 17 00:00:00 2001 From: Zhen Lu Date: Wed, 9 Oct 2024 14:43:14 -0700 Subject: [PATCH 6/6] Fix aggregate_spark --- frost-core/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frost-core/src/lib.rs b/frost-core/src/lib.rs index aa67832..1c2a0f0 100644 --- a/frost-core/src/lib.rs +++ b/frost-core/src/lib.rs @@ -747,7 +747,7 @@ where ::aggregate_sig_finalize(z, R, &verifying_key, &signing_package.sig_target); // Verify the aggregate signature - let verification_result = verifying_key.verify(signing_package.message(), &signature); + let verification_result = verifying_key.verify(signing_package.sig_target.clone(), &signature); verification_result?; Ok(signature)