Skip to main content

arcana/encoding/
keys.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2026 Cédric Mesnil <cslashm@pm.me>
3
4//! Key serialization: PKCS#1 (RSA), SEC1 (ECC), SPKI, PKCS#8.
5//!
6//! Implements `to_*_der` / `from_*_der` and `to_*_pem` / `from_*_pem`
7//! on the existing key types in `rsa::rsa` and `ecc::curves` /
8//! `ecc::eddsa`.
9
10use super::der::*;
11use super::pem::*;
12use crate::ecc::curves::{PublicKey as EcPublicKey, SecretKey as EcSecretKey};
13use crate::ecc::eddsa::{Ed25519PublicKey, Ed25519SecretKey};
14use crate::rsa::bigint::BigInt;
15use crate::rsa::rsa::{RsaPublicKey, RsaSecretKey};
16
17// ====================================================================
18// RSA — PKCS#1 DER (RFC 8017 §A.1)
19// ====================================================================
20
21impl RsaPublicKey {
22    /// Encode as PKCS#1 DER (`RSAPublicKey ::= SEQUENCE { n INTEGER, e INTEGER }`).
23    pub fn to_pkcs1_der(&self) -> Vec<u8> {
24        let n_bytes = self.n.to_be_bytes(self.n.byte_len());
25        let e_bytes = self.e.to_be_bytes(self.e.byte_len());
26        let mut inner = DerEncoder::new();
27        inner.integer(&n_bytes);
28        inner.integer(&e_bytes);
29        let content = inner.finish();
30        let mut outer = DerEncoder::new();
31        outer.sequence(&content);
32        outer.finish()
33    }
34
35    /// Parse from PKCS#1 DER.
36    pub fn from_pkcs1_der(der: &[u8]) -> Option<Self> {
37        let mut dec = DerDecoder::new(der);
38        let mut seq = dec.read_sequence()?;
39        let n = BigInt::from_be_bytes(seq.read_integer()?);
40        let e = BigInt::from_be_bytes(seq.read_integer()?);
41        if !seq.is_empty() {
42            return None;
43        }
44        Some(Self { n, e })
45    }
46
47    /// Encode as SubjectPublicKeyInfo DER (RFC 5280).
48    pub fn to_spki_der(&self) -> Vec<u8> {
49        let pkcs1 = self.to_pkcs1_der();
50        // AlgorithmIdentifier: SEQUENCE { rsaEncryption OID, NULL }
51        let mut algo = DerEncoder::new();
52        algo.oid(OID_RSA);
53        algo.null();
54        let algo_bytes = algo.finish();
55        let mut inner = DerEncoder::new();
56        inner.sequence(&algo_bytes);
57        inner.bit_string(&pkcs1);
58        let content = inner.finish();
59        let mut outer = DerEncoder::new();
60        outer.sequence(&content);
61        outer.finish()
62    }
63
64    /// Parse from SubjectPublicKeyInfo DER.
65    pub fn from_spki_der(der: &[u8]) -> Option<Self> {
66        let mut dec = DerDecoder::new(der);
67        let mut seq = dec.read_sequence()?;
68        let mut algo_seq = seq.read_sequence()?;
69        let oid = algo_seq.read_oid()?;
70        if oid != OID_RSA {
71            return None;
72        }
73        algo_seq.read_null()?;
74        let pk_bits = seq.read_bit_string()?;
75        Self::from_pkcs1_der(pk_bits)
76    }
77
78    /// Encode as PKCS#1 PEM.
79    pub fn to_pkcs1_pem(&self) -> String {
80        pem_encode("RSA PUBLIC KEY", &self.to_pkcs1_der())
81    }
82    /// Parse from PKCS#1 PEM.
83    pub fn from_pkcs1_pem(pem: &str) -> Option<Self> {
84        Self::from_pkcs1_der(&pem_decode("RSA PUBLIC KEY", pem)?)
85    }
86    /// Encode as SPKI PEM.
87    pub fn to_spki_pem(&self) -> String {
88        pem_encode("PUBLIC KEY", &self.to_spki_der())
89    }
90    /// Parse from SPKI PEM.
91    pub fn from_spki_pem(pem: &str) -> Option<Self> {
92        Self::from_spki_der(&pem_decode("PUBLIC KEY", pem)?)
93    }
94}
95
96impl RsaSecretKey {
97    /// Encode as PKCS#1 DER (`RSAPrivateKey`, RFC 8017 §A.1.2).
98    pub fn to_pkcs1_der(&self) -> Vec<u8> {
99        let n = self.n.to_be_bytes(self.n.byte_len());
100        let e_val = BigInt::from_be_bytes(&[0x01, 0x00, 0x01]); // 65537
101        let e = e_val.to_be_bytes(e_val.byte_len());
102        let d = self.d.to_be_bytes(self.d.byte_len());
103        let p = self.p.to_be_bytes(self.p.byte_len());
104        let q = self.q.to_be_bytes(self.q.byte_len());
105        let dp = self.dp.to_be_bytes(self.dp.byte_len());
106        let dq = self.dq.to_be_bytes(self.dq.byte_len());
107        let qinv = self.qinv.to_be_bytes(self.qinv.byte_len());
108
109        let mut inner = DerEncoder::new();
110        inner.integer_u64(0); // version
111        inner.integer(&n);
112        inner.integer(&e);
113        inner.integer(&d);
114        inner.integer(&p);
115        inner.integer(&q);
116        inner.integer(&dp);
117        inner.integer(&dq);
118        inner.integer(&qinv);
119        let content = inner.finish();
120        let mut outer = DerEncoder::new();
121        outer.sequence(&content);
122        outer.finish()
123    }
124
125    /// Parse from PKCS#1 DER.
126    pub fn from_pkcs1_der(der: &[u8]) -> Option<Self> {
127        let mut dec = DerDecoder::new(der);
128        let mut seq = dec.read_sequence()?;
129        let version = seq.read_integer_u64()?;
130        if version != 0 {
131            return None;
132        } // only two-prime RSA
133        let n = BigInt::from_be_bytes(seq.read_integer()?);
134        let _e = seq.read_integer()?; // public exponent (we store it in pk)
135        let d = BigInt::from_be_bytes(seq.read_integer()?);
136        let p = BigInt::from_be_bytes(seq.read_integer()?);
137        let q = BigInt::from_be_bytes(seq.read_integer()?);
138        let dp = BigInt::from_be_bytes(seq.read_integer()?);
139        let dq = BigInt::from_be_bytes(seq.read_integer()?);
140        let qinv = BigInt::from_be_bytes(seq.read_integer()?);
141        Some(Self {
142            n,
143            d,
144            p,
145            q,
146            dp,
147            dq,
148            qinv,
149        })
150    }
151
152    /// Encode as PKCS#1 PEM.
153    pub fn to_pkcs1_pem(&self) -> String {
154        pem_encode("RSA PRIVATE KEY", &self.to_pkcs1_der())
155    }
156    /// Parse from PKCS#1 PEM.
157    pub fn from_pkcs1_pem(pem: &str) -> Option<Self> {
158        Self::from_pkcs1_der(&pem_decode("RSA PRIVATE KEY", pem)?)
159    }
160}
161
162// ====================================================================
163// ECC — SPKI (public) + PKCS#8 (private) + SEC1 (private)
164// ====================================================================
165
166/// Curve identifier for ECC key serialization.
167#[derive(Clone, Copy, Debug, PartialEq, Eq)]
168pub enum EcCurve {
169    /// NIST P-256 / secp256r1.
170    P256,
171    /// NIST P-384 / secp384r1.
172    P384,
173    /// NIST P-521 / secp521r1.
174    P521,
175    /// secp256k1.
176    Secp256k1,
177    /// brainpoolP256r1.
178    BrainpoolP256r1,
179    /// brainpoolP384r1.
180    BrainpoolP384r1,
181    /// brainpoolP512r1.
182    BrainpoolP512r1,
183}
184
185impl EcCurve {
186    fn oid(self) -> &'static [u8] {
187        match self {
188            EcCurve::P256 => OID_SECP256R1,
189            EcCurve::P384 => OID_SECP384R1,
190            EcCurve::P521 => OID_SECP521R1,
191            EcCurve::Secp256k1 => OID_SECP256K1,
192            EcCurve::BrainpoolP256r1 => OID_BRAINPOOL_P256R1,
193            EcCurve::BrainpoolP384r1 => OID_BRAINPOOL_P384R1,
194            EcCurve::BrainpoolP512r1 => OID_BRAINPOOL_P512R1,
195        }
196    }
197
198    fn from_oid(oid: &[u8]) -> Option<Self> {
199        match oid {
200            x if x == OID_SECP256R1 => Some(EcCurve::P256),
201            x if x == OID_SECP384R1 => Some(EcCurve::P384),
202            x if x == OID_SECP521R1 => Some(EcCurve::P521),
203            x if x == OID_SECP256K1 => Some(EcCurve::Secp256k1),
204            x if x == OID_BRAINPOOL_P256R1 => Some(EcCurve::BrainpoolP256r1),
205            x if x == OID_BRAINPOOL_P384R1 => Some(EcCurve::BrainpoolP384r1),
206            x if x == OID_BRAINPOOL_P512R1 => Some(EcCurve::BrainpoolP512r1),
207            _ => None,
208        }
209    }
210}
211
212impl EcPublicKey {
213    /// Encode as SubjectPublicKeyInfo DER (RFC 5480).
214    pub fn to_spki_der(&self, curve: EcCurve) -> Vec<u8> {
215        // AlgorithmIdentifier: SEQUENCE { id-ecPublicKey OID, curve OID }
216        let mut algo = DerEncoder::new();
217        algo.oid(OID_EC_PUBLIC_KEY);
218        algo.oid(curve.oid());
219        let algo_bytes = algo.finish();
220        let mut inner = DerEncoder::new();
221        inner.sequence(&algo_bytes);
222        inner.bit_string(&self.bytes);
223        let content = inner.finish();
224        let mut outer = DerEncoder::new();
225        outer.sequence(&content);
226        outer.finish()
227    }
228
229    /// Parse from SubjectPublicKeyInfo DER. Returns `(key, curve)`.
230    pub fn from_spki_der(der: &[u8]) -> Option<(Self, EcCurve)> {
231        let mut dec = DerDecoder::new(der);
232        let mut seq = dec.read_sequence()?;
233        let mut algo_seq = seq.read_sequence()?;
234        let oid = algo_seq.read_oid()?;
235        if oid != OID_EC_PUBLIC_KEY {
236            return None;
237        }
238        let curve_oid = algo_seq.read_oid()?;
239        let curve = EcCurve::from_oid(curve_oid)?;
240        let pk_bits = seq.read_bit_string()?;
241        Some((
242            Self {
243                bytes: pk_bits.to_vec(),
244            },
245            curve,
246        ))
247    }
248
249    /// Encode as SPKI PEM.
250    pub fn to_spki_pem(&self, curve: EcCurve) -> String {
251        pem_encode("PUBLIC KEY", &self.to_spki_der(curve))
252    }
253
254    /// Parse from SPKI PEM.
255    pub fn from_spki_pem(pem: &str) -> Option<(Self, EcCurve)> {
256        Self::from_spki_der(&pem_decode("PUBLIC KEY", pem)?)
257    }
258}
259
260impl EcSecretKey {
261    /// Encode as SEC1 DER (RFC 5915: `ECPrivateKey`).
262    pub fn to_sec1_der(&self, curve: EcCurve, public_key: Option<&EcPublicKey>) -> Vec<u8> {
263        let mut inner = DerEncoder::new();
264        inner.integer_u64(1); // version
265
266        inner.octet_string(&self.bytes);
267
268        // [0] EXPLICIT curve OID (optional but recommended)
269        {
270            let mut oid_enc = DerEncoder::new();
271            oid_enc.oid(curve.oid());
272            let oid_bytes = oid_enc.finish();
273            inner.context_explicit(0, &oid_bytes);
274        }
275
276        // [1] EXPLICIT public key BIT STRING (optional)
277        if let Some(pk) = public_key {
278            let mut bs = DerEncoder::new();
279            bs.bit_string(&pk.bytes);
280            let bs_bytes = bs.finish();
281            inner.context_explicit(1, &bs_bytes);
282        }
283
284        let content = inner.finish();
285        let mut outer = DerEncoder::new();
286        outer.sequence(&content);
287        outer.finish()
288    }
289
290    /// Parse from SEC1 DER. Returns `(secret_key, curve, optional_public_key)`.
291    pub fn from_sec1_der(der: &[u8]) -> Option<(Self, EcCurve, Option<EcPublicKey>)> {
292        let mut dec = DerDecoder::new(der);
293        let mut seq = dec.read_sequence()?;
294        let version = seq.read_integer_u64()?;
295        if version != 1 {
296            return None;
297        }
298        let sk_bytes = seq.read_octet_string()?;
299
300        // [0] curve OID
301        let mut ctx0 = seq.read_context_explicit(0)?;
302        let curve_oid = ctx0.read_oid()?;
303        let curve = EcCurve::from_oid(curve_oid)?;
304
305        // [1] public key (optional)
306        let pk = if let Some(mut ctx1) = seq.read_context_explicit(1) {
307            let pk_bits = ctx1.read_bit_string()?;
308            Some(EcPublicKey {
309                bytes: pk_bits.to_vec(),
310            })
311        } else {
312            None
313        };
314
315        Some((
316            Self {
317                bytes: sk_bytes.to_vec(),
318            },
319            curve,
320            pk,
321        ))
322    }
323
324    /// Encode as PKCS#8 DER (RFC 5958).
325    pub fn to_pkcs8_der(&self, curve: EcCurve, public_key: Option<&EcPublicKey>) -> Vec<u8> {
326        let sec1 = self.to_sec1_der(curve, public_key);
327        // AlgorithmIdentifier: SEQUENCE { id-ecPublicKey, curve OID }
328        let mut algo = DerEncoder::new();
329        algo.oid(OID_EC_PUBLIC_KEY);
330        algo.oid(curve.oid());
331        let algo_bytes = algo.finish();
332
333        let mut inner = DerEncoder::new();
334        inner.integer_u64(0); // version (v1)
335        inner.sequence(&algo_bytes);
336        inner.octet_string(&sec1);
337        let content = inner.finish();
338        let mut outer = DerEncoder::new();
339        outer.sequence(&content);
340        outer.finish()
341    }
342
343    /// Encode as SEC1 PEM.
344    pub fn to_sec1_pem(&self, curve: EcCurve, public_key: Option<&EcPublicKey>) -> String {
345        pem_encode("EC PRIVATE KEY", &self.to_sec1_der(curve, public_key))
346    }
347
348    /// Encode as PKCS#8 PEM.
349    pub fn to_pkcs8_pem(&self, curve: EcCurve, public_key: Option<&EcPublicKey>) -> String {
350        pem_encode("PRIVATE KEY", &self.to_pkcs8_der(curve, public_key))
351    }
352}
353
354// ====================================================================
355// Ed25519 — SPKI (public) + PKCS#8 (private) per RFC 8037
356// ====================================================================
357
358impl Ed25519PublicKey {
359    /// Encode as SubjectPublicKeyInfo DER (RFC 8037).
360    pub fn to_spki_der(&self) -> Vec<u8> {
361        // AlgorithmIdentifier: SEQUENCE { id-Ed25519 } — no parameters
362        let mut algo = DerEncoder::new();
363        algo.oid(OID_ED25519);
364        let algo_bytes = algo.finish();
365        let mut inner = DerEncoder::new();
366        inner.sequence(&algo_bytes);
367        inner.bit_string(&self.0);
368        let content = inner.finish();
369        let mut outer = DerEncoder::new();
370        outer.sequence(&content);
371        outer.finish()
372    }
373
374    /// Parse from SPKI DER.
375    pub fn from_spki_der(der: &[u8]) -> Option<Self> {
376        let mut dec = DerDecoder::new(der);
377        let mut seq = dec.read_sequence()?;
378        let mut algo_seq = seq.read_sequence()?;
379        let oid = algo_seq.read_oid()?;
380        if oid != OID_ED25519 {
381            return None;
382        }
383        let pk_bits = seq.read_bit_string()?;
384        if pk_bits.len() != 32 {
385            return None;
386        }
387        let mut out = [0u8; 32];
388        out.copy_from_slice(pk_bits);
389        Some(Self(out))
390    }
391
392    /// Encode as SPKI PEM.
393    pub fn to_spki_pem(&self) -> String {
394        pem_encode("PUBLIC KEY", &self.to_spki_der())
395    }
396    /// Parse from SPKI PEM.
397    pub fn from_spki_pem(pem: &str) -> Option<Self> {
398        Self::from_spki_der(&pem_decode("PUBLIC KEY", pem)?)
399    }
400}
401
402impl Ed25519SecretKey {
403    /// Encode as PKCS#8 DER (RFC 8037).
404    pub fn to_pkcs8_der(&self) -> Vec<u8> {
405        // The "private key" in PKCS#8 for Ed25519 is an OCTET STRING
406        // containing the 32-byte seed, itself wrapped in an OCTET STRING.
407        let mut seed_enc = DerEncoder::new();
408        seed_enc.octet_string(&self.0);
409        let seed_der = seed_enc.finish();
410
411        let mut algo = DerEncoder::new();
412        algo.oid(OID_ED25519);
413        let algo_bytes = algo.finish();
414
415        let mut inner = DerEncoder::new();
416        inner.integer_u64(0); // version
417        inner.sequence(&algo_bytes);
418        inner.octet_string(&seed_der);
419        let content = inner.finish();
420        let mut outer = DerEncoder::new();
421        outer.sequence(&content);
422        outer.finish()
423    }
424
425    /// Parse from PKCS#8 DER.
426    pub fn from_pkcs8_der(der: &[u8]) -> Option<Self> {
427        let mut dec = DerDecoder::new(der);
428        let mut seq = dec.read_sequence()?;
429        let version = seq.read_integer_u64()?;
430        if version != 0 {
431            return None;
432        }
433        let mut algo_seq = seq.read_sequence()?;
434        let oid = algo_seq.read_oid()?;
435        if oid != OID_ED25519 {
436            return None;
437        }
438        let pk_octet = seq.read_octet_string()?;
439        // Inner OCTET STRING wrapping the 32-byte seed.
440        let mut inner = DerDecoder::new(pk_octet);
441        let seed = inner.read_octet_string()?;
442        if seed.len() != 32 {
443            return None;
444        }
445        let mut out = [0u8; 32];
446        out.copy_from_slice(seed);
447        Some(Self(out))
448    }
449
450    /// Encode as PKCS#8 PEM.
451    pub fn to_pkcs8_pem(&self) -> String {
452        pem_encode("PRIVATE KEY", &self.to_pkcs8_der())
453    }
454    /// Parse from PKCS#8 PEM.
455    pub fn from_pkcs8_pem(pem: &str) -> Option<Self> {
456        Self::from_pkcs8_der(&pem_decode("PRIVATE KEY", pem)?)
457    }
458}
459
460// ====================================================================
461// Tests
462// ====================================================================
463
464#[cfg(test)]
465mod tests {
466    use super::*;
467    use crate::ecc::eddsa::ed25519_keygen;
468
469    fn rng_fill(buf: &mut [u8]) {
470        static mut CTR: u64 = 0xdeadbeef;
471        for b in buf.iter_mut() {
472            unsafe {
473                CTR = CTR.wrapping_mul(6364136223846793005).wrapping_add(1);
474                *b = (CTR >> 33) as u8;
475            }
476        }
477    }
478
479    // ---------- RSA ----------
480
481    #[test]
482    fn rsa_pkcs1_roundtrip() {
483        let (pk, sk) = crate::rsa::rsa::rsa_keygen(1024, &mut rng_fill);
484
485        let pk_der = pk.to_pkcs1_der();
486        let pk_back = RsaPublicKey::from_pkcs1_der(&pk_der).unwrap();
487        assert_eq!(
488            pk_back.n.to_be_bytes(pk.n.byte_len()),
489            pk.n.to_be_bytes(pk.n.byte_len())
490        );
491        assert_eq!(
492            pk_back.e.to_be_bytes(pk.e.byte_len()),
493            pk.e.to_be_bytes(pk.e.byte_len())
494        );
495
496        let sk_der = sk.to_pkcs1_der();
497        let sk_back = RsaSecretKey::from_pkcs1_der(&sk_der).unwrap();
498        assert_eq!(
499            sk_back.n.to_be_bytes(sk.n.byte_len()),
500            sk.n.to_be_bytes(sk.n.byte_len())
501        );
502        assert_eq!(
503            sk_back.p.to_be_bytes(sk.p.byte_len()),
504            sk.p.to_be_bytes(sk.p.byte_len())
505        );
506    }
507
508    #[test]
509    fn rsa_spki_roundtrip() {
510        let (pk, _) = crate::rsa::rsa::rsa_keygen(1024, &mut rng_fill);
511        let der = pk.to_spki_der();
512        let pk_back = RsaPublicKey::from_spki_der(&der).unwrap();
513        assert_eq!(
514            pk_back.n.to_be_bytes(pk.n.byte_len()),
515            pk.n.to_be_bytes(pk.n.byte_len())
516        );
517    }
518
519    #[test]
520    fn rsa_pem_roundtrip() {
521        let (pk, sk) = crate::rsa::rsa::rsa_keygen(1024, &mut rng_fill);
522        let pk_pem = pk.to_pkcs1_pem();
523        assert!(pk_pem.contains("-----BEGIN RSA PUBLIC KEY-----"));
524        let pk_back = RsaPublicKey::from_pkcs1_pem(&pk_pem).unwrap();
525        assert_eq!(
526            pk_back.n.to_be_bytes(pk.n.byte_len()),
527            pk.n.to_be_bytes(pk.n.byte_len())
528        );
529
530        let sk_pem = sk.to_pkcs1_pem();
531        assert!(sk_pem.contains("-----BEGIN RSA PRIVATE KEY-----"));
532        let sk_back = RsaSecretKey::from_pkcs1_pem(&sk_pem).unwrap();
533        assert_eq!(
534            sk_back.p.to_be_bytes(sk.p.byte_len()),
535            sk.p.to_be_bytes(sk.p.byte_len())
536        );
537    }
538
539    // ---------- ECC P-256 ----------
540
541    #[test]
542    fn ec_spki_roundtrip() {
543        use crate::ecc::curves::{CryptoRng, Curve, P256};
544        struct Rng(u64);
545        impl CryptoRng for Rng {
546            fn fill_bytes(&mut self, dest: &mut [u8]) {
547                for b in dest {
548                    self.0 = self.0.wrapping_mul(6364136223846793005).wrapping_add(1);
549                    *b = (self.0 >> 33) as u8;
550                }
551            }
552        }
553        let (pk, _sk) = P256::keygen(&mut Rng(0xCAFE));
554        let der = pk.to_spki_der(EcCurve::P256);
555        let (pk_back, curve) = EcPublicKey::from_spki_der(&der).unwrap();
556        assert_eq!(curve, EcCurve::P256);
557        assert_eq!(pk_back.bytes, pk.bytes);
558    }
559
560    #[test]
561    fn ec_sec1_roundtrip() {
562        use crate::ecc::curves::{CryptoRng, Curve, P256};
563        struct Rng(u64);
564        impl CryptoRng for Rng {
565            fn fill_bytes(&mut self, dest: &mut [u8]) {
566                for b in dest {
567                    self.0 = self.0.wrapping_mul(6364136223846793005).wrapping_add(1);
568                    *b = (self.0 >> 33) as u8;
569                }
570            }
571        }
572        let (pk, sk) = P256::keygen(&mut Rng(0xBEEF));
573        let der = sk.to_sec1_der(EcCurve::P256, Some(&pk));
574        let (sk_back, curve, pk_back) = EcSecretKey::from_sec1_der(&der).unwrap();
575        assert_eq!(curve, EcCurve::P256);
576        assert_eq!(sk_back.bytes, sk.bytes);
577        assert_eq!(pk_back.unwrap().bytes, pk.bytes);
578    }
579
580    #[test]
581    fn ec_pem_roundtrip() {
582        use crate::ecc::curves::{CryptoRng, Curve, P256};
583        struct Rng(u64);
584        impl CryptoRng for Rng {
585            fn fill_bytes(&mut self, dest: &mut [u8]) {
586                for b in dest {
587                    self.0 = self.0.wrapping_mul(6364136223846793005).wrapping_add(1);
588                    *b = (self.0 >> 33) as u8;
589                }
590            }
591        }
592        let (pk, sk) = P256::keygen(&mut Rng(0xFACE));
593        let pem = pk.to_spki_pem(EcCurve::P256);
594        assert!(pem.contains("-----BEGIN PUBLIC KEY-----"));
595        let (pk_back, _) = EcPublicKey::from_spki_pem(&pem).unwrap();
596        assert_eq!(pk_back.bytes, pk.bytes);
597
598        let sk_pem = sk.to_sec1_pem(EcCurve::P256, None);
599        assert!(sk_pem.contains("-----BEGIN EC PRIVATE KEY-----"));
600    }
601
602    // ---------- Ed25519 ----------
603
604    #[test]
605    fn ed25519_spki_roundtrip() {
606        let seed = [0x42u8; 32];
607        let (pk, _sk) = ed25519_keygen(&seed);
608        let der = pk.to_spki_der();
609        let pk_back = Ed25519PublicKey::from_spki_der(&der).unwrap();
610        assert_eq!(pk_back.0, pk.0);
611    }
612
613    #[test]
614    fn ed25519_pkcs8_roundtrip() {
615        let seed = [0x42u8; 32];
616        let (_pk, sk) = ed25519_keygen(&seed);
617        let der = sk.to_pkcs8_der();
618        let sk_back = Ed25519SecretKey::from_pkcs8_der(&der).unwrap();
619        assert_eq!(sk_back.0, sk.0);
620    }
621
622    #[test]
623    fn ed25519_pem_roundtrip() {
624        let seed = [0x42u8; 32];
625        let (pk, sk) = ed25519_keygen(&seed);
626        let pem = pk.to_spki_pem();
627        assert!(pem.contains("-----BEGIN PUBLIC KEY-----"));
628        let pk_back = Ed25519PublicKey::from_spki_pem(&pem).unwrap();
629        assert_eq!(pk_back.0, pk.0);
630
631        let sk_pem = sk.to_pkcs8_pem();
632        assert!(sk_pem.contains("-----BEGIN PRIVATE KEY-----"));
633        let sk_back = Ed25519SecretKey::from_pkcs8_pem(&sk_pem).unwrap();
634        assert_eq!(sk_back.0, sk.0);
635    }
636}