1- use kes_summed_ed25519:: { kes:: Sum6Kes , traits:: KesSk } ;
1+ use kes_summed_ed25519:: { kes:: Sum6Kes , traits:: KesSk , PublicKey as KesPublicKey } ;
22use rand_chacha:: ChaCha20Rng ;
33use rand_core:: { RngCore , SeedableRng } ;
44
@@ -11,6 +11,8 @@ use crate::{
1111 test_utils:: { fake_data, mithril_fixture:: MithrilFixture } ,
1212} ;
1313
14+ use super :: precomputed_kes_key;
15+
1416/// A builder of mithril types.
1517pub struct MithrilFixtureBuilder {
1618 protocol_parameters : ProtocolParameters ,
@@ -130,13 +132,9 @@ impl MithrilFixtureBuilder {
130132 match self . stake_distribution_generation_method {
131133 StakeDistributionGenerationMethod :: Custom ( _) => vec ! [ ] ,
132134 _ => {
133- let mut kes_keys_seed = [ 0u8 ; 32 ] ;
134135 let signers_party_ids = ( 0 ..self . number_of_signers ) . map ( |party_index| {
135136 if self . enable_signers_certification {
136- self . build_party_with_operational_certificate (
137- party_index,
138- & mut kes_keys_seed,
139- )
137+ self . build_party_with_operational_certificate ( party_index)
140138 } else {
141139 party_index. to_string ( )
142140 }
@@ -146,25 +144,61 @@ impl MithrilFixtureBuilder {
146144 }
147145 }
148146
149- fn build_party_with_operational_certificate (
150- & self ,
151- party_index : usize ,
152- kes_key_seed : & mut [ u8 ] ,
153- ) -> PartyId {
154- let mut cold_key_seed: Vec < u8 > = ( party_index)
147+ fn provide_kes_key ( kes_key_seed : & mut [ u8 ] ) -> ( Sum6KesBytes , KesPublicKey ) {
148+ if let Some ( ( kes_bytes, kes_verification_key) ) =
149+ MithrilFixtureBuilder :: cached_kes_key ( kes_key_seed)
150+ {
151+ ( kes_bytes, kes_verification_key)
152+ } else {
153+ println ! (
154+ "KES key not found in test cache, generating a new one for the seed {:?}." ,
155+ kes_key_seed
156+ ) ;
157+ MithrilFixtureBuilder :: generate_kes_key ( kes_key_seed)
158+ }
159+ }
160+
161+ fn cached_kes_key ( kes_key_seed : & [ u8 ] ) -> Option < ( Sum6KesBytes , KesPublicKey ) > {
162+ precomputed_kes_key:: cached_kes_key ( kes_key_seed) . map (
163+ |( kes_bytes, kes_verification_key) | {
164+ let kes_verification_key = KesPublicKey :: from_bytes ( & kes_verification_key) . unwrap ( ) ;
165+ let kes_bytes = Sum6KesBytes ( kes_bytes) ;
166+
167+ ( kes_bytes, kes_verification_key)
168+ } ,
169+ )
170+ }
171+
172+ fn generate_kes_key ( kes_key_seed : & mut [ u8 ] ) -> ( Sum6KesBytes , KesPublicKey ) {
173+ let mut key_buffer = [ 0u8 ; Sum6Kes :: SIZE + 4 ] ;
174+
175+ let ( kes_secret_key, kes_verification_key) = Sum6Kes :: keygen ( & mut key_buffer, kes_key_seed) ;
176+ let mut kes_bytes = Sum6KesBytes ( [ 0u8 ; Sum6Kes :: SIZE + 4 ] ) ;
177+ kes_bytes. 0 . copy_from_slice ( & kes_secret_key. clone_sk ( ) ) ;
178+
179+ ( kes_bytes, kes_verification_key)
180+ }
181+
182+ fn generate_cold_key_seed ( & self , party_index : usize ) -> Vec < u8 > {
183+ let mut cold_key_seed: Vec < _ > = ( party_index)
155184 . to_le_bytes ( )
156185 . iter ( )
157186 . zip ( self . party_id_seed )
158187 . map ( |( v1, v2) | v1 + v2)
159188 . collect ( ) ;
160189 cold_key_seed. resize ( 32 , 0 ) ;
190+
191+ cold_key_seed
192+ }
193+
194+ fn build_party_with_operational_certificate ( & self , party_index : usize ) -> PartyId {
195+ let cold_key_seed = self . generate_cold_key_seed ( party_index) . to_vec ( ) ;
196+ let mut kes_key_seed = cold_key_seed. clone ( ) ;
197+
161198 let keypair =
162199 ColdKeyGenerator :: create_deterministic_keypair ( cold_key_seed. try_into ( ) . unwrap ( ) ) ;
163- let mut dummy_buffer = [ 0u8 ; Sum6Kes :: SIZE + 4 ] ;
164- let ( kes_secret_key, kes_verification_key) =
165- Sum6Kes :: keygen ( & mut dummy_buffer, kes_key_seed) ;
166- let mut kes_bytes = Sum6KesBytes ( [ 0u8 ; Sum6Kes :: SIZE + 4 ] ) ;
167- kes_bytes. 0 . copy_from_slice ( & kes_secret_key. clone_sk ( ) ) ;
200+ let ( kes_bytes, kes_verification_key) =
201+ MithrilFixtureBuilder :: provide_kes_key ( & mut kes_key_seed) ;
168202 let operational_certificate = OpCert :: new ( kes_verification_key, 0 , 0 , keypair) ;
169203 let party_id = operational_certificate
170204 . compute_protocol_party_id ( )
@@ -265,11 +299,11 @@ mod tests {
265299 #[ test]
266300 fn changing_party_id_seed_change_all_builded_party_ids ( ) {
267301 let first_signers = MithrilFixtureBuilder :: default ( )
268- . with_signers ( 20 )
302+ . with_signers ( 10 )
269303 . build ( )
270304 . signers_with_stake ( ) ;
271305 let different_party_id_seed_signers = MithrilFixtureBuilder :: default ( )
272- . with_signers ( 20 )
306+ . with_signers ( 10 )
273307 . with_party_id_seed ( [ 1u8 ; 32 ] )
274308 . build ( )
275309 . signers_with_stake ( ) ;
@@ -279,4 +313,65 @@ mod tests {
279313 assert ! ( !first_party_ids. contains( & party_id) ) ;
280314 }
281315 }
316+
317+ /// Verify that there is a cached kes key for a number of party id.
318+ /// If the cache is not up to date, the test will generate the code that can be copied/pasted into the [precomputed_kes_key] module.
319+ /// The number of party id that should be in cache is defined with `precomputed_number`
320+ #[ test]
321+ fn verify_kes_key_cache_content ( ) {
322+ // Generate code that should be in the `cached_kes_key` function of the `precomputed_kes_key.rs` file.
323+ // It can be copied and pasted to update the cache.
324+ fn generate_code ( party_ids : & Vec < ( & [ u8 ] , [ u8 ; 612 ] , KesPublicKey ) > ) -> String {
325+ party_ids
326+ . iter ( )
327+ . map ( |( key, i, p) | format ! ( "{:?} => ({:?}, {:?})," , key, i, p. as_bytes( ) ) )
328+ . collect :: < Vec < _ > > ( )
329+ . join ( "\n " )
330+ }
331+
332+ let precomputed_number = 10 ;
333+
334+ let fixture = MithrilFixtureBuilder :: default ( ) ;
335+ let cold_keys: Vec < _ > = ( 0 ..precomputed_number)
336+ . map ( |party_index| fixture. generate_cold_key_seed ( party_index) )
337+ . collect ( ) ;
338+
339+ let computed_keys_key: Vec < _ > = cold_keys
340+ . iter ( )
341+ . map ( |cold_key| {
342+ let mut kes_key_seed: Vec < u8 > = cold_key. clone ( ) ;
343+ let ( kes_bytes, kes_verification_key) =
344+ MithrilFixtureBuilder :: generate_kes_key ( & mut kes_key_seed) ;
345+
346+ ( cold_key. as_slice ( ) , kes_bytes. 0 , kes_verification_key)
347+ } )
348+ . collect ( ) ;
349+
350+ let cached_kes_key: Vec < _ > = cold_keys
351+ . iter ( )
352+ . filter_map ( |cold_key| {
353+ MithrilFixtureBuilder :: cached_kes_key ( cold_key) . map (
354+ |( kes_bytes, kes_verification_key) | {
355+ ( cold_key. as_slice ( ) , kes_bytes. 0 , kes_verification_key)
356+ } ,
357+ )
358+ } )
359+ . collect ( ) ;
360+
361+ let expected_code = generate_code ( & computed_keys_key) ;
362+ let actual_code = generate_code ( & cached_kes_key) ;
363+
364+ assert_eq ! (
365+ computed_keys_key, cached_kes_key,
366+ "Precomputed KES keys should be:\n {}\n but seems to be:\n {}" ,
367+ expected_code, actual_code
368+ ) ;
369+
370+ let kes_key_seed = fixture. generate_cold_key_seed ( precomputed_number) ;
371+ assert ! (
372+ MithrilFixtureBuilder :: cached_kes_key( kes_key_seed. as_slice( ) ) . is_none( ) ,
373+ "We checked precomputed KES keys up to {} but it seems to be more." ,
374+ precomputed_number
375+ ) ;
376+ }
282377}
0 commit comments