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