@@ -41,6 +41,7 @@ mod util;
4141// TODO(RLB) Move module to an independent crate shared with ml_kem
4242mod module_lattice;
4343
44+ use const_oid:: db:: fips204;
4445use core:: convert:: { AsRef , TryFrom , TryInto } ;
4546use hybrid_array:: {
4647 typenum:: {
@@ -49,13 +50,31 @@ use hybrid_array::{
4950 } ,
5051 Array ,
5152} ;
53+ use pkcs8:: {
54+ der:: AnyRef ,
55+ spki:: {
56+ AlgorithmIdentifier , AssociatedAlgorithmIdentifier , SignatureAlgorithmIdentifier ,
57+ SubjectPublicKeyInfoRef ,
58+ } ,
59+ AlgorithmIdentifierRef , PrivateKeyInfoRef ,
60+ } ;
5261
5362#[ cfg( feature = "rand_core" ) ]
5463use rand_core:: CryptoRngCore ;
5564
5665#[ cfg( feature = "zeroize" ) ]
5766use zeroize:: { Zeroize , ZeroizeOnDrop } ;
5867
68+ #[ cfg( feature = "alloc" ) ]
69+ use pkcs8:: {
70+ der:: {
71+ self ,
72+ asn1:: { BitString , BitStringRef } ,
73+ } ,
74+ spki:: { self , SignatureBitStringEncoding , SubjectPublicKeyInfo } ,
75+ EncodePublicKey ,
76+ } ;
77+
5978use crate :: algebra:: { AlgebraExt , Elem , NttMatrix , NttVector , Truncate , Vector } ;
6079use crate :: crypto:: H ;
6180use crate :: hint:: Hint ;
@@ -124,6 +143,22 @@ impl<P: MlDsaParams> signature::SignatureEncoding for Signature<P> {
124143 type Repr = EncodedSignature < P > ;
125144}
126145
146+ #[ cfg( feature = "alloc" ) ]
147+ impl < P : MlDsaParams > SignatureBitStringEncoding for Signature < P > {
148+ fn to_bitstring ( & self ) -> der:: Result < BitString > {
149+ BitString :: new ( 0 , self . encode ( ) . to_vec ( ) )
150+ }
151+ }
152+
153+ impl < P : MlDsaParams > AssociatedAlgorithmIdentifier for Signature < P > {
154+ type Params = AnyRef < ' static > ;
155+
156+ const ALGORITHM_IDENTIFIER : AlgorithmIdentifierRef < ' static > = AlgorithmIdentifierRef {
157+ oid : P :: ALGORITHM_OID ,
158+ parameters : None ,
159+ } ;
160+ }
161+
127162// This method takes a slice of slices so that we can accommodate the varying calculations (direct
128163// for test vectors, 0... for sign/sign_deterministic, 1... for the pre-hashed version) without
129164// having to allocate memory for components.
@@ -156,6 +191,23 @@ impl<P: MlDsaParams> signature::KeypairRef for KeyPair<P> {
156191 type VerifyingKey = VerifyingKey < P > ;
157192}
158193
194+ impl < P > TryFrom < PrivateKeyInfoRef < ' _ > > for KeyPair < P >
195+ where
196+ P : MlDsaParams ,
197+ {
198+ type Error = pkcs8:: Error ;
199+
200+ fn try_from ( private_key_info : pkcs8:: PrivateKeyInfoRef < ' _ > ) -> pkcs8:: Result < Self > {
201+ private_key_info
202+ . algorithm
203+ . assert_algorithm_oid ( P :: ALGORITHM_OID ) ?;
204+
205+ let seed = Array :: try_from ( private_key_info. private_key . as_bytes ( ) )
206+ . map_err ( |_| pkcs8:: Error :: KeyMalformed ) ?;
207+ Ok ( P :: key_gen_internal ( & seed) )
208+ }
209+ }
210+
159211/// An ML-DSA signing key
160212#[ derive( Clone , PartialEq ) ]
161213pub struct SigningKey < P : MlDsaParams > {
@@ -384,8 +436,28 @@ impl<P: MlDsaParams> signature::RandomizedSigner<Signature<P>> for SigningKey<P>
384436 }
385437}
386438
439+ impl < P : MlDsaParams > SignatureAlgorithmIdentifier for SigningKey < P > {
440+ type Params = AnyRef < ' static > ;
441+
442+ const SIGNATURE_ALGORITHM_IDENTIFIER : AlgorithmIdentifier < Self :: Params > =
443+ Signature :: < P > :: ALGORITHM_IDENTIFIER ;
444+ }
445+
446+ impl < P > TryFrom < PrivateKeyInfoRef < ' _ > > for SigningKey < P >
447+ where
448+ P : MlDsaParams ,
449+ {
450+ type Error = pkcs8:: Error ;
451+
452+ fn try_from ( private_key_info : pkcs8:: PrivateKeyInfoRef < ' _ > ) -> pkcs8:: Result < Self > {
453+ let keypair = KeyPair :: try_from ( private_key_info) ?;
454+
455+ Ok ( keypair. signing_key )
456+ }
457+ }
458+
387459/// An ML-DSA verification key
388- #[ derive( Clone , PartialEq ) ]
460+ #[ derive( Clone , Debug , PartialEq ) ]
389461pub struct VerifyingKey < P : ParameterSet > {
390462 rho : B32 ,
391463 t1 : Vector < P :: K > ,
@@ -488,6 +560,49 @@ impl<P: MlDsaParams> signature::Verifier<Signature<P>> for VerifyingKey<P> {
488560 }
489561}
490562
563+ impl < P : MlDsaParams > SignatureAlgorithmIdentifier for VerifyingKey < P > {
564+ type Params = AnyRef < ' static > ;
565+
566+ const SIGNATURE_ALGORITHM_IDENTIFIER : AlgorithmIdentifier < Self :: Params > =
567+ Signature :: < P > :: ALGORITHM_IDENTIFIER ;
568+ }
569+
570+ #[ cfg( feature = "alloc" ) ]
571+ impl < P : MlDsaParams > EncodePublicKey for VerifyingKey < P > {
572+ fn to_public_key_der ( & self ) -> spki:: Result < der:: Document > {
573+ let algorithm_identifier = AlgorithmIdentifierRef {
574+ oid : P :: ALGORITHM_OID ,
575+ parameters : None ,
576+ } ;
577+
578+ let public_key = self . encode ( ) ;
579+ let subject_public_key = BitStringRef :: new ( 0 , & public_key) ?;
580+
581+ SubjectPublicKeyInfo {
582+ algorithm : algorithm_identifier,
583+ subject_public_key,
584+ }
585+ . try_into ( )
586+ }
587+ }
588+
589+ impl < P : MlDsaParams > TryFrom < SubjectPublicKeyInfoRef < ' _ > > for VerifyingKey < P > {
590+ type Error = spki:: Error ;
591+
592+ fn try_from ( spki : SubjectPublicKeyInfoRef < ' _ > ) -> spki:: Result < Self > {
593+ spki. algorithm . assert_algorithm_oid ( P :: ALGORITHM_OID ) ?;
594+
595+ Ok ( Self :: decode (
596+ & EncodedVerifyingKey :: < P > :: try_from (
597+ spki. subject_public_key
598+ . as_bytes ( )
599+ . ok_or_else ( || der:: Tag :: BitString . value_error ( ) ) ?,
600+ )
601+ . map_err ( |_| pkcs8:: Error :: KeyMalformed ) ?,
602+ ) )
603+ }
604+ }
605+
491606/// `MlDsa44` is the parameter set for security category 2.
492607#[ derive( Default , Clone , Debug , PartialEq ) ]
493608pub struct MlDsa44 ;
@@ -503,6 +618,7 @@ impl ParameterSet for MlDsa44 {
503618 type Lambda = U32 ;
504619 type Omega = U80 ;
505620 const TAU : usize = 39 ;
621+ const ALGORITHM_OID : pkcs8:: ObjectIdentifier = fips204:: ID_ML_DSA_44 ;
506622}
507623
508624/// `MlDsa65` is the parameter set for security category 3.
@@ -520,6 +636,7 @@ impl ParameterSet for MlDsa65 {
520636 type Lambda = U48 ;
521637 type Omega = U55 ;
522638 const TAU : usize = 49 ;
639+ const ALGORITHM_OID : pkcs8:: ObjectIdentifier = fips204:: ID_ML_DSA_65 ;
523640}
524641
525642/// `MlKem87` is the parameter set for security category 5.
@@ -537,6 +654,7 @@ impl ParameterSet for MlDsa87 {
537654 type Lambda = U64 ;
538655 type Omega = U75 ;
539656 const TAU : usize = 60 ;
657+ const ALGORITHM_OID : pkcs8:: ObjectIdentifier = fips204:: ID_ML_DSA_87 ;
540658}
541659
542660/// A parameter set that knows how to generate key pairs
0 commit comments