1use core::{
4 fmt::{self, Debug, Formatter},
5 ops::Add,
6};
7
8use aead::generic_array::GenericArray;
9use blake2::Digest;
10use bls12_381::{G1Affine, G1Projective, G2Affine, G2Projective, Scalar};
11use group::GroupEncoding;
12use sha2::Sha256;
13use subtle::ConstantTimeEq;
14use zeroize::{Zeroize, Zeroizing};
15
16use crate::generic_array::{
17 typenum::{self, Unsigned, U144, U32, U48, U96},
18 ArrayLength,
19};
20
21use super::{BlsCurves, HasKeyAlg, HasKeyBackend, KeyAlg};
22use crate::{
23 buffer::ArrayKey,
24 error::Error,
25 jwk::{FromJwk, JwkEncoder, JwkParts, ToJwk},
26 random::KeyMaterial,
27 repr::{KeyGen, KeyMeta, KeyPublicBytes, KeySecretBytes, KeypairMeta},
28};
29
30pub const JWK_KEY_TYPE: &str = "OKP";
32
33#[derive(Clone, Zeroize)]
35pub struct BlsKeyPair<Pk: BlsPublicKeyType> {
36 secret: Option<BlsSecretKey>,
37 public: Pk::Buffer,
38}
39
40impl<Pk: BlsPublicKeyType> BlsKeyPair<Pk> {
41 pub fn from_seed(seed: &[u8]) -> Result<Self, Error> {
43 Ok(Self::from_secret_key(BlsSecretKey::generate(
44 BlsKeyGen::new(seed)?,
45 )?))
46 }
47
48 #[inline]
49 pub(crate) fn from_secret_key(sk: BlsSecretKey) -> Self {
50 let public = Pk::from_secret_scalar(&sk.0);
51 Self {
52 secret: Some(sk),
53 public,
54 }
55 }
56
57 pub(crate) fn check_public_bytes(&self, pk: &[u8]) -> Result<(), Error> {
58 if Pk::with_bytes(&self.public, None, |slf| slf.ct_eq(pk)).into() {
59 Ok(())
60 } else {
61 Err(err_msg!(InvalidKeyData, "invalid BLS keypair"))
62 }
63 }
64
65 pub fn bls_public_key(&self) -> &Pk::Buffer {
67 &self.public
68 }
69
70 pub fn bls_secret_scalar(&self) -> Option<&Scalar> {
72 self.secret.as_ref().map(|s| &s.0)
73 }
74}
75
76impl<Pk: BlsPublicKeyType> Debug for BlsKeyPair<Pk> {
77 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
78 f.debug_struct("BlsKeyPair")
79 .field("crv", &Pk::JWK_CURVE)
80 .field("secret", &self.secret)
81 .field("public", &self.public)
82 .finish()
83 }
84}
85
86impl<Pk: BlsPublicKeyType> PartialEq for BlsKeyPair<Pk> {
87 fn eq(&self, other: &Self) -> bool {
88 other.secret == self.secret && other.public == self.public
89 }
90}
91
92impl<Pk: BlsPublicKeyType> Eq for BlsKeyPair<Pk> {}
93
94impl<Pk: BlsPublicKeyType> HasKeyBackend for BlsKeyPair<Pk> {}
95
96impl<Pk: BlsPublicKeyType> HasKeyAlg for BlsKeyPair<Pk> {
97 fn algorithm(&self) -> KeyAlg {
98 KeyAlg::Bls12_381(Pk::ALG_TYPE)
99 }
100}
101
102impl<Pk: BlsPublicKeyType> KeyMeta for BlsKeyPair<Pk> {
103 type KeySize = U32;
104}
105
106impl<Pk> KeypairMeta for BlsKeyPair<Pk>
107where
108 Pk: BlsPublicKeyType,
109 U32: Add<Pk::BufferSize>,
110 <U32 as Add<Pk::BufferSize>>::Output: ArrayLength<u8>,
111{
112 type PublicKeySize = Pk::BufferSize;
113 type KeypairSize = typenum::Sum<Self::KeySize, Pk::BufferSize>;
114}
115
116impl<Pk: BlsPublicKeyType> KeyGen for BlsKeyPair<Pk> {
117 fn generate(rng: impl KeyMaterial) -> Result<Self, Error> {
118 let secret = BlsSecretKey::generate(rng)?;
119 Ok(Self::from_secret_key(secret))
120 }
121}
122
123impl<Pk: BlsPublicKeyType> KeySecretBytes for BlsKeyPair<Pk> {
124 fn from_secret_bytes(key: &[u8]) -> Result<Self, Error>
125 where
126 Self: Sized,
127 {
128 let sk = BlsSecretKey::from_bytes(key)?;
129 Ok(Self::from_secret_key(sk))
130 }
131
132 fn with_secret_bytes<O>(&self, f: impl FnOnce(Option<&[u8]>) -> O) -> O {
133 if let Some(sk) = self.secret.as_ref() {
134 let mut skb = Zeroizing::new(sk.0.to_bytes());
135 skb.reverse(); f(Some(&*skb))
137 } else {
138 f(None)
139 }
140 }
141}
142
143impl<Pk: BlsPublicKeyType> KeyPublicBytes for BlsKeyPair<Pk>
144where
145 Self: KeypairMeta,
146{
147 fn from_public_bytes(key: &[u8]) -> Result<Self, Error> {
148 Ok(Self {
149 secret: None,
150 public: Pk::from_public_bytes(key)?,
151 })
152 }
153
154 fn with_public_bytes<O>(&self, f: impl FnOnce(&[u8]) -> O) -> O {
155 Pk::with_bytes(&self.public, None, f)
156 }
157}
158
159impl<Pk: BlsPublicKeyType> ToJwk for BlsKeyPair<Pk> {
160 fn encode_jwk(&self, enc: &mut dyn JwkEncoder) -> Result<(), Error> {
161 enc.add_str("crv", Pk::get_jwk_curve(enc.alg()))?;
162 enc.add_str("kty", JWK_KEY_TYPE)?;
163 Pk::with_bytes(&self.public, enc.alg(), |buf| enc.add_as_base64("x", buf))?;
164 if enc.is_secret() {
165 self.with_secret_bytes(|buf| {
166 if let Some(sk) = buf {
167 enc.add_as_base64("d", sk)
168 } else {
169 Ok(())
170 }
171 })?;
172 }
173 Ok(())
174 }
175}
176
177impl<Pk: BlsPublicKeyType> FromJwk for BlsKeyPair<Pk> {
178 fn from_jwk_parts(jwk: JwkParts<'_>) -> Result<Self, Error> {
179 if jwk.kty != JWK_KEY_TYPE &&
180 jwk.kty != "EC"
182 {
183 return Err(err_msg!(InvalidKeyData, "Unsupported key type"));
184 }
185 if jwk.crv != Pk::JWK_CURVE {
186 return Err(err_msg!(InvalidKeyData, "Unsupported key algorithm"));
187 }
188 ArrayKey::<Pk::BufferSize>::temp(|pk_arr| {
189 if jwk.x.decode_base64(pk_arr)? != pk_arr.len() {
190 Err(err_msg!(InvalidKeyData))
191 } else if jwk.d.is_some() {
192 ArrayKey::<U32>::temp(|sk_arr| {
193 if jwk.d.decode_base64(sk_arr)? != sk_arr.len() {
194 Err(err_msg!(InvalidKeyData))
195 } else {
196 let result = BlsKeyPair::from_secret_key(BlsSecretKey::from_bytes(sk_arr)?);
197 result.check_public_bytes(pk_arr)?;
198 Ok(result)
199 }
200 })
201 } else {
202 Ok(Self {
203 secret: None,
204 public: Pk::from_public_bytes(pk_arr)?,
205 })
206 }
207 })
208 }
209}
210
211#[derive(Clone, Debug, PartialEq, Eq, Zeroize)]
212#[repr(transparent)]
213pub(crate) struct BlsSecretKey(Scalar);
214
215impl BlsSecretKey {
216 fn generate(mut rng: impl KeyMaterial) -> Result<Self, Error> {
217 let mut secret = Zeroizing::new([0u8; 64]);
218 rng.read_okm(&mut secret[16..]);
219 secret.reverse(); Ok(Self(Scalar::from_bytes_wide(&secret)))
221 }
222
223 pub fn from_bytes(sk: &[u8]) -> Result<Self, Error> {
224 if sk.len() != 32 {
225 return Err(err_msg!(InvalidKeyData));
226 }
227 let mut skb = Zeroizing::new([0u8; 32]);
228 skb.copy_from_slice(sk);
229 skb.reverse(); let result: Option<Scalar> = Scalar::from_bytes(&skb).into();
231 Ok(Self(result.ok_or_else(|| err_msg!(InvalidKeyData))?))
232 }
233}
234
235impl Drop for BlsSecretKey {
236 fn drop(&mut self) {
237 self.zeroize();
238 }
239}
240
241#[derive(Debug, Clone)]
244pub struct BlsKeyGen<'g> {
245 salt: Option<GenericArray<u8, U32>>,
246 ikm: &'g [u8],
247}
248
249impl<'g> BlsKeyGen<'g> {
250 pub fn new(ikm: &'g [u8]) -> Result<Self, Error> {
252 if ikm.len() < 32 {
253 return Err(err_msg!(Usage, "Insufficient length for seed"));
254 }
255 Ok(Self { salt: None, ikm })
256 }
257}
258
259impl KeyMaterial for BlsKeyGen<'_> {
260 fn read_okm(&mut self, buf: &mut [u8]) {
261 const SALT: &[u8] = b"BLS-SIG-KEYGEN-SALT-";
262
263 self.salt.replace(match self.salt {
264 None => Sha256::digest(SALT),
265 Some(salt) => Sha256::digest(salt),
266 });
267 let mut extract = hkdf::HkdfExtract::<Sha256>::new(Some(self.salt.as_ref().unwrap()));
268 extract.input_ikm(self.ikm);
269 extract.input_ikm(&[0u8]);
270 let (_, hkdf) = extract.finalize();
271 hkdf.expand(&(buf.len() as u16).to_be_bytes(), buf)
272 .expect("HDKF extract failure");
273 }
274}
275
276pub trait BlsPublicKeyType: 'static {
278 type Buffer: Clone + Debug + PartialEq + Sized + Zeroize;
280
281 type BufferSize: ArrayLength<u8>;
283
284 const ALG_TYPE: BlsCurves;
286 const JWK_CURVE: &'static str;
288
289 fn get_jwk_curve(_alg: Option<KeyAlg>) -> &'static str {
291 Self::JWK_CURVE
292 }
293
294 fn from_secret_scalar(secret: &Scalar) -> Self::Buffer;
296
297 fn from_public_bytes(key: &[u8]) -> Result<Self::Buffer, Error>;
299
300 fn with_bytes<O>(buf: &Self::Buffer, alg: Option<KeyAlg>, f: impl FnOnce(&[u8]) -> O) -> O;
302}
303
304#[derive(Debug)]
306pub struct G1;
307
308impl BlsPublicKeyType for G1 {
309 type Buffer = G1Affine;
310 type BufferSize = U48;
311
312 const ALG_TYPE: BlsCurves = BlsCurves::G1;
313 const JWK_CURVE: &'static str = "BLS12381_G1";
314
315 #[inline]
316 fn from_secret_scalar(secret: &Scalar) -> Self::Buffer {
317 G1Affine::from(G1Projective::generator() * secret)
318 }
319
320 fn from_public_bytes(key: &[u8]) -> Result<Self::Buffer, Error> {
321 let buf: Option<G1Affine> = G1Affine::from_compressed(
322 TryInto::<&[u8; 48]>::try_into(key).map_err(|_| err_msg!(InvalidKeyData))?,
323 )
324 .into();
325 buf.ok_or_else(|| err_msg!(InvalidKeyData))
326 }
327
328 fn with_bytes<O>(buf: &Self::Buffer, _alg: Option<KeyAlg>, f: impl FnOnce(&[u8]) -> O) -> O {
329 f(buf.to_bytes().as_ref())
330 }
331}
332
333#[derive(Debug)]
335pub struct G2;
336
337impl BlsPublicKeyType for G2 {
338 type Buffer = G2Affine;
339 type BufferSize = U96;
340
341 const ALG_TYPE: BlsCurves = BlsCurves::G2;
342 const JWK_CURVE: &'static str = "BLS12381_G2";
343
344 #[inline]
345 fn from_secret_scalar(secret: &Scalar) -> Self::Buffer {
346 G2Affine::from(G2Projective::generator() * secret)
347 }
348
349 fn from_public_bytes(key: &[u8]) -> Result<Self::Buffer, Error> {
350 let buf: Option<G2Affine> = G2Affine::from_compressed(
351 TryInto::<&[u8; 96]>::try_into(key).map_err(|_| err_msg!(InvalidKeyData))?,
352 )
353 .into();
354 buf.ok_or_else(|| err_msg!(InvalidKeyData))
355 }
356
357 fn with_bytes<O>(buf: &Self::Buffer, _alg: Option<KeyAlg>, f: impl FnOnce(&[u8]) -> O) -> O {
358 f(buf.to_bytes().as_ref())
359 }
360}
361
362#[derive(Debug)]
364pub struct G1G2;
365
366impl BlsPublicKeyType for G1G2 {
367 type Buffer = G1G2Pair;
368 type BufferSize = U144;
369
370 const ALG_TYPE: BlsCurves = BlsCurves::G1G2;
371 const JWK_CURVE: &'static str = "BLS12381_G1G2";
372
373 fn get_jwk_curve(alg: Option<KeyAlg>) -> &'static str {
374 if alg == Some(KeyAlg::Bls12_381(BlsCurves::G1)) {
375 G1::JWK_CURVE
376 } else if alg == Some(KeyAlg::Bls12_381(BlsCurves::G2)) {
377 G2::JWK_CURVE
378 } else {
379 Self::JWK_CURVE
380 }
381 }
382
383 #[inline]
384 fn from_secret_scalar(secret: &Scalar) -> Self::Buffer {
385 G1G2Pair(
386 G1Affine::from(G1Projective::generator() * secret),
387 G2Affine::from(G2Projective::generator() * secret),
388 )
389 }
390
391 fn from_public_bytes(key: &[u8]) -> Result<Self::Buffer, Error> {
392 if key.len() != Self::BufferSize::USIZE {
393 return Err(err_msg!(InvalidKeyData));
394 }
395 let g1: Option<G1Affine> =
396 G1Affine::from_compressed(TryInto::<&[u8; 48]>::try_into(&key[..48]).unwrap()).into();
397 let g2: Option<G2Affine> =
398 G2Affine::from_compressed(TryInto::<&[u8; 96]>::try_into(&key[48..]).unwrap()).into();
399 if let (Some(g1), Some(g2)) = (g1, g2) {
400 Ok(G1G2Pair(g1, g2))
401 } else {
402 Err(err_msg!(InvalidKeyData))
403 }
404 }
405
406 fn with_bytes<O>(buf: &Self::Buffer, alg: Option<KeyAlg>, f: impl FnOnce(&[u8]) -> O) -> O {
407 if alg == Some(KeyAlg::Bls12_381(BlsCurves::G1)) {
408 ArrayKey::<U48>::temp(|arr| {
409 arr.copy_from_slice(buf.0.to_bytes().as_ref());
410 f(&arr[..])
411 })
412 } else if alg == Some(KeyAlg::Bls12_381(BlsCurves::G2)) {
413 ArrayKey::<U96>::temp(|arr| {
414 arr.copy_from_slice(buf.1.to_bytes().as_ref());
415 f(&arr[..])
416 })
417 } else {
418 ArrayKey::<U144>::temp(|arr| {
419 arr[0..48].copy_from_slice(buf.0.to_bytes().as_ref());
420 arr[48..].copy_from_slice(buf.1.to_bytes().as_ref());
421 f(&arr[..])
422 })
423 }
424 }
425}
426
427impl From<&BlsKeyPair<G1G2>> for BlsKeyPair<G1> {
428 fn from(kp: &BlsKeyPair<G1G2>) -> Self {
429 BlsKeyPair {
430 secret: kp.secret.clone(),
431 public: kp.public.0,
432 }
433 }
434}
435
436impl From<&BlsKeyPair<G1G2>> for BlsKeyPair<G2> {
437 fn from(kp: &BlsKeyPair<G1G2>) -> Self {
438 BlsKeyPair {
439 secret: kp.secret.clone(),
440 public: kp.public.1,
441 }
442 }
443}
444
445#[derive(Clone, Debug, PartialEq, Eq, Zeroize)]
446pub struct G1G2Pair(G1Affine, G2Affine);
448
449#[cfg(test)]
450mod tests {
451 use base64::Engine;
452 use std::string::ToString;
453
454 use super::*;
455 use crate::repr::{ToPublicBytes, ToSecretBytes};
456
457 #[test]
459 fn key_gen_expected() {
460 let seed = &hex!(
461 "c55257c360c07c72029aebc1b53c05ed0362ada38ead3e3e9efa3708e5349553
462 1f09a6987599d18264c1e1c92f2cf141630c7a3c4ab7c81b2f001698e7463b04"
463 );
464 let kp = BlsKeyPair::<G1>::from_seed(&seed[..]).unwrap();
465 let sk = kp.to_secret_bytes().unwrap();
466 assert_eq!(
467 sk.as_hex().to_string(),
468 "0d7359d57963ab8fbbde1852dcf553fedbc31f464d80ee7d40ae683122b45070"
469 );
470 }
471
472 #[test]
473 fn g1_key_expected() {
474 let sk = hex!("0d7359d57963ab8fbbde1852dcf553fedbc31f464d80ee7d40ae683122b45070");
475 let kp = BlsKeyPair::<G1>::from_secret_bytes(&sk[..]).unwrap();
476 let pk = kp.to_public_bytes().unwrap();
477 assert_eq!(
478 pk.as_hex().to_string(),
479 "a2c975348667926acf12f3eecb005044e08a7a9b7d95f30bd281b55445107367a2e5d0558be7943c8bd13f9a1a7036fb"
480 );
481 assert_eq!(
482 BlsKeyPair::<G1>::from_public_bytes(pk.as_ref())
483 .unwrap()
484 .to_public_bytes()
485 .unwrap(),
486 pk
487 );
488 }
489
490 #[test]
491 fn g2_key_expected() {
492 let sk = hex!("0d7359d57963ab8fbbde1852dcf553fedbc31f464d80ee7d40ae683122b45070");
493 let kp = BlsKeyPair::<G2>::from_secret_bytes(&sk[..]).unwrap();
494 let pk = kp.to_public_bytes().unwrap();
495 assert_eq!(
496 pk.as_hex().to_string(),
497 "a5e43d5ecb7b8c01ceb3b91f7413b628ef02c6859dc42a4354b21f9195531988a648655037faafd1bac2fd2d7d9466180baa3705a45a6c597853db51eaf431616057fd8049c6bee8764292f9a104200a45a63ceae9d3c368643ab9e5ff0f8810"
498 );
499 assert_eq!(
500 BlsKeyPair::<G2>::from_public_bytes(pk.as_ref())
501 .unwrap()
502 .to_public_bytes()
503 .unwrap(),
504 pk
505 );
506 }
507
508 #[test]
509 fn g1g2_key_expected() {
510 let sk = hex!("0d7359d57963ab8fbbde1852dcf553fedbc31f464d80ee7d40ae683122b45070");
511 let kp = BlsKeyPair::<G1G2>::from_secret_bytes(&sk[..]).unwrap();
512 let pk = kp.to_public_bytes().unwrap();
513 assert_eq!(
514 pk.as_hex().to_string(),
515 "a2c975348667926acf12f3eecb005044e08a7a9b7d95f30bd281b55445107367a2e5d0558be7943c8bd13f9a1a7036fb\
516 a5e43d5ecb7b8c01ceb3b91f7413b628ef02c6859dc42a4354b21f9195531988a648655037faafd1bac2fd2d7d9466180baa3705a45a6c597853db51eaf431616057fd8049c6bee8764292f9a104200a45a63ceae9d3c368643ab9e5ff0f8810"
517 );
518 assert_eq!(
519 BlsKeyPair::<G1G2>::from_public_bytes(pk.as_ref())
520 .unwrap()
521 .to_public_bytes()
522 .unwrap(),
523 pk
524 );
525 }
526
527 #[test]
528 fn g1_jwk_expected() {
529 let test_pvt = &hex!("0d7359d57963ab8fbbde1852dcf553fedbc31f464d80ee7d40ae683122b45070");
530 let test_pub_g1 = &hex!("a2c975348667926acf12f3eecb005044e08a7a9b7d95f30bd281b55445107367a2e5d0558be7943c8bd13f9a1a7036fb");
531 let kp = BlsKeyPair::<G1>::from_secret_bytes(&test_pvt[..]).expect("Error creating key");
532
533 let jwk = kp.to_jwk_public(None).expect("Error converting key to JWK");
534 let jwk = JwkParts::try_from_str(&jwk).expect("Error parsing JWK");
535 assert_eq!(jwk.kty, JWK_KEY_TYPE);
536 assert_eq!(jwk.crv, G1::JWK_CURVE);
537 assert_eq!(
538 jwk.x,
539 base64::engine::general_purpose::URL_SAFE_NO_PAD
540 .encode(test_pub_g1)
541 .as_str()
542 );
543 assert_eq!(jwk.d, None);
544 let pk_load = BlsKeyPair::<G1>::from_jwk_parts(jwk).unwrap();
545 assert_eq!(kp.to_public_bytes(), pk_load.to_public_bytes());
546
547 let jwk = kp.to_jwk_secret(None).expect("Error converting key to JWK");
548 let jwk = JwkParts::from_slice(&jwk).expect("Error parsing JWK");
549 assert_eq!(jwk.kty, JWK_KEY_TYPE);
550 assert_eq!(jwk.crv, G1::JWK_CURVE);
551 assert_eq!(
552 jwk.x,
553 base64::engine::general_purpose::URL_SAFE_NO_PAD
554 .encode(test_pub_g1)
555 .as_str()
556 );
557 assert_eq!(
558 jwk.d,
559 base64::engine::general_purpose::URL_SAFE_NO_PAD
560 .encode(test_pvt)
561 .as_str()
562 );
563 let _sk_load = BlsKeyPair::<G1>::from_jwk_parts(jwk).unwrap();
564 }
569
570 #[cfg(feature = "any_key")]
571 #[test]
572 fn g1_jwk_any_compat() {
574 use crate::alg::{any::AnyKey, BlsCurves, KeyAlg};
575 use alloc::boxed::Box;
576
577 let test_jwk_compat = r#"
578 {
579 "crv": "BLS12381_G1",
580 "kty": "EC",
581 "x": "osl1NIZnkmrPEvPuywBQROCKept9lfML0oG1VEUQc2ei5dBVi-eUPIvRP5oacDb7"
582 }"#;
583 let key = Box::<AnyKey>::from_jwk(test_jwk_compat).expect("Error decoding BLS key JWK");
584 assert_eq!(key.algorithm(), KeyAlg::Bls12_381(BlsCurves::G1));
585 let as_bls = key
586 .downcast_ref::<BlsKeyPair<G1>>()
587 .expect("Error downcasting BLS key");
588 let _ = as_bls
589 .to_jwk_public(None)
590 .expect("Error converting key to JWK");
591 }
592}