Skip to content

Commit

Permalink
ThresholdBls: accept Iterator directly where possible
Browse files Browse the repository at this point in the history
Instead of requiring a slice that we immediately and only call
`iter()` on, accept the Iterator. This can enable clients to avoid
extra copies.
  • Loading branch information
aschran committed Dec 12, 2023
1 parent 14d62bb commit e4a7664
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 43 deletions.
6 changes: 3 additions & 3 deletions fastcrypto-tbls/benches/tbls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ mod tbls_benches {
.collect::<Vec<_>>();

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))
});
}
}
Expand All @@ -39,10 +39,10 @@ mod tbls_benches {
.map(|i| private_poly.eval(NonZeroU32::new(i as u32).unwrap()))
.collect::<Vec<_>>();

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())
});
}
}
Expand Down
48 changes: 25 additions & 23 deletions fastcrypto-tbls/src/tbls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,19 @@ pub trait ThresholdBls {

/// Sign a message using the private share/partial key.
fn partial_sign(share: &Share<Self::Private>, msg: &[u8]) -> PartialSignature<Self::Signature> {
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<Self::Private>],
fn partial_sign_batch<'a>(
shares: impl Iterator<Item = &'a Share<Self::Private>>,
msg: &[u8],
) -> Vec<PartialSignature<Self::Signature>> {
) -> Vec<PartialSignature<Self::Signature>>
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,
Expand All @@ -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<R: AllowedRng>(
fn partial_verify_batch<'a, R: AllowedRng>(
vss_pk: &Poly<Self::Public>,
msg: &[u8],
partial_sigs: &[PartialSignature<Self::Signature>],
partial_sigs: impl Iterator<Item = &'a PartialSignature<Self::Signature>>,
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::<Self::Private, R>(partial_sigs.len() as u32, rng);
let evals_as_scalars = partial_sigs
.iter()
.map(|e| Self::Private::from(e.index.get().into()))
.collect::<Vec<_>>();
let rs = get_random_scalars::<Self::Private, R>(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::<Vec<_>>(),
)
.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<Self::Signature>],
) -> FastCryptoResult<Self::Signature> {
partials: impl Iterator<Item = &'a PartialSignature<Self::Signature>>,
) -> FastCryptoResult<Self::Signature>
where
Self::Signature: 'a,
{
let unique_partials = partials
.iter()
.unique_by(|p| p.index)
.take(threshold as usize)
.cloned()
Expand Down
2 changes: 1 addition & 1 deletion fastcrypto-tbls/src/tests/dkg_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}

Expand Down
32 changes: 16 additions & 16 deletions fastcrypto-tbls/src/tests/tbls_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -69,75 +69,75 @@ 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());
// different msg should fail
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());
Expand Down

0 comments on commit e4a7664

Please sign in to comment.