1#![forbid(unsafe_code)]
2#![warn(rust_2018_idioms)]
3#![warn(future_incompatible)]
4#![forbid(missing_docs)]
5
6use hex_literal::hex;
9use k256::{
10 AffinePoint, Scalar, Secp256k1,
11 elliptic_curve::{
12 Curve,
13 generic_array::{GenericArray, typenum::Unsigned},
14 },
15};
16use rand::{CryptoRng, Rng, RngCore, SeedableRng};
17use std::sync::LazyLock;
18use zeroize::ZeroizeOnDrop;
19
20pub use ic_principal::Principal as CanisterId;
21
22#[derive(Clone, Debug)]
24pub enum KeyDecodingError {
25 InvalidKeyEncoding(String),
27 InvalidPemEncoding(String),
29 UnexpectedPemLabel(String),
31}
32
33#[derive(Clone, Debug)]
35pub enum InvalidTaprootHash {
36 InvalidLength,
38 InvalidScalar,
41}
42
43impl std::fmt::Display for KeyDecodingError {
44 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
45 write!(f, "{self:?}")
46 }
47}
48
49impl std::error::Error for KeyDecodingError {}
50
51static ECDSA_OID: LazyLock<simple_asn1::OID> =
53 LazyLock::new(|| simple_asn1::oid!(1, 2, 840, 10045, 2, 1));
54
55static SECP256K1_OID: LazyLock<simple_asn1::OID> =
59 LazyLock::new(|| simple_asn1::oid!(1, 3, 132, 0, 10));
60
61#[derive(Clone, Debug)]
63pub struct DerivationIndex(pub Vec<u8>);
64
65#[derive(Clone, Debug)]
69pub struct DerivationPath {
70 path: Vec<DerivationIndex>,
71}
72
73impl DerivationPath {
74 pub fn new_bip32(bip32: &[u32]) -> Self {
76 let mut path = Vec::with_capacity(bip32.len());
77 for n in bip32 {
78 path.push(DerivationIndex(n.to_be_bytes().to_vec()));
79 }
80 Self::new(path)
81 }
82
83 pub fn new(path: Vec<DerivationIndex>) -> Self {
85 Self { path }
86 }
87
88 pub fn from_canister_id_and_path(canister_id: &[u8], path: &[Vec<u8>]) -> Self {
90 let mut vpath = Vec::with_capacity(1 + path.len());
91 vpath.push(DerivationIndex(canister_id.to_vec()));
92
93 for n in path {
94 vpath.push(DerivationIndex(n.to_vec()));
95 }
96 Self::new(vpath)
97 }
98
99 pub fn len(&self) -> usize {
101 self.path.len()
102 }
103
104 pub fn is_empty(&self) -> bool {
106 self.len() == 0
107 }
108
109 pub fn path(&self) -> &[DerivationIndex] {
111 &self.path
112 }
113
114 fn ckd(idx: &[u8], input: &[u8], chain_code: &[u8; 32]) -> ([u8; 32], Scalar) {
115 use hmac::{Hmac, Mac};
116 use k256::{elliptic_curve::ops::Reduce, sha2::Sha512};
117
118 let mut hmac = Hmac::<Sha512>::new_from_slice(chain_code)
119 .expect("HMAC-SHA-512 should accept 256 bit key");
120
121 hmac.update(input);
122 hmac.update(idx);
123
124 let hmac_output: [u8; 64] = hmac.finalize().into_bytes().into();
125
126 let fb = k256::FieldBytes::from_slice(&hmac_output[..32]);
127 let next_offset = <k256::Scalar as Reduce<k256::U256>>::reduce_bytes(fb);
128 let next_chain_key: [u8; 32] = hmac_output[32..].to_vec().try_into().expect("Correct size");
129
130 if next_offset.to_bytes().to_vec() != hmac_output[..32] {
132 let mut next_input = [0u8; 33];
133 next_input[0] = 0x01;
134 next_input[1..].copy_from_slice(&next_chain_key);
135 Self::ckd(idx, &next_input, chain_code)
136 } else {
137 (next_chain_key, next_offset)
138 }
139 }
140
141 fn ckd_pub(
142 idx: &[u8],
143 pt: AffinePoint,
144 chain_code: &[u8; 32],
145 ) -> ([u8; 32], Scalar, AffinePoint) {
146 use k256::ProjectivePoint;
147 use k256::elliptic_curve::{
148 group::GroupEncoding, group::prime::PrimeCurveAffine, ops::MulByGenerator,
149 };
150
151 let mut ckd_input = pt.to_bytes();
152
153 let pt: ProjectivePoint = pt.into();
154
155 loop {
156 let (next_chain_code, next_offset) = Self::ckd(idx, &ckd_input, chain_code);
157
158 let next_pt = (pt + k256::ProjectivePoint::mul_by_generator(&next_offset)).to_affine();
159
160 if !bool::from(next_pt.is_identity()) {
162 return (next_chain_code, next_offset, next_pt);
163 }
164
165 ckd_input[0] = 0x01;
167 ckd_input[1..].copy_from_slice(&next_chain_code);
168 }
169 }
170
171 fn derive_offset(
172 &self,
173 pt: AffinePoint,
174 chain_code: &[u8; 32],
175 ) -> (AffinePoint, Scalar, [u8; 32]) {
176 let mut offset = Scalar::ZERO;
177 let mut pt = pt;
178 let mut chain_code = *chain_code;
179
180 for idx in self.path() {
181 let (next_chain_code, next_offset, next_pt) = Self::ckd_pub(&idx.0, pt, &chain_code);
182 chain_code = next_chain_code;
183 pt = next_pt;
184 offset = offset.add(&next_offset);
185 }
186
187 (pt, offset, chain_code)
188 }
189}
190
191const PEM_HEADER_PKCS8: &str = "PRIVATE KEY";
192const PEM_HEADER_RFC5915: &str = "EC PRIVATE KEY";
193
194fn der_encode_rfc5915_privatekey(
214 secret_key: &[u8],
215 include_curve: bool,
216 public_key: Option<Vec<u8>>,
217) -> Vec<u8> {
218 use simple_asn1::*;
219
220 let ecdsa_version = ASN1Block::Integer(0, BigInt::new(num_bigint::Sign::Plus, vec![1]));
224 let key_bytes = ASN1Block::OctetString(0, secret_key.to_vec());
225 let mut key_blocks = vec![ecdsa_version, key_bytes];
226
227 if include_curve {
228 let tag0 = BigUint::new(vec![0]);
229 let secp256k1_oid = Box::new(ASN1Block::ObjectIdentifier(0, SECP256K1_OID.clone()));
230 let oid_param = ASN1Block::Explicit(ASN1Class::ContextSpecific, 0, tag0, secp256k1_oid);
231 key_blocks.push(oid_param);
232 }
233
234 if let Some(public_key) = public_key {
235 let tag1 = BigUint::new(vec![1]);
236 let pk_bs = Box::new(ASN1Block::BitString(
237 0,
238 public_key.len() * 8,
239 public_key.to_vec(),
240 ));
241 let pk_param = ASN1Block::Explicit(ASN1Class::ContextSpecific, 0, tag1, pk_bs);
242 key_blocks.push(pk_param);
243 }
244
245 to_der(&ASN1Block::Sequence(0, key_blocks))
246 .expect("Failed to encode ECDSA private key as RFC 5915 DER")
247}
248
249fn der_decode_rfc5915_privatekey(der: &[u8]) -> Result<Vec<u8>, KeyDecodingError> {
250 use simple_asn1::*;
251
252 let der = simple_asn1::from_der(der)
253 .map_err(|e| KeyDecodingError::InvalidKeyEncoding(format!("{e:?}")))?;
254
255 let seq = match der.len() {
256 1 => der.first(),
257 x => {
258 return Err(KeyDecodingError::InvalidKeyEncoding(format!(
259 "Unexpected number of elements {x}"
260 )));
261 }
262 };
263
264 if let Some(ASN1Block::Sequence(_, seq)) = seq {
265 match seq.first() {
267 Some(ASN1Block::Integer(_, _version)) => {}
268 _ => {
269 return Err(KeyDecodingError::InvalidKeyEncoding(
270 "Version field was not an integer".to_string(),
271 ));
272 }
273 };
274
275 let private_key = match seq.get(1) {
277 Some(ASN1Block::OctetString(_, sk)) => sk.clone(),
278 _ => {
279 return Err(KeyDecodingError::InvalidKeyEncoding(
280 "Not an octet string".to_string(),
281 ));
282 }
283 };
284
285 Ok(private_key)
289 } else {
290 Err(KeyDecodingError::InvalidKeyEncoding(
291 "Not a sequence".to_string(),
292 ))
293 }
294}
295
296fn der_encode_pkcs8_rfc5208_private_key(secret_key: &[u8]) -> Vec<u8> {
297 use simple_asn1::*;
298
299 let pkcs8_version = ASN1Block::Integer(0, BigInt::new(num_bigint::Sign::Plus, vec![0]));
303 let ecdsa_oid = ASN1Block::ObjectIdentifier(0, ECDSA_OID.clone());
304 let secp256k1_oid = ASN1Block::ObjectIdentifier(0, SECP256K1_OID.clone());
305
306 let alg_id = ASN1Block::Sequence(0, vec![ecdsa_oid, secp256k1_oid]);
307
308 let octet_string =
309 ASN1Block::OctetString(0, der_encode_rfc5915_privatekey(secret_key, false, None));
310
311 let blocks = vec![pkcs8_version, alg_id, octet_string];
312
313 simple_asn1::to_der(&ASN1Block::Sequence(0, blocks))
314 .expect("Failed to encode ECDSA private key as DER")
315}
316
317fn der_encode_ecdsa_spki_pubkey(public_point: &[u8]) -> Vec<u8> {
321 use simple_asn1::*;
322
323 let ecdsa_oid = ASN1Block::ObjectIdentifier(0, ECDSA_OID.clone());
327 let secp256k1_oid = ASN1Block::ObjectIdentifier(0, SECP256K1_OID.clone());
328 let alg_id = ASN1Block::Sequence(0, vec![ecdsa_oid, secp256k1_oid]);
329
330 let key_bytes = ASN1Block::BitString(0, public_point.len() * 8, public_point.to_vec());
331
332 let blocks = vec![alg_id, key_bytes];
333
334 simple_asn1::to_der(&ASN1Block::Sequence(0, blocks))
335 .expect("Failed to encode ECDSA private key as DER")
336}
337
338fn pem_encode(raw: &[u8], label: &'static str) -> String {
339 pem::encode(&pem::Pem {
340 tag: label.to_string(),
341 contents: raw.to_vec(),
342 })
343}
344
345fn bip341_generate_tweak(pk_x: &[u8], ttr: &[u8]) -> Result<Scalar, InvalidTaprootHash> {
355 if pk_x.len() != 32 {
357 return Err(InvalidTaprootHash::InvalidLength);
358 }
359 if !(ttr.is_empty() || ttr.len() == 32) {
360 return Err(InvalidTaprootHash::InvalidLength);
361 }
362
363 use k256::elliptic_curve::PrimeField;
364 use sha2::Digest;
365
366 let tag = "TapTweak";
367
368 let h_tag: [u8; 32] = sha2::Sha256::digest(tag).into();
369
370 let mut sha256 = sha2::Sha256::new();
371 sha256.update(h_tag);
372 sha256.update(h_tag);
373 sha256.update(pk_x);
374 sha256.update(ttr);
375 let bytes: [u8; 32] = sha256.finalize().into();
376
377 let fb = k256::FieldBytes::from_slice(&bytes);
378 let s = k256::Scalar::from_repr(*fb);
379
380 if bool::from(s.is_some()) {
381 Ok(s.unwrap())
382 } else {
383 Err(InvalidTaprootHash::InvalidScalar)
384 }
385}
386
387#[derive(Clone, ZeroizeOnDrop)]
389pub struct PrivateKey {
390 key: k256::SecretKey,
391}
392
393impl PrivateKey {
394 pub fn generate() -> Self {
396 let mut rng = rand::thread_rng();
397 Self::generate_using_rng(&mut rng)
398 }
399
400 pub fn generate_using_rng<R: RngCore + CryptoRng>(rng: &mut R) -> Self {
402 let key = k256::SecretKey::random(rng);
403 Self { key }
404 }
405
406 pub fn generate_from_seed(seed: &[u8]) -> Self {
413 use k256::{elliptic_curve::ops::Reduce, sha2::Digest, sha2::Sha256};
414
415 let digest: [u8; 32] = {
416 let mut sha256 = Sha256::new();
417 sha256.update(seed);
418 sha256.finalize().into()
419 };
420
421 let scalar = {
422 let fb = k256::FieldBytes::from_slice(&digest);
423 let scalar = <k256::Scalar as Reduce<k256::U256>>::reduce_bytes(fb);
424
425 k256::NonZeroScalar::new(scalar).expect("Not zero")
432 };
433
434 Self {
435 key: k256::SecretKey::from(scalar),
436 }
437 }
438
439 pub fn deserialize_sec1(bytes: &[u8]) -> Result<Self, KeyDecodingError> {
441 let byte_array: [u8; <Secp256k1 as Curve>::FieldBytesSize::USIZE] =
442 bytes.try_into().map_err(|_e| {
443 KeyDecodingError::InvalidKeyEncoding(format!("invalid key size = {}.", bytes.len()))
444 })?;
445
446 let key = k256::SecretKey::from_bytes(&GenericArray::from(byte_array))
447 .map_err(|e| KeyDecodingError::InvalidKeyEncoding(format!("{e:?}")))?;
448 Ok(Self { key })
449 }
450
451 pub fn deserialize_pkcs8_der(der: &[u8]) -> Result<Self, KeyDecodingError> {
453 use k256::pkcs8::DecodePrivateKey;
454 let key = k256::SecretKey::from_pkcs8_der(der)
455 .map_err(|e| KeyDecodingError::InvalidKeyEncoding(format!("{e:?}")))?;
456 Ok(Self { key })
457 }
458
459 pub fn deserialize_pkcs8_pem(pem: &str) -> Result<Self, KeyDecodingError> {
461 let der =
462 pem::parse(pem).map_err(|e| KeyDecodingError::InvalidPemEncoding(format!("{e:?}")))?;
463 if der.tag != PEM_HEADER_PKCS8 {
464 return Err(KeyDecodingError::UnexpectedPemLabel(der.tag));
465 }
466
467 Self::deserialize_pkcs8_der(&der.contents)
468 }
469
470 pub fn deserialize_rfc5915_der(der: &[u8]) -> Result<Self, KeyDecodingError> {
472 let key = der_decode_rfc5915_privatekey(der)?;
473 Self::deserialize_sec1(&key)
474 }
475
476 pub fn deserialize_rfc5915_pem(pem: &str) -> Result<Self, KeyDecodingError> {
478 let der =
479 pem::parse(pem).map_err(|e| KeyDecodingError::InvalidPemEncoding(format!("{e:?}")))?;
480 if der.tag != PEM_HEADER_RFC5915 {
481 return Err(KeyDecodingError::UnexpectedPemLabel(der.tag));
482 }
483 Self::deserialize_rfc5915_der(&der.contents)
484 }
485
486 pub fn serialize_sec1(&self) -> Vec<u8> {
492 self.key.to_bytes().to_vec()
493 }
494
495 pub fn serialize_pkcs8_der(&self) -> Vec<u8> {
497 der_encode_pkcs8_rfc5208_private_key(&self.serialize_sec1())
498 }
499
500 pub fn serialize_pkcs8_pem(&self) -> String {
502 pem_encode(&self.serialize_pkcs8_der(), PEM_HEADER_PKCS8)
503 }
504
505 pub fn serialize_rfc5915_der(&self) -> Vec<u8> {
507 let sk = self.serialize_sec1();
508 let pk = self.public_key().serialize_sec1(false);
509 der_encode_rfc5915_privatekey(&sk, true, Some(pk))
510 }
511
512 pub fn serialize_rfc5915_pem(&self) -> String {
514 pem_encode(&self.serialize_rfc5915_der(), PEM_HEADER_RFC5915)
515 }
516
517 pub fn sign_message_with_ecdsa(&self, message: &[u8]) -> [u8; 64] {
522 use k256::ecdsa::{Signature, signature::Signer};
523
524 let ecdsa = k256::ecdsa::SigningKey::from(&self.key);
525 let sig: Signature = ecdsa.sign(message);
526 sig.to_bytes().into()
527 }
528
529 pub fn sign_digest_with_ecdsa(&self, digest: &[u8]) -> [u8; 64] {
533 if digest.len() < 16 {
534 let mut zdigest = [0u8; 32];
537 let z_prefix_len = zdigest.len() - digest.len();
538 zdigest[z_prefix_len..].copy_from_slice(digest);
539 return self.sign_digest_with_ecdsa(&zdigest);
540 }
541
542 use k256::ecdsa::{Signature, signature::hazmat::PrehashSigner};
543 let ecdsa = k256::ecdsa::SigningKey::from(&self.key);
544 let sig: Signature = ecdsa.sign_prehash(digest).expect("Failed to sign digest");
545 sig.to_bytes().into()
546 }
547
548 fn sign_bip340_with_aux_rand(&self, message: &[u8], aux_rand: &[u8; 32]) -> Option<[u8; 64]> {
553 let bip340 = k256::schnorr::SigningKey::from(&self.key);
554
555 bip340
556 .sign_raw(message, aux_rand)
557 .map(|s| s.to_bytes())
558 .ok()
559 }
560
561 pub fn sign_message_with_bip340<R: Rng + CryptoRng>(
563 &self,
564 message: &[u8],
565 rng: &mut R,
566 ) -> [u8; 64] {
567 loop {
568 let aux_rand = rng.r#gen::<[u8; 32]>();
574 if let Some(sig) = self.sign_bip340_with_aux_rand(message, &aux_rand) {
575 return sig;
576 }
577 }
578 }
579
580 pub fn sign_message_with_bip340_no_rng(&self, message: &[u8]) -> [u8; 64] {
589 let mut rng = rand_chacha::ChaCha20Rng::seed_from_u64(0);
590 self.sign_message_with_bip340(message, &mut rng)
591 }
592
593 fn derive_bip341(&self, ttr: &[u8]) -> Result<Self, InvalidTaprootHash> {
595 let pk = self.public_key().serialize_sec1(true);
596
597 let t = bip341_generate_tweak(&pk[1..], ttr)?;
598 let pk_y_is_even = pk[0] == 0x02;
599
600 let z = if pk_y_is_even {
601 self.key.to_nonzero_scalar().as_ref() + t
602 } else {
603 self.key.to_nonzero_scalar().as_ref().negate() + t
604 };
605
606 let nz_ds = k256::NonZeroScalar::new(z).expect("Derivation always produces non-zero sum");
607
608 Ok(Self {
609 key: k256::SecretKey::from(nz_ds),
610 })
611 }
612
613 pub fn sign_message_with_bip341<R: Rng + CryptoRng>(
615 &self,
616 message: &[u8],
617 rng: &mut R,
618 taproot_tree_hash: &[u8],
619 ) -> Result<[u8; 64], InvalidTaprootHash> {
620 if !taproot_tree_hash.is_empty() && taproot_tree_hash.len() != 32 {
621 return Err(InvalidTaprootHash::InvalidLength);
622 }
623
624 let tweaked_key = self.derive_bip341(taproot_tree_hash)?;
625 Ok(tweaked_key.sign_message_with_bip340(message, rng))
626 }
627
628 pub fn sign_message_with_bip341_no_rng(
637 &self,
638 message: &[u8],
639 taproot_tree_hash: &[u8],
640 ) -> Result<[u8; 64], InvalidTaprootHash> {
641 let mut rng = rand_chacha::ChaCha20Rng::seed_from_u64(0);
642 self.sign_message_with_bip341(message, &mut rng, taproot_tree_hash)
643 }
644
645 pub fn public_key(&self) -> PublicKey {
647 PublicKey {
648 key: self.key.public_key(),
649 }
650 }
651
652 pub fn derive_subkey(&self, derivation_path: &DerivationPath) -> (Self, [u8; 32]) {
664 let chain_code = [0u8; 32];
665 self.derive_subkey_with_chain_code(derivation_path, &chain_code)
666 }
667
668 pub fn derive_subkey_with_chain_code(
681 &self,
682 derivation_path: &DerivationPath,
683 chain_code: &[u8; 32],
684 ) -> (Self, [u8; 32]) {
685 use k256::NonZeroScalar;
686
687 let public_key: AffinePoint = self.key.public_key().to_projective().to_affine();
688 let (_pt, offset, derived_chain_code) =
689 derivation_path.derive_offset(public_key, chain_code);
690
691 let derived_scalar = self.key.to_nonzero_scalar().as_ref().add(&offset);
692
693 let nz_ds =
694 NonZeroScalar::new(derived_scalar).expect("Derivation always produces non-zero sum");
695
696 let derived_key = Self {
697 key: k256::SecretKey::from(nz_ds),
698 };
699
700 (derived_key, derived_chain_code)
701 }
702}
703
704#[derive(Copy, Clone, Eq, PartialEq, Debug)]
706pub enum MasterPublicKeyId {
707 EcdsaKey1,
709 EcdsaTestKey1,
711 SchnorrKey1,
713 SchnorrTestKey1,
715}
716
717#[derive(Copy, Clone, Eq, PartialEq, Debug)]
719pub enum PocketIcMasterPublicKeyId {
720 EcdsaKey1,
722 EcdsaTestKey1,
724 SchnorrKey1,
728 SchnorrTestKey1,
732 EcdsaDfxTestKey,
734 SchnorrDfxTestKey,
738}
739
740#[derive(Clone, Eq, PartialEq, Debug)]
742pub struct PublicKey {
743 key: k256::PublicKey,
744}
745
746impl PublicKey {
747 pub fn mainnet_key(key_id: MasterPublicKeyId) -> Self {
749 match key_id {
750 MasterPublicKeyId::EcdsaKey1 => Self::deserialize_sec1(&hex!(
751 "02121bc3a5c38f38ca76487c72007ebbfd34bc6c4cb80a671655aa94585bbd0a02"
752 ))
753 .expect("Hardcoded master key was rejected"),
754 MasterPublicKeyId::EcdsaTestKey1 => Self::deserialize_sec1(&hex!(
755 "02f9ac345f6be6db51e1c5612cddb59e72c3d0d493c994d12035cf13257e3b1fa7"
756 ))
757 .expect("Hardcoded master key was rejected"),
758 MasterPublicKeyId::SchnorrKey1 => Self::deserialize_sec1(&hex!(
759 "02246e29785f06d37a8a50c49f6152a34df74738f8c13a44f59fef4cbe90eb13ac"
760 ))
761 .expect("Hardcoded master key was rejected"),
762 MasterPublicKeyId::SchnorrTestKey1 => Self::deserialize_sec1(&hex!(
763 "037a651a2e5ef3d1ef63e84c4c4caa029fa4a43a347a91e4d84a8e846853d51be1"
764 ))
765 .expect("Hardcoded master key was rejected"),
766 }
767 }
768
769 pub fn pocketic_key(key_id: PocketIcMasterPublicKeyId) -> Self {
774 match key_id {
775 PocketIcMasterPublicKeyId::EcdsaKey1 | PocketIcMasterPublicKeyId::SchnorrKey1 => {
776 Self::deserialize_sec1(&hex!(
780 "036ad6e838b46811ad79c37b2f4b854b7a05f406715b2935edc5d3251e7666977b"
781 ))
782 .expect("Hardcoded master key was rejected")
783 }
784 PocketIcMasterPublicKeyId::EcdsaTestKey1
785 | PocketIcMasterPublicKeyId::SchnorrTestKey1 => {
786 Self::deserialize_sec1(&hex!(
790 "03cc365e15cb552589c7175717b2ac63d1050b9bb2e5aed35432b1b1be55d3abcf"
791 ))
792 .expect("Hardcoded master key was rejected")
793 }
794 PocketIcMasterPublicKeyId::EcdsaDfxTestKey
795 | PocketIcMasterPublicKeyId::SchnorrDfxTestKey => {
796 Self::deserialize_sec1(&hex!(
800 "03e6f78b1a90e361c5cc9903f73bb8acbe3bc17ad01e82554d25cf0ecd70c67484"
801 ))
802 .expect("Hardcoded master key was rejected")
803 }
804 }
805 }
806
807 pub fn derive_mainnet_key(
812 key_id: MasterPublicKeyId,
813 canister_id: &CanisterId,
814 derivation_path: &[Vec<u8>],
815 ) -> (Self, [u8; 32]) {
816 let mk = PublicKey::mainnet_key(key_id);
817 mk.derive_subkey(&DerivationPath::from_canister_id_and_path(
818 canister_id.as_slice(),
819 derivation_path,
820 ))
821 }
822
823 pub fn derive_pocketic_key(
828 key_id: PocketIcMasterPublicKeyId,
829 canister_id: &CanisterId,
830 derivation_path: &[Vec<u8>],
831 ) -> (Self, [u8; 32]) {
832 let mk = PublicKey::pocketic_key(key_id);
833 mk.derive_subkey(&DerivationPath::from_canister_id_and_path(
834 canister_id.as_slice(),
835 derivation_path,
836 ))
837 }
838
839 pub fn deserialize_sec1(bytes: &[u8]) -> Result<Self, KeyDecodingError> {
846 let key = k256::PublicKey::from_sec1_bytes(bytes)
847 .map_err(|e| KeyDecodingError::InvalidKeyEncoding(format!("{e:?}")))?;
848 Ok(Self { key })
849 }
850
851 pub fn deserialize_bip340(bytes: &[u8]) -> Result<Self, KeyDecodingError> {
859 if bytes.len() != 32 {
860 return Err(KeyDecodingError::InvalidKeyEncoding(format!(
861 "Expected 32 bytes got {}",
862 bytes.len()
863 )));
864 }
865
866 let mut sec1 = [0u8; 33];
867 sec1[0] = 0x02; sec1[1..].copy_from_slice(bytes);
869
870 Self::deserialize_sec1(&sec1)
871 }
872
873 pub fn deserialize_der(bytes: &[u8]) -> Result<Self, KeyDecodingError> {
875 use k256::pkcs8::DecodePublicKey;
876 let key = k256::PublicKey::from_public_key_der(bytes)
877 .map_err(|e| KeyDecodingError::InvalidKeyEncoding(format!("{e:?}")))?;
878 Ok(Self { key })
879 }
880
881 pub fn deserialize_pem(pem: &str) -> Result<Self, KeyDecodingError> {
883 let der =
884 pem::parse(pem).map_err(|e| KeyDecodingError::InvalidPemEncoding(format!("{e:?}")))?;
885 if der.tag != "PUBLIC KEY" {
886 return Err(KeyDecodingError::UnexpectedPemLabel(der.tag));
887 }
888
889 Self::deserialize_der(&der.contents)
890 }
891
892 pub fn serialize_sec1(&self, compressed: bool) -> Vec<u8> {
898 use k256::elliptic_curve::sec1::ToEncodedPoint;
899 self.key.to_encoded_point(compressed).as_bytes().to_vec()
900 }
901
902 pub fn serialize_bip340(&self) -> Vec<u8> {
909 let sec1 = self.serialize_sec1(true);
910
911 sec1[1..].to_vec()
914 }
915
916 pub fn serialize_der(&self) -> Vec<u8> {
918 der_encode_ecdsa_spki_pubkey(&self.serialize_sec1(false))
919 }
920
921 pub fn serialize_pem(&self) -> String {
923 pem_encode(&self.serialize_der(), "PUBLIC KEY")
924 }
925
926 pub fn verify_signature(&self, message: &[u8], signature: &[u8]) -> bool {
928 self.verify_ecdsa_signature(message, signature)
929 }
930
931 pub fn verify_signature_with_malleability(&self, message: &[u8], signature: &[u8]) -> bool {
933 self.verify_ecdsa_signature_with_malleability(message, signature)
934 }
935
936 pub fn verify_signature_prehashed(&self, digest: &[u8], signature: &[u8]) -> bool {
938 self.verify_ecdsa_signature_prehashed(digest, signature)
939 }
940
941 pub fn verify_signature_prehashed_with_malleability(
943 &self,
944 digest: &[u8],
945 signature: &[u8],
946 ) -> bool {
947 self.verify_ecdsa_signature_prehashed_with_malleability(digest, signature)
948 }
949
950 pub fn verify_ecdsa_signature(&self, message: &[u8], signature: &[u8]) -> bool {
956 use k256::ecdsa::signature::Verifier;
957 let signature = match k256::ecdsa::Signature::try_from(signature) {
958 Ok(sig) => sig,
959 Err(_) => return false,
960 };
961
962 let ecdsa = k256::ecdsa::VerifyingKey::from(&self.key);
963 ecdsa.verify(message, &signature).is_ok()
964 }
965
966 pub fn verify_ecdsa_signature_with_malleability(
981 &self,
982 message: &[u8],
983 signature: &[u8],
984 ) -> bool {
985 use k256::ecdsa::signature::Verifier;
986 let signature = match k256::ecdsa::Signature::try_from(signature) {
987 Ok(sig) => sig,
988 Err(_) => return false,
989 };
990
991 let ecdsa = k256::ecdsa::VerifyingKey::from(&self.key);
992 if let Some(normalized) = signature.normalize_s() {
993 ecdsa.verify(message, &normalized).is_ok()
994 } else {
995 ecdsa.verify(message, &signature).is_ok()
996 }
997 }
998
999 pub fn verify_ecdsa_signature_prehashed(&self, digest: &[u8], signature: &[u8]) -> bool {
1001 if digest.len() < 16 {
1002 let mut zdigest = [0u8; 32];
1003 let z_prefix_len = zdigest.len() - digest.len();
1004 zdigest[z_prefix_len..].copy_from_slice(digest);
1005 return self.verify_ecdsa_signature_prehashed(&zdigest, signature);
1006 }
1007
1008 use k256::ecdsa::signature::hazmat::PrehashVerifier;
1009
1010 let signature = match k256::ecdsa::Signature::try_from(signature) {
1011 Ok(sig) => sig,
1012 Err(_) => return false,
1013 };
1014
1015 let ecdsa = k256::ecdsa::VerifyingKey::from(&self.key);
1016 ecdsa.verify_prehash(digest, &signature).is_ok()
1017 }
1018
1019 pub fn verify_ecdsa_signature_prehashed_with_malleability(
1032 &self,
1033 digest: &[u8],
1034 signature: &[u8],
1035 ) -> bool {
1036 if digest.len() < 16 {
1037 let mut zdigest = [0u8; 32];
1038 let z_prefix_len = zdigest.len() - digest.len();
1039 zdigest[z_prefix_len..].copy_from_slice(digest);
1040 return self.verify_ecdsa_signature_prehashed_with_malleability(&zdigest, signature);
1041 }
1042
1043 use k256::ecdsa::signature::hazmat::PrehashVerifier;
1044
1045 let signature = match k256::ecdsa::Signature::try_from(signature) {
1046 Ok(sig) => sig,
1047 Err(_) => return false,
1048 };
1049
1050 let ecdsa = k256::ecdsa::VerifyingKey::from(&self.key);
1051 if let Some(normalized) = signature.normalize_s() {
1052 ecdsa.verify_prehash(digest, &normalized).is_ok()
1053 } else {
1054 ecdsa.verify_prehash(digest, &signature).is_ok()
1055 }
1056 }
1057
1058 pub fn verify_bip340_signature(&self, message: &[u8], signature: &[u8]) -> bool {
1060 use k256::schnorr::signature::hazmat::PrehashVerifier;
1061
1062 let signature = match k256::schnorr::Signature::try_from(signature) {
1063 Ok(sig) => sig,
1064 Err(_) => return false,
1065 };
1066
1067 let pt = self.serialize_sec1(true);
1068
1069 match k256::schnorr::VerifyingKey::from_bytes(&pt[1..]) {
1071 Ok(bip340) => bip340.verify_prehash(message, &signature).is_ok(),
1072 _ => false,
1073 }
1074 }
1075
1076 fn derive_bip341(&self, ttr: &[u8]) -> Result<Self, InvalidTaprootHash> {
1078 use k256::elliptic_curve::ops::MulByGenerator;
1079
1080 let pk = self.serialize_sec1(true);
1081
1082 let t = k256::ProjectivePoint::mul_by_generator(&bip341_generate_tweak(&pk[1..], ttr)?);
1083 let pk_y_is_even = pk[0] == 0x02;
1084
1085 let tweaked_key = if pk_y_is_even {
1086 self.key.to_projective() + t
1087 } else {
1088 use std::ops::Neg;
1089 self.key.to_projective().neg() + t
1090 };
1091
1092 let key = k256::PublicKey::from_affine(tweaked_key.to_affine())
1093 .map_err(|_| InvalidTaprootHash::InvalidScalar)?;
1094
1095 Ok(Self { key })
1096 }
1097
1098 pub fn verify_bip341_signature(
1100 &self,
1101 message: &[u8],
1102 signature: &[u8],
1103 taproot_tree_root: &[u8],
1104 ) -> bool {
1105 let tweaked_key = match self.derive_bip341(taproot_tree_root) {
1106 Ok(k) => k,
1107 Err(_) => return false,
1108 };
1109
1110 tweaked_key.verify_bip340_signature(message, signature)
1111 }
1112
1113 pub fn try_recovery_from_digest(
1122 &self,
1123 digest: &[u8],
1124 signature: &[u8],
1125 ) -> Result<RecoveryId, RecoveryError> {
1126 let signature = k256::ecdsa::Signature::from_slice(signature)
1127 .map_err(|e| RecoveryError::SignatureParseError(e.to_string()))?;
1128
1129 let ecdsa = k256::ecdsa::VerifyingKey::from(&self.key);
1130
1131 k256::ecdsa::RecoveryId::trial_recovery_from_prehash(&ecdsa, digest, &signature)
1132 .map(|recid| RecoveryId { recid })
1133 .map_err(|e| RecoveryError::WrongParameters(e.to_string()))
1134 }
1135
1136 pub fn derive_subkey(&self, derivation_path: &DerivationPath) -> (Self, [u8; 32]) {
1142 let chain_code = [0u8; 32];
1143 self.derive_subkey_with_chain_code(derivation_path, &chain_code)
1144 }
1145
1146 pub fn derive_subkey_with_chain_code(
1154 &self,
1155 derivation_path: &DerivationPath,
1156 chain_code: &[u8; 32],
1157 ) -> (Self, [u8; 32]) {
1158 let public_key: AffinePoint = *self.key.as_affine();
1159 let (pt, _offset, chain_code) = derivation_path.derive_offset(public_key, chain_code);
1160
1161 let derived_key = Self {
1162 key: k256::PublicKey::from(
1163 k256::PublicKey::from_affine(pt).expect("Derived point is valid"),
1164 ),
1165 };
1166
1167 (derived_key, chain_code)
1168 }
1169}
1170
1171#[derive(Clone, Eq, PartialEq, Hash, Debug)]
1173pub enum RecoveryError {
1174 SignatureParseError(String),
1176 WrongParameters(String),
1179}
1180
1181#[derive(Clone, Eq, PartialEq, Debug)]
1200pub struct RecoveryId {
1201 recid: k256::ecdsa::RecoveryId,
1202}
1203
1204impl RecoveryId {
1205 pub const fn is_y_odd(&self) -> bool {
1207 self.recid.is_y_odd()
1208 }
1209
1210 pub const fn is_x_reduced(&self) -> bool {
1228 self.recid.is_x_reduced()
1229 }
1230
1231 pub const fn to_byte(&self) -> u8 {
1233 self.recid.to_byte()
1234 }
1235}