ic_secp256k1/
lib.rs

1#![forbid(unsafe_code)]
2#![warn(rust_2018_idioms)]
3#![warn(future_incompatible)]
4#![forbid(missing_docs)]
5
6//! A crate with handling of ECDSA and Schnorr keys over the secp256k1 curve
7
8use 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/// An error indicating that decoding a key failed
23#[derive(Clone, Debug)]
24pub enum KeyDecodingError {
25    /// The key encoding was invalid in some way
26    InvalidKeyEncoding(String),
27    /// The PEM encoding was invalid
28    InvalidPemEncoding(String),
29    /// The PEM encoding had an unexpected label
30    UnexpectedPemLabel(String),
31}
32
33/// An error indicating that the Taproot hash was not acceptable
34#[derive(Clone, Debug)]
35pub enum InvalidTaprootHash {
36    /// The Taproot Tree Hash value should be either 0 or 32 bytes
37    InvalidLength,
38    /// The internal hash produced an invalid scalar value; this failure is
39    /// mandated by BIP341 (but is very unlikely to occur in practice)
40    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
51/// See RFC 3279 section 2.3.5
52static ECDSA_OID: LazyLock<simple_asn1::OID> =
53    LazyLock::new(|| simple_asn1::oid!(1, 2, 840, 10045, 2, 1));
54
55/// See "SEC 2: Recommended Elliptic Curve Domain Parameters"
56/// Section A.2.1
57/// https://www.secg.org/sec2-v2.pdf
58static SECP256K1_OID: LazyLock<simple_asn1::OID> =
59    LazyLock::new(|| simple_asn1::oid!(1, 3, 132, 0, 10));
60
61/// A component of a derivation path
62#[derive(Clone, Debug)]
63pub struct DerivationIndex(pub Vec<u8>);
64
65/// Derivation Path
66///
67/// A derivation path is simply a sequence of DerivationIndex
68#[derive(Clone, Debug)]
69pub struct DerivationPath {
70    path: Vec<DerivationIndex>,
71}
72
73impl DerivationPath {
74    /// Create a BIP32-style derivation path
75    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    /// Create a free-form derivation path
84    pub fn new(path: Vec<DerivationIndex>) -> Self {
85        Self { path }
86    }
87
88    /// Create a path from a canister ID and a user provided path
89    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    /// Return the length of this path
100    pub fn len(&self) -> usize {
101        self.path.len()
102    }
103
104    /// Return if this path is empty
105    pub fn is_empty(&self) -> bool {
106        self.len() == 0
107    }
108
109    /// Return the components of the derivation path
110    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 iL >= order, try again with the "next" index as described in SLIP-10
131        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 the new key is not infinity, we're done: return the new key
161            if !bool::from(next_pt.is_identity()) {
162                return (next_chain_code, next_offset, next_pt);
163            }
164
165            // Otherwise set up the next input as defined by SLIP-0010
166            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
194/*
195RFC 5915 <https://www.rfc-editor.org/rfc/rfc5915> specifies how to
196encode ECC private keys in ASN.1
197
198Ordinarily this encoding is used embedded within a PKCS #8 ASN.1
199PrivateKeyInfo block <https://www.rfc-editor.org/rfc/rfc5208>.
200However OpenSSL's command line utility by default uses the "bare" RFC
2015915 ECPrivateKey structure to represent ECDSA keys, and as a
202consequence many utilities originally written using OpenSSL use this
203format instead of PKCS #8.
204
205If the RFC 5915 block is destined to be included in a PKCS #8 encoding,
206then we omit the curve parameter, as the curve is instead specified in
207the PKCS #8 privateKeyAlgorithm field. This is controlled by the `include_curve`
208parameter.
209
210The public key can be optionally specified in the ECPrivateKey structure;
211if the `public_key` argument is `Some` then it is included.
212*/
213fn 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    // simple_asn1::to_der can only fail if you use an invalid object identifier
221    // so to avoid returning a Result from this function we use expect
222
223    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        // mandatory field: version, should be equal to 1
266        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        // mandatory field: the private key
276        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        // following may be optional params and/or public key, which
286        // we ignore
287
288        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    // simple_asn1::to_der can only fail if you use an invalid object identifier
300    // so to avoid returning a Result from this function we use expect
301
302    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
317/// DER encode the public point into a SubjectPublicKeyInfo
318///
319/// The public_point can be either the compressed or uncompressed format
320fn der_encode_ecdsa_spki_pubkey(public_point: &[u8]) -> Vec<u8> {
321    use simple_asn1::*;
322
323    // simple_asn1::to_der can only fail if you use an invalid object identifier
324    // so to avoid returning a Result from this function we use expect
325
326    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
345/// BIP341 / Taproot derivation step
346///
347/// BIP341 defines a key tweaking operation that occurs with Taproot
348/// <https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#constructing-and-spending-taproot-outputs>
349///
350/// This function implements what is referred to in BIP341 as int_from_bytes(tagged_hash("TapTweak", ...))
351///
352/// * pk_x is the x coordinate of the public key (even y coordinate is assumed)
353/// * ttr is the Taproot Tree Root, referred to as `h` in BIP341
354fn bip341_generate_tweak(pk_x: &[u8], ttr: &[u8]) -> Result<Scalar, InvalidTaprootHash> {
355    // The caller should have already validated these but let's double check...
356    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/// A secp256k1 public key, suitable for generating ECDSA and BIP340 signatures
388#[derive(Clone, ZeroizeOnDrop)]
389pub struct PrivateKey {
390    key: k256::SecretKey,
391}
392
393impl PrivateKey {
394    /// Generate a new random private key
395    pub fn generate() -> Self {
396        let mut rng = rand::thread_rng();
397        Self::generate_using_rng(&mut rng)
398    }
399
400    /// Generate a new random private key using some provided RNG
401    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    /// Generate a key using an input seed
407    ///
408    /// # Warning
409    ///
410    /// For security the seed should be at least 256 bits and
411    /// randomly generated
412    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            // This could with ~ 1/2**256 probability fail. If it ever did, it
426            // implies we've found a seed such that the SHA-256 hash of it,
427            // reduced modulo the group order, is zero. Such an input would be
428            // exceptionally useful for constructing test cases which currently
429            // cannot be created, since such an input is not known to any party.
430
431            k256::NonZeroScalar::new(scalar).expect("Not zero")
432        };
433
434        Self {
435            key: k256::SecretKey::from(scalar),
436        }
437    }
438
439    /// Deserialize a private key encoded in SEC1 format
440    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    /// Deserialize a private key encoded in PKCS8 format
452    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    /// Deserialize a private key encoded in PKCS8 format with PEM encoding
460    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    /// Deserialize a private key encoded in RFC 5915 format
471    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    /// Deserialize a private key encoded in RFC 5915 format with PEM encoding
477    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    /// Serialize the private key to a simple bytestring
487    ///
488    /// This uses the SEC1 encoding, which is just the representation
489    /// of the secret integer in a 32-byte array, encoding it using
490    /// big-endian notation.
491    pub fn serialize_sec1(&self) -> Vec<u8> {
492        self.key.to_bytes().to_vec()
493    }
494
495    /// Serialize the private key as PKCS8 format in DER encoding
496    pub fn serialize_pkcs8_der(&self) -> Vec<u8> {
497        der_encode_pkcs8_rfc5208_private_key(&self.serialize_sec1())
498    }
499
500    /// Serialize the private key as PKCS8 format in PEM encoding
501    pub fn serialize_pkcs8_pem(&self) -> String {
502        pem_encode(&self.serialize_pkcs8_der(), PEM_HEADER_PKCS8)
503    }
504
505    /// Serialize the private key as RFC 5915 in DER encoding
506    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    /// Serialize the private key as RFC 5915 in PEM encoding
513    pub fn serialize_rfc5915_pem(&self) -> String {
514        pem_encode(&self.serialize_rfc5915_der(), PEM_HEADER_RFC5915)
515    }
516
517    /// Sign a message with ECDSA
518    ///
519    /// The message is hashed with SHA-256 and the signature is
520    /// normalized (using the minimum-s approach of BitCoin)
521    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    /// Sign a message digest with ECDSA
530    ///
531    /// The signature is normalized (using the minimum-s approach of BitCoin)
532    pub fn sign_digest_with_ecdsa(&self, digest: &[u8]) -> [u8; 64] {
533        if digest.len() < 16 {
534            // k256 arbitrarily rejects digests that are < 128 bits
535            // handle this by prefixing with a sufficient number of zero bytes
536            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    /// Sign a message with BIP340 Schnorr
549    ///
550    /// This can theoretically fail, in the case that k/s generated is zero.
551    /// This will never occur in practice
552    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    /// Sign a message with BIP340 Schnorr
562    pub fn sign_message_with_bip340<R: Rng + CryptoRng>(
563        &self,
564        message: &[u8],
565        rng: &mut R,
566    ) -> [u8; 64] {
567        loop {
568            /*
569             * The only way this function can fail is the (cryptographically unlikely)
570             * situation where k or s of zero is generated. If this occurs, simply retry
571             * with a new aux_rand
572             */
573            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    /// Sign a message with BIP340 Schnorr without using an external RNG
581    ///
582    /// By default BIP340/BIP341 take the output of a random number generator
583    /// which is used to re-randomize the otherwise deterministic nonce generation
584    /// process.
585    ///
586    /// This randomization is not necessary for security, and in some contexts a RNG
587    /// is not easily accessible, or deterministic signatures may be helpful.
588    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    /// BIP341 derivation
594    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    /// Sign a message with BIP340 Schnorr with Taproot derivation
614    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    /// Sign a message with BIP340 Schnorr with Taproot derivation, without using an external RNG
629    ///
630    /// By default BIP340/BIP341 take the output of a random number generator
631    /// which is used to re-randomize the otherwise deterministic nonce generation
632    /// process.
633    ///
634    /// This randomization is not necessary for security, and in some contexts a RNG
635    /// is not easily accessible, or deterministic signatures may be helpful.
636    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    /// Return the public key corresponding to this private key
646    pub fn public_key(&self) -> PublicKey {
647        PublicKey {
648            key: self.key.public_key(),
649        }
650    }
651
652    /// Derive a private key from this private key using a derivation path
653    ///
654    /// This is the same derivation system used by the Internet Computer when
655    /// deriving subkeys for threshold ECDSA with secp256k1 and BIP340 Schnorr
656    ///
657    /// As long as each index of the derivation path is a 4-byte input with the highest
658    /// bit cleared, this derivation scheme matches BIP32 and SLIP-10
659    ///
660    /// See <https://internetcomputer.org/docs/current/references/ic-interface-spec#ic-ecdsa_public_key>
661    /// for details on the derivation scheme.
662    ///
663    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    /// Derive a private key from this private key using a derivation path
669    /// and chain code
670    ///
671    /// This is the same derivation system used by the Internet Computer when
672    /// deriving subkeys for threshold ECDSA with secp256k1 and BIP340 Schnorr
673    ///
674    /// As long as each index of the derivation path is a 4-byte input with the highest
675    /// bit cleared, this derivation scheme matches BIP32 and SLIP-10
676    ///
677    /// See <https://internetcomputer.org/docs/current/references/ic-interface-spec#ic-ecdsa_public_key>
678    /// for details on the derivation scheme.
679    ///
680    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/// An identifier for the mainnet production key
705#[derive(Copy, Clone, Eq, PartialEq, Debug)]
706pub enum MasterPublicKeyId {
707    /// The production master key "key_1" for ECDSA
708    EcdsaKey1,
709    /// The test master key "test_key_1" for ECDSA
710    EcdsaTestKey1,
711    /// The production master key "key_1" for Schnorr
712    SchnorrKey1,
713    /// The test master key "test_key_1" for Schnorr
714    SchnorrTestKey1,
715}
716
717/// An identifier for the mainnet production key
718#[derive(Copy, Clone, Eq, PartialEq, Debug)]
719pub enum PocketIcMasterPublicKeyId {
720    /// The PocketIC hardcoded key for ECDSA "key_1"
721    EcdsaKey1,
722    /// The PocketIC hardcoded key for ECDSA "test_key_1"
723    EcdsaTestKey1,
724    /// The PocketIC hardcoded key for Schnorr "key_1"
725    ///
726    /// Note this is the same as the ECDSA key
727    SchnorrKey1,
728    /// The PocketIC hardcoded key for Schnorr "test_key_1"
729    ///
730    /// Note this is the same as the ECDSA key
731    SchnorrTestKey1,
732    /// Another test key
733    EcdsaDfxTestKey,
734    /// Another test key
735    ///
736    /// Note this is the same as the ECDSA key
737    SchnorrDfxTestKey,
738}
739
740/// A secp256k1 public key, suitable for verifying ECDSA or BIP340 signatures
741#[derive(Clone, Eq, PartialEq, Debug)]
742pub struct PublicKey {
743    key: k256::PublicKey,
744}
745
746impl PublicKey {
747    /// Return the public master keys used in the production mainnet
748    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    /// Return the public master keys used by PocketIC
770    ///
771    /// Note that the secret keys for these public keys are known, and these keys are
772    /// should only be used for offline testing with PocketIC
773    pub fn pocketic_key(key_id: PocketIcMasterPublicKeyId) -> Self {
774        match key_id {
775            PocketIcMasterPublicKeyId::EcdsaKey1 | PocketIcMasterPublicKeyId::SchnorrKey1 => {
776                // PocketIC uses the same key for ECDSA secp256k1 and BIP340 Schnorr
777                // Secret key is 6f65b33c736ceaf3d89e6b913a508e0612a2f43d872128606d59ab855b80d288
778
779                Self::deserialize_sec1(&hex!(
780                    "036ad6e838b46811ad79c37b2f4b854b7a05f406715b2935edc5d3251e7666977b"
781                ))
782                .expect("Hardcoded master key was rejected")
783            }
784            PocketIcMasterPublicKeyId::EcdsaTestKey1
785            | PocketIcMasterPublicKeyId::SchnorrTestKey1 => {
786                // PocketIC uses the same key for ECDSA secp256k1 and BIP340 Schnorr
787                // Secret key is cb1eb3d67ff91be823715ee2f2af9c2b88252dacbf67f8d09c167c10e7deca7a
788
789                Self::deserialize_sec1(&hex!(
790                    "03cc365e15cb552589c7175717b2ac63d1050b9bb2e5aed35432b1b1be55d3abcf"
791                ))
792                .expect("Hardcoded master key was rejected")
793            }
794            PocketIcMasterPublicKeyId::EcdsaDfxTestKey
795            | PocketIcMasterPublicKeyId::SchnorrDfxTestKey => {
796                // PocketIC uses the same key for ECDSA secp256k1 and BIP340 Schnorr
797                // Secret key is 2aff2be7e3e57007909036d08767bcc5e192717b59eeae19ead8eff9ee874a48
798
799                Self::deserialize_sec1(&hex!(
800                    "03e6f78b1a90e361c5cc9903f73bb8acbe3bc17ad01e82554d25cf0ecd70c67484"
801                ))
802                .expect("Hardcoded master key was rejected")
803            }
804        }
805    }
806
807    /// Derive a public key from the mainnet parameters
808    ///
809    /// This is an offline equivalent to the `ecdsa_public_key` or
810    /// `schnorr_public_key` management canister call
811    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    /// Derive a public key as is done on PocketIC
824    ///
825    /// This is an offline equivalent to the `ecdsa_public_key` or
826    /// `schnorr_public_key` management canister call when running on PocketIC
827    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    /// Deserialize a public key stored in SEC1 format
840    ///
841    /// This is just the encoding of the point. Both compressed and uncompressed
842    /// points are accepted
843    ///
844    /// See SEC1 <https://www.secg.org/sec1-v2.pdf> section 2.3.3 for details of the format
845    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    /// Deserialize a public key stored as BIP340 key
852    ///
853    /// This is just the encoding of the x coordinate of the point. Implicitly,
854    /// the y coordinate is the even choice.
855    ///
856    /// See BIP340 <https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki>
857    /// for details
858    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; // even y
868        sec1[1..].copy_from_slice(bytes);
869
870        Self::deserialize_sec1(&sec1)
871    }
872
873    /// Deserialize a public key stored in DER SubjectPublicKeyInfo format
874    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    /// Deserialize a public key stored in PEM SubjectPublicKeyInfo format
882    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    /// Serialize a public key in SEC1 format
893    ///
894    /// The point can optionally be compressed
895    ///
896    /// See SEC1 <https://www.secg.org/sec1-v2.pdf> section 2.3.3 for details
897    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    /// Serialize a public key in the style of BIP340
903    ///
904    /// That is, with the x coordinate only and the y coordinate being implicit
905    ///
906    /// See BIP340 <https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki>
907    /// for details
908    pub fn serialize_bip340(&self) -> Vec<u8> {
909        let sec1 = self.serialize_sec1(true);
910
911        // Remove the leading byte of the SEC1 encoding, which indicates
912        // the sign of y, returning only the encoding of the x coordinate
913        sec1[1..].to_vec()
914    }
915
916    /// Serialize a public key in DER as a SubjectPublicKeyInfo
917    pub fn serialize_der(&self) -> Vec<u8> {
918        der_encode_ecdsa_spki_pubkey(&self.serialize_sec1(false))
919    }
920
921    /// Serialize a public key in PEM encoding of a SubjectPublicKeyInfo
922    pub fn serialize_pem(&self) -> String {
923        pem_encode(&self.serialize_der(), "PUBLIC KEY")
924    }
925
926    /// Deprecated alias of verify_ecdsa_signature
927    pub fn verify_signature(&self, message: &[u8], signature: &[u8]) -> bool {
928        self.verify_ecdsa_signature(message, signature)
929    }
930
931    /// Deprecated alias of verify_ecdsa_signature_with_malleability
932    pub fn verify_signature_with_malleability(&self, message: &[u8], signature: &[u8]) -> bool {
933        self.verify_ecdsa_signature_with_malleability(message, signature)
934    }
935
936    /// Deprecated alias of verify_ecdsa_signature_prehashed
937    pub fn verify_signature_prehashed(&self, digest: &[u8], signature: &[u8]) -> bool {
938        self.verify_ecdsa_signature_prehashed(digest, signature)
939    }
940
941    /// Deprecated alias of verify_ecdsa_signature_prehashed_with_malleability
942    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    /// Verify a (message,signature) pair, requiring s-normalization
951    ///
952    /// If used to verify signatures generated by a library that does not
953    /// perform s-normalization, this function will reject roughly half of all
954    /// signatures.
955    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    /// Verify a (message,signature) pair
967    ///
968    /// The message is hashed with SHA-256
969    ///
970    /// This accepts signatures without requiring s-normalization
971    ///
972    /// ECDSA signatures are a pair of integers (r,s) which satisfy a certain
973    /// equation which involves also the public key and the message.  A quirk of
974    /// ECDSA is that if (r,s) is a valid signature then (r,-s) is also a valid
975    /// signature (here negation is modulo the group order).
976    ///
977    /// This means that given a valid ECDSA signature, it is possible to create
978    /// a "new" ECDSA signature that is also valid, without having access to the
979    /// key. Unlike `verify_signature`, this function accepts either `s` value.
980    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    /// Verify a (message digest,signature) pair
1000    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    /// Verify a (digest,signature) pair
1020    ///
1021    /// This accepts signatures without requiring s-normalization
1022    ///
1023    /// ECDSA signatures are a pair of integers (r,s) which satisfy a certain
1024    /// equation which involves also the public key and the message.  A quirk of
1025    /// ECDSA is that if (r,s) is a valid signature then (r,-s) is also a valid
1026    /// signature (here negation is modulo the group order) for the same message.
1027    ///
1028    /// This means that given a valid ECDSA signature, it is possible to create
1029    /// a "new" ECDSA signature, without having access to the key. Unlike
1030    /// `verify_signature_prehashed`, this function accepts either `s` value.
1031    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    /// Verify a BIP340 (message,signature) pair
1059    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        // from_bytes takes just the x coordinate encoding:
1070        match k256::schnorr::VerifyingKey::from_bytes(&pt[1..]) {
1071            Ok(bip340) => bip340.verify_prehash(message, &signature).is_ok(),
1072            _ => false,
1073        }
1074    }
1075
1076    /// BIP341 derivation
1077    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    /// Verify a BIP341 (message,signature) pair
1099    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    /// Determines the [`RecoveryId`] for a given public key, digest and signature.
1114    ///
1115    /// The recovery cannot fail if the parameters are correct, meaning that
1116    /// `signature` corresponds to a signature on the given `digest`
1117    /// with the secret key associated with this `PublicKey`.
1118    ///
1119    /// # Errors
1120    /// See [`RecoveryError`] for details.
1121    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    /// Derive a public key from this public key using a derivation path
1137    ///
1138    /// This is the same derivation system used by the Internet Computer when
1139    /// deriving subkeys for threshold ECDSA with secp256k1 and BIP340 Schnorr
1140    ///
1141    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    /// Derive a public key from this public key using a derivation path
1147    /// and chain code
1148    ///
1149    /// This is the same derivation system used by the Internet Computer when
1150    /// deriving subkeys for threshold ECDSA with secp256k1 and BIP340 Schnorr
1151    ///
1152    /// This derivation matches BIP340 and SLIP-10
1153    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/// An error indicating that recovering the recovery of the signature y parity bit failed.
1172#[derive(Clone, Eq, PartialEq, Hash, Debug)]
1173pub enum RecoveryError {
1174    /// The signature is syntactically invalid and cannot be parsed.
1175    SignatureParseError(String),
1176    /// Recovery failed which can only happen if parameters are wrong:
1177    /// signature was not done on given digest or was done by another key pair.
1178    WrongParameters(String),
1179}
1180
1181/// Given an ECDSA signature `(r,s)` and a signed digest, there can be several public
1182/// keys that could verify this signature. This is problematic for certain applications (Bitcoin, Ethereum)
1183/// where the public key is not transmitted but computed from the signature.
1184/// The [`RecoveryId`] determines uniquely which one of those public keys (and corresponding secret key)
1185/// was used and is usually transmitted together with the signature.
1186///
1187/// Note that in secp256k1 there can be at most 4 public keys for a given signature `(r,s)` and message digest `d`.
1188/// The public key is determined by the following equation `r⁻¹(𝑠𝑅 − d𝐺)`,
1189/// where `R` is a point on the curve and can have 4 possible values
1190/// (see [Public Key Recovery Operation](https://www.secg.org/sec1-v2.pdf)):
1191/// 1. `(r, y)`
1192/// 2. `(r, -y)`
1193/// 3. `(r + n, y' )`
1194/// 4. `(r + n, -y')`
1195///
1196/// where `y`, `y'` are computed from the affine x-coordinate together with the curve equation and `n` is the order of the curve.
1197/// Note that because the affine coordinates are over `𝔽ₚ`, where `p > n` but `p` and `n` are somewhat close from each other,
1198/// the last 2 possibilities often do not exist, see [`RecoveryId::is_x_reduced`].
1199#[derive(Clone, Eq, PartialEq, Debug)]
1200pub struct RecoveryId {
1201    recid: k256::ecdsa::RecoveryId,
1202}
1203
1204impl RecoveryId {
1205    /// True iff the affine y-coordinate of `𝑘×𝑮` odd.
1206    pub const fn is_y_odd(&self) -> bool {
1207        self.recid.is_y_odd()
1208    }
1209
1210    /// True iff the affine x-coordinate of `𝑘×𝑮` overflows the curve order.
1211    ///
1212    /// This is `false` with overwhelming probability and some applications like Ethereum completely ignore this bit.
1213    /// To see why, recall that in ECDSA the signature starts with choosing a random number `𝑘` in `[1, n-1]` and computing `𝑘×𝑮`
1214    /// which is an element of the elliptic curve and whose affine x-coordinate is in `𝔽ₚ`.
1215    /// This value is then reduced modulo `n` to get `r` (the first part of the signature),
1216    /// which can only happen if the affine x-coordinate of `𝑘×𝑮` is in the interval `[n, p-1]`,
1217    /// which contains `p-n` elements.
1218    ///
1219    /// However, the number of affine x-coordinates in 𝔽ₚ is `(n-1)/2`
1220    /// (since every x-coordinate corresponds to 2 symmetric points on the curve which also contains the point at infinity),
1221    /// and so the probability that a random affine x-coordinate is in `[n, p-1]`
1222    /// is `(p-n)/((n-1)/2) = 2(p-n)/(n-1)`, which with secp256k1 parameters is less than `2⁻¹²⁵`:
1223    /// * `p = 0xFFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F > 2²⁵⁵`
1224    /// * `n = 0xFFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE BAAEDCE6 AF48A03B BFD25E8C D0364141 > 2²⁵⁵`
1225    /// * `p-n = 432420386565659656852420866390673177326 < 2¹²⁹`
1226    /// * `2(p-n)/(n-1) < 2 * 2¹²⁹ * 2⁻²⁵⁵ = 2⁻¹²⁵`
1227    pub const fn is_x_reduced(&self) -> bool {
1228        self.recid.is_x_reduced()
1229    }
1230
1231    /// Convert this [`RecoveryId`] into a `u8`.
1232    pub const fn to_byte(&self) -> u8 {
1233        self.recid.to_byte()
1234    }
1235}