Skip to content

Commit 584b718

Browse files
committed
Avoid cloning bundles and use Arc<Inner> in cell.
1 parent 090f0dd commit 584b718

File tree

4 files changed

+90
-39
lines changed

4 files changed

+90
-39
lines changed

timeboost-sequencer/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,5 @@ tracing = { workspace = true }
3333
ark-std = { workspace = true }
3434
bs58 = { workspace = true }
3535
futures = { workspace = true }
36-
test-utils = { path = "../test-utils", features = ["ports"]}
36+
test-utils = { path = "../test-utils", features = ["ports"] }
3737
timeboost-utils = { path = "../timeboost-utils" }

timeboost-sequencer/src/decrypt.rs

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,28 @@
1+
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet, VecDeque};
2+
use std::result::Result as StdResult;
3+
use std::sync::Arc;
4+
15
use ark_std::{UniformRand, rand::thread_rng};
26
use bon::Builder;
37
use bytes::{BufMut, Bytes, BytesMut};
48
use cliquenet::overlay::{Data, DataError, NetworkDown, Overlay};
59
use cliquenet::{
610
AddressableCommittee, MAX_MESSAGE_SIZE, Network, NetworkError, NetworkMetrics, Role,
711
};
8-
use rayon::iter::ParallelIterator;
9-
use rayon::prelude::*;
10-
1112
use multisig::{Committee, CommitteeId, PublicKey};
1213
use parking_lot::RwLock;
14+
use rayon::iter::ParallelIterator;
15+
use rayon::prelude::*;
1316
use sailfish::types::{Evidence, Round, RoundNumber};
1417
use serde::{Deserialize, Serialize};
15-
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet, VecDeque};
16-
use std::result::Result as StdResult;
17-
use std::sync::Arc;
1818
use timeboost_config::DECRYPTER_PORT_OFFSET;
1919
use timeboost_crypto::prelude::{
2020
DkgDecKey, LabeledDkgDecKey, Plaintext, ThresholdCiphertext, ThresholdDecShare,
2121
ThresholdEncError, ThresholdEncScheme, ThresholdScheme, Vess, VssSecret,
2222
};
2323
use timeboost_types::{
24-
AccumulatorMode, DkgAccumulator, DkgBundle, DkgSubset, InclusionList, KeyStore, KeyStoreVec,
25-
ThresholdKey, ThresholdKeyCell,
24+
AccumulatorMode, DkgAccumulator, DkgBundle, DkgSubset, DkgSubsetRef, InclusionList, KeyStore,
25+
KeyStoreVec, ThresholdKey, ThresholdKeyCell,
2626
};
2727
use tokio::spawn;
2828
use tokio::sync::mpsc::{Receiver, Sender, channel};
@@ -728,21 +728,31 @@ impl Worker {
728728
.ok_or(DecrypterError::NoCommittee(self.current))?;
729729

730730
let prev = (guard.len() == 2).then(|| guard.last().clone());
731-
732-
subsets.insert(src, res.subset.to_owned());
733731
let committee = current.committee();
734732
let threshold: usize = committee.one_honest_threshold().into();
735733

736-
let mut counts = HashMap::new();
737-
for subset in subsets.values() {
738-
*counts.entry(subset).or_insert(0) += 1;
734+
subsets.insert(src, res.subset);
735+
736+
let mut subset_groups: HashMap<DkgSubsetRef, Vec<&PublicKey>> = HashMap::new();
737+
let mut threshold_subset = None;
738+
739+
for (pk, subset) in subsets.iter() {
740+
let pks = subset_groups.entry(subset.as_ref()).or_default();
741+
pks.push(pk);
742+
743+
if pks.len() >= threshold {
744+
threshold_subset = Some((subset.as_ref(), pks[0]));
745+
break;
746+
}
739747
}
740748

741-
if let Some((&subset, _)) = counts.iter().find(|(_, count)| **count >= threshold) {
742-
let acc = DkgAccumulator::from_subset(current.clone(), subset.to_owned());
749+
if let Some((subset_ref, pk)) = threshold_subset {
750+
let subset = subsets.to_owned().remove(pk).expect("subset exists in map");
751+
let acc = DkgAccumulator::from_subset(current.clone(), subset);
743752
let mode = acc.mode().clone();
744753
self.tracker.insert(committee.id(), acc);
745-
let dec_key = subset
754+
755+
let dec_key = subset_ref
746756
.extract_key(current, &self.dkg_sk, prev.as_ref())
747757
.map_err(|e| DecrypterError::Dkg(e.to_string()))?;
748758

@@ -830,7 +840,7 @@ impl Worker {
830840
if matches!(mode, AccumulatorMode::Dkg) {
831841
if let Some(subset) = acc.try_finalize() {
832842
let dec_key = subset
833-
.extract_key(&key_store.clone(), &self.dkg_sk, None)
843+
.extract_key(&key_store, &self.dkg_sk, None)
834844
.map_err(|e| DecrypterError::Dkg(e.to_string()))?;
835845
self.dec_key.set(dec_key);
836846
self.state = WorkerState::Running;

timeboost-types/src/decryption.rs

Lines changed: 60 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -131,10 +131,15 @@ impl ThresholdKey {
131131

132132
/// `DecryptionKeyCell` is a thread-safe container for an optional `DecryptionKey`
133133
/// that allows asynchronous notification when the key is set.
134-
#[derive(Debug, Clone, Default)]
134+
#[derive(Debug, Default)]
135135
pub struct ThresholdKeyCell {
136-
key: Arc<RwLock<Option<ThresholdKey>>>,
137-
notify: Arc<Notify>,
136+
inner: Arc<ThresholdKeyCellInner>,
137+
}
138+
139+
#[derive(Debug, Default)]
140+
struct ThresholdKeyCellInner {
141+
key: RwLock<Option<ThresholdKey>>,
142+
notify: Notify,
138143
}
139144

140145
impl ThresholdKeyCell {
@@ -143,25 +148,25 @@ impl ThresholdKeyCell {
143148
}
144149

145150
pub fn set(&self, key: ThresholdKey) {
146-
*self.key.write() = Some(key);
147-
self.notify.notify_waiters();
151+
*self.inner.key.write() = Some(key);
152+
self.inner.notify.notify_waiters();
148153
}
149154

150155
pub fn get(&self) -> Option<ThresholdKey> {
151-
(*self.key.read()).clone()
156+
(*self.inner.key.read()).clone()
152157
}
153158

154159
pub fn enc_key(&self) -> Option<ThresholdEncKey> {
155160
self.get().map(|sk| sk.pubkey)
156161
}
157162

158163
pub fn get_ref(&self) -> impl Deref<Target = Option<ThresholdKey>> {
159-
self.key.read()
164+
self.inner.key.read()
160165
}
161166

162167
pub async fn read(&self) -> ThresholdKey {
163168
loop {
164-
let fut = self.notify.notified();
169+
let fut = self.inner.notify.notified();
165170
if let Some(k) = self.get() {
166171
return k;
167172
}
@@ -170,6 +175,14 @@ impl ThresholdKeyCell {
170175
}
171176
}
172177

178+
impl Clone for ThresholdKeyCell {
179+
fn clone(&self) -> Self {
180+
Self {
181+
inner: self.inner.clone(),
182+
}
183+
}
184+
}
185+
173186
/// A small, non-empty collection of KeyStores.
174187
#[derive(Debug, Default, Clone)]
175188
#[allow(clippy::len_without_is_empty)]
@@ -280,10 +293,10 @@ impl<const N: usize> From<KeyStore> for KeyStoreVec<N> {
280293

281294
/// A `KeyStore` with committee information and public keys used in the DKG or key resharing
282295
#[derive(Debug, Clone)]
283-
pub struct KeyStore(Arc<Inner>);
296+
pub struct KeyStore(Arc<KeyStoreInner>);
284297

285298
#[derive(Debug)]
286-
struct Inner {
299+
struct KeyStoreInner {
287300
committee: Committee,
288301
keys: BTreeMap<KeyId, DkgEncKey>,
289302
}
@@ -294,7 +307,7 @@ impl KeyStore {
294307
I: IntoIterator<Item = (T, DkgEncKey)>,
295308
T: Into<KeyId>,
296309
{
297-
let this = Self(Arc::new(Inner {
310+
let this = Self(Arc::new(KeyStoreInner {
298311
committee: c,
299312
keys: keys.into_iter().map(|(i, k)| (i.into(), k)).collect(),
300313
}));
@@ -446,20 +459,19 @@ impl DkgAccumulator {
446459
}
447460

448461
/// Try to finalize the accumulator into a subset if enough bundles are collected.
449-
pub fn try_finalize(&mut self) -> Option<DkgSubset> {
462+
/// Returns a reference to the internal data to avoid cloning the bundles.
463+
pub fn try_finalize(&self) -> Option<DkgSubsetRef<'_>> {
450464
if self.complete {
451465
let combkey = match &self.mode {
452466
AccumulatorMode::Dkg => None,
453467
AccumulatorMode::Resharing(combkey) => Some(combkey.clone()),
454468
};
455469

456-
let subset = DkgSubset {
470+
Some(DkgSubsetRef {
457471
committee_id: self.committee().id(),
458-
bundles: self.bundles.clone(),
472+
bundles: &self.bundles,
459473
combkey,
460-
};
461-
462-
Some(subset)
474+
})
463475
} else {
464476
None
465477
}
@@ -488,6 +500,14 @@ pub struct DkgSubset {
488500
combkey: Option<ThresholdCombKey>,
489501
}
490502

503+
/// A reference-based version of DkgSubset to avoid cloning bundles.
504+
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
505+
pub struct DkgSubsetRef<'a> {
506+
committee_id: CommitteeId,
507+
bundles: &'a [DkgBundle],
508+
combkey: Option<ThresholdCombKey>,
509+
}
510+
491511
impl DkgSubset {
492512
/// Create a new subset with DKG bundles.
493513
pub fn new_dkg(committee_id: CommitteeId, bundles: Vec<DkgBundle>) -> Self {
@@ -536,6 +556,27 @@ impl DkgSubset {
536556
self.combkey.is_some()
537557
}
538558

559+
/// Convert this DkgSubset to a DkgSubsetRef.
560+
pub fn as_ref(&self) -> DkgSubsetRef<'_> {
561+
DkgSubsetRef {
562+
committee_id: self.committee_id,
563+
bundles: &self.bundles,
564+
combkey: self.combkey.as_ref().cloned(),
565+
}
566+
}
567+
568+
/// Extract the new threshold decryption key from the subset.
569+
pub fn extract_key(
570+
&self,
571+
curr: &KeyStore,
572+
dkg_sk: &LabeledDkgDecKey,
573+
prev: Option<&KeyStore>,
574+
) -> anyhow::Result<ThresholdKey> {
575+
self.as_ref().extract_key(curr, dkg_sk, prev)
576+
}
577+
}
578+
579+
impl<'a> DkgSubsetRef<'a> {
539580
/// Extract the new threshold decryption key from the subset.
540581
pub fn extract_key(
541582
&self,
@@ -547,7 +588,7 @@ impl DkgSubset {
547588

548589
match &self.combkey {
549590
None => {
550-
let mut dealings_iter = ResultIter::new(self.bundles().iter().map(|b| {
591+
let mut dealings_iter = ResultIter::new(self.bundles.iter().map(|b| {
551592
vess.decrypt_share(curr.committee(), dkg_sk, b.vess_ct(), DKG_AAD)
552593
.map(|s| (s, b.comm().clone()))
553594
}));
@@ -568,7 +609,7 @@ impl DkgSubset {
568609
};
569610

570611
let dealings: Vec<_> = self
571-
.bundles()
612+
.bundles
572613
.iter()
573614
.map(|b| {
574615
let node_idx = b.origin().0.into();

timeboost-types/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ pub use bundle::{
2222
pub use bytes::Bytes;
2323
pub use candidate_list::{CandidateList, CandidateListBytes};
2424
pub use decryption::{
25-
AccumulatorMode, DkgAccumulator, DkgSubset, KeyStore, KeyStoreVec, ResultIter, ThresholdKey,
26-
ThresholdKeyCell,
25+
AccumulatorMode, DkgAccumulator, DkgSubset, DkgSubsetRef, KeyStore, KeyStoreVec, ResultIter,
26+
ThresholdKey, ThresholdKeyCell,
2727
};
2828
pub use delayed_inbox::DelayedInboxIndex;
2929
pub use inclusion_list::InclusionList;

0 commit comments

Comments
 (0)