ic_ed25519/
lib.rs

1#![warn(rust_2018_idioms)]
2#![warn(future_incompatible)]
3#![forbid(missing_docs)]
4#![forbid(unsafe_code)]
5
6//! A crate for creating and verifying Ed25519 signatures
7
8use curve25519_dalek::{EdwardsPoint, Scalar, edwards::CompressedEdwardsY};
9use ed25519_dalek::pkcs8::{DecodePrivateKey, DecodePublicKey, EncodePrivateKey, EncodePublicKey};
10use ed25519_dalek::{Digest, Sha512};
11use ed25519_dalek::{Signer, SigningKey, VerifyingKey};
12use hex_literal::hex;
13use thiserror::Error;
14use zeroize::ZeroizeOnDrop;
15
16pub use ic_principal::Principal as CanisterId;
17
18/// An error if a private key cannot be decoded
19#[derive(Clone, Debug, Error)]
20pub enum PrivateKeyDecodingError {
21    /// The outer PEM encoding is invalid
22    #[error("The outer PEM encoding is invalid: {0}")]
23    InvalidPemEncoding(String),
24    /// The PEM label was not the expected value
25    #[error("The PEM label was not the expected value: {0}")]
26    UnexpectedPemLabel(String),
27    /// The private key seems invalid in some way; the string contains details
28    #[error("The private key seems invalid in some way: {0}")]
29    InvalidKeyEncoding(String),
30}
31
32/// An Ed25519 secret key
33#[derive(Clone, Eq, PartialEq, ZeroizeOnDrop)]
34pub struct PrivateKey {
35    sk: SigningKey,
36}
37
38impl std::fmt::Debug for PrivateKey {
39    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
40        f.debug_struct("PrivateKey")
41            .field("public_key", &self.public_key().serialize_raw())
42            .finish_non_exhaustive() // avoids printing secret information
43    }
44}
45
46/*
47The ring crate, in versions prior to 0.17 has an unfortunate bug that
48it both requires that Ed25519 private keys be conveyed using the PKCS8 V2
49encoding AND it has a bug such that it does not accept the actual (correct)
50PKCS8 V2 encoding.
51*/
52
53const BUGGY_RING_V2_DER_PREFIX: [u8; 16] = [
54    48, 83, // A sequence of 83 bytes follows.
55    2, 1, // An integer denoting version
56    1, // 0 if secret key only, 1 if public key is also present
57    48, 5, // An element of 5 bytes follows
58    6, 3, 43, 101, 112, // The OID
59    4, 34, // An octet string of 34 bytes follows.
60    4, 32, // An octet string of 32 bytes follows.
61];
62
63const BUGGY_RING_V2_DER_PK_PREFIX: [u8; 5] = [
64    161,
65    35, // An explicitly tagged with 35 bytes. (This is the bug; this should be an implicit tag)
66    3, 33, // A bitstring of 33 bytes follows.
67    0,  // The bitstring (32 bytes) is divisible by 8
68];
69
70const BUGGY_RING_V2_LEN: usize = BUGGY_RING_V2_DER_PREFIX.len()
71    + PrivateKey::BYTES
72    + BUGGY_RING_V2_DER_PK_PREFIX.len()
73    + PublicKey::BYTES;
74
75/// Specifies a private key encoding format
76#[derive(Copy, Clone, Eq, PartialEq, Debug)]
77pub enum PrivateKeyFormat {
78    /// PKCS #8 v1: most common version, implemented by for example OpenSSL
79    Pkcs8v1,
80    /// PKCS #8 v2: newer format which includes the public key.
81    ///
82    /// # Warning
83    ///
84    /// Many libraries including OpenSSL cannot parse PKCS8 v2 formatting
85    Pkcs8v2,
86    /// PKCS #8 v2 emulating a bug that makes it compatible with
87    /// versions of the ring cryptography library prior to 0.17
88    ///
89    /// # Warning
90    ///
91    /// The only libraries that can parse this format are ring,
92    /// or libraries (such as this crate) that go out of their way
93    /// to be compatible with ring's buggy format.
94    Pkcs8v2WithRingBug,
95}
96
97impl PrivateKey {
98    /// The length in bytes of the raw private key
99    pub const BYTES: usize = 32;
100
101    /// Create a new random secret Ed25519 key
102    #[cfg(feature = "rand")]
103    pub fn generate() -> Self {
104        let mut rng = rand::thread_rng();
105        Self::generate_using_rng(&mut rng)
106    }
107
108    /// Create a new random secret Ed25519 key using specified RNG
109    #[cfg(feature = "rand")]
110    pub fn generate_using_rng<R: rand::CryptoRng + rand::Rng>(rng: &mut R) -> Self {
111        let sk = SigningKey::generate(rng);
112        Self { sk }
113    }
114
115    /// Generate a key using an input seed
116    ///
117    /// # Warning
118    ///
119    /// For security the seed should be at least 256 bits and
120    /// randomly generated
121    pub fn generate_from_seed(seed: &[u8]) -> Self {
122        let digest: [u8; 32] = {
123            let mut sha2 = Sha512::new();
124            sha2.update(seed);
125            let digest: [u8; 64] = sha2.finalize().into();
126            let mut truncated = [0u8; 32];
127            truncated.copy_from_slice(&digest[..32]);
128            truncated
129        };
130
131        Self {
132            sk: SigningKey::from_bytes(&digest),
133        }
134    }
135
136    /// Sign a message and return a signature
137    ///
138    /// This is the non-prehashed variant of Ed25519
139    pub fn sign_message(&self, msg: &[u8]) -> [u8; 64] {
140        self.sk.sign(msg).into()
141    }
142
143    /// Return the public key associated with this secret key
144    pub fn public_key(&self) -> PublicKey {
145        PublicKey::new(self.sk.verifying_key())
146    }
147
148    /// Serialize the Ed25519 secret key
149    ///
150    /// This returns the 32-byte encoding of the seed value
151    /// which is used to derive the secret scalar
152    pub fn serialize_raw(&self) -> [u8; Self::BYTES] {
153        self.sk.to_bytes()
154    }
155
156    /// Deserialize an Ed25519 private key from raw format
157    ///
158    /// This is just the plain 32 byte random seed from which the
159    /// internal key material is derived
160    ///
161    /// This corresponds with the format used by PrivateKey::serialize_raw
162    pub fn deserialize_raw(bytes: &[u8]) -> Result<Self, PrivateKeyDecodingError> {
163        let bytes = <[u8; Self::BYTES]>::try_from(bytes).map_err(|_| {
164            PrivateKeyDecodingError::InvalidKeyEncoding(format!(
165                "Expected key of exactly {} bytes, got {}",
166                Self::BYTES,
167                bytes.len()
168            ))
169        })?;
170
171        Ok(Self::deserialize_raw_32(&bytes))
172    }
173
174    /// Deserialize an Ed25519 private key from raw format
175    ///
176    /// This is just the plain 32 byte random seed from which the
177    /// internal key material is derived
178    ///
179    /// This corresponds with the format used by PrivateKey::serialize_raw
180    pub fn deserialize_raw_32(bytes: &[u8; 32]) -> Self {
181        let sk = SigningKey::from_bytes(bytes);
182        Self { sk }
183    }
184
185    /// Serialize the Ed25519 secret key in PKCS8 format
186    ///
187    /// The details of the formatting are specified using the argument
188    pub fn serialize_pkcs8(&self, format: PrivateKeyFormat) -> Vec<u8> {
189        let sk_bytes = self.serialize_raw();
190        let pk_bytes = self.public_key().serialize_raw();
191
192        fn to_pkcs8<T: EncodePrivateKey>(v: &T) -> Vec<u8> {
193            let pkcs8 = v.to_pkcs8_der();
194
195            // Key encoding with the pkcs8 crate can fail, largely to allow for
196            // fallible encoding on the part of the algorithm specific code.  But
197            // logically speaking, as long as the key is valid (which we've already
198            // checked) then there is no reason for encoding to ever fail outside of
199            // memory allocation errors. None of the error types that to_pkcs8_der
200            // can return have any relevance to encoding. And the dalek encoding
201            // functions themselves do not have any error cases.
202
203            pkcs8.expect("PKCS8 encoding failed").to_bytes().to_vec()
204        }
205
206        match format {
207            PrivateKeyFormat::Pkcs8v1 => {
208                let kp = ed25519_dalek::pkcs8::KeypairBytes {
209                    secret_key: sk_bytes,
210                    public_key: None,
211                };
212
213                to_pkcs8(&kp)
214            }
215            PrivateKeyFormat::Pkcs8v2 => {
216                let kp = ed25519_dalek::pkcs8::KeypairBytes {
217                    secret_key: sk_bytes,
218                    public_key: Some(ed25519_dalek::pkcs8::PublicKeyBytes(pk_bytes)),
219                };
220
221                to_pkcs8(&kp)
222            }
223            PrivateKeyFormat::Pkcs8v2WithRingBug => {
224                let mut ringv2 = Vec::with_capacity(BUGGY_RING_V2_LEN);
225
226                ringv2.extend_from_slice(&BUGGY_RING_V2_DER_PREFIX);
227                ringv2.extend_from_slice(&sk_bytes);
228                ringv2.extend_from_slice(&BUGGY_RING_V2_DER_PK_PREFIX);
229                ringv2.extend_from_slice(&pk_bytes);
230
231                ringv2
232            }
233        }
234    }
235
236    /// Deserialize an Ed25519 private key from PKCS8 format
237    ///
238    /// Both v1 and v2 PKCS8 encodings are accepted. The only difference is
239    /// that v2 includes the public key as well. This also accepts the buggy
240    /// format used by ring 0.16.
241    ///
242    /// This corresponds with the format used by PrivateKey::serialize_pkcs8
243    pub fn deserialize_pkcs8(bytes: &[u8]) -> Result<Self, PrivateKeyDecodingError> {
244        if bytes.len() == BUGGY_RING_V2_LEN && bytes.starts_with(&BUGGY_RING_V2_DER_PREFIX) {
245            let sk_offset = BUGGY_RING_V2_DER_PREFIX.len();
246            Self::deserialize_raw(&bytes[sk_offset..sk_offset + Self::BYTES])
247        } else {
248            let sk = SigningKey::from_pkcs8_der(bytes)
249                .map_err(|e| PrivateKeyDecodingError::InvalidKeyEncoding(format!("{e:?}")))?;
250            Ok(Self { sk })
251        }
252    }
253
254    /// Serialize the Ed25519 secret key in PKCS8 v2 format with PEM encoding
255    ///
256    /// The details of the formatting are specified using the argument
257    pub fn serialize_pkcs8_pem(&self, format: PrivateKeyFormat) -> String {
258        let pkcs8 = self.serialize_pkcs8(format);
259
260        pem::encode(&pem::Pem {
261            tag: "PRIVATE KEY".to_string(),
262            contents: pkcs8,
263        })
264    }
265
266    /// Deserialize an Ed25519 private key from PKCS8 PEM format
267    ///
268    /// Both v1 and v2 PKCS8 encodings are accepted
269    ///
270    /// This corresponds with the format used by PrivateKey::serialize_pkcs8_pem
271    pub fn deserialize_pkcs8_pem(pem: &str) -> Result<Self, PrivateKeyDecodingError> {
272        let der = pem::parse(pem)
273            .map_err(|e| PrivateKeyDecodingError::InvalidPemEncoding(format!("{e:?}")))?;
274        if der.tag != "PRIVATE KEY" {
275            return Err(PrivateKeyDecodingError::UnexpectedPemLabel(der.tag));
276        }
277
278        Self::deserialize_pkcs8(&der.contents)
279    }
280
281    /// Derive a private key from this private key using a derivation path
282    ///
283    /// This is the same derivation system used by the Internet Computer when
284    /// deriving subkeys for threshold Ed25519
285    ///
286    /// Note that this function returns a DerivedPrivateKey rather than Self,
287    /// and that DerivedPrivateKey can sign messages but cannot be serialized.
288    /// This is due to the definition of Ed25519 private keys, which is
289    /// incompatible with additive derivation.
290    ///
291    pub fn derive_subkey(&self, derivation_path: &DerivationPath) -> (DerivedPrivateKey, [u8; 32]) {
292        let chain_code = [0u8; 32];
293        self.derive_subkey_with_chain_code(derivation_path, &chain_code)
294    }
295
296    /// Derive a private key from this private key using a derivation path
297    /// and chain code
298    ///
299    /// This is the same derivation system used by the Internet Computer when
300    /// deriving subkeys for threshold Ed25519
301    ///
302    /// Note that this function returns a DerivedPrivateKey rather than Self,
303    /// and that DerivedPrivateKey can sign messages but cannot be serialized.
304    /// This is due to the definition of Ed25519 private keys, which is
305    /// incompatible with additive derivation.
306    ///
307    pub fn derive_subkey_with_chain_code(
308        &self,
309        derivation_path: &DerivationPath,
310        chain_code: &[u8; 32],
311    ) -> (DerivedPrivateKey, [u8; 32]) {
312        let sk_scalar = self.sk.to_scalar();
313        let pt = EdwardsPoint::mul_base(&sk_scalar);
314
315        let (pt, sum, chain_code) = derivation_path.derive_offset(pt, chain_code);
316
317        let derived_scalar = sk_scalar + sum;
318
319        let derived_hash_prefix = {
320            // Hash the new derived key and chain code with SHA-512 to derive
321            // the new hash prefix
322            let mut sha2 = Sha512::new();
323            sha2.update(derived_scalar.to_bytes());
324            sha2.update(chain_code);
325            let hash: [u8; 64] = sha2.finalize().into();
326            let mut truncated = [0u8; 32];
327            truncated.copy_from_slice(&hash[..32]);
328            truncated
329        };
330
331        let dpk = DerivedPrivateKey::new(derived_scalar, derived_hash_prefix, pt);
332        (dpk, chain_code)
333    }
334}
335
336/// A private key derived via the IC's derivation mechanism
337///
338/// Due to oddities in Ed25519's secret key format, a derived private
339/// key cannot be treated the same way as an ordinary private key.
340/// In particular, it cannot be serialized.
341pub struct DerivedPrivateKey {
342    // ExpandedSecretKey has a Drop impl which will zeroize the key
343    esk: ed25519_dalek::hazmat::ExpandedSecretKey,
344    vk: ed25519_dalek::VerifyingKey,
345}
346
347impl DerivedPrivateKey {
348    fn new(scalar: Scalar, hash_prefix: [u8; 32], pk: EdwardsPoint) -> Self {
349        let esk = ed25519_dalek::hazmat::ExpandedSecretKey {
350            scalar,
351            hash_prefix,
352        };
353
354        let vk = ed25519_dalek::VerifyingKey::from(pk);
355
356        Self { esk, vk }
357    }
358
359    /// Sign a message and return a signature
360    ///
361    /// This is the non-prehashed variant of Ed25519
362    pub fn sign_message(&self, msg: &[u8]) -> [u8; 64] {
363        ed25519_dalek::hazmat::raw_sign::<Sha512>(&self.esk, msg, &self.vk).to_bytes()
364    }
365
366    /// Return the public key associated with this private key
367    pub fn public_key(&self) -> PublicKey {
368        PublicKey::new(self.vk)
369    }
370
371    /// Derive a private key from this private key using a derivation path
372    ///
373    /// This is the same derivation system used by the Internet Computer when
374    /// deriving subkeys for threshold Ed25519
375    ///
376    /// Note that this function returns a DerivedPrivateKey rather than Self,
377    /// and that DerivedPrivateKey can sign messages but cannot be serialized.
378    /// This is due to the definition of Ed25519 private keys, which is
379    /// incompatible with additive derivation.
380    ///
381    pub fn derive_subkey(&self, derivation_path: &DerivationPath) -> (DerivedPrivateKey, [u8; 32]) {
382        let chain_code = [0u8; 32];
383        self.derive_subkey_with_chain_code(derivation_path, &chain_code)
384    }
385
386    /// Derive a private key from this private key using a derivation path
387    /// and chain code
388    ///
389    /// This is the same derivation system used by the Internet Computer when
390    /// deriving subkeys for threshold Ed25519
391    ///
392    /// Note that this function returns a DerivedPrivateKey rather than Self,
393    /// and that DerivedPrivateKey can sign messages but cannot be serialized.
394    /// This is due to the definition of Ed25519 private keys, which is
395    /// incompatible with additive derivation.
396    ///
397    pub fn derive_subkey_with_chain_code(
398        &self,
399        derivation_path: &DerivationPath,
400        chain_code: &[u8; 32],
401    ) -> (DerivedPrivateKey, [u8; 32]) {
402        let sk_scalar = self.esk.scalar;
403        let pt = EdwardsPoint::mul_base(&sk_scalar);
404
405        let (pt, sum, chain_code) = derivation_path.derive_offset(pt, chain_code);
406
407        let derived_scalar = sk_scalar + sum;
408
409        let derived_hash_prefix = {
410            // Hash the new derived key and chain code with SHA-512 to derive
411            // the new hash prefix
412            let mut sha2 = Sha512::new();
413            sha2.update(derived_scalar.to_bytes());
414            sha2.update(chain_code);
415            let hash: [u8; 64] = sha2.finalize().into();
416            let mut truncated = [0u8; 32];
417            truncated.copy_from_slice(&hash[..32]);
418            truncated
419        };
420
421        let dpk = DerivedPrivateKey::new(derived_scalar, derived_hash_prefix, pt);
422        (dpk, chain_code)
423    }
424}
425
426/// An invalid key was encountered
427#[derive(Clone, Debug, Error)]
428pub enum PublicKeyDecodingError {
429    /// The outer PEM encoding is invalid
430    #[error("The outer PEM encoding is invalid: {0}")]
431    InvalidPemEncoding(String),
432    /// The PEM label was not the expected value
433    #[error("The PEM label was not the expected value: {0}")]
434    UnexpectedPemLabel(String),
435    /// The encoding of the public key is invalid, the string contains details
436    #[error("The encoding of the public key is invalid: {0}")]
437    InvalidKeyEncoding(String),
438}
439
440/// An Ed25519 signature (not a public API)
441struct Signature {
442    r: EdwardsPoint,
443    r_bytes: [u8; 32], // potentially non-canonical
444    s: Scalar,
445}
446
447impl Signature {
448    fn from_slice(signature: &[u8]) -> Result<Self, SignatureError> {
449        if signature.len() != 64 {
450            return Err(SignatureError::InvalidLength);
451        }
452
453        let (r, r_bytes) = {
454            let mut r_bytes = [0u8; 32];
455            r_bytes.copy_from_slice(&signature[..32]);
456            let r = CompressedEdwardsY(r_bytes)
457                .decompress()
458                .ok_or(SignatureError::InvalidSignature)?;
459
460            (r, r_bytes)
461        };
462
463        let s = {
464            let mut s_bytes = [0u8; 32];
465            s_bytes.copy_from_slice(&signature[32..]);
466            Option::<Scalar>::from(Scalar::from_canonical_bytes(s_bytes))
467                .ok_or(SignatureError::InvalidSignature)?
468        };
469
470        Ok(Self { r, r_bytes, s })
471    }
472
473    pub fn r_bytes(&self) -> &[u8; 32] {
474        &self.r_bytes
475    }
476
477    pub fn r(&self) -> &EdwardsPoint {
478        &self.r
479    }
480
481    pub fn s(&self) -> &Scalar {
482        &self.s
483    }
484}
485
486/// An identifier for the mainnet production key
487#[derive(Copy, Clone, Eq, PartialEq, Debug)]
488pub enum MasterPublicKeyId {
489    /// The production master key
490    Key1,
491    /// The test master key
492    TestKey1,
493}
494
495/// An identifier for the hardcoded keys used in PocketIC
496#[derive(Copy, Clone, Eq, PartialEq, Debug)]
497pub enum PocketIcMasterPublicKeyId {
498    /// The PocketIC hardcoded key "key_1"
499    Key1,
500    /// The PocketIC hardcoded key "test_key_1"
501    TestKey1,
502    /// The PocketIC hardcoded key "dfx_test_key"
503    DfxTestKey,
504}
505
506/// An Ed25519 public key
507#[derive(Copy, Clone, Eq, PartialEq, Debug)]
508pub struct PublicKey {
509    pk: VerifyingKey,
510    // TODO(CRP-2412) This struct member can be removed once
511    // https://github.com/dalek-cryptography/curve25519-dalek/issues/624
512    // makes it into a release and replaced with calls to to_edwards
513    // where required
514    edwards: EdwardsPoint,
515}
516
517/// An error that occurs when verifying signatures or batches of signatures
518#[derive(Copy, Clone, Debug, Error)]
519pub enum SignatureError {
520    /// The signature had an invalid length, and cannot possibly be valid
521    #[error("The signature had an invalid length, and cannot possibly be valid")]
522    InvalidLength,
523    /// The batch was invalid (e.g., due to length mismatch between number of
524    /// messages and number of signatures)
525    #[error(
526        "The batch was invalid (e.g., due to length mismatch between number of 
527        messages and number of signatures)"
528    )]
529    InvalidBatch,
530    /// A signature was invalid
531    #[error("A signature was invalid")]
532    InvalidSignature,
533}
534
535impl PublicKey {
536    /// The number of bytes in the raw public key
537    pub const BYTES: usize = 32;
538
539    /// Internal constructor
540    ///
541    /// # Warning
542    ///
543    /// This does not verify that the key is within the prime order
544    /// subgroup, or that the public key is canonical. To check these
545    /// properties, use is_torsion_free and is_canonical
546    fn new(pk: VerifyingKey) -> Self {
547        let edwards = CompressedEdwardsY(pk.to_bytes()).decompress().unwrap();
548
549        Self { pk, edwards }
550    }
551
552    /// Return true if and only if the key is contained within the prime
553    /// order subgroup
554    pub fn is_torsion_free(&self) -> bool {
555        // We don't need to call is_weak here since that is subsumed by the
556        // test that the point is torsion free - is_weak just checks if the
557        // point is within the size-8 cofactor group.
558        self.edwards.is_torsion_free()
559    }
560
561    /// Return true if and only if the public key uses a canonical encoding
562    pub fn is_canonical(&self) -> bool {
563        self.pk.to_bytes() == self.edwards.compress().0
564    }
565
566    /// Convert a raw Ed25519 public key (32 bytes) to the DER encoding
567    ///
568    /// # Warning
569    ///
570    /// This performs no validity check on the public key aside from verifying
571    /// that it is exactly 32 bytes long. If you pass an invalid key (ie a
572    /// encoding of a point not in the prime order subgroup), then the DER
573    /// encoding of that invalid key will be returned.
574    pub fn convert_raw_to_der(raw: &[u8]) -> Result<Vec<u8>, PublicKeyDecodingError> {
575        // We continue to check the length, since otherwise the DER
576        // encoding itself would be invalid and unparsable.
577        if raw.len() != Self::BYTES {
578            return Err(PublicKeyDecodingError::InvalidKeyEncoding(format!(
579                "Expected key of exactly {} bytes, got {}",
580                Self::BYTES,
581                raw.len()
582            )));
583        };
584
585        const DER_PREFIX: [u8; 12] = [
586            48, 42, // A sequence of 42 bytes follows
587            48, 5, // An sequence of 5 bytes follows
588            6, 3, 43, 101, 112, // The OID (1.3.101.112)
589            3, 33, // A bitstring of 33 bytes follows
590            0,  // The bitstring has no unused bits
591        ];
592
593        let mut der_enc = Vec::with_capacity(DER_PREFIX.len() + Self::BYTES);
594        der_enc.extend_from_slice(&DER_PREFIX);
595        der_enc.extend_from_slice(raw);
596        Ok(der_enc)
597    }
598
599    /// Serialize this public key in raw format
600    ///
601    /// This is just the 32 byte encoding of the public point
602    pub fn serialize_raw(&self) -> [u8; Self::BYTES] {
603        *self.pk.as_bytes()
604    }
605
606    /// Deserialize a public key in raw format
607    ///
608    /// This is just the 32 byte encoding of the public point,
609    /// cooresponding to Self::serialize_raw
610    ///
611    /// # Warning
612    ///
613    /// This does not verify that the key is within the prime order
614    /// subgroup, or that the public key is canonical. To check these
615    /// properties, use is_torsion_free and is_canonical
616    pub fn deserialize_raw(bytes: &[u8]) -> Result<Self, PublicKeyDecodingError> {
617        let bytes = <[u8; Self::BYTES]>::try_from(bytes).map_err(|_| {
618            PublicKeyDecodingError::InvalidKeyEncoding(format!(
619                "Expected key of exactly {} bytes, got {}",
620                Self::BYTES,
621                bytes.len()
622            ))
623        })?;
624        let pk = VerifyingKey::from_bytes(&bytes)
625            .map_err(|e| PublicKeyDecodingError::InvalidKeyEncoding(format!("{e:?}")))?;
626
627        Ok(Self::new(pk))
628    }
629
630    /// Serialize this public key as a DER encoded structure
631    ///
632    /// See RFC 8410 for details on the format
633    pub fn serialize_rfc8410_der(&self) -> Vec<u8> {
634        let der = self.pk.to_public_key_der();
635
636        // See comment in serialize_pkcs8 regarding this expect
637        der.expect("Encoding public key as DER failed")
638            .as_bytes()
639            .to_vec()
640    }
641
642    /// Serialize this public key as a PEM encoded structure
643    ///
644    /// See RFC 8410 for details on the format
645    pub fn serialize_rfc8410_pem(&self) -> Vec<u8> {
646        pem::encode(&pem::Pem {
647            tag: "PUBLIC KEY".to_string(),
648            contents: self.serialize_rfc8410_der(),
649        })
650        .into()
651    }
652
653    /// Deserialize the DER encoded public key
654    ///
655    /// See RFC 8410 for details on the format. This cooresponds to
656    /// Self::serialize_rfc8410_der
657    ///
658    /// # Warning
659    ///
660    /// This does not verify that the key is within the prime order
661    /// subgroup, or that the public key is canonical. To check these
662    /// properties, use is_torsion_free and is_canonical
663    pub fn deserialize_rfc8410_der(bytes: &[u8]) -> Result<Self, PublicKeyDecodingError> {
664        let pk = VerifyingKey::from_public_key_der(bytes)
665            .map_err(|e| PublicKeyDecodingError::InvalidKeyEncoding(format!("{e:?}")))?;
666        Ok(Self::new(pk))
667    }
668
669    /// Deserialize the PEM encoded public key
670    ///
671    /// See RFC 8410 for details on the format. This cooresponds to
672    /// Self::serialize_rfc8410_pem
673    ///
674    /// # Warning
675    ///
676    /// This does not verify that the key is within the prime order
677    /// subgroup, or that the public key is canonical. To check these
678    /// properties, use is_torsion_free and is_canonical
679    pub fn deserialize_rfc8410_pem(pem: &str) -> Result<Self, PublicKeyDecodingError> {
680        let der = pem::parse(pem)
681            .map_err(|e| PublicKeyDecodingError::InvalidPemEncoding(format!("{e:?}")))?;
682        if der.tag != "PUBLIC KEY" {
683            return Err(PublicKeyDecodingError::UnexpectedPemLabel(der.tag));
684        }
685
686        Self::deserialize_rfc8410_der(&der.contents)
687    }
688
689    /// Helper function for computing H(R || A || M)
690    fn compute_challenge(sig: &Signature, pk: &Self, msg: &[u8]) -> Scalar {
691        let mut sha512 = Sha512::new();
692        sha512.update(sig.r_bytes());
693        // VerifyingKey::as_bytes returns the original encoding which may be non-canonical;
694        // this is exactly what we need under ZIP215
695        sha512.update(pk.pk.as_bytes());
696        sha512.update(msg);
697        Scalar::from_hash(sha512)
698    }
699
700    /// Verify a Ed25519 signature
701    ///
702    /// Returns Ok if the signature is valid, or Err otherwise
703    ///
704    /// This verification follows ZIP215 validation rules
705    pub fn verify_signature(&self, msg: &[u8], signature: &[u8]) -> Result<(), SignatureError> {
706        let signature = Signature::from_slice(signature)?;
707
708        let k = Self::compute_challenge(&signature, self, msg);
709        let minus_a = -self.edwards;
710        let recomputed_r =
711            EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &minus_a, signature.s());
712
713        use curve25519_dalek::traits::IsIdentity;
714
715        if (recomputed_r - signature.r())
716            .mul_by_cofactor()
717            .is_identity()
718        {
719            Ok(())
720        } else {
721            Err(SignatureError::InvalidSignature)
722        }
723    }
724
725    /// Verify a batch of signatures
726    ///
727    /// Returns Ok if the signatures are all valid, or Err otherwise
728    ///
729    /// Note that this does not indicate which of the signature(s) are invalid;
730    /// if batch verification fails you must then test serially to find the
731    /// valid signatures (if any).
732    ///
733    /// This verification follows ZIP215 validation rules
734    #[cfg(feature = "rand")]
735    pub fn batch_verify<R: rand::CryptoRng + rand::Rng>(
736        messages: &[&[u8]],
737        signatures: &[&[u8]],
738        keys: &[Self],
739        rng: &mut R,
740    ) -> Result<(), SignatureError> {
741        if messages.len() != signatures.len() || signatures.len() != keys.len() {
742            return Err(SignatureError::InvalidBatch);
743        }
744
745        use curve25519_dalek::{
746            constants::ED25519_BASEPOINT_POINT, traits::IsIdentity, traits::VartimeMultiscalarMul,
747        };
748        use std::iter::once;
749
750        let signatures = signatures
751            .iter()
752            .map(|s| Signature::from_slice(s))
753            .collect::<Result<Vec<_>, _>>()?;
754
755        let n = signatures.len();
756
757        let hrams = (0..n)
758            .map(|i| Self::compute_challenge(&signatures[i], &keys[i], messages[i]))
759            .collect::<Vec<_>>();
760
761        // Select a random Scalar for each signature.
762        let zs: Vec<Scalar> = (0..n).map(|_| Scalar::from(rng.r#gen::<u128>())).collect();
763
764        let b_coefficient: Scalar = signatures
765            .iter()
766            .zip(zs.iter())
767            .map(|(sig, z)| sig.s() * z)
768            .sum();
769
770        let zhrams = hrams.iter().zip(zs.iter()).map(|(hram, z)| hram * z);
771
772        let r = signatures.iter().map(|sig| *sig.r());
773        let pk = keys.iter().map(|pk| pk.edwards);
774
775        let id = EdwardsPoint::vartime_multiscalar_mul(
776            once(-b_coefficient).chain(zs.iter().cloned()).chain(zhrams),
777            once(ED25519_BASEPOINT_POINT).chain(r).chain(pk),
778        )
779        .mul_by_cofactor();
780
781        if id.is_identity() {
782            Ok(())
783        } else {
784            Err(SignatureError::InvalidSignature)
785        }
786    }
787
788    /// Return the public master keys used in the production mainnet
789    pub fn mainnet_key(key_id: MasterPublicKeyId) -> Self {
790        match key_id {
791            MasterPublicKeyId::Key1 => Self::deserialize_raw(&hex!(
792                "476374d9df3a8af28d3164dc2422cff894482eadd1295290b6d9ad92b2eeaa5c"
793            ))
794            .expect("Hardcoded master key was rejected"),
795            MasterPublicKeyId::TestKey1 => Self::deserialize_raw(&hex!(
796                "6c0824beb37621bcca6eecc237ed1bc4e64c9c59dcb85344aa7f9cc8278ee31f"
797            ))
798            .expect("Hardcoded master key was rejected"),
799        }
800    }
801
802    /// Return the public master keys used by PocketIC
803    ///
804    /// Note that the secret keys for these public keys are known, and these keys
805    /// should only be used for offline testing with PocketIC
806    pub fn pocketic_key(key_id: PocketIcMasterPublicKeyId) -> Self {
807        match key_id {
808            PocketIcMasterPublicKeyId::Key1 => Self::deserialize_raw(&hex!(
809                "db415b8eb85bd5127b0984723e0448054042cf40e7a9c262ed0cc87ecea98349"
810            ))
811            .expect("Hardcoded master key was rejected"),
812            PocketIcMasterPublicKeyId::TestKey1 => Self::deserialize_raw(&hex!(
813                "6ed9121ecf701b9e301fce17d8a65214888984e8211225691b089d6b219ec144"
814            ))
815            .expect("Hardcoded master key was rejected"),
816            PocketIcMasterPublicKeyId::DfxTestKey => Self::deserialize_raw(&hex!(
817                "7124afcb1be5927cac0397a7447b9c3cda2a4099af62d9bc0a2c2fe42d33efe1"
818            ))
819            .expect("Hardcoded master key was rejected"),
820        }
821    }
822
823    /// Derive a public key from the mainnet parameters
824    ///
825    /// This is an offline equivalent to the `schnorr_public_key` management canister call
826    pub fn derive_mainnet_key(
827        key_id: MasterPublicKeyId,
828        canister_id: &CanisterId,
829        derivation_path: &[Vec<u8>],
830    ) -> (Self, [u8; 32]) {
831        let mk = PublicKey::mainnet_key(key_id);
832        mk.derive_subkey(&DerivationPath::from_canister_id_and_path(
833            canister_id.as_slice(),
834            derivation_path,
835        ))
836    }
837
838    /// Derive a public key as is done on PocketIC
839    ///
840    /// This is an offline equivalent to the `schnorr_public_key` management canister call
841    /// when running on PocketIC
842    pub fn derive_pocketic_key(
843        key_id: PocketIcMasterPublicKeyId,
844        canister_id: &CanisterId,
845        derivation_path: &[Vec<u8>],
846    ) -> (Self, [u8; 32]) {
847        let mk = PublicKey::pocketic_key(key_id);
848        mk.derive_subkey(&DerivationPath::from_canister_id_and_path(
849            canister_id.as_slice(),
850            derivation_path,
851        ))
852    }
853
854    /// Derive a public key from this public key using a derivation path
855    ///
856    /// This is the same derivation system used by the Internet Computer when
857    /// deriving subkeys for Ed25519
858    pub fn derive_subkey(&self, derivation_path: &DerivationPath) -> (Self, [u8; 32]) {
859        let chain_code = [0u8; 32];
860        self.derive_subkey_with_chain_code(derivation_path, &chain_code)
861    }
862
863    /// Derive a public key from this public key using a derivation path
864    /// and chain code
865    ///
866    /// This is the same derivation system used by the Internet Computer when
867    /// deriving subkeys for Ed25519
868    pub fn derive_subkey_with_chain_code(
869        &self,
870        derivation_path: &DerivationPath,
871        chain_code: &[u8; 32],
872    ) -> (Self, [u8; 32]) {
873        // TODO(CRP-2412) Use VerifyingKey::to_edwards once available
874
875        let pt = CompressedEdwardsY(self.pk.to_bytes()).decompress().unwrap();
876
877        let (pt, _sum, chain_code) = derivation_path.derive_offset(pt, chain_code);
878
879        let key = Self::new(VerifyingKey::from(pt));
880
881        (key, chain_code)
882    }
883}
884
885/// A component of a derivation path
886#[derive(Clone, Debug)]
887pub struct DerivationIndex(pub Vec<u8>);
888
889/// Derivation Path
890///
891/// A derivation path is simply a sequence of DerivationIndex
892#[derive(Clone, Debug)]
893pub struct DerivationPath {
894    path: Vec<DerivationIndex>,
895}
896
897impl DerivationPath {
898    /// Create a BIP32-style derivation path
899    pub fn new_bip32(bip32: &[u32]) -> Self {
900        let mut path = Vec::with_capacity(bip32.len());
901        for n in bip32 {
902            path.push(DerivationIndex(n.to_be_bytes().to_vec()));
903        }
904        Self::new(path)
905    }
906
907    /// Create a free-form derivation path
908    pub fn new(path: Vec<DerivationIndex>) -> Self {
909        Self { path }
910    }
911
912    /// Create a path from a canister ID and a user provided path
913    pub fn from_canister_id_and_path(canister_id: &[u8], path: &[Vec<u8>]) -> Self {
914        let mut vpath = Vec::with_capacity(1 + path.len());
915        vpath.push(DerivationIndex(canister_id.to_vec()));
916
917        for n in path {
918            vpath.push(DerivationIndex(n.to_vec()));
919        }
920        Self::new(vpath)
921    }
922
923    /// Return the length of this path
924    pub fn len(&self) -> usize {
925        self.path.len()
926    }
927
928    /// Return if this path is empty
929    pub fn is_empty(&self) -> bool {
930        self.len() == 0
931    }
932
933    /// Return the components of the derivation path
934    pub fn path(&self) -> &[DerivationIndex] {
935        &self.path
936    }
937
938    fn derive_offset(
939        &self,
940        mut pt: EdwardsPoint,
941        chain_code: &[u8; 32],
942    ) -> (EdwardsPoint, Scalar, [u8; 32]) {
943        let mut chain_code = *chain_code;
944        let mut sum = Scalar::ZERO;
945
946        for idx in self.path() {
947            let mut ikm = Vec::with_capacity(PublicKey::BYTES + idx.0.len());
948            ikm.extend_from_slice(&pt.compress().0);
949            ikm.extend_from_slice(&idx.0);
950
951            let hkdf = hkdf::Hkdf::<Sha512>::new(Some(&chain_code), &ikm);
952
953            let mut okm = [0u8; 96];
954            hkdf.expand(b"Ed25519", &mut okm)
955                .expect("96 is a valid length for HKDF-SHA-512");
956
957            let mut offset = [0u8; 64];
958            offset.copy_from_slice(&okm[0..64]);
959            offset.reverse(); // dalek uses little endian
960            let offset = Scalar::from_bytes_mod_order_wide(&offset);
961
962            pt += EdwardsPoint::mul_base(&offset);
963            sum += offset;
964            chain_code.copy_from_slice(&okm[64..]);
965        }
966
967        (pt, sum, chain_code)
968    }
969}