Coverage Report

Created: 2026-07-25 06:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/aws-lc-rs-1.16.2/src/ed25519.rs
Line
Count
Source
1
// Copyright 2015-2016 Brian Smith.
2
// SPDX-License-Identifier: ISC
3
// Modifications copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
4
// SPDX-License-Identifier: Apache-2.0 OR ISC
5
6
use core::fmt;
7
use core::fmt::{Debug, Formatter};
8
use std::marker::PhantomData;
9
10
#[cfg(feature = "ring-sig-verify")]
11
use untrusted::Input;
12
13
use crate::aws_lc::{EVP_PKEY, EVP_PKEY_ED25519};
14
15
use crate::buffer::Buffer;
16
use crate::digest::Digest;
17
use crate::encoding::{
18
    AsBigEndian, AsDer, Curve25519SeedBin, Pkcs8V1Der, Pkcs8V2Der, PublicKeyX509Der,
19
};
20
use crate::error::{KeyRejected, Unspecified};
21
use crate::evp_pkey::No_EVP_PKEY_CTX_consumer;
22
use crate::pkcs8::{Document, Version};
23
use crate::ptr::LcPtr;
24
use crate::rand::SecureRandom;
25
use crate::signature::{
26
    KeyPair, ParsedPublicKey, ParsedVerificationAlgorithm, Signature, VerificationAlgorithm,
27
};
28
use crate::{constant_time, digest, hex, sealed};
29
30
/// The length of an Ed25519 public key.
31
pub const ED25519_PUBLIC_KEY_LEN: usize = crate::aws_lc::ED25519_PUBLIC_KEY_LEN as usize;
32
const ED25519_SIGNATURE_LEN: usize = crate::aws_lc::ED25519_SIGNATURE_LEN as usize;
33
const ED25519_SEED_LEN: usize = 32;
34
35
/// Parameters for `EdDSA` signing and verification.
36
#[derive(Debug)]
37
pub struct EdDSAParameters;
38
39
impl sealed::Sealed for EdDSAParameters {}
40
41
impl ParsedVerificationAlgorithm for EdDSAParameters {
42
0
    fn parsed_verify_sig(
43
0
        &self,
44
0
        public_key: &ParsedPublicKey,
45
0
        msg: &[u8],
46
0
        signature: &[u8],
47
0
    ) -> Result<(), Unspecified> {
48
0
        public_key
49
0
            .key()
50
0
            .verify(msg, None, No_EVP_PKEY_CTX_consumer, signature)
51
0
    }
52
53
0
    fn parsed_verify_digest_sig(
54
0
        &self,
55
0
        _public_key: &ParsedPublicKey,
56
0
        _digest: &Digest,
57
0
        _signature: &[u8],
58
0
    ) -> Result<(), Unspecified> {
59
0
        Err(Unspecified)
60
0
    }
61
}
62
63
impl VerificationAlgorithm for EdDSAParameters {
64
    #[inline]
65
    #[cfg(feature = "ring-sig-verify")]
66
    fn verify(
67
        &self,
68
        public_key: Input<'_>,
69
        msg: Input<'_>,
70
        signature: Input<'_>,
71
    ) -> Result<(), Unspecified> {
72
        self.verify_sig(
73
            public_key.as_slice_less_safe(),
74
            msg.as_slice_less_safe(),
75
            signature.as_slice_less_safe(),
76
        )
77
    }
78
79
    /// Verify `signature` for `msg` using `public_key`.
80
    ///
81
    /// # Errors
82
    ///  Returns `Unspecified` if the `msg` cannot be verified using `public_key`.
83
0
    fn verify_sig(
84
0
        &self,
85
0
        public_key: &[u8],
86
0
        msg: &[u8],
87
0
        signature: &[u8],
88
0
    ) -> Result<(), Unspecified> {
89
0
        let evp_pkey = parse_ed25519_public_key(public_key)?;
90
0
        evp_pkey.verify(msg, None, No_EVP_PKEY_CTX_consumer, signature)
91
0
    }
92
93
    /// DO NOT USE. This function is required by `VerificationAlgorithm` but cannot be used w/ Ed25519.
94
    ///
95
    /// # Errors
96
    /// Always returns `Unspecified`.
97
0
    fn verify_digest_sig(
98
0
        &self,
99
0
        _public_key: &[u8],
100
0
        _digest: &digest::Digest,
101
0
        _signature: &[u8],
102
0
    ) -> Result<(), Unspecified> {
103
0
        Err(Unspecified)
104
0
    }
105
}
106
107
0
pub(crate) fn parse_ed25519_public_key(key_bytes: &[u8]) -> Result<LcPtr<EVP_PKEY>, KeyRejected> {
108
    // If the length of key bytes matches the raw public key size then it has to be that
109
0
    if key_bytes.len() == ED25519_PUBLIC_KEY_LEN {
110
0
        LcPtr::<EVP_PKEY>::parse_raw_public_key(key_bytes, EVP_PKEY_ED25519)
111
    } else {
112
        // Otherwise we support X.509 SubjectPublicKeyInfo formatted keys which are inherently larger
113
0
        LcPtr::<EVP_PKEY>::parse_rfc5280_public_key(key_bytes, EVP_PKEY_ED25519)
114
    }
115
0
}
116
117
/// An Ed25519 key pair, for signing.
118
#[allow(clippy::module_name_repetitions)]
119
pub struct Ed25519KeyPair {
120
    evp_pkey: LcPtr<EVP_PKEY>,
121
    public_key: PublicKey,
122
}
123
124
impl Debug for Ed25519KeyPair {
125
0
    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
126
0
        f.write_str(&format!(
127
0
            "Ed25519KeyPair {{ public_key: PublicKey(\"{}\") }}",
128
0
            hex::encode(&self.public_key)
129
0
        ))
130
0
    }
