1use std::{collections::HashMap, sync::Arc};
7
8use blake2::{
9 Blake2b, Digest,
10 digest::{FixedOutput, consts::U32},
11};
12use kes_summed_ed25519::kes::Sum6KesSig;
13use rand_core::{CryptoRng, RngCore};
14use serde::{Deserialize, Serialize};
15use thiserror::Error;
16
17use mithril_stm::{
18 ClosedKeyRegistration, Initializer, KeyRegistration, Parameters, RegisterError, Signer, Stake,
19 VerificationKeyProofOfPossession,
20};
21
22use crate::{
23 StdError, StdResult,
24 crypto_helper::{
25 ProtocolOpCert,
26 cardano::{KesSigner, KesVerifier, KesVerifierStandard},
27 types::{
28 ProtocolParameters, ProtocolPartyId, ProtocolSignerVerificationKey,
29 ProtocolSignerVerificationKeySignature, ProtocolStakeDistribution,
30 },
31 },
32};
33
34type D = Blake2b<U32>;
36
37pub type KesPeriod = u32;
39
40#[derive(Error, Debug)]
42pub enum ProtocolRegistrationErrorWrapper {
43 #[error("missing party id")]
47 PartyIdMissing,
48
49 #[error("party id does not exist in the stake distribution")]
51 PartyIdNonExisting,
52
53 #[error("missing operational certificate")]
55 OpCertMissing,
56
57 #[error("invalid operational certificate")]
59 OpCertInvalid,
60
61 #[error("KES signature verification error: CurrentKesPeriod={0}, StartKesPeriod={1}")]
63 KesSignatureInvalid(u32, u64),
64
65 #[error("missing KES signature")]
67 KesSignatureMissing,
68
69 #[error("missing KES period")]
71 KesPeriodMissing,
72
73 #[error("pool address encoding error")]
75 PoolAddressEncoding,
76
77 #[error("core registration error")]
79 CoreRegister(#[source] RegisterError),
80}
81
82#[derive(Error, Debug)]
84pub enum ProtocolInitializerErrorWrapper {
85 #[error("protocol initializer error")]
87 ProtocolInitializer(#[source] StdError),
88
89 #[error("KES key cannot be updated for period {0}")]
91 KesUpdate(KesPeriod),
92
93 #[error("Period of key file, {0}, does not match with period provided by user, {1}")]
95 KesMismatch(KesPeriod, KesPeriod),
96}
97
98#[derive(Debug, Clone, Serialize, Deserialize)]
102pub struct StmInitializerWrapper {
103 stm_initializer: Initializer,
105
106 kes_signature: Option<Sum6KesSig>,
110}
111
112impl StmInitializerWrapper {
113 pub fn setup<R: RngCore + CryptoRng>(
117 params: Parameters,
118 kes_signer: Option<Arc<dyn KesSigner>>,
119 kes_period: Option<KesPeriod>,
120 stake: Stake,
121 rng: &mut R,
122 ) -> StdResult<Self> {
123 let stm_initializer = Initializer::setup(params, stake, rng);
124 let kes_signature = if let Some(kes_signer) = kes_signer {
125 let (signature, _op_cert) = kes_signer.sign(
126 &stm_initializer.verification_key().to_bytes(),
127 kes_period.unwrap_or_default(),
128 )?;
129
130 Some(signature)
131 } else {
132 println!(
133 "WARNING: Non certified signer registration by providing only a Pool Id is decommissioned and must be used for tests only!"
134 );
135 None
136 };
137
138 Ok(Self {
139 stm_initializer,
140 kes_signature,
141 })
142 }
143
144 pub fn verification_key(&self) -> VerificationKeyProofOfPossession {
146 self.stm_initializer.verification_key()
147 }
148
149 pub fn verification_key_signature(&self) -> Option<ProtocolSignerVerificationKeySignature> {
151 self.kes_signature.map(|k| k.into())
152 }
153
154 pub fn get_protocol_parameters(&self) -> ProtocolParameters {
156 self.stm_initializer.params
157 }
158
159 pub fn get_stake(&self) -> Stake {
161 self.stm_initializer.stake
162 }
163
164 pub fn new_signer(
177 self,
178 closed_reg: ClosedKeyRegistration<D>,
179 ) -> Result<Signer<D>, ProtocolRegistrationErrorWrapper> {
180 self.stm_initializer
181 .new_signer(closed_reg)
182 .map_err(ProtocolRegistrationErrorWrapper::CoreRegister)
183 }
184
185 pub fn to_bytes(&self) -> Vec<u8> {
190 let mut out = Vec::new();
191 out.extend_from_slice(&self.stm_initializer.to_bytes());
192 if let Some(kes_signature) = &self.kes_signature {
193 out.extend_from_slice(&kes_signature.to_bytes());
194 }
195
196 out
197 }
198
199 pub fn from_bytes(bytes: &[u8]) -> Result<Self, RegisterError> {
203 let stm_initializer =
204 Initializer::from_bytes(bytes.get(..256).ok_or(RegisterError::SerializationError)?)?;
205 let bytes = bytes.get(256..).ok_or(RegisterError::SerializationError)?;
206 let kes_signature = if bytes.is_empty() {
207 None
208 } else {
209 Some(Sum6KesSig::from_bytes(bytes).map_err(|_| RegisterError::SerializationError)?)
210 };
211
212 Ok(Self {
213 stm_initializer,
214 kes_signature,
215 })
216 }
217
218 cfg_test_tools! {
219 pub fn override_protocol_parameters(&mut self, protocol_parameters: &ProtocolParameters) {
221 self.stm_initializer.params = protocol_parameters.to_owned();
222 }
223 }
224}
225
226#[derive(Debug, Clone)]
233pub struct KeyRegWrapper {
234 kes_verifier: Arc<dyn KesVerifier>,
235 stm_key_reg: KeyRegistration,
236 stake_distribution: HashMap<ProtocolPartyId, Stake>,
237}
238
239impl KeyRegWrapper {
240 pub fn init(stake_dist: &ProtocolStakeDistribution) -> Self {
243 Self {
244 kes_verifier: Arc::new(KesVerifierStandard),
245 stm_key_reg: KeyRegistration::init(),
246 stake_distribution: HashMap::from_iter(stake_dist.to_vec()),
247 }
248 }
249
250 pub fn register(
254 &mut self,
255 party_id: Option<ProtocolPartyId>, opcert: Option<ProtocolOpCert>, kes_sig: Option<ProtocolSignerVerificationKeySignature>, kes_period: Option<KesPeriod>,
259 pk: ProtocolSignerVerificationKey,
260 ) -> Result<ProtocolPartyId, ProtocolRegistrationErrorWrapper> {
261 let pool_id_bech32: ProtocolPartyId = if let Some(opcert) = opcert {
262 let signature = kes_sig.ok_or(ProtocolRegistrationErrorWrapper::KesSignatureMissing)?;
263 let kes_period =
264 kes_period.ok_or(ProtocolRegistrationErrorWrapper::KesPeriodMissing)?;
265 if self
266 .kes_verifier
267 .verify(&pk.to_bytes(), &signature, &opcert, kes_period)
268 .is_ok()
269 {
270 opcert
271 .compute_protocol_party_id()
272 .map_err(|_| ProtocolRegistrationErrorWrapper::PoolAddressEncoding)?
273 } else {
274 return Err(ProtocolRegistrationErrorWrapper::KesSignatureInvalid(
275 kes_period,
276 opcert.start_kes_period,
277 ));
278 }
279 } else {
280 if cfg!(not(feature = "allow_skip_signer_certification")) {
281 Err(ProtocolRegistrationErrorWrapper::OpCertMissing)?
282 }
283 party_id.ok_or(ProtocolRegistrationErrorWrapper::PartyIdMissing)?
284 };
285
286 if let Some(&stake) = self.stake_distribution.get(&pool_id_bech32) {
287 self.stm_key_reg
288 .register(stake, pk.into())
289 .map_err(ProtocolRegistrationErrorWrapper::CoreRegister)?;
290 return Ok(pool_id_bech32);
291 }
292 Err(ProtocolRegistrationErrorWrapper::PartyIdNonExisting)
293 }
294
295 pub fn close<D: Digest + FixedOutput>(self) -> ClosedKeyRegistration<D> {
298 self.stm_key_reg.close()
299 }
300}
301
302#[cfg(test)]
303mod test {
304 use crate::crypto_helper::cardano::kes::{
305 KesSignerStandard,
306 tests_setup::{
307 KesCryptographicMaterialForTest, KesPartyIndexForTest,
308 create_kes_cryptographic_material,
309 },
310 };
311 use crate::crypto_helper::{OpCert, SerDeShelleyFileFormat};
312
313 use rand_chacha::ChaCha20Rng;
314 use rand_core::SeedableRng;
315
316 use super::*;
317
318 #[test]
319 fn test_vector_key_reg() {
320 let params = Parameters {
321 m: 5,
322 k: 5,
323 phi_f: 1.0,
324 };
325 let mut rng = ChaCha20Rng::from_seed([0u8; 32]);
326 let KesCryptographicMaterialForTest {
327 party_id: party_id_1,
328 operational_certificate_file: operational_certificate_file_1,
329 kes_secret_key_file: kes_secret_key_file_1,
330 } = create_kes_cryptographic_material(
331 1 as KesPartyIndexForTest,
332 0 as KesPeriod,
333 "test_vector_key_reg",
334 );
335 let KesCryptographicMaterialForTest {
336 party_id: party_id_2,
337 operational_certificate_file: operational_certificate_file_2,
338 kes_secret_key_file: kes_secret_key_file_2,
339 } = create_kes_cryptographic_material(
340 2 as KesPartyIndexForTest,
341 0 as KesPeriod,
342 "test_vector_key_reg",
343 );
344
345 let mut key_reg = KeyRegWrapper::init(&vec![(party_id_1, 10), (party_id_2, 3)]);
346
347 let initializer_1 = StmInitializerWrapper::setup(
348 params,
349 Some(Arc::new(KesSignerStandard::new(
350 kes_secret_key_file_1,
351 operational_certificate_file_1.clone(),
352 ))),
353 Some(0),
354 10,
355 &mut rng,
356 )
357 .unwrap();
358
359 let opcert1 = OpCert::from_file(operational_certificate_file_1)
360 .expect("opcert deserialization should not fail")
361 .into();
362
363 let key_registration_1 = key_reg.register(
364 None,
365 Some(opcert1),
366 initializer_1.verification_key_signature(),
367 Some(0),
368 initializer_1.stm_initializer.verification_key().into(),
369 );
370 assert!(key_registration_1.is_ok());
371
372 let initializer_2 = StmInitializerWrapper::setup(
373 params,
374 Some(Arc::new(KesSignerStandard::new(
375 kes_secret_key_file_2,
376 operational_certificate_file_2.clone(),
377 ))),
378 Some(0),
379 10,
380 &mut rng,
381 )
382 .unwrap();
383
384 let opcert2 = OpCert::from_file(operational_certificate_file_2)
385 .expect("opcert deserialization should not fail")
386 .into();
387
388 let key_registration_2 = key_reg.register(
389 None,
390 Some(opcert2),
391 initializer_2.verification_key_signature(),
392 Some(0),
393 initializer_2.stm_initializer.verification_key().into(),
394 );
395 assert!(key_registration_2.is_ok())
396 }
397
398 const GOLDEN_STM_INITIALIZER_WRAPPER_JSON: &str = r#"
399 {
400 "stm_initializer": {
401 "stake": 9497432569,
402 "params": {
403 "m": 20973,
404 "k": 2422,
405 "phi_f": 0.2
406 },
407 "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],
408 "pk": {
409 "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],
410 "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]
411 }
412 },
413 "kes_signature": {
414 "sigma": {
415 "sigma": {
416 "sigma": {
417 "sigma": {
418 "sigma": {
419 "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],
420 "lhs_pk": [
421 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],
422 "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]
423 },
424 "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],
425 "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]
426 },
427 "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],
428 "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]
429 },
430 "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],
431 "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]
432 },
433 "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],
434 "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]
435 },
436 "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],
437 "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]
438 }
439 }
440 "#;
441
442 #[test]
443 fn golden_initializer_deserialization() {
444 let _: StmInitializerWrapper = serde_json::from_str(GOLDEN_STM_INITIALIZER_WRAPPER_JSON)
445 .expect("Deserializing a StmInitializerWrapper should not fail");
446 }
447
448 #[test]
449 fn test_initializer_wrapper_conversions() {
450 let stm_initializer_wrapper_json = GOLDEN_STM_INITIALIZER_WRAPPER_JSON;
451
452 let stm_initializer_wrapper_from_json: StmInitializerWrapper =
453 serde_json::from_str(stm_initializer_wrapper_json)
454 .expect("Deserializing a StmInitializerWrapper should not fail");
455 let stm_initializer_wrapper_from_json_to_json =
456 serde_json::to_string(&stm_initializer_wrapper_from_json)
457 .expect("Serializing a StmInitializerWrapper to json should not fail");
458
459 let stm_initializer_wrapper_from_bytes =
460 StmInitializerWrapper::from_bytes(&stm_initializer_wrapper_from_json.to_bytes())
461 .expect("Deserializing a StmInitializerWrapper from bytes should not fail");
462 let stm_initializer_wrapper_from_bytes_to_json =
463 serde_json::to_string(&stm_initializer_wrapper_from_bytes)
464 .expect("Serializing a StmInitializerWrapper to json should not fail");
465
466 assert_eq!(
467 stm_initializer_wrapper_from_json_to_json,
468 stm_initializer_wrapper_from_bytes_to_json
469 );
470
471 let mut stm_initializer_wrapper_from_json = stm_initializer_wrapper_from_json;
472 stm_initializer_wrapper_from_json.kes_signature = None;
473
474 let stm_initializer_wrapper_from_bytes =
475 StmInitializerWrapper::from_bytes(&stm_initializer_wrapper_from_json.to_bytes())
476 .expect("Deserializing a StmInitializerWrapper from bytes should not fail");
477 assert_eq!(None, stm_initializer_wrapper_from_bytes.kes_signature);
478 }
479}