diff --git a/fastcrypto-tbls/benches/tbls.rs b/fastcrypto-tbls/benches/tbls.rs index 5a0d356028..170f272fea 100644 --- a/fastcrypto-tbls/benches/tbls.rs +++ b/fastcrypto-tbls/benches/tbls.rs @@ -25,7 +25,7 @@ mod tbls_benches { .collect::>(); create.bench_function(format!("w={}", w).as_str(), |b| { - b.iter(|| ThresholdBls12381MinSig::partial_sign_batch(&shares, msg)) + b.iter(|| ThresholdBls12381MinSig::partial_sign_batch(shares.iter(), msg)) }); } } @@ -39,10 +39,10 @@ mod tbls_benches { .map(|i| private_poly.eval(NonZeroU32::new(i as u32).unwrap())) .collect::>(); - let sigs = ThresholdBls12381MinSig::partial_sign_batch(&shares, msg); + let sigs = ThresholdBls12381MinSig::partial_sign_batch(shares.iter(), msg); create.bench_function(format!("w={}", w).as_str(), |b| { - b.iter(|| ThresholdBls12381MinSig::aggregate(w as u32, &sigs).unwrap()) + b.iter(|| ThresholdBls12381MinSig::aggregate(w as u32, sigs.iter()).unwrap()) }); } } diff --git a/fastcrypto-tbls/src/tbls.rs b/fastcrypto-tbls/src/tbls.rs index 93e96b6251..dbe052d4b2 100644 --- a/fastcrypto-tbls/src/tbls.rs +++ b/fastcrypto-tbls/src/tbls.rs @@ -29,17 +29,19 @@ pub trait ThresholdBls { /// Sign a message using the private share/partial key. fn partial_sign(share: &Share, msg: &[u8]) -> PartialSignature { - Self::partial_sign_batch(&[share.clone()], msg)[0].clone() + Self::partial_sign_batch(std::iter::once(share), msg)[0].clone() } /// Sign a message using one of more private share/partial keys. - fn partial_sign_batch( - shares: &[Share], + fn partial_sign_batch<'a>( + shares: impl Iterator>, msg: &[u8], - ) -> Vec> { + ) -> Vec> + where + Self::Private: 'a, + { let h = Self::Signature::hash_to_group_element(msg); shares - .iter() .map(|share| PartialSignature { index: share.index, value: h * share.value, @@ -60,40 +62,40 @@ pub trait ThresholdBls { /// Verify a set of signatures done by a partial key holder. /// Randomly check if \sum r_i sig_i is a valid signature with public key \sum r_i p(i) G /// where r_i are random scalars, and p(i) are points on the polynomial. - fn partial_verify_batch( + fn partial_verify_batch<'a, R: AllowedRng>( vss_pk: &Poly, msg: &[u8], - partial_sigs: &[PartialSignature], + partial_sigs: impl Iterator>, rng: &mut R, - ) -> FastCryptoResult<()> { + ) -> FastCryptoResult<()> + where + Self::Signature: 'a, + { assert!(vss_pk.degree() > 0 || !msg.is_empty()); - if partial_sigs.is_empty() { + let (evals_as_scalars, points): (Vec<_>, Vec<_>) = partial_sigs + .map(|sig| (Self::Private::from(sig.index.get().into()), sig.value)) + .unzip(); + if points.is_empty() { return Ok(()); } - let rs = get_random_scalars::(partial_sigs.len() as u32, rng); - let evals_as_scalars = partial_sigs - .iter() - .map(|e| Self::Private::from(e.index.get().into())) - .collect::>(); + let rs = get_random_scalars::(points.len() as u32, rng); // TODO: should we cache it instead? that would replace t-wide msm with w-wide msm. let coeffs = batch_coefficients(&rs, &evals_as_scalars, vss_pk.degree()); let pk = Self::Public::multi_scalar_mul(&coeffs, vss_pk.as_vec()).expect("sizes match"); - let aggregated_sig = Self::Signature::multi_scalar_mul( - &rs, - &partial_sigs.iter().map(|s| s.value).collect::>(), - ) - .expect("sizes match"); + let aggregated_sig = Self::Signature::multi_scalar_mul(&rs, &points).expect("sizes match"); Self::verify(&pk, msg, &aggregated_sig) } /// Interpolate partial signatures to recover the full signature. - fn aggregate( + fn aggregate<'a>( threshold: u32, - partials: &[PartialSignature], - ) -> FastCryptoResult { + partials: impl Iterator>, + ) -> FastCryptoResult + where + Self::Signature: 'a, + { let unique_partials = partials - .iter() .unique_by(|p| p.index) .take(threshold as usize) .cloned() diff --git a/fastcrypto-tbls/src/tests/dkg_tests.rs b/fastcrypto-tbls/src/tests/dkg_tests.rs index 8bdb875e6f..9fc186c84d 100644 --- a/fastcrypto-tbls/src/tests/dkg_tests.rs +++ b/fastcrypto-tbls/src/tests/dkg_tests.rs @@ -237,7 +237,7 @@ fn test_dkg_e2e_5_parties_min_weight_2_threshold_4() { S::partial_verify(&o3.vss_pk, &MSG, &sig31).unwrap(); let sigs = vec![sig00, sig30, sig31]; - let sig = S::aggregate(d0.t(), &sigs).unwrap(); + let sig = S::aggregate(d0.t(), sigs.iter()).unwrap(); S::verify(o0.vss_pk.c0(), &MSG, &sig).unwrap(); } diff --git a/fastcrypto-tbls/src/tests/tbls_tests.rs b/fastcrypto-tbls/src/tests/tbls_tests.rs index 2f057e4205..08ff1a0393 100644 --- a/fastcrypto-tbls/src/tests/tbls_tests.rs +++ b/fastcrypto-tbls/src/tests/tbls_tests.rs @@ -34,11 +34,11 @@ fn test_tbls_e2e() { ThresholdBls12381MinSig::partial_verify(&public_poly, b"other message", &sig1).is_err() ); // Aggregate should fail if we don't have enough signatures. - assert!(ThresholdBls12381MinSig::aggregate(t, &[sig1.clone(), sig2.clone()]).is_err()); + assert!(ThresholdBls12381MinSig::aggregate(t, [sig1.clone(), sig2.clone()].iter()).is_err()); // Signatures should be the same no matter if calculated with the private key or from a // threshold of partial signatures. - let full_sig = ThresholdBls12381MinSig::aggregate(t, &[sig1, sig2, sig3]).unwrap(); + let full_sig = ThresholdBls12381MinSig::aggregate(t, [sig1, sig2, sig3].iter()).unwrap(); assert!(ThresholdBls12381MinSig::verify(public_poly.c0(), msg, &full_sig).is_ok()); assert_eq!( full_sig, @@ -69,26 +69,26 @@ fn test_partial_verify_batch() { assert!(ThresholdBls12381MinSig::partial_verify_batch( &public_poly, msg, - &[], + [].iter(), &mut thread_rng() ) .is_ok()); // standard sigs should pass - let sigs = ThresholdBls12381MinSig::partial_sign_batch(&shares, msg); + let sigs = ThresholdBls12381MinSig::partial_sign_batch(shares.iter(), msg); assert!(ThresholdBls12381MinSig::partial_verify_batch( &public_poly, msg, - &sigs, + sigs.iter(), &mut thread_rng() ) .is_ok()); // even if repeated - let mut sigs = ThresholdBls12381MinSig::partial_sign_batch(&shares, msg); + let mut sigs = ThresholdBls12381MinSig::partial_sign_batch(shares.iter(), msg); sigs[0] = sigs[2].clone(); assert!(ThresholdBls12381MinSig::partial_verify_batch( &public_poly, msg, - &sigs, + sigs.iter(), &mut thread_rng() ) .is_ok()); @@ -96,48 +96,48 @@ fn test_partial_verify_batch() { assert!(ThresholdBls12381MinSig::partial_verify_batch( &public_poly, b"other message", - &sigs, + sigs.iter(), &mut thread_rng() ) .is_err()); // invalid signatures according to the polynomial should fail - let mut sigs = ThresholdBls12381MinSig::partial_sign_batch(&shares, msg); + let mut sigs = ThresholdBls12381MinSig::partial_sign_batch(shares.iter(), msg); (sigs[0].index, sigs[1].index) = (sigs[1].index, sigs[0].index); assert!(ThresholdBls12381MinSig::partial_verify_batch( &public_poly, msg, - &sigs, + sigs.iter(), &mut thread_rng() ) .is_err()); // identity as the signature should fail - let mut sigs = ThresholdBls12381MinSig::partial_sign_batch(&shares, msg); + let mut sigs = ThresholdBls12381MinSig::partial_sign_batch(shares.iter(), msg); sigs[1].value = G1Element::zero(); assert!(ThresholdBls12381MinSig::partial_verify_batch( &public_poly, msg, - &sigs, + sigs.iter(), &mut thread_rng() ) .is_err()); // generator as the signature should fail - let mut sigs = ThresholdBls12381MinSig::partial_sign_batch(&shares, msg); + let mut sigs = ThresholdBls12381MinSig::partial_sign_batch(shares.iter(), msg); sigs[1].value = G1Element::generator(); assert!(ThresholdBls12381MinSig::partial_verify_batch( &public_poly, msg, - &sigs, + sigs.iter(), &mut thread_rng() ) .is_err()); // even if the sum of sigs is ok, should fail since not consistent with the polynomial - let mut sigs = ThresholdBls12381MinSig::partial_sign_batch(&shares, msg); + let mut sigs = ThresholdBls12381MinSig::partial_sign_batch(shares.iter(), msg); sigs[0].value -= G1Element::generator(); sigs[1].value += G1Element::generator(); assert!(ThresholdBls12381MinSig::partial_verify_batch( &public_poly, msg, - &sigs, + sigs.iter(), &mut thread_rng() ) .is_err());