Skip to main content

pq_key_encoder/
types.rs

1use core::fmt;
2
3#[cfg(any(feature = "pem", feature = "jwk"))]
4use alloc::string::String;
5use alloc::vec::Vec;
6use pq_oid::Algorithm;
7use zeroize::{Zeroize, ZeroizeOnDrop, Zeroizing};
8
9use crate::error::Result;
10use crate::validation::validate_key_size;
11use crate::{der, pkcs8, spki};
12
13/// The type of key (public or private).
14#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
15pub enum KeyType {
16    Public,
17    Private,
18}
19
20impl fmt::Display for KeyType {
21    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
22        match self {
23            KeyType::Public => write!(f, "public"),
24            KeyType::Private => write!(f, "private"),
25        }
26    }
27}
28
29// =============================================================================
30// Borrowed types (zero-copy)
31// =============================================================================
32
33/// A borrowed public key reference. Zero-copy over input data.
34#[derive(Debug, Clone, Copy, PartialEq, Eq)]
35pub struct PublicKeyRef<'a> {
36    algorithm: Algorithm,
37    bytes: &'a [u8],
38}
39
40impl<'a> PublicKeyRef<'a> {
41    /// Creates a new `PublicKeyRef` after validating key size.
42    pub fn new(algorithm: Algorithm, bytes: &'a [u8]) -> Result<Self> {
43        validate_key_size(algorithm, KeyType::Public, bytes)?;
44        Ok(Self { algorithm, bytes })
45    }
46
47    /// Returns the algorithm.
48    #[inline]
49    pub fn algorithm(&self) -> Algorithm {
50        self.algorithm
51    }
52
53    /// Returns the raw key bytes.
54    #[inline]
55    pub fn bytes(&self) -> &'a [u8] {
56        self.bytes
57    }
58
59    /// Returns the key type (always `Public`).
60    #[inline]
61    pub fn key_type(&self) -> KeyType {
62        KeyType::Public
63    }
64
65    /// Decode an SPKI DER-encoded public key (zero-copy).
66    pub fn from_spki(der: &'a [u8]) -> Result<Self> {
67        let (alg, key_bytes) = spki::decode_spki(der)?;
68        validate_key_size(alg, KeyType::Public, key_bytes)?;
69        Ok(Self {
70            algorithm: alg,
71            bytes: key_bytes,
72        })
73    }
74
75    /// Encode this public key as SPKI DER into the given buffer.
76    pub fn encode_spki_to(&self, out: &mut Vec<u8>) {
77        spki::encode_spki(self.algorithm, self.bytes, out);
78    }
79
80    /// Encode this public key as DER into the given buffer (alias for `encode_spki_to`).
81    pub fn encode_der_to(&self, out: &mut Vec<u8>) {
82        self.encode_spki_to(out);
83    }
84
85    /// Encode this public key as SPKI DER, returning a new `Vec<u8>`.
86    pub fn to_spki(&self) -> Vec<u8> {
87        let mut out = Vec::new();
88        self.encode_spki_to(&mut out);
89        out
90    }
91
92    /// Encode this public key as DER, returning a new `Vec<u8>` (alias for `to_spki`).
93    pub fn to_der(&self) -> Vec<u8> {
94        self.to_spki()
95    }
96
97    /// Encode this public key as PEM, appending directly to `out`.
98    #[cfg(feature = "pem")]
99    pub fn encode_pem_to(&self, out: &mut String) {
100        let der = self.to_spki();
101        crate::pem::encode_pem_to(&der, crate::pem::label_for_key_type(KeyType::Public), out);
102    }
103
104    /// Encode this public key as PEM.
105    #[cfg(feature = "pem")]
106    pub fn to_pem(&self) -> String {
107        let der = self.to_spki();
108        crate::pem::encode_pem(&der, crate::pem::label_for_key_type(KeyType::Public))
109    }
110
111    /// Encode this public key as a JWK.
112    #[cfg(feature = "jwk")]
113    pub fn to_jwk(&self) -> crate::jwk::PublicJwk {
114        crate::jwk::encode_public_jwk(self.algorithm, self.bytes)
115    }
116
117    /// Converts to an owned `PublicKey`.
118    pub fn to_owned(&self) -> PublicKey {
119        PublicKey {
120            algorithm: self.algorithm,
121            bytes: self.bytes.to_vec(),
122        }
123    }
124}
125
126/// A borrowed private key reference. Zero-copy over input data.
127#[derive(Clone, Copy, PartialEq, Eq)]
128pub struct PrivateKeyRef<'a> {
129    algorithm: Algorithm,
130    bytes: &'a [u8],
131}
132
133impl fmt::Debug for PrivateKeyRef<'_> {
134    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
135        f.debug_struct("PrivateKeyRef")
136            .field("algorithm", &self.algorithm)
137            .field("bytes", &"[REDACTED]")
138            .finish()
139    }
140}
141
142impl<'a> PrivateKeyRef<'a> {
143    /// Creates a new `PrivateKeyRef` after validating key size.
144    pub fn new(algorithm: Algorithm, bytes: &'a [u8]) -> Result<Self> {
145        validate_key_size(algorithm, KeyType::Private, bytes)?;
146        Ok(Self { algorithm, bytes })
147    }
148
149    /// Returns the algorithm.
150    #[inline]
151    pub fn algorithm(&self) -> Algorithm {
152        self.algorithm
153    }
154
155    /// Returns the raw key bytes.
156    #[inline]
157    pub fn bytes(&self) -> &'a [u8] {
158        self.bytes
159    }
160
161    /// Returns the key type (always `Private`).
162    #[inline]
163    pub fn key_type(&self) -> KeyType {
164        KeyType::Private
165    }
166
167    /// Decode a PKCS8 DER-encoded private key (zero-copy).
168    pub fn from_pkcs8(der: &'a [u8]) -> Result<Self> {
169        let (alg, key_bytes) = pkcs8::decode_pkcs8(der)?;
170        validate_key_size(alg, KeyType::Private, key_bytes)?;
171        Ok(Self {
172            algorithm: alg,
173            bytes: key_bytes,
174        })
175    }
176
177    /// Encode this private key as PKCS8 DER into the given buffer.
178    pub fn encode_pkcs8_to(&self, out: &mut Vec<u8>) {
179        pkcs8::encode_pkcs8(self.algorithm, self.bytes, out);
180    }
181
182    /// Encode this private key as DER into the given buffer (alias for `encode_pkcs8_to`).
183    pub fn encode_der_to(&self, out: &mut Vec<u8>) {
184        self.encode_pkcs8_to(out);
185    }
186
187    /// Encode this private key as PKCS8 DER, returning a `Zeroizing<Vec<u8>>`.
188    /// The returned wrapper automatically zeroizes the DER bytes on drop.
189    pub fn to_pkcs8(&self) -> Zeroizing<Vec<u8>> {
190        let mut out = Vec::new();
191        self.encode_pkcs8_to(&mut out);
192        Zeroizing::new(out)
193    }
194
195    /// Encode this private key as DER, returning a `Zeroizing<Vec<u8>>` (alias for `to_pkcs8`).
196    /// The returned wrapper automatically zeroizes the DER bytes on drop.
197    pub fn to_der(&self) -> Zeroizing<Vec<u8>> {
198        self.to_pkcs8()
199    }
200
201    /// Encode this private key as PEM, appending directly to `out`.
202    #[cfg(feature = "pem")]
203    pub fn encode_pem_to(&self, out: &mut String) {
204        let mut der = self.to_pkcs8();
205        crate::pem::encode_pem_to(&der, crate::pem::label_for_key_type(KeyType::Private), out);
206        der.zeroize();
207    }
208
209    /// Encode this private key as PEM, returning a `Zeroizing<String>`.
210    /// The returned wrapper automatically zeroizes the PEM string on drop.
211    #[cfg(feature = "pem")]
212    pub fn to_pem(&self) -> Zeroizing<String> {
213        let mut der = self.to_pkcs8();
214        let pem = crate::pem::encode_pem(&der, crate::pem::label_for_key_type(KeyType::Private));
215        der.zeroize();
216        Zeroizing::new(pem)
217    }
218
219    /// Encode this private key as a JWK. Requires the corresponding public key.
220    ///
221    /// Returns an error if the public key's algorithm does not match.
222    #[cfg(feature = "jwk")]
223    pub fn to_jwk(&self, public_key: &PublicKeyRef<'_>) -> Result<crate::jwk::PrivateJwk> {
224        if public_key.algorithm != self.algorithm {
225            return Err(crate::error::Error::InvalidJwk(
226                "public key algorithm does not match private key",
227            ));
228        }
229        Ok(crate::jwk::encode_private_jwk(
230            self.algorithm,
231            public_key.bytes,
232            self.bytes,
233        ))
234    }
235
236    /// Converts to an owned `PrivateKey`.
237    pub fn to_owned(&self) -> PrivateKey {
238        PrivateKey {
239            algorithm: self.algorithm,
240            bytes: self.bytes.to_vec(),
241        }
242    }
243}
244
245// =============================================================================
246// Owned types
247// =============================================================================
248
249/// An owned public key.
250#[derive(Debug, Clone, PartialEq, Eq)]
251pub struct PublicKey {
252    algorithm: Algorithm,
253    bytes: Vec<u8>,
254}
255
256impl PublicKey {
257    /// Creates a new `PublicKey` from an owned `Vec<u8>` after validating key size.
258    pub fn new(algorithm: Algorithm, bytes: Vec<u8>) -> Result<Self> {
259        validate_key_size(algorithm, KeyType::Public, &bytes)?;
260        Ok(Self { algorithm, bytes })
261    }
262
263    /// Creates a new `PublicKey` by copying the provided bytes after validation.
264    pub fn from_bytes(algorithm: Algorithm, bytes: &[u8]) -> Result<Self> {
265        validate_key_size(algorithm, KeyType::Public, bytes)?;
266        Ok(Self {
267            algorithm,
268            bytes: bytes.to_vec(),
269        })
270    }
271
272    /// Returns the algorithm.
273    #[inline]
274    pub fn algorithm(&self) -> Algorithm {
275        self.algorithm
276    }
277
278    /// Returns the raw key bytes.
279    #[inline]
280    pub fn bytes(&self) -> &[u8] {
281        &self.bytes
282    }
283
284    /// Returns the key type (always `Public`).
285    #[inline]
286    pub fn key_type(&self) -> KeyType {
287        KeyType::Public
288    }
289
290    /// Consumes self and returns the inner byte vector.
291    pub fn into_bytes(self) -> Vec<u8> {
292        self.bytes
293    }
294
295    /// Decode an SPKI DER-encoded public key into an owned `PublicKey`.
296    pub fn from_spki(der: &[u8]) -> Result<Self> {
297        let (alg, key_bytes) = spki::decode_spki(der)?;
298        validate_key_size(alg, KeyType::Public, key_bytes)?;
299        Ok(Self {
300            algorithm: alg,
301            bytes: key_bytes.to_vec(),
302        })
303    }
304
305    /// Encode this public key as SPKI DER into the given buffer.
306    pub fn encode_spki_to(&self, out: &mut Vec<u8>) {
307        self.as_key_ref().encode_spki_to(out);
308    }
309
310    /// Encode this public key as DER into the given buffer.
311    pub fn encode_der_to(&self, out: &mut Vec<u8>) {
312        self.as_key_ref().encode_der_to(out);
313    }
314
315    /// Encode this public key as SPKI DER, returning a new `Vec<u8>`.
316    pub fn to_spki(&self) -> Vec<u8> {
317        self.as_key_ref().to_spki()
318    }
319
320    /// Encode this public key as DER, returning a new `Vec<u8>`.
321    pub fn to_der(&self) -> Vec<u8> {
322        self.as_key_ref().to_der()
323    }
324
325    /// Decode a PEM-encoded public key into an owned `PublicKey`.
326    #[cfg(feature = "pem")]
327    pub fn from_pem(pem: &str) -> Result<Self> {
328        let (label, der) = crate::pem::decode_pem(pem)?;
329        if label != crate::pem::label_for_key_type(KeyType::Public) {
330            return Err(crate::error::Error::InvalidPem("expected PUBLIC KEY label"));
331        }
332        Self::from_spki(&der)
333    }
334
335    /// Encode this public key as PEM.
336    #[cfg(feature = "pem")]
337    pub fn to_pem(&self) -> String {
338        self.as_key_ref().to_pem()
339    }
340
341    /// Decode a JWK into an owned `PublicKey`.
342    #[cfg(feature = "jwk")]
343    pub fn from_jwk(jwk: &crate::jwk::PublicJwk) -> Result<Self> {
344        let (alg, bytes) = crate::jwk::decode_public_jwk(jwk)?;
345        Ok(Self {
346            algorithm: alg,
347            bytes,
348        })
349    }
350
351    /// Encode this public key as a JWK.
352    #[cfg(feature = "jwk")]
353    pub fn to_jwk(&self) -> crate::jwk::PublicJwk {
354        self.as_key_ref().to_jwk()
355    }
356
357    /// Returns a borrowed `PublicKeyRef`.
358    pub fn as_key_ref(&self) -> PublicKeyRef<'_> {
359        PublicKeyRef {
360            algorithm: self.algorithm,
361            bytes: &self.bytes,
362        }
363    }
364}
365
366impl AsRef<[u8]> for PublicKey {
367    fn as_ref(&self) -> &[u8] {
368        &self.bytes
369    }
370}
371
372impl<'a> From<PublicKeyRef<'a>> for PublicKey {
373    fn from(key: PublicKeyRef<'a>) -> Self {
374        key.to_owned()
375    }
376}
377
378/// An owned private key.
379///
380/// Private key bytes are zeroized on drop to prevent key material from
381/// lingering in heap memory. `Clone` is deliberately not derived —
382/// cloning private keys should be an explicit operation via `from_bytes`.
383#[derive(Zeroize, ZeroizeOnDrop)]
384pub struct PrivateKey {
385    #[zeroize(skip)]
386    algorithm: Algorithm,
387    bytes: Vec<u8>,
388}
389
390impl PartialEq for PrivateKey {
391    fn eq(&self, other: &Self) -> bool {
392        self.algorithm == other.algorithm && self.bytes == other.bytes
393    }
394}
395
396impl Eq for PrivateKey {}
397
398impl fmt::Debug for PrivateKey {
399    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
400        f.debug_struct("PrivateKey")
401            .field("algorithm", &self.algorithm)
402            .field("bytes", &"[REDACTED]")
403            .finish()
404    }
405}
406
407impl PrivateKey {
408    /// Creates a new `PrivateKey` from an owned `Vec<u8>` after validating key size.
409    pub fn new(algorithm: Algorithm, bytes: Vec<u8>) -> Result<Self> {
410        validate_key_size(algorithm, KeyType::Private, &bytes)?;
411        Ok(Self { algorithm, bytes })
412    }
413
414    /// Creates a new `PrivateKey` by copying the provided bytes after validation.
415    pub fn from_bytes(algorithm: Algorithm, bytes: &[u8]) -> Result<Self> {
416        validate_key_size(algorithm, KeyType::Private, bytes)?;
417        Ok(Self {
418            algorithm,
419            bytes: bytes.to_vec(),
420        })
421    }
422
423    /// Returns the algorithm.
424    #[inline]
425    pub fn algorithm(&self) -> Algorithm {
426        self.algorithm
427    }
428
429    /// Returns the raw key bytes.
430    #[inline]
431    pub fn bytes(&self) -> &[u8] {
432        &self.bytes
433    }
434
435    /// Returns the key type (always `Private`).
436    #[inline]
437    pub fn key_type(&self) -> KeyType {
438        KeyType::Private
439    }
440
441    /// Extracts the inner byte vector wrapped in `Zeroizing` so the
442    /// key material is automatically zeroized when the returned value
443    /// is dropped.
444    pub fn into_bytes(mut self) -> zeroize::Zeroizing<Vec<u8>> {
445        zeroize::Zeroizing::new(core::mem::take(&mut self.bytes))
446    }
447
448    /// Decode a PKCS8 DER-encoded private key into an owned `PrivateKey`.
449    pub fn from_pkcs8(der: &[u8]) -> Result<Self> {
450        let (alg, key_bytes) = pkcs8::decode_pkcs8(der)?;
451        validate_key_size(alg, KeyType::Private, key_bytes)?;
452        Ok(Self {
453            algorithm: alg,
454            bytes: key_bytes.to_vec(),
455        })
456    }
457
458    /// Encode this private key as PKCS8 DER into the given buffer.
459    pub fn encode_pkcs8_to(&self, out: &mut Vec<u8>) {
460        self.as_key_ref().encode_pkcs8_to(out);
461    }
462
463    /// Encode this private key as DER into the given buffer.
464    pub fn encode_der_to(&self, out: &mut Vec<u8>) {
465        self.as_key_ref().encode_der_to(out);
466    }
467
468    /// Encode this private key as PKCS8 DER, returning a `Zeroizing<Vec<u8>>`.
469    /// The returned wrapper automatically zeroizes the DER bytes on drop.
470    pub fn to_pkcs8(&self) -> Zeroizing<Vec<u8>> {
471        self.as_key_ref().to_pkcs8()
472    }
473
474    /// Encode this private key as DER, returning a `Zeroizing<Vec<u8>>`.
475    /// The returned wrapper automatically zeroizes the DER bytes on drop.
476    pub fn to_der(&self) -> Zeroizing<Vec<u8>> {
477        self.as_key_ref().to_der()
478    }
479
480    /// Decode a PEM-encoded private key into an owned `PrivateKey`.
481    #[cfg(feature = "pem")]
482    pub fn from_pem(pem: &str) -> Result<Self> {
483        let (label, der) = crate::pem::decode_pem(pem)?;
484        if label != crate::pem::label_for_key_type(KeyType::Private) {
485            return Err(crate::error::Error::InvalidPem(
486                "expected PRIVATE KEY label",
487            ));
488        }
489        Self::from_pkcs8(&der)
490    }
491
492    /// Encode this private key as PEM, returning a `Zeroizing<String>`.
493    /// The returned wrapper automatically zeroizes the PEM string on drop.
494    #[cfg(feature = "pem")]
495    pub fn to_pem(&self) -> Zeroizing<String> {
496        self.as_key_ref().to_pem()
497    }
498
499    /// Decode a JWK into an owned `PrivateKey`.
500    #[cfg(feature = "jwk")]
501    pub fn from_jwk(jwk: &crate::jwk::PrivateJwk) -> Result<Self> {
502        let (alg, bytes) = crate::jwk::decode_private_jwk(jwk)?;
503        Ok(Self {
504            algorithm: alg,
505            bytes,
506        })
507    }
508
509    /// Encode this private key as a JWK. Requires the corresponding public key.
510    ///
511    /// Returns an error if the public key's algorithm does not match.
512    #[cfg(feature = "jwk")]
513    pub fn to_jwk(&self, public_key: &PublicKey) -> Result<crate::jwk::PrivateJwk> {
514        self.as_key_ref().to_jwk(&public_key.as_key_ref())
515    }
516
517    /// Returns a borrowed `PrivateKeyRef`.
518    pub fn as_key_ref(&self) -> PrivateKeyRef<'_> {
519        PrivateKeyRef {
520            algorithm: self.algorithm,
521            bytes: &self.bytes,
522        }
523    }
524}
525
526impl AsRef<[u8]> for PrivateKey {
527    fn as_ref(&self) -> &[u8] {
528        &self.bytes
529    }
530}
531
532impl<'a> From<PrivateKeyRef<'a>> for PrivateKey {
533    fn from(key: PrivateKeyRef<'a>) -> Self {
534        key.to_owned()
535    }
536}
537
538impl Clone for PrivateKey {
539    /// Explicitly clone a private key. The cloned copy is also zeroized on drop.
540    fn clone(&self) -> Self {
541        Self {
542            algorithm: self.algorithm,
543            bytes: self.bytes.clone(),
544        }
545    }
546}
547
548// =============================================================================
549// Key enum
550// =============================================================================
551
552/// A key that is either public or private.
553#[derive(Clone, PartialEq, Eq)]
554pub enum Key {
555    Public(PublicKey),
556    Private(PrivateKey),
557}
558
559impl fmt::Debug for Key {
560    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
561        match self {
562            Key::Public(k) => f.debug_tuple("Key::Public").field(k).finish(),
563            Key::Private(k) => f.debug_tuple("Key::Private").field(k).finish(),
564        }
565    }
566}
567
568impl Key {
569    /// Returns the algorithm.
570    #[inline]
571    pub fn algorithm(&self) -> Algorithm {
572        match self {
573            Key::Public(k) => k.algorithm(),
574            Key::Private(k) => k.algorithm(),
575        }
576    }
577
578    /// Returns the key type.
579    #[inline]
580    pub fn key_type(&self) -> KeyType {
581        match self {
582            Key::Public(_) => KeyType::Public,
583            Key::Private(_) => KeyType::Private,
584        }
585    }
586
587    /// Returns the raw key bytes.
588    #[inline]
589    pub fn bytes(&self) -> &[u8] {
590        match self {
591            Key::Public(k) => k.bytes(),
592            Key::Private(k) => k.bytes(),
593        }
594    }
595
596    /// Returns a reference to the inner `PublicKey` if this is a public key.
597    #[inline]
598    pub fn as_public(&self) -> Option<&PublicKey> {
599        match self {
600            Key::Public(k) => Some(k),
601            Key::Private(_) => None,
602        }
603    }
604
605    /// Returns a reference to the inner `PrivateKey` if this is a private key.
606    #[inline]
607    pub fn as_private(&self) -> Option<&PrivateKey> {
608        match self {
609            Key::Public(_) => None,
610            Key::Private(k) => Some(k),
611        }
612    }
613
614    /// Consumes self and returns the inner `PublicKey` if this is a public key.
615    pub fn into_public(self) -> Option<PublicKey> {
616        match self {
617            Key::Public(k) => Some(k),
618            Key::Private(_) => None,
619        }
620    }
621
622    /// Consumes self and returns the inner `PrivateKey` if this is a private key.
623    pub fn into_private(self) -> Option<PrivateKey> {
624        match self {
625            Key::Public(_) => None,
626            Key::Private(k) => Some(k),
627        }
628    }
629
630    /// Decode a DER-encoded key (auto-detecting SPKI or PKCS8).
631    pub fn from_der(der: &[u8]) -> Result<Self> {
632        let (alg, key_type, key_bytes) = der::decode_der(der)?;
633        match key_type {
634            KeyType::Public => {
635                let key = PublicKey::from_bytes(alg, key_bytes)?;
636                Ok(Key::Public(key))
637            }
638            KeyType::Private => {
639                let key = PrivateKey::from_bytes(alg, key_bytes)?;
640                Ok(Key::Private(key))
641            }
642        }
643    }
644
645    /// Encode this key as DER, returning a new `Vec<u8>`.
646    ///
647    /// Note: For private keys, prefer using `PrivateKey::to_der()` directly
648    /// to get a `Zeroizing<Vec<u8>>` wrapper that auto-zeroizes on drop.
649    pub fn to_der(&self) -> Vec<u8> {
650        let mut out = Vec::new();
651        self.encode_der_to(&mut out);
652        out
653    }
654
655    /// Encode this key as DER into the given buffer.
656    pub fn encode_der_to(&self, out: &mut Vec<u8>) {
657        match self {
658            Key::Public(k) => k.encode_der_to(out),
659            Key::Private(k) => k.encode_der_to(out),
660        }
661    }
662
663    /// Decode a PEM-encoded key (auto-detecting PUBLIC KEY or PRIVATE KEY label).
664    #[cfg(feature = "pem")]
665    pub fn from_pem(pem: &str) -> Result<Self> {
666        let (label, der) = crate::pem::decode_pem(pem)?;
667        match label {
668            "PUBLIC KEY" => {
669                let key = PublicKey::from_spki(&der)?;
670                Ok(Key::Public(key))
671            }
672            "PRIVATE KEY" => {
673                let key = PrivateKey::from_pkcs8(&der)?;
674                Ok(Key::Private(key))
675            }
676            _ => Err(crate::error::Error::InvalidPem("unsupported PEM label")),
677        }
678    }
679
680    /// Encode this key as PEM.
681    ///
682    /// Note: For private keys, prefer using `PrivateKey::to_pem()` directly
683    /// to get a `Zeroizing<String>` wrapper that auto-zeroizes on drop.
684    #[cfg(feature = "pem")]
685    pub fn to_pem(&self) -> String {
686        match self {
687            Key::Public(k) => k.to_pem(),
688            Key::Private(k) => {
689                let mut der = k.to_pkcs8();
690                let pem =
691                    crate::pem::encode_pem(&der, crate::pem::label_for_key_type(KeyType::Private));
692                der.zeroize();
693                pem
694            }
695        }
696    }
697
698    /// Decode a JWK into a `Key`.
699    #[cfg(feature = "jwk")]
700    pub fn from_jwk(jwk: &crate::jwk::Jwk) -> Result<Self> {
701        match jwk {
702            crate::jwk::Jwk::Public(j) => PublicKey::from_jwk(j).map(Key::Public),
703            crate::jwk::Jwk::Private(j) => PrivateKey::from_jwk(j).map(Key::Private),
704        }
705    }
706
707    /// Decode a JWK JSON string into a `Key` (parses JSON then dispatches).
708    #[cfg(feature = "jwk")]
709    pub fn from_jwk_str(json: &str) -> Result<Self> {
710        let jwk = crate::jwk::Jwk::from_json(json)?;
711        Self::from_jwk(&jwk)
712    }
713}
714
715impl AsRef<[u8]> for Key {
716    fn as_ref(&self) -> &[u8] {
717        self.bytes()
718    }
719}
720
721impl From<PublicKey> for Key {
722    fn from(key: PublicKey) -> Self {
723        Key::Public(key)
724    }
725}
726
727impl From<PrivateKey> for Key {
728    fn from(key: PrivateKey) -> Self {
729        Key::Private(key)
730    }
731}
732
733impl<'a> TryFrom<&'a [u8]> for Key {
734    type Error = crate::error::Error;
735
736    fn try_from(der: &'a [u8]) -> Result<Self> {
737        Key::from_der(der)
738    }
739}
740
741#[cfg(test)]
742mod tests {
743    use super::*;
744    use pq_oid::{MlDsa, MlKem, SlhDsa};
745
746    #[test]
747    fn test_public_key_ref_valid() {
748        let alg = Algorithm::MlKem(MlKem::Kem512);
749        let bytes = vec![0u8; 800];
750        let key = PublicKeyRef::new(alg, &bytes).unwrap();
751        assert_eq!(key.algorithm(), alg);
752        assert_eq!(key.bytes().len(), 800);
753        assert_eq!(key.key_type(), KeyType::Public);
754    }
755
756    #[test]
757    fn test_public_key_ref_invalid_size() {
758        let alg = Algorithm::MlKem(MlKem::Kem512);
759        let bytes = vec![0u8; 100];
760        let err = PublicKeyRef::new(alg, &bytes).unwrap_err();
761        assert!(matches!(
762            err,
763            crate::error::Error::KeySizeMismatch {
764                expected: 800,
765                actual: 100,
766                ..
767            }
768        ));
769    }
770
771    #[test]
772    fn test_public_key_ref_empty() {
773        let alg = Algorithm::MlKem(MlKem::Kem512);
774        let err = PublicKeyRef::new(alg, &[]).unwrap_err();
775        assert!(matches!(err, crate::error::Error::EmptyKey));
776    }
777
778    #[test]
779    fn test_private_key_ref_valid() {
780        let alg = Algorithm::MlKem(MlKem::Kem512);
781        let bytes = vec![0u8; 1632];
782        let key = PrivateKeyRef::new(alg, &bytes).unwrap();
783        assert_eq!(key.algorithm(), alg);
784        assert_eq!(key.bytes().len(), 1632);
785        assert_eq!(key.key_type(), KeyType::Private);
786    }
787
788    #[test]
789    fn test_owned_public_key() {
790        let alg = Algorithm::MlKem(MlKem::Kem768);
791        let bytes = vec![0u8; 1184];
792        let key = PublicKey::new(alg, bytes).unwrap();
793        assert_eq!(key.algorithm(), alg);
794        assert_eq!(key.bytes().len(), 1184);
795
796        let key_ref = key.as_key_ref();
797        assert_eq!(key_ref.algorithm(), alg);
798    }
799
800    #[test]
801    fn test_owned_public_key_from_bytes() {
802        let alg = Algorithm::MlKem(MlKem::Kem512);
803        let bytes = [0u8; 800];
804        let key = PublicKey::from_bytes(alg, &bytes).unwrap();
805        assert_eq!(key.bytes().len(), 800);
806    }
807
808    #[test]
809    fn test_owned_public_key_into_bytes() {
810        let alg = Algorithm::MlKem(MlKem::Kem512);
811        let bytes = vec![42u8; 800];
812        let key = PublicKey::new(alg, bytes.clone()).unwrap();
813        let recovered = key.into_bytes();
814        assert_eq!(recovered, bytes);
815    }
816
817    #[test]
818    fn test_ref_to_owned() {
819        let alg = Algorithm::MlKem(MlKem::Kem512);
820        let bytes = vec![0u8; 800];
821        let key_ref = PublicKeyRef::new(alg, &bytes).unwrap();
822        let key: PublicKey = key_ref.into();
823        assert_eq!(key.algorithm(), alg);
824        assert_eq!(key.bytes().len(), 800);
825    }
826
827    #[test]
828    fn test_key_enum() {
829        let alg = Algorithm::MlKem(MlKem::Kem512);
830        let pub_key = PublicKey::new(alg, vec![0u8; 800]).unwrap();
831        let key: Key = pub_key.into();
832        assert_eq!(key.algorithm(), alg);
833        assert_eq!(key.key_type(), KeyType::Public);
834        assert!(key.as_public().is_some());
835        assert!(key.as_private().is_none());
836    }
837
838    #[test]
839    fn test_key_enum_private() {
840        let alg = Algorithm::MlKem(MlKem::Kem512);
841        let priv_key = PrivateKey::new(alg, vec![0u8; 1632]).unwrap();
842        let key: Key = priv_key.into();
843        assert_eq!(key.key_type(), KeyType::Private);
844        assert!(key.as_private().is_some());
845        assert!(key.as_public().is_none());
846    }
847
848    #[test]
849    fn test_key_into_public() {
850        let alg = Algorithm::MlKem(MlKem::Kem512);
851        let pub_key = PublicKey::new(alg, vec![0u8; 800]).unwrap();
852        let key: Key = pub_key.into();
853        assert!(key.into_public().is_some());
854    }
855
856    #[test]
857    fn test_key_into_private() {
858        let alg = Algorithm::MlKem(MlKem::Kem512);
859        let priv_key = PrivateKey::new(alg, vec![0u8; 1632]).unwrap();
860        let key: Key = priv_key.into();
861        assert!(key.into_private().is_some());
862    }
863
864    #[test]
865    fn test_as_ref_u8() {
866        let alg = Algorithm::MlKem(MlKem::Kem512);
867        let pub_key = PublicKey::new(alg, vec![1u8; 800]).unwrap();
868        let bytes: &[u8] = pub_key.as_ref();
869        assert_eq!(bytes.len(), 800);
870        assert_eq!(bytes[0], 1);
871    }
872
873    #[test]
874    fn test_key_type_display() {
875        assert_eq!(KeyType::Public.to_string(), "public");
876        assert_eq!(KeyType::Private.to_string(), "private");
877    }
878
879    // =========================================================================
880    // DER encoding/decoding tests
881    // =========================================================================
882
883    #[test]
884    fn test_public_key_ref_spki_roundtrip() {
885        let alg = Algorithm::MlKem(MlKem::Kem512);
886        let bytes = vec![0xABu8; 800];
887        let key = PublicKeyRef::new(alg, &bytes).unwrap();
888        let der = key.to_spki();
889        let decoded = PublicKeyRef::from_spki(&der).unwrap();
890        assert_eq!(decoded.algorithm(), alg);
891        assert_eq!(decoded.bytes(), &bytes[..]);
892    }
893
894    #[test]
895    fn test_public_key_ref_der_roundtrip() {
896        let alg = Algorithm::MlDsa(MlDsa::Dsa44);
897        let bytes = vec![0xCDu8; 1312];
898        let key = PublicKeyRef::new(alg, &bytes).unwrap();
899        let der = key.to_der();
900        let decoded = PublicKeyRef::from_spki(&der).unwrap();
901        assert_eq!(decoded.algorithm(), alg);
902        assert_eq!(decoded.bytes(), &bytes[..]);
903    }
904
905    #[test]
906    fn test_private_key_ref_pkcs8_roundtrip() {
907        let alg = Algorithm::MlKem(MlKem::Kem512);
908        let bytes = vec![0xABu8; 1632];
909        let key = PrivateKeyRef::new(alg, &bytes).unwrap();
910        let der = key.to_pkcs8();
911        let decoded = PrivateKeyRef::from_pkcs8(&der).unwrap();
912        assert_eq!(decoded.algorithm(), alg);
913        assert_eq!(decoded.bytes(), &bytes[..]);
914    }
915
916    #[test]
917    fn test_private_key_ref_der_roundtrip() {
918        let alg = Algorithm::SlhDsa(SlhDsa::Sha2_128s);
919        let bytes = vec![0xEFu8; 64];
920        let key = PrivateKeyRef::new(alg, &bytes).unwrap();
921        let der = key.to_der();
922        let decoded = PrivateKeyRef::from_pkcs8(&der).unwrap();
923        assert_eq!(decoded.algorithm(), alg);
924        assert_eq!(decoded.bytes(), &bytes[..]);
925    }
926
927    #[test]
928    fn test_public_key_spki_roundtrip() {
929        let alg = Algorithm::MlKem(MlKem::Kem768);
930        let bytes = vec![0x42u8; 1184];
931        let key = PublicKey::new(alg, bytes.clone()).unwrap();
932        let der = key.to_spki();
933        let decoded = PublicKey::from_spki(&der).unwrap();
934        assert_eq!(decoded.algorithm(), alg);
935        assert_eq!(decoded.bytes(), &bytes[..]);
936    }
937
938    #[test]
939    fn test_private_key_pkcs8_roundtrip() {
940        let alg = Algorithm::MlDsa(MlDsa::Dsa44);
941        let bytes = vec![0x42u8; 2560];
942        let key = PrivateKey::new(alg, bytes.clone()).unwrap();
943        let der = key.to_pkcs8();
944        let decoded = PrivateKey::from_pkcs8(&der).unwrap();
945        assert_eq!(decoded.algorithm(), alg);
946        assert_eq!(decoded.bytes(), &bytes[..]);
947    }
948
949    #[test]
950    fn test_key_from_der_public() {
951        let alg = Algorithm::MlKem(MlKem::Kem512);
952        let bytes = vec![0xAAu8; 800];
953        let key = PublicKey::new(alg, bytes.clone()).unwrap();
954        let der = key.to_der();
955        let decoded = Key::from_der(&der).unwrap();
956        assert_eq!(decoded.algorithm(), alg);
957        assert_eq!(decoded.key_type(), KeyType::Public);
958        assert_eq!(decoded.bytes(), &bytes[..]);
959    }
960
961    #[test]
962    fn test_key_from_der_private() {
963        let alg = Algorithm::MlKem(MlKem::Kem512);
964        let bytes = vec![0xBBu8; 1632];
965        let key = PrivateKey::new(alg, bytes.clone()).unwrap();
966        let der = key.to_der();
967        let decoded = Key::from_der(&der).unwrap();
968        assert_eq!(decoded.algorithm(), alg);
969        assert_eq!(decoded.key_type(), KeyType::Private);
970        assert_eq!(decoded.bytes(), &bytes[..]);
971    }
972
973    #[test]
974    fn test_key_try_from_bytes() {
975        let alg = Algorithm::MlKem(MlKem::Kem512);
976        let bytes = vec![0xCCu8; 800];
977        let key = PublicKey::new(alg, bytes).unwrap();
978        let der = key.to_der();
979        let decoded: Key = der.as_slice().try_into().unwrap();
980        assert_eq!(decoded.algorithm(), alg);
981        assert_eq!(decoded.key_type(), KeyType::Public);
982    }
983
984    #[test]
985    fn test_key_encode_der_to() {
986        let alg = Algorithm::MlKem(MlKem::Kem512);
987        let bytes = vec![0xDDu8; 800];
988        let key = PublicKey::new(alg, bytes).unwrap();
989        let key = Key::Public(key);
990        let mut buf = Vec::new();
991        key.encode_der_to(&mut buf);
992        let decoded = Key::from_der(&buf).unwrap();
993        assert_eq!(decoded.algorithm(), alg);
994    }
995
996    #[test]
997    fn test_all_algorithms_public_der_roundtrip() {
998        for alg in Algorithm::all() {
999            let bytes = vec![0x42u8; alg.public_key_size()];
1000            let key = PublicKey::new(alg, bytes.clone()).unwrap();
1001            let der = key.to_der();
1002            let decoded = PublicKey::from_spki(&der).unwrap();
1003            assert_eq!(decoded.algorithm(), alg, "failed for {}", alg);
1004            assert_eq!(decoded.bytes(), &bytes[..]);
1005        }
1006    }
1007
1008    #[test]
1009    fn test_all_algorithms_private_der_roundtrip() {
1010        for alg in Algorithm::all() {
1011            let bytes = vec![0x42u8; alg.private_key_size()];
1012            let key = PrivateKey::new(alg, bytes.clone()).unwrap();
1013            let der = key.to_der();
1014            let decoded = PrivateKey::from_pkcs8(&der).unwrap();
1015            assert_eq!(decoded.algorithm(), alg, "failed for {}", alg);
1016            assert_eq!(decoded.bytes(), &bytes[..]);
1017        }
1018    }
1019
1020    #[test]
1021    fn test_all_algorithms_key_from_der_roundtrip() {
1022        for alg in Algorithm::all() {
1023            // Public
1024            let pub_bytes = vec![0x42u8; alg.public_key_size()];
1025            let pub_key = PublicKey::new(alg, pub_bytes).unwrap();
1026            let pub_der = pub_key.to_der();
1027            let decoded = Key::from_der(&pub_der).unwrap();
1028            assert_eq!(decoded.algorithm(), alg);
1029            assert_eq!(decoded.key_type(), KeyType::Public);
1030
1031            // Private
1032            let priv_bytes = vec![0x42u8; alg.private_key_size()];
1033            let priv_key = PrivateKey::new(alg, priv_bytes).unwrap();
1034            let priv_der = priv_key.to_der();
1035            let decoded = Key::from_der(&priv_der).unwrap();
1036            assert_eq!(decoded.algorithm(), alg);
1037            assert_eq!(decoded.key_type(), KeyType::Private);
1038        }
1039    }
1040
1041    // =========================================================================
1042    // PEM encoding/decoding tests
1043    // =========================================================================
1044
1045    #[cfg(feature = "pem")]
1046    #[test]
1047    fn test_public_key_pem_roundtrip() {
1048        let alg = Algorithm::MlKem(MlKem::Kem512);
1049        let bytes = vec![0xABu8; 800];
1050        let key = PublicKey::new(alg, bytes).unwrap();
1051        let pem = key.to_pem();
1052        let decoded = PublicKey::from_pem(&pem).unwrap();
1053        assert_eq!(decoded.algorithm(), alg);
1054        assert_eq!(decoded.bytes(), key.bytes());
1055    }
1056
1057    #[cfg(feature = "pem")]
1058    #[test]
1059    fn test_private_key_pem_roundtrip() {
1060        let alg = Algorithm::MlKem(MlKem::Kem512);
1061        let bytes = vec![0xCDu8; 1632];
1062        let key = PrivateKey::new(alg, bytes).unwrap();
1063        let pem = key.to_pem();
1064        let decoded = PrivateKey::from_pem(&pem).unwrap();
1065        assert_eq!(decoded.algorithm(), alg);
1066        assert_eq!(decoded.bytes(), key.bytes());
1067    }
1068
1069    #[cfg(feature = "pem")]
1070    #[test]
1071    fn test_public_key_from_pem_wrong_label() {
1072        let alg = Algorithm::MlKem(MlKem::Kem512);
1073        let bytes = vec![0xABu8; 1632];
1074        let key = PrivateKey::new(alg, bytes).unwrap();
1075        let pem = key.to_pem();
1076        let err = PublicKey::from_pem(&pem).unwrap_err();
1077        assert!(matches!(err, crate::error::Error::InvalidPem(_)));
1078    }
1079
1080    #[cfg(feature = "pem")]
1081    #[test]
1082    fn test_private_key_from_pem_wrong_label() {
1083        let alg = Algorithm::MlKem(MlKem::Kem512);
1084        let bytes = vec![0xABu8; 800];
1085        let key = PublicKey::new(alg, bytes).unwrap();
1086        let pem = key.to_pem();
1087        let err = PrivateKey::from_pem(&pem).unwrap_err();
1088        assert!(matches!(err, crate::error::Error::InvalidPem(_)));
1089    }
1090
1091    #[cfg(feature = "pem")]
1092    #[test]
1093    fn test_key_from_pem_public() {
1094        let alg = Algorithm::MlKem(MlKem::Kem768);
1095        let bytes = vec![0x42u8; 1184];
1096        let key = PublicKey::new(alg, bytes).unwrap();
1097        let pem = key.to_pem();
1098        let decoded = Key::from_pem(&pem).unwrap();
1099        assert_eq!(decoded.algorithm(), alg);
1100        assert_eq!(decoded.key_type(), KeyType::Public);
1101        assert_eq!(decoded.bytes(), key.bytes());
1102    }
1103
1104    #[cfg(feature = "pem")]
1105    #[test]
1106    fn test_key_from_pem_private() {
1107        let alg = Algorithm::MlDsa(MlDsa::Dsa44);
1108        let bytes = vec![0x42u8; 2560];
1109        let key = PrivateKey::new(alg, bytes).unwrap();
1110        let pem = key.to_pem();
1111        let decoded = Key::from_pem(&pem).unwrap();
1112        assert_eq!(decoded.algorithm(), alg);
1113        assert_eq!(decoded.key_type(), KeyType::Private);
1114        assert_eq!(decoded.bytes(), key.bytes());
1115    }
1116
1117    #[cfg(feature = "pem")]
1118    #[test]
1119    fn test_key_from_pem_unsupported_label() {
1120        let pem = "-----BEGIN CERTIFICATE-----\nAAA=\n-----END CERTIFICATE-----";
1121        let err = Key::from_pem(pem).unwrap_err();
1122        assert!(matches!(err, crate::error::Error::InvalidPem(_)));
1123    }
1124
1125    #[cfg(feature = "pem")]
1126    #[test]
1127    fn test_public_key_ref_to_pem() {
1128        let alg = Algorithm::MlKem(MlKem::Kem512);
1129        let bytes = vec![0xABu8; 800];
1130        let key_ref = PublicKeyRef::new(alg, &bytes).unwrap();
1131        let pem = key_ref.to_pem();
1132        let decoded = PublicKey::from_pem(&pem).unwrap();
1133        assert_eq!(decoded.algorithm(), alg);
1134        assert_eq!(decoded.bytes(), &bytes[..]);
1135    }
1136
1137    #[cfg(feature = "pem")]
1138    #[test]
1139    fn test_private_key_ref_to_pem() {
1140        let alg = Algorithm::MlKem(MlKem::Kem512);
1141        let bytes = vec![0xCDu8; 1632];
1142        let key_ref = PrivateKeyRef::new(alg, &bytes).unwrap();
1143        let pem = key_ref.to_pem();
1144        let decoded = PrivateKey::from_pem(&pem).unwrap();
1145        assert_eq!(decoded.algorithm(), alg);
1146        assert_eq!(decoded.bytes(), &bytes[..]);
1147    }
1148
1149    #[cfg(feature = "pem")]
1150    #[test]
1151    fn test_all_algorithms_pem_roundtrip() {
1152        for alg in Algorithm::all() {
1153            // Public
1154            let pub_bytes = vec![0x42u8; alg.public_key_size()];
1155            let pub_key = PublicKey::new(alg, pub_bytes).unwrap();
1156            let pub_pem = pub_key.to_pem();
1157            let decoded = PublicKey::from_pem(&pub_pem).unwrap();
1158            assert_eq!(
1159                decoded.algorithm(),
1160                alg,
1161                "public PEM roundtrip failed for {}",
1162                alg
1163            );
1164            assert_eq!(decoded.bytes(), pub_key.bytes());
1165
1166            // Private
1167            let priv_bytes = vec![0x42u8; alg.private_key_size()];
1168            let priv_key = PrivateKey::new(alg, priv_bytes).unwrap();
1169            let priv_pem = priv_key.to_pem();
1170            let decoded = PrivateKey::from_pem(&priv_pem).unwrap();
1171            assert_eq!(
1172                decoded.algorithm(),
1173                alg,
1174                "private PEM roundtrip failed for {}",
1175                alg
1176            );
1177            assert_eq!(decoded.bytes(), priv_key.bytes());
1178        }
1179    }
1180
1181    // =========================================================================
1182    // JWK encoding/decoding tests
1183    // =========================================================================
1184
1185    #[cfg(feature = "jwk")]
1186    #[test]
1187    fn test_public_key_to_jwk() {
1188        let alg = Algorithm::MlKem(MlKem::Kem512);
1189        let bytes = vec![0x42u8; 800];
1190        let key = PublicKey::new(alg, bytes).unwrap();
1191        let jwk = key.to_jwk();
1192        assert_eq!(jwk.kty, "PQC");
1193        assert_eq!(jwk.alg, "ML-KEM-512");
1194        assert!(!jwk.x.is_empty());
1195    }
1196
1197    #[cfg(feature = "jwk")]
1198    #[test]
1199    fn test_public_key_jwk_roundtrip() {
1200        let alg = Algorithm::MlKem(MlKem::Kem512);
1201        let bytes = vec![0x42u8; 800];
1202        let key = PublicKey::new(alg, bytes).unwrap();
1203        let jwk = key.to_jwk();
1204        let decoded = PublicKey::from_jwk(&jwk).unwrap();
1205        assert_eq!(decoded, key);
1206    }
1207
1208    #[cfg(feature = "jwk")]
1209    #[test]
1210    fn test_private_key_jwk_roundtrip() {
1211        let alg = Algorithm::MlKem(MlKem::Kem512);
1212        let pub_bytes = vec![0x42u8; 800];
1213        let priv_bytes = vec![0xABu8; 1632];
1214        let pub_key = PublicKey::new(alg, pub_bytes).unwrap();
1215        let priv_key = PrivateKey::new(alg, priv_bytes).unwrap();
1216        let jwk = priv_key.to_jwk(&pub_key).unwrap();
1217        let decoded = PrivateKey::from_jwk(&jwk).unwrap();
1218        assert_eq!(decoded, priv_key);
1219    }
1220
1221    #[cfg(feature = "jwk")]
1222    #[test]
1223    fn test_public_key_ref_to_jwk() {
1224        let alg = Algorithm::MlKem(MlKem::Kem768);
1225        let bytes = vec![0x42u8; 1184];
1226        let key_ref = PublicKeyRef::new(alg, &bytes).unwrap();
1227        let jwk = key_ref.to_jwk();
1228        let decoded = PublicKey::from_jwk(&jwk).unwrap();
1229        assert_eq!(decoded.algorithm(), alg);
1230        assert_eq!(decoded.bytes(), &bytes[..]);
1231    }
1232
1233    #[cfg(feature = "jwk")]
1234    #[test]
1235    fn test_private_key_ref_to_jwk() {
1236        let alg = Algorithm::SlhDsa(SlhDsa::Sha2_128s);
1237        let pub_bytes = vec![0x42u8; 32];
1238        let priv_bytes = vec![0xABu8; 64];
1239        let pub_ref = PublicKeyRef::new(alg, &pub_bytes).unwrap();
1240        let priv_ref = PrivateKeyRef::new(alg, &priv_bytes).unwrap();
1241        let jwk = priv_ref.to_jwk(&pub_ref).unwrap();
1242        let decoded = PrivateKey::from_jwk(&jwk).unwrap();
1243        assert_eq!(decoded.algorithm(), alg);
1244        assert_eq!(decoded.bytes(), &priv_bytes[..]);
1245    }
1246
1247    #[cfg(feature = "jwk")]
1248    #[test]
1249    fn test_private_key_to_jwk_algorithm_mismatch() {
1250        // SLH-DSA SHA2-128s and SHAKE-128s both have 32-byte public keys
1251        let priv_alg = Algorithm::SlhDsa(SlhDsa::Sha2_128s);
1252        let pub_alg = Algorithm::SlhDsa(SlhDsa::Shake128s);
1253        let priv_bytes = vec![0xABu8; 64];
1254        let pub_bytes = vec![0x42u8; 32];
1255        let priv_ref = PrivateKeyRef::new(priv_alg, &priv_bytes).unwrap();
1256        let pub_ref = PublicKeyRef::new(pub_alg, &pub_bytes).unwrap();
1257        let err = priv_ref.to_jwk(&pub_ref).unwrap_err();
1258        assert!(matches!(err, crate::error::Error::InvalidJwk(_)));
1259    }
1260
1261    #[cfg(feature = "jwk")]
1262    #[test]
1263    fn test_key_from_jwk_public() {
1264        let alg = Algorithm::MlDsa(MlDsa::Dsa44);
1265        let bytes = vec![0x42u8; 1312];
1266        let pub_key = PublicKey::new(alg, bytes).unwrap();
1267        let jwk = crate::jwk::Jwk::Public(pub_key.to_jwk());
1268        let decoded = Key::from_jwk(&jwk).unwrap();
1269        assert_eq!(decoded.algorithm(), alg);
1270        assert_eq!(decoded.key_type(), KeyType::Public);
1271        assert_eq!(decoded.bytes(), pub_key.bytes());
1272    }
1273
1274    #[cfg(feature = "jwk")]
1275    #[test]
1276    fn test_key_from_jwk_private() {
1277        let alg = Algorithm::MlDsa(MlDsa::Dsa44);
1278        let pub_bytes = vec![0x42u8; 1312];
1279        let priv_bytes = vec![0xABu8; 2560];
1280        let pub_key = PublicKey::new(alg, pub_bytes).unwrap();
1281        let priv_key = PrivateKey::new(alg, priv_bytes).unwrap();
1282        let jwk = crate::jwk::Jwk::Private(priv_key.to_jwk(&pub_key).unwrap());
1283        let decoded = Key::from_jwk(&jwk).unwrap();
1284        assert_eq!(decoded.algorithm(), alg);
1285        assert_eq!(decoded.key_type(), KeyType::Private);
1286        assert_eq!(decoded.bytes(), priv_key.bytes());
1287    }
1288
1289    #[cfg(feature = "jwk")]
1290    #[test]
1291    fn test_key_from_jwk_str_public() {
1292        let alg = Algorithm::MlKem(MlKem::Kem512);
1293        let bytes = vec![0x42u8; 800];
1294        let key = PublicKey::new(alg, bytes).unwrap();
1295        let json = key.to_jwk().to_json();
1296        let decoded = Key::from_jwk_str(&json).unwrap();
1297        assert_eq!(decoded.algorithm(), alg);
1298        assert_eq!(decoded.key_type(), KeyType::Public);
1299        assert_eq!(decoded.bytes(), key.bytes());
1300    }
1301
1302    #[cfg(feature = "jwk")]
1303    #[test]
1304    fn test_key_from_jwk_str_private() {
1305        let alg = Algorithm::MlKem(MlKem::Kem512);
1306        let pub_bytes = vec![0x42u8; 800];
1307        let priv_bytes = vec![0xABu8; 1632];
1308        let pub_key = PublicKey::new(alg, pub_bytes).unwrap();
1309        let priv_key = PrivateKey::new(alg, priv_bytes).unwrap();
1310        let json = priv_key.to_jwk(&pub_key).unwrap().to_json();
1311        let decoded = Key::from_jwk_str(&json).unwrap();
1312        assert_eq!(decoded.algorithm(), alg);
1313        assert_eq!(decoded.key_type(), KeyType::Private);
1314        assert_eq!(decoded.bytes(), priv_key.bytes());
1315    }
1316
1317    #[cfg(feature = "jwk")]
1318    #[test]
1319    fn test_all_algorithms_jwk_roundtrip() {
1320        for alg in Algorithm::all() {
1321            let pub_bytes = vec![0x42u8; alg.public_key_size()];
1322            let priv_bytes = vec![0xABu8; alg.private_key_size()];
1323            let pub_key = PublicKey::new(alg, pub_bytes).unwrap();
1324            let priv_key = PrivateKey::new(alg, priv_bytes).unwrap();
1325
1326            // Public JWK roundtrip
1327            let pub_jwk = pub_key.to_jwk();
1328            let decoded_pub = PublicKey::from_jwk(&pub_jwk).unwrap();
1329            assert_eq!(
1330                decoded_pub, pub_key,
1331                "public JWK roundtrip failed for {}",
1332                alg
1333            );
1334
1335            // Private JWK roundtrip
1336            let priv_jwk = priv_key.to_jwk(&pub_key).unwrap();
1337            let decoded_priv = PrivateKey::from_jwk(&priv_jwk).unwrap();
1338            assert_eq!(
1339                decoded_priv, priv_key,
1340                "private JWK roundtrip failed for {}",
1341                alg
1342            );
1343        }
1344    }
1345
1346    #[cfg(feature = "pem")]
1347    #[test]
1348    fn test_real_fixture_pem_types_roundtrip() {
1349        use pq_oid::SlhDsa;
1350
1351        let fixtures: &[(&str, Algorithm, KeyType)] = &[
1352            (
1353                include_str!("../../test-data/test-keys/ml_kem_512_pub.pem"),
1354                Algorithm::MlKem(MlKem::Kem512),
1355                KeyType::Public,
1356            ),
1357            (
1358                include_str!("../../test-data/test-keys/ml_kem_512_priv.pem"),
1359                Algorithm::MlKem(MlKem::Kem512),
1360                KeyType::Private,
1361            ),
1362            (
1363                include_str!("../../test-data/test-keys/ml_kem_768_pub.pem"),
1364                Algorithm::MlKem(MlKem::Kem768),
1365                KeyType::Public,
1366            ),
1367            (
1368                include_str!("../../test-data/test-keys/ml_kem_768_priv.pem"),
1369                Algorithm::MlKem(MlKem::Kem768),
1370                KeyType::Private,
1371            ),
1372            (
1373                include_str!("../../test-data/test-keys/ml_kem_1024_pub.pem"),
1374                Algorithm::MlKem(MlKem::Kem1024),
1375                KeyType::Public,
1376            ),
1377            (
1378                include_str!("../../test-data/test-keys/ml_kem_1024_priv.pem"),
1379                Algorithm::MlKem(MlKem::Kem1024),
1380                KeyType::Private,
1381            ),
1382            (
1383                include_str!("../../test-data/test-keys/ml_dsa_44_pub.pem"),
1384                Algorithm::MlDsa(MlDsa::Dsa44),
1385                KeyType::Public,
1386            ),
1387            (
1388                include_str!("../../test-data/test-keys/ml_dsa_44_priv.pem"),
1389                Algorithm::MlDsa(MlDsa::Dsa44),
1390                KeyType::Private,
1391            ),
1392            (
1393                include_str!("../../test-data/test-keys/ml_dsa_65_pub.pem"),
1394                Algorithm::MlDsa(MlDsa::Dsa65),
1395                KeyType::Public,
1396            ),
1397            (
1398                include_str!("../../test-data/test-keys/ml_dsa_65_priv.pem"),
1399                Algorithm::MlDsa(MlDsa::Dsa65),
1400                KeyType::Private,
1401            ),
1402            (
1403                include_str!("../../test-data/test-keys/slh_dsa_sha2_128s_pub.pem"),
1404                Algorithm::SlhDsa(SlhDsa::Sha2_128s),
1405                KeyType::Public,
1406            ),
1407            (
1408                include_str!("../../test-data/test-keys/slh_dsa_sha2_128s_priv.pem"),
1409                Algorithm::SlhDsa(SlhDsa::Sha2_128s),
1410                KeyType::Private,
1411            ),
1412        ];
1413
1414        for (pem_str, expected_alg, expected_type) in fixtures {
1415            match expected_type {
1416                KeyType::Public => {
1417                    let key = PublicKey::from_pem(pem_str).unwrap();
1418                    assert_eq!(
1419                        key.algorithm(),
1420                        *expected_alg,
1421                        "alg mismatch for {}",
1422                        expected_alg
1423                    );
1424                    let re_pem = key.to_pem();
1425                    let re_key = PublicKey::from_pem(&re_pem).unwrap();
1426                    assert_eq!(re_key, key, "PEM roundtrip failed for {}", expected_alg);
1427                }
1428                KeyType::Private => {
1429                    let key = PrivateKey::from_pem(pem_str).unwrap();
1430                    assert_eq!(
1431                        key.algorithm(),
1432                        *expected_alg,
1433                        "alg mismatch for {}",
1434                        expected_alg
1435                    );
1436                    let re_pem = key.to_pem();
1437                    let re_key = PrivateKey::from_pem(&re_pem).unwrap();
1438                    assert_eq!(re_key, key, "PEM roundtrip failed for {}", expected_alg);
1439                }
1440            }
1441
1442            // Also test Key::from_pem dispatch
1443            let key = Key::from_pem(pem_str).unwrap();
1444            assert_eq!(key.algorithm(), *expected_alg);
1445            assert_eq!(key.key_type(), *expected_type);
1446        }
1447    }
1448}