Skip to content

Commit 2d88eb4

Browse files
authored
refactor: bls_signatures: use iterators instead of slices in various APIs (#371)
The use of iterators allows the caller to use the API without having to `collect()` the items first. This will help in eliminating a `collect()` [here](https://github.com/anza-xyz/alpenglow/blob/master/votor/src/consensus_pool/vote_certificate_builder.rs#L106-L109).
1 parent 8ebe2fc commit 2d88eb4

File tree

3 files changed

+68
-65
lines changed

3 files changed

+68
-65
lines changed

bls-signatures/benches/bls_signatures.rs

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,9 @@ fn bench_aggregate(c: &mut Criterion) {
3939
let signatures: Vec<SignatureProjective> =
4040
keypairs.iter().map(|kp| kp.sign(message)).collect();
4141

42-
let pubkey_refs: Vec<&PubkeyProjective> = pubkeys.iter().collect();
43-
let signature_refs: Vec<&SignatureProjective> = signatures.iter().collect();
44-
4542
// Benchmark for aggregating multiple signatures
4643
group.bench_function(format!("{num_validators} signature aggregation"), |b| {
47-
b.iter(|| black_box(SignatureProjective::aggregate(&signature_refs)));
44+
b.iter(|| black_box(SignatureProjective::aggregate(signatures.iter())));
4845
});
4946

5047
#[cfg(feature = "parallel")]
@@ -57,7 +54,7 @@ fn bench_aggregate(c: &mut Criterion) {
5754

5855
// Benchmark for aggregating multiple public keys
5956
group.bench_function(format!("{num_validators} pubkey aggregation"), |b| {
60-
b.iter(|| black_box(PubkeyProjective::aggregate(&pubkey_refs)));
57+
b.iter(|| black_box(PubkeyProjective::aggregate(pubkeys.iter())));
6158
});
6259

6360
// Benchmark for aggregate verify
@@ -75,8 +72,8 @@ fn bench_aggregate(c: &mut Criterion) {
7572
b.iter(|| {
7673
let verification_result = black_box(
7774
SignatureProjective::verify_aggregate(
78-
&pubkey_refs,
79-
&signature_refs,
75+
pubkeys.iter(),
76+
signatures.iter(),
8077
message,
8178
)
8279
.unwrap(),
@@ -149,7 +146,6 @@ fn bench_batch_verification(c: &mut Criterion) {
149146
.zip(message_refs.iter())
150147
.map(|(kp, msg)| kp.sign(msg).into())
151148
.collect();
152-
let signature_refs: Vec<&Signature> = signatures.iter().collect();
153149

154150
group.bench_function(
155151
format!("{num_validators} sequential batch verification"),
@@ -158,7 +154,7 @@ fn bench_batch_verification(c: &mut Criterion) {
158154
let verification_result = black_box(
159155
SignatureProjective::verify_distinct(
160156
&pubkey_refs,
161-
&signature_refs,
157+
&signatures,
162158
&message_refs,
163159
)
164160
.unwrap(),

bls-signatures/src/pubkey.rs

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -105,9 +105,9 @@ impl PubkeyProjective {
105105

106106
/// Aggregate a list of public keys into an existing aggregate
107107
#[allow(clippy::arithmetic_side_effects)]
108-
pub fn aggregate_with<P: AsPubkeyProjective + ?Sized>(
108+
pub fn aggregate_with<'a, P: AsPubkeyProjective + ?Sized + 'a>(
109109
&mut self,
110-
pubkeys: &[&P],
110+
pubkeys: impl Iterator<Item = &'a P>,
111111
) -> Result<(), BlsError> {
112112
for pubkey in pubkeys {
113113
self.0 += pubkey.try_as_projective()?.0;
@@ -117,18 +117,16 @@ impl PubkeyProjective {
117117

118118
/// Aggregate a list of public keys
119119
#[allow(clippy::arithmetic_side_effects)]
120-
pub fn aggregate<P: AsPubkeyProjective + ?Sized>(
121-
pubkeys: &[&P],
120+
pub fn aggregate<'a, P: AsPubkeyProjective + ?Sized + 'a>(
121+
mut pubkeys: impl Iterator<Item = &'a P>,
122122
) -> Result<PubkeyProjective, BlsError> {
123-
if pubkeys.is_empty() {
124-
return Err(BlsError::EmptyAggregation);
125-
}
126-
if let Some((first, rest)) = pubkeys.split_first() {
127-
let mut aggregate = first.try_as_projective()?;
128-
aggregate.aggregate_with(rest)?;
129-
Ok(aggregate)
130-
} else {
131-
Err(BlsError::EmptyAggregation)
123+
match pubkeys.next() {
124+
Some(first) => {
125+
let mut aggregate = first.try_as_projective()?;
126+
aggregate.aggregate_with(pubkeys)?;
127+
Ok(aggregate)
128+
}
129+
None => Err(BlsError::EmptyAggregation),
132130
}
133131
}
134132

@@ -471,9 +469,10 @@ mod tests {
471469
let dyn_pubkeys: std::vec::Vec<&dyn AsPubkeyProjective> =
472470
std::vec![&pubkey_projective, &pubkey_affine, &pubkey_compressed];
473471

474-
let aggregate_from_dyn = PubkeyProjective::aggregate(&dyn_pubkeys).unwrap();
472+
let aggregate_from_dyn = PubkeyProjective::aggregate(dyn_pubkeys.into_iter()).unwrap();
475473
let pubkeys_for_baseline = [&keypair0.public, &keypair1.public, &keypair1.public];
476-
let baseline_aggregate = PubkeyProjective::aggregate(&pubkeys_for_baseline).unwrap();
474+
let baseline_aggregate =
475+
PubkeyProjective::aggregate(pubkeys_for_baseline.into_iter()).unwrap();
477476

478477
assert_eq!(aggregate_from_dyn, baseline_aggregate);
479478
}

bls-signatures/src/signature.rs

Lines changed: 49 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,9 @@ impl SignatureProjective {
8181

8282
/// Aggregate a list of signatures into an existing aggregate
8383
#[allow(clippy::arithmetic_side_effects)]
84-
pub fn aggregate_with<S: AsSignatureProjective + ?Sized>(
84+
pub fn aggregate_with<'a, S: AsSignatureProjective + ?Sized + 'a>(
8585
&mut self,
86-
signatures: &[&S],
86+
signatures: impl Iterator<Item = &'a S>,
8787
) -> Result<(), BlsError> {
8888
for signature in signatures {
8989
self.0 += signature.try_as_projective()?.0;
@@ -92,23 +92,27 @@ impl SignatureProjective {
9292
}
9393

9494
/// Aggregate a list of signatures
95-
#[allow(clippy::arithmetic_side_effects)]
96-
pub fn aggregate<S: AsSignatureProjective + ?Sized>(
97-
signatures: &[&S],
95+
pub fn aggregate<'a, S: AsSignatureProjective + ?Sized + 'a>(
96+
mut signatures: impl Iterator<Item = &'a S>,
9897
) -> Result<SignatureProjective, BlsError> {
99-
if let Some((first, rest)) = signatures.split_first() {
100-
let mut aggregate = first.try_as_projective()?;
101-
aggregate.aggregate_with(rest)?;
102-
Ok(aggregate)
103-
} else {
104-
Err(BlsError::EmptyAggregation)
98+
match signatures.next() {
99+
Some(first) => {
100+
let mut aggregate = first.try_as_projective()?;
101+
aggregate.aggregate_with(signatures)?;
102+
Ok(aggregate)
103+
}
104+
None => Err(BlsError::EmptyAggregation),
105105
}
106106
}
107107

108108
/// Verify a list of signatures against a message and a list of public keys
109-
pub fn verify_aggregate<P: AsPubkeyProjective + ?Sized, S: AsSignatureProjective + ?Sized>(
110-
public_keys: &[&P],
111-
signatures: &[&S],
109+
pub fn verify_aggregate<
110+
'a,
111+
P: AsPubkeyProjective + ?Sized + 'a,
112+
S: AsSignatureProjective + ?Sized + 'a,
113+
>(
114+
public_keys: impl Iterator<Item = &'a P>,
115+
signatures: impl Iterator<Item = &'a S>,
112116
message: &[u8],
113117
) -> Result<bool, BlsError> {
114118
let aggregate_pubkey = PubkeyProjective::aggregate(public_keys)?;
@@ -121,7 +125,7 @@ impl SignatureProjective {
121125
/// public keys.
122126
pub fn verify_distinct(
123127
public_keys: &[&Pubkey],
124-
signatures: &[&Signature],
128+
signatures: &[Signature],
125129
messages: &[&[u8]],
126130
) -> Result<bool, BlsError> {
127131
if public_keys.len() != messages.len() || public_keys.len() != signatures.len() {
@@ -130,7 +134,7 @@ impl SignatureProjective {
130134
if public_keys.is_empty() {
131135
return Err(BlsError::EmptyAggregation);
132136
}
133-
let aggregate_signature = SignatureProjective::aggregate(signatures)?;
137+
let aggregate_signature = SignatureProjective::aggregate(signatures.iter())?;
134138
Self::verify_distinct_aggregated(public_keys, &aggregate_signature.into(), messages)
135139
}
136140

@@ -486,11 +490,11 @@ mod tests {
486490
let signature1_affine: Signature = signature1.into();
487491

488492
let aggregate_signature =
489-
SignatureProjective::aggregate(&[&signature0, &signature1]).unwrap();
493+
SignatureProjective::aggregate([&signature0, &signature1].into_iter()).unwrap();
490494

491495
let mut aggregate_signature_with = signature0;
492496
aggregate_signature_with
493-
.aggregate_with(&[&signature1_affine])
497+
.aggregate_with([&signature1_affine].into_iter())
494498
.unwrap();
495499

496500
assert_eq!(aggregate_signature, aggregate_signature_with);
@@ -516,8 +520,8 @@ mod tests {
516520

517521
// basic case
518522
assert!(SignatureProjective::verify_aggregate(
519-
&[&keypair0.public, &keypair1.public],
520-
&[&signature0, &signature1],
523+
[&keypair0.public, &keypair1.public].into_iter(),
524+
[&signature0, &signature1].into_iter(),
521525
test_message,
522526
)
523527
.unwrap());
@@ -528,44 +532,46 @@ mod tests {
528532
let signature0_affine: Signature = signature0.into();
529533
let signature1_affine: Signature = signature1.into();
530534
assert!(SignatureProjective::verify_aggregate(
531-
&[&pubkey0_affine, &pubkey1_affine],
532-
&[&signature0_affine, &signature1_affine],
535+
[&pubkey0_affine, &pubkey1_affine].into_iter(),
536+
[&signature0_affine, &signature1_affine].into_iter(),
533537
test_message,
534538
)
535539
.unwrap());
536540

537541
// pre-aggregate the signatures
538542
let aggregate_signature =
539-
SignatureProjective::aggregate(&[&signature0, &signature1]).unwrap();
543+
SignatureProjective::aggregate([&signature0, &signature1].into_iter()).unwrap();
540544
assert!(SignatureProjective::verify_aggregate(
541-
&[&keypair0.public, &keypair1.public],
542-
&[&aggregate_signature],
545+
[&keypair0.public, &keypair1.public].into_iter(),
546+
[&aggregate_signature].into_iter(),
543547
test_message,
544548
)
545549
.unwrap());
546550

547551
// pre-aggregate the public keys
548552
let aggregate_pubkey =
549-
PubkeyProjective::aggregate(&[&keypair0.public, &keypair1.public]).unwrap();
553+
PubkeyProjective::aggregate([&keypair0.public, &keypair1.public].into_iter()).unwrap();
550554
assert!(SignatureProjective::verify_aggregate(
551-
&[&aggregate_pubkey],
552-
&[&signature0, &signature1],
555+
[&aggregate_pubkey].into_iter(),
556+
[&signature0, &signature1].into_iter(),
553557
test_message,
554558
)
555559
.unwrap());
560+
let pubkeys = Vec::new() as Vec<PubkeyProjective>;
556561

557562
// empty set of public keys or signatures
558563
let err = SignatureProjective::verify_aggregate(
559-
&[] as &[&PubkeyProjective],
560-
&[&signature0, &signature1],
564+
pubkeys.iter(),
565+
[&signature0, &signature1].into_iter(),
561566
test_message,
562567
)
563568
.unwrap_err();
564569
assert_eq!(err, BlsError::EmptyAggregation);
565570

571+
let signatures = Vec::new() as Vec<&SignatureProjective>;
566572
let err = SignatureProjective::verify_aggregate(
567-
&[&keypair0.public, &keypair1.public],
568-
&[] as &[&SignatureProjective],
573+
[&keypair0.public, &keypair1.public].into_iter(),
574+
signatures.into_iter(),
569575
test_message,
570576
)
571577
.unwrap_err();
@@ -593,7 +599,7 @@ mod tests {
593599
// Success cases
594600
let pubkeys_refs = [&keypair0.public, &keypair1.public, &keypair2.public];
595601
let messages_refs_vec: Vec<&[u8]> = std::vec![message0, message1, message2];
596-
let signatures_refs = [&signature0, &signature1, &signature2];
602+
let signatures_refs = std::vec![signature0, signature1, signature2];
597603

598604
assert!(SignatureProjective::verify_distinct(
599605
&pubkeys_refs,
@@ -630,7 +636,7 @@ mod tests {
630636

631637
let wrong_signature_proj = wrong_keypair.sign(message1);
632638
let wrong_signature: Signature = wrong_signature_proj.into();
633-
let wrong_signatures = [&signature0, &wrong_signature, &signature2];
639+
let wrong_signatures = [signature0, wrong_signature, signature2];
634640
assert!(!SignatureProjective::verify_distinct(
635641
&pubkeys_refs,
636642
&wrong_signatures,
@@ -656,7 +662,7 @@ mod tests {
656662

657663
let err = SignatureProjective::verify_distinct(
658664
&[] as &[&Pubkey],
659-
&[] as &[&Signature],
665+
&[] as &[Signature],
660666
&[] as &[&[u8]],
661667
)
662668
.unwrap_err();
@@ -689,19 +695,21 @@ mod tests {
689695
let dyn_signatures: Vec<&dyn AsSignatureProjective> =
690696
std::vec![&signature0, &signature1_affine, &signature2_compressed];
691697

692-
assert!(
693-
SignatureProjective::verify_aggregate(&dyn_pubkeys, &dyn_signatures, test_message)
694-
.unwrap()
695-
);
698+
assert!(SignatureProjective::verify_aggregate(
699+
dyn_pubkeys.into_iter(),
700+
dyn_signatures.into_iter(),
701+
test_message
702+
)
703+
.unwrap());
696704

697705
let wrong_message = b"this is not the correct message";
698706
let dyn_pubkeys_fail: Vec<&dyn AsPubkeyProjective> =
699707
std::vec![&pubkey0, &pubkey1_affine, &pubkey2_compressed];
700708
let dyn_signatures_fail: Vec<&dyn AsSignatureProjective> =
701709
std::vec![&signature0, &signature1_affine, &signature2_compressed];
702710
assert!(!SignatureProjective::verify_aggregate(
703-
&dyn_pubkeys_fail,
704-
&dyn_signatures_fail,
711+
dyn_pubkeys_fail.into_iter(),
712+
dyn_signatures_fail.into_iter(),
705713
wrong_message
706714
)
707715
.unwrap());

0 commit comments

Comments
 (0)