@@ -38,6 +38,7 @@ mod encode;
3838mod hint;
3939mod ntt;
4040mod param;
41+ mod pkcs8;
4142mod sampling;
4243mod util;
4344
@@ -52,37 +53,17 @@ use hybrid_array::{
5253 U75 , U80 , U88 , Unsigned ,
5354 } ,
5455} ;
56+ use sha3:: Shake256 ;
5557use signature:: { DigestSigner , DigestVerifier , MultipartSigner , MultipartVerifier , Signer } ;
5658
5759#[ cfg( feature = "rand_core" ) ]
58- use signature:: { RandomizedDigestSigner , RandomizedMultipartSigner , RandomizedSigner } ;
59-
60- #[ cfg( feature = "rand_core" ) ]
61- use rand_core:: { CryptoRng , TryCryptoRng } ;
62-
63- use sha3:: Shake256 ;
64- #[ cfg( feature = "zeroize" ) ]
65- use zeroize:: { Zeroize , ZeroizeOnDrop } ;
66-
67- #[ cfg( feature = "pkcs8" ) ]
6860use {
69- const_oid:: db:: fips204,
70- pkcs8:: {
71- AlgorithmIdentifierRef , PrivateKeyInfoRef ,
72- der:: { self , AnyRef } ,
73- spki:: {
74- self , AlgorithmIdentifier , AssociatedAlgorithmIdentifier , SignatureAlgorithmIdentifier ,
75- SubjectPublicKeyInfoRef ,
76- } ,
77- } ,
61+ rand_core:: { CryptoRng , TryCryptoRng } ,
62+ signature:: { RandomizedDigestSigner , RandomizedMultipartSigner , RandomizedSigner } ,
7863} ;
7964
80- #[ cfg( all( feature = "alloc" , feature = "pkcs8" ) ) ]
81- use pkcs8:: {
82- EncodePrivateKey , EncodePublicKey ,
83- der:: asn1:: { BitString , BitStringRef , OctetStringRef } ,
84- spki:: { SignatureBitStringEncoding , SubjectPublicKeyInfo } ,
85- } ;
65+ #[ cfg( feature = "zeroize" ) ]
66+ use zeroize:: { Zeroize , ZeroizeOnDrop } ;
8667
8768use crate :: algebra:: { AlgebraExt , Elem , NttMatrix , NttVector , Truncate , Vector } ;
8869use crate :: crypto:: H ;
@@ -97,6 +78,10 @@ pub use crate::param::{EncodedSignature, EncodedSigningKey, EncodedVerifyingKey,
9778pub use crate :: util:: B32 ;
9879pub use signature:: { self , Error } ;
9980
81+ /// ML-DSA seeds are signing (private) keys, which are consistently 32-bytes across all security
82+ /// levels, and are the preferred serialization for representing such keys.
83+ pub type Seed = B32 ;
84+
10085/// An ML-DSA signature
10186#[ derive( Clone , PartialEq , Debug ) ]
10287pub struct Signature < P : MlDsaParams > {
@@ -153,24 +138,6 @@ impl<P: MlDsaParams> signature::SignatureEncoding for Signature<P> {
153138 type Repr = EncodedSignature < P > ;
154139}
155140
156- #[ cfg( all( feature = "alloc" , feature = "pkcs8" ) ) ]
157- impl < P : MlDsaParams > SignatureBitStringEncoding for Signature < P > {
158- fn to_bitstring ( & self ) -> der:: Result < BitString > {
159- BitString :: new ( 0 , self . encode ( ) . to_vec ( ) )
160- }
161- }
162-
163- #[ cfg( feature = "pkcs8" ) ]
164- impl < P > AssociatedAlgorithmIdentifier for Signature < P >
165- where
166- P : MlDsaParams ,
167- P : AssociatedAlgorithmIdentifier < Params = AnyRef < ' static > > ,
168- {
169- type Params = AnyRef < ' static > ;
170-
171- const ALGORITHM_IDENTIFIER : AlgorithmIdentifierRef < ' static > = P :: ALGORITHM_IDENTIFIER ;
172- }
173-
174141struct MuBuilder ( H ) ;
175142
176143impl MuBuilder {
@@ -256,26 +223,6 @@ impl<P: MlDsaParams> signature::KeypairRef for KeyPair<P> {
256223 type VerifyingKey = VerifyingKey < P > ;
257224}
258225
259- #[ cfg( feature = "pkcs8" ) ]
260- impl < P > TryFrom < PrivateKeyInfoRef < ' _ > > for KeyPair < P >
261- where
262- P : MlDsaParams ,
263- P : AssociatedAlgorithmIdentifier < Params = AnyRef < ' static > > ,
264- {
265- type Error = pkcs8:: Error ;
266-
267- fn try_from ( private_key_info : pkcs8:: PrivateKeyInfoRef < ' _ > ) -> pkcs8:: Result < Self > {
268- match private_key_info. algorithm {
269- alg if alg == P :: ALGORITHM_IDENTIFIER => { }
270- other => return Err ( spki:: Error :: OidUnknown { oid : other. oid } . into ( ) ) ,
271- }
272-
273- let seed = Array :: try_from ( private_key_info. private_key . as_bytes ( ) )
274- . map_err ( |_| pkcs8:: Error :: KeyMalformed ) ?;
275- Ok ( P :: from_seed ( & seed) )
276- }
277- }
278-
279226/// The `Signer` implementation for `KeyPair` uses the optional deterministic variant of ML-DSA, and
280227/// only supports signing with an empty context string.
281228impl < P : MlDsaParams > Signer < Signature < P > > for KeyPair < P > {
@@ -303,33 +250,6 @@ impl<P: MlDsaParams> DigestSigner<Shake256, Signature<P>> for KeyPair<P> {
303250 }
304251}
305252
306- #[ cfg( feature = "pkcs8" ) ]
307- impl < P > SignatureAlgorithmIdentifier for KeyPair < P >
308- where
309- P : MlDsaParams ,
310- P : AssociatedAlgorithmIdentifier < Params = AnyRef < ' static > > ,
311- {
312- type Params = AnyRef < ' static > ;
313-
314- const SIGNATURE_ALGORITHM_IDENTIFIER : AlgorithmIdentifier < Self :: Params > =
315- Signature :: < P > :: ALGORITHM_IDENTIFIER ;
316- }
317-
318- #[ cfg( all( feature = "alloc" , feature = "pkcs8" ) ) ]
319- impl < P > EncodePrivateKey for KeyPair < P >
320- where
321- P : MlDsaParams ,
322- P : AssociatedAlgorithmIdentifier < Params = AnyRef < ' static > > ,
323- {
324- fn to_pkcs8_der ( & self ) -> pkcs8:: Result < der:: SecretDocument > {
325- let pkcs8_key = pkcs8:: PrivateKeyInfoRef :: new (
326- P :: ALGORITHM_IDENTIFIER ,
327- OctetStringRef :: new ( & self . seed ) ?,
328- ) ;
329- Ok ( der:: SecretDocument :: encode_msg ( & pkcs8_key) ?)
330- }
331- }
332-
333253/// An ML-DSA signing key
334254#[ derive( Clone , PartialEq ) ]
335255pub struct SigningKey < P : MlDsaParams > {
@@ -403,7 +323,7 @@ impl<P: MlDsaParams> SigningKey<P> {
403323 /// This method reflects the ML-DSA.KeyGen_internal algorithm from FIPS 204, but only returns a
404324 /// signing key.
405325 #[ must_use]
406- pub fn from_seed ( seed : & B32 ) -> Self {
326+ pub fn from_seed ( seed : & Seed ) -> Self {
407327 let kp = P :: from_seed ( seed) ;
408328 kp. signing_key
409329 }
@@ -712,33 +632,6 @@ impl<P: MlDsaParams> RandomizedDigestSigner<Shake256, Signature<P>> for SigningK
712632 }
713633}
714634
715- #[ cfg( feature = "pkcs8" ) ]
716- impl < P > SignatureAlgorithmIdentifier for SigningKey < P >
717- where
718- P : MlDsaParams ,
719- P : AssociatedAlgorithmIdentifier < Params = AnyRef < ' static > > ,
720- {
721- type Params = AnyRef < ' static > ;
722-
723- const SIGNATURE_ALGORITHM_IDENTIFIER : AlgorithmIdentifier < Self :: Params > =
724- Signature :: < P > :: ALGORITHM_IDENTIFIER ;
725- }
726-
727- #[ cfg( feature = "pkcs8" ) ]
728- impl < P > TryFrom < PrivateKeyInfoRef < ' _ > > for SigningKey < P >
729- where
730- P : MlDsaParams ,
731- P : AssociatedAlgorithmIdentifier < Params = AnyRef < ' static > > ,
732- {
733- type Error = pkcs8:: Error ;
734-
735- fn try_from ( private_key_info : pkcs8:: PrivateKeyInfoRef < ' _ > ) -> pkcs8:: Result < Self > {
736- let keypair = KeyPair :: try_from ( private_key_info) ?;
737-
738- Ok ( keypair. signing_key )
739- }
740- }
741-
742635/// An ML-DSA verification key
743636#[ derive( Clone , Debug , PartialEq ) ]
744637pub struct VerifyingKey < P : ParameterSet > {
@@ -895,61 +788,6 @@ impl<P: MlDsaParams> DigestVerifier<Shake256, Signature<P>> for VerifyingKey<P>
895788 }
896789}
897790
898- #[ cfg( feature = "pkcs8" ) ]
899- impl < P > SignatureAlgorithmIdentifier for VerifyingKey < P >
900- where
901- P : MlDsaParams ,
902- P : AssociatedAlgorithmIdentifier < Params = AnyRef < ' static > > ,
903- {
904- type Params = AnyRef < ' static > ;
905-
906- const SIGNATURE_ALGORITHM_IDENTIFIER : AlgorithmIdentifier < Self :: Params > =
907- Signature :: < P > :: ALGORITHM_IDENTIFIER ;
908- }
909-
910- #[ cfg( all( feature = "alloc" , feature = "pkcs8" ) ) ]
911- impl < P > EncodePublicKey for VerifyingKey < P >
912- where
913- P : MlDsaParams ,
914- P : AssociatedAlgorithmIdentifier < Params = AnyRef < ' static > > ,
915- {
916- fn to_public_key_der ( & self ) -> spki:: Result < der:: Document > {
917- let public_key = self . encode ( ) ;
918- let subject_public_key = BitStringRef :: new ( 0 , & public_key) ?;
919-
920- SubjectPublicKeyInfo {
921- algorithm : P :: ALGORITHM_IDENTIFIER ,
922- subject_public_key,
923- }
924- . try_into ( )
925- }
926- }
927-
928- #[ cfg( feature = "pkcs8" ) ]
929- impl < P > TryFrom < SubjectPublicKeyInfoRef < ' _ > > for VerifyingKey < P >
930- where
931- P : MlDsaParams ,
932- P : AssociatedAlgorithmIdentifier < Params = AnyRef < ' static > > ,
933- {
934- type Error = spki:: Error ;
935-
936- fn try_from ( spki : SubjectPublicKeyInfoRef < ' _ > ) -> spki:: Result < Self > {
937- match spki. algorithm {
938- alg if alg == P :: ALGORITHM_IDENTIFIER => { }
939- other => return Err ( spki:: Error :: OidUnknown { oid : other. oid } ) ,
940- }
941-
942- Ok ( Self :: decode (
943- & EncodedVerifyingKey :: < P > :: try_from (
944- spki. subject_public_key
945- . as_bytes ( )
946- . ok_or_else ( || der:: Tag :: BitString . value_error ( ) . to_error ( ) ) ?,
947- )
948- . map_err ( |_| pkcs8:: Error :: KeyMalformed ) ?,
949- ) )
950- }
951- }
952-
953791/// `MlDsa44` is the parameter set for security category 2.
954792#[ derive( Default , Clone , Debug , PartialEq ) ]
955793pub struct MlDsa44 ;
@@ -967,16 +805,6 @@ impl ParameterSet for MlDsa44 {
967805 const TAU : usize = 39 ;
968806}
969807
970- #[ cfg( feature = "pkcs8" ) ]
971- impl AssociatedAlgorithmIdentifier for MlDsa44 {
972- type Params = AnyRef < ' static > ;
973-
974- const ALGORITHM_IDENTIFIER : AlgorithmIdentifierRef < ' static > = AlgorithmIdentifierRef {
975- oid : fips204:: ID_ML_DSA_44 ,
976- parameters : None ,
977- } ;
978- }
979-
980808/// `MlDsa65` is the parameter set for security category 3.
981809#[ derive( Default , Clone , Debug , PartialEq ) ]
982810pub struct MlDsa65 ;
@@ -994,16 +822,6 @@ impl ParameterSet for MlDsa65 {
994822 const TAU : usize = 49 ;
995823}
996824
997- #[ cfg( feature = "pkcs8" ) ]
998- impl AssociatedAlgorithmIdentifier for MlDsa65 {
999- type Params = AnyRef < ' static > ;
1000-
1001- const ALGORITHM_IDENTIFIER : AlgorithmIdentifierRef < ' static > = AlgorithmIdentifierRef {
1002- oid : fips204:: ID_ML_DSA_65 ,
1003- parameters : None ,
1004- } ;
1005- }
1006-
1007825/// `MlKem87` is the parameter set for security category 5.
1008826#[ derive( Default , Clone , Debug , PartialEq ) ]
1009827pub struct MlDsa87 ;
@@ -1021,16 +839,6 @@ impl ParameterSet for MlDsa87 {
1021839 const TAU : usize = 60 ;
1022840}
1023841
1024- #[ cfg( feature = "pkcs8" ) ]
1025- impl AssociatedAlgorithmIdentifier for MlDsa87 {
1026- type Params = AnyRef < ' static > ;
1027-
1028- const ALGORITHM_IDENTIFIER : AlgorithmIdentifierRef < ' static > = AlgorithmIdentifierRef {
1029- oid : fips204:: ID_ML_DSA_87 ,
1030- parameters : None ,
1031- } ;
1032- }
1033-
1034842/// A parameter set that knows how to generate key pairs
1035843pub trait KeyGen : MlDsaParams {
1036844 /// The type that is returned by key generation
@@ -1065,7 +873,7 @@ where
1065873 ///
1066874 /// This method reflects the ML-DSA.KeyGen_internal algorithm from FIPS 204.
1067875 // Algorithm 6 ML-DSA.KeyGen_internal
1068- fn from_seed ( xi : & B32 ) -> KeyPair < P >
876+ fn from_seed ( xi : & Seed ) -> KeyPair < P >
1069877 where
1070878 P : MlDsaParams ,
1071879 {
@@ -1367,7 +1175,7 @@ mod test {
13671175 where
13681176 P : MlDsaParams ,
13691177 {
1370- let seed = Array ( [ 0u8 ; 32 ] ) ;
1178+ let seed = Seed :: default ( ) ;
13711179 let kp1 = P :: from_seed ( & seed) ;
13721180 let sk1 = SigningKey :: < P > :: from_seed ( & seed) ;
13731181 let vk1 = sk1. verifying_key ( ) ;
0 commit comments