From abebea17b0c28cc3489507ffb0b60d8ba3df05dc Mon Sep 17 00:00:00 2001 From: eschorn1 Date: Wed, 16 Oct 2024 15:14:54 -0500 Subject: [PATCH] v0.4.3 RC1 --- CHANGELOG.md | 6 +++--- benches/benchmark.rs | 1 - src/encodings.rs | 2 +- src/hashing.rs | 4 +++- src/lib.rs | 6 ++++-- src/ml_dsa.rs | 32 ++++++++++++++++---------------- src/traits.rs | 31 ++----------------------------- src/types.rs | 28 ++++++++-------------------- 8 files changed, 37 insertions(+), 73 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b45aa33..e10c2a5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,10 +5,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## 0.4.3 (2024-10-XX) +## 0.4.3 (2024-10-16) -- Adapted PrivateKey into PrivateKey and PublicKey into PublicKey, removed the former(s) -- Internal revision to align comments with released spec +- Adapted ExpandedPrivateKey into PrivateKey and ExpandedPublicKey into PublicKey, removed the former(s) +- Internal revision to align comments with released spec; added try_hash_sign (using OS rng) - Revisit/revise supporting benchmarks, embedded target, dudect, fuzz and wasm functionality - Fixed a bug in verify relating to non-empty contexts; asserts on all doctests diff --git a/benches/benchmark.rs b/benches/benchmark.rs index 40b632c..497d041 100644 --- a/benches/benchmark.rs +++ b/benches/benchmark.rs @@ -58,7 +58,6 @@ pub fn criterion_benchmark(c: &mut Criterion) { c.bench_function("ml_dsa_44 pk verify", |b| b.iter(|| pk44.verify(&msg, &sig44, &[]))); c.bench_function("ml_dsa_65 pk verify", |b| b.iter(|| pk65.verify(&msg, &sig65, &[]))); c.bench_function("ml_dsa_87 pk verify", |b| b.iter(|| pk87.verify(&msg, &sig87, &[]))); - } criterion_group!(benches, criterion_benchmark); diff --git a/src/encodings.rs b/src/encodings.rs index 3c40da6..9e44714 100644 --- a/src/encodings.rs +++ b/src/encodings.rs @@ -32,7 +32,7 @@ pub(crate) fn pk_encode( pk[32..] .chunks_mut(32 * blqd) .enumerate() - .take(K) // not strictly needed + .take(K) // not strictly needed .for_each(|(i, chunk)| simple_bit_pack(&t1[i], (1 << blqd) - 1, chunk)); // 5: return pk diff --git a/src/hashing.rs b/src/hashing.rs index 58dc2fe..6394d80 100644 --- a/src/hashing.rs +++ b/src/hashing.rs @@ -298,7 +298,8 @@ pub(crate) fn expand_mask(gamma1: i32, rho: &[u8; 64], mu: u16) xof.read(&mut v); // 5: y[r] ← BitUnpack(v, γ_1 − 1, γ_1) - y[r as usize] = bit_unpack(&v[0..32 * c], gamma1 - 1, gamma1).expect("Alg 34: try_from2 fail"); + y[r as usize] = + bit_unpack(&v[0..32 * c], gamma1 - 1, gamma1).expect("Alg 34: try_from2 fail"); // 6: end for } @@ -312,6 +313,7 @@ pub(crate) fn expand_mask(gamma1: i32, rho: &[u8; 64], mu: u16) y } + /// See for example, Algorithm 4 lines 10-22 pub(crate) fn hash_message(message: &[u8], ph: &Ph, phm: &mut [u8; 64]) -> ([u8; 11], usize) { match ph { diff --git a/src/lib.rs b/src/lib.rs index 30a8c6d..70c377c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,7 +16,9 @@ // TODO Roadmap // 1. Improve docs on first/last few algorithms -// 2. Always more testing... +// 2. Several outstanding refactors (mostly down below in this file) +// 3. Always more testing... + // Implements FIPS 204 Module-Lattice-Based Digital Signature Standard. // See @@ -74,7 +76,7 @@ // Algorithm 49 MontgomeryReduce(a) on page 50 --> helpers.rs // Types are in types.rs, traits are in traits.rs... -// Note that debug! statements enforce correct program construction and are not involved +// Note that debug_assert! statements enforce correct program construction and are not involved // in any operational dataflow (so are good fuzz targets). The ensure! statements implement // conservative dataflow validation. Separately, functions are only generic over security // parameters that are directly involved in memory allocation (on the stack). Some coding diff --git a/src/ml_dsa.rs b/src/ml_dsa.rs index 550669b..638c853 100644 --- a/src/ml_dsa.rs +++ b/src/ml_dsa.rs @@ -1,12 +1,10 @@ // This file implements functionality from FIPS 204 sections 5/6: Key Generation, Signing, Verification -use crate::encodings::{ - pk_decode, pk_encode, sig_decode, sig_encode, sk_decode, w1_encode, -}; +use crate::encodings::{pk_decode, pk_encode, sig_decode, sig_encode, sk_decode, w1_encode}; use crate::hashing::{expand_a, expand_mask, expand_s, h256_xof, sample_in_ball}; use crate::helpers::{ - center_mod, full_reduce32, infinity_norm, mat_vec_mul, mont_reduce, partial_reduce32, to_mont, - add_vector_ntt, + add_vector_ntt, center_mod, full_reduce32, infinity_norm, mat_vec_mul, mont_reduce, + partial_reduce32, to_mont, }; use crate::high_low::{high_bits, low_bits, make_hint, power2round, use_hint}; use crate::ntt::{inv_ntt, ntt}; @@ -33,7 +31,7 @@ pub(crate) fn key_gen< const SK_LEN: usize, >( rng: &mut impl CryptoRngCore, eta: i32, -) -> Result<(PublicKey::, PrivateKey::), &'static str> { +) -> Result<(PublicKey, PrivateKey), &'static str> { // // 1: ξ ← {0,1}^{256} ▷ Choose random seed let mut xi = [0u8; 32]; @@ -258,8 +256,6 @@ pub(crate) fn sign< } - - /// Continuation of `verify_start()`. The `lib.rs` wrapper around this will convert `Error()` to false. #[allow(clippy::too_many_arguments, clippy::similar_names)] pub(crate) fn verify< @@ -270,8 +266,8 @@ pub(crate) fn verify< const SIG_LEN: usize, const W1_LEN: usize, >( - beta: i32, gamma1: i32, gamma2: i32, omega: i32, tau: i32, epk: &PublicKey, - m: &[u8], sig: &[u8; SIG_LEN], ctx: &[u8], oid: &[u8], phm: &[u8], nist: bool, + beta: i32, gamma1: i32, gamma2: i32, omega: i32, tau: i32, epk: &PublicKey, m: &[u8], + sig: &[u8; SIG_LEN], ctx: &[u8], oid: &[u8], phm: &[u8], nist: bool, ) -> Result { // let PublicKey { rho: _, cap_a_hat, tr, t1_d2_hat_mont } = epk; @@ -369,7 +365,7 @@ pub(crate) fn key_gen_internal< const SK_LEN: usize, >( eta: i32, xi: &[u8; 32], -) -> (PublicKey::, PrivateKey) { +) -> (PublicKey, PrivateKey) { // // 1: (rho, rho′, 𝐾) ∈ 𝔹32 × 𝔹64 × 𝔹32 ← H(𝜉||IntegerToBytes(𝑘, 1)||IntegerToBytes(ℓ, 1), 128) let mut h2 = h256_xof(&[xi, &[K.to_le_bytes()[0]], &[L.to_le_bytes()[0]]]); @@ -393,7 +389,8 @@ pub(crate) fn key_gen_internal< let s_1_hat: [T; L] = ntt(&s_1); let as1_hat: [T; K] = mat_vec_mul(&cap_a_hat, &s_1_hat); let t_not_reduced: [R; K] = add_vector_ntt(&inv_ntt(&as1_hat), &s_2); - let t: [R; K] = core::array::from_fn(|k| R(core::array::from_fn(|n| full_reduce32(t_not_reduced[k].0[n])))); + let t: [R; K] = + core::array::from_fn(|k| R(core::array::from_fn(|n| full_reduce32(t_not_reduced[k].0[n])))); // 6: (t_1, t_0) ← Power2Round(t, d) ▷ Compress t let (t_1, t_0): ([R; K], [R; K]) = power2round(&t); @@ -421,7 +418,7 @@ pub(crate) fn key_gen_internal< // 2: s_hat_1 ← NTT(s_1) let s_hat_1_mont: [T; L] = to_mont(&s_1_hat); //ntt(&s_1)); - // 3: s_hat_2 ← NTT(s_2) + // 3: s_hat_2 ← NTT(s_2) let s_hat_2_mont: [T; K] = to_mont(&ntt(&s_2)); // 4: t_hat_0 ← NTT(t_0) let t_hat_0_mont: [T; K] = to_mont(&ntt(&t_0)); @@ -440,13 +437,16 @@ pub(crate) fn key_gen_internal< } - - /// Expand the private/secret key by pre-calculating some constants used in the signing process. /// This is only used in the `try_from_bytes()` deserialization functionality. /// # Errors /// Returns an error on malformed private key. -pub(crate) fn expand_private( +pub(crate) fn expand_private< + const CTEST: bool, + const K: usize, + const L: usize, + const SK_LEN: usize, +>( eta: i32, sk: &[u8; SK_LEN], ) -> Result, &'static str> { // diff --git a/src/traits.rs b/src/traits.rs index c2d9848..869fdf6 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -6,12 +6,6 @@ use rand_core::OsRng; /// The `KeyGen` trait is defined to allow trait objects for keygen. pub trait KeyGen { - // /// A public key specific to the chosen security parameter set, e.g., ml-dsa-44, - // /// ml-dsa-65 or ml-dsa-87 - // type PublicKey; - // /// A private (secret) key specific to the chosen security parameter set, e.g., - // /// ml-dsa-44, ml-dsa-65 or ml-dsa-87 - // type PrivateKey; /// An expanded public key containing precomputed elements to increase (repeated) /// verify performance. Derived from the public key. type PublicKey; @@ -108,28 +102,6 @@ pub trait KeyGen { /// ``` #[must_use] fn keygen_from_seed(xi: &[u8; 32]) -> (Self::PublicKey, Self::PrivateKey); - - - // /// Generates an expanded private key from the normal/compressed private key. - // /// This supports improved signing performance. This function operates in constant-time - // /// relative to secret data (which specifically excludes the provided random `rho` - // /// value as it is stored in the public key). - // /// # Errors - // /// This function operates on trusted data - either a private key directly from `keygen()` - // /// or one validated during deserialization. Nonetheless, a `Result<>` is returned for - // /// symmetry which can propagates internal errors. - // fn gen_expanded_private( - // sk: &Self::PrivateKey, - // ) -> Result; - // - // /// Generates an expanded public key from the normal/compressed public key. - // /// This supports improved verification performance. As this function operates on purely - // /// public data, it need not provide constant-time assurances. - // /// # Errors - // /// This function operates on trusted data - either a public key directly from `keygen()` - // /// or one validated during deserialization. Nonetheless, a `Result<>` is returned for - // /// symmetry which can propagates internal errors. - // fn gen_expanded_public(pk: &Self::PublicKey) -> Result; } @@ -218,7 +190,8 @@ pub trait Signer { /// Will return an error on rng failure #[cfg(feature = "default-rng")] fn try_hash_sign( - &self, message: &[u8], ctx: &[u8], ph: &Ph) -> Result { + &self, message: &[u8], ctx: &[u8], ph: &Ph, + ) -> Result { self.try_hash_sign_with_rng(&mut OsRng, message, ctx, ph) } diff --git a/src/types.rs b/src/types.rs index 401f855..304be1a 100644 --- a/src/types.rs +++ b/src/types.rs @@ -12,16 +12,10 @@ pub enum Ph { } -// /// Correctly sized private key specific to the target security parameter set.
-// /// Implements the [`crate::traits::Signer`] and [`crate::traits::SerDes`] trait. -// #[derive(Clone, Zeroize, ZeroizeOnDrop)] -// #[repr(align(8))] -// pub struct PrivateKey(pub(crate) [u8; SK_LEN]); - - -/// Expanded private key, specific to the target security parameter set, that contains
-/// precomputed elements which increase (repeated) signature performance. Implements only -/// the [`crate::traits::Signer`] trait. +/// Private key specific to the target security parameter set that contains +/// precomputed elements which improve signature performance. +/// +/// Implements the [`crate::traits::Signer`] and [`crate::traits::SerDes`] traits. #[derive(Clone, Zeroize, ZeroizeOnDrop)] #[repr(align(8))] pub struct PrivateKey { @@ -35,16 +29,10 @@ pub struct PrivateKey { } -// /// Correctly sized public key specific to the target security parameter set.
-// /// Implements the [`crate::traits::Verifier`] and [`crate::traits::SerDes`] traits. -// #[derive(Clone, Zeroize, ZeroizeOnDrop)] -// #[repr(align(8))] -// pub struct PublicKey(pub(crate) [u8; PK_LEN]); - - -/// Expanded public key, specific to the target security parameter set, that contains
-/// precomputed elements which increase (repeated) verification performance. Implements only -/// the [`crate::traits::Verifier`] traits. +/// Public key specific to the target security parameter set that contains +/// precomputed elements which improve verification performance. +/// +/// Implements the [`crate::traits::Verifier`] and [`crate::traits::SerDes`] traits. #[derive(Clone, Zeroize, ZeroizeOnDrop)] #[repr(align(8))] pub struct PublicKey {