1#![no_std]
2#![doc = include_str!("../README.md")]
3#![doc(
4 html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg",
5 html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg"
6)]
7#![cfg_attr(docsrs, feature(doc_cfg))]
8#![allow(non_snake_case)] #![allow(clippy::similar_names)] #![allow(clippy::many_single_char_names)] #![allow(clippy::clone_on_copy)] #![cfg_attr(feature = "getrandom", doc = "```")]
29#![cfg_attr(not(feature = "getrandom"), doc = "```ignore")]
30#[cfg(feature = "alloc")]
44extern crate alloc;
45
46#[cfg(feature = "pkcs8")]
47pub mod pkcs8;
48
49mod algebra;
50mod crypto;
51mod encode;
52mod hint;
53mod ntt;
54mod param;
55mod sampling;
56mod signing;
57mod verifying;
58
59pub use crate::{
60 param::{EncodedSignature, EncodedVerifyingKey, ExpandedSigningKeyBytes, MlDsaParams},
61 signing::{ExpandedSigningKey, SigningKey},
62 verifying::VerifyingKey,
63};
64pub use common::{self, KeyExport, KeyInit, KeySizeUser};
65pub use signature::{self, Error, Keypair, SignatureEncoding, Signer, Verifier};
66
67#[cfg(feature = "rand_core")]
68pub use common::Generate;
69
70use crate::{
71 algebra::{AlgebraExt, Vector},
72 crypto::H,
73 hint::Hint,
74 param::{ParameterSet, QMinus1},
75};
76use core::convert::{TryFrom, TryInto};
77use hybrid_array::{
78 Array,
79 sizes::{U1, U2, U4, U5, U6, U7, U8, U17, U19, U32, U48, U55, U64, U75, U80, U88},
80 typenum::{Diff, Length, Prod, Quot, Shleft},
81};
82use module_lattice::{MaybeBox, Truncate};
83use shake::Shake256;
84
85pub type B32 = Array<u8, U32>;
87
88pub(crate) type B64 = Array<u8, U64>;
90
91pub type Seed = B32;
94
95#[derive(Clone, Debug, PartialEq)]
97pub struct Signature<P: MlDsaParams> {
98 c_tilde: Array<u8, P::Lambda>,
99 z: MaybeBox<Vector<P::L>>,
100 h: Hint<P>,
101}
102
103impl<P: MlDsaParams> Signature<P> {
104 pub fn encode(&self) -> EncodedSignature<P> {
107 let c_tilde = self.c_tilde.clone();
108 let z = P::encode_z(&self.z);
109 let h = self.h.bit_pack();
110 P::concat_sig(c_tilde, z, h)
111 }
112
113 pub fn decode(enc: &EncodedSignature<P>) -> Option<Self> {
116 let (c_tilde, z, h) = P::split_sig(enc);
117
118 let c_tilde = c_tilde.clone();
119 let z = MaybeBox::new(P::decode_z(z));
120 let h = Hint::bit_unpack(h)?;
121
122 if z.infinity_norm() >= P::GAMMA1_MINUS_BETA {
123 return None;
124 }
125
126 Some(Self { c_tilde, z, h })
127 }
128
129 pub fn c_tilde(&self) -> &Array<u8, P::Lambda> {
131 &self.c_tilde
132 }
133}
134
135impl<'a, P: MlDsaParams> TryFrom<&'a [u8]> for Signature<P> {
136 type Error = Error;
137
138 fn try_from(value: &'a [u8]) -> Result<Self, Self::Error> {
139 let enc = EncodedSignature::<P>::try_from(value).map_err(|_| Error::new())?;
140 Self::decode(&enc).ok_or(Error::new())
141 }
142}
143
144impl<P: MlDsaParams> TryInto<EncodedSignature<P>> for Signature<P> {
145 type Error = Error;
146
147 fn try_into(self) -> Result<EncodedSignature<P>, Self::Error> {
148 Ok(self.encode())
149 }
150}
151
152impl<P: MlDsaParams> SignatureEncoding for Signature<P> {
153 type Repr = EncodedSignature<P>;
154}
155
156impl<P: MlDsaParams> core::hash::Hash for Signature<P> {
157 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
158 self.encode().hash(state);
159 }
160}
161
162struct MuBuilder(H);
163
164impl MuBuilder {
165 fn new(tr: &[u8], ctx: &[u8]) -> Self {
166 let mut h = H::default();
167 h = h.absorb(tr);
168 h = h.absorb(&[0]);
169 h = h.absorb(&[Truncate::truncate(ctx.len())]);
170 h = h.absorb(ctx);
171
172 Self(h)
173 }
174
175 fn internal(tr: &[u8], Mp: &[&[u8]]) -> B64 {
176 let mut h = H::default().absorb(tr);
177
178 for m in Mp {
179 h = h.absorb(m);
180 }
181
182 h.squeeze_new()
183 }
184
185 fn message(mut self, M: &[&[u8]]) -> B64 {
186 for m in M {
187 self.0 = self.0.absorb(m);
188 }
189
190 self.0.squeeze_new()
191 }
192
193 fn finish(mut self) -> B64 {
194 self.0.squeeze_new()
195 }
196}
197
198impl AsMut<Shake256> for MuBuilder {
199 fn as_mut(&mut self) -> &mut Shake256 {
200 self.0.updatable()
201 }
202}
203
204#[derive(Clone, Copy, Debug, Default, PartialEq)]
207pub struct MlDsa44;
208
209impl ParameterSet for MlDsa44 {
210 type K = U4;
211 type L = U4;
212 type Eta = U2;
213 type Gamma1 = Shleft<U1, U17>;
214 type Gamma2 = Quot<QMinus1, U88>;
215 type TwoGamma2 = Prod<U2, Self::Gamma2>;
216 type W1Bits = Length<Diff<Quot<U88, U2>, U1>>;
217 type Lambda = U32;
218 type Omega = U80;
219 const TAU: usize = 39;
220}
221
222#[derive(Clone, Copy, Debug, Default, PartialEq)]
227pub struct MlDsa65;
228
229impl ParameterSet for MlDsa65 {
230 type K = U6;
231 type L = U5;
232 type Eta = U4;
233 type Gamma1 = Shleft<U1, U19>;
234 type Gamma2 = Quot<QMinus1, U32>;
235 type TwoGamma2 = Prod<U2, Self::Gamma2>;
236 type W1Bits = Length<Diff<Quot<U32, U2>, U1>>;
237 type Lambda = U48;
238 type Omega = U55;
239 const TAU: usize = 49;
240}
241
242#[derive(Clone, Copy, Debug, Default, PartialEq)]
245pub struct MlDsa87;
246
247impl ParameterSet for MlDsa87 {
248 type K = U8;
249 type L = U7;
250 type Eta = U2;
251 type Gamma1 = Shleft<U1, U19>;
252 type Gamma2 = Quot<QMinus1, U32>;
253 type TwoGamma2 = Prod<U2, Self::Gamma2>;
254 type W1Bits = Length<Diff<Quot<U32, U2>, U1>>;
255 type Lambda = U64;
256 type Omega = U75;
257 const TAU: usize = 60;
258}
259
260#[cfg(test)]
261mod test {
262 use super::*;
263 use crate::param::*;
264 use hybrid_array::typenum::Unsigned;
265 use signature::{Keypair, digest::Update};
266
267 #[test]
268 fn output_sizes() {
269 assert_eq!(SigningKeySize::<MlDsa44>::USIZE, 2560);
274 assert_eq!(VerifyingKeySize::<MlDsa44>::USIZE, 1312);
275 assert_eq!(SignatureSize::<MlDsa44>::USIZE, 2420);
276
277 assert_eq!(SigningKeySize::<MlDsa65>::USIZE, 4032);
278 assert_eq!(VerifyingKeySize::<MlDsa65>::USIZE, 1952);
279 assert_eq!(SignatureSize::<MlDsa65>::USIZE, 3309);
280
281 assert_eq!(SigningKeySize::<MlDsa87>::USIZE, 4896);
282 assert_eq!(VerifyingKeySize::<MlDsa87>::USIZE, 2592);
283 assert_eq!(SignatureSize::<MlDsa87>::USIZE, 4627);
284 }
285
286 fn encode_decode_round_trip_test<P>()
287 where
288 P: MlDsaParams + PartialEq,
289 {
290 let seed = Array::default();
291 let ssk = SigningKey::from_seed(&seed);
292 assert_eq!(ssk.to_seed(), seed);
293
294 let esk = ssk.expanded_key();
295 let vk = ssk.verifying_key();
296
297 let vk_bytes = vk.encode();
298 let vk2 = VerifyingKey::<P>::decode(&vk_bytes);
299 assert!(vk == vk2);
300
301 #[allow(deprecated)]
302 {
303 let sk_bytes = esk.to_expanded();
304 let sk2 = ExpandedSigningKey::<P>::from_expanded(&sk_bytes);
305 assert!(esk == &sk2);
306
307 let M = b"Hello world";
308 let rnd = Array([0u8; 32]);
309 let sig = esk.sign_internal(&[M], &rnd);
310 let sig_bytes = sig.encode();
311 let sig2 = Signature::<P>::decode(&sig_bytes).unwrap();
312 assert!(sig == sig2);
313 }
314 }
315
316 #[test]
317 fn encode_decode_round_trip() {
318 encode_decode_round_trip_test::<MlDsa44>();
319 encode_decode_round_trip_test::<MlDsa65>();
320 encode_decode_round_trip_test::<MlDsa87>();
321 }
322
323 fn public_from_private_test<P>()
324 where
325 P: MlDsaParams + PartialEq,
326 {
327 let ssk = SigningKey::<P>::from_seed(&Array::default());
328 let esk = ssk.expanded_key();
329 let vk = ssk.verifying_key();
330 let vk_derived = esk.verifying_key();
331
332 assert!(vk == vk_derived);
333 }
334
335 #[test]
336 fn public_from_private() {
337 public_from_private_test::<MlDsa44>();
338 public_from_private_test::<MlDsa65>();
339 public_from_private_test::<MlDsa87>();
340 }
341
342 fn sign_verify_round_trip_test<P>()
343 where
344 P: MlDsaParams,
345 {
346 let ssk = SigningKey::<P>::from_seed(&Array::default());
347 let esk = ssk.expanded_key();
348 let vk = ssk.verifying_key();
349
350 let M = b"Hello world";
351 let rnd = Array([0u8; 32]);
352 let sig = esk.sign_internal(&[M], &rnd);
353
354 assert!(vk.verify_internal(M, &sig));
355 }
356
357 #[test]
358 fn sign_verify_round_trip() {
359 sign_verify_round_trip_test::<MlDsa44>();
360 sign_verify_round_trip_test::<MlDsa65>();
361 sign_verify_round_trip_test::<MlDsa87>();
362 }
363
364 #[test]
365 fn sign_mu_verify_mu_round_trip() {
366 fn sign_mu_verify_mu<P>()
367 where
368 P: MlDsaParams,
369 {
370 let ssk = SigningKey::<P>::from_seed(&Array::default());
371 let esk = ssk.expanded_key();
372 let vk = ssk.verifying_key();
373
374 let M = b"Hello world";
375 let rnd = Array([0u8; 32]);
376 let mu = MuBuilder::internal(&esk.tr, &[M]);
377 let sig = esk.raw_sign_mu(&mu, &rnd);
378
379 assert!(vk.raw_verify_mu(&mu, &sig));
380 }
381 sign_mu_verify_mu::<MlDsa44>();
382 sign_mu_verify_mu::<MlDsa65>();
383 sign_mu_verify_mu::<MlDsa87>();
384 }
385
386 #[test]
387 fn sign_mu_verify_internal_round_trip() {
388 fn sign_mu_verify_internal<P>()
389 where
390 P: MlDsaParams,
391 {
392 let ssk = SigningKey::<P>::from_seed(&Array::default());
393 let esk = ssk.expanded_key();
394 let vk = ssk.verifying_key();
395
396 let M = b"Hello world";
397 let rnd = Array([0u8; 32]);
398 let mu = MuBuilder::internal(&esk.tr, &[M]);
399 let sig = esk.raw_sign_mu(&mu, &rnd);
400
401 assert!(vk.verify_internal(M, &sig));
402 }
403 sign_mu_verify_internal::<MlDsa44>();
404 sign_mu_verify_internal::<MlDsa65>();
405 sign_mu_verify_internal::<MlDsa87>();
406 }
407
408 #[test]
409 fn sign_internal_verify_mu_round_trip() {
410 fn sign_internal_verify_mu<P>()
411 where
412 P: MlDsaParams,
413 {
414 let ssk = SigningKey::<P>::from_seed(&Array::default());
415 let esk = ssk.expanded_key();
416 let vk = ssk.verifying_key();
417
418 let M = b"Hello world";
419 let rnd = Array([0u8; 32]);
420 let mu = MuBuilder::internal(&esk.tr, &[M]);
421 let sig = esk.sign_internal(&[M], &rnd);
422
423 assert!(vk.raw_verify_mu(&mu, &sig));
424 }
425 sign_internal_verify_mu::<MlDsa44>();
426 sign_internal_verify_mu::<MlDsa65>();
427 sign_internal_verify_mu::<MlDsa87>();
428 }
429
430 #[test]
431 fn from_seed_implementations_match() {
432 fn assert_from_seed_equality<P>()
433 where
434 P: MlDsaParams,
435 {
436 let seed = Seed::default();
437 let ssk = SigningKey::<P>::from_seed(&seed);
438 let sk1 = ExpandedSigningKey::<P>::from_seed(&seed);
439 assert_eq!(ssk.expanded_key(), &sk1);
440 }
441 assert_from_seed_equality::<MlDsa44>();
442 assert_from_seed_equality::<MlDsa65>();
443 assert_from_seed_equality::<MlDsa87>();
444 }
445
446 #[test]
447 fn to_seed_returns_correct_seed() {
448 fn test_to_seed<P: MlDsaParams>() {
449 let seed = Array([
450 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
451 24, 25, 26, 27, 28, 29, 30, 31, 32,
452 ]);
453 let kp = SigningKey::<P>::from_seed(&seed);
454 assert_eq!(kp.to_seed(), seed);
455 }
456 test_to_seed::<MlDsa44>();
457 test_to_seed::<MlDsa65>();
458 test_to_seed::<MlDsa87>();
459 }
460
461 #[test]
462 fn verification_rejects_invalid_signature() {
463 fn test_invalid_sig<P: MlDsaParams>() {
464 let kp = SigningKey::<P>::from_seed(&Array::default());
465 let vk = kp.verifying_key();
466
467 let msg = b"Hello world";
468 let rnd = Array([0u8; 32]);
469 let mut sig = kp.expanded_key().sign_internal(&[msg], &rnd);
470 sig.c_tilde[0] ^= 0xFF;
471
472 assert!(!vk.verify_with_context(msg, &[], &sig));
473 }
474 test_invalid_sig::<MlDsa44>();
475 test_invalid_sig::<MlDsa65>();
476 test_invalid_sig::<MlDsa87>();
477 }
478
479 #[test]
480 fn verification_rejects_wrong_message() {
481 fn test_wrong_msg<P: MlDsaParams>() {
482 let kp = SigningKey::<P>::from_seed(&Array::default());
483 let vk = kp.verifying_key();
484
485 let msg1 = b"Hello world";
486 let msg2 = b"Wrong message";
487 let rnd = Array([0u8; 32]);
488 let sig = kp.expanded_key().sign_internal(&[msg1], &rnd);
489
490 assert!(!vk.verify_with_context(msg2, &[], &sig));
491 }
492 test_wrong_msg::<MlDsa44>();
493 test_wrong_msg::<MlDsa65>();
494 test_wrong_msg::<MlDsa87>();
495 }
496
497 #[test]
498 fn context_length_validation() {
499 fn test_ctx_length<P: MlDsaParams>() {
500 let ssk = SigningKey::<P>::from_seed(&Array::default());
501 let sk = ssk.expanded_key();
502 let vk = ssk.verifying_key();
503
504 let msg = b"Hello world";
505 let long_ctx = [0u8; 256];
506 let short_ctx = [0u8; 255];
507
508 assert!(sk.sign_deterministic(msg, &long_ctx).is_err());
509
510 let sig = sk.sign_deterministic(msg, &short_ctx).unwrap();
511 assert!(!vk.verify_with_context(msg, &long_ctx, &sig));
512 assert!(vk.verify_with_context(msg, &short_ctx, &sig));
513
514 assert!(
515 vk.compute_mu(
516 |_| panic!("oversized context must be rejected before invoking the callback"),
517 &long_ctx,
518 )
519 .is_err()
520 );
521
522 let mu = vk
523 .compute_mu(
524 |h| {
525 h.update(msg);
526 Ok(())
527 },
528 &short_ctx,
529 )
530 .unwrap();
531 assert!(vk.verify_mu(&mu, &sig));
532 assert_eq!(sk.sign_mu_deterministic(&mu).encode(), sig.encode());
533 }
534 test_ctx_length::<MlDsa44>();
535 test_ctx_length::<MlDsa65>();
536 test_ctx_length::<MlDsa87>();
537 }
538
539 #[test]
540 fn derived_verifying_key_validates_signatures() {
541 fn test_derived_vk<P: MlDsaParams>() {
542 let seed = Array([42u8; 32]);
543 let ssk = SigningKey::<P>::from_seed(&seed);
544 let sk = ssk.expanded_key();
545 let derived_vk = sk.verifying_key();
546
547 let msg = b"Test message for derived key";
548 let rnd = Array([0u8; 32]);
549 let sig = sk.sign_internal(&[msg], &rnd);
550
551 assert!(derived_vk.verify_internal(msg, &sig));
552 assert_eq!(derived_vk.encode(), ssk.verifying_key().encode());
553 }
554 test_derived_vk::<MlDsa44>();
555 test_derived_vk::<MlDsa65>();
556 test_derived_vk::<MlDsa87>();
557 }
558
559 #[test]
560 #[cfg(feature = "alloc")]
561 fn debug_implementations() {
562 extern crate alloc;
563 use core::fmt::Write;
564
565 fn test_debug<P: MlDsaParams>() {
566 let kp = SigningKey::<P>::from_seed(&Array::default());
567
568 let mut kp_debug = alloc::string::String::new();
569 write!(&mut kp_debug, "{:?}", kp).unwrap();
570 assert!(kp_debug.contains("SigningKey"));
571
572 let mut sk_debug = alloc::string::String::new();
573 write!(&mut sk_debug, "{:?}", kp.expanded_key()).unwrap();
574 assert!(sk_debug.contains("ExpandedSigningKey"));
575 }
576 test_debug::<MlDsa44>();
577 test_debug::<MlDsa65>();
578 test_debug::<MlDsa87>();
579 }
580}