From eb6fa707d53242c6548d58c8a79b760c21aa530d Mon Sep 17 00:00:00 2001 From: Conrado Gouvea Date: Mon, 21 Aug 2023 14:46:28 -0300 Subject: [PATCH] improve sign() performance by caching SigningCommitments --- frost-core/src/frost/round1.rs | 32 ++++++++++++++++++++++++-------- frost-core/src/frost/round2.rs | 6 +----- frost-core/src/tests/vectors.rs | 8 ++++---- 3 files changed, 29 insertions(+), 17 deletions(-) diff --git a/frost-core/src/frost/round1.rs b/frost-core/src/frost/round1.rs index 86c336d6..969d57d1 100644 --- a/frost-core/src/frost/round1.rs +++ b/frost-core/src/frost/round1.rs @@ -207,6 +207,12 @@ pub struct SigningNonces { pub(crate) hiding: Nonce, /// The binding [`Nonce`]. pub(crate) binding: Nonce, + /// The commitments to the nonces. This is precomputed to improve + /// sign() performance, since it needs to check if the commitments + /// to the participant's nonces are included in the commitments sent + /// by the Coordinator, and this prevents having to recompute them. + #[zeroize(skip)] + pub(crate) commitments: SigningCommitments, } impl SigningNonces @@ -221,12 +227,26 @@ where where R: CryptoRng + RngCore, { - // The values of 'hiding' and 'binding' must be non-zero so that commitments are - // not the identity. let hiding = Nonce::::new(secret, rng); let binding = Nonce::::new(secret, rng); - Self { hiding, binding } + Self::from_nonces(hiding, binding) + } + + /// Generates a new [`SigningNonces`] from a pair of [`Nonce`]. This is + /// useful internally since [`SigningNonces`] precompute the respective + /// commitments. + #[cfg_attr(test, visibility::make(pub))] + pub(crate) fn from_nonces(hiding: Nonce, binding: Nonce) -> Self { + let hiding_commitment = (&hiding).into(); + let binding_commitment = (&binding).into(); + let commitments = SigningCommitments::new(hiding_commitment, binding_commitment); + + Self { + hiding, + binding, + commitments, + } } /// Gets the hiding [`Nonce`] @@ -295,11 +315,7 @@ where C: Ciphersuite, { fn from(nonces: &SigningNonces) -> Self { - Self { - hiding: nonces.hiding.clone().into(), - binding: nonces.binding.clone().into(), - ciphersuite: (), - } + nonces.commitments } } diff --git a/frost-core/src/frost/round2.rs b/frost-core/src/frost/round2.rs index 2e38f301..22724773 100644 --- a/frost-core/src/frost/round2.rs +++ b/frost-core/src/frost/round2.rs @@ -11,8 +11,6 @@ use crate::{ #[cfg(feature = "serde")] use crate::ScalarSerialization; -use super::round1::SigningCommitments; - // Used to help encoding a SignatureShare. Since it has a Scalar it can't // be directly encoded with serde, so we use this struct to wrap the scalar. #[cfg(feature = "serde")] @@ -195,10 +193,8 @@ pub fn sign( .get(&key_package.identifier) .ok_or(Error::MissingCommitment)?; - let signing_commitments = SigningCommitments::from(signer_nonces); - // Validate if the signer's commitment exists - if &signing_commitments != commitment { + if &signer_nonces.commitments != commitment { return Err(Error::IncorrectCommitment); } diff --git a/frost-core/src/tests/vectors.rs b/frost-core/src/tests/vectors.rs index 4e1edb6c..5bf0665c 100644 --- a/frost-core/src/tests/vectors.rs +++ b/frost-core/src/tests/vectors.rs @@ -96,10 +96,10 @@ pub fn parse_test_vectors(json_vectors: &Value) -> TestVectors { - hiding: Nonce::::from_hex(signer["hiding_nonce"].as_str().unwrap()).unwrap(), - binding: Nonce::::from_hex(signer["binding_nonce"].as_str().unwrap()).unwrap(), - }; + let signing_nonces = SigningNonces::::from_nonces( + Nonce::::from_hex(signer["hiding_nonce"].as_str().unwrap()).unwrap(), + Nonce::::from_hex(signer["binding_nonce"].as_str().unwrap()).unwrap(), + ); signer_nonces.insert(identifier, signing_nonces);