Add SHA256 midstate conversion to Midstate
What changed, and why it matters
This commit simply moves an existing SHA256 midstate-to-engine conversion from one place in the code to another. The actual logic is unchanged; it is a code-organization refactor following a Rust API design guideline. There is no security fix or vulnerability here.
No security action required. Treat as a normal API refactor; review for downstream compatibility if your code depends on the exact method location.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The change relocates the implementation of converting a SHA256 Midstate into a HashEngine. Previously this lived as HashEngine::from_midstate(midstate). Now it is implemented as Midstate::to_engine(self), and HashEngine::from_midstate delegates to it. The byte conversion, buffer initialization, and bytes_hashed propagation are identical. Tests and tagged-hash initialization are updated to use the new method path. No cryptographic behavior changes.
Changed components
hashes/src/sha256/mod.rshashes/src/sha256/tests.rshashes/src/sha256t/mod.rsInspect captured patch +17 / −14
diff --git a/hashes/src/sha256/mod.rs b/hashes/src/sha256/mod.rs
index 581ecb48..cf7783fd 100644
--- a/hashes/src/sha256/mod.rs
+++ b/hashes/src/sha256/mod.rs
@@ -95,15 +95,7 @@ impl HashEngine {
/// Constructs a new [`HashEngine`] from a [`Midstate`].
///
/// Please see docs on [`Midstate`] before using this function.
- pub fn from_midstate(midstate: Midstate) -> Self {
- let mut ret = [0; 8];
- for (ret_val, midstate_bytes) in ret.iter_mut().zip(midstate.as_ref().bitcoin_as_chunks().0)
- {
- *ret_val = u32::from_be_bytes(*midstate_bytes);
- }
-
- Self { buffer: [0; BLOCK_SIZE], h: ret, bytes_hashed: midstate.bytes_hashed }
- }
+ pub fn from_midstate(midstate: Midstate) -> Self { midstate.to_engine() }
/// Returns `true` if the midstate can be extracted from this engine.
///
@@ -219,6 +211,17 @@ impl Midstate {
/// Deconstructs the [`Midstate`], returning the underlying byte array and number of bytes hashed.
pub const fn to_parts(self) -> ([u8; 32], u64) { (self.bytes, self.bytes_hashed) }
+ /// Constructs a new [`HashEngine`] from this [`Midstate`].
+ pub fn to_engine(self) -> HashEngine {
+ let mut ret = [0; 8];
+ for (ret_val, midstate_bytes) in ret.iter_mut().zip(self.as_ref().bitcoin_as_chunks().0)
+ {
+ *ret_val = u32::from_be_bytes(*midstate_bytes);
+ }
+
+ HashEngine { buffer: [0; BLOCK_SIZE], h: ret, bytes_hashed: self.bytes_hashed }
+ }
+
/// Constructs a new midstate for tagged hashes.
///
/// Warning: this function is inefficient. It should be only used in `const` context.
diff --git a/hashes/src/sha256/tests.rs b/hashes/src/sha256/tests.rs
index e73d6dda..e31f3852 100644
--- a/hashes/src/sha256/tests.rs
+++ b/hashes/src/sha256/tests.rs
@@ -132,7 +132,7 @@ fn engine_with_state() {
];
let mut engine = sha256::Hash::engine();
- let midstate_engine = sha256::HashEngine::from_midstate(engine.midstate_unchecked());
+ let midstate_engine = engine.midstate_unchecked().to_engine();
// Fresh engine and engine initialized with fresh state should have same state
assert_eq!(engine.h, midstate_engine.h);
@@ -147,7 +147,7 @@ fn engine_with_state() {
let data_vec: &[&[u8]] = &[&[3u8; 1], &[4u8; 63], &[5u8; 65], &[6u8; 66]];
for data in data_vec {
let mut engine = engine.clone();
- let mut midstate_engine = sha256::HashEngine::from_midstate(engine.midstate_unchecked());
+ let mut midstate_engine = engine.midstate_unchecked().to_engine();
assert_eq!(engine.h, midstate_engine.h);
assert_eq!(engine.bytes_hashed, midstate_engine.bytes_hashed);
engine.input(data);
@@ -158,7 +158,7 @@ fn engine_with_state() {
assert_eq!(hash1, hash2);
}
- let midstate_engine = sha256::HashEngine::from_midstate(sha256::Midstate::new(MIDSTATE, 64));
+ let midstate_engine = sha256::Midstate::new(MIDSTATE, 64).to_engine();
let hash = sha256::Hash::from_engine(midstate_engine);
assert_eq!(hash, sha256::Hash(HASH_EXPECTED));
}
@@ -227,7 +227,7 @@ fn midstate_error_resume_hashing() {
let err = engine1.midstate().expect_err("100 bytes not block-aligned");
assert_eq!(err.unprocessed_bytes().len(), 36);
// we can resume hashing from err data
- let mut engine2 = sha256::HashEngine::from_midstate(*err.midstate());
+ let mut engine2 = err.midstate().to_engine();
engine2.input(err.unprocessed_bytes());
assert_eq!(sha256::Hash::from_engine(engine1), sha256::Hash::from_engine(engine2));
}
diff --git a/hashes/src/sha256t/mod.rs b/hashes/src/sha256t/mod.rs
index 39df5a5b..44cf4540 100644
--- a/hashes/src/sha256t/mod.rs
+++ b/hashes/src/sha256t/mod.rs
@@ -133,7 +133,7 @@ pub struct HashEngine<T>(sha256::HashEngine, PhantomData<T>);
impl<T: Tag> Default for HashEngine<T> {
fn default() -> Self {
- let tagged = sha256::HashEngine::from_midstate(T::MIDSTATE);
+ let tagged = T::MIDSTATE.to_engine();
Self(tagged, PhantomData)
}
}
Why this scored 19/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.