mithril_stm/protocol/participant/
initializer.rs

1use anyhow::anyhow;
2use rand_core::{CryptoRng, RngCore};
3use serde::{Deserialize, Serialize};
4
5use crate::{
6    ClosedKeyRegistration, MembershipDigest, Parameters, RegisterError, Stake, StmResult,
7    signature_scheme::{BlsSigningKey, BlsVerificationKeyProofOfPossession},
8};
9
10use super::Signer;
11
12/// Wrapper of the MultiSignature Verification key with proof of possession
13pub type VerificationKeyProofOfPossession = BlsVerificationKeyProofOfPossession;
14
15/// Initializer for `Signer`.
16/// This is the data that is used during the key registration procedure.
17/// Once the latter is finished, this instance is consumed into an `Signer`.
18#[derive(Debug, Clone, Serialize, Deserialize)]
19pub struct Initializer {
20    /// This participant's stake.
21    pub stake: Stake,
22    /// Current protocol instantiation parameters.
23    pub params: Parameters,
24    /// Secret key.
25    pub(crate) sk: BlsSigningKey,
26    /// Verification (public) key + proof of possession.
27    pub(crate) pk: VerificationKeyProofOfPossession,
28}
29
30impl Initializer {
31    /// Builds an `Initializer` that is ready to register with the key registration service.
32    /// This function generates the signing and verification key with a PoP, and initialises the structure.
33    pub fn new<R: RngCore + CryptoRng>(params: Parameters, stake: Stake, rng: &mut R) -> Self {
34        let sk = BlsSigningKey::generate(rng);
35        let pk = VerificationKeyProofOfPossession::from(&sk);
36        Self {
37            stake,
38            params,
39            sk,
40            pk,
41        }
42    }
43
44    /// Extract the verification key with proof of possession.
45    pub fn get_verification_key_proof_of_possession(&self) -> VerificationKeyProofOfPossession {
46        self.pk
47    }
48
49    /// Build the `avk` for the given list of parties.
50    ///
51    /// Note that if this Initializer was modified *between* the last call to `register`,
52    /// then the resulting `Signer` may not be able to produce valid signatures.
53    ///
54    /// Returns an `Signer` specialized to
55    /// * this `Signer`'s ID and current stake
56    /// * this `Signer`'s parameter valuation
57    /// * the `avk` as built from the current registered parties (according to the registration service)
58    /// * the current total stake (according to the registration service)
59    /// # Error
60    /// This function fails if the initializer is not registered.
61    pub fn create_signer<D: MembershipDigest>(
62        self,
63        closed_reg: ClosedKeyRegistration<D>,
64    ) -> StmResult<Signer<D>> {
65        let mut my_index = None;
66        for (i, rp) in closed_reg.reg_parties.iter().enumerate() {
67            if rp.0 == self.pk.vk {
68                my_index = Some(i as u64);
69                break;
70            }
71        }
72        if my_index.is_none() {
73            return Err(anyhow!(RegisterError::UnregisteredInitializer));
74        }
75
76        Ok(Signer::set_signer(
77            my_index.unwrap(),
78            self.stake,
79            self.params,
80            self.sk,
81            self.pk.vk,
82            closed_reg,
83        ))
84    }
85
86    /// Convert to bytes
87    /// # Layout
88    /// * Stake (u64)
89    /// * Params
90    /// * Secret Key
91    /// * Public key (including PoP)
92    pub fn to_bytes(&self) -> [u8; 256] {
93        let mut out = [0u8; 256];
94        out[..8].copy_from_slice(&self.stake.to_be_bytes());
95        out[8..32].copy_from_slice(&self.params.to_bytes());
96        out[32..64].copy_from_slice(&self.sk.to_bytes());
97        out[64..].copy_from_slice(&self.pk.to_bytes());
98        out
99    }
100
101    /// Convert a slice of bytes to an `Initializer`
102    /// # Error
103    /// The function fails if the given string of bytes is not of required size.
104    pub fn from_bytes(bytes: &[u8]) -> StmResult<Initializer> {
105        let mut u64_bytes = [0u8; 8];
106        u64_bytes.copy_from_slice(bytes.get(..8).ok_or(RegisterError::SerializationError)?);
107        let stake = u64::from_be_bytes(u64_bytes);
108        let params =
109            Parameters::from_bytes(bytes.get(8..32).ok_or(RegisterError::SerializationError)?)?;
110        let sk =
111            BlsSigningKey::from_bytes(bytes.get(32..).ok_or(RegisterError::SerializationError)?)?;
112        let pk = VerificationKeyProofOfPossession::from_bytes(
113            bytes.get(64..).ok_or(RegisterError::SerializationError)?,
114        )?;
115
116        Ok(Self {
117            stake,
118            params,
119            sk,
120            pk,
121        })
122    }
123}
124
125impl PartialEq for Initializer {
126    fn eq(&self, other: &Self) -> bool {
127        self.stake == other.stake
128            && self.params == other.params
129            && self.sk.to_bytes() == other.sk.to_bytes()
130            && self.get_verification_key_proof_of_possession()
131                == other.get_verification_key_proof_of_possession()
132    }
133}
134
135#[cfg(test)]
136mod tests {
137    use super::*;
138
139    mod golden {
140        use rand_chacha::ChaCha20Rng;
141        use rand_core::SeedableRng;
142
143        use super::*;
144
145        const GOLDEN_JSON: &str = r#"
146            {
147                "stake":1,
148                "params":
149                {
150                    "m":20973,
151                    "k":2422,
152                    "phi_f":0.2
153                },
154                "sk":[64,129,87,121,27,239,221,215,2,103,45,207,207,201,157,163,81,47,156,14,168,24,137,15,203,106,183,73,88,14,242,207],
155                "pk":
156                {
157                    "vk":[143,161,255,48,78,57,204,220,25,221,164,252,248,14,56,126,186,135,228,188,145,181,52,200,97,99,213,46,0,199,193,89,187,88,29,135,173,244,86,36,83,54,67,164,6,137,94,72,6,105,128,128,93,48,176,11,4,246,138,48,180,133,90,142,192,24,193,111,142,31,76,111,110,234,153,90,208,192,31,124,95,102,49,158,99,52,220,165,94,251,68,69,121,16,224,194],
158                    "pop":[168,50,233,193,15,136,65,72,123,148,129,176,38,198,209,47,28,204,176,144,57,251,42,28,66,76,89,97,158,63,54,198,194,176,135,221,14,185,197,225,202,98,243,74,233,225,143,151,147,177,170,117,66,165,66,62,33,216,232,75,68,114,195,22,100,65,44,198,4,166,102,233,253,240,59,175,60,117,142,114,140,122,17,87,110,187,1,17,10,195,154,13,249,86,54,226]
159                }
160            }
161        "#;
162
163        fn golden_value() -> Initializer {
164            let mut rng = ChaCha20Rng::from_seed([0u8; 32]);
165            let sk = BlsSigningKey::generate(&mut rng);
166            let pk = BlsVerificationKeyProofOfPossession::from(&sk);
167            Initializer {
168                stake: 1,
169                params: Parameters {
170                    m: 20973,
171                    k: 2422,
172                    phi_f: 0.2,
173                },
174                sk,
175                pk,
176            }
177        }
178
179        #[test]
180        fn golden_conversions() {
181            let value = serde_json::from_str(GOLDEN_JSON)
182                .expect("This JSON deserialization should not fail");
183            assert_eq!(golden_value(), value);
184
185            let serialized =
186                serde_json::to_string(&value).expect("This JSON serialization should not fail");
187            let golden_serialized = serde_json::to_string(&golden_value())
188                .expect("This JSON serialization should not fail");
189            assert_eq!(golden_serialized, serialized);
190        }
191    }
192}