Skip to content

Commit 84530e0

Browse files
authored
Merge pull request #2161 from input-output-hk/sfa/2153/accelerate_signer_fixtures_creation_in_tests
Accelerate signer fixtures creation in tests
2 parents f1441bc + 38314fe commit 84530e0

File tree

9 files changed

+596
-33
lines changed

9 files changed

+596
-33
lines changed

Cargo.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

mithril-aggregator/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "mithril-aggregator"
3-
version = "0.5.121"
3+
version = "0.5.122"
44
description = "A Mithril Aggregator server"
55
authors = { workspace = true }
66
edition = { workspace = true }

mithril-aggregator/src/http_server/routes/status.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -237,8 +237,8 @@ mod tests {
237237

238238
#[tokio::test]
239239
async fn retrieves_correct_total_signers_from_epoch_service() {
240-
let total_signers = 12;
241-
let total_next_signers = 345;
240+
let total_signers = 5;
241+
let total_next_signers = 4;
242242
let epoch_service = FakeEpochServiceBuilder {
243243
current_signers_with_stake: fake_data::signers_with_stakes(total_signers),
244244
next_signers_with_stake: fake_data::signers_with_stakes(total_next_signers),

mithril-aggregator/src/services/epoch_service.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1057,7 +1057,7 @@ mod tests {
10571057
allowed_discriminants: SignedEntityConfig::dummy().allowed_discriminants,
10581058
cardano_era: "CardanoEra".to_string(),
10591059
mithril_era: SupportedEra::eras()[1],
1060-
total_spo: 40,
1060+
total_spo: 10,
10611061
total_stake: 20_000_000,
10621062
..EpochServiceBuilder::new(epoch, current_epoch_fixture.clone())
10631063
};
@@ -1095,7 +1095,7 @@ mod tests {
10951095
current_signers: current_epoch_fixture.signers().into_iter().collect(),
10961096
next_signers: next_epoch_fixture.signers().into_iter().collect(),
10971097
signed_entity_config: SignedEntityConfig::dummy(),
1098-
total_spo: 40,
1098+
total_spo: 10,
10991099
total_stake: 20_000_000,
11001100
}
11011101
);

mithril-common/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "mithril-common"
3-
version = "0.4.94"
3+
version = "0.4.95"
44
description = "Common types, interfaces, and utilities for Mithril nodes."
55
authors = { workspace = true }
66
edition = { workspace = true }

mithril-common/src/entities/mithril_stake_distribution.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -70,11 +70,11 @@ mod tests {
7070

7171
use super::*;
7272

73-
const EXPECTED_HASH: &str = "47675a6fad57040b194655b103bc0439ff9d6920a7ba86bd53756db7ce2952f5";
73+
const EXPECTED_HASH: &str = "c5c1ff02e37c751329e3db7625c77fa2a24e86b2a75422c54f1b9f9232374d6f";
7474

7575
#[test]
7676
fn test_compute_hash() {
77-
let fixtures = MithrilFixtureBuilder::default().with_signers(100).build();
77+
let fixtures = MithrilFixtureBuilder::default().with_signers(10).build();
7878
let stake_distribution = MithrilStakeDistribution::new(
7979
Epoch(1),
8080
fixtures.signers_with_stake(),
@@ -86,7 +86,7 @@ mod tests {
8686

8787
#[test]
8888
fn test_hash_fail_for_different_stake() {
89-
let fixtures = MithrilFixtureBuilder::default().with_signers(100).build();
89+
let fixtures = MithrilFixtureBuilder::default().with_signers(10).build();
9090
let mut signers = fixtures.signers_with_stake();
9191
signers[0].stake += 1;
9292
let stake_distribution =
@@ -97,7 +97,7 @@ mod tests {
9797

9898
#[test]
9999
fn test_hash_fail_for_different_epoch() {
100-
let fixtures = MithrilFixtureBuilder::default().with_signers(100).build();
100+
let fixtures = MithrilFixtureBuilder::default().with_signers(10).build();
101101
let stake_distribution = MithrilStakeDistribution::new(
102102
Epoch(2),
103103
fixtures.signers_with_stake(),
@@ -110,7 +110,7 @@ mod tests {
110110
#[test]
111111
fn test_independence_protocol_parameters() {
112112
let signers = MithrilFixtureBuilder::default()
113-
.with_signers(100)
113+
.with_signers(10)
114114
.build()
115115
.signers_with_stake();
116116
let protocol_parameters = ProtocolParameters {

mithril-common/src/test_utils/fixture_builder.rs

Lines changed: 114 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use kes_summed_ed25519::{kes::Sum6Kes, traits::KesSk};
1+
use kes_summed_ed25519::{kes::Sum6Kes, traits::KesSk, PublicKey as KesPublicKey};
22
use rand_chacha::ChaCha20Rng;
33
use 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.
1517
pub 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{}\nbut 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
}

mithril-common/src/test_utils/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ mod cardano_transactions_builder;
1717
mod certificate_chain_builder;
1818
mod fixture_builder;
1919
mod mithril_fixture;
20-
20+
mod precomputed_kes_key;
2121
mod temp_dir;
2222

2323
#[cfg(feature = "test_http_server")]

0 commit comments

Comments
 (0)