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#[cfg(feature = "future_snark")]
12use crate::{VerificationKeyForSnark, signature_scheme::SchnorrSigningKey};
13
14use super::Signer;
15
16#[derive(Debug, Clone, Serialize, Deserialize)]
18pub struct Initializer {
19 pub stake: Stake,
21 #[serde(rename = "params")]
23 pub parameters: Parameters,
24 #[serde(rename = "sk")]
26 pub bls_signing_key: BlsSigningKey,
27 #[serde(rename = "pk")]
29 pub bls_verification_key_proof_of_possession: VerificationKeyProofOfPossessionForConcatenation,
30 #[cfg(feature = "future_snark")]
32 #[serde(skip_serializing_if = "Option::is_none")]
33 pub schnorr_signing_key: Option<SchnorrSigningKey>,
34 #[cfg(feature = "future_snark")]
36 #[serde(skip_serializing_if = "Option::is_none")]
37 pub schnorr_verification_key: Option<VerificationKeyForSnark>,
38}
39
40impl Initializer {
41 pub fn new<R: RngCore + CryptoRng>(parameters: Parameters, stake: Stake, rng: &mut R) -> Self {
43 let bls_signing_key = BlsSigningKey::generate(rng);
44 let bls_verification_key_proof_of_possession =
45 VerificationKeyProofOfPossessionForConcatenation::from(&bls_signing_key);
46 #[cfg(feature = "future_snark")]
47 let (schnorr_signing_key, schnorr_verification_key) = {
48 let sk = SchnorrSigningKey::generate(rng);
49 let vk = VerificationKeyForSnark::new_from_signing_key(sk.clone());
50 (Some(sk), Some(vk))
51 };
52 Self {
53 stake,
54 parameters,
55 bls_signing_key,
56 bls_verification_key_proof_of_possession,
57 #[cfg(feature = "future_snark")]
58 schnorr_signing_key,
59 #[cfg(feature = "future_snark")]
60 schnorr_verification_key,
61 }
62 }
63
64 pub fn try_create_signer<D: MembershipDigest>(
77 self,
78 closed_key_registration: &ClosedKeyRegistration,
79 ) -> StmResult<Signer<D>> {
80 let registration_entry = RegistrationEntry::new(
81 self.bls_verification_key_proof_of_possession,
82 self.stake,
83 #[cfg(feature = "future_snark")]
84 self.schnorr_verification_key,
85 )?;
86
87 let signer_index = closed_key_registration
88 .get_signer_index_for_registration(
89 &(registration_entry, closed_key_registration.total_stake).into(),
90 )
91 .ok_or_else(|| anyhow!(RegisterError::UnregisteredInitializer))?;
92
93 let key_registration_commitment = closed_key_registration
94 .to_merkle_tree::<D::ConcatenationHash, RegistrationEntryForConcatenation>();
95
96 let concatenation_proof_signer = ConcatenationProofSigner::new(
98 registration_entry.get_stake(),
99 closed_key_registration.total_stake,
100 self.parameters,
101 self.bls_signing_key,
102 self.bls_verification_key_proof_of_possession.vk,
103 key_registration_commitment,
104 );
105
106 Ok(Signer::new(
108 signer_index,
109 concatenation_proof_signer,
110 closed_key_registration.clone(),
111 self.parameters,
112 registration_entry.get_stake(),
113 ))
114 }
115
116 pub fn get_verification_key_proof_of_possession_for_concatenation(
118 &self,
119 ) -> VerificationKeyProofOfPossessionForConcatenation {
120 self.bls_verification_key_proof_of_possession
121 }
122
123 #[cfg(feature = "future_snark")]
125 pub fn get_verification_key_for_snark(&self) -> Option<VerificationKeyForSnark> {
126 self.schnorr_verification_key
127 }
128
129 pub fn to_bytes(&self) -> Vec<u8> {
138 let capacity = if cfg!(feature = "future_snark") {
139 352
140 } else {
141 256
142 };
143 let mut out = Vec::with_capacity(capacity);
144 out.extend_from_slice(&self.stake.to_be_bytes());
145 out.extend_from_slice(&self.parameters.to_bytes());
146 out.extend_from_slice(&self.bls_signing_key.to_bytes());
147 out.extend_from_slice(&self.bls_verification_key_proof_of_possession.to_bytes());
148
149 #[cfg(feature = "future_snark")]
150 if let (Some(schnorr_sk), Some(schnorr_vk)) =
151 (&self.schnorr_signing_key, &self.schnorr_verification_key)
152 {
153 out.extend_from_slice(&schnorr_sk.to_bytes());
154 out.extend_from_slice(&schnorr_vk.to_bytes());
155 }
156
157 out
158 }
159
160 pub fn from_bytes(bytes: &[u8]) -> StmResult<Initializer> {
164 let mut u64_bytes = [0u8; 8];
165 u64_bytes.copy_from_slice(bytes.get(..8).ok_or(RegisterError::SerializationError)?);
166 let stake = u64::from_be_bytes(u64_bytes);
167 let params =
168 Parameters::from_bytes(bytes.get(8..32).ok_or(RegisterError::SerializationError)?)?;
169 let bls_signing_key =
170 BlsSigningKey::from_bytes(bytes.get(32..64).ok_or(RegisterError::SerializationError)?)?;
171 let bls_verification_key_proof_of_possession =
172 VerificationKeyProofOfPossessionForConcatenation::from_bytes(
173 bytes.get(64..256).ok_or(RegisterError::SerializationError)?,
174 )?;
175
176 #[cfg(feature = "future_snark")]
177 let (schnorr_signing_key, schnorr_verification_key) = {
178 let schnorr_signing_key =
179 bytes.get(256..288).map(SchnorrSigningKey::from_bytes).transpose()?;
180 let schnorr_verification_key = bytes
181 .get(288..352)
182 .map(VerificationKeyForSnark::from_bytes)
183 .transpose()?;
184
185 match (&schnorr_signing_key, &schnorr_verification_key) {
186 (Some(_), None) | (None, Some(_)) => {
187 return Err(RegisterError::SerializationError.into());
188 }
189 _ => {}
190 }
191 (schnorr_signing_key, schnorr_verification_key)
192 };
193
194 Ok(Self {
195 stake,
196 parameters: params,
197 bls_signing_key,
198 bls_verification_key_proof_of_possession,
199 #[cfg(feature = "future_snark")]
200 schnorr_signing_key,
201 #[cfg(feature = "future_snark")]
202 schnorr_verification_key,
203 })
204 }
205}
206
207impl PartialEq for Initializer {
208 fn eq(&self, other: &Self) -> bool {
209 let base_eq = self.stake == other.stake
210 && self.parameters == other.parameters
211 && self.bls_signing_key.to_bytes() == other.bls_signing_key.to_bytes()
212 && self.get_verification_key_proof_of_possession_for_concatenation()
213 == other.get_verification_key_proof_of_possession_for_concatenation();
214
215 #[cfg(feature = "future_snark")]
216 let base_eq = base_eq
217 && self.schnorr_signing_key == other.schnorr_signing_key
218 && self.schnorr_verification_key == other.schnorr_verification_key;
219
220 base_eq
221 }
222}
223
224#[cfg(test)]
225mod tests {
226 use super::*;
227
228 mod golden {
229 use rand_chacha::ChaCha20Rng;
230 use rand_core::SeedableRng;
231
232 use super::*;
233
234 const GOLDEN_JSON: &str = r#"
235 {
236 "stake":1,
237 "params":
238 {
239 "m":20973,
240 "k":2422,
241 "phi_f":0.2
242 },
243 "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],
244 "pk":
245 {
246 "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],
247 "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]
248 }
249 }
250 "#;
251
252 fn golden_value() -> Initializer {
253 let mut rng = ChaCha20Rng::from_seed([0u8; 32]);
254 let sk = BlsSigningKey::generate(&mut rng);
255 let pk = VerificationKeyProofOfPossessionForConcatenation::from(&sk);
256 Initializer {
257 stake: 1,
258 parameters: Parameters {
259 m: 20973,
260 k: 2422,
261 phi_f: 0.2,
262 },
263 bls_signing_key: sk,
264 bls_verification_key_proof_of_possession: pk,
265 #[cfg(feature = "future_snark")]
266 schnorr_signing_key: None,
267 #[cfg(feature = "future_snark")]
268 schnorr_verification_key: None,
269 }
270 }
271
272 #[test]
273 fn golden_conversions() {
274 let value = serde_json::from_str(GOLDEN_JSON)
275 .expect("This JSON deserialization should not fail");
276 assert_eq!(golden_value(), value);
277
278 let serialized =
279 serde_json::to_string(&value).expect("This JSON serialization should not fail");
280 let golden_serialized = serde_json::to_string(&golden_value())
281 .expect("This JSON serialization should not fail");
282 assert_eq!(golden_serialized, serialized);
283 }
284 }
285}