1use crate::{
4 EncodedVerifyingKey, ExpandedSigningKey, MlDsa44, MlDsa65, MlDsa87, MlDsaParams, Signature,
5 SigningKey, VerifyingKey,
6};
7pub use ::pkcs8::*;
8use ::pkcs8::{
9 der::{
10 AnyRef, Reader, TagNumber,
11 asn1::{ContextSpecific, OctetStringRef},
12 },
13 spki::{AlgorithmIdentifier, AssociatedAlgorithmIdentifier, SignatureAlgorithmIdentifier},
14};
15use const_oid::db::fips204;
16
17#[cfg(feature = "alloc")]
18use pkcs8::{
19 der::{
20 Encode, TagMode,
21 asn1::{BitString, BitStringRef},
22 },
23 spki::SignatureBitStringEncoding,
24};
25
26const SEED_TAG_NUMBER: TagNumber = TagNumber(0);
28
29type SeedString<'a> = ContextSpecific<&'a OctetStringRef>;
31
32impl AssociatedAlgorithmIdentifier for MlDsa44 {
33 type Params = AnyRef<'static>;
34
35 const ALGORITHM_IDENTIFIER: AlgorithmIdentifierRef<'static> = AlgorithmIdentifierRef {
36 oid: fips204::ID_ML_DSA_44,
37 parameters: None,
38 };
39}
40
41impl AssociatedAlgorithmIdentifier for MlDsa65 {
42 type Params = AnyRef<'static>;
43
44 const ALGORITHM_IDENTIFIER: AlgorithmIdentifierRef<'static> = AlgorithmIdentifierRef {
45 oid: fips204::ID_ML_DSA_65,
46 parameters: None,
47 };
48}
49
50impl AssociatedAlgorithmIdentifier for MlDsa87 {
51 type Params = AnyRef<'static>;
52
53 const ALGORITHM_IDENTIFIER: AlgorithmIdentifierRef<'static> = AlgorithmIdentifierRef {
54 oid: fips204::ID_ML_DSA_87,
55 parameters: None,
56 };
57}
58
59impl<P> AssociatedAlgorithmIdentifier for Signature<P>
60where
61 P: MlDsaParams,
62 P: AssociatedAlgorithmIdentifier<Params = AnyRef<'static>>,
63{
64 type Params = AnyRef<'static>;
65
66 const ALGORITHM_IDENTIFIER: AlgorithmIdentifierRef<'static> = P::ALGORITHM_IDENTIFIER;
67}
68
69#[cfg(feature = "alloc")]
70impl<P: MlDsaParams> SignatureBitStringEncoding for Signature<P> {
71 fn to_bitstring(&self) -> der::Result<BitString> {
72 BitString::new(0, self.encode().to_vec())
73 }
74}
75
76impl<P> SignatureAlgorithmIdentifier for SigningKey<P>
77where
78 P: MlDsaParams,
79 P: AssociatedAlgorithmIdentifier<Params = AnyRef<'static>>,
80{
81 type Params = AnyRef<'static>;
82
83 const SIGNATURE_ALGORITHM_IDENTIFIER: AlgorithmIdentifier<Self::Params> =
84 Signature::<P>::ALGORITHM_IDENTIFIER;
85}
86
87impl<P> TryFrom<PrivateKeyInfoRef<'_>> for SigningKey<P>
88where
89 P: MlDsaParams,
90 P: AssociatedAlgorithmIdentifier<Params = AnyRef<'static>>,
91{
92 type Error = Error;
93
94 fn try_from(private_key_info: PrivateKeyInfoRef<'_>) -> Result<Self> {
95 private_key_info
96 .algorithm
97 .assert_algorithm_oid(P::ALGORITHM_IDENTIFIER.oid)?;
98
99 let mut reader = der::SliceReader::new(private_key_info.private_key.as_bytes())?;
100 let seed_string =
101 SeedString::decode_implicit(&mut reader, SEED_TAG_NUMBER)?.ok_or(KeyError::Invalid)?;
102 let seed = seed_string
103 .value
104 .as_bytes()
105 .try_into()
106 .map_err(|_| KeyError::Invalid)?;
107 reader.finish()?;
108
109 Ok(SigningKey::from_seed(&seed))
110 }
111}
112
113#[cfg(feature = "alloc")]
114impl<P> EncodePrivateKey for SigningKey<P>
115where
116 P: MlDsaParams,
117 P: AssociatedAlgorithmIdentifier<Params = AnyRef<'static>>,
118{
119 fn to_pkcs8_der(&self) -> ::pkcs8::Result<SecretDocument> {
120 let seed_der = SeedString {
121 tag_mode: TagMode::Implicit,
122 tag_number: SEED_TAG_NUMBER,
123 value: OctetStringRef::new(self.as_seed())?,
124 }
125 .to_der()?;
126
127 let private_key = OctetStringRef::new(&seed_der)?;
128 let private_key_info = PrivateKeyInfoRef::new(P::ALGORITHM_IDENTIFIER, private_key);
129 ::pkcs8::SecretDocument::encode_msg(&private_key_info).map_err(::pkcs8::Error::Asn1)
130 }
131}
132
133impl<P> SignatureAlgorithmIdentifier for ExpandedSigningKey<P>
134where
135 P: MlDsaParams,
136 P: AssociatedAlgorithmIdentifier<Params = AnyRef<'static>>,
137{
138 type Params = AnyRef<'static>;
139
140 const SIGNATURE_ALGORITHM_IDENTIFIER: AlgorithmIdentifier<Self::Params> =
141 Signature::<P>::ALGORITHM_IDENTIFIER;
142}
143
144impl<P> TryFrom<PrivateKeyInfoRef<'_>> for ExpandedSigningKey<P>
145where
146 P: MlDsaParams,
147 P: AssociatedAlgorithmIdentifier<Params = AnyRef<'static>>,
148{
149 type Error = ::pkcs8::Error;
150
151 fn try_from(private_key_info: PrivateKeyInfoRef<'_>) -> Result<Self> {
152 SigningKey::try_from(private_key_info).map(|sk| sk.expanded_key().clone())
153 }
154}
155
156impl<P> SignatureAlgorithmIdentifier for VerifyingKey<P>
157where
158 P: MlDsaParams,
159 P: AssociatedAlgorithmIdentifier<Params = AnyRef<'static>>,
160{
161 type Params = AnyRef<'static>;
162
163 const SIGNATURE_ALGORITHM_IDENTIFIER: AlgorithmIdentifier<Self::Params> =
164 Signature::<P>::ALGORITHM_IDENTIFIER;
165}
166
167#[cfg(feature = "alloc")]
168impl<P> EncodePublicKey for VerifyingKey<P>
169where
170 P: MlDsaParams,
171 P: AssociatedAlgorithmIdentifier<Params = AnyRef<'static>>,
172{
173 fn to_public_key_der(&self) -> spki::Result<Document> {
174 let public_key = self.encode();
175 let subject_public_key = BitStringRef::new(0, &public_key)?;
176
177 SubjectPublicKeyInfo {
178 algorithm: P::ALGORITHM_IDENTIFIER,
179 subject_public_key,
180 }
181 .try_into()
182 }
183}
184
185impl<P> TryFrom<SubjectPublicKeyInfoRef<'_>> for VerifyingKey<P>
186where
187 P: MlDsaParams,
188 P: AssociatedAlgorithmIdentifier<Params = AnyRef<'static>>,
189{
190 type Error = spki::Error;
191
192 fn try_from(spki: SubjectPublicKeyInfoRef<'_>) -> spki::Result<Self> {
193 spki.algorithm
194 .assert_algorithm_oid(P::ALGORITHM_IDENTIFIER.oid)?;
195
196 let evk = EncodedVerifyingKey::<P>::try_from(
197 spki.subject_public_key
198 .as_bytes()
199 .ok_or_else(|| der::Tag::BitString.value_error().to_error())?,
200 )
201 .map_err(|_| spki::Error::KeyMalformed)?;
202
203 Ok(Self::decode(&evk))
204 }
205}