Coverage Report

Created: 2025-11-16 06:37

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