From a22d9efd958dfa8d28e61931e7bc66df35136307 Mon Sep 17 00:00:00 2001 From: Abdullah1738 Date: Mon, 10 Aug 2026 04:46:59 +0400 Subject: [PATCH 1/2] fix(digest): erase truncated output temporary --- digest/src/block_api/ct_variable.rs | 60 ++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/digest/src/block_api/ct_variable.rs b/digest/src/block_api/ct_variable.rs index 8c8dba038..165c04849 100644 --- a/digest/src/block_api/ct_variable.rs +++ b/digest/src/block_api/ct_variable.rs @@ -13,6 +13,30 @@ use common::{ }; use core::{fmt, marker::PhantomData}; +#[cfg(feature = "zeroize")] +struct ScopedFullResult(Array); + +#[cfg(feature = "zeroize")] +impl Default for ScopedFullResult { + fn default() -> Self { + Self(Default::default()) + } +} + +#[cfg(feature = "zeroize")] +impl Drop for ScopedFullResult { + fn drop(&mut self) { + use zeroize::Zeroize; + self.0.as_mut_slice().zeroize(); + #[cfg(test)] + SCOPED_FULL_RESULT_DROPS.fetch_add(1, core::sync::atomic::Ordering::SeqCst); + } +} + +#[cfg(all(test, feature = "zeroize"))] +static SCOPED_FULL_RESULT_DROPS: core::sync::atomic::AtomicUsize = + core::sync::atomic::AtomicUsize::new(0); + /// Wrapper around [`VariableOutputCore`] which selects output size at compile time. pub struct CtOutWrapper where @@ -105,8 +129,15 @@ where buffer: &mut Buffer, out: &mut Array, ) { + #[cfg(feature = "zeroize")] + let mut scoped_full_res = ScopedFullResult::::default(); + #[cfg(feature = "zeroize")] + let full_res = &mut scoped_full_res.0; + #[cfg(not(feature = "zeroize"))] let mut full_res = Default::default(); - self.inner.finalize_variable_core(buffer, &mut full_res); + #[cfg(not(feature = "zeroize"))] + let full_res = &mut full_res; + self.inner.finalize_variable_core(buffer, full_res); let n = out.len(); let m = full_res.len() - n; match T::TRUNC_SIDE { @@ -116,6 +147,33 @@ where } } +#[cfg(all(test, feature = "zeroize"))] +mod tests { + use super::{SCOPED_FULL_RESULT_DROPS, ScopedFullResult}; + use common::typenum::U32; + use core::sync::atomic::Ordering; + + extern crate std; + + #[test] + fn scoped_full_result_zeroizes_on_return() { + SCOPED_FULL_RESULT_DROPS.store(0, Ordering::SeqCst); + drop(ScopedFullResult::::default()); + assert_eq!(SCOPED_FULL_RESULT_DROPS.load(Ordering::SeqCst), 1); + } + + #[test] + fn scoped_full_result_zeroizes_on_unwind() { + SCOPED_FULL_RESULT_DROPS.store(0, Ordering::SeqCst); + let result = std::panic::catch_unwind(|| { + let _result = ScopedFullResult::::default(); + panic!("test-only finalization unwind"); + }); + assert!(result.is_err()); + assert_eq!(SCOPED_FULL_RESULT_DROPS.load(Ordering::SeqCst), 1); + } +} + impl Default for CtOutWrapper where T: VariableOutputCore, From 113c5ba12876e332335e49d1462a2c96c9928006 Mon Sep 17 00:00:00 2001 From: Abdullah1738 Date: Mon, 10 Aug 2026 04:54:02 +0400 Subject: [PATCH 2/2] test(digest): avoid erasure test race --- digest/src/block_api/ct_variable.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/digest/src/block_api/ct_variable.rs b/digest/src/block_api/ct_variable.rs index 165c04849..da7fec423 100644 --- a/digest/src/block_api/ct_variable.rs +++ b/digest/src/block_api/ct_variable.rs @@ -156,14 +156,11 @@ mod tests { extern crate std; #[test] - fn scoped_full_result_zeroizes_on_return() { + fn scoped_full_result_zeroizes_on_return_and_unwind() { SCOPED_FULL_RESULT_DROPS.store(0, Ordering::SeqCst); drop(ScopedFullResult::::default()); assert_eq!(SCOPED_FULL_RESULT_DROPS.load(Ordering::SeqCst), 1); - } - #[test] - fn scoped_full_result_zeroizes_on_unwind() { SCOPED_FULL_RESULT_DROPS.store(0, Ordering::SeqCst); let result = std::panic::catch_unwind(|| { let _result = ScopedFullResult::::default();