Skip to main content

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    /// Remove the SNARK-related keys from the underlying initializer and the
207    /// corresponding KES signature.
208    ///
209    /// This is used during eras that do not yet support SNARK proofs to ensure the
210    /// initializer's registration entry matches the closed key registration built from
211    /// signers without SNARK verification keys.
212    #[cfg(feature = "future_snark")]
213    pub fn strip_snark_keys(&mut self) {
214        self.stm_initializer.strip_snark_keys();
215        self.kes_signature_for_snark = None;
216    }
217
218    /// Extract the protocol parameters of the initializer
219    pub fn get_protocol_parameters(&self) -> ProtocolParameters {
220        self.stm_initializer.parameters
221    }
222
223    /// Extract the stake of the party
224    pub fn get_stake(&self) -> Stake {
225        self.stm_initializer.stake
226    }
227
228    /// Build the `avk` for the given list of parties.
229    ///
230    /// Note that if this Initializer was modified *between* the last call to `register`,
231    /// then the resulting `Signer` may not be able to produce valid signatures.
232    ///
233    /// Returns a `StmSignerWrapper` specialized to
234    /// * this `StmSignerWrapper`'s ID and current stake
235    /// * this `StmSignerWrapper`'s parameter valuation
236    /// * the `avk` as built from the current registered parties (according to the registration service)
237    /// * the current total stake (according to the registration service)
238    /// # Error
239    /// This function fails if the initializer is not registered.
240    pub fn new_signer(self, closed_reg: ClosedKeyRegistration) -> StdResult<Signer<D>> {
241        self.stm_initializer.try_create_signer(&closed_reg)
242    }
243
244    /// Convert to bytes
245    ///
246    /// * Length-prefixed STM Initializer (dynamic size)
247    /// * Optional KES signature for the concatenation proof system (fixed size)
248    /// * Optional KES signature for the SNARK proof system (fixed size, when `future_snark` feature is enabled and if some KES signature for concatenation)
249    pub fn to_bytes(&self) -> StdResult<Vec<u8>> {
250        let mut out = Vec::new();
251
252        let stm_initializer_bytes = self.stm_initializer.to_bytes()?;
253        out.extend_from_slice(
254            &u64::try_from(stm_initializer_bytes.len())
255                .context("STM initializer byte length should fit in u64")?
256                .to_be_bytes(),
257        );
258        out.extend_from_slice(&stm_initializer_bytes);
259
260        if let Some(kes_signature_for_concatenation) = &self.kes_signature_for_concatenation {
261            out.extend_from_slice(&kes_signature_for_concatenation.to_bytes());
262
263            #[cfg(feature = "future_snark")]
264            if let Some(kes_signature_for_snark) = &self.kes_signature_for_snark {
265                out.extend_from_slice(&kes_signature_for_snark.to_bytes());
266            }
267        }
268
269        Ok(out)
270    }
271
272    /// Convert a slice of bytes to an `StmInitializerWrapper`
273    /// # Error
274    /// The function fails if the given string of bytes is not of required size.
275    pub fn from_bytes(bytes: &[u8]) -> StdResult<Self> {
276        let mut bytes_index = 0;
277
278        let mut u64_bytes = [0u8; 8];
279        u64_bytes.copy_from_slice(
280            bytes
281                .get(bytes_index..bytes_index + 8)
282                .ok_or(RegisterError::SerializationError)?,
283        );
284        let stm_initializer_size = usize::try_from(u64::from_be_bytes(u64_bytes))
285            .map_err(|_| RegisterError::SerializationError)?;
286
287        let stm_initializer = Initializer::from_bytes(
288            bytes
289                .get(bytes_index + 8..bytes_index + 8 + stm_initializer_size)
290                .ok_or(RegisterError::SerializationError)?,
291        )?;
292        bytes_index += 8 + stm_initializer_size;
293
294        let kes_signature_for_concatenation;
295        #[cfg(feature = "future_snark")]
296        let kes_signature_for_snark;
297        if let Some(kes_signature) = bytes.get(bytes_index..bytes_index + Sum6KesSig::SIZE) {
298            kes_signature_for_concatenation = Some(
299                Sum6KesSig::from_bytes(kes_signature)
300                    .map_err(|_| RegisterError::SerializationError)?,
301            );
302
303            #[cfg(feature = "future_snark")]
304            {
305                bytes_index += Sum6KesSig::SIZE;
306                kes_signature_for_snark = if let Some(snark_kes_signature) =
307                    bytes.get(bytes_index..bytes_index + Sum6KesSig::SIZE)
308                {
309                    let snark_kes_signature = Sum6KesSig::from_bytes(snark_kes_signature)
310                        .map_err(|_| RegisterError::SerializationError)?;
311
312                    Some(snark_kes_signature)
313                } else {
314                    None
315                };
316            }
317        } else {
318            kes_signature_for_concatenation = None;
319            #[cfg(feature = "future_snark")]
320            {
321                kes_signature_for_snark = None;
322            }
323        }
324
325        Ok(Self {
326            stm_initializer,
327            kes_signature_for_concatenation,
328            #[cfg(feature = "future_snark")]
329            kes_signature_for_snark,
330        })
331    }
332}
333
334/// Parameters required for registering a signer with the key registration service.
335///
336/// Groups the verification keys, their KES signatures, and the operational certificate
337/// that together prove a signer's identity and authorization.
338#[derive(Debug, Clone)]
339pub struct SignerRegistrationParameters {
340    /// The party identifier of the signer
341    ///
342    /// Used only for testing when SPO pool id is not certified
343    pub party_id: Option<ProtocolPartyId>,
344
345    /// The operational certificate of the stake pool operator
346    ///
347    /// Used only for testing when SPO pool id is not certified
348    pub operational_certificate: Option<ProtocolOpCert>,
349
350    /// The verification key for the Concatenation proof system
351    pub verification_key_for_concatenation: ProtocolSignerVerificationKeyForConcatenation,
352
353    /// The KES signature over the verification key for Concatenation
354    ///
355    /// None is used only for testing when SPO pool id is not certified
356    pub verification_key_signature_for_concatenation:
357        Option<ProtocolSignerVerificationKeySignatureForConcatenation>,
358
359    /// The number of evolutions of the KES key since the start KES period of the
360    /// operational certificate at the time of signature
361    pub kes_evolutions: Option<KesEvolutions>,
362
363    /// The verification key for the SNARK proof system
364    #[cfg(feature = "future_snark")]
365    pub verification_key_for_snark: Option<ProtocolSignerVerificationKeyForSnark>,
366
367    /// The KES signature over the verification key for SNARK
368    #[cfg(feature = "future_snark")]
369    pub verification_key_signature_for_snark:
370        Option<ProtocolSignerVerificationKeySignatureForSnark>,
371}
372
373/// Wrapper structure for [MithrilStm:KeyRegistration](mithril_stm::key_reg::KeyRegistration).
374/// The wrapper not only contains a map between `Mithril vkey <-> Stake`, but also
375/// a map `PoolID <-> Stake`. This information is recovered from the node state, and
376/// is used to verify the identity of a Mithril signer. Furthermore, the `register` function
377/// of the wrapper forces the registrar to check that the KES signature over the Mithril key
378/// is valid with respect to the PoolID.
379#[derive(Debug, Clone)]
380pub struct KeyRegWrapper {
381    kes_verifier: Arc<dyn KesVerifier>,
382    stm_key_reg: KeyRegistration,
383    stake_distribution: HashMap<ProtocolPartyId, Stake>,
384}
385
386impl KeyRegWrapper {
387    /// New Initialisation function. We temporarily keep the other init function,
388    /// but we should eventually transition to only use this one.
389    pub fn init(stake_dist: &ProtocolStakeDistribution) -> Self {
390        Self {
391            kes_verifier: Arc::new(KesVerifierStandard),
392            stm_key_reg: KeyRegistration::initialize(),
393            stake_distribution: HashMap::from_iter(stake_dist.to_vec()),
394        }
395    }
396
397    /// Verify a KES signature over a message.
398    ///
399    /// Returns an error if the signature is missing or invalid.
400    fn verify_kes_signature(
401        &self,
402        message: &[u8],
403        kes_sig: Option<Sum6KesSig>,
404        opcert: &ProtocolOpCert,
405        kes_evolutions: KesEvolutions,
406    ) -> Result<(), ProtocolRegistrationErrorWrapper> {
407        let signature = kes_sig.ok_or(ProtocolRegistrationErrorWrapper::KesSignatureMissing)?;
408        self.kes_verifier
409            .verify(message, &signature, opcert, kes_evolutions)
410            .map_err(|e| {
411                ProtocolRegistrationErrorWrapper::KesSignatureInvalid(
412                    kes_evolutions,
413                    opcert.get_start_kes_period(),
414                    e,
415                )
416            })
417    }
418
419    /// Register a new party. For a successful registration, the registrar needs to
420    /// provide the OpCert (in cbor form), the cold VK, a KES signature, and a
421    /// Mithril key (with its corresponding Proof of Possession).
422    ///
423    /// When the `future_snark` feature is enabled, an optional Schnorr verification key
424    /// and its KES signature can be provided for SNARK proof system authentication.
425    pub fn register(
426        &mut self,
427        parameters: SignerRegistrationParameters,
428    ) -> StdResult<ProtocolPartyId> {
429        let pool_id_bech32: ProtocolPartyId =
430            if let Some(opcert) = &parameters.operational_certificate {
431                let kes_evolutions = parameters
432                    .kes_evolutions
433                    .ok_or(ProtocolRegistrationErrorWrapper::KesPeriodMissing)?;
434
435                self.verify_kes_signature(
436                    &parameters.verification_key_for_concatenation.to_bytes(),
437                    parameters
438                        .verification_key_signature_for_concatenation
439                        .map(|s| s.into_inner()),
440                    opcert,
441                    kes_evolutions,
442                )
443                .with_context(|| "invalid KES signature for Concatenation")?;
444
445                #[cfg(feature = "future_snark")]
446                if let Some(verification_key_for_snark) = &parameters.verification_key_for_snark {
447                    self.verify_kes_signature(
448                        &verification_key_for_snark.to_bytes(),
449                        parameters
450                            .verification_key_signature_for_snark
451                            .map(|s| s.into_inner()),
452                        opcert,
453                        kes_evolutions,
454                    )
455                    .with_context(|| "invalid KES signature for SNARK")?;
456                }
457
458                opcert
459                    .compute_protocol_party_id()
460                    .map_err(|_| ProtocolRegistrationErrorWrapper::PoolAddressEncoding)?
461            } else {
462                if cfg!(not(feature = "allow_skip_signer_certification")) {
463                    Err(ProtocolRegistrationErrorWrapper::OpCertMissing)?
464                }
465                parameters
466                    .party_id
467                    .ok_or(ProtocolRegistrationErrorWrapper::PartyIdMissing)?
468            };
469
470        if let Some(&stake) = self.stake_distribution.get(&pool_id_bech32) {
471            self.stm_key_reg.register(
472                stake,
473                &parameters.verification_key_for_concatenation.into(),
474                #[cfg(feature = "future_snark")]
475                parameters.verification_key_for_snark.map(|k| k.into()),
476            )?;
477            return Ok(pool_id_bech32);
478        }
479        Err(anyhow!(
480            ProtocolRegistrationErrorWrapper::PartyIdNonExisting
481        ))
482    }
483
484    /// Finalize the key registration.
485    /// This function disables `ClosedKeyRegistration::register`, consumes the instance of `self`, and returns a `ClosedKeyRegistration`.
486    pub fn close(self, protocol_params: &ProtocolParameters) -> StdResult<ClosedKeyRegistration> {
487        self.stm_key_reg.close_registration(protocol_params)
488    }
489}
490
491mod test_extensions {
492    use crate::test::crypto_helper::ProtocolInitializerTestExtension;
493
494    use super::*;
495
496    impl ProtocolInitializerTestExtension for StmInitializerWrapper {
497        fn override_protocol_parameters(&mut self, protocol_parameters: &ProtocolParameters) {
498            self.stm_initializer.parameters = protocol_parameters.to_owned();
499        }
500    }
501}
502
503#[cfg(test)]
504mod test {
505    use crate::crypto_helper::cardano::kes::KesSignerStandard;
506    use crate::crypto_helper::{OpCert, SerDeShelleyFileFormat};
507    use crate::test::crypto_helper::{
508        KesCryptographicMaterialForTest, KesPartyIndexForTest, create_kes_cryptographic_material,
509    };
510
511    use rand_chacha::ChaCha20Rng;
512    use rand_core::SeedableRng;
513
514    use super::*;
515
516    #[test]
517    fn test_vector_key_reg() {
518        let params = Parameters {
519            m: 5,
520            k: 5,
521            phi_f: 1.0,
522        };
523        let mut rng = ChaCha20Rng::from_seed([0u8; 32]);
524        let KesCryptographicMaterialForTest {
525            party_id: party_id_1,
526            operational_certificate_file: operational_certificate_file_1,
527            kes_secret_key_file: kes_secret_key_file_1,
528        } = create_kes_cryptographic_material(
529            1 as KesPartyIndexForTest,
530            KesPeriod(0),
531            "test_vector_key_reg",
532        );
533        let KesCryptographicMaterialForTest {
534            party_id: party_id_2,
535            operational_certificate_file: operational_certificate_file_2,
536            kes_secret_key_file: kes_secret_key_file_2,
537        } = create_kes_cryptographic_material(
538            2 as KesPartyIndexForTest,
539            KesPeriod(0),
540            "test_vector_key_reg",
541        );
542
543        let mut key_reg = KeyRegWrapper::init(&vec![(party_id_1, 10), (party_id_2, 3)]);
544
545        let initializer_1 = StmInitializerWrapper::setup(
546            params,
547            Some(Arc::new(KesSignerStandard::new(
548                kes_secret_key_file_1,
549                operational_certificate_file_1.clone(),
550            ))),
551            Some(KesPeriod(0)),
552            10,
553            &mut rng,
554        )
555        .unwrap();
556
557        let opcert1 = OpCert::from_file(operational_certificate_file_1)
558            .expect("opcert deserialization should not fail")
559            .into();
560
561        let key_registration_1 = key_reg.register(SignerRegistrationParameters {
562            party_id: None,
563            operational_certificate: Some(opcert1),
564            verification_key_signature_for_concatenation: initializer_1
565                .verification_key_signature_for_concatenation(),
566            kes_evolutions: Some(KesEvolutions(0)),
567            verification_key_for_concatenation: initializer_1
568                .stm_initializer
569                .get_verification_key_proof_of_possession_for_concatenation()
570                .into(),
571            #[cfg(feature = "future_snark")]
572            verification_key_for_snark: initializer_1.verification_key_for_snark().map(Into::into),
573            #[cfg(feature = "future_snark")]
574            verification_key_signature_for_snark: initializer_1
575                .verification_key_signature_for_snark(),
576        });
577        assert!(key_registration_1.is_ok());
578
579        let initializer_2 = StmInitializerWrapper::setup(
580            params,
581            Some(Arc::new(KesSignerStandard::new(
582                kes_secret_key_file_2,
583                operational_certificate_file_2.clone(),
584            ))),
585            Some(KesPeriod(0)),
586            10,
587            &mut rng,
588        )
589        .unwrap();
590
591        let opcert2 = OpCert::from_file(operational_certificate_file_2)
592            .expect("opcert deserialization should not fail")
593            .into();
594
595        let key_registration_2 = key_reg.register(SignerRegistrationParameters {
596            party_id: None,
597            operational_certificate: Some(opcert2),
598            verification_key_signature_for_concatenation: initializer_2
599                .verification_key_signature_for_concatenation(),
600            kes_evolutions: Some(KesEvolutions(0)),
601            verification_key_for_concatenation: initializer_2
602                .stm_initializer
603                .get_verification_key_proof_of_possession_for_concatenation()
604                .into(),
605            #[cfg(feature = "future_snark")]
606            verification_key_for_snark: initializer_2.verification_key_for_snark().map(Into::into),
607            #[cfg(feature = "future_snark")]
608            verification_key_signature_for_snark: initializer_2
609                .verification_key_signature_for_snark(),
610        });
611        assert!(key_registration_2.is_ok())
612    }
613
614    const GOLDEN_STM_INITIALIZER_WRAPPER_JSON: &str = r#"
615    {
616        "stm_initializer": {
617            "stake": 9497432569,
618            "params": {
619                "m": 20973,
620                "k": 2422,
621                "phi_f": 0.2
622            },
623            "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],
624            "pk": {
625                "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],
626                "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]
627            }
628        },
629        "kes_signature": {
630            "sigma": {
631                "sigma": {
632                    "sigma": {
633                        "sigma": {
634                            "sigma": {
635                                "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],
636                                "lhs_pk": [
637                                    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],
638                                    "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]
639                                    },
640                            "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],
641                            "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]
642                        },
643                        "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],
644                        "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]
645                    },
646                    "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],
647                    "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]
648                },
649                "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],
650                "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]
651            },
652            "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],
653            "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]
654        }
655    }
656    "#;
657
658    #[test]
659    fn golden_initializer_deserialization() {
660        let _: StmInitializerWrapper = serde_json::from_str(GOLDEN_STM_INITIALIZER_WRAPPER_JSON)
661            .expect("Deserializing a StmInitializerWrapper should not fail");
662    }
663
664    #[test]
665    fn test_initializer_wrapper_conversions() {
666        let stm_initializer_wrapper_json = GOLDEN_STM_INITIALIZER_WRAPPER_JSON;
667
668        let stm_initializer_wrapper_from_json: StmInitializerWrapper =
669            serde_json::from_str(stm_initializer_wrapper_json)
670                .expect("Deserializing a StmInitializerWrapper should not fail");
671        let stm_initializer_wrapper_from_json_to_json =
672            serde_json::to_string(&stm_initializer_wrapper_from_json)
673                .expect("Serializing a StmInitializerWrapper to json should not fail");
674
675        let stm_initializer_wrapper_bytes = stm_initializer_wrapper_from_json
676            .to_bytes()
677            .expect("Serializing a StmInitializerWrapper to bytes should not fail");
678        let stm_initializer_wrapper_from_bytes =
679            StmInitializerWrapper::from_bytes(&stm_initializer_wrapper_bytes)
680                .expect("Deserializing a StmInitializerWrapper from bytes should not fail");
681        let stm_initializer_wrapper_from_bytes_to_json =
682            serde_json::to_string(&stm_initializer_wrapper_from_bytes)
683                .expect("Serializing a StmInitializerWrapper to json should not fail");
684
685        assert_eq!(
686            stm_initializer_wrapper_from_json_to_json,
687            stm_initializer_wrapper_from_bytes_to_json
688        );
689
690        let mut stm_initializer_wrapper_from_json = stm_initializer_wrapper_from_json;
691        stm_initializer_wrapper_from_json.kes_signature_for_concatenation = None;
692
693        let stm_initializer_wrapper_bytes = stm_initializer_wrapper_from_json
694            .to_bytes()
695            .expect("Serializing a StmInitializerWrapper to bytes should not fail");
696        let stm_initializer_wrapper_from_bytes =
697            StmInitializerWrapper::from_bytes(&stm_initializer_wrapper_bytes)
698                .expect("Deserializing a StmInitializerWrapper from bytes should not fail");
699        assert_eq!(
700            None,
701            stm_initializer_wrapper_from_bytes.kes_signature_for_concatenation
702        );
703    }
704}