@@ -41,6 +41,7 @@ mod util;
41
41
// TODO(RLB) Move module to an independent crate shared with ml_kem
42
42
mod module_lattice;
43
43
44
+ use const_oid:: db:: fips204;
44
45
use core:: convert:: { AsRef , TryFrom , TryInto } ;
45
46
use hybrid_array:: {
46
47
typenum:: {
@@ -49,13 +50,31 @@ use hybrid_array::{
49
50
} ,
50
51
Array ,
51
52
} ;
53
+ use pkcs8:: {
54
+ der:: AnyRef ,
55
+ spki:: {
56
+ AlgorithmIdentifier , AssociatedAlgorithmIdentifier , SignatureAlgorithmIdentifier ,
57
+ SubjectPublicKeyInfoRef ,
58
+ } ,
59
+ AlgorithmIdentifierRef , PrivateKeyInfoRef ,
60
+ } ;
52
61
53
62
#[ cfg( feature = "rand_core" ) ]
54
63
use rand_core:: CryptoRngCore ;
55
64
56
65
#[ cfg( feature = "zeroize" ) ]
57
66
use zeroize:: { Zeroize , ZeroizeOnDrop } ;
58
67
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
+
59
78
use crate :: algebra:: { AlgebraExt , Elem , NttMatrix , NttVector , Truncate , Vector } ;
60
79
use crate :: crypto:: H ;
61
80
use crate :: hint:: Hint ;
@@ -124,6 +143,22 @@ impl<P: MlDsaParams> signature::SignatureEncoding for Signature<P> {
124
143
type Repr = EncodedSignature < P > ;
125
144
}
126
145
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
+
127
162
// This method takes a slice of slices so that we can accommodate the varying calculations (direct
128
163
// for test vectors, 0... for sign/sign_deterministic, 1... for the pre-hashed version) without
129
164
// having to allocate memory for components.
@@ -156,6 +191,23 @@ impl<P: MlDsaParams> signature::KeypairRef for KeyPair<P> {
156
191
type VerifyingKey = VerifyingKey < P > ;
157
192
}
158
193
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
+
159
211
/// An ML-DSA signing key
160
212
#[ derive( Clone , PartialEq ) ]
161
213
pub struct SigningKey < P : MlDsaParams > {
@@ -384,8 +436,34 @@ impl<P: MlDsaParams> signature::RandomizedSigner<Signature<P>> for SigningKey<P>
384
436
}
385
437
}
386
438
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
+ private_key_info
454
+ . algorithm
455
+ . assert_algorithm_oid ( P :: ALGORITHM_OID ) ?;
456
+
457
+ let seed = Array :: try_from ( private_key_info. private_key . as_bytes ( ) )
458
+ . map_err ( |_| pkcs8:: Error :: KeyMalformed ) ?;
459
+ let keypair = P :: key_gen_internal ( & seed) ;
460
+
461
+ Ok ( keypair. signing_key )
462
+ }
463
+ }
464
+
387
465
/// An ML-DSA verification key
388
- #[ derive( Clone , PartialEq ) ]
466
+ #[ derive( Clone , Debug , PartialEq ) ]
389
467
pub struct VerifyingKey < P : ParameterSet > {
390
468
rho : B32 ,
391
469
t1 : Vector < P :: K > ,
@@ -488,6 +566,49 @@ impl<P: MlDsaParams> signature::Verifier<Signature<P>> for VerifyingKey<P> {
488
566
}
489
567
}
490
568
569
+ impl < P : MlDsaParams > SignatureAlgorithmIdentifier for VerifyingKey < P > {
570
+ type Params = AnyRef < ' static > ;
571
+
572
+ const SIGNATURE_ALGORITHM_IDENTIFIER : AlgorithmIdentifier < Self :: Params > =
573
+ Signature :: < P > :: ALGORITHM_IDENTIFIER ;
574
+ }
575
+
576
+ #[ cfg( feature = "alloc" ) ]
577
+ impl < P : MlDsaParams > EncodePublicKey for VerifyingKey < P > {
578
+ fn to_public_key_der ( & self ) -> spki:: Result < der:: Document > {
579
+ let algorithm_identifier = AlgorithmIdentifierRef {
580
+ oid : P :: ALGORITHM_OID ,
581
+ parameters : None ,
582
+ } ;
583
+
584
+ let public_key = self . encode ( ) ;
585
+ let subject_public_key = BitStringRef :: new ( 0 , & public_key) ?;
586
+
587
+ SubjectPublicKeyInfo {
588
+ algorithm : algorithm_identifier,
589
+ subject_public_key,
590
+ }
591
+ . try_into ( )
592
+ }
593
+ }
594
+
595
+ impl < P : MlDsaParams > TryFrom < SubjectPublicKeyInfoRef < ' _ > > for VerifyingKey < P > {
596
+ type Error = spki:: Error ;
597
+
598
+ fn try_from ( spki : SubjectPublicKeyInfoRef < ' _ > ) -> spki:: Result < Self > {
599
+ spki. algorithm . assert_algorithm_oid ( P :: ALGORITHM_OID ) ?;
600
+
601
+ Ok ( Self :: decode (
602
+ & EncodedVerifyingKey :: < P > :: try_from (
603
+ spki. subject_public_key
604
+ . as_bytes ( )
605
+ . ok_or_else ( || der:: Tag :: BitString . value_error ( ) ) ?,
606
+ )
607
+ . map_err ( |_| pkcs8:: Error :: KeyMalformed ) ?,
608
+ ) )
609
+ }
610
+ }
611
+
491
612
/// `MlDsa44` is the parameter set for security category 2.
492
613
#[ derive( Default , Clone , Debug , PartialEq ) ]
493
614
pub struct MlDsa44 ;
@@ -503,6 +624,7 @@ impl ParameterSet for MlDsa44 {
503
624
type Lambda = U32 ;
504
625
type Omega = U80 ;
505
626
const TAU : usize = 39 ;
627
+ const ALGORITHM_OID : pkcs8:: ObjectIdentifier = fips204:: ID_ML_DSA_44 ;
506
628
}
507
629
508
630
/// `MlDsa65` is the parameter set for security category 3.
@@ -520,6 +642,7 @@ impl ParameterSet for MlDsa65 {
520
642
type Lambda = U48 ;
521
643
type Omega = U55 ;
522
644
const TAU : usize = 49 ;
645
+ const ALGORITHM_OID : pkcs8:: ObjectIdentifier = fips204:: ID_ML_DSA_65 ;
523
646
}
524
647
525
648
/// `MlKem87` is the parameter set for security category 5.
@@ -537,6 +660,7 @@ impl ParameterSet for MlDsa87 {
537
660
type Lambda = U64 ;
538
661
type Omega = U75 ;
539
662
const TAU : usize = 60 ;
663
+ const ALGORITHM_OID : pkcs8:: ObjectIdentifier = fips204:: ID_ML_DSA_87 ;
540
664
}
541
665
542
666
/// A parameter set that knows how to generate key pairs
0 commit comments