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 sha2::Sha256;
12use zeroize::{Zeroize, Zeroizing};
13
14use crate::generic_array::{
15 typenum::{self, Unsigned, U192, U32, U48, U96},
16 ArrayLength,
17};
18
19use super::{BlsCurves, HasKeyAlg, HasKeyBackend, KeyAlg};
20use crate::{
21 buffer::ArrayKey,
22 error::Error,
23 jwk::{FromJwk, JwkEncoder, JwkParts, ToJwk},
24 random::KeyMaterial,
25 repr::{KeyGen, KeyMeta, KeyPublicBytes, KeySecretBytes, KeypairMeta},
26};
27
28pub const JWK_KEY_TYPE_EC: &str = "EC";
30pub const JWK_KEY_TYPE_OKP: &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 fn bls_public_key(&self) -> &Pk::Buffer {
59 &self.public
60 }
61
62 pub fn bls_secret_scalar(&self) -> Option<&Scalar> {
64 self.secret.as_ref().map(|s| &s.0)
65 }
66}
67
68impl<Pk: BlsPublicKeyType> Debug for BlsKeyPair<Pk> {
69 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
70 f.debug_struct("BlsKeyPair")
71 .field("crv", &Pk::JWK_CURVE)
72 .field("secret", &self.secret)
73 .field("public", &self.public)
74 .finish()
75 }
76}
77
78impl<Pk: BlsPublicKeyType> PartialEq for BlsKeyPair<Pk> {
79 fn eq(&self, other: &Self) -> bool {
80 other.secret == self.secret && other.public == self.public
81 }
82}
83
84impl<Pk: BlsPublicKeyType> Eq for BlsKeyPair<Pk> {}
85
86impl<Pk: BlsPublicKeyType> HasKeyBackend for BlsKeyPair<Pk> {}
87
88impl<Pk: BlsPublicKeyType> HasKeyAlg for BlsKeyPair<Pk> {
89 fn algorithm(&self) -> KeyAlg {
90 KeyAlg::Bls12_381(Pk::ALG_TYPE)
91 }
92}
93
94impl<Pk: BlsPublicKeyType> KeyMeta for BlsKeyPair<Pk> {
95 type KeySize = U32;
96}
97
98impl<Pk> KeypairMeta for BlsKeyPair<Pk>
99where
100 Pk: BlsPublicKeyType,
101 U32: Add<Pk::BufferSize>,
102 <U32 as Add<Pk::BufferSize>>::Output: ArrayLength<u8>,
103{
104 type PublicKeySize = Pk::BufferSize;
105 type KeypairSize = typenum::Sum<Self::KeySize, Pk::BufferSize>;
106}
107
108impl<Pk: BlsPublicKeyType> KeyGen for BlsKeyPair<Pk> {
109 fn generate(rng: impl KeyMaterial) -> Result<Self, Error> {
110 let secret = BlsSecretKey::generate(rng)?;
111 Ok(Self::from_secret_key(secret))
112 }
113}
114
115impl<Pk: BlsPublicKeyType> KeySecretBytes for BlsKeyPair<Pk> {
116 fn from_secret_bytes(key: &[u8]) -> Result<Self, Error>
117 where
118 Self: Sized,
119 {
120 let sk = BlsSecretKey::from_bytes(key)?;
121 Ok(Self::from_secret_key(sk))
122 }
123
124 fn with_secret_bytes<O>(&self, f: impl FnOnce(Option<&[u8]>) -> O) -> O {
125 if let Some(sk) = self.secret.as_ref() {
126 let mut skb = Zeroizing::new(sk.0.to_bytes());
127 skb.reverse(); f(Some(&*skb))
129 } else {
130 f(None)
131 }
132 }
133}
134
135impl<Pk: BlsPublicKeyType> KeyPublicBytes for BlsKeyPair<Pk>
136where
137 Self: KeypairMeta,
138{
139 fn from_public_bytes(key: &[u8]) -> Result<Self, Error> {
140 Ok(Self {
141 secret: None,
142 public: Pk::from_public_bytes(key)?,
143 })
144 }
145
146 fn with_public_bytes<O>(&self, f: impl FnOnce(&[u8]) -> O) -> O {
147 Pk::with_bytes(&self.public, None, f)
148 }
149}
150
151impl<Pk: BlsPublicKeyType> ToJwk for BlsKeyPair<Pk> {
152 fn encode_jwk(&self, enc: &mut dyn JwkEncoder) -> Result<(), Error> {
153 enc.add_str("crv", Pk::get_jwk_curve(enc.alg()))?;
154 enc.add_str("kty", JWK_KEY_TYPE_EC)?;
155 Pk::with_bytes_uncompressed(&self.public, enc.alg(), |buf| {
156 enc.add_as_base64("x", &buf[..Pk::BufferSize::USIZE])?;
157 enc.add_as_base64("y", &buf[Pk::BufferSize::USIZE..])
158 })?;
159 if enc.is_secret() {
160 self.with_secret_bytes(|buf| {
161 if let Some(sk) = buf {
162 let mut skr = Zeroizing::new([0u8; 32]);
163 skr.copy_from_slice(sk);
164 skr.reverse(); enc.add_as_base64("d", skr.as_ref())
166 } else {
167 Ok(())
168 }
169 })?;
170 }
171 Ok(())
172 }
173}
174
175impl<Pk: BlsPublicKeyType> FromJwk for BlsKeyPair<Pk> {
176 fn from_jwk_parts(jwk: JwkParts<'_>) -> Result<Self, Error> {
177 let public = match jwk.kty {
178 JWK_KEY_TYPE_EC => {
179 if jwk.crv != Pk::JWK_CURVE {
180 return Err(err_msg!(InvalidKeyData, "Unsupported key algorithm"));
181 }
182
183 ArrayKey::<Pk::BufferSizeWide>::temp(|arr| {
184 jwk.x.decode_base64(&mut arr[..Pk::BufferSize::USIZE])?;
186 jwk.y.decode_base64(&mut arr[Pk::BufferSize::USIZE..])?;
187 Pk::from_public_bytes(arr)
188 })
189 .map_err(|_| err_msg!(InvalidKeyData, "Invalid public key coordinates"))?
190 }
191
192 JWK_KEY_TYPE_OKP => {
194 if jwk.crv != Pk::JWK_CURVE_OKP {
195 return Err(err_msg!(InvalidKeyData, "Unsupported key algorithm"));
196 }
197 if jwk.y.is_some() {
198 return Err(err_msg!(InvalidKeyData, "Disallowed y coordinate"));
199 }
200
201 ArrayKey::<Pk::BufferSize>::temp(|arr| {
202 jwk.x.decode_base64(arr)?;
203 Pk::from_public_bytes(arr)
204 })
205 .map_err(|_| err_msg!(InvalidKeyData, "Invalid public key coordinates"))?
206 }
207
208 _ => {
209 return Err(err_msg!(InvalidKeyData, "Unsupported key type"));
210 }
211 };
212
213 if jwk.d.is_some() {
214 ArrayKey::<U32>::temp(|sk_arr| {
215 if jwk.d.decode_base64(sk_arr)? != sk_arr.len() {
216 Err(err_msg!(InvalidKeyData, "Invalid private key"))
217 } else {
218 if jwk.kty == JWK_KEY_TYPE_EC {
219 sk_arr.reverse(); }
221 let result = BlsKeyPair::from_secret_key(BlsSecretKey::from_bytes(sk_arr)?);
222 if result.public != public {
223 return Err(err_msg!(InvalidKeyData, "Public key mismatch"));
224 }
225 Ok(result)
226 }
227 })
228 } else {
229 Ok(Self {
230 secret: None,
231 public,
232 })
233 }
234 }
235}
236
237#[derive(Clone, Debug, PartialEq, Eq, Zeroize)]
238#[repr(transparent)]
239pub(crate) struct BlsSecretKey(Scalar);
240
241impl BlsSecretKey {
242 fn generate(mut rng: impl KeyMaterial) -> Result<Self, Error> {
243 let mut secret = Zeroizing::new([0u8; 64]);
244 rng.read_okm(&mut secret[16..]);
245 secret.reverse(); Ok(Self(Scalar::from_bytes_wide(&secret)))
247 }
248
249 pub fn from_bytes(sk: &[u8]) -> Result<Self, Error> {
250 if sk.len() != 32 {
251 return Err(err_msg!(InvalidKeyData));
252 }
253 let mut skb = Zeroizing::new([0u8; 32]);
254 skb.copy_from_slice(sk);
255 skb.reverse(); let result: Option<Scalar> = Scalar::from_bytes(&skb).into();
257 Ok(Self(result.ok_or_else(|| err_msg!(InvalidKeyData))?))
258 }
259}
260
261impl Drop for BlsSecretKey {
262 fn drop(&mut self) {
263 self.zeroize();
264 }
265}
266
267#[derive(Debug, Clone)]
270pub struct BlsKeyGen<'g> {
271 salt: Option<GenericArray<u8, U32>>,
272 ikm: &'g [u8],
273}
274
275impl<'g> BlsKeyGen<'g> {
276 pub fn new(ikm: &'g [u8]) -> Result<Self, Error> {
278 if ikm.len() < 32 {
279 return Err(err_msg!(Usage, "Insufficient length for seed"));
280 }
281 Ok(Self { salt: None, ikm })
282 }
283}
284
285impl KeyMaterial for BlsKeyGen<'_> {
286 fn read_okm(&mut self, buf: &mut [u8]) {
287 const SALT: &[u8] = b"BLS-SIG-KEYGEN-SALT-";
288
289 self.salt.replace(match self.salt {
290 None => Sha256::digest(SALT),
291 Some(salt) => Sha256::digest(salt),
292 });
293 let mut extract = hkdf::HkdfExtract::<Sha256>::new(Some(self.salt.as_ref().unwrap()));
294 extract.input_ikm(self.ikm);
295 extract.input_ikm(&[0u8]);
296 let (_, hkdf) = extract.finalize();
297 hkdf.expand(&(buf.len() as u16).to_be_bytes(), buf)
298 .expect("HDKF extract failure");
299 }
300}
301
302pub trait BlsPublicKeyType: 'static {
304 type Buffer: Clone + Debug + PartialEq + Sized + Zeroize;
306
307 type BufferSize: ArrayLength<u8>;
309 type BufferSizeWide: ArrayLength<u8>;
311
312 const ALG_TYPE: BlsCurves;
314 const JWK_CURVE: &'static str;
316 const JWK_CURVE_OKP: &'static str;
318
319 fn get_jwk_curve(_alg: Option<KeyAlg>) -> &'static str {
321 Self::JWK_CURVE
322 }
323
324 fn from_secret_scalar(secret: &Scalar) -> Self::Buffer;
326
327 fn from_public_bytes(key: &[u8]) -> Result<Self::Buffer, Error>;
329
330 fn with_bytes<O>(buf: &Self::Buffer, alg: Option<KeyAlg>, f: impl FnOnce(&[u8]) -> O) -> O;
332
333 fn with_bytes_uncompressed<O>(
335 buf: &Self::Buffer,
336 alg: Option<KeyAlg>,
337 f: impl FnOnce(&[u8]) -> O,
338 ) -> O;
339}
340
341#[derive(Debug)]
343pub struct G1;
344
345impl BlsPublicKeyType for G1 {
346 type Buffer = G1Affine;
347 type BufferSize = U48;
348 type BufferSizeWide = U96;
349
350 const ALG_TYPE: BlsCurves = BlsCurves::G1;
351 const JWK_CURVE: &'static str = "BLS12381G1";
352 const JWK_CURVE_OKP: &'static str = "BLS12381_G1";
353
354 #[inline]
355 fn from_secret_scalar(secret: &Scalar) -> Self::Buffer {
356 G1Affine::from(G1Projective::generator() * secret)
357 }
358
359 fn from_public_bytes(key: &[u8]) -> Result<Self::Buffer, Error> {
360 let res = if let Ok(buf) = key.try_into() {
361 G1Affine::from_compressed(buf).into_option()
362 } else if let Ok(buf) = key.try_into() {
363 G1Affine::from_uncompressed(buf).into_option()
364 } else {
365 None
366 };
367 res.ok_or_else(|| err_msg!(InvalidKeyData))
368 }
369
370 fn with_bytes<O>(buf: &Self::Buffer, _alg: Option<KeyAlg>, f: impl FnOnce(&[u8]) -> O) -> O {
371 f(buf.to_compressed().as_ref())
372 }
373
374 fn with_bytes_uncompressed<O>(
375 buf: &Self::Buffer,
376 _alg: Option<KeyAlg>,
377 f: impl FnOnce(&[u8]) -> O,
378 ) -> O {
379 f(buf.to_uncompressed().as_ref())
380 }
381}
382
383#[derive(Debug)]
385pub struct G2;
386
387impl BlsPublicKeyType for G2 {
388 type Buffer = G2Affine;
389 type BufferSize = U96;
390 type BufferSizeWide = U192;
391
392 const ALG_TYPE: BlsCurves = BlsCurves::G2;
393 const JWK_CURVE: &'static str = "BLS12381G2";
394 const JWK_CURVE_OKP: &'static str = "BLS12381_G2";
395
396 #[inline]
397 fn from_secret_scalar(secret: &Scalar) -> Self::Buffer {
398 G2Affine::from(G2Projective::generator() * secret)
399 }
400
401 fn from_public_bytes(key: &[u8]) -> Result<Self::Buffer, Error> {
402 let res = if let Ok(buf) = key.try_into() {
403 G2Affine::from_compressed(buf).into_option()
404 } else if let Ok(buf) = key.try_into() {
405 G2Affine::from_uncompressed(buf).into_option()
406 } else {
407 None
408 };
409 res.ok_or_else(|| err_msg!(InvalidKeyData))
410 }
411
412 fn with_bytes<O>(buf: &Self::Buffer, _alg: Option<KeyAlg>, f: impl FnOnce(&[u8]) -> O) -> O {
413 f(buf.to_compressed().as_ref())
414 }
415
416 fn with_bytes_uncompressed<O>(
417 buf: &Self::Buffer,
418 _alg: Option<KeyAlg>,
419 f: impl FnOnce(&[u8]) -> O,
420 ) -> O {
421 f(buf.to_uncompressed().as_ref())
422 }
423}
424
425impl TryFrom<&BlsKeyPair<G1>> for BlsKeyPair<G2> {
426 type Error = Error;
427
428 fn try_from(kp: &BlsKeyPair<G1>) -> Result<Self, Self::Error> {
429 if let Some(sec) = kp.secret.as_ref() {
430 Ok(BlsKeyPair {
431 secret: Some(sec.clone()),
432 public: G2::from_secret_scalar(&sec.0),
433 })
434 } else {
435 Err(err_msg!(InvalidKeyData, "No secret key available"))
436 }
437 }
438}
439
440impl TryFrom<&BlsKeyPair<G2>> for BlsKeyPair<G1> {
441 type Error = Error;
442
443 fn try_from(kp: &BlsKeyPair<G2>) -> Result<Self, Self::Error> {
444 if let Some(sec) = kp.secret.as_ref() {
445 Ok(BlsKeyPair {
446 secret: Some(sec.clone()),
447 public: G1::from_secret_scalar(&sec.0),
448 })
449 } else {
450 Err(err_msg!(InvalidKeyData, "No secret key available"))
451 }
452 }
453}
454
455#[cfg(test)]
456mod tests {
457 use base64::Engine;
458 use std::string::ToString;
459
460 use super::*;
461 use crate::repr::{ToPublicBytes, ToSecretBytes};
462
463 #[test]
465 fn key_gen_expected() {
466 let seed = &hex!(
467 "c55257c360c07c72029aebc1b53c05ed0362ada38ead3e3e9efa3708e5349553
468 1f09a6987599d18264c1e1c92f2cf141630c7a3c4ab7c81b2f001698e7463b04"
469 );
470 let kp = BlsKeyPair::<G1>::from_seed(&seed[..]).unwrap();
471 let sk = kp.to_secret_bytes().unwrap();
472 assert_eq!(
473 sk.as_hex().to_string(),
474 "0d7359d57963ab8fbbde1852dcf553fedbc31f464d80ee7d40ae683122b45070"
475 );
476 }
477
478 #[test]
479 fn g1_key_expected() {
480 let sk = hex!("0d7359d57963ab8fbbde1852dcf553fedbc31f464d80ee7d40ae683122b45070");
481 let kp = BlsKeyPair::<G1>::from_secret_bytes(&sk[..]).unwrap();
482 let pk = kp.to_public_bytes().unwrap();
483 assert_eq!(
484 pk.as_hex().to_string(),
485 "a2c975348667926acf12f3eecb005044e08a7a9b7d95f30bd281b55445107367a2e5d0558be7943c8bd13f9a1a7036fb"
486 );
487 assert_eq!(
488 BlsKeyPair::<G1>::from_public_bytes(pk.as_ref())
489 .unwrap()
490 .to_public_bytes()
491 .unwrap(),
492 pk
493 );
494 }
495
496 #[test]
497 fn g2_key_expected() {
498 let sk = hex!("0d7359d57963ab8fbbde1852dcf553fedbc31f464d80ee7d40ae683122b45070");
499 let kp = BlsKeyPair::<G2>::from_secret_bytes(&sk[..]).unwrap();
500 let pk = kp.to_public_bytes().unwrap();
501 assert_eq!(
502 pk.as_hex().to_string(),
503 "a5e43d5ecb7b8c01ceb3b91f7413b628ef02c6859dc42a4354b21f9195531988a648655037faafd1bac2fd2d7d9466180baa3705a45a6c597853db51eaf431616057fd8049c6bee8764292f9a104200a45a63ceae9d3c368643ab9e5ff0f8810"
504 );
505 assert_eq!(
506 BlsKeyPair::<G2>::from_public_bytes(pk.as_ref())
507 .unwrap()
508 .to_public_bytes()
509 .unwrap(),
510 pk
511 );
512 }
513
514 #[test]
515 fn g1_jwk_expected() {
516 let test_pvt = &hex!("0d7359d57963ab8fbbde1852dcf553fedbc31f464d80ee7d40ae683122b45070");
517 let test_pub_g1_x = &hex!("02c975348667926acf12f3eecb005044e08a7a9b7d95f30bd281b55445107367a2e5d0558be7943c8bd13f9a1a7036fb");
518 let test_pub_g1_y = &hex!("13f396ec1b79d6f461189d20a0d3f27718dd6efff3066c31380d785bce9957abc640d2f1301266d1e9d7b1e6da60da95");
519 let kp = BlsKeyPair::<G1>::from_secret_bytes(&test_pvt[..]).expect("Error creating key");
520
521 let jwk = kp.to_jwk_public(None).expect("Error converting key to JWK");
522 let jwk = JwkParts::try_from_str(&jwk).expect("Error parsing JWK");
523 assert_eq!(jwk.kty, JWK_KEY_TYPE_EC);
524 assert_eq!(jwk.crv, G1::JWK_CURVE);
525 assert_eq!(
526 jwk.x,
527 base64::engine::general_purpose::URL_SAFE_NO_PAD
528 .encode(test_pub_g1_x)
529 .as_str()
530 );
531 assert_eq!(
532 jwk.y,
533 base64::engine::general_purpose::URL_SAFE_NO_PAD
534 .encode(test_pub_g1_y)
535 .as_str()
536 );
537 assert_eq!(jwk.d, None);
538 let pk_load = BlsKeyPair::<G1>::from_jwk_parts(jwk).unwrap();
539 assert_eq!(kp.to_public_bytes(), pk_load.to_public_bytes());
540
541 let jwk = kp.to_jwk_secret(None).expect("Error converting key to JWK");
542 let jwk = JwkParts::from_slice(&jwk).expect("Error parsing JWK");
543 assert_eq!(jwk.kty, JWK_KEY_TYPE_EC);
544 assert_eq!(jwk.crv, G1::JWK_CURVE);
545 assert_eq!(
546 jwk.x,
547 base64::engine::general_purpose::URL_SAFE_NO_PAD
548 .encode(test_pub_g1_x)
549 .as_str()
550 );
551 assert_eq!(
552 jwk.y,
553 base64::engine::general_purpose::URL_SAFE_NO_PAD
554 .encode(test_pub_g1_y)
555 .as_str()
556 );
557 let mut sk_rev = *test_pvt;
558 sk_rev.reverse(); assert_eq!(
560 jwk.d,
561 base64::engine::general_purpose::URL_SAFE_NO_PAD
562 .encode(sk_rev)
563 .as_str()
564 );
565 let _sk_load = BlsKeyPair::<G1>::from_jwk_parts(jwk).unwrap();
566 }
571
572 #[cfg(feature = "any_key")]
573 #[test]
574 fn g1_jwk_any() {
576 use crate::alg::{any::AnyKey, AnyKeyCreate, BlsCurves, KeyAlg};
577 use alloc::boxed::Box;
578
579 let test_jwk = r#"
580 {
581 "kty": "EC",
582 "crv": "BLS12381G1",
583 "x": "Ed4GBGLVasEp4ejPz44CvllbTldfLLcm2QcIJluBL6p_SQmRrZvJNa3YaJ-Wx8Im",
584 "y": "AbdYAsAb20CHzlVW6VBO9i16BcGOmcYiMLlBEh9DfAiDu_1ZIAd1zewSi9f6517g",
585 "d": "3nc6_s38FVVlawbwmPFOjB4TlAPy_K2Tx39I7XnEnDc"
586 }
587 "#;
588 let test_jwk_g2 = r#"
589 {
590 "kty": "EC",
591 "crv": "BLS12381G2",
592 "x": "GJ4CTKTdbhJ606E_zoXvBerW3susF0rCRkkOjSSoXzAbo75pF5a_TuUGrYICNRpKA6cQe4FqWEgLW0KKW3-5nAXX1BEKk2flns1VE-2hpbRZqmfA0xPyLPomtUBmLZsR",
593 "y": "AnUhMCJ0P0MITDiU4Xf_NHGiJZoyVXGol99Xrrn4fqAcQ-SIXTgbIEP3aBHvsaiQCKqnpWzWycJ4AYOVcaDgKs-ms5bweXiDAafBO-tiuCcrqeAJzY_ZJtNon8IvP_5-",
594 "d": "3nc6_s38FVVlawbwmPFOjB4TlAPy_K2Tx39I7XnEnDc"
595 }
596 "#;
597 let key = Box::<AnyKey>::from_jwk(test_jwk).expect("Error decoding BLS key JWK");
598 assert_eq!(key.algorithm(), KeyAlg::Bls12_381(BlsCurves::G1));
599 let as_g1 = key
600 .downcast_ref::<BlsKeyPair<G1>>()
601 .expect("Error downcasting BLS key");
602 let _ = as_g1
603 .to_jwk_public(None)
604 .expect("Error converting key to JWK");
605 let g2key = key
606 .convert_key(KeyAlg::Bls12_381(BlsCurves::G2))
607 .expect("Error converting keypair");
608 assert_eq!(g2key.algorithm(), KeyAlg::Bls12_381(BlsCurves::G2));
609 let as_g2 = g2key
610 .downcast_ref::<BlsKeyPair<G2>>()
611 .expect("Error downcasting BLS key");
612 let g2_expect =
613 BlsKeyPair::<G2>::from_jwk(test_jwk_g2).expect("Error decoding BLS key JWK");
614 assert_eq!(&g2_expect, as_g2);
615 }
616
617 #[cfg(feature = "any_key")]
618 #[test]
619 fn g1_jwk_any_compat() {
621 use crate::alg::{any::AnyKey, BlsCurves, KeyAlg};
622 use alloc::boxed::Box;
623
624 let test_jwk_compat = r#"
625 {
626 "crv":"BLS12381_G1",
627 "kty":"OKP",
628 "x":"lQ-SOS1aBydOBEHaKThf667LGeZVe3EiVSLXRd8Y3DBuR8ll4VJONAlytjG1CAc7",
629 "d":"XMltkZ-3H94Rl8orHfWufxrPe1hdURFAUKdyt0SNdrk"
630 }
631 "#;
632 let test_jwk_new = r#"
633 {
634 "crv":"BLS12381G1",
635 "kty":"EC",
636 "x":"FQ-SOS1aBydOBEHaKThf667LGeZVe3EiVSLXRd8Y3DBuR8ll4VJONAlytjG1CAc7",
637 "y":"CvFVTlp_IO8NxTIekI8Ik9drVLNUCQl6sfo6zDa7oOiaoxqTfTnU70HLJzjHQ6_m",
638 "d":"uXaNRLdyp1BAEVFdWHvPGn-u9R0rypcR3h-3n5FtyVw"
639 }
640 "#;
641 let key = Box::<AnyKey>::from_jwk(test_jwk_compat).expect("Error decoding BLS key JWK");
642 assert_eq!(key.algorithm(), KeyAlg::Bls12_381(BlsCurves::G1));
643 let as_bls = key
644 .downcast_ref::<BlsKeyPair<G1>>()
645 .expect("Error downcasting BLS key");
646
647 let knew = BlsKeyPair::<G1>::from_jwk(test_jwk_new).expect("Error decoding BLS key JWK");
648 assert_eq!(as_bls, &knew);
649
650 let _ = as_bls
651 .to_jwk_public(None)
652 .expect("Error converting key to JWK");
653 }
654}