1use anyhow::anyhow;
2use rand_core::{CryptoRng, RngCore};
3use serde::{Deserialize, Serialize};
4
5use crate::{
6 ClosedKeyRegistration, MembershipDigest, Parameters, RegisterError, RegistrationEntry,
7 RegistrationEntryForConcatenation, Stake, StmResult,
8 VerificationKeyProofOfPossessionForConcatenation, proof_system::ConcatenationProofSigner,
9 signature_scheme::BlsSigningKey,
10};
11
12use super::Signer;
13
14#[derive(Debug, Clone, Serialize, Deserialize)]
16pub struct Initializer {
17 pub stake: Stake,
19 #[serde(rename = "params")]
21 pub parameters: Parameters,
22 #[serde(rename = "sk")]
24 pub bls_signing_key: BlsSigningKey,
25 #[serde(rename = "pk")]
27 pub bls_verification_key_proof_of_possession: VerificationKeyProofOfPossessionForConcatenation,
28}
29
30impl Initializer {
31 pub fn new<R: RngCore + CryptoRng>(parameters: Parameters, stake: Stake, rng: &mut R) -> Self {
33 let bls_signing_key = BlsSigningKey::generate(rng);
34 let bls_verification_key_proof_of_possession =
35 VerificationKeyProofOfPossessionForConcatenation::from(&bls_signing_key);
36 Self {
37 stake,
38 parameters,
39 bls_signing_key,
40 bls_verification_key_proof_of_possession,
41 }
42 }
43
44 pub fn try_create_signer<D: MembershipDigest>(
57 self,
58 closed_key_registration: &ClosedKeyRegistration,
59 ) -> StmResult<Signer<D>> {
60 let registration_entry =
61 RegistrationEntry::new(self.bls_verification_key_proof_of_possession, self.stake)?;
62
63 let signer_index = match closed_key_registration
64 .key_registration
65 .get_signer_index_for_registration(®istration_entry)
66 {
67 Some(index) => index,
68 None => return Err(anyhow!(RegisterError::UnregisteredInitializer)),
69 };
70
71 let key_registration_commitment = closed_key_registration
72 .key_registration
73 .into_merkle_tree::<D::ConcatenationHash, RegistrationEntryForConcatenation>(
74 );
75
76 let concatenation_proof_signer = ConcatenationProofSigner::new(
78 registration_entry.get_stake(),
79 closed_key_registration.total_stake,
80 self.parameters,
81 self.bls_signing_key,
82 self.bls_verification_key_proof_of_possession.vk,
83 key_registration_commitment,
84 );
85
86 Ok(Signer::new(
88 signer_index,
89 concatenation_proof_signer,
90 closed_key_registration.clone(),
91 self.parameters,
92 registration_entry.get_stake(),
93 ))
94 }
95
96 pub fn get_verification_key_proof_of_possession_for_concatenation(
98 &self,
99 ) -> VerificationKeyProofOfPossessionForConcatenation {
100 self.bls_verification_key_proof_of_possession
101 }
102
103 pub fn to_bytes(&self) -> [u8; 256] {
110 let mut out = [0u8; 256];
111 out[..8].copy_from_slice(&self.stake.to_be_bytes());
112 out[8..32].copy_from_slice(&self.parameters.to_bytes());
113 out[32..64].copy_from_slice(&self.bls_signing_key.to_bytes());
114 out[64..].copy_from_slice(&self.bls_verification_key_proof_of_possession.to_bytes());
115 out
116 }
117
118 pub fn from_bytes(bytes: &[u8]) -> StmResult<Initializer> {
122 let mut u64_bytes = [0u8; 8];
123 u64_bytes.copy_from_slice(bytes.get(..8).ok_or(RegisterError::SerializationError)?);
124 let stake = u64::from_be_bytes(u64_bytes);
125 let params =
126 Parameters::from_bytes(bytes.get(8..32).ok_or(RegisterError::SerializationError)?)?;
127 let sk =
128 BlsSigningKey::from_bytes(bytes.get(32..).ok_or(RegisterError::SerializationError)?)?;
129 let pk = VerificationKeyProofOfPossessionForConcatenation::from_bytes(
130 bytes.get(64..).ok_or(RegisterError::SerializationError)?,
131 )?;
132
133 Ok(Self {
134 stake,
135 parameters: params,
136 bls_signing_key: sk,
137 bls_verification_key_proof_of_possession: pk,
138 })
139 }
140}
141
142impl PartialEq for Initializer {
143 fn eq(&self, other: &Self) -> bool {
144 self.stake == other.stake
145 && self.parameters == other.parameters
146 && self.bls_signing_key.to_bytes() == other.bls_signing_key.to_bytes()
147 && self.get_verification_key_proof_of_possession_for_concatenation()
148 == other.get_verification_key_proof_of_possession_for_concatenation()
149 }
150}
151
152#[cfg(test)]
153mod tests {
154 use super::*;
155
156 mod golden {
157 use rand_chacha::ChaCha20Rng;
158 use rand_core::SeedableRng;
159
160 use super::*;
161
162 const GOLDEN_JSON: &str = r#"
163 {
164 "stake":1,
165 "params":
166 {
167 "m":20973,
168 "k":2422,
169 "phi_f":0.2
170 },
171 "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],
172 "pk":
173 {
174 "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],
175 "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]
176 }
177 }
178 "#;
179
180 fn golden_value() -> Initializer {
181 let mut rng = ChaCha20Rng::from_seed([0u8; 32]);
182 let sk = BlsSigningKey::generate(&mut rng);
183 let pk = VerificationKeyProofOfPossessionForConcatenation::from(&sk);
184 Initializer {
185 stake: 1,
186 parameters: Parameters {
187 m: 20973,
188 k: 2422,
189 phi_f: 0.2,
190 },
191 bls_signing_key: sk,
192 bls_verification_key_proof_of_possession: pk,
193 }
194 }
195
196 #[test]
197 fn golden_conversions() {
198 let value = serde_json::from_str(GOLDEN_JSON)
199 .expect("This JSON deserialization should not fail");
200 assert_eq!(golden_value(), value);
201
202 let serialized =
203 serde_json::to_string(&value).expect("This JSON serialization should not fail");
204 let golden_serialized = serde_json::to_string(&golden_value())
205 .expect("This JSON serialization should not fail");
206 assert_eq!(golden_serialized, serialized);
207 }
208 }
209}