131
}
132
133
#[derive(Clone)]
134
#[allow(clippy::module_name_repetitions)]
135
/// The seed value for the `EdDSA` signature scheme using Curve25519
136
pub struct Seed<'a> {
137
    bytes: Box<[u8]>,
138
    phantom: PhantomData<&'a [u8]>,
139
}
140
141
impl AsBigEndian<Curve25519SeedBin<'static>> for Seed<'_> {
142
    /// Exposes the seed encoded as a big-endian fixed-length integer.
143
    ///
144
    /// For most use-cases, `EcdsaKeyPair::to_pkcs8()` should be preferred.
145
    ///
146
    /// # Errors
147
    /// `error::Unspecified` if serialization failed.
148
0
    fn as_be_bytes(&self) -> Result<Curve25519SeedBin<'static>, Unspecified> {
149
0
        Ok(Curve25519SeedBin::new(self.bytes.to_vec()))
150
0
    }
151
}
152
153
impl Debug for Seed<'_> {
154
0
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
155
0
        f.write_str("Ed25519Seed()")
156
0
    }
157
}
158
159
#[derive(Clone)]
160
#[allow(clippy::module_name_repetitions)]
161
/// Ed25519 Public Key
162
pub struct PublicKey {
163
    evp_pkey: LcPtr<EVP_PKEY>,
164
    public_key_bytes: [u8; ED25519_PUBLIC_KEY_LEN],
165
}
166
167
impl AsRef<[u8]> for PublicKey {
168
    #[inline]
169
    /// Returns the "raw" bytes of the ED25519 public key
170
0
    fn as_ref(&self) -> &[u8] {
171
0
        &self.public_key_bytes
172
0
    }
Unexecuted instantiation: <aws_lc_rs::ed25519::PublicKey as core::convert::AsRef<[u8]>>::as_ref
Unexecuted instantiation: <aws_lc_rs::ed25519::PublicKey as core::convert::AsRef<[u8]>>::as_ref
173
}
174
175
impl Debug for PublicKey {
176
0
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
177
0
        f.write_str(&format!(
178
0
            "PublicKey(\"{}\")",
179
0
            hex::encode(self.public_key_bytes)
180
0
        ))
181
0
    }
182
}
183
184
unsafe impl Send for PublicKey {}
185
unsafe impl Sync for PublicKey {}
186
187
impl AsDer<PublicKeyX509Der<'static>> for PublicKey {
188
    /// Provides the public key as a DER-encoded (X.509) `SubjectPublicKeyInfo` structure.
189
    /// # Errors
190
    /// Returns an error if the public key fails to marshal to X.509.
191
0
    fn as_der(&self) -> Result<PublicKeyX509Der<'static>, crate::error::Unspecified> {
192
        // Initial size of 44 based on:
193
        // 0:d=0  hl=2 l=  42 cons: SEQUENCE
194
        // 2:d=1  hl=2 l=   5 cons:  SEQUENCE
195
        // 4:d=2  hl=2 l=   3 prim:   OBJECT            :ED25519
196
        // 9:d=1  hl=2 l=  33 prim:  BIT STRING
197
0
        let der = self.evp_pkey.as_const().marshal_rfc5280_public_key()?;
198
0
        Ok(PublicKeyX509Der::from(Buffer::new(der)))
199
0
    }
200
}
201
202
impl KeyPair for Ed25519KeyPair {
203
    type PublicKey = PublicKey;
204
    #[inline]
205
0
    fn public_key(&self) -> &Self::PublicKey {
206
0
        &self.public_key
207
0
    }
Unexecuted instantiation: <aws_lc_rs::ed25519::Ed25519KeyPair as aws_lc_rs::signature::KeyPair>::public_key
Unexecuted instantiation: <aws_lc_rs::ed25519::Ed25519KeyPair as aws_lc_rs::signature::KeyPair>::public_key
208
}
209
210
unsafe impl Send for Ed25519KeyPair {}
211
unsafe impl Sync for Ed25519KeyPair {}
212
213
0
pub(crate) fn generate_key() -> Result<LcPtr<EVP_PKEY>, Unspecified> {
214
0
    LcPtr::<EVP_PKEY>::generate(EVP_PKEY_ED25519, No_EVP_PKEY_CTX_consumer)
215
0
}
216
217
impl Ed25519KeyPair {
218
    /// Generates a new key pair and returns the key pair.
219
    ///
220
    /// # Errors
221
    /// `error::Unspecified` if key generation fails.
222
0
    pub fn generate() -> Result<Self, Unspecified> {
223
0
        let evp_pkey = generate_key()?;
224
225
0
        let mut public_key = [0u8; ED25519_PUBLIC_KEY_LEN];
226
0
        let out_len: usize = evp_pkey
227
0
            .as_const()
228
0
            .marshal_raw_public_to_buffer(&mut public_key)?;
229
0
        debug_assert_eq!(public_key.len(), out_len);
230
231
0
        Ok(Self {
232
0
            public_key: PublicKey {
233
0
                public_key_bytes: public_key,
234
0
                evp_pkey: evp_pkey.clone(),
235
0
            },
236
0
            evp_pkey,
237
0
        })
238
0
    }
239
240
    /// Generates a new key pair and returns the key pair serialized as a
241
    /// PKCS#8 document.
242
    ///
243
    /// The PKCS#8 document will be a v2 `OneAsymmetricKey` with the public key,
244
    /// as described in [RFC 5958 Section 2]; see [RFC 8410 Section 10.3] for an
245
    /// example.
246
    ///
247
    /// [RFC 5958 Section 2]: https://tools.ietf.org/html/rfc5958#section-2
248
    /// [RFC 8410 Section 10.3]: https://tools.ietf.org/html/rfc8410#section-10.3
249
    ///
250
    /// # *ring* Compatibility
251
    /// The ring 0.16.x API did not produce encoded v2 documents that were compliant with RFC 5958.
252
    /// The aws-lc-ring implementation produces PKCS#8 v2 encoded documents that are compliant per
253
    /// the RFC specification.
254
    ///
255
    /// Our implementation ignores the `SecureRandom` parameter.
256
    ///
257
    // # FIPS
258
    // This function must not be used.
259
    //
260
    /// # Errors
261
    /// `error::Unspecified` if `rng` cannot provide enough bits or if there's an internal error.
262
0
    pub fn generate_pkcs8(_rng: &dyn SecureRandom) -> Result<Document, Unspecified> {
263
0
        let evp_pkey = generate_key()?;
264
0
        Ok(Document::new(
265
0
            evp_pkey
266
0
                .as_const()
267
0
                .marshal_rfc5208_private_key(Version::V2)?,
268
        ))
269
0
    }
270
271
    /// Serializes this `Ed25519KeyPair` into a PKCS#8 v2 document.
272
    ///
273
    /// # Errors
274
    /// `error::Unspecified` on internal error.
275
    ///
276
0
    pub fn to_pkcs8(&self) -> Result<Document, Unspecified> {
277
0
        Ok(Document::new(
278
0
            self.evp_pkey
279
0
                .as_const()
280
0
                .marshal_rfc5208_private_key(Version::V2)?,
281
        ))
282
0
    }
283
284
    /// Generates a `Ed25519KeyPair` using the `rng` provided, then serializes that key as a
285
    /// PKCS#8 document.
286
    ///
287
    /// The PKCS#8 document will be a v1 `PrivateKeyInfo` structure (RFC5208). Use this method
288
    /// when needing to produce documents that are compatible with the OpenSSL CLI.
289
    ///
290
    /// # *ring* Compatibility
291
    ///  Our implementation ignores the `SecureRandom` parameter.
292
    ///
293
    // # FIPS
294
    // This function must not be used.
295
    //
296
    /// # Errors
297
    /// `error::Unspecified` if `rng` cannot provide enough bits or if there's an internal error.
298
0
    pub fn generate_pkcs8v1(_rng: &dyn SecureRandom) -> Result<Document, Unspecified> {
299
0
        let evp_pkey = generate_key()?;
300
0
        Ok(Document::new(
301
0
            evp_pkey
302
0
                .as_const()
303
0
                .marshal_rfc5208_private_key(Version::V1)?,
304
        ))
305
0
    }
306
307
    /// Serializes this `Ed25519KeyPair` into a PKCS#8 v1 document.
308
    ///
309
    /// # Errors
310
    /// `error::Unspecified` on internal error.
311
    ///
312
0
    pub fn to_pkcs8v1(&self) -> Result<Document, Unspecified> {
313
0
        Ok(Document::new(
314
0
            self.evp_pkey
315
0
                .as_const()
316
0
                .marshal_rfc5208_private_key(Version::V1)?,
317
        ))
318
0
    }
319
320
    /// Constructs an Ed25519 key pair from the private key seed `seed` and its
321
    /// public key `public_key`.
322
    ///
323
    /// It is recommended to use `Ed25519KeyPair::from_pkcs8()` instead.
324
    ///
325
    /// The private and public keys will be verified to be consistent with each
326
    /// other. This helps avoid misuse of the key (e.g. accidentally swapping
327
    /// the private key and public key, or using the wrong private key for the
328
    /// public key). This also detects any corruption of the public or private
329
    /// key.
330
    ///
331
    /// # Errors
332
    /// `error::KeyRejected` if parse error, or if key is otherwise unacceptable.
333
0
    pub fn from_seed_and_public_key(seed: &[u8], public_key: &[u8]) -> Result<Self, KeyRejected> {
334
0
        let this = Self::from_seed_unchecked(seed)?;
335
336
0
        constant_time::verify_slices_are_equal(public_key, &this.public_key.public_key_bytes)
337
0
            .map_err(|_| KeyRejected::inconsistent_components())?;
338
0
        Ok(this)
339
0
    }
340
341
    /// Constructs an Ed25519 key pair from the private key seed `seed`.
342
    ///
343
    /// It is recommended to use `Ed25519KeyPair::from_pkcs8()` instead. If the public key is
344
    /// available, prefer to use `Ed25519KeyPair::from_seed_and_public_key()` as it will verify
345
    /// the validity of the key pair.
346
    ///
347
    /// CAUTION: Both an Ed25519 seed and its public key are 32-bytes. If the bytes of a public key
348
    /// are provided this function will create an (effectively) invalid `Ed25519KeyPair`. This
349
    /// problem is undetectable by the API.
350
    ///
351
    /// # Errors
352
    /// `error::KeyRejected` if parse error, or if key is otherwise unacceptable.
353
0
    pub fn from_seed_unchecked(seed: &[u8]) -> Result<Self, KeyRejected> {
354
0
        if seed.len() < ED25519_SEED_LEN {
355
0
            return Err(KeyRejected::inconsistent_components());
356
0
        }
357
358
0
        let evp_pkey = LcPtr::<EVP_PKEY>::parse_raw_private_key(seed, EVP_PKEY_ED25519)?;
359
360
0
        let mut derived_public_key = [0u8; ED25519_PUBLIC_KEY_LEN];
361
0
        let out_len: usize = evp_pkey
362
0
            .as_const()
363
0
            .marshal_raw_public_to_buffer(&mut derived_public_key)?;
364
0
        debug_assert_eq!(derived_public_key.len(), out_len);
365
366
0
        Ok(Self {
367
0
            public_key: PublicKey {
368
0
                public_key_bytes: derived_public_key,
369
0
                evp_pkey: evp_pkey.clone(),
370
0
            },
371
0
            evp_pkey,
372
0
        })
373
0
    }
374
375
    /// Constructs an Ed25519 key pair by parsing an unencrypted PKCS#8 v1 or v2
376
    /// Ed25519 private key.
377
    ///
378
    /// `openssl genpkey -algorithm ED25519` generates PKCS#8 v1 keys.
379
    ///
380
    /// # Ring Compatibility
381
    /// * This method accepts either v1 or v2 encoded keys, if a v2 encoded key is provided, with the
382
    ///   public key component present, it will be verified to match the one derived from the
383
    ///   encoded private key.
384
    /// * The ring 0.16.x API did not produce encoded v2 documents that were compliant with RFC 5958.
385
    ///   The aws-lc-ring implementation produces PKCS#8 v2 encoded documents that are compliant per
386
    ///   the RFC specification.
387
    ///
388
    /// # Errors
389
    /// `error::KeyRejected` on parse error, or if key is otherwise unacceptable.
390
0
    pub fn from_pkcs8(pkcs8: &[u8]) -> Result<Self, KeyRejected> {
391
0
        Self::parse_pkcs8(pkcs8)
392
0
    }
393
394
    /// Constructs an Ed25519 key pair by parsing an unencrypted PKCS#8 v1 or v2
395
    /// Ed25519 private key.
396
    ///
397
    /// `openssl genpkey -algorithm ED25519` generates PKCS# v1 keys.
398
    ///
399
    /// # Ring Compatibility
400
    /// * This method accepts either v1 or v2 encoded keys, if a v2 encoded key is provided, with the
401
    ///   public key component present, it will be verified to match the one derived from the
402
    ///   encoded private key.
403
    /// * The ring 0.16.x API did not produce encoded v2 documents that were compliant with RFC 5958.
404
    ///   The aws-lc-ring implementation produces PKCS#8 v2 encoded documents that are compliant per
405
    ///   the RFC specification.
406
    ///
407
    /// # Errors
408
    /// `error::KeyRejected` on parse error, or if key is otherwise unacceptable.
409
0
    pub fn from_pkcs8_maybe_unchecked(pkcs8: &[u8]) -> Result<Self, KeyRejected> {
410
0
        Self::parse_pkcs8(pkcs8)
411
0
    }
412
413
0
    fn parse_pkcs8(pkcs8: &[u8]) -> Result<Self, KeyRejected> {
414
0
        let evp_pkey = LcPtr::<EVP_PKEY>::parse_rfc5208_private_key(pkcs8, EVP_PKEY_ED25519)?;
415
416
0
        evp_pkey.as_const().validate_as_ed25519()?;
417
418
0
        let mut public_key = [0u8; ED25519_PUBLIC_KEY_LEN];
419
0
        let out_len: usize = evp_pkey
420
0
            .as_const()
421
0
            .marshal_raw_public_to_buffer(&mut public_key)?;
422
0
        debug_assert_eq!(public_key.len(), out_len);
423
424
0
        Ok(Self {
425
0
            public_key: PublicKey {
426
0
                public_key_bytes: public_key,
427
0
                evp_pkey: evp_pkey.clone(),
428
0
            },
429
0
            evp_pkey,
430
0
        })
431
0
    }
432
433
    /// Returns the signature of the message msg.
434
    ///
435
    // # FIPS
436
    // This method must not be used.
437
    //
438
    /// # Panics
439
    /// Panics if the message is unable to be signed
440
    #[inline]
441
    #[must_use]
442
0
    pub fn sign(&self, msg: &[u8]) -> Signature {
443
0
        Self::try_sign(self, msg).expect("ED25519 signing failed")
444
0
    }
Unexecuted instantiation: <aws_lc_rs::ed25519::Ed25519KeyPair>::sign
Unexecuted instantiation: <aws_lc_rs::ed25519::Ed25519KeyPair>::sign
445
446
    /// Returns the signature of the message `msg`.
447
    ///
448
    // # FIPS
449
    // This method must not be used.
450
    //
451
    /// # Errors
452
    /// Returns `error::Unspecified` if the signing operation fails.
453
    #[inline]
454
0
    pub fn try_sign(&self, msg: &[u8]) -> Result<Signature, Unspecified> {
455
0
        let sig_bytes = self.evp_pkey.sign(msg, None, No_EVP_PKEY_CTX_consumer)?;
456
457
0
        Ok(Signature::new(|slice| {
458
0
            slice[0..ED25519_SIGNATURE_LEN].copy_from_slice(&sig_bytes);
459
0
            ED25519_SIGNATURE_LEN
460
0
        }))
Unexecuted instantiation: <aws_lc_rs::ed25519::Ed25519KeyPair>::try_sign::{closure#0}
Unexecuted instantiation: <aws_lc_rs::ed25519::Ed25519KeyPair>::try_sign::{closure#0}
461
0
    }
Unexecuted instantiation: <aws_lc_rs::ed25519::Ed25519KeyPair>::try_sign
Unexecuted instantiation: <aws_lc_rs::ed25519::Ed25519KeyPair>::try_sign
462
463
    /// Provides the private key "seed" for this `Ed25519` key pair.
464
    ///
465
    /// For serialization of the key pair, `Ed25519KeyPair::to_pkcs8()` is preferred.
466
    ///
467
    /// # Errors
468
    /// Currently the function cannot fail, but it might in future implementations.
469
0
    pub fn seed(&self) -> Result<Seed<'static>, Unspecified> {
470
        Ok(Seed {
471
0
            bytes: self
472
0
                .evp_pkey
473
0
                .as_const()
474
0
                .marshal_raw_private_key()?
475
0
                .into_boxed_slice(),
476
0
            phantom: PhantomData,
477
        })
478
0
    }
479
}
480
481
impl AsDer<Pkcs8V1Der<'static>> for Ed25519KeyPair {
482
    /// Serializes this `Ed25519KeyPair` into a PKCS#8 v1 document.
483
    ///
484
    /// # Errors
485
    /// `error::Unspecified` on internal error.
486
0
    fn as_der(&self) -> Result<Pkcs8V1Der<'static>, crate::error::Unspecified> {
487
0
        Ok(Pkcs8V1Der::new(
488
0
            self.evp_pkey
489
0
                .as_const()
490
0
                .marshal_rfc5208_private_key(Version::V1)?,
491
        ))
492
0
    }
493
}
494
495
impl AsDer<Pkcs8V2Der<'static>> for Ed25519KeyPair {
496
    /// Serializes this `Ed25519KeyPair` into a PKCS#8 v1 document.
497
    ///
498
    /// # Errors
499
    /// `error::Unspecified` on internal error.
500
0
    fn as_der(&self) -> Result<Pkcs8V2Der<'static>, crate::error::Unspecified> {
501
0
        Ok(Pkcs8V2Der::new(
502
0
            self.evp_pkey
503
0
                .as_const()
504
0
                .marshal_rfc5208_private_key(Version::V2)?,
505
        ))
506
0
    }
507
}
508
509
#[cfg(test)]
510
mod tests {
511
    use crate::ed25519::Ed25519KeyPair;
512
    use crate::encoding::{AsBigEndian, AsDer, Pkcs8V1Der, Pkcs8V2Der, PublicKeyX509Der};
513
    use crate::rand::SystemRandom;
514
    use crate::signature::{KeyPair, UnparsedPublicKey, ED25519};
515
    use crate::{hex, test};
516
517
    #[test]
518
    fn test_generate() {
519
        const MESSAGE: &[u8] = b"test message";
520
        let key_pair = Ed25519KeyPair::generate().unwrap();
521
        let public_key = key_pair.public_key();
522
        let signature = key_pair.sign(MESSAGE);
523
        let unparsed_public_key = UnparsedPublicKey::new(&ED25519, public_key.as_ref());
524
        unparsed_public_key
525
            .verify(MESSAGE, signature.as_ref())
526
            .unwrap();
527
    }
528
529
    #[test]
530
    fn test_generate_pkcs8() {
531
        let rng = SystemRandom::new();
532
        let document = Ed25519KeyPair::generate_pkcs8(&rng).unwrap();
533
        let kp1: Ed25519KeyPair = Ed25519KeyPair::from_pkcs8(document.as_ref()).unwrap();
534
        assert_eq!(
535
            document.as_ref(),
536
            AsDer::<Pkcs8V2Der>::as_der(&kp1).unwrap().as_ref()
537
        );
538
        let kp2: Ed25519KeyPair =
539
            Ed25519KeyPair::from_pkcs8_maybe_unchecked(document.as_ref()).unwrap();
540
        assert_eq!(
541
            kp1.seed().unwrap().as_be_bytes().unwrap().as_ref(),
542
            kp2.seed().unwrap().as_be_bytes().unwrap().as_ref(),
543
        );
544
        assert_eq!(kp1.public_key.as_ref(), kp2.public_key.as_ref());
545
546
        let document = Ed25519KeyPair::generate_pkcs8v1(&rng).unwrap();
547
        let kp1: Ed25519KeyPair = Ed25519KeyPair::from_pkcs8(document.as_ref()).unwrap();
548
        assert_eq!(
549
            document.as_ref(),
550
            AsDer::<Pkcs8V1Der>::as_der(&kp1).unwrap().as_ref()
551
        );
552
        let kp2: Ed25519KeyPair =
553
            Ed25519KeyPair::from_pkcs8_maybe_unchecked(document.as_ref()).unwrap();
554
        assert_eq!(
555
            kp1.seed().unwrap().as_be_bytes().unwrap().as_ref(),
556
            kp2.seed().unwrap().as_be_bytes().unwrap().as_ref(),
557
        );
558
        assert_eq!(kp1.public_key.as_ref(), kp2.public_key.as_ref());
559
        let seed = kp1.seed().unwrap();
560
        assert_eq!("Ed25519Seed()", format!("{seed:?}"));
561
    }
562
563
    #[test]
564
    fn test_from_pkcs8() {
565
        struct TestCase {
566
            key: &'static str,
567
            expected_public: &'static str,
568
        }
569
570
        for case in [
571
            TestCase {
572
                key: "302e020100300506032b6570042204209d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60",
573
                expected_public: "d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a",
574
            },
575
            TestCase {
576
                key: "3051020101300506032b657004220420756434bd5b824753007a138d27abbc14b5cc786adb78fb62435e6419a2b2e72b8121000faccd81e57de15fa6343a7fbb43b2b93f28be6435100ae8bd633c6dfee3d198",
577
                expected_public: "0faccd81e57de15fa6343a7fbb43b2b93f28be6435100ae8bd633c6dfee3d198",
578
            },
579
            TestCase {
580
                key: "304f020100300506032b657004220420d4ee72dbf913584ad5b6d8f1f769f8ad3afe7c28cbf1d4fbe097a88f44755842a01f301d060a2a864886f70d01090914310f0c0d437572646c6520436861697273",
581
                expected_public: "19bf44096984cdfe8541bac167dc3b96c85086aa30b6b6cb0c5c38ad703166e1",
582
            },
583
            TestCase {
584
                key: "3072020101300506032b657004220420d4ee72dbf913584ad5b6d8f1f769f8ad3afe7c28cbf1d4fbe097a88f44755842a01f301d060a2a864886f70d01090914310f0c0d437572646c652043686169727381210019bf44096984cdfe8541bac167dc3b96c85086aa30b6b6cb0c5c38ad703166e1",
585
                expected_public: "19bf44096984cdfe8541bac167dc3b96c85086aa30b6b6cb0c5c38ad703166e1",
586
            }
587
        ] {
588
            let key_pair = Ed25519KeyPair::from_pkcs8(&test::from_dirty_hex(case.key)).unwrap();
589
            assert_eq!(
590
                format!(
591
                    r#"Ed25519KeyPair {{ public_key: PublicKey("{}") }}"#,
592
                    case.expected_public
593
                ),
594
                format!("{key_pair:?}")
595
            );
596
            let key_pair = Ed25519KeyPair::from_pkcs8_maybe_unchecked(&test::from_dirty_hex(case.key)).unwrap();
597
            assert_eq!(
598
                format!(
599
                    r#"Ed25519KeyPair {{ public_key: PublicKey("{}") }}"#,
600
                    case.expected_public
601
                ),
602
                format!("{key_pair:?}")
603
            );
604
        }
605
    }
606
607
    #[test]
608
    fn test_public_key_as_der_x509() {
609
        let key_pair = Ed25519KeyPair::from_pkcs8(&hex::decode("302e020100300506032b6570042204209d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60").unwrap()).unwrap();
610
        let public_key = key_pair.public_key();
611
        let x509der = AsDer::<PublicKeyX509Der>::as_der(public_key).unwrap();
612
        assert_eq!(
613
            x509der.as_ref(),
614
            &[
615
                0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x03, 0x21, 0x00, 0xd7, 0x5a,
616
                0x98, 0x01, 0x82, 0xb1, 0x0a, 0xb7, 0xd5, 0x4b, 0xfe, 0xd3, 0xc9, 0x64, 0x07, 0x3a,
617
                0x0e, 0xe1, 0x72, 0xf3, 0xda, 0xa6, 0x23, 0x25, 0xaf, 0x02, 0x1a, 0x68, 0xf7, 0x07,
618
                0x51, 0x1a
619
            ]
620
        );
621
    }
622
}