diff --git a/crypto/mldsa-lowmemory/src/lib.rs b/crypto/mldsa-lowmemory/src/lib.rs index 966f32ef..02b03d40 100644 --- a/crypto/mldsa-lowmemory/src/lib.rs +++ b/crypto/mldsa-lowmemory/src/lib.rs @@ -266,6 +266,3 @@ pub use mldsa::{MLDSA65_PK_LEN, MLDSA65_SIG_LEN, MLDSA65_SK_LEN}; pub use mldsa::{MLDSA87_PK_LEN, MLDSA87_SIG_LEN, MLDSA87_SK_LEN}; pub use mldsa::SUSPENDED_MU_BUILDER_STATE_LEN; - -// re-export just so it's visible to unit tests -pub use polynomial::Polynomial; diff --git a/crypto/mldsa-lowmemory/src/polynomial.rs b/crypto/mldsa-lowmemory/src/polynomial.rs index 95e3387b..51e81ea4 100644 --- a/crypto/mldsa-lowmemory/src/polynomial.rs +++ b/crypto/mldsa-lowmemory/src/polynomial.rs @@ -6,19 +6,13 @@ use core::ops::{Index, IndexMut}; /// A polynomial over the ML-DSA ring. /// -/// Dev note: The following structure does not necessarily need to be declared as public. -/// There is no real scenario where this function needs to be called directly. -/// However, in order to test the Debug and Display traits, it is necessary to use STD, so those -/// can't be tested from inline tests in this file and the real unit tests are in a different crate. -/// That's the reason why pub is used. -/// /// # 🚨 Security 🚨 /// Polynomials themselves are not inherently secret since sometimes they are part of public keys /// and sometimes private keys. /// It is the responsibility of the caller to wrap sensitive instances in `Secret`. /// Note: at the moment, nothing in this crate uses `Secret`, so I have left the `impl ZeroizablePrimitive` commented-out. #[derive(Clone, Copy)] -pub struct Polynomial { +pub(crate) struct Polynomial { pub(crate) coeffs: [i32; N], } diff --git a/crypto/mldsa/src/aux_functions.rs b/crypto/mldsa/src/aux_functions.rs index c35dc609..9eadbb89 100644 --- a/crypto/mldsa/src/aux_functions.rs +++ b/crypto/mldsa/src/aux_functions.rs @@ -407,7 +407,7 @@ pub(crate) fn sig_encode< for i in 0..l { output[pos..pos + POLY_Z_PACKED_LEN] - .copy_from_slice(&bitpack_gamma1::(&z.vec[i])); + .copy_from_slice(&bitpack_gamma1::(&z.elems[i])); pos += POLY_Z_PACKED_LEN; } @@ -416,7 +416,7 @@ pub(crate) fn sig_encode< let mut m: usize = 0; for i in 0..k { for j in 0..N { - if h.vec[i][j] != 0 { + if h.elems[i][j] != 0 { output[pos + m] = j as u8; m += 1; } @@ -453,7 +453,7 @@ pub(crate) fn sig_decode< pos += LAMBDA_over_4; for i in 0..l { - z.vec[i] = bit_unpack_gamma1::(&sig[pos..pos + POLY_Z_PACKED_LEN]); + z.elems[i] = bit_unpack_gamma1::(&sig[pos..pos + POLY_Z_PACKED_LEN]); pos += POLY_Z_PACKED_LEN; } @@ -486,7 +486,7 @@ pub(crate) fn sig_decode< return Err(()); } // 12: 𝐡[𝑖]_𝑦[Index] ← 1 - h.vec[i][sig[pos + j] as usize] = 1; + h.elems[i][sig[pos + j] as usize] = 1; // 13: Index ← Index + 1 // > done by for loop @@ -672,7 +672,7 @@ pub(crate) fn expandA(rho: &[u8; 32]) -> Matrix< for r in 0..k { for s in 0..l { - A_hat[r][s] = rej_ntt_poly(rho, &[s as u8, r as u8]); + A_hat.elems[r][s] = rej_ntt_poly(rho, &[s as u8, r as u8]); } } @@ -692,11 +692,11 @@ pub(crate) fn expandS( let mut s2: Secret> = Secret::new(); for r in 0..l { - s1.vec[r] = rej_bounded_poly::(rho, &(r as u16).to_le_bytes()); + s1.elems[r] = rej_bounded_poly::(rho, &(r as u16).to_le_bytes()); } for r in 0..k { - s2.vec[r] = rej_bounded_poly::(rho, &(r as u16 + l as u16).to_le_bytes()); + s2.elems[r] = rej_bounded_poly::(rho, &(r as u16 + l as u16).to_le_bytes()); } (s1, s2) @@ -710,7 +710,7 @@ pub(crate) fn power_2_round_vec(v: &Vector) -> (Vector(&v); + y.elems[r] = bit_unpack_gamma1::(&v); } y @@ -881,8 +881,8 @@ pub(crate) fn make_hint_vecs( let mut count = 0i32; for i in 0..k { - let (w, c) = r.vec[i].make_hint::(&s.vec[i]); - out.vec[i] = w; + let (w, c) = r.elems[i].make_hint::(&s.elems[i]); + out.elems[i] = w; // mutants note: this chains up to hint_hamming_weight > OMEGA and there is no test KAT that triggers this branch count += c; @@ -942,7 +942,7 @@ pub(crate) fn use_hint_vecs( ) -> Vector { let mut out = Vector::::new(); for i in 0..k { - use_hint_polys::(&wp_approx.vec[i], &h.vec[i], &mut out.vec[i]); + use_hint_polys::(&wp_approx.elems[i], &h.elems[i], &mut out.elems[i]); } out diff --git a/crypto/mldsa/src/lib.rs b/crypto/mldsa/src/lib.rs index 15fa7408..2bea9873 100644 --- a/crypto/mldsa/src/lib.rs +++ b/crypto/mldsa/src/lib.rs @@ -188,6 +188,3 @@ pub use mldsa::{MLDSA87_PK_LEN, MLDSA87_SIG_LEN, MLDSA87_SK_LEN}; pub use mldsa::SUSPENDED_MU_BUILDER_STATE_LEN; pub use matrix::Matrix; - -// re-export just so it's visible to unit tests -pub use polynomial::Polynomial; diff --git a/crypto/mldsa/src/matrix.rs b/crypto/mldsa/src/matrix.rs index bbb3b7ca..916fe47d 100644 --- a/crypto/mldsa/src/matrix.rs +++ b/crypto/mldsa/src/matrix.rs @@ -10,26 +10,14 @@ use core::ops::{Index, IndexMut}; /// A matrix over the ML-DSA ring. #[derive(Clone)] -pub struct Matrix(/*pub(crate)*/ [[Polynomial; l]; k]); - -/// Convenience function to avoid ".0" all over the place. -impl Index for Matrix { - type Output = [Polynomial; l]; - - fn index(&self, index: usize) -> &Self::Output { - &self.0[index] - } -} -/// Convenience function to avoid ".0" all over the place. -impl IndexMut for Matrix { - fn index_mut(&mut self, index: usize) -> &mut Self::Output { - &mut self.0[index] - } +pub struct Matrix { + /// Indexed `elems[row][col]` + pub(crate) elems: [[Polynomial; l]; k], } impl Matrix { pub(crate) fn new() -> Self { - Self { 0: [[(); l]; k].map(|_| [(); l].map(|_| Polynomial::new())) } + Self { elems: [[(); l]; k].map(|_| [(); l].map(|_| Polynomial::new())) } } /// Algorithm 48 MatrixVectorNTT(𝐌, 𝐯) @@ -39,18 +27,18 @@ impl Matrix { /// Performs dot product multiplication of this matrix by a vector /// Input: vector of length l /// Output: vector of length k - pub fn matrix_vector_ntt(&self, v: &Vector) -> Vector { + pub(crate) fn matrix_vector_ntt(&self, v: &Vector) -> Vector { let mut w = Vector::::new(); for i in 0..k { // split out the 0 case to skip a no-op add_ntt() - w[i].coeffs.copy_from_slice(&multiply_ntt(&self[i][0], &v[0]).coeffs); + w[i].coeffs.copy_from_slice(&multiply_ntt(&self.elems[i][0], &v[0]).coeffs); let mut w1: Polynomial; for j in 1..l { // dot product a vector into a matrix: multiply the input vector // into each row of the matrix, then sum the results to produce a vector of // length k. - w1 = multiply_ntt(&self[i][j], &v[j]); + w1 = multiply_ntt(&self.elems[i][j], &v[j]); w[i].add_ntt(&w1); } } @@ -61,7 +49,7 @@ impl Matrix { #[derive(Clone, Copy)] pub(crate) struct Vector { - pub(crate) vec: [Polynomial; LEN], + pub(crate) elems: [Polynomial; LEN], } /// Convenience function to avoid ".0" all over the place. @@ -69,13 +57,13 @@ impl Index for Vector { type Output = Polynomial; fn index(&self, index: usize) -> &Self::Output { - &self.vec[index] + &self.elems[index] } } /// Convenience function to avoid ".0" all over the place. impl IndexMut for Vector { fn index_mut(&mut self, index: usize) -> &mut Self::Output { - &mut self.vec[index] + &mut self.elems[index] } } @@ -85,7 +73,7 @@ impl ZeroizablePrimitive for Vector { impl Vector { pub(crate) const fn new() -> Self { - Self { vec: [Polynomial::new(); LEN] } + Self { elems: [Polynomial::new(); LEN] } } /// Algorithm 46 AddVectorNTT(𝐯, 𝐰)̂ @@ -176,7 +164,7 @@ impl Vector { pub(crate) fn check_norm(&self) -> bool { // Fine that this is not constant-time because it is used in a rejection loop -- the early quit leads to rejection. - for x in self.vec.iter() { + for x in self.elems.iter() { if x.check_norm::() { return true; } @@ -196,7 +184,7 @@ impl Vector { // 2: for 𝑖 from 0 to 𝑘 − 1 do // 3: 𝐰̃1 ← 𝐰̃1 || SimpleBitPack (𝐰1[𝑖], (𝑞 − 1)/(2𝛾2) − 1) // 4: end for - for w in self.vec.iter() { + for w in self.elems.iter() { h.absorb(&w.w1_encode::()) .expect("absorb before squeeze is infallible"); } diff --git a/crypto/mldsa/src/mldsa_keys.rs b/crypto/mldsa/src/mldsa_keys.rs index b3c84d6f..456a26c8 100644 --- a/crypto/mldsa/src/mldsa_keys.rs +++ b/crypto/mldsa/src/mldsa_keys.rs @@ -105,7 +105,7 @@ impl MLDSAPublicKey MLDSAPublicKeyTrait(&sk_chunk).coeffs); @@ -650,7 +650,7 @@ impl(&sk_chunk).coeffs); @@ -675,7 +675,7 @@ impl`. #[derive(Clone, Copy)] -pub struct Polynomial { +pub(crate) struct Polynomial { pub(crate) coeffs: [i32; N], } diff --git a/crypto/mlkem-lowmemory/src/lib.rs b/crypto/mlkem-lowmemory/src/lib.rs index ae933459..250c9ea6 100644 --- a/crypto/mlkem-lowmemory/src/lib.rs +++ b/crypto/mlkem-lowmemory/src/lib.rs @@ -264,6 +264,3 @@ pub use mlkem::{MLKEM_RND_LEN, MLKEM_SEED_LEN, MLKEM_SS_LEN}; pub use mlkem::{MLKEM512_CT_LEN, MLKEM512_PK_LEN, MLKEM512_SK_LEN}; pub use mlkem::{MLKEM768_CT_LEN, MLKEM768_PK_LEN, MLKEM768_SK_LEN}; pub use mlkem::{MLKEM1024_CT_LEN, MLKEM1024_PK_LEN, MLKEM1024_SK_LEN}; - -// re-export just so it is visible to unit tests -pub use polynomial::Polynomial; diff --git a/crypto/mlkem-lowmemory/src/polynomial.rs b/crypto/mlkem-lowmemory/src/polynomial.rs index 28d7bbc7..20684c02 100644 --- a/crypto/mlkem-lowmemory/src/polynomial.rs +++ b/crypto/mlkem-lowmemory/src/polynomial.rs @@ -7,9 +7,6 @@ use crate::mlkem::{N, q}; use core::ops::{Index, IndexMut}; /// A polynomial over the ML-KEM ring. -/// Dev note: this doesn't strictly need to be pub ... ie there's no good reason for a caller to use this class directly, -/// but in order to test the Debug and Display traits, you need STD, so those can't be tested from inline tests in this file -/// and the real unit tests are in a different crate, so here we are. /// /// # 🚨 Security 🚨 /// Polynomials themselves are not inherently secret since sometimes they are part of public keys @@ -17,7 +14,7 @@ use core::ops::{Index, IndexMut}; /// It is the responsibility of the caller to wrap sensitive instances in `Secret`. /// Note: at the moment, nothing in this crate uses `Secret`, so I have left the `impl ZeroizablePrimitive` commented-out. #[derive(Clone, Copy)] -pub struct Polynomial { +pub(crate) struct Polynomial { pub(crate) coeffs: [i16; N], } diff --git a/crypto/mlkem/src/aux_functions.rs b/crypto/mlkem/src/aux_functions.rs index 09998374..dbd71e0f 100644 --- a/crypto/mlkem/src/aux_functions.rs +++ b/crypto/mlkem/src/aux_functions.rs @@ -1,8 +1,8 @@ //! Implements auxiliary functions for ML-DSA as defined in Section 7 of FIPS 204. -use crate::matrix::Vector; +use crate::matrix::{Matrix, Vector}; use crate::mlkem::{N, q, q_inv}; -use crate::{Matrix, Polynomial}; +use crate::polynomial::Polynomial; use bouncycastle_core::traits::XOF; use bouncycastle_sha3::{SHAKE128, SHAKE256}; @@ -13,7 +13,7 @@ pub(crate) fn expandA(rho: &[u8; 32]) -> Matrix { for j in 0..k { // 6: 𝐀[𝑖, 𝑗] ← SampleNTT(𝜌‖𝑗‖𝑖) // ▷ 𝑗 and 𝑖 are bytes 33 and 34 of the input - A_hat[i][j] = sample_ntt(rho, &[j as u8, i as u8]); + A_hat.elems[i][j] = sample_ntt(rho, &[j as u8, i as u8]); } } diff --git a/crypto/mlkem/src/lib.rs b/crypto/mlkem/src/lib.rs index 0dbbb449..cfd91c3f 100644 --- a/crypto/mlkem/src/lib.rs +++ b/crypto/mlkem/src/lib.rs @@ -153,11 +153,11 @@ #[allow(unused_imports)] use bouncycastle_core::key_material::KeyMaterialTrait; -pub mod aux_functions; +mod aux_functions; mod matrix; pub mod mlkem; mod mlkem_keys; -pub mod polynomial; +mod polynomial; /*** Exported types ***/ pub use mlkem::{MLKEM, MLKEM512, MLKEM768, MLKEM1024, MLKEMTrait}; @@ -187,6 +187,3 @@ pub use mlkem::{MLKEM768_CT_LEN, MLKEM768_PK_LEN, MLKEM768_SK_LEN}; pub use mlkem::{MLKEM1024_CT_LEN, MLKEM1024_PK_LEN, MLKEM1024_SK_LEN}; pub use matrix::Matrix; - -// re-export just so it's visible to unit tests -pub use polynomial::Polynomial; diff --git a/crypto/mlkem/src/matrix.rs b/crypto/mlkem/src/matrix.rs index de2cddc9..93356585 100644 --- a/crypto/mlkem/src/matrix.rs +++ b/crypto/mlkem/src/matrix.rs @@ -11,27 +11,13 @@ use bouncycastle_utils::secret::ZeroizablePrimitive; #[derive(Clone)] /// A matrix over the ML-KEM ring. pub struct Matrix { - /*pub(crate)*/ mat: [[Polynomial; l]; k], -} - -/// Convenience function to avoid ".0" all over the place. -impl Index for Matrix { - type Output = [Polynomial; l]; - - fn index(&self, index: usize) -> &Self::Output { - &self.mat[index] - } -} -/// Convenience function to avoid ".0" all over the place. -impl IndexMut for Matrix { - fn index_mut(&mut self, index: usize) -> &mut Self::Output { - &mut self.mat[index] - } + /// Indexed `elems[row][col]` + pub(crate) elems: [[Polynomial; l]; k], } impl Matrix { pub(crate) fn new() -> Self { - Self { mat: [[(); l]; k].map(|_| [(); l].map(|_| Polynomial::new())) } + Self { elems: [[(); l]; k].map(|_| [(); l].map(|_| Polynomial::new())) } } /// FIPS 204 Algorithm 48 MatrixVectorNTT(𝐌, 𝐯) @@ -41,15 +27,15 @@ impl Matrix { /// Input: vector of length l /// Output: vector of length k /// - /// transpose: False will multiply A, where as True will multiply A^T + /// `transpose`: False will multiply A, where as True will multiply A^T pub(crate) fn matrix_vector_ntt(&self, v: &Vector) -> Vector { let mut w = Vector::::new(); for i in 0..k { // split out the 0 case to skip a no-op add_ntt() w[i] = if transpose { - polynomial::base_mult_montgomery(&self.mat[0][i], &v[0]) + polynomial::base_mult_montgomery(&self.elems[0][i], &v[0]) } else { - polynomial::base_mult_montgomery(&self.mat[i][0], &v[0]) + polynomial::base_mult_montgomery(&self.elems[i][0], &v[0]) }; let mut w1: Polynomial; @@ -58,9 +44,9 @@ impl Matrix { // into each row of the matrix, then sum the results to produce a vector of // length k. w1 = if transpose { - polynomial::base_mult_montgomery(&self.mat[j][i], &v[j]) + polynomial::base_mult_montgomery(&self.elems[j][i], &v[j]) } else { - polynomial::base_mult_montgomery(&self.mat[i][j], &v[j]) + polynomial::base_mult_montgomery(&self.elems[i][j], &v[j]) }; w[i].add(&w1); @@ -80,7 +66,7 @@ impl Matrix { #[derive(Clone, Copy)] pub(crate) struct Vector { - pub(crate) vec: [Polynomial; k], + pub(crate) elems: [Polynomial; k], } /// Convenience function to avoid ".0" all over the place. @@ -88,13 +74,13 @@ impl Index for Vector { type Output = Polynomial; fn index(&self, index: usize) -> &Self::Output { - &self.vec[index] + &self.elems[index] } } /// Convenience function to avoid ".0" all over the place. impl IndexMut for Vector { fn index_mut(&mut self, index: usize) -> &mut Self::Output { - &mut self.vec[index] + &mut self.elems[index] } } @@ -104,7 +90,7 @@ impl ZeroizablePrimitive for Vector { impl Vector { pub(crate) const fn new() -> Self { - Self { vec: [Polynomial::new(); k] } + Self { elems: [Polynomial::new(); k] } } /// Algorithm 46 AddVectorNTT(𝐯, 𝐰)̂ diff --git a/crypto/mlkem/src/mlkem_keys.rs b/crypto/mlkem/src/mlkem_keys.rs index 63398f29..8fd2bb8a 100644 --- a/crypto/mlkem/src/mlkem_keys.rs +++ b/crypto/mlkem/src/mlkem_keys.rs @@ -118,7 +118,7 @@ impl MLKEMPublicKeyTrait let t_hat = { let mut t_hat = Vector::::new(); - for (t_i, pk_chunk) in t_hat.vec.iter_mut().zip(pk_chunks) { + for (t_i, pk_chunk) in t_hat.elems.iter_mut().zip(pk_chunks) { t_i.coeffs.copy_from_slice(&byte_decode::<12, POLY_BYTES>(pk_chunk).coeffs); // FIPS 203 says: @@ -188,7 +188,7 @@ impl KEMPublicKey for MLKEMPublicKe debug_assert_eq!(pk_chunks.len(), k); debug_assert_eq!(last_chunk.len(), 32); - for (pk_chunk, t_i) in pk_chunks.into_iter().zip(&self.t_hat.vec) { + for (pk_chunk, t_i) in pk_chunks.into_iter().zip(&self.t_hat.elems) { pk_chunk.copy_from_slice(&byte_encode::<12, POLY_BYTES>(t_i)); } last_chunk.copy_from_slice(&self.rho); @@ -367,7 +367,7 @@ impl, const PK_LEN: u /// An ML-KEM private key. /// -/// This will automatically inherit the [`Secret`] protections because [`Polynomial`] wraps the underlying data with [`Secret`]. +// Dev note: This will automatically inherit the [`Secret`] protections because [`Polynomial`] wraps the underlying data with [`Secret`]. #[derive(Clone)] pub struct MLKEMPrivateKey< const k: usize, diff --git a/crypto/mlkem/src/polynomial.rs b/crypto/mlkem/src/polynomial.rs index 40025286..9d913db0 100644 --- a/crypto/mlkem/src/polynomial.rs +++ b/crypto/mlkem/src/polynomial.rs @@ -9,20 +9,13 @@ use crate::mlkem::{N, q}; /// A polynomial over the ML-KEM ring. /// -/// Dev note: The following structure does not necessarily need to be declared as public. -/// There is no real scenario where this function needs to be called directly. -/// However, in order to test the Debug and Display traits, it is necessary to use STD, so those -/// can't be tested from inline tests in this file and the real unit tests are in a different crate. -/// That's the reason why pub is used. -/// /// # 🚨 Security 🚨 /// Polynomials themselves are not inherently secret since sometimes they are part of public keys /// and sometimes private keys. /// It is the responsibility of the caller to wrap sensitive instances in `Secret`. #[derive(Clone, Copy)] -pub struct Polynomial { - /// Note: this is exposed publicly only for testing purposes and there is no good reason to use it in production code. - pub coeffs: [i16; N], +pub(crate) struct Polynomial { + pub(crate) coeffs: [i16; N], } /// Convenience function to avoid ".0" all over the place. @@ -263,8 +256,7 @@ impl Polynomial { /// Computes the NTT representation 𝑓_hat of the given polynomial 𝑓 ∈ 𝑅𝑞. /// Input: array 𝑓 ∈ ℤ256 ▷ the coefficients of the input polynomial /// Output: array 𝑓_hat ∈ ℤ256 ▷ the coefficients of the NTT of the input polynomial - /// Note: this is exposed publicly only for testing purposes and there is no good reason to use it in production code. - pub fn ntt(&mut self) { + pub(crate) fn ntt(&mut self) { let mut len = 128; let mut k = 1; @@ -290,8 +282,7 @@ impl Polynomial { /// Computes the polynomial 𝑓 ∈ 𝑅𝑞 that corresponds to the given NTT representation 𝑓 ∈ 𝑇𝑞. /// Input: array 𝑓 ∈ ℤ_{256} ▷ the coefficients of input NTT representation /// Output: array 𝑓 ∈ ℤ_{256} ▷ the coefficients of the inverse NTT of the input - /// Note: this is exposed publicly only for testing purposes and there is no good reason to use it in production code. - pub fn inv_ntt(&mut self) { + pub(crate) fn inv_ntt(&mut self) { // FIPS 203 Alg 10 wants you to copy f_hat into f, and then act on f // but here it is performed in-place in order to optimize memory usage. @@ -330,7 +321,7 @@ impl Polynomial { /// Borrowed from: /// /// Note: this is exposed publicly only for testing purposes and there is no good reason to use it in production code. -pub fn base_mult_montgomery(a: &Polynomial, b: &Polynomial) -> Polynomial { +pub(crate) fn base_mult_montgomery(a: &Polynomial, b: &Polynomial) -> Polynomial { let mut r = Polynomial::new(); for i in 0..(N / 4) {