Skip to main content

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