1use std::{collections::HashMap, sync::Arc};
7
8use anyhow::{Context, anyhow};
9use kes_summed_ed25519::kes::Sum6KesSig;
10use rand_core::{CryptoRng, RngCore};
11use serde::{Deserialize, Serialize};
12use thiserror::Error;
13
14#[cfg(feature = "future_snark")]
15use mithril_stm::VerificationKeyForSnark;
16use mithril_stm::{
17 ClosedKeyRegistration, Initializer, KeyRegistration, MithrilMembershipDigest, Parameters,
18 RegisterError, Signer, Stake, VerificationKeyProofOfPossessionForConcatenation,
19};
20
21#[cfg(feature = "future_snark")]
22use crate::crypto_helper::types::{
23 ProtocolSignerVerificationKeyForSnark, ProtocolSignerVerificationKeySignatureForSnark,
24};
25use crate::{
26 StdError, StdResult,
27 crypto_helper::{
28 KesEvolutions, KesPeriod, ProtocolOpCert,
29 cardano::{KesSigner, KesVerifier, KesVerifierStandard},
30 types::{
31 ProtocolParameters, ProtocolPartyId, ProtocolSignerVerificationKeyForConcatenation,
32 ProtocolSignerVerificationKeySignatureForConcatenation, ProtocolStakeDistribution,
33 },
34 },
35};
36
37type D = MithrilMembershipDigest;
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: KesEvolutions={0}, StartKesPeriod={1}")]
63 KesSignatureInvalid(KesEvolutions, KesPeriod, #[source] StdError),
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 evolution {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 #[serde(rename = "kes_signature")]
110 kes_signature_for_concatenation: Option<Sum6KesSig>,
111
112 #[cfg(feature = "future_snark")]
114 #[serde(skip_serializing_if = "Option::is_none", default)]
115 kes_signature_for_snark: Option<Sum6KesSig>,
116}
117
118impl StmInitializerWrapper {
119 pub fn setup<R: RngCore + CryptoRng>(
123 params: Parameters,
124 kes_signer: Option<Arc<dyn KesSigner>>,
125 current_kes_period: Option<KesPeriod>,
126 stake: Stake,
127 rng: &mut R,
128 ) -> StdResult<Self> {
129 let stm_initializer = Initializer::new(params, stake, rng);
130 let kes_signature;
131 #[cfg(feature = "future_snark")]
132 let kes_signature_for_snark;
133
134 if let Some(kes_signer) = kes_signer {
135 let (signature, _op_cert) = kes_signer.sign(
136 &stm_initializer
137 .get_verification_key_proof_of_possession_for_concatenation()
138 .to_bytes(),
139 current_kes_period.unwrap_or_default(),
140 )?;
141 kes_signature = Some(signature);
142
143 #[cfg(feature = "future_snark")]
144 {
145 kes_signature_for_snark = if let Some(schnorr_verification_key) =
146 &stm_initializer.schnorr_verification_key
147 {
148 let (signature, _op_cert) = kes_signer.sign(
149 &schnorr_verification_key.to_bytes(),
150 current_kes_period.unwrap_or_default(),
151 )?;
152
153 Some(signature)
154 } else {
155 None
156 };
157 }
158 } else {
159 println!(
160 "WARNING: Non certified signer registration by providing only a Pool Id is decommissioned and must be used for tests only!"
161 );
162 kes_signature = None;
163 #[cfg(feature = "future_snark")]
164 {
165 kes_signature_for_snark = None;
166 }
167 };
168
169 Ok(Self {
170 stm_initializer,
171 kes_signature_for_concatenation: kes_signature,
172 #[cfg(feature = "future_snark")]
173 kes_signature_for_snark,
174 })
175 }
176
177 pub fn verification_key_for_concatenation(
179 &self,
180 ) -> VerificationKeyProofOfPossessionForConcatenation {
181 self.stm_initializer
182 .get_verification_key_proof_of_possession_for_concatenation()
183 }
184
185 pub fn verification_key_signature_for_concatenation(
187 &self,
188 ) -> Option<ProtocolSignerVerificationKeySignatureForConcatenation> {
189 self.kes_signature_for_concatenation.map(|k| k.into())
190 }
191
192 #[cfg(feature = "future_snark")]
194 pub fn verification_key_for_snark(&self) -> Option<VerificationKeyForSnark> {
195 self.stm_initializer.schnorr_verification_key
196 }
197
198 #[cfg(feature = "future_snark")]
200 pub fn verification_key_signature_for_snark(
201 &self,
202 ) -> Option<ProtocolSignerVerificationKeySignatureForSnark> {
203 self.kes_signature_for_snark.map(|k| k.into())
204 }
205
206 pub fn get_protocol_parameters(&self) -> ProtocolParameters {
208 self.stm_initializer.parameters
209 }
210
211 pub fn get_stake(&self) -> Stake {
213 self.stm_initializer.stake
214 }
215
216 pub fn new_signer(self, closed_reg: ClosedKeyRegistration) -> StdResult<Signer<D>> {
229 self.stm_initializer.try_create_signer(&closed_reg)
230 }
231
232 pub fn to_bytes(&self) -> Vec<u8> {
238 let mut out = Vec::new();
239
240 let stm_initializer_bytes = self.stm_initializer.to_bytes();
241 out.extend_from_slice(
242 &u64::try_from(stm_initializer_bytes.len())
243 .expect("STM initializer byte length should always fit in u64")
244 .to_be_bytes(),
245 );
246 out.extend_from_slice(&stm_initializer_bytes);
247
248 if let Some(kes_signature_for_concatenation) = &self.kes_signature_for_concatenation {
249 out.extend_from_slice(&kes_signature_for_concatenation.to_bytes());
250
251 #[cfg(feature = "future_snark")]
252 if let Some(kes_signature_for_snark) = &self.kes_signature_for_snark {
253 out.extend_from_slice(&kes_signature_for_snark.to_bytes());
254 }
255 }
256
257 out
258 }
259
260 pub fn from_bytes(bytes: &[u8]) -> StdResult<Self> {
264 let mut bytes_index = 0;
265
266 let mut u64_bytes = [0u8; 8];
267 u64_bytes.copy_from_slice(
268 bytes
269 .get(bytes_index..bytes_index + 8)
270 .ok_or(RegisterError::SerializationError)?,
271 );
272 let stm_initializer_size = usize::try_from(u64::from_be_bytes(u64_bytes))
273 .map_err(|_| RegisterError::SerializationError)?;
274
275 let stm_initializer = Initializer::from_bytes(
276 bytes
277 .get(bytes_index + 8..bytes_index + 8 + stm_initializer_size)
278 .ok_or(RegisterError::SerializationError)?,
279 )?;
280 bytes_index += 8 + stm_initializer_size;
281
282 let kes_signature_for_concatenation;
283 #[cfg(feature = "future_snark")]
284 let kes_signature_for_snark;
285 if let Some(kes_signature) = bytes.get(bytes_index..bytes_index + Sum6KesSig::SIZE) {
286 kes_signature_for_concatenation = Some(
287 Sum6KesSig::from_bytes(kes_signature)
288 .map_err(|_| RegisterError::SerializationError)?,
289 );
290
291 #[cfg(feature = "future_snark")]
292 {
293 bytes_index += Sum6KesSig::SIZE;
294 kes_signature_for_snark = if let Some(snark_kes_signature) =
295 bytes.get(bytes_index..bytes_index + Sum6KesSig::SIZE)
296 {
297 let snark_kes_signature = Sum6KesSig::from_bytes(snark_kes_signature)
298 .map_err(|_| RegisterError::SerializationError)?;
299
300 Some(snark_kes_signature)
301 } else {
302 None
303 };
304 }
305 } else {
306 kes_signature_for_concatenation = None;
307 #[cfg(feature = "future_snark")]
308 {
309 kes_signature_for_snark = None;
310 }
311 }
312
313 Ok(Self {
314 stm_initializer,
315 kes_signature_for_concatenation,
316 #[cfg(feature = "future_snark")]
317 kes_signature_for_snark,
318 })
319 }
320}
321
322#[derive(Debug, Clone)]
327pub struct SignerRegistrationParameters {
328 pub party_id: Option<ProtocolPartyId>,
332
333 pub operational_certificate: Option<ProtocolOpCert>,
337
338 pub verification_key_for_concatenation: ProtocolSignerVerificationKeyForConcatenation,
340
341 pub verification_key_signature_for_concatenation:
345 Option<ProtocolSignerVerificationKeySignatureForConcatenation>,
346
347 pub kes_evolutions: Option<KesEvolutions>,
350
351 #[cfg(feature = "future_snark")]
353 pub verification_key_for_snark: Option<ProtocolSignerVerificationKeyForSnark>,
354
355 #[cfg(feature = "future_snark")]
357 pub verification_key_signature_for_snark:
358 Option<ProtocolSignerVerificationKeySignatureForSnark>,
359}
360
361#[derive(Debug, Clone)]
368pub struct KeyRegWrapper {
369 kes_verifier: Arc<dyn KesVerifier>,
370 stm_key_reg: KeyRegistration,
371 stake_distribution: HashMap<ProtocolPartyId, Stake>,
372}
373
374impl KeyRegWrapper {
375 pub fn init(stake_dist: &ProtocolStakeDistribution) -> Self {
378 Self {
379 kes_verifier: Arc::new(KesVerifierStandard),
380 stm_key_reg: KeyRegistration::initialize(),
381 stake_distribution: HashMap::from_iter(stake_dist.to_vec()),
382 }
383 }
384
385 fn verify_kes_signature(
389 &self,
390 message: &[u8],
391 kes_sig: Option<Sum6KesSig>,
392 opcert: &ProtocolOpCert,
393 kes_evolutions: KesEvolutions,
394 ) -> Result<(), ProtocolRegistrationErrorWrapper> {
395 let signature = kes_sig.ok_or(ProtocolRegistrationErrorWrapper::KesSignatureMissing)?;
396 self.kes_verifier
397 .verify(message, &signature, opcert, kes_evolutions)
398 .map_err(|e| {
399 ProtocolRegistrationErrorWrapper::KesSignatureInvalid(
400 kes_evolutions,
401 opcert.get_start_kes_period(),
402 e,
403 )
404 })
405 }
406
407 pub fn register(
414 &mut self,
415 parameters: SignerRegistrationParameters,
416 ) -> StdResult<ProtocolPartyId> {
417 let pool_id_bech32: ProtocolPartyId =
418 if let Some(opcert) = ¶meters.operational_certificate {
419 let kes_evolutions = parameters
420 .kes_evolutions
421 .ok_or(ProtocolRegistrationErrorWrapper::KesPeriodMissing)?;
422
423 self.verify_kes_signature(
424 ¶meters.verification_key_for_concatenation.to_bytes(),
425 parameters
426 .verification_key_signature_for_concatenation
427 .map(|s| s.into_inner()),
428 opcert,
429 kes_evolutions,
430 )
431 .with_context(|| "invalid KES signature for Concatenation")?;
432
433 #[cfg(feature = "future_snark")]
434 if let Some(verification_key_for_snark) = ¶meters.verification_key_for_snark {
435 self.verify_kes_signature(
436 &verification_key_for_snark.to_bytes(),
437 parameters
438 .verification_key_signature_for_snark
439 .map(|s| s.into_inner()),
440 opcert,
441 kes_evolutions,
442 )
443 .with_context(|| "invalid KES signature for SNARK")?;
444 }
445
446 opcert
447 .compute_protocol_party_id()
448 .map_err(|_| ProtocolRegistrationErrorWrapper::PoolAddressEncoding)?
449 } else {
450 if cfg!(not(feature = "allow_skip_signer_certification")) {
451 Err(ProtocolRegistrationErrorWrapper::OpCertMissing)?
452 }
453 parameters
454 .party_id
455 .ok_or(ProtocolRegistrationErrorWrapper::PartyIdMissing)?
456 };
457
458 if let Some(&stake) = self.stake_distribution.get(&pool_id_bech32) {
459 self.stm_key_reg.register(
460 stake,
461 ¶meters.verification_key_for_concatenation.into(),
462 #[cfg(feature = "future_snark")]
463 parameters.verification_key_for_snark.map(|k| k.into()),
464 )?;
465 return Ok(pool_id_bech32);
466 }
467 Err(anyhow!(
468 ProtocolRegistrationErrorWrapper::PartyIdNonExisting
469 ))
470 }
471
472 pub fn close(self) -> ClosedKeyRegistration {
475 self.stm_key_reg.close_registration()
476 }
477}
478
479mod test_extensions {
480 use crate::test::crypto_helper::ProtocolInitializerTestExtension;
481
482 use super::*;
483
484 impl ProtocolInitializerTestExtension for StmInitializerWrapper {
485 fn override_protocol_parameters(&mut self, protocol_parameters: &ProtocolParameters) {
486 self.stm_initializer.parameters = protocol_parameters.to_owned();
487 }
488 }
489}
490
491#[cfg(test)]
492mod test {
493 use crate::crypto_helper::cardano::kes::KesSignerStandard;
494 use crate::crypto_helper::{OpCert, SerDeShelleyFileFormat};
495 use crate::test::crypto_helper::{
496 KesCryptographicMaterialForTest, KesPartyIndexForTest, create_kes_cryptographic_material,
497 };
498
499 use rand_chacha::ChaCha20Rng;
500 use rand_core::SeedableRng;
501
502 use super::*;
503
504 #[test]
505 fn test_vector_key_reg() {
506 let params = Parameters {
507 m: 5,
508 k: 5,
509 phi_f: 1.0,
510 };
511 let mut rng = ChaCha20Rng::from_seed([0u8; 32]);
512 let KesCryptographicMaterialForTest {
513 party_id: party_id_1,
514 operational_certificate_file: operational_certificate_file_1,
515 kes_secret_key_file: kes_secret_key_file_1,
516 } = create_kes_cryptographic_material(
517 1 as KesPartyIndexForTest,
518 KesPeriod(0),
519 "test_vector_key_reg",
520 );
521 let KesCryptographicMaterialForTest {
522 party_id: party_id_2,
523 operational_certificate_file: operational_certificate_file_2,
524 kes_secret_key_file: kes_secret_key_file_2,
525 } = create_kes_cryptographic_material(
526 2 as KesPartyIndexForTest,
527 KesPeriod(0),
528 "test_vector_key_reg",
529 );
530
531 let mut key_reg = KeyRegWrapper::init(&vec![(party_id_1, 10), (party_id_2, 3)]);
532
533 let initializer_1 = StmInitializerWrapper::setup(
534 params,
535 Some(Arc::new(KesSignerStandard::new(
536 kes_secret_key_file_1,
537 operational_certificate_file_1.clone(),
538 ))),
539 Some(KesPeriod(0)),
540 10,
541 &mut rng,
542 )
543 .unwrap();
544
545 let opcert1 = OpCert::from_file(operational_certificate_file_1)
546 .expect("opcert deserialization should not fail")
547 .into();
548
549 let key_registration_1 = key_reg.register(SignerRegistrationParameters {
550 party_id: None,
551 operational_certificate: Some(opcert1),
552 verification_key_signature_for_concatenation: initializer_1
553 .verification_key_signature_for_concatenation(),
554 kes_evolutions: Some(KesEvolutions(0)),
555 verification_key_for_concatenation: initializer_1
556 .stm_initializer
557 .get_verification_key_proof_of_possession_for_concatenation()
558 .into(),
559 #[cfg(feature = "future_snark")]
560 verification_key_for_snark: initializer_1.verification_key_for_snark().map(Into::into),
561 #[cfg(feature = "future_snark")]
562 verification_key_signature_for_snark: initializer_1
563 .verification_key_signature_for_snark(),
564 });
565 assert!(key_registration_1.is_ok());
566
567 let initializer_2 = StmInitializerWrapper::setup(
568 params,
569 Some(Arc::new(KesSignerStandard::new(
570 kes_secret_key_file_2,
571 operational_certificate_file_2.clone(),
572 ))),
573 Some(KesPeriod(0)),
574 10,
575 &mut rng,
576 )
577 .unwrap();
578
579 let opcert2 = OpCert::from_file(operational_certificate_file_2)
580 .expect("opcert deserialization should not fail")
581 .into();
582
583 let key_registration_2 = key_reg.register(SignerRegistrationParameters {
584 party_id: None,
585 operational_certificate: Some(opcert2),
586 verification_key_signature_for_concatenation: initializer_2
587 .verification_key_signature_for_concatenation(),
588 kes_evolutions: Some(KesEvolutions(0)),
589 verification_key_for_concatenation: initializer_2
590 .stm_initializer
591 .get_verification_key_proof_of_possession_for_concatenation()
592 .into(),
593 #[cfg(feature = "future_snark")]
594 verification_key_for_snark: initializer_2.verification_key_for_snark().map(Into::into),
595 #[cfg(feature = "future_snark")]
596 verification_key_signature_for_snark: initializer_2
597 .verification_key_signature_for_snark(),
598 });
599 assert!(key_registration_2.is_ok())
600 }
601
602 const GOLDEN_STM_INITIALIZER_WRAPPER_JSON: &str = r#"
603 {
604 "stm_initializer": {
605 "stake": 9497432569,
606 "params": {
607 "m": 20973,
608 "k": 2422,
609 "phi_f": 0.2
610 },
611 "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],
612 "pk": {
613 "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],
614 "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]
615 }
616 },
617 "kes_signature": {
618 "sigma": {
619 "sigma": {
620 "sigma": {
621 "sigma": {
622 "sigma": {
623 "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],
624 "lhs_pk": [
625 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],
626 "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]
627 },
628 "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],
629 "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]
630 },
631 "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],
632 "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]
633 },
634 "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],
635 "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]
636 },
637 "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],
638 "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]
639 },
640 "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],
641 "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]
642 }
643 }
644 "#;
645
646 #[test]
647 fn golden_initializer_deserialization() {
648 let _: StmInitializerWrapper = serde_json::from_str(GOLDEN_STM_INITIALIZER_WRAPPER_JSON)
649 .expect("Deserializing a StmInitializerWrapper should not fail");
650 }
651
652 #[test]
653 fn test_initializer_wrapper_conversions() {
654 let stm_initializer_wrapper_json = GOLDEN_STM_INITIALIZER_WRAPPER_JSON;
655
656 let stm_initializer_wrapper_from_json: StmInitializerWrapper =
657 serde_json::from_str(stm_initializer_wrapper_json)
658 .expect("Deserializing a StmInitializerWrapper should not fail");
659 let stm_initializer_wrapper_from_json_to_json =
660 serde_json::to_string(&stm_initializer_wrapper_from_json)
661 .expect("Serializing a StmInitializerWrapper to json should not fail");
662
663 let stm_initializer_wrapper_from_bytes =
664 StmInitializerWrapper::from_bytes(&stm_initializer_wrapper_from_json.to_bytes())
665 .expect("Deserializing a StmInitializerWrapper from bytes should not fail");
666 let stm_initializer_wrapper_from_bytes_to_json =
667 serde_json::to_string(&stm_initializer_wrapper_from_bytes)
668 .expect("Serializing a StmInitializerWrapper to json should not fail");
669
670 assert_eq!(
671 stm_initializer_wrapper_from_json_to_json,
672 stm_initializer_wrapper_from_bytes_to_json
673 );
674
675 let mut stm_initializer_wrapper_from_json = stm_initializer_wrapper_from_json;
676 stm_initializer_wrapper_from_json.kes_signature_for_concatenation = None;
677
678 let stm_initializer_wrapper_from_bytes =
679 StmInitializerWrapper::from_bytes(&stm_initializer_wrapper_from_json.to_bytes())
680 .expect("Deserializing a StmInitializerWrapper from bytes should not fail");
681 assert_eq!(
682 None,
683 stm_initializer_wrapper_from_bytes.kes_signature_for_concatenation
684 );
685 }
686}