11// Copyright 2019-2024 ChainSafe Systems
22// SPDX-License-Identifier: Apache-2.0, MIT
33
4+ use std:: sync:: Arc ;
45use bls_signatures:: { PublicKey , Serialize , Signature , verify_messages} ;
56use filecoin_f3_gpbft:: PubKey ;
67use filecoin_f3_gpbft:: api:: Verifier ;
@@ -43,11 +44,14 @@ pub enum BLSError {
4344///
4445/// This verifier implements the same scheme used by `go-f3/blssig`, with:
4546/// - BLS12_381 curve
46- /// - G1 for public keys, G2 for signatures
47+ /// - G1 for public keys, G2 for signatures
4748/// - BDN aggregation for rogue-key attack prevention
4849pub struct BLSVerifier {
4950 /// Cache for deserialized public key points to avoid expensive repeated operations
5051 point_cache : RwLock < LruCache < Vec < u8 > , PublicKey > > ,
52+ /// Cache for current power table's BDN aggregation
53+ /// Only caches the current since power tables don't tend to repeat after rotation
54+ bdn_cache : RwLock < Option < ( Vec < PubKey > , Arc < BDNAggregation > ) > > ,
5155}
5256
5357impl Default for BLSVerifier {
@@ -70,6 +74,7 @@ impl BLSVerifier {
7074 Self {
7175 // key size: 48, value size: 196, total estimated: 1.83 MiB
7276 point_cache : RwLock :: new ( LruCache :: new ( MAX_POINT_CACHE_SIZE ) ) ,
77+ bdn_cache : RwLock :: new ( None ) ,
7378 }
7479 }
7580
@@ -120,6 +125,34 @@ impl BLSVerifier {
120125 fn deserialize_signature ( & self , sig : & [ u8 ] ) -> Result < Signature , BLSError > {
121126 Signature :: from_bytes ( sig) . map_err ( BLSError :: SignatureDeserialization )
122127 }
128+
129+ /// Gets a cached BDN aggregation or creates and caches it
130+ fn get_or_cache_bdn ( & self , power_table : & [ PubKey ] ) -> Result < Arc < BDNAggregation > , BLSError > {
131+ // Check cache first
132+ if let Some ( ( cached_power_table, cached_bdn) ) = self . bdn_cache . read ( ) . as_ref ( ) {
133+ if cached_power_table == power_table {
134+ return Ok ( cached_bdn. clone ( ) ) ;
135+ }
136+ }
137+
138+ // Deserialize and create new BDN aggregation
139+ let mut typed_pub_keys = vec ! [ ] ;
140+ for pub_key in power_table {
141+ if pub_key. 0 . len ( ) != BLS_PUBLIC_KEY_LENGTH {
142+ return Err ( BLSError :: InvalidPublicKeyLength ( pub_key. 0 . len ( ) ) ) ;
143+ }
144+ typed_pub_keys. push ( self . get_or_cache_public_key ( & pub_key. 0 ) ?) ;
145+ }
146+
147+ let bdn = Arc :: new ( BDNAggregation :: new ( typed_pub_keys) ?) ;
148+
149+ // Cache it
150+ self . bdn_cache
151+ . write ( )
152+ . replace ( ( power_table. to_vec ( ) , bdn. clone ( ) ) ) ;
153+
154+ Ok ( bdn)
155+ }
123156}
124157
125158impl Verifier for BLSVerifier {
@@ -178,16 +211,7 @@ impl Verifier for BLSVerifier {
178211 return Err ( BLSError :: EmptySigners ) ;
179212 }
180213
181- let mut typed_pub_keys = vec ! [ ] ;
182- for pub_key in power_table {
183- if pub_key. 0 . len ( ) != BLS_PUBLIC_KEY_LENGTH {
184- return Err ( BLSError :: InvalidPublicKeyLength ( pub_key. 0 . len ( ) ) ) ;
185- }
186-
187- typed_pub_keys. push ( self . get_or_cache_public_key ( & pub_key. 0 ) ?) ;
188- }
189-
190- let bdn = BDNAggregation :: new ( typed_pub_keys) ?;
214+ let bdn = self . get_or_cache_bdn ( power_table) ?;
191215 let agg_pub_key = bdn. aggregate_pub_keys ( signer_indices) ?;
192216 let agg_pub_key_bytes = PubKey ( agg_pub_key. as_bytes ( ) . to_vec ( ) ) ;
193217 self . verify_single ( & agg_pub_key_bytes, payload, agg_sig)
0 commit comments