nym_compact_ecash/scheme/
keygen.rs1use crate::error::{CompactEcashError, Result};
5use crate::scheme::aggregation::aggregate_verification_keys;
6use crate::scheme::SignerIndex;
7use crate::traits::Bytable;
8use crate::utils::{hash_to_scalar, Polynomial};
9use crate::utils::{
10 try_deserialize_g1_projective, try_deserialize_g2_projective, try_deserialize_scalar,
11 try_deserialize_scalar_vec,
12};
13use crate::{ecash_group_parameters, Base58};
14use core::borrow::Borrow;
15use core::iter::Sum;
16use core::ops::{Add, Mul};
17use group::{Curve, GroupEncoding};
18use nym_bls12_381_fork::{G1Projective, G2Projective, Scalar};
19use nym_pemstore::traits::{PemStorableKey, PemStorableKeyPair};
20use serde::{Deserialize, Serialize};
21use zeroize::{Zeroize, ZeroizeOnDrop};
22
23#[derive(Debug, PartialEq, Clone, Zeroize, ZeroizeOnDrop)]
24pub struct SecretKeyAuth {
25 pub(crate) x: Scalar,
26 pub(crate) ys: Vec<Scalar>,
27}
28
29impl PemStorableKey for SecretKeyAuth {
30 type Error = CompactEcashError;
31
32 fn pem_type() -> &'static str {
33 "ECASH SECRET KEY"
34 }
35
36 fn to_bytes(&self) -> Vec<u8> {
37 self.to_bytes()
38 }
39
40 fn from_bytes(bytes: &[u8]) -> std::result::Result<Self, Self::Error> {
41 Self::from_bytes(bytes)
42 }
43}
44
45impl TryFrom<&[u8]> for SecretKeyAuth {
46 type Error = CompactEcashError;
47
48 fn try_from(bytes: &[u8]) -> Result<SecretKeyAuth> {
49 if bytes.len() < 32 * 2 + 8 || !(bytes.len() - 8).is_multiple_of(32) {
51 return Err(CompactEcashError::DeserializationInvalidLength {
52 actual: bytes.len(),
53 modulus_target: bytes.len() - 8,
54 target: 32 * 2 + 8,
55 modulus: 32,
56 object: "secret key".to_string(),
57 });
58 }
59
60 #[allow(clippy::unwrap_used)]
62 #[allow(clippy::indexing_slicing)]
63 let x_bytes: [u8; 32] = bytes[..32].try_into().unwrap();
64
65 #[allow(clippy::unwrap_used)]
66 #[allow(clippy::indexing_slicing)]
67 let ys_len = u64::from_le_bytes(bytes[32..40].try_into().unwrap());
68 let actual_ys_len = (bytes.len() - 40) / 32;
69
70 if ys_len as usize != actual_ys_len {
71 return Err(CompactEcashError::DeserializationLengthMismatch {
72 type_name: "Secret_key ys".into(),
73 expected: ys_len as usize,
74 actual: actual_ys_len,
75 });
76 }
77
78 let x = try_deserialize_scalar(&x_bytes)?;
79 #[allow(clippy::indexing_slicing)]
80 let ys = try_deserialize_scalar_vec(ys_len, &bytes[40..])?;
81
82 Ok(SecretKeyAuth { x, ys })
83 }
84}
85
86impl SecretKeyAuth {
87 pub fn create_from_raw(x: Scalar, ys: Vec<Scalar>) -> Self {
90 Self { x, ys }
91 }
92
93 pub fn hazmat_to_raw(&self) -> (Scalar, Vec<Scalar>) {
96 (self.x, self.ys.clone())
97 }
98
99 pub fn size(&self) -> usize {
100 self.ys.len()
101 }
102
103 pub fn verification_key(&self) -> VerificationKeyAuth {
104 let params = ecash_group_parameters();
105 let g1 = params.gen1();
106 let g2 = params.gen2();
107 VerificationKeyAuth {
108 alpha: g2 * self.x,
109 beta_g1: self.ys.iter().map(|y| g1 * y).collect(),
110 beta_g2: self.ys.iter().map(|y| g2 * y).collect(),
111 }
112 }
113
114 pub fn to_bytes(&self) -> Vec<u8> {
115 let ys_len = self.ys.len();
116 let mut bytes = Vec::with_capacity(8 + (ys_len + 1) * 32);
117 bytes.extend_from_slice(&self.x.to_bytes());
118 bytes.extend_from_slice(&(ys_len as u64).to_le_bytes());
119 for y in self.ys.iter() {
120 bytes.extend_from_slice(&y.to_bytes())
121 }
122 bytes
123 }
124
125 pub fn from_bytes(bytes: &[u8]) -> Result<SecretKeyAuth> {
126 SecretKeyAuth::try_from(bytes)
127 }
128}
129
130#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
131pub struct VerificationKeyAuth {
132 pub(crate) alpha: G2Projective,
133 pub(crate) beta_g1: Vec<G1Projective>,
134 pub(crate) beta_g2: Vec<G2Projective>,
135}
136
137impl PemStorableKey for VerificationKeyAuth {
138 type Error = CompactEcashError;
139
140 fn pem_type() -> &'static str {
141 "ECASH VERIFICATION KEY"
142 }
143
144 fn to_bytes(&self) -> Vec<u8> {
145 self.to_bytes()
146 }
147
148 fn from_bytes(bytes: &[u8]) -> std::result::Result<Self, Self::Error> {
149 Self::from_bytes(bytes)
150 }
151}
152
153impl TryFrom<&[u8]> for VerificationKeyAuth {
154 type Error = CompactEcashError;
155
156 fn try_from(bytes: &[u8]) -> Result<VerificationKeyAuth> {
157 if bytes.len() < 96 * 2 + 48 + 8 || !(bytes.len() - 8 - 96).is_multiple_of(96 + 48) {
159 return Err(CompactEcashError::DeserializationInvalidLength {
160 actual: bytes.len(),
161 modulus_target: bytes.len() - 8 - 96,
162 target: 96 * 2 + 48 + 8,
163 modulus: 96 + 48,
164 object: "verification key".to_string(),
165 });
166 }
167
168 #[allow(clippy::unwrap_used)]
170 #[allow(clippy::indexing_slicing)]
171 let alpha_bytes: [u8; 96] = bytes[..96].try_into().unwrap();
172 #[allow(clippy::unwrap_used)]
173 #[allow(clippy::indexing_slicing)]
174 let betas_len = u64::from_le_bytes(bytes[96..104].try_into().unwrap());
175
176 let actual_betas_len = (bytes.len() - 104) / (96 + 48);
177
178 if betas_len as usize != actual_betas_len {
179 return Err(CompactEcashError::DeserializationLengthMismatch {
180 type_name: "Verification_key betas".into(),
181 expected: betas_len as usize,
182 actual: actual_betas_len,
183 });
184 }
185
186 let alpha = try_deserialize_g2_projective(&alpha_bytes)?;
187
188 let mut beta_g1 = Vec::with_capacity(betas_len as usize);
189 let mut beta_g1_end: u64 = 0;
190 for i in 0..betas_len {
191 let start = (104 + i * 48) as usize;
192 let end = start + 48;
193 #[allow(clippy::unwrap_used)]
195 #[allow(clippy::indexing_slicing)]
196 let beta_i_bytes = bytes[start..end].try_into().unwrap();
197 let beta_i = try_deserialize_g1_projective(&beta_i_bytes)?;
198
199 beta_g1_end = end as u64;
200 beta_g1.push(beta_i)
201 }
202
203 let mut beta_g2 = Vec::with_capacity(betas_len as usize);
204 for i in 0..betas_len {
205 let start = (beta_g1_end + i * 96) as usize;
206 let end = start + 96;
207 #[allow(clippy::unwrap_used)]
209 #[allow(clippy::indexing_slicing)]
210 let beta_i_bytes = bytes[start..end].try_into().unwrap();
211 let beta_i = try_deserialize_g2_projective(&beta_i_bytes)?;
212
213 beta_g2.push(beta_i)
214 }
215
216 Ok(VerificationKeyAuth {
217 alpha,
218 beta_g1,
219 beta_g2,
220 })
221 }
222}
223
224impl<'b> Add<&'b VerificationKeyAuth> for VerificationKeyAuth {
225 type Output = VerificationKeyAuth;
226
227 #[inline]
228 fn add(self, rhs: &'b VerificationKeyAuth) -> VerificationKeyAuth {
229 assert_eq!(
233 self.beta_g1.len(),
234 rhs.beta_g1.len(),
235 "trying to add verification keys generated for different number of attributes [G1]"
236 );
237
238 assert_eq!(
239 self.beta_g2.len(),
240 rhs.beta_g2.len(),
241 "trying to add verification keys generated for different number of attributes [G2]"
242 );
243
244 assert_eq!(
245 self.beta_g1.len(),
246 self.beta_g2.len(),
247 "this key is incorrect - the number of elements G1 and G2 does not match"
248 );
249
250 assert_eq!(
251 rhs.beta_g1.len(),
252 rhs.beta_g2.len(),
253 "they key you want to add is incorrect - the number of elements G1 and G2 does not match"
254 );
255
256 VerificationKeyAuth {
257 alpha: self.alpha + rhs.alpha,
258 beta_g1: self
259 .beta_g1
260 .iter()
261 .zip(rhs.beta_g1.iter())
262 .map(|(self_beta_g1, rhs_beta_g1)| self_beta_g1 + rhs_beta_g1)
263 .collect(),
264 beta_g2: self
265 .beta_g2
266 .iter()
267 .zip(rhs.beta_g2.iter())
268 .map(|(self_beta_g2, rhs_beta_g2)| self_beta_g2 + rhs_beta_g2)
269 .collect(),
270 }
271 }
272}
273
274impl Mul<Scalar> for &VerificationKeyAuth {
275 type Output = VerificationKeyAuth;
276
277 #[inline]
278 fn mul(self, rhs: Scalar) -> Self::Output {
279 VerificationKeyAuth {
280 alpha: self.alpha * rhs,
281 beta_g1: self.beta_g1.iter().map(|b_i| b_i * rhs).collect(),
282 beta_g2: self.beta_g2.iter().map(|b_i| b_i * rhs).collect(),
283 }
284 }
285}
286
287impl<T> Sum<T> for VerificationKeyAuth
288where
289 T: Borrow<VerificationKeyAuth>,
290{
291 #[inline]
292 fn sum<I>(iter: I) -> Self
293 where
294 I: Iterator<Item = T>,
295 {
296 let mut peekable = iter.peekable();
297 let head_attributes = match peekable.peek() {
298 Some(head) => head.borrow().beta_g2.len(),
299 None => {
300 return VerificationKeyAuth::identity(0);
303 }
304 };
305
306 peekable.fold(
307 VerificationKeyAuth::identity(head_attributes),
308 |acc, item| acc + item.borrow(),
309 )
310 }
311}
312
313impl VerificationKeyAuth {
314 pub(crate) fn identity(beta_size: usize) -> Self {
317 VerificationKeyAuth {
318 alpha: G2Projective::identity(),
319 beta_g1: vec![G1Projective::identity(); beta_size],
320 beta_g2: vec![G2Projective::identity(); beta_size],
321 }
322 }
323
324 pub fn aggregate(sigs: &[Self], indices: Option<&[SignerIndex]>) -> Result<Self> {
325 aggregate_verification_keys(sigs, indices)
326 }
327
328 pub fn alpha(&self) -> &G2Projective {
329 &self.alpha
330 }
331
332 pub fn beta_g1(&self) -> &Vec<G1Projective> {
333 &self.beta_g1
334 }
335
336 pub fn beta_g2(&self) -> &Vec<G2Projective> {
337 &self.beta_g2
338 }
339
340 pub fn to_bytes(&self) -> Vec<u8> {
341 let beta_g1_len = self.beta_g1.len();
342 let beta_g2_len = self.beta_g2.len();
343 let mut bytes = Vec::with_capacity(96 + 8 + beta_g1_len * 48 + beta_g2_len * 96);
344
345 bytes.extend_from_slice(&self.alpha.to_affine().to_compressed());
346
347 bytes.extend_from_slice(&(beta_g1_len as u64).to_le_bytes());
348
349 for beta_g1 in self.beta_g1.iter() {
350 bytes.extend_from_slice(&beta_g1.to_affine().to_compressed())
351 }
352
353 for beta_g2 in self.beta_g2.iter() {
354 bytes.extend_from_slice(&beta_g2.to_affine().to_compressed())
355 }
356
357 bytes
358 }
359
360 pub fn from_bytes(bytes: &[u8]) -> Result<VerificationKeyAuth> {
361 VerificationKeyAuth::try_from(bytes)
362 }
363}
364
365impl Bytable for VerificationKeyAuth {
366 fn to_byte_vec(&self) -> Vec<u8> {
367 self.to_bytes().to_vec()
368 }
369
370 fn try_from_byte_slice(slice: &[u8]) -> std::result::Result<Self, CompactEcashError> {
371 Self::from_bytes(slice)
372 }
373}
374
375impl Base58 for VerificationKeyAuth {}
376
377#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Zeroize, ZeroizeOnDrop)]
378pub struct SecretKeyUser {
379 pub(crate) sk: Scalar,
380}
381
382impl SecretKeyUser {
383 pub fn public_key(&self) -> PublicKeyUser {
384 PublicKeyUser {
385 pk: ecash_group_parameters().gen1() * self.sk,
386 }
387 }
388
389 pub fn to_bytes(&self) -> Vec<u8> {
390 self.sk.to_bytes().to_vec()
391 }
392
393 pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
394 let sk = Scalar::try_from_byte_slice(bytes)?;
395 Ok(SecretKeyUser { sk })
396 }
397}
398
399impl Bytable for SecretKeyUser {
400 fn to_byte_vec(&self) -> Vec<u8> {
401 self.to_bytes().to_vec()
402 }
403
404 fn try_from_byte_slice(slice: &[u8]) -> std::result::Result<Self, CompactEcashError> {
405 Self::from_bytes(slice)
406 }
407}
408
409impl Base58 for SecretKeyUser {}
410
411#[derive(Debug, Eq, PartialEq, Clone, Copy, Serialize, Deserialize)]
412pub struct PublicKeyUser {
413 pub(crate) pk: G1Projective,
414}
415
416impl PublicKeyUser {
417 pub fn to_base58_string(&self) -> String {
418 bs58::encode(&self.pk.to_bytes()).into_string()
419 }
420
421 pub fn from_base58_string<I: AsRef<[u8]>>(val: I) -> Result<Self> {
422 let bytes = bs58::decode(val).into_vec()?;
423 Self::from_bytes(&bytes)
424 }
425
426 pub fn to_bytes(&self) -> Vec<u8> {
427 self.pk.to_affine().to_compressed().to_vec()
428 }
429
430 pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
431 if bytes.len() != 48 {
432 return Err(CompactEcashError::DeserializationLengthMismatch {
433 type_name: "PublicKeyUser".into(),
434 expected: 48,
435 actual: bytes.len(),
436 });
437 }
438 #[allow(clippy::unwrap_used)]
440 #[allow(clippy::indexing_slicing)]
441 let pk_bytes: &[u8; 48] = bytes[..48].try_into().unwrap();
442 let pk = try_deserialize_g1_projective(pk_bytes)?;
443 Ok(PublicKeyUser { pk })
444 }
445}
446
447impl Bytable for PublicKeyUser {
448 fn to_byte_vec(&self) -> Vec<u8> {
449 self.to_bytes().to_vec()
450 }
451
452 fn try_from_byte_slice(slice: &[u8]) -> Result<Self> {
453 Self::from_bytes(slice)
454 }
455}
456
457impl Base58 for PublicKeyUser {}
458
459#[derive(Debug, Zeroize, ZeroizeOnDrop)]
460pub struct KeyPairAuth {
461 secret_key: SecretKeyAuth,
462 #[zeroize(skip)]
463 verification_key: VerificationKeyAuth,
464 pub index: Option<SignerIndex>,
466}
467
468impl From<SecretKeyAuth> for KeyPairAuth {
469 fn from(secret_key: SecretKeyAuth) -> Self {
470 KeyPairAuth {
471 verification_key: secret_key.verification_key(),
472 secret_key,
473 index: None,
474 }
475 }
476}
477
478impl PemStorableKeyPair for KeyPairAuth {
479 type PrivatePemKey = SecretKeyAuth;
480 type PublicPemKey = VerificationKeyAuth;
481
482 fn private_key(&self) -> &Self::PrivatePemKey {
483 &self.secret_key
484 }
485
486 fn public_key(&self) -> &Self::PublicPemKey {
487 &self.verification_key
488 }
489
490 fn from_keys(secret_key: Self::PrivatePemKey, verification_key: Self::PublicPemKey) -> Self {
491 Self::from_keys(secret_key, verification_key)
492 }
493}
494
495impl KeyPairAuth {
496 pub fn new(
497 sk: SecretKeyAuth,
498 vk: VerificationKeyAuth,
499 index: Option<SignerIndex>,
500 ) -> KeyPairAuth {
501 KeyPairAuth {
502 secret_key: sk,
503 verification_key: vk,
504 index,
505 }
506 }
507
508 pub fn from_keys(secret_key: SecretKeyAuth, verification_key: VerificationKeyAuth) -> Self {
509 Self {
510 secret_key,
511 verification_key,
512 index: None,
513 }
514 }
515
516 pub fn secret_key(&self) -> &SecretKeyAuth {
517 &self.secret_key
518 }
519
520 pub fn verification_key(&self) -> VerificationKeyAuth {
521 self.verification_key.clone()
522 }
523
524 pub fn verification_key_ref(&self) -> &VerificationKeyAuth {
525 &self.verification_key
526 }
527}
528
529#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
530pub struct KeyPairUser {
531 secret_key: SecretKeyUser,
532 public_key: PublicKeyUser,
533}
534
535impl From<KeyPairUser> for SecretKeyUser {
536 fn from(value: KeyPairUser) -> Self {
537 value.secret_key
538 }
539}
540
541impl From<SecretKeyUser> for KeyPairUser {
542 fn from(value: SecretKeyUser) -> Self {
543 KeyPairUser {
544 public_key: value.public_key(),
545 secret_key: value,
546 }
547 }
548}
549
550impl KeyPairUser {
551 #[allow(clippy::new_without_default)]
552 pub fn new() -> Self {
553 generate_keypair_user()
554 }
555
556 pub fn new_seeded<M: AsRef<[u8]>>(seed: M) -> Self {
557 generate_keypair_user_from_seed(seed)
558 }
559
560 pub fn secret_key(&self) -> &SecretKeyUser {
561 &self.secret_key
562 }
563
564 pub fn public_key(&self) -> PublicKeyUser {
565 self.public_key
566 }
567
568 pub fn to_bytes(&self) -> Vec<u8> {
569 [self.secret_key.to_bytes(), self.public_key.to_bytes()].concat()
570 }
571
572 pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
573 if bytes.len() != 32 + 48 {
574 return Err(CompactEcashError::DeserializationLengthMismatch {
575 type_name: "KeyPairUser".into(),
576 expected: 80,
577 actual: bytes.len(),
578 });
579 }
580 #[allow(clippy::indexing_slicing)]
581 let sk = SecretKeyUser::from_bytes(&bytes[..32])?;
582 #[allow(clippy::indexing_slicing)]
583 let pk = PublicKeyUser::from_bytes(&bytes[32..32 + 48])?;
584 Ok(KeyPairUser {
585 secret_key: sk,
586 public_key: pk,
587 })
588 }
589}
590
591pub fn generate_keypair_user() -> KeyPairUser {
592 let params = ecash_group_parameters();
593 let sk_user = SecretKeyUser {
594 sk: params.random_scalar(),
595 };
596 let pk_user = PublicKeyUser {
597 pk: params.gen1() * sk_user.sk,
598 };
599
600 KeyPairUser {
601 secret_key: sk_user,
602 public_key: pk_user,
603 }
604}
605
606pub fn generate_keypair_user_from_seed<M: AsRef<[u8]>>(seed: M) -> KeyPairUser {
607 let params = ecash_group_parameters();
608 let sk_user = SecretKeyUser {
609 sk: hash_to_scalar(seed),
610 };
611 let pk_user = PublicKeyUser {
612 pk: params.gen1() * sk_user.sk,
613 };
614
615 KeyPairUser {
616 secret_key: sk_user,
617 public_key: pk_user,
618 }
619}
620
621pub fn ttp_keygen(threshold: u64, num_authorities: u64) -> Result<Vec<KeyPairAuth>> {
622 let params = ecash_group_parameters();
623 if threshold == 0 {
624 return Err(CompactEcashError::KeygenParameters);
625 }
626
627 if threshold > num_authorities {
628 return Err(CompactEcashError::KeygenParameters);
629 }
630
631 let attributes = params.gammas().len();
632
633 let v = Polynomial::new_random(params, threshold - 1);
635 let ws = (0..attributes + 1)
636 .map(|_| Polynomial::new_random(params, threshold - 1))
637 .collect::<Vec<_>>();
638
639 let polynomial_indices = (1..=num_authorities).collect::<Vec<_>>();
642
643 let x = polynomial_indices
645 .iter()
646 .map(|&id| v.evaluate(&Scalar::from(id)));
647 let ys = polynomial_indices.iter().map(|&id| {
648 ws.iter()
649 .map(|w| w.evaluate(&Scalar::from(id)))
650 .collect::<Vec<_>>()
651 });
652
653 let secret_keys = x.zip(ys).map(|(x, ys)| SecretKeyAuth { x, ys });
655
656 let keypairs = secret_keys
657 .zip(polynomial_indices.iter())
658 .map(|(secret_key, index)| {
659 let verification_key = secret_key.verification_key();
660 KeyPairAuth {
661 secret_key,
662 verification_key,
663 index: Some(*index),
664 }
665 })
666 .collect();
667
668 Ok(keypairs)
669}
670
671#[cfg(test)]
672mod tests {
673 use super::*;
674
675 fn assert_zeroize_on_drop<T: ZeroizeOnDrop>() {}
676
677 fn assert_zeroize<T: Zeroize>() {}
678
679 #[test]
680 fn secret_key_is_zeroized() {
681 assert_zeroize::<SecretKeyAuth>();
682 assert_zeroize_on_drop::<SecretKeyAuth>();
683
684 assert_zeroize::<SecretKeyUser>();
685 assert_zeroize_on_drop::<SecretKeyUser>();
686 }
687}