hashes: Add SHA256d dispatch and public API
What changed, and why it matters
This commit adds a new performance-oriented function for computing many double-SHA256 hashes at once, with a special two-at-a-time path for ARM CPUs that support SHA2 hardware instructions. It also exposes that function as a new public API. There is nothing in the diff that fixes a bug, checks bounds incorrectly, or introduces an obvious security flaw; it appears to be a routine optimization and API addition.
No immediate security action required. If reviewing further, verify that `sha256d_64_arm_2way` correctly writes exactly 32 bytes per output and does not read beyond the two input blocks, and consider adding a `debug_assert_eq!` or documented precondition that `outputs.len() == inputs.len()` for the public API.
Security signals we found
New unsafe call site added, but it invokes an existing internal ARM SHA-NI routine with the same contract
New public API increases attack surface, though the function is a pure computation with no I/O, allocation, or secret-dependent branching
No bounds-check bypasses or integer-overflow patterns visible in the added code
Evidence from the diff
The change introduces sha256::HashEngine::sha256d_64, a dispatcher that processes pairs of 64-byte inputs using an ARM SHA-NI 2-way implementation when available, otherwise falls back to the existing software sha256d::hash. It then exposes this via a new public method Hash::hash_64_many. The function asserts outputs.len() == inputs.len() and uses try_from slices of exactly 2 elements, so the indexing is bounded. No unsafe code is added beyond calling the pre-existing sha256d_64_arm_2way. The commit is additive only and does not alter existing hash semantics.
Changed components
hashes/src/sha256/crypto.rshashes/src/sha256d/mod.rsInspect captured patch +46 / −0
diff --git a/hashes/src/sha256/crypto.rs b/hashes/src/sha256/crypto.rs
index 709f752f..05301080 100644
--- a/hashes/src/sha256/crypto.rs
+++ b/hashes/src/sha256/crypto.rs
@@ -332,6 +332,47 @@ impl HashEngine {
Self::software_process_block(state, blocks);
}
+ pub(crate) fn sha256d_64(outputs: &mut [[u8; 32]], inputs: &[[u8; 64]]) {
+ assert_eq!(outputs.len(), inputs.len());
+ let mut i = 0;
+ let count = inputs.len();
+
+ // TODO: 8-way AVX2
+ // TODO: 4-way SSE4.1
+ // TODO: 2-way x86 SHA-NI
+
+ // 2-way ARM SHA2
+ #[cfg(all(feature = "std", target_arch = "aarch64"))]
+ {
+ if std::arch::is_aarch64_feature_detected!("sha2") {
+ while count - i >= 2 {
+ let out = <&mut [[u8; 32]; 2]>::try_from(&mut outputs[i..i + 2]).unwrap();
+ let inp = <&[[u8; 64]; 2]>::try_from(&inputs[i..i + 2]).unwrap();
+ unsafe { Self::sha256d_64_arm_2way(out, inp) };
+ i += 2;
+ }
+ }
+ }
+
+ #[cfg(all(feature = "cpufeatures", target_arch = "aarch64"))]
+ {
+ if cpuid_sha256_aarch64::get() {
+ while count - i >= 2 {
+ let out = <&mut [[u8; 32]; 2]>::try_from(&mut outputs[i..i + 2]).unwrap();
+ let inp = <&[[u8; 64]; 2]>::try_from(&inputs[i..i + 2]).unwrap();
+ unsafe { Self::sha256d_64_arm_2way(out, inp) };
+ i += 2;
+ }
+ }
+ }
+
+ // fallback
+ while i < count {
+ outputs[i] = sha256d::hash(&inputs[i]).to_byte_array();
+ i += 1;
+ }
+ }
+
#[cfg(all(
any(target_arch = "x86", target_arch = "x86_64"),
any(feature = "std", feature = "cpufeatures")
diff --git a/hashes/src/sha256d/mod.rs b/hashes/src/sha256d/mod.rs
index 4a174106..0c49d015 100644
--- a/hashes/src/sha256d/mod.rs
+++ b/hashes/src/sha256d/mod.rs
@@ -11,6 +11,11 @@ crate::internal_macros::general_hash_type! {
}
impl Hash {
+ /// computes double-sha256 of multiple 64-byte blocks in parallel.
+ pub fn hash_64_many(outputs: &mut [[u8; 32]], inputs: &[[u8; 64]]) {
+ sha256::HashEngine::sha256d_64(outputs, inputs);
+ }
+
/// Finalize a hash engine to produce a hash.
pub fn from_engine(e: HashEngine) -> Self {
let sha2 = sha256::Hash::from_engine(e.0);
Why this scored 16/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.