Skip to content

Commit f4ebe78

Browse files
committed
perf: parallel proceessing in vess verifier
1 parent 19d626d commit f4ebe78

File tree

1 file changed

+55
-32
lines changed

1 file changed

+55
-32
lines changed

timeboost-crypto/src/vess.rs

Lines changed: 55 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ impl<C: CurveGroup> ShoupVess<C> {
176176
aad: &[u8],
177177
) -> Result<(), VessError>
178178
where
179-
I: IntoIterator<Item = &'a mre::EncryptionKey<C>> + Clone,
179+
I: IntoIterator<Item = &'a mre::EncryptionKey<C>> + Clone + Sync,
180180
I::IntoIter: ExactSizeIterator,
181181
{
182182
self.verify_internal(committee, recipients, ct, comm, aad, Mode::Dkg)
@@ -194,7 +194,7 @@ impl<C: CurveGroup> ShoupVess<C> {
194194
pub_share: C,
195195
) -> Result<(), VessError>
196196
where
197-
I: IntoIterator<Item = &'a mre::EncryptionKey<C>> + Clone,
197+
I: IntoIterator<Item = &'a mre::EncryptionKey<C>> + Clone + Sync,
198198
I::IntoIter: ExactSizeIterator,
199199
{
200200
self.verify_internal(
@@ -490,7 +490,7 @@ impl<C: CurveGroup> ShoupVess<C> {
490490
mode: Mode<C>,
491491
) -> Result<(), VessError>
492492
where
493-
I: IntoIterator<Item = &'a mre::EncryptionKey<C>> + Clone,
493+
I: IntoIterator<Item = &'a mre::EncryptionKey<C>> + Clone + Sync,
494494
I::IntoIter: ExactSizeIterator,
495495
{
496496
let vss_pp = FeldmanVssPublicParam::from(committee).with_lookup_table();
@@ -499,7 +499,7 @@ impl<C: CurveGroup> ShoupVess<C> {
499499
.to_verifier_state(&ct.transcript);
500500

501501
// verifier logic
502-
let (expected_comm, h, subset_seed, mut shifted_polys, mut mre_cts, mut seeds) =
502+
let (expected_comm, h, subset_seed, shifted_polys, mre_cts, seeds) =
503503
self.verify_core(&vss_pp, &mut verifier_state, &mode)?;
504504
if &expected_comm != comm {
505505
return Err(VessError::WrongCommitment);
@@ -511,49 +511,72 @@ impl<C: CurveGroup> ShoupVess<C> {
511511

512512
// k in S, then homomorphically shift commitment; k notin S, reproduce dealing from seed
513513
let subset_indices = self.map_subset_seed(subset_seed);
514-
let mut subset_iter = subset_indices.iter().peekable();
515-
let mut next_subset_idx = subset_iter.next();
516-
for i in 0..self.num_repetition {
517-
match next_subset_idx {
518-
Some(j) if i == *j => {
514+
515+
// Convert subset_indices to a HashSet for O(1) lookup
516+
let subset_set: std::collections::HashSet<usize> = subset_indices.iter().copied().collect();
517+
518+
// Create vectors to store the shifted polys and mre_cts data in the correct order
519+
let mut shifted_polys_vec = Vec::new();
520+
let mut mre_cts_vec = Vec::new();
521+
let mut seeds_vec = Vec::new();
522+
523+
// Convert VecDeque to Vec to preserve order for subset items
524+
for poly in shifted_polys.iter() {
525+
shifted_polys_vec.push(poly.clone());
526+
}
527+
for ct in mre_cts.iter() {
528+
mre_cts_vec.push(ct.clone());
529+
}
530+
for seed in seeds.iter() {
531+
seeds_vec.push(*seed);
532+
}
533+
534+
// Compute all hash data in parallel
535+
let hash_data = (0..self.num_repetition)
536+
.into_par_iter()
537+
.map(|i| {
538+
if subset_set.contains(&i) {
519539
// k in S, shift the commitment
520-
let shifted_comm = vss_pp.commit(
521-
&shifted_polys
522-
.pop_front()
523-
.expect("subset_size > 0, so is shifted_polys.len()"),
524-
);
540+
// Find the position of i in subset_indices to get the correct poly/ct
541+
let subset_pos = subset_indices
542+
.iter()
543+
.position(|&x| x == i)
544+
.expect("i should be in subset_indices");
545+
546+
let shifted_comm = vss_pp.commit(&shifted_polys_vec[subset_pos]);
525547

526548
let mut unshifted_comm = vec![];
527549
for (shifted, delta) in shifted_comm.into_iter().zip(comm.iter()) {
528550
// g^omega'' / C in paper
529551
unshifted_comm.push(shifted - delta);
530552
}
531553
let unshifted_comm = C::normalize_batch(&unshifted_comm);
532-
hasher.update(serialize_to_vec![unshifted_comm]?);
533-
534-
let mre_ct = mre_cts
535-
.pop_front()
536-
.expect("subset_size > 0, so is mre_cts.len()");
537-
hasher.update(mre_ct.to_bytes());
554+
let unshifted_comm_bytes = serialize_to_vec![unshifted_comm]?;
555+
let mre_ct_bytes = mre_cts_vec[subset_pos].to_bytes();
538556

539-
next_subset_idx = subset_iter.next();
540-
}
541-
_ => {
557+
Ok((unshifted_comm_bytes, mre_ct_bytes))
558+
} else {
542559
// k notin S, reproduce the dealing deterministically from seed
543-
let seed = seeds
544-
.pop_front()
545-
.expect("subset_size < num_repetitions, so seeds.len() > 0");
560+
// Find the position of i among non-subset indices
561+
let non_subset_pos = (0..i).filter(|&j| !subset_set.contains(&j)).count();
562+
let seed = seeds_vec[non_subset_pos];
563+
546564
let (_poly, cm, mre_ct) =
547565
self.new_dealing(&vss_pp, i, &seed, recipients.clone(), aad)?;
548566

549-
hasher.update(serialize_to_vec![cm]?);
550-
hasher.update(mre_ct.to_bytes());
567+
let cm_bytes = serialize_to_vec![cm]?;
568+
let mre_ct_bytes = mre_ct.to_bytes();
569+
570+
Ok((cm_bytes, mre_ct_bytes))
551571
}
552-
}
572+
})
573+
.collect::<Result<Vec<_>, VessError>>()?;
574+
575+
// Apply all hash updates in the correct sequential order
576+
for (cm_bytes, mre_ct_bytes) in hash_data {
577+
hasher.update(&cm_bytes);
578+
hasher.update(&mre_ct_bytes);
553579
}
554-
debug_assert!(shifted_polys.is_empty());
555-
debug_assert!(mre_cts.is_empty());
556-
debug_assert!(seeds.is_empty());
557580

558581
if h == hasher.finalize().as_slice() {
559582
Ok(())

0 commit comments

Comments
 (0)