1use crate::{
7 crypto_helper::{
8 cardano::SerDeShelleyFileFormat,
9 types::{
10 ProtocolParameters, ProtocolPartyId, ProtocolSignerVerificationKey,
11 ProtocolSignerVerificationKeySignature, ProtocolStakeDistribution,
12 },
13 ProtocolOpCert,
14 },
15 StdError, StdResult,
16};
17
18use mithril_stm::key_reg::{ClosedKeyReg, KeyReg};
19use mithril_stm::stm::{Stake, StmInitializer, StmParameters, StmSigner, StmVerificationKeyPoP};
20use mithril_stm::RegisterError;
21
22use crate::crypto_helper::cardano::Sum6KesBytes;
23use anyhow::{anyhow, Context};
24use blake2::{
25 digest::{consts::U32, FixedOutput},
26 Blake2b, Digest,
27};
28use kes_summed_ed25519::kes::{Sum6Kes, Sum6KesSig};
29use kes_summed_ed25519::traits::{KesSig, KesSk};
30use rand_core::{CryptoRng, RngCore};
31use serde::{Deserialize, Serialize};
32use std::collections::HashMap;
33use std::path::Path;
34use thiserror::Error;
35
36type D = Blake2b<U32>;
38
39pub type KESPeriod = u32;
41
42#[derive(Error, Debug)]
44pub enum ProtocolRegistrationErrorWrapper {
45 #[error("missing party id")]
49 PartyIdMissing,
50
51 #[error("party id does not exist in the stake distribution")]
53 PartyIdNonExisting,
54
55 #[error("missing operational certificate")]
57 OpCertMissing,
58
59 #[error("invalid operational certificate")]
61 OpCertInvalid,
62
63 #[error("KES signature verification error: CurrentKesPeriod={0}, StartKesPeriod={1}")]
65 KesSignatureInvalid(u32, u64),
66
67 #[error("missing KES signature")]
69 KesSignatureMissing,
70
71 #[error("missing KES period")]
73 KesPeriodMissing,
74
75 #[error("pool address encoding error")]
77 PoolAddressEncoding,
78
79 #[error("core registration error")]
81 CoreRegister(#[source] RegisterError),
82}
83
84#[derive(Error, Debug)]
86pub enum ProtocolInitializerErrorWrapper {
87 #[error("protocol initializer error")]
89 ProtocolInitializer(#[source] StdError),
90
91 #[error("KES key cannot be updated for period {0}")]
93 KesUpdate(KESPeriod),
94
95 #[error("Period of key file, {0}, does not match with period provided by user, {1}")]
97 KesMismatch(KESPeriod, KESPeriod),
98}
99
100#[derive(Debug, Clone, Serialize, Deserialize)]
104pub struct StmInitializerWrapper {
105 stm_initializer: StmInitializer,
107
108 kes_signature: Option<Sum6KesSig>,
112}
113
114#[derive(Debug, Clone)]
121pub struct KeyRegWrapper {
122 stm_key_reg: KeyReg,
123 stake_distribution: HashMap<ProtocolPartyId, Stake>,
124}
125
126impl StmInitializerWrapper {
127 pub fn setup<R: RngCore + CryptoRng, P: AsRef<Path>>(
131 params: StmParameters,
132 kes_sk_path: Option<P>,
133 kes_period: Option<KESPeriod>,
134 stake: Stake,
135 rng: &mut R,
136 ) -> StdResult<Self> {
137 let stm_initializer = StmInitializer::setup(params, stake, rng);
138 let kes_signature = if let Some(kes_sk_path) = kes_sk_path {
139 let mut kes_sk_bytes = Sum6KesBytes::from_file(kes_sk_path)
140 .map_err(|e| anyhow!(e))
141 .with_context(|| "StmInitializerWrapper can not read KES secret key from file")?;
142 let mut kes_sk = Sum6Kes::try_from(&mut kes_sk_bytes)
143 .map_err(|e| ProtocolInitializerErrorWrapper::ProtocolInitializer(anyhow!(e)))
144 .with_context(|| "StmInitializerWrapper can not use KES secret key")?;
145 let kes_sk_period = kes_sk.get_period();
146 let provided_period = kes_period.unwrap_or_default();
147 if kes_sk_period > provided_period {
148 return Err(anyhow!(ProtocolInitializerErrorWrapper::KesMismatch(
149 kes_sk_period,
150 provided_period,
151 )));
152 }
153
154 for period in kes_sk_period..provided_period {
156 kes_sk
157 .update()
158 .map_err(|_| ProtocolInitializerErrorWrapper::KesUpdate(period))?;
159 }
160
161 Some(kes_sk.sign(&stm_initializer.verification_key().to_bytes()))
162 } else {
163 println!("WARNING: Non certified signer registration by providing only a Pool Id is decommissioned and must be used for tests only!");
164 None
165 };
166
167 Ok(Self {
168 stm_initializer,
169 kes_signature,
170 })
171 }
172
173 pub fn verification_key(&self) -> StmVerificationKeyPoP {
175 self.stm_initializer.verification_key()
176 }
177
178 pub fn verification_key_signature(&self) -> Option<ProtocolSignerVerificationKeySignature> {
180 self.kes_signature.map(|k| k.into())
181 }
182
183 pub fn get_protocol_parameters(&self) -> ProtocolParameters {
185 self.stm_initializer.params
186 }
187
188 pub fn get_stake(&self) -> Stake {
190 self.stm_initializer.stake
191 }
192
193 pub fn new_signer(
206 self,
207 closed_reg: ClosedKeyReg<D>,
208 ) -> Result<StmSigner<D>, ProtocolRegistrationErrorWrapper> {
209 self.stm_initializer
210 .new_signer(closed_reg)
211 .map_err(ProtocolRegistrationErrorWrapper::CoreRegister)
212 }
213
214 pub fn to_bytes(&self) -> Vec<u8> {
219 let mut out = Vec::new();
220 out.extend_from_slice(&self.stm_initializer.to_bytes());
221 if let Some(kes_signature) = &self.kes_signature {
222 out.extend_from_slice(&kes_signature.to_bytes());
223 }
224
225 out
226 }
227
228 pub fn from_bytes(bytes: &[u8]) -> Result<Self, RegisterError> {
232 let stm_initializer = StmInitializer::from_bytes(&bytes[..256])?;
233 let kes_signature = if bytes[256..].is_empty() {
234 None
235 } else {
236 Some(
237 Sum6KesSig::from_bytes(&bytes[256..])
238 .map_err(|_| RegisterError::SerializationError)?,
239 )
240 };
241
242 Ok(Self {
243 stm_initializer,
244 kes_signature,
245 })
246 }
247
248 cfg_test_tools! {
249 pub fn override_protocol_parameters(&mut self, protocol_parameters: &ProtocolParameters) {
251 self.stm_initializer.params = protocol_parameters.to_owned();
252 }
253 }
254}
255
256impl KeyRegWrapper {
257 pub fn init(stake_dist: &ProtocolStakeDistribution) -> Self {
260 Self {
261 stm_key_reg: KeyReg::init(),
262 stake_distribution: HashMap::from_iter(stake_dist.to_vec()),
263 }
264 }
265
266 pub fn register(
270 &mut self,
271 party_id: Option<ProtocolPartyId>, opcert: Option<ProtocolOpCert>, kes_sig: Option<ProtocolSignerVerificationKeySignature>, kes_period: Option<KESPeriod>,
275 pk: ProtocolSignerVerificationKey,
276 ) -> Result<ProtocolPartyId, ProtocolRegistrationErrorWrapper> {
277 let pool_id_bech32: ProtocolPartyId = if let Some(opcert) = opcert {
278 opcert
279 .validate()
280 .map_err(|_| ProtocolRegistrationErrorWrapper::OpCertInvalid)?;
281 let mut pool_id = None;
282 let sig = kes_sig.ok_or(ProtocolRegistrationErrorWrapper::KesSignatureMissing)?;
283 let kes_period =
284 kes_period.ok_or(ProtocolRegistrationErrorWrapper::KesPeriodMissing)?;
285 let kes_period_try_min = std::cmp::max(0, kes_period.saturating_sub(1));
286 let kes_period_try_max = std::cmp::min(64, kes_period.saturating_add(1));
287 for kes_period_try in kes_period_try_min..kes_period_try_max {
288 if sig
289 .verify(kes_period_try, &opcert.kes_vk, &pk.to_bytes())
290 .is_ok()
291 {
292 pool_id = Some(
293 opcert
294 .compute_protocol_party_id()
295 .map_err(|_| ProtocolRegistrationErrorWrapper::PoolAddressEncoding)?,
296 );
297 break;
298 }
299 }
300 pool_id.ok_or(ProtocolRegistrationErrorWrapper::KesSignatureInvalid(
301 kes_period,
302 opcert.start_kes_period,
303 ))?
304 } else {
305 if cfg!(not(feature = "allow_skip_signer_certification")) {
306 Err(ProtocolRegistrationErrorWrapper::OpCertMissing)?
307 }
308 party_id.ok_or(ProtocolRegistrationErrorWrapper::PartyIdMissing)?
309 };
310
311 if let Some(&stake) = self.stake_distribution.get(&pool_id_bech32) {
312 self.stm_key_reg
313 .register(stake, pk.into())
314 .map_err(ProtocolRegistrationErrorWrapper::CoreRegister)?;
315 return Ok(pool_id_bech32);
316 }
317 Err(ProtocolRegistrationErrorWrapper::PartyIdNonExisting)
318 }
319
320 pub fn close<D: Digest + FixedOutput>(self) -> ClosedKeyReg<D> {
323 self.stm_key_reg.close()
324 }
325}
326
327#[cfg(test)]
328mod test {
329 use super::*;
330 use crate::crypto_helper::{cardano::ColdKeyGenerator, OpCert};
331
332 use crate::test_utils::TempDir;
333 use rand_chacha::ChaCha20Rng;
334 use rand_core::SeedableRng;
335 use std::path::PathBuf;
336
337 fn setup_temp_directory(test_name: &str) -> PathBuf {
338 TempDir::create("mithril_cardano_key_certification", test_name)
339 }
340
341 fn create_cryptographic_material(party_idx: u64) -> (ProtocolPartyId, PathBuf, PathBuf) {
342 let temp_dir = setup_temp_directory(&format!("create_cryptographic_material_{party_idx}"));
343 let keypair = ColdKeyGenerator::create_deterministic_keypair([party_idx as u8; 32]);
344 let mut dummy_buffer = [0u8; Sum6Kes::SIZE + 4];
345 let mut dummy_seed = [party_idx as u8; 32];
346 let (kes_secret_key, kes_verification_key) =
347 Sum6Kes::keygen(&mut dummy_buffer, &mut dummy_seed);
348 let mut kes_bytes = Sum6KesBytes([0u8; Sum6Kes::SIZE + 4]);
349 kes_bytes.0.copy_from_slice(&kes_secret_key.clone_sk());
350 let operational_certificate = OpCert::new(kes_verification_key, 0, 0, keypair);
351 let kes_secret_key_file = temp_dir.join(format!("kes{party_idx}.skey"));
352 kes_bytes
353 .to_file(&kes_secret_key_file)
354 .expect("KES secret key file export should not fail");
355 let operational_certificate_file = temp_dir.join(format!("pool{party_idx}.cert"));
356 operational_certificate
357 .to_file(&operational_certificate_file)
358 .expect("operational certificate file export should not fail");
359 let party_id = operational_certificate
360 .compute_protocol_party_id()
361 .expect("compute protocol party id should not fail");
362 (party_id, operational_certificate_file, kes_secret_key_file)
363 }
364
365 #[test]
366 fn test_vector_key_reg() {
367 let params = StmParameters {
368 m: 5,
369 k: 5,
370 phi_f: 1.0,
371 };
372 let mut rng = ChaCha20Rng::from_seed([0u8; 32]);
373
374 let (party_id_1, operational_certificate_file_1, kes_secret_key_file_1) =
375 create_cryptographic_material(1);
376 let (party_id_2, operational_certificate_file_2, kes_secret_key_file_2) =
377 create_cryptographic_material(2);
378
379 let mut key_reg = KeyRegWrapper::init(&vec![(party_id_1, 10), (party_id_2, 3)]);
380
381 let initializer_1 = StmInitializerWrapper::setup(
382 params,
383 Some(kes_secret_key_file_1),
384 Some(0),
385 10,
386 &mut rng,
387 )
388 .unwrap();
389
390 let opcert1 = OpCert::from_file(operational_certificate_file_1)
391 .expect("opcert deserialization should not fail")
392 .into();
393
394 let key_registration_1 = key_reg.register(
395 None,
396 Some(opcert1),
397 initializer_1.verification_key_signature(),
398 Some(0),
399 initializer_1.stm_initializer.verification_key().into(),
400 );
401 assert!(key_registration_1.is_ok());
402
403 let initializer_2 = StmInitializerWrapper::setup(
404 params,
405 Some(kes_secret_key_file_2),
406 Some(0),
407 10,
408 &mut rng,
409 )
410 .unwrap();
411
412 let opcert2 = OpCert::from_file(operational_certificate_file_2)
413 .expect("opcert deserialization should not fail")
414 .into();
415
416 let key_registration_2 = key_reg.register(
417 None,
418 Some(opcert2),
419 initializer_2.verification_key_signature(),
420 Some(0),
421 initializer_2.stm_initializer.verification_key().into(),
422 );
423 assert!(key_registration_2.is_ok())
424 }
425
426 const GOLDEN_STM_INITIALIZER_WRAPPER_JSON: &str = r#"
427 {
428 "stm_initializer": {
429 "stake": 9497432569,
430 "params": {
431 "m": 20973,
432 "k": 2422,
433 "phi_f": 0.2
434 },
435 "sk": [49, 181, 118, 110, 190, 161, 107, 218, 165, 20, 147, 129, 193, 79, 160, 0, 37, 23, 102, 223, 88, 174, 208, 70, 97, 79, 174, 51, 28, 0, 192, 210],
436 "pk": {
437 "vk": [173, 149, 133, 21, 100, 254, 36, 74, 165, 174, 56, 9, 145, 190, 48, 14, 12, 193, 243, 3, 200, 148, 221, 124, 170, 143, 89, 5, 168, 0, 226, 125, 61, 181, 190, 80, 62, 199, 99, 161, 117, 49, 65, 34, 81, 96, 34, 81, 2, 235, 173, 57, 58, 128, 49, 22, 242, 42, 30, 137, 6, 51, 77, 57, 142, 192, 140, 161, 206, 206, 213, 114, 156, 191, 127, 167, 167, 9, 39, 29, 97, 166, 134, 76, 55, 179, 72, 29, 41, 251, 14, 71, 89, 181, 31, 115],
438 "pop": [171, 0, 214, 91, 37, 208, 228, 71, 228, 31, 138, 0, 237, 175, 24, 45, 160, 117, 14, 210, 23, 46, 235, 83, 45, 9, 58, 207, 18, 36, 31, 160, 252, 111, 69, 102, 248, 205, 46, 71, 24, 38, 41, 77, 29, 129, 95, 16, 136, 114, 250, 44, 230, 184, 222, 122, 120, 58, 249, 103, 48, 121, 141, 244, 243, 26, 252, 60, 230, 64, 75, 3, 86, 107, 198, 198, 117, 242, 107, 104, 219, 209, 211, 255, 174, 203, 43, 141, 34, 146, 25, 181, 212, 38, 194, 99]
439 }
440 },
441 "kes_signature": {
442 "sigma": {
443 "sigma": {
444 "sigma": {
445 "sigma": {
446 "sigma": {
447 "sigma": [71, 225, 146, 98, 81, 62, 28, 21, 7, 157, 88, 4, 226, 126, 27, 133, 146, 171, 216, 170, 77, 17, 38, 146, 98, 202, 35, 87, 166, 162, 25, 207, 105, 174, 48, 225, 152, 68, 19, 109, 72, 241, 69, 111, 22, 214, 72, 20, 81, 56, 181, 104, 69, 121, 173, 194, 37, 60, 16, 155, 86, 99, 253, 7],
448 "lhs_pk": [
449 91, 82, 235, 39, 167, 29, 141, 253, 163, 163, 55, 185, 162, 191, 52, 8, 245, 7, 104, 22, 182, 239, 133, 138, 131, 15, 233, 116, 147, 251, 182, 140],
450 "rhs_pk": [189, 26, 9, 118, 59, 34, 225, 34, 104, 202, 192, 7, 66, 150, 137, 75, 106, 7, 22, 234, 42, 94, 139, 65, 241, 65, 1, 190, 153, 16, 221, 87]
451 },
452 "lhs_pk": [206, 50, 185, 93, 20, 234, 100, 168, 163, 125, 95, 201, 162, 104, 35, 2, 205, 41, 180, 73, 107, 140, 79, 182, 173, 17, 172, 49, 51, 85, 180, 5],
453 "rhs_pk": [68, 40, 90, 110, 254, 68, 87, 12, 19, 21, 252, 197, 69, 255, 33, 172, 140, 70, 79, 39, 71, 217, 12, 254, 82, 125, 123, 148, 221, 217, 141, 194]
454 },
455 "lhs_pk": [155, 2, 30, 71, 52, 89, 112, 247, 108, 177, 144, 212, 206, 254, 87, 126, 180, 207, 146, 223, 164, 246, 178, 62, 148, 96, 39, 136, 106, 36, 253, 56],
456 "rhs_pk": [155, 140, 124, 154, 235, 97, 51, 77, 208, 24, 45, 219, 199, 232, 222, 26, 160, 62, 38, 253, 121, 241, 219, 233, 36, 50, 60, 182, 127, 255, 132, 245]
457 },
458 "lhs_pk": [172, 176, 18, 228, 203, 85, 44, 151, 221, 13, 91, 250, 67, 232, 114, 16, 251, 13, 115, 233, 214, 194, 102, 199, 200, 124, 30, 190, 143, 18, 85, 75],
459 "rhs_pk": [100, 192, 98, 123, 150, 116, 55, 42, 207, 44, 181, 31, 203, 65, 237, 13, 55, 246, 185, 211, 149, 245, 245, 219, 183, 41, 237, 253, 128, 231, 161, 226]
460 },
461 "lhs_pk": [112, 16, 177, 142, 158, 1, 36, 210, 87, 165, 5, 195, 199, 61, 13, 195, 219, 26, 231, 103, 163, 223, 54, 16, 106, 0, 252, 69, 242, 31, 210, 167],
462 "rhs_pk": [15, 246, 81, 72, 172, 15, 170, 235, 10, 64, 229, 233, 169, 140, 179, 209, 244, 183, 3, 59, 2, 252, 233, 229, 13, 190, 196, 208, 109, 30, 73, 113]
463 },
464 "lhs_pk": [114, 238, 75, 184, 228, 147, 37, 72, 134, 65, 139, 64, 81, 114, 157, 148, 197, 108, 80, 89, 30, 235, 75, 108, 193, 53, 185, 15, 57, 61, 181, 119],
465 "rhs_pk": [82, 28, 113, 114, 168, 192, 222, 110, 96, 15, 28, 179, 164, 180, 76, 87, 254, 72, 48, 154, 167, 102, 220, 74, 76, 136, 45, 105, 243, 87, 165, 212]
466 }
467 }
468 "#;
469
470 #[test]
471 fn golden_initializer_deserialization() {
472 let _: StmInitializerWrapper = serde_json::from_str(GOLDEN_STM_INITIALIZER_WRAPPER_JSON)
473 .expect("Deserializing a StmInitializerWrapper should not fail");
474 }
475
476 #[test]
477 fn test_initializer_wrapper_conversions() {
478 let stm_initializer_wrapper_json = GOLDEN_STM_INITIALIZER_WRAPPER_JSON;
479
480 let stm_initializer_wrapper_from_json: StmInitializerWrapper =
481 serde_json::from_str(stm_initializer_wrapper_json)
482 .expect("Deserializing a StmInitializerWrapper should not fail");
483 let stm_initializer_wrapper_from_json_to_json =
484 serde_json::to_string(&stm_initializer_wrapper_from_json)
485 .expect("Serializing a StmInitializerWrapper to json should not fail");
486
487 let stm_initializer_wrapper_from_bytes =
488 StmInitializerWrapper::from_bytes(&stm_initializer_wrapper_from_json.to_bytes())
489 .expect("Deserializing a StmInitializerWrapper from bytes should not fail");
490 let stm_initializer_wrapper_from_bytes_to_json =
491 serde_json::to_string(&stm_initializer_wrapper_from_bytes)
492 .expect("Serializing a StmInitializerWrapper to json should not fail");
493
494 assert_eq!(
495 stm_initializer_wrapper_from_json_to_json,
496 stm_initializer_wrapper_from_bytes_to_json
497 );
498
499 let mut stm_initializer_wrapper_from_json = stm_initializer_wrapper_from_json;
500 stm_initializer_wrapper_from_json.kes_signature = None;
501
502 let stm_initializer_wrapper_from_bytes =
503 StmInitializerWrapper::from_bytes(&stm_initializer_wrapper_from_json.to_bytes())
504 .expect("Deserializing a StmInitializerWrapper from bytes should not fail");
505 assert_eq!(None, stm_initializer_wrapper_from_bytes.kes_signature);
506 }
507}