mithril_common/crypto_helper/cardano/
key_certification.rs

1//! API for mithril key certification.
2//! Includes the wrappers for Initializer and KeyRegistration, and ProtocolRegistrationErrorWrapper.
3//! These wrappers allows keeping mithril-stm agnostic to Cardano, while providing some
4//! guarantees that mithril-stm will not be misused in the context of Cardano.  
5
6use 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
37// Protocol types alias
38type D = MithrilMembershipDigest;
39
40/// New registration error
41#[derive(Error, Debug)]
42pub enum ProtocolRegistrationErrorWrapper {
43    /// Error raised when a party id is needed but not provided
44    ///
45    /// Used only for testing when SPO pool id is not certified
46    #[error("missing party id")]
47    PartyIdMissing,
48
49    /// Error raised when a party id is not available in the Cardano_stake distribution
50    #[error("party id does not exist in the stake distribution")]
51    PartyIdNonExisting,
52
53    /// Error raised when the operational certificate is missing
54    #[error("missing operational certificate")]
55    OpCertMissing,
56
57    /// Error raised when an operational certificate is invalid
58    #[error("invalid operational certificate")]
59    OpCertInvalid,
60
61    /// Error raised when a KES Signature verification fails
62    #[error("KES signature verification error: KesEvolutions={0}, StartKesPeriod={1}")]
63    KesSignatureInvalid(KesEvolutions, KesPeriod, #[source] StdError),
64
65    /// Error raised when a KES Signature is needed but not provided
66    #[error("missing KES signature")]
67    KesSignatureMissing,
68
69    /// Error raised when a KES Period is needed but not provided
70    #[error("missing KES period")]
71    KesPeriodMissing,
72
73    /// Error raised when a pool address encoding fails
74    #[error("pool address encoding error")]
75    PoolAddressEncoding,
76
77    /// Error raised when a core registration error occurs
78    #[error("core registration error")]
79    CoreRegister(#[source] RegisterError),
80}
81
82/// New initializer error
83#[derive(Error, Debug)]
84pub enum ProtocolInitializerErrorWrapper {
85    /// Error raised when the underlying protocol initializer fails
86    #[error("protocol initializer error")]
87    ProtocolInitializer(#[source] StdError),
88
89    /// Error raised when a KES update error occurs
90    #[error("KES key cannot be updated for evolution {0}")]
91    KesUpdate(KesPeriod),
92
93    /// Period of key file does not match with period provided by user
94    #[error("Period of key file, {0}, does not match with period provided by user, {1}")]
95    KesMismatch(KesPeriod, KesPeriod),
96}
97
98/// Wrapper structure for [MithrilStm:Initializer](mithril_stm::stm::Initializer).
99/// It now obtains a KES signature over the Mithril key. This allows the signers prove
100/// their correct identity with respect to a Cardano PoolID.
101#[derive(Debug, Clone, Serialize, Deserialize)]
102pub struct StmInitializerWrapper {
103    /// The Initializer
104    stm_initializer: Initializer,
105
106    /// The KES signature over the verification key for the concatenation proof system
107    ///
108    /// None is used only for testing when SPO pool id is not certified
109    #[serde(rename = "kes_signature")]
110    kes_signature_for_concatenation: Option<Sum6KesSig>,
111
112    /// The KES signature over the verification key for the SNARK proof system
113    #[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    /// Builds an `Initializer` that is ready to register with the key registration service.
120    /// This function generates the signing and verification key with a PoP, signs the verification
121    /// key with a provided KES signer implementation, and initializes the structure.
122    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    /// Extract the verification key for the concatenation proof system.
178    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    /// Extract the verification key signature.
186    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    /// Extract the verification key for the SNARK proof system.
193    #[cfg(feature = "future_snark")]
194    pub fn verification_key_for_snark(&self) -> Option<VerificationKeyForSnark> {
195        self.stm_initializer.schnorr_verification_key
196    }
197
198    /// Extract the KES signature over the Schnorr verification key.
199    #[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    /// Extract the protocol parameters of the initializer
207    pub fn get_protocol_parameters(&self) -> ProtocolParameters {
208        self.stm_initializer.parameters
209    }
210
211    /// Extract the stake of the party
212    pub fn get_stake(&self) -> Stake {
213        self.stm_initializer.stake
214    }
215
216    /// Build the `avk` for the given list of parties.
217    ///
218    /// Note that if this Initializer was modified *between* the last call to `register`,
219    /// then the resulting `Signer` may not be able to produce valid signatures.
220    ///
221    /// Returns a `StmSignerWrapper` specialized to
222    /// * this `StmSignerWrapper`'s ID and current stake
223    /// * this `StmSignerWrapper`'s parameter valuation
224    /// * the `avk` as built from the current registered parties (according to the registration service)
225    /// * the current total stake (according to the registration service)
226    /// # Error
227    /// This function fails if the initializer is not registered.
228    pub fn new_signer(self, closed_reg: ClosedKeyRegistration) -> StdResult<Signer<D>> {
229        self.stm_initializer.try_create_signer(&closed_reg)
230    }
231
232    /// Convert to bytes
233    ///
234    /// * Length-prefixed STM Initializer (dynamic size)
235    /// * Optional KES signature for the concatenation proof system (fixed size)
236    /// * Optional KES signature for the SNARK proof system (fixed size, when `future_snark` feature is enabled and if some KES signature for concatenation)
237    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    /// Convert a slice of bytes to an `StmInitializerWrapper`
261    /// # Error
262    /// The function fails if the given string of bytes is not of required size.
263    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/// Parameters required for registering a signer with the key registration service.
323///
324/// Groups the verification keys, their KES signatures, and the operational certificate
325/// that together prove a signer's identity and authorization.
326#[derive(Debug, Clone)]
327pub struct SignerRegistrationParameters {
328    /// The party identifier of the signer
329    ///
330    /// Used only for testing when SPO pool id is not certified
331    pub party_id: Option<ProtocolPartyId>,
332
333    /// The operational certificate of the stake pool operator
334    ///
335    /// Used only for testing when SPO pool id is not certified
336    pub operational_certificate: Option<ProtocolOpCert>,
337
338    /// The verification key for the Concatenation proof system
339    pub verification_key_for_concatenation: ProtocolSignerVerificationKeyForConcatenation,
340
341    /// The KES signature over the verification key for Concatenation
342    ///
343    /// None is used only for testing when SPO pool id is not certified
344    pub verification_key_signature_for_concatenation:
345        Option<ProtocolSignerVerificationKeySignatureForConcatenation>,
346
347    /// The number of evolutions of the KES key since the start KES period of the
348    /// operational certificate at the time of signature
349    pub kes_evolutions: Option<KesEvolutions>,
350
351    /// The verification key for the SNARK proof system
352    #[cfg(feature = "future_snark")]
353    pub verification_key_for_snark: Option<ProtocolSignerVerificationKeyForSnark>,
354
355    /// The KES signature over the verification key for SNARK
356    #[cfg(feature = "future_snark")]
357    pub verification_key_signature_for_snark:
358        Option<ProtocolSignerVerificationKeySignatureForSnark>,
359}
360
361/// Wrapper structure for [MithrilStm:KeyRegistration](mithril_stm::key_reg::KeyRegistration).
362/// The wrapper not only contains a map between `Mithril vkey <-> Stake`, but also
363/// a map `PoolID <-> Stake`. This information is recovered from the node state, and
364/// is used to verify the identity of a Mithril signer. Furthermore, the `register` function
365/// of the wrapper forces the registrar to check that the KES signature over the Mithril key
366/// is valid with respect to the PoolID.
367#[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    /// New Initialisation function. We temporarily keep the other init function,
376    /// but we should eventually transition to only use this one.
377    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    /// Verify a KES signature over a message.
386    ///
387    /// Returns an error if the signature is missing or invalid.
388    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    /// Register a new party. For a successful registration, the registrar needs to
408    /// provide the OpCert (in cbor form), the cold VK, a KES signature, and a
409    /// Mithril key (with its corresponding Proof of Possession).
410    ///
411    /// When the `future_snark` feature is enabled, an optional Schnorr verification key
412    /// and its KES signature can be provided for SNARK proof system authentication.
413    pub fn register(
414        &mut self,
415        parameters: SignerRegistrationParameters,
416    ) -> StdResult<ProtocolPartyId> {
417        let pool_id_bech32: ProtocolPartyId =
418            if let Some(opcert) = &parameters.operational_certificate {
419                let kes_evolutions = parameters
420                    .kes_evolutions
421                    .ok_or(ProtocolRegistrationErrorWrapper::KesPeriodMissing)?;
422
423                self.verify_kes_signature(
424                    &parameters.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) = &parameters.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                &parameters.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    /// Finalize the key registration.
473    /// This function disables `ClosedKeyRegistration::register`, consumes the instance of `self`, and returns a `ClosedKeyRegistration`.
474    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}