@@ -8,7 +8,7 @@ use cliquenet::{
8
8
use rayon:: iter:: ParallelIterator ;
9
9
use rayon:: prelude:: * ;
10
10
11
- use multisig:: { CommitteeId , PublicKey } ;
11
+ use multisig:: { Committee , CommitteeId , PublicKey } ;
12
12
use parking_lot:: RwLock ;
13
13
use sailfish:: types:: { Evidence , Round , RoundNumber } ;
14
14
use serde:: { Deserialize , Serialize } ;
@@ -38,7 +38,6 @@ const THRES_AAD: &[u8] = b"threshold";
38
38
type Result < T > = StdResult < T , DecrypterError > ;
39
39
type DecShare = <DecryptionScheme as ThresholdEncScheme >:: DecShare ;
40
40
type Ciphertext = <DecryptionScheme as ThresholdEncScheme >:: Ciphertext ;
41
- type DecShareCache = BTreeMap < RoundNumber , Vec < Vec < Option < DecShare > > > > ;
42
41
43
42
/// The message types exchanged during decryption phase.
44
43
#[ derive( Debug , Serialize , Deserialize ) ]
@@ -497,9 +496,9 @@ struct Worker {
497
496
#[ builder( default ) ]
498
497
tracker : BTreeMap < CommitteeId , DkgAccumulator > ,
499
498
500
- /// Cache of decryption shares received from remote nodes or produced from local ciphertexts.
499
+ /// Decryption shares received from remote nodes or produced from local ciphertexts.
501
500
#[ builder( default ) ]
502
- dec_shares : DecShareCache ,
501
+ dec_shares : ShareStore ,
503
502
504
503
/// Map of received decryption shares for each round (DOS prevention).
505
504
#[ builder( default ) ]
@@ -882,7 +881,7 @@ impl Worker {
882
881
// doesn't need those shares, thus pruning them.
883
882
if self . first_requested_round . is_none ( ) {
884
883
trace ! ( node = %self . label, %round, "set first requested round" ) ;
885
- self . dec_shares . retain ( |k , _| k >= & round) ;
884
+ self . dec_shares . gc ( & round) ;
886
885
self . first_requested_round = Some ( round) ;
887
886
}
888
887
@@ -901,7 +900,7 @@ impl Worker {
901
900
902
901
/// Garbage collect internally cached state.
903
902
async fn gc ( & mut self , round : & RoundNumber ) -> Result < ( ) > {
904
- self . dec_shares . retain ( |r , _| r > round) ;
903
+ self . dec_shares . gc ( round) ;
905
904
self . incls . retain ( |r, _| r > round) ;
906
905
self . acks . retain ( |r, _| r > round) ;
907
906
self . remove_old_committee ( ) . await ?;
@@ -978,15 +977,7 @@ impl Worker {
978
977
// there are 3 ciphertexts, and node a and b has contributed their decrypted shares batch so
979
978
// far. with node c's batch [s1c, s2c, s3c], the new local cache is:
980
979
// [[s1a, s1b, s1c], [s2a, s2b, s2c], [s3a, s3b, s3c]]
981
- let entry = self
982
- . dec_shares
983
- . entry ( round. num ( ) )
984
- . or_insert_with ( || vec ! [ vec![ ] ; batch. len( ) ] ) ;
985
- entry
986
- . iter_mut ( )
987
- . zip ( batch. dec_shares )
988
- . for_each ( |( shares, new) | shares. push ( new) ) ;
989
-
980
+ self . dec_shares . insert ( round. num ( ) , batch. dec_shares ) ;
990
981
Ok ( ( ) )
991
982
}
992
983
@@ -1085,18 +1076,10 @@ impl Worker {
1085
1076
dec_key : & DecryptionKey ,
1086
1077
) -> Result < Option < Vec < Option < Plaintext > > > > {
1087
1078
let ciphertexts = incl. filter_ciphertexts ( ) . map ( |b| deserialize ( b) . ok ( ) ) ;
1088
- let Some ( dec_shares) = self . dec_shares . get ( & round) else {
1089
- return Ok ( None ) ;
1090
- } ;
1091
1079
let key_store = self . current_store ( ) ?;
1092
-
1093
- if dec_shares. is_empty ( )
1094
- || dec_shares. iter ( ) . any ( |opt_dec_shares| {
1095
- let valid = opt_dec_shares. iter ( ) . filter ( |s| s. is_some ( ) ) . count ( ) ;
1096
- let invalid = opt_dec_shares. len ( ) - valid;
1097
- valid < key_store. committee ( ) . one_honest_threshold ( ) . get ( )
1098
- && invalid < key_store. committee ( ) . quorum_size ( ) . get ( )
1099
- } )
1080
+ if !self
1081
+ . dec_shares
1082
+ . has_sufficient_shares ( & round, key_store. committee ( ) )
1100
1083
{
1101
1084
return Ok ( None ) ;
1102
1085
}
@@ -1368,6 +1351,61 @@ impl Worker {
1368
1351
}
1369
1352
}
1370
1353
1354
+ #[ derive( Debug , Default ) ]
1355
+ struct ShareStore {
1356
+ inner : BTreeMap < RoundNumber , Vec < Vec < Option < DecShare > > > > ,
1357
+ }
1358
+
1359
+ impl ShareStore {
1360
+ /// Inserts decryption shares for a specific round
1361
+ fn insert ( & mut self , round : RoundNumber , shares : Vec < Option < DecShare > > ) {
1362
+ let entry = self
1363
+ . inner
1364
+ . entry ( round)
1365
+ . or_insert_with ( || vec ! [ vec![ ] ; shares. len( ) ] ) ;
1366
+ entry
1367
+ . iter_mut ( )
1368
+ . zip ( shares)
1369
+ . for_each ( |( shares, new) | shares. push ( new) ) ;
1370
+ }
1371
+
1372
+ /// Gets a reference to the decryption shares for a specific round, if any
1373
+ fn get ( & self , round : & RoundNumber ) -> Option < & Vec < Vec < Option < DecShare > > > > {
1374
+ self . inner . get ( round)
1375
+ }
1376
+
1377
+ /// Gets a mutable reference to the decryption shares for a specific round, if any
1378
+ fn get_mut ( & mut self , round : & RoundNumber ) -> Option < & mut Vec < Vec < Option < DecShare > > > > {
1379
+ self . inner . get_mut ( round)
1380
+ }
1381
+ /// Returns true if the cache is empty.
1382
+ fn is_empty ( & self ) -> bool {
1383
+ self . inner . is_empty ( )
1384
+ }
1385
+
1386
+ /// Checks if there are enough valid decryption shares for the given round.
1387
+ fn has_sufficient_shares ( & self , round : & RoundNumber , committee : & Committee ) -> bool {
1388
+ let Some ( dec_shares) = self . get ( round) else {
1389
+ return false ;
1390
+ } ;
1391
+
1392
+ // Check if there are enough valid shares to proceed
1393
+ let one_honest_threshold = committee. one_honest_threshold ( ) . get ( ) ;
1394
+ let quorum_size = committee. quorum_size ( ) . get ( ) ;
1395
+
1396
+ !dec_shares. iter ( ) . any ( |opt_dec_shares| {
1397
+ let valid = opt_dec_shares. iter ( ) . filter ( |s| s. is_some ( ) ) . count ( ) ;
1398
+ let invalid = opt_dec_shares. len ( ) - valid;
1399
+ valid < one_honest_threshold && invalid < quorum_size
1400
+ } )
1401
+ }
1402
+
1403
+ /// Removes and returns the decryption shares for a specific round
1404
+ fn gc ( & mut self , round : & RoundNumber ) {
1405
+ self . inner . retain ( |k, _| k >= round)
1406
+ }
1407
+ }
1408
+
1371
1409
/// A batch of decryption shares. Each batch is uniquely identified via round_number.
1372
1410
#[ derive( Clone , Debug , Serialize , Deserialize , PartialEq , Eq , Hash ) ]
1373
1411
struct DecShareBatch {
@@ -1382,12 +1420,6 @@ struct DecShareBatch {
1382
1420
}
1383
1421
1384
1422
impl DecShareBatch {
1385
- /// Returns the number of decryption share in this batch. Equivalently, it's the number of
1386
- /// ciphertexts.
1387
- pub fn len ( & self ) -> usize {
1388
- self . dec_shares . len ( )
1389
- }
1390
-
1391
1423
/// Returns true if there's no *valid* decryption share. There are three sub-cases this may be
1392
1424
/// true
1393
1425
/// - empty set of ciphertext/encrypted bundle
0 commit comments