From 97b956774ae760f486e428cde2141cf1b1aef46d Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Thu, 29 Jan 2026 08:37:30 -0700 Subject: [PATCH] ml-dsa: impl `MultiplyNtt` trait from `module-lattice` (#1190) Previously Algorithm 45: `MultiplyNTT` from FIPS 204 was implemented in the `module-lattice` crate, but for `ml-kem` we need to plug in Algorithm 11: `MultiplyNTTs` from FIPS 203 instead, so `module-lattice` now defines a new `MultiplyNTT` trait that lets either crate plug in their own algorithm that will also work with the `Mul` impls on `NttVector` and `NttMatrix`. This adds a temporary git dependency on `module-lattice` until it gets another crate release. --- Cargo.lock | 3 +-- Cargo.toml | 2 ++ ml-dsa/src/ntt.rs | 18 +++++++++++++++++- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 108d753..27b6f2e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -725,8 +725,7 @@ dependencies = [ [[package]] name = "module-lattice" version = "0.1.0-pre.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f95b02843c605c5c6d4747f07a1171645be22ce1fb42629e2cf0c5ba199ed640" +source = "git+https://github.com/RustCrypto/KEMs#5a2b2ae2003bd6c6f5ff5944ef07b3cd84a4d252" dependencies = [ "hybrid-array", "num-traits", diff --git a/Cargo.toml b/Cargo.toml index 79c5444..58d0a7d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,3 +25,5 @@ lms-signature = { path = "./lms" } ml-dsa = { path = "./ml-dsa" } rfc6979 = { path = "./rfc6979" } slh-dsa = { path = "./slh-dsa" } + +module-lattice = { git = "https://github.com/RustCrypto/KEMs" } diff --git a/ml-dsa/src/ntt.rs b/ml-dsa/src/ntt.rs index 0480230..3edeaba 100644 --- a/ml-dsa/src/ntt.rs +++ b/ml-dsa/src/ntt.rs @@ -1,4 +1,7 @@ -use module_lattice::{algebra::Field, encode::ArraySize}; +use module_lattice::{ + algebra::{Field, MultiplyNtt}, + encode::ArraySize, +}; use crate::algebra::{BaseField, Elem, NttPolynomial, NttVector, Polynomial, Vector}; @@ -161,6 +164,19 @@ impl NttInverse for NttVector { } } +impl MultiplyNtt for BaseField { + // Algorithm 45 MultiplyNTT + fn multiply_ntt(lhs: &NttPolynomial, rhs: &NttPolynomial) -> NttPolynomial { + NttPolynomial::new( + lhs.0 + .iter() + .zip(rhs.0.iter()) + .map(|(&x, &y)| x * y) + .collect(), + ) + } +} + #[cfg(test)] #[allow(clippy::as_conversions)] #[allow(clippy::cast_possible_truncation)]