From 4191905232aca0a73b7c9dd4a619e723df610ec3 Mon Sep 17 00:00:00 2001 From: Tamish Dahiya Date: Fri, 19 Jun 2026 23:38:10 +0530 Subject: [PATCH 1/8] add zeroize as a dependency in bouncycastle-core --- crypto/core/Cargo.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crypto/core/Cargo.toml b/crypto/core/Cargo.toml index 2b9c969..22b6a1f 100644 --- a/crypto/core/Cargo.toml +++ b/crypto/core/Cargo.toml @@ -4,7 +4,8 @@ version = "0.1.1" edition.workspace = true [dependencies] +zeroize = { version = "1.9.0", features = ["zeroize_derive"] } bouncycastle-utils.workspace = true [dev-dependencies] -bouncycastle-rng.workspace = true \ No newline at end of file +bouncycastle-rng.workspace = true From e6de01cad8b06dda8240a897bfdcf43acf6ab2f8 Mon Sep 17 00:00:00 2001 From: Tamish Dahiya Date: Fri, 19 Jun 2026 23:58:17 +0530 Subject: [PATCH 2/8] Replace Drop supertrait for Secret trait with ZeroizeOnDrop and implement DefaultIsZeroes for SecurityStrength --- crypto/core/src/traits.rs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/crypto/core/src/traits.rs b/crypto/core/src/traits.rs index 089e282..5ec2637 100644 --- a/crypto/core/src/traits.rs +++ b/crypto/core/src/traits.rs @@ -4,6 +4,7 @@ use crate::errors::{HashError, KDFError, KEMError, MACError, RNGError, Signature use crate::key_material::KeyMaterialTrait; use core::fmt::{Debug, Display}; use core::marker::Sized; +use zeroize::{DefaultIsZeroes, ZeroizeOnDrop}; // Imports needed for docs #[allow(unused_imports)] @@ -346,7 +347,7 @@ pub trait MAC: Sized { fn max_security_strength(&self) -> SecurityStrength; } -#[derive(Eq, PartialEq, PartialOrd, Clone, Debug)] +#[derive(Eq, PartialEq, PartialOrd, Clone, Copy, Debug)] pub enum SecurityStrength { None, _112bit, @@ -387,6 +388,15 @@ impl SecurityStrength { } } +impl DefaultIsZeroes for SecurityStrength {} + +impl Default for SecurityStrength { + fn default() -> Self { + Self::None + } +} + + /// An interface for random number generation. /// This interface is meant to be simpler and more ergonomic than the interfaces provided by the /// `rng` crate, but that one should @@ -418,10 +428,7 @@ pub trait RNG: Default { /// A trait that forces an object to implement a zeroizing Drop() as well as Debug and Display that /// will not log the sensitive contents, even in error or crash-dump scenarios. -#[allow(drop_bounds)] // Since rust auto-implements Drop, there's a lint that explicitly bounding on Drop is useless. -// I disagree because I want to force things that are secrets to manually implement Drop that zeroizes the data. -// So I'm turning off this lint. -pub trait Secret: Drop + Debug + Display {} +pub trait Secret : ZeroizeOnDrop + Debug + Display {} /// Pre-Hashed Signature is an extension to [Signature] that adds functionality specific to signature /// primatives that can operate on a pre-hashed message instead of the full message. From e867483a8af3c46b4e3354c07242fc6e98cc60f5 Mon Sep 17 00:00:00 2001 From: Tamish Dahiya Date: Sat, 20 Jun 2026 00:00:12 +0530 Subject: [PATCH 3/8] Derive ZeroizeOnDrop to replace zeroize() for KeyMaterial --- crypto/core/src/key_material.rs | 26 ++++++++++--------------- crypto/core/tests/key_material_tests.rs | 7 ++++++- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/crypto/core/src/key_material.rs b/crypto/core/src/key_material.rs index 48f903e..8deb49e 100644 --- a/crypto/core/src/key_material.rs +++ b/crypto/core/src/key_material.rs @@ -40,6 +40,7 @@ use crate::errors::KeyMaterialError; use crate::traits::{RNG, Secret, SecurityStrength}; use bouncycastle_utils::{ct, min}; +use zeroize::{DefaultIsZeroes, ZeroizeOnDrop}; use core::cmp::{Ordering, PartialOrd}; use core::fmt; @@ -146,8 +147,6 @@ pub trait KeyMaterialTrait { fn is_full_entropy(&self) -> bool; - fn zeroize(&mut self); - /// Is simply an alias to [KeyMaterialTrait::set_key_len], however, this does not require [KeyMaterialTrait::allow_hazardous_operations] /// since truncation is a safe operation. /// If truncating below the current security strength, the security strength will be lowered accordingly. @@ -172,7 +171,7 @@ pub trait KeyMaterialTrait { /// A wrapper for holding bytes-like key material (symmetric keys or seeds) which aims to apply a /// strict typing system to prevent many kinds of mis-use mistakes. /// The capacity of the internal buffer can be set at compile-time via the param. -#[derive(Clone)] +#[derive(Clone, ZeroizeOnDrop)] pub struct KeyMaterial { buf: [u8; KEY_LEN], key_len: usize, @@ -204,6 +203,14 @@ pub enum KeyType { SymmetricCipherKey, } +impl DefaultIsZeroes for KeyType {} + +impl Default for KeyType { + fn default() -> Self { + KeyType::Zeroized + } +} + impl Default for KeyMaterial { /// Create a new empty (zeroized) instance. fn default() -> Self { @@ -539,12 +546,6 @@ impl KeyMaterialTrait for KeyMaterial { } } - fn zeroize(&mut self) { - self.buf.fill(0u8); - self.key_len = 0; - self.key_type = KeyType::Zeroized; - } - fn truncate(&mut self, new_len: usize) -> Result<(), KeyMaterialError> { if new_len > self.key_len { return Err(KeyMaterialError::InvalidLength); @@ -647,10 +648,3 @@ impl fmt::Debug for KeyMaterial { ) } } - -/// Zeroize the key material on drop. -impl Drop for KeyMaterial { - fn drop(&mut self) { - self.zeroize() - } -} diff --git a/crypto/core/tests/key_material_tests.rs b/crypto/core/tests/key_material_tests.rs index 5e773fd..00b5529 100644 --- a/crypto/core/tests/key_material_tests.rs +++ b/crypto/core/tests/key_material_tests.rs @@ -173,7 +173,12 @@ mod test_key_material { #[test] fn zeroize() { let mut key = KeyMaterial256::from_bytes(&DUMMY_KEY[..32]).unwrap(); - key.zeroize(); + assert_eq!(key.key_len(), 32); + assert_eq!(key.key_type(), KeyType::BytesLowEntropy); + assert_eq!(key.security_strength(), SecurityStrength::None); + + unsafe { core::ptr::drop_in_place(&mut key) }; + let key_len = key.key_len(); assert_eq!(key_len, 0); assert_eq!(key.key_type(), KeyType::Zeroized); From 8ef55b27bb88da73128fdce4b0c0b7253248ee31 Mon Sep 17 00:00:00 2001 From: Tamish Dahiya Date: Sat, 20 Jun 2026 07:10:08 +0530 Subject: [PATCH 4/8] propagate zeroize in bouncycastle-mldsa --- crypto/mldsa/Cargo.toml | 3 ++- crypto/mldsa/src/matrix.rs | 5 +++-- crypto/mldsa/src/mldsa_keys.rs | 30 +++--------------------------- crypto/mldsa/src/polynomial.rs | 10 +++------- 4 files changed, 11 insertions(+), 37 deletions(-) diff --git a/crypto/mldsa/Cargo.toml b/crypto/mldsa/Cargo.toml index cddc8c6..635d775 100644 --- a/crypto/mldsa/Cargo.toml +++ b/crypto/mldsa/Cargo.toml @@ -9,6 +9,7 @@ bouncycastle-sha2.workspace = true bouncycastle-sha3.workspace = true bouncycastle-rng.workspace = true bouncycastle-utils.workspace = true +zeroize = { version = "1.9.0", features = ["zeroize_derive"] } [dev-dependencies] bouncycastle-core-test-framework.workspace = true @@ -19,4 +20,4 @@ serde_json = "1.0" [[bench]] name = "mldsa_benches" -harness = false \ No newline at end of file +harness = false diff --git a/crypto/mldsa/src/matrix.rs b/crypto/mldsa/src/matrix.rs index c0ef5d2..8699abb 100644 --- a/crypto/mldsa/src/matrix.rs +++ b/crypto/mldsa/src/matrix.rs @@ -6,9 +6,10 @@ use crate::mldsa::H; use crate::polynomial::Polynomial; use bouncycastle_core::traits::XOF; use core::ops::{Index, IndexMut}; +use zeroize::ZeroizeOnDrop; /// A matrix over the ML-DSA ring. -#[derive(Clone)] +#[derive(Clone, ZeroizeOnDrop)] pub struct Matrix(/*pub(crate)*/ [[Polynomial; l]; k]); /// Convenience function to avoid ".0" all over the place. @@ -62,7 +63,7 @@ impl Matrix { // Technically all matrices and some vectors are only part of the public key and might not need to be zeroized, // but I'll leave it zeroizing for now and leave this as a potential future optimization. -#[derive(Clone)] +#[derive(Clone, ZeroizeOnDrop)] pub(crate) struct Vector { pub(crate) vec: [Polynomial; k], } diff --git a/crypto/mldsa/src/mldsa_keys.rs b/crypto/mldsa/src/mldsa_keys.rs index c1643ba..93358eb 100644 --- a/crypto/mldsa/src/mldsa_keys.rs +++ b/crypto/mldsa/src/mldsa_keys.rs @@ -14,6 +14,7 @@ use bouncycastle_core::key_material::KeyMaterial; use bouncycastle_core::traits::{Secret, SignaturePrivateKey, SignaturePublicKey, XOF}; use core::fmt; use core::fmt::{Debug, Display, Formatter}; +use zeroize::ZeroizeOnDrop; // imports just for docs #[allow(unused_imports)] @@ -403,7 +404,7 @@ impl< } /// An ML-DSA private key. -#[derive(Clone)] +#[derive(Clone, ZeroizeOnDrop)] pub struct MLDSAPrivateKey< const k: usize, const l: usize, @@ -805,20 +806,11 @@ impl - Drop for MLDSAPrivateKey -{ - fn drop(&mut self) { - self.K.fill(0u8); - // s1, s2, t0, seed have their own zeroizing drop - } -} /// A fully expanded ML-DSA private key that includes the intermediate values needed for performing /// multiple sign operations with the same private key, which causes the private ey struct to take up /// more memory, but results in more efficient repeated sign() operations. -#[derive(Clone)] +#[derive(Clone, ZeroizeOnDrop)] pub struct MLDSAPrivateKeyExpanded< const k: usize, const l: usize, @@ -876,22 +868,6 @@ impl< { } -impl< - const k: usize, - const l: usize, - const eta: usize, - PK: MLDSAPublicKeyInternalTrait, - SK: MLDSAPrivateKeyTrait - + MLDSAPrivateKeyInternalTrait, - const SK_LEN: usize, - const PK_LEN: usize, -> Drop for MLDSAPrivateKeyExpanded -{ - fn drop(&mut self) { - // Nothing to do since self.sk already impls zeroizing Drop - } -} - impl< const k: usize, const l: usize, diff --git a/crypto/mldsa/src/polynomial.rs b/crypto/mldsa/src/polynomial.rs index b5f0999..f744670 100644 --- a/crypto/mldsa/src/polynomial.rs +++ b/crypto/mldsa/src/polynomial.rs @@ -9,11 +9,13 @@ use core::fmt; use core::fmt::{Debug, Display, Formatter}; use core::ops::{Index, IndexMut}; +use zeroize::ZeroizeOnDrop; + /// A polynomial over the ML-DSA 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. -#[derive(Clone)] +#[derive(Clone, ZeroizeOnDrop)] pub struct Polynomial { pub(crate) coeffs: [i32; N], } @@ -237,12 +239,6 @@ impl Polynomial { impl Secret for Polynomial {} -impl Drop for Polynomial { - fn drop(&mut self) { - self.coeffs.fill(0i32); - } -} - impl Debug for Polynomial { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!(f, "Polynomial (data masked)") From 2e3470db72602e9e426961b1ee2e4f0003854e42 Mon Sep 17 00:00:00 2001 From: Tamish Dahiya Date: Sat, 20 Jun 2026 07:15:40 +0530 Subject: [PATCH 5/8] propagate zeroize inbouncycastle-mldsa-lowmemory --- crypto/mldsa-lowmemory/Cargo.toml | 3 +- crypto/mldsa-lowmemory/src/mldsa_keys.rs | 39 ++---------------------- crypto/mldsa-lowmemory/src/polynomial.rs | 10 ++---- 3 files changed, 8 insertions(+), 44 deletions(-) diff --git a/crypto/mldsa-lowmemory/Cargo.toml b/crypto/mldsa-lowmemory/Cargo.toml index 83ccce7..2bce1bd 100644 --- a/crypto/mldsa-lowmemory/Cargo.toml +++ b/crypto/mldsa-lowmemory/Cargo.toml @@ -9,6 +9,7 @@ bouncycastle-sha2.workspace = true bouncycastle-sha3.workspace = true bouncycastle-rng.workspace = true bouncycastle-utils.workspace = true +zeroize = { version = "1.9.0", features = ["zeroize_derive"] } [dev-dependencies] bouncycastle-core-test-framework.workspace = true @@ -19,4 +20,4 @@ serde_json = "1.0" [[bench]] name = "mldsa_benches" -harness = false \ No newline at end of file +harness = false diff --git a/crypto/mldsa-lowmemory/src/mldsa_keys.rs b/crypto/mldsa-lowmemory/src/mldsa_keys.rs index b805d89..1b85e95 100644 --- a/crypto/mldsa-lowmemory/src/mldsa_keys.rs +++ b/crypto/mldsa-lowmemory/src/mldsa_keys.rs @@ -28,6 +28,8 @@ use bouncycastle_core::traits::{ use core::fmt; use core::fmt::{Debug, Display, Formatter}; +use zeroize::ZeroizeOnDrop; + // imports just for docs #[allow(unused_imports)] use crate::mldsa::MLDSATrait; @@ -294,7 +296,7 @@ pub trait MLDSAPrivateKeyTrait< } /// Internal structure for holding a seed-based private key for ML-DSA. -#[derive(Clone, PartialEq, Eq)] +#[derive(Clone, PartialEq, Eq, ZeroizeOnDrop)] pub struct MLDSASeedPrivateKey< const LAMBDA: i32, const GAMMA2: i32, @@ -314,41 +316,6 @@ pub struct MLDSASeedPrivateKey< K: [u8; 32], } -impl< - const LAMBDA: i32, - const GAMMA2: i32, - const k: usize, - const l: usize, - const eta: usize, - const S1_PACKED_LEN: usize, - const S2_PACKED_LEN: usize, - const T1_PACKED_LEN: usize, - const SK_LEN: usize, - const PK_LEN: usize, - const FULL_SK_LEN: usize, -> Drop - for MLDSASeedPrivateKey< - LAMBDA, - GAMMA2, - k, - l, - eta, - S1_PACKED_LEN, - S2_PACKED_LEN, - T1_PACKED_LEN, - PK_LEN, - SK_LEN, - FULL_SK_LEN, - > -{ - fn drop(&mut self) { - // seed is a KeyMaterialSized which will zeroize itself - self.rho.fill(0u8); - self.rho_prime.fill(0u8); - self.K.fill(0u8); - } -} - impl< const LAMBDA: i32, const GAMMA2: i32, diff --git a/crypto/mldsa-lowmemory/src/polynomial.rs b/crypto/mldsa-lowmemory/src/polynomial.rs index dc2438c..6d134fe 100644 --- a/crypto/mldsa-lowmemory/src/polynomial.rs +++ b/crypto/mldsa-lowmemory/src/polynomial.rs @@ -7,11 +7,13 @@ use core::fmt; use core::fmt::{Debug, Display, Formatter}; use core::ops::{Index, IndexMut}; +use zeroize::ZeroizeOnDrop; + /// A polynomial over the ML-DSA 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. -#[derive(Clone)] +#[derive(Clone, ZeroizeOnDrop)] pub struct Polynomial { pub(crate) coeffs: [i32; N], } @@ -248,12 +250,6 @@ impl Polynomial { impl Secret for Polynomial {} -impl Drop for Polynomial { - fn drop(&mut self) { - self.coeffs.fill(0i32); - } -} - impl Debug for Polynomial { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!(f, "Polynomial (data masked)") From 1201d908e6403e8fb69d593655d9889b13fb3a69 Mon Sep 17 00:00:00 2001 From: Tamish Dahiya Date: Sat, 20 Jun 2026 20:20:39 +0530 Subject: [PATCH 6/8] propagate zeroize in bouncycastle-mlkem --- crypto/mlkem/Cargo.toml | 3 ++- crypto/mlkem/src/matrix.rs | 6 ++++-- crypto/mlkem/src/mlkem_keys.rs | 21 ++++++--------------- crypto/mlkem/src/polynomial.rs | 10 +++------- 4 files changed, 15 insertions(+), 25 deletions(-) diff --git a/crypto/mlkem/Cargo.toml b/crypto/mlkem/Cargo.toml index 8235352..9f1c4de 100644 --- a/crypto/mlkem/Cargo.toml +++ b/crypto/mlkem/Cargo.toml @@ -8,6 +8,7 @@ bouncycastle-core.workspace = true bouncycastle-sha3.workspace = true bouncycastle-rng.workspace = true bouncycastle-utils.workspace = true +zeroize = { version = "1.9.0", features = ["zeroize_derive"] } [dev-dependencies] bouncycastle-core-test-framework.workspace = true @@ -18,4 +19,4 @@ serde_json = "1.0" [[bench]] name = "mlkem_benches" -harness = false \ No newline at end of file +harness = false diff --git a/crypto/mlkem/src/matrix.rs b/crypto/mlkem/src/matrix.rs index 100d6e0..1dc0f73 100644 --- a/crypto/mlkem/src/matrix.rs +++ b/crypto/mlkem/src/matrix.rs @@ -7,7 +7,9 @@ use crate::mlkem::{N, q}; use crate::polynomial; use crate::polynomial::Polynomial; -#[derive(Clone)] +use zeroize::ZeroizeOnDrop; + +#[derive(Clone, ZeroizeOnDrop)] /// A matrix over the ML-KEM ring. pub struct Matrix { /*pub(crate)*/ mat: [[Polynomial; l]; k], @@ -81,7 +83,7 @@ impl Matrix { // Technically all matrices and some vectors are only part of the public key and might not need to be zeroized, // but I'll leave it zeroizing for now and leave this as a potential future optimization. -#[derive(Clone)] +#[derive(Clone, ZeroizeOnDrop)] pub(crate) struct Vector { pub(crate) vec: [Polynomial; k], } diff --git a/crypto/mlkem/src/mlkem_keys.rs b/crypto/mlkem/src/mlkem_keys.rs index 327878c..0fa234d 100644 --- a/crypto/mlkem/src/mlkem_keys.rs +++ b/crypto/mlkem/src/mlkem_keys.rs @@ -12,6 +12,8 @@ use bouncycastle_sha3::SHA3_256; use core::fmt; use core::fmt::{Debug, Display, Formatter}; +use zeroize::ZeroizeOnDrop; + // imports just for docs #[allow(unused_imports)] use crate::mlkem::MLKEMTrait; @@ -683,6 +685,9 @@ impl< } } +impl, const SK_LEN: usize, const PK_LEN: usize> + ZeroizeOnDrop for MLKEMPrivateKey {} + /// Zeroizing drop impl< const k: usize, @@ -704,7 +709,7 @@ impl< /// A fully expanded ML-KEM private key that includes the intermediate values needed for performing /// multiple decaps operations with the same private key, which causes the private key struct to /// take up more memory, but results in more efficient repeated decaps() operations. -#[derive(Clone)] +#[derive(Clone, ZeroizeOnDrop)] pub struct MLKEMPrivateKeyExpanded< const k: usize, PK: MLKEMPublicKeyInternalTrait, @@ -796,20 +801,6 @@ impl< { } -impl< - const k: usize, - PK: MLKEMPublicKeyInternalTrait, - SK: MLKEMPrivateKeyTrait - + MLKEMPrivateKeyInternalTrait, - const SK_LEN: usize, - const PK_LEN: usize, -> Drop for MLKEMPrivateKeyExpanded -{ - fn drop(&mut self) { - // Nothing to do since self.sk already impls zeroizing Drop - } -} - impl< const k: usize, PK: MLKEMPublicKeyInternalTrait, diff --git a/crypto/mlkem/src/polynomial.rs b/crypto/mlkem/src/polynomial.rs index 951cc13..375c188 100644 --- a/crypto/mlkem/src/polynomial.rs +++ b/crypto/mlkem/src/polynomial.rs @@ -10,11 +10,13 @@ use crate::aux_functions::{ use crate::mlkem::{N, q}; use bouncycastle_core::traits::Secret; +use zeroize::ZeroizeOnDrop; + /// 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. -#[derive(Clone)] +#[derive(Clone, ZeroizeOnDrop)] pub struct Polynomial { pub(crate) coeffs: [i16; N], } @@ -328,12 +330,6 @@ pub(crate) fn base_mult_montgomery(a: &Polynomial, b: &Polynomial) -> Polynomial impl Secret for Polynomial {} -impl Drop for Polynomial { - fn drop(&mut self) { - self.coeffs.fill(0i16); - } -} - impl Debug for Polynomial { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!(f, "Polynomial (data masked)") From 39c3fc7d74eaeb9309ea3ac71b93e03845b0d57e Mon Sep 17 00:00:00 2001 From: Tamish Dahiya Date: Sat, 20 Jun 2026 20:34:55 +0530 Subject: [PATCH 7/8] propagate zeroize in bouncycastle-mlkem-lowmemory --- crypto/mlkem-lowmemory/Cargo.toml | 3 ++- crypto/mlkem-lowmemory/src/mlkem_keys.rs | 23 +++-------------------- crypto/mlkem-lowmemory/src/polynomial.rs | 10 +++------- 3 files changed, 8 insertions(+), 28 deletions(-) diff --git a/crypto/mlkem-lowmemory/Cargo.toml b/crypto/mlkem-lowmemory/Cargo.toml index 8ccb067..f75fbfc 100644 --- a/crypto/mlkem-lowmemory/Cargo.toml +++ b/crypto/mlkem-lowmemory/Cargo.toml @@ -8,6 +8,7 @@ bouncycastle-core.workspace = true bouncycastle-sha3.workspace = true bouncycastle-rng.workspace = true bouncycastle-utils.workspace = true +zeroize = { version = "1.9.0", features = ["zeroize_derive"] } [dev-dependencies] bouncycastle-core-test-framework.workspace = true @@ -18,4 +19,4 @@ serde_json = "1.0" [[bench]] name = "mlkem_benches" -harness = false \ No newline at end of file +harness = false diff --git a/crypto/mlkem-lowmemory/src/mlkem_keys.rs b/crypto/mlkem-lowmemory/src/mlkem_keys.rs index b9e58f3..5f6f4d1 100644 --- a/crypto/mlkem-lowmemory/src/mlkem_keys.rs +++ b/crypto/mlkem-lowmemory/src/mlkem_keys.rs @@ -24,6 +24,8 @@ use bouncycastle_sha3::SHA3_256; use core::fmt; use core::fmt::{Debug, Display, Formatter}; +use zeroize::ZeroizeOnDrop; + // imports just for docs /* Pub Types */ @@ -236,7 +238,7 @@ impl Display } /// An ML-KEM private key. -#[derive(Clone)] +#[derive(Clone, ZeroizeOnDrop)] pub struct MLKEMSeedPrivateKey< const k: usize, const eta1: i16, @@ -659,22 +661,3 @@ impl< write!(f, "MLKEMSeedPrivateKey {{ alg: {}, pub_key_hash: {:x?} }}", alg, &pk_hash,) } } - -/// Zeroizing drop -impl< - const k: usize, - const eta1: i16, - const LAMBDA: i16, - const SK_LEN: usize, - const FULL_SK_LEN: usize, - const PK_LEN: usize, - const T_PACKED_LEN: usize, -> Drop for MLKEMSeedPrivateKey -{ - fn drop(&mut self) { - self.rho.fill(0u8); - self.sigma.fill(0u8); - self.z.fill(0u8); - self.seed_d.fill(0u8); - } -} diff --git a/crypto/mlkem-lowmemory/src/polynomial.rs b/crypto/mlkem-lowmemory/src/polynomial.rs index bec4ee4..6b7c6aa 100644 --- a/crypto/mlkem-lowmemory/src/polynomial.rs +++ b/crypto/mlkem-lowmemory/src/polynomial.rs @@ -9,11 +9,13 @@ use core::fmt; use core::fmt::{Debug, Display, Formatter}; use core::ops::{Index, IndexMut}; +use zeroize::ZeroizeOnDrop; + /// 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. -#[derive(Clone)] +#[derive(Clone, ZeroizeOnDrop)] pub struct Polynomial { pub(crate) coeffs: [i16; N], } @@ -320,12 +322,6 @@ impl Polynomial { impl Secret for Polynomial {} -impl Drop for Polynomial { - fn drop(&mut self) { - self.coeffs.fill(0i16); - } -} - impl Debug for Polynomial { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!(f, "Polynomial (data masked)") From 910a831c9dc2bbf76e7719bea40dc8db81fd7b0f Mon Sep 17 00:00:00 2001 From: Tamish Dahiya Date: Sat, 20 Jun 2026 22:06:31 +0530 Subject: [PATCH 8/8] fix whitespace overwrites --- crypto/core/src/traits.rs | 2 +- crypto/core/tests/key_material_tests.rs | 2 +- crypto/mldsa-lowmemory/src/polynomial.rs | 4 ++-- crypto/mldsa/src/polynomial.rs | 1 - crypto/mlkem-lowmemory/Cargo.toml | 2 +- crypto/mlkem/src/matrix.rs | 2 +- crypto/mlkem/src/mlkem_keys.rs | 2 +- 7 files changed, 7 insertions(+), 8 deletions(-) diff --git a/crypto/core/src/traits.rs b/crypto/core/src/traits.rs index 5ec2637..546eb23 100644 --- a/crypto/core/src/traits.rs +++ b/crypto/core/src/traits.rs @@ -196,7 +196,7 @@ pub trait KEM< /// Generate a keypair. /// Error condition: Basically only on RNG failures fn keygen() -> Result<(PK, SK), KEMError>; - + /// Performs an encapsulation against the given public key. /// Returns the ciphertext and derived shared secret. fn encaps(pk: &PK) -> Result<(KeyMaterial, [u8; CT_LEN]), KEMError>; diff --git a/crypto/core/tests/key_material_tests.rs b/crypto/core/tests/key_material_tests.rs index 00b5529..611b169 100644 --- a/crypto/core/tests/key_material_tests.rs +++ b/crypto/core/tests/key_material_tests.rs @@ -449,7 +449,7 @@ mod test_key_material { let key1 = KeyMaterial256::from_bytes_as_type(&DUMMY_KEY[..32], KeyType::MACKey).unwrap(); assert_eq!(key1.key_type(), KeyType::MACKey); assert_eq!(key1.security_strength(), SecurityStrength::_256bit); - + // success case: same size using default From impl; only works if the sizes are the same (ie the compiler knows that they are the same type. let key2 = KeyMaterial256::from(key1.clone()); assert_eq!(key1.key_len(), key2.key_len()); diff --git a/crypto/mldsa-lowmemory/src/polynomial.rs b/crypto/mldsa-lowmemory/src/polynomial.rs index 6d134fe..e399b02 100644 --- a/crypto/mldsa-lowmemory/src/polynomial.rs +++ b/crypto/mldsa-lowmemory/src/polynomial.rs @@ -136,7 +136,7 @@ impl Polynomial { // then it's free to optimize all of the computation into CPU registers and skip, in this case, // several hundred physical memory writes. // So while it looks odd to use a scope variable in a low-memory implementation, it's way faster - // and I'm not convinced that it uses any more physical memory. + // and I'm not convinced that it uses any more physical memory. let mut r = [0u8; POLY_W1_PACKED_LEN]; match POLY_W1_PACKED_LEN { @@ -157,7 +157,7 @@ impl Polynomial { unreachable!() } } - + r } diff --git a/crypto/mldsa/src/polynomial.rs b/crypto/mldsa/src/polynomial.rs index f744670..b19951a 100644 --- a/crypto/mldsa/src/polynomial.rs +++ b/crypto/mldsa/src/polynomial.rs @@ -97,7 +97,6 @@ impl Polynomial { // } // but since BOUND is a constant here, we'll just do a debug_assert to make sure the value is what we expect. debug_assert!(BOUND <= (q - 1) / 8); - let mut t: i32; for x in self.coeffs.iter() { t = *x >> 31; diff --git a/crypto/mlkem-lowmemory/Cargo.toml b/crypto/mlkem-lowmemory/Cargo.toml index f75fbfc..b472d56 100644 --- a/crypto/mlkem-lowmemory/Cargo.toml +++ b/crypto/mlkem-lowmemory/Cargo.toml @@ -19,4 +19,4 @@ serde_json = "1.0" [[bench]] name = "mlkem_benches" -harness = false +harness = false \ No newline at end of file diff --git a/crypto/mlkem/src/matrix.rs b/crypto/mlkem/src/matrix.rs index 1dc0f73..2c08665 100644 --- a/crypto/mlkem/src/matrix.rs +++ b/crypto/mlkem/src/matrix.rs @@ -310,4 +310,4 @@ impl Vector { u } -} +} \ No newline at end of file diff --git a/crypto/mlkem/src/mlkem_keys.rs b/crypto/mlkem/src/mlkem_keys.rs index 0fa234d..9b15542 100644 --- a/crypto/mlkem/src/mlkem_keys.rs +++ b/crypto/mlkem/src/mlkem_keys.rs @@ -529,7 +529,7 @@ impl< // This satisfies the "Decapsulation input check #3) in FIPS 203 section 7.3. // We're doing it here on key load rather than as part of the decapsulation for performance - // because if you're doing multiple decapsulations, you only need to perform this check once. + // because if you're doing multiple decapsulations, you only need to perform this check once. if h_pk != ek.compute_hash() { return Err(KEMError::ConsistencyCheckFailed( "Corrupted private key: computed hash of ek != h_ek stored in private key",