From a7422a779c1fb47fef5b092c9e8458dd3108f4db Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Tue, 9 Jul 2024 13:01:13 +1000 Subject: [PATCH 1/3] hashes: Add const hash engine constructors Add `const` constructors to all hash engines. Call through to `Self::new` in `default` impls on `HashEngine`. --- hashes/src/ripemd160.rs | 11 ++++++++--- hashes/src/sha1.rs | 11 ++++++++--- hashes/src/sha256.rs | 11 ++++++++--- hashes/src/sha384.rs | 10 ++++++---- hashes/src/sha512.rs | 19 ++++++++++++------- hashes/src/sha512_256.rs | 10 ++++++---- 6 files changed, 48 insertions(+), 24 deletions(-) diff --git a/hashes/src/ripemd160.rs b/hashes/src/ripemd160.rs index 4ad076090..34f43a601 100644 --- a/hashes/src/ripemd160.rs +++ b/hashes/src/ripemd160.rs @@ -51,9 +51,10 @@ pub struct HashEngine { length: usize, } -impl Default for HashEngine { - fn default() -> Self { - HashEngine { +impl HashEngine { + /// Creates a new SHA256 hash engine. + pub const fn new() -> Self { + Self { h: [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0], length: 0, buffer: [0; BLOCK_SIZE], @@ -61,6 +62,10 @@ impl Default for HashEngine { } } +impl Default for HashEngine { + fn default() -> Self { Self::new() } +} + impl crate::HashEngine for HashEngine { type MidState = [u8; 20]; diff --git a/hashes/src/sha1.rs b/hashes/src/sha1.rs index 221666301..0ab25ff78 100644 --- a/hashes/src/sha1.rs +++ b/hashes/src/sha1.rs @@ -43,9 +43,10 @@ pub struct HashEngine { length: usize, } -impl Default for HashEngine { - fn default() -> Self { - HashEngine { +impl HashEngine { + /// Creates a new SHA1 hash engine. + pub const fn new() -> Self { + Self { h: [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0], length: 0, buffer: [0; BLOCK_SIZE], @@ -53,6 +54,10 @@ impl Default for HashEngine { } } +impl Default for HashEngine { + fn default() -> Self { Self::new() } +} + impl crate::HashEngine for HashEngine { type MidState = [u8; 20]; diff --git a/hashes/src/sha256.rs b/hashes/src/sha256.rs index 6900ae583..0c673e341 100644 --- a/hashes/src/sha256.rs +++ b/hashes/src/sha256.rs @@ -59,9 +59,10 @@ pub struct HashEngine { length: usize, } -impl Default for HashEngine { - fn default() -> Self { - HashEngine { +impl HashEngine { + /// Creates a new SHA256 hash engine. + pub const fn new() -> Self { + Self { h: [ 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19, @@ -72,6 +73,10 @@ impl Default for HashEngine { } } +impl Default for HashEngine { + fn default() -> Self { Self::new() } +} + impl crate::HashEngine for HashEngine { type MidState = Midstate; diff --git a/hashes/src/sha384.rs b/hashes/src/sha384.rs index ed675ce78..53db4e43f 100644 --- a/hashes/src/sha384.rs +++ b/hashes/src/sha384.rs @@ -23,11 +23,13 @@ fn from_engine(e: HashEngine) -> Hash { #[derive(Clone)] pub struct HashEngine(sha512::HashEngine); +impl HashEngine { + /// Creates a new SHA384 hash engine. + pub const fn new() -> Self { Self(sha512::HashEngine::sha384()) } +} + impl Default for HashEngine { - #[rustfmt::skip] - fn default() -> Self { - HashEngine(sha512::HashEngine::sha384()) - } + fn default() -> Self { Self::new() } } impl crate::HashEngine for HashEngine { diff --git a/hashes/src/sha512.rs b/hashes/src/sha512.rs index fb3ab5433..77997a0e3 100644 --- a/hashes/src/sha512.rs +++ b/hashes/src/sha512.rs @@ -52,10 +52,11 @@ pub struct HashEngine { buffer: [u8; BLOCK_SIZE], } -impl Default for HashEngine { +impl HashEngine { + /// Creates a new SHA512 hash engine. #[rustfmt::skip] - fn default() -> Self { - HashEngine { + pub const fn new() -> Self { + Self { h: [ 0x6a09e667f3bcc908, 0xbb67ae8584caa73b, 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1, 0x510e527fade682d1, 0x9b05688c2b3e6c1f, 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179, @@ -66,10 +67,14 @@ impl Default for HashEngine { } } +impl Default for HashEngine { + fn default() -> Self { Self::new() } +} + impl HashEngine { - /// Constructs a hash engine suitable for use inside the default `sha512_256::HashEngine`. + /// Constructs a hash engine suitable for use constructing a `sha512_256::HashEngine`. #[rustfmt::skip] - pub(crate) fn sha512_256() -> Self { + pub(crate) const fn sha512_256() -> Self { HashEngine { h: [ 0x22312194fc2bf72c, 0x9f555fa3c84c64c2, 0x2393b86b6f53b151, 0x963877195940eabd, @@ -80,9 +85,9 @@ impl HashEngine { } } - /// Constructs a hash engine suitable for use inside the default `sha384::HashEngine`. + /// Constructs a hash engine suitable for constructing `sha384::HashEngine`. #[rustfmt::skip] - pub(crate) fn sha384() -> Self { + pub(crate) const fn sha384() -> Self { HashEngine { h: [ 0xcbbb9d5dc1059ed8, 0x629a292a367cd507, 0x9159015a3070dd17, 0x152fecd8f70e5939, diff --git a/hashes/src/sha512_256.rs b/hashes/src/sha512_256.rs index 73d871621..413152196 100644 --- a/hashes/src/sha512_256.rs +++ b/hashes/src/sha512_256.rs @@ -33,11 +33,13 @@ fn from_engine(e: HashEngine) -> Hash { #[derive(Clone)] pub struct HashEngine(sha512::HashEngine); +impl HashEngine { + /// Creates a new SHA512/256 hash engine. + pub const fn new() -> Self { Self(sha512::HashEngine::sha512_256()) } +} + impl Default for HashEngine { - #[rustfmt::skip] - fn default() -> Self { - HashEngine(sha512::HashEngine::sha512_256()) - } + fn default() -> Self { Self::new() } } impl crate::HashEngine for HashEngine { From d5dd54a489a43effcd38df46e1eb7825f6cae464 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Tue, 9 Jul 2024 13:14:26 +1000 Subject: [PATCH 2/3] hashes: Strongly type the sha256d::HashEngine Currently we are using a type alias for the `sha256d::HashEngine`. Type alias' allow for potential mixing of types, a `sha256d::HashEngine` struct can better serve our users with not much additional complexity or maintenance burden. --- bitcoin/src/crypto/sighash.rs | 8 ++++---- hashes/src/impls.rs | 11 ++++++++++- hashes/src/sha256d.rs | 26 +++++++++++++++++++++++--- 3 files changed, 37 insertions(+), 8 deletions(-) diff --git a/bitcoin/src/crypto/sighash.rs b/bitcoin/src/crypto/sighash.rs index cf302e5ca..0554261b0 100644 --- a/bitcoin/src/crypto/sighash.rs +++ b/bitcoin/src/crypto/sighash.rs @@ -59,12 +59,12 @@ impl_message_from_hash!(SegwitV0Sighash); // but outside of it, it should not be possible to construct these hash // types from arbitrary data (except by casting via to/from_byte_array). impl LegacySighash { - fn engine() -> sha256::HashEngine { sha256d::Hash::engine() } - fn from_engine(e: sha256::HashEngine) -> Self { Self(sha256d::Hash::from_engine(e)) } + fn engine() -> sha256d::HashEngine { sha256d::Hash::engine() } + fn from_engine(e: sha256d::HashEngine) -> Self { Self(sha256d::Hash::from_engine(e)) } } impl SegwitV0Sighash { - fn engine() -> sha256::HashEngine { sha256d::Hash::engine() } - fn from_engine(e: sha256::HashEngine) -> Self { Self(sha256d::Hash::from_engine(e)) } + fn engine() -> sha256d::HashEngine { sha256d::Hash::engine() } + fn from_engine(e: sha256d::HashEngine) -> Self { Self(sha256d::Hash::from_engine(e)) } } sha256t_hash_newtype! { diff --git a/hashes/src/impls.rs b/hashes/src/impls.rs index bf9f0b8d4..f3d753ded 100644 --- a/hashes/src/impls.rs +++ b/hashes/src/impls.rs @@ -6,7 +6,7 @@ use bitcoin_io::impl_write; -use crate::{hmac, ripemd160, sha1, sha256, sha512, siphash24, HashEngine}; +use crate::{hmac, ripemd160, sha1, sha256, sha256d, sha512, siphash24, HashEngine}; impl_write!( sha1::HashEngine, @@ -26,6 +26,15 @@ impl_write!( |_us| { Ok(()) } ); +impl_write!( + sha256d::HashEngine, + |us: &mut sha256d::HashEngine, buf| { + us.input(buf); + Ok(buf.len()) + }, + |_us| { Ok(()) } +); + impl_write!( sha512::HashEngine, |us: &mut sha512::HashEngine, buf| { diff --git a/hashes/src/sha256d.rs b/hashes/src/sha256d.rs index 87a4cde35..175f1bae9 100644 --- a/hashes/src/sha256d.rs +++ b/hashes/src/sha256d.rs @@ -13,10 +13,30 @@ crate::internal_macros::hash_type! { "Output of the SHA256d hash function." } -type HashEngine = sha256::HashEngine; +/// Engine to compute SHA256d hash function. +#[derive(Clone)] +pub struct HashEngine(sha256::HashEngine); -fn from_engine(e: sha256::HashEngine) -> Hash { - let sha2 = sha256::Hash::from_engine(e); +impl HashEngine { + /// Creates a new SHA256d hash engine. + pub const fn new() -> Self { Self(sha256::HashEngine::new()) } +} + +impl Default for HashEngine { + fn default() -> Self { Self::new() } +} + +impl crate::HashEngine for HashEngine { + type MidState = sha256::Midstate; + fn midstate(&self) -> Self::MidState { self.0.midstate() } + + const BLOCK_SIZE: usize = 64; // Same as sha256::HashEngine::BLOCK_SIZE; + fn input(&mut self, data: &[u8]) { self.0.input(data) } + fn n_bytes_hashed(&self) -> usize { self.0.n_bytes_hashed() } +} + +fn from_engine(e: HashEngine) -> Hash { + let sha2 = sha256::Hash::from_engine(e.0); let sha2d = sha256::Hash::hash(&sha2[..]); let mut ret = [0; 32]; From 51010777bf4b4e738348855d5e637ea8f5571570 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Tue, 9 Jul 2024 13:19:15 +1000 Subject: [PATCH 3/3] hashes: Strongly type the hash160::HashEngine Currently we are using a type alias for the `hash160::HashEngine`. Type alias' allow for potential mixing of types, a `hash160::HashEngine` struct can better serve our users with not much additional complexity or maintenance burden. As we did for the `sha256d::HashEngine`, add a new wrapper type `hash160::HashEngine` that replaces the current type alias. --- bitcoin/src/address/mod.rs | 8 ++++---- hashes/src/hash160.rs | 24 ++++++++++++++++++++++-- hashes/src/impls.rs | 11 ++++++++++- 3 files changed, 36 insertions(+), 7 deletions(-) diff --git a/bitcoin/src/address/mod.rs b/bitcoin/src/address/mod.rs index 7813c7030..def904fb3 100644 --- a/bitcoin/src/address/mod.rs +++ b/bitcoin/src/address/mod.rs @@ -34,7 +34,7 @@ use core::str::FromStr; use bech32::primitives::gf32::Fe32; use bech32::primitives::hrp::Hrp; -use hashes::{sha256, HashEngine}; +use hashes::{hash160, HashEngine}; use secp256k1::{Secp256k1, Verification, XOnlyPublicKey}; use crate::consensus::Params; @@ -878,11 +878,11 @@ impl FromStr for Address { } /// Convert a byte array of a pubkey hash into a segwit redeem hash -fn segwit_redeem_hash(pubkey_hash: PubkeyHash) -> crate::hashes::hash160::Hash { - let mut sha_engine = sha256::Hash::engine(); +fn segwit_redeem_hash(pubkey_hash: PubkeyHash) -> hash160::Hash { + let mut sha_engine = hash160::Hash::engine(); sha_engine.input(&[0, 20]); sha_engine.input(pubkey_hash.as_ref()); - crate::hashes::hash160::Hash::from_engine(sha_engine) + hash160::Hash::from_engine(sha_engine) } #[cfg(test)] diff --git a/hashes/src/hash160.rs b/hashes/src/hash160.rs index 6993dadd7..f3065196d 100644 --- a/hashes/src/hash160.rs +++ b/hashes/src/hash160.rs @@ -18,10 +18,30 @@ crate::internal_macros::hash_type! { "Output of the Bitcoin HASH160 hash function. (RIPEMD160(SHA256))" } -type HashEngine = sha256::HashEngine; +/// Engine to compute HASH160 hash function. +#[derive(Clone)] +pub struct HashEngine(sha256::HashEngine); + +impl HashEngine { + /// Creates a new HASH160 hash engine. + pub const fn new() -> Self { Self(sha256::HashEngine::new()) } +} + +impl Default for HashEngine { + fn default() -> Self { Self::new() } +} + +impl crate::HashEngine for HashEngine { + type MidState = sha256::Midstate; + fn midstate(&self) -> Self::MidState { self.0.midstate() } + + const BLOCK_SIZE: usize = 64; // Same as sha256::HashEngine::BLOCK_SIZE; + fn input(&mut self, data: &[u8]) { self.0.input(data) } + fn n_bytes_hashed(&self) -> usize { self.0.n_bytes_hashed() } +} fn from_engine(e: HashEngine) -> Hash { - let sha2 = sha256::Hash::from_engine(e); + let sha2 = sha256::Hash::from_engine(e.0); let rmd = ripemd160::Hash::hash(&sha2[..]); let mut ret = [0; 20]; diff --git a/hashes/src/impls.rs b/hashes/src/impls.rs index f3d753ded..be5e8520f 100644 --- a/hashes/src/impls.rs +++ b/hashes/src/impls.rs @@ -6,7 +6,16 @@ use bitcoin_io::impl_write; -use crate::{hmac, ripemd160, sha1, sha256, sha256d, sha512, siphash24, HashEngine}; +use crate::{hash160, hmac, ripemd160, sha1, sha256, sha256d, sha512, siphash24, HashEngine}; + +impl_write!( + hash160::HashEngine, + |us: &mut hash160::HashEngine, buf| { + us.input(buf); + Ok(buf.len()) + }, + |_us| { Ok(()) } +); impl_write!( sha1::HashEngine,