diff --git a/CHANGELOG.md b/CHANGELOG.md
index fd501d27d..48878601c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -13,6 +13,44 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
serialization traits as Platform. Existing bincode encodings and C interfaces
are unchanged, but Rust consumers must use the fork for compatible `Encode`/`Decode` traits.
The dependency switch does not automatically opt types into `DecodeUntrusted`.
+- **Breaking:** `dashcore_hashes` re-exports the hash primitives (`sha1`,
+ `sha256`, `sha256d`, `sha512`, `sha512_256`, `ripemd160`, `hash160`, `hmac`,
+ `siphash24`, `cmp`, `hex`) from `bitcoin_hashes` 0.14. The raw types no longer
+ implement bincode or accept byte and sequence forms in serde, `Error` is
+ `FromSliceError`, and `forward_hex`, `backward_hex` and the `schemars` feature
+ are removed
+- **Breaking:** hashes honour the format precision, so `{:.8}` prints 8 digits
+- **Breaking:** `hash_x11::Hash` loses `forward_hex`, `backward_hex`,
+ `from_bytes_ref` and `from_bytes_mut`, `hash_x11::Midstate` is replaced by
+ `[u8; 32]`, and `n_bytes_hashed()` returns the bytes written
+- **Breaking:** `EcdsaSighashType` comes from `bitcoin-crypto` and gains a
+ `NonStandard` variant, which `from_consensus` returns for non-standard flags
+ and which displays, parses and serializes as `0xNN`. The `from_standard` error
+ is `NonStandardSighashTypeError`, `TapSighashType` converts through `TryFrom`,
+ and `sighash::Error` no longer derives `Copy`, `PartialOrd`, `Ord` or `Hash`
+- **Breaking:** the taproot types come from `bitcoin-crypto`. `Signature`
+ fields are renamed to `signature` and `sighash_type`, and `taproot::Error` is
+ `SigFromSliceError`, without a `Secp256k1` variant
+- **Breaking:** `dashcore::eddsa` uses the `dash-pkc` types, so `EddsaPkBytes`
+ and `EddsaSkBytes` no longer implement `BaseCodec` and `EddsaError` changes
+ shape. Use `EddsaPublicKey::try_from`, `EddsaPkHash::from` and
+ `EddsaSecretKey::public_key` instead of `EddsaPkBytes::validate`,
+ `EddsaPkBytes::hash` and `EddsaSkBytes::public_key`
+- **Breaking:** `QualifiedMasternodeListEntry::entry_hash` and
+ `MessageVerificationError::ThresholdSignatureNotValid` hold `Sha256dHash`
+- **Breaking:** `dashcore::base58` is `base58ck` 0.5.0, so `Base58CkString`
+ replaces the `encode_*` functions and the `Base58` error variants carry
+ `base58::DecodeCheckError`
+- Relicense `dash-network`, `dash-network-seeds`, `dash-spv`, `dash-spv-ffi`,
+ `dash-spv-bench`, `git-state` and `masternode-seeds-fetcher` to CC0-1.0
+- All workspace crates declare a MSRV of 1.89
+
+### Fixed
+
+- Treat `SIGHASH_SINGLE` flags with `ANYONECANPAY` set, such as `0x83`, as
+ single when checking for the legacy `SIGHASH_SINGLE` bug
+- `transaction_sighash` in `key-wallet-ffi` hashes non-standard flags as given
+ and rejects flags above `0xff`
## 0.44.0 - 2026-07-01
diff --git a/Cargo.toml b/Cargo.toml
index b19b39ad4..657504a39 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -3,12 +3,32 @@ members = ["dash", "crypto", "dash-network", "hashes", "internals", "fuzz", "rpc
resolver = "2"
[workspace.dependencies]
+# Packages shared across crates
bincode = { package = "grovedb-bincode", version = "=2.1.0" }
bincode_derive = { package = "grovedb-bincode-derive", version = "=2.1.0" }
+futures = "0.3"
+hex = "0.4"
+hex_lit = "0.1.1"
+rayon = "1.11"
+secp256k1 = "0.33.1" # must match with version used in `bitcoin-crypto` and `dash-pkc`
+serde = { version = "1.0.219", default-features = false }
+zeroize = { version = "1.8", features = ["derive"] }
+
+# Packages from `dashpay/base-sdk`, MUST share same version ACROSS crates
dash-pkc = { git = "https://github.com/dashpay/base-sdk", rev = "e6402ced257c370a586ade9840ebbf545a4b7926", default-features = false }
dash-types = { git = "https://github.com/dashpay/base-sdk", rev = "e6402ced257c370a586ade9840ebbf545a4b7926", default-features = false }
+# Packages from `rust-bitcoin/rust-bitcoin`, `bitcoin-crypto` uses revision due to `secp256k1`
+base58ck = { version = "0.5.0" }
+bitcoin_hashes = { version = "0.14.101", default-features = false }
+bitcoin-crypto = { git = "https://github.com/rust-bitcoin/rust-bitcoin", rev = "7ba35c7c1dd63892bfb9c9395bbd80e2ab5df516", default-features = false }
+
[workspace.package]
+authors = ["The rust-dashcore Developers"]
+edition = "2024"
+license = "CC0-1.0"
+repository = "https://github.com/dashpay/rust-dashcore"
+rust-version = "1.89.0"
version = "0.45.0"
[patch.crates-io]
diff --git a/README.md b/README.md
index bc4374d06..5c0726456 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@
-
+
diff --git a/crypto/Cargo.toml b/crypto/Cargo.toml
index 896d58bcc..39eed93d5 100644
--- a/crypto/Cargo.toml
+++ b/crypto/Cargo.toml
@@ -1,34 +1,36 @@
[package]
name = "dashcore-crypto"
-version = { workspace = true }
-authors = ["The Dash Core Developers"]
-license = "CC0-1.0"
-repository = "https://github.com/dashpay/rust-dashcore/"
description = "Cryptographic primitives shared by rust-dashcore crates."
+edition = "2021"
categories = ["cryptography::cryptocurrencies"]
keywords = ["crypto", "dash", "bls", "secp256k1"]
-edition = "2021"
+authors.workspace = true
+license.workspace = true
+repository.workspace = true
+rust-version.workspace = true
+version.workspace = true
[features]
default = []
bincode = ["dep:bincode", "dep:bincode_derive", "dashcore_hashes/bincode", "dash-network/bincode"]
-bls = ["dep:dash-pkc", "dash-pkc/bls", "dep:tracing"]
-eddsa = ["dep:dash-pkc", "dash-pkc/eddsa"]
-serde = ["dep:serde", "dash-types/serde", "dashcore_hashes/serde", "dash-network/serde", "secp256k1/serde"]
+bls = ["dash-pkc/bls", "dep:tracing"]
+eddsa = ["dash-pkc/eddsa"]
+serde = ["dep:serde", "bitcoin-crypto/serde", "dash-types/serde", "dashcore_hashes/serde", "dash-network/serde", "dash-pkc/serde", "secp256k1/serde"]
[dependencies]
-base58ck = { version = "0.1.0" }
+base58ck = { workspace = true }
+bitcoin-crypto = { workspace = true, features = ["std", "hex"] }
bincode = { workspace = true, optional = true }
bincode_derive = { workspace = true, optional = true }
dash-network = { path = "../dash-network" }
-dash-pkc = { workspace = true, features = ["std"], optional = true }
+dash-pkc = { workspace = true, features = ["std"] }
dash-types = { workspace = true, features = ["codec"] }
dashcore_hashes = { path = "../hashes" }
-hex = { version = "0.4" }
+hex = { workspace = true }
internals = { path = "../internals", package = "dashcore-private" }
-secp256k1 = { version = "0.33.1" }
-serde = { version = "1.0.219", default-features = false, features = [ "derive", "alloc" ], optional = true }
+secp256k1 = { workspace = true }
+serde = { workspace = true, features = ["derive", "alloc"], optional = true }
thiserror = "2"
tracing = { version = "0.1", optional = true }
@@ -36,5 +38,5 @@ tracing = { version = "0.1", optional = true }
unexpected_cfgs = { level = "deny", check-cfg = ['cfg(bench)', 'cfg(fuzzing)', 'cfg(kani)'] }
[dev-dependencies]
-hex_lit = { version = "0.1.1", features = ["rust_v_1_46"] }
+hex_lit = { workspace = true, features = ["rust_v_1_46"] }
serde_json = { version = "1.0" }
diff --git a/crypto/src/ecdsa.rs b/crypto/src/ecdsa.rs
index f3e44e070..dcb9deb82 100644
--- a/crypto/src/ecdsa.rs
+++ b/crypto/src/ecdsa.rs
@@ -19,7 +19,7 @@ use secp256k1;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
-use crate::sighash::{EcdsaSighashType, NonStandardSighashType};
+use crate::sighash::EcdsaSighashType;
const MAX_SIG_LEN: usize = 73;
@@ -61,7 +61,7 @@ impl Signature {
let mut buf = [0u8; MAX_SIG_LEN];
let signature = self.sig.serialize_der();
buf[..signature.len()].copy_from_slice(&signature);
- buf[signature.len()] = self.hash_ty as u8;
+ buf[signature.len()] = self.hash_ty.to_consensus_u8();
SerializedSignature {
data: buf,
len: signature.len() + 1,
@@ -74,14 +74,19 @@ impl Signature {
/// [`serialize`](Self::serialize) method instead.
pub fn to_vec(self) -> Vec {
// TODO: add support to serialize to a writer to SerializedSig
- self.sig.serialize_der().iter().copied().chain(iter::once(self.hash_ty as u8)).collect()
+ self.sig
+ .serialize_der()
+ .iter()
+ .copied()
+ .chain(iter::once(self.hash_ty.to_consensus_u8()))
+ .collect()
}
}
impl fmt::Display for Signature {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::LowerHex::fmt(&self.sig.serialize_der().as_hex(), f)?;
- fmt::LowerHex::fmt(&[self.hash_ty as u8].as_hex(), f)
+ fmt::LowerHex::fmt(&[self.hash_ty.to_consensus_u8()].as_hex(), f)
}
}
@@ -93,7 +98,8 @@ impl FromStr for Signature {
let (sighash_byte, signature) = bytes.split_last().ok_or(Error::EmptySignature)?;
Ok(Signature {
sig: secp256k1::ecdsa::Signature::from_der(signature)?,
- hash_ty: EcdsaSighashType::from_standard(*sighash_byte as u32)?,
+ hash_ty: EcdsaSighashType::from_standard(*sighash_byte as u32)
+ .map_err(|_| Error::NonStandardSighashType(*sighash_byte as u32))?,
})
}
}
@@ -217,12 +223,12 @@ impl<'a> IntoIterator for &'a SerializedSignature {
}
/// A key-related error.
-#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+#[derive(Clone, PartialEq, Eq, Debug)]
#[non_exhaustive]
pub enum Error {
/// Hex encoding error
- HexEncoding(hex::Error),
- /// Base58 encoding error
+ HexEncoding(hex::HexToBytesError),
+ /// Non-standard sighash type
NonStandardSighashType(u32),
/// Empty Signature
EmptySignature,
@@ -261,14 +267,8 @@ impl From for Error {
}
}
-impl From for Error {
- fn from(err: NonStandardSighashType) -> Self {
- Error::NonStandardSighashType(err.0)
- }
-}
-
-impl From for Error {
- fn from(err: hex::Error) -> Self {
+impl From for Error {
+ fn from(err: hex::HexToBytesError) -> Self {
Error::HexEncoding(err)
}
}
diff --git a/crypto/src/eddsa.rs b/crypto/src/eddsa.rs
index 6a2ae6582..4e71c6f70 100644
--- a/crypto/src/eddsa.rs
+++ b/crypto/src/eddsa.rs
@@ -7,33 +7,13 @@
//! Ed25519 keys for Platform node identity.
#[cfg(feature = "eddsa")]
-use dash_pkc::eddsa::{
- EddsaPkBytes as PkcPkBytes, EddsaPublicKey as PkcPublicKey, EddsaSecretKey as PkcSecretKey,
-};
-#[cfg(feature = "eddsa")]
-use dash_types::Hashable;
-use dash_types::{make_bytes, make_sbytes};
-#[cfg(feature = "eddsa")]
-use thiserror::Error as ThisError;
-
-/// Raw Ed25519 public key length.
-pub const EDDSA_PK_LEN: usize = 32;
+pub use dash_pkc::eddsa::{EddsaError, EddsaPublicKey, EddsaSecretKey};
+pub use dash_pkc::eddsa::{EddsaPkBytes, EddsaSkBytes, EDDSA_PK_LEN, EDDSA_SK_LEN};
+use dash_types::{make_bytes, Hashable};
/// Ed25519 public key hash length.
pub const EDDSA_PK_HASH_LEN: usize = 20;
-/// Raw Ed25519 secret key (seed) length.
-pub const EDDSA_SK_LEN: usize = 32;
-
-/// Errors produced by Ed25519 operations.
-#[cfg(feature = "eddsa")]
-#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, ThisError)]
-pub enum EddsaError {
- /// Public key bytes are not a usable curve point.
- #[error("Invalid Ed25519 public key: {0}")]
- InvalidPublicKey(String),
-}
-
make_bytes! {
/// Ed25519 public key hash (20 bytes).
EddsaPkHash, EDDSA_PK_HASH_LEN, rev
@@ -82,42 +62,10 @@ impl<'de, C> bincode::BorrowDecode<'de, C> for EddsaPkHash {
}
}
-make_bytes! {
- /// Ed25519 public key (32 bytes, unvalidated).
- EddsaPkBytes, EDDSA_PK_LEN
-}
-
-#[cfg(feature = "eddsa")]
-impl EddsaPkBytes {
- /// Checks these bytes are a usable curve point.
- ///
- /// # Errors
- ///
- /// Returns `InvalidPublicKey` when the bytes are not on the curve.
- pub fn validate(&self) -> Result<(), EddsaError> {
- PkcPublicKey::from_bytes(self.as_bytes())
- .map(|_| ())
- .map_err(|e| EddsaError::InvalidPublicKey(e.to_string()))
- }
-
- /// The CometBFT hash of the public key.
- pub fn hash(&self) -> EddsaPkHash {
- EddsaPkHash::from_bytes(
- *Hashable::hash(&PkcPkBytes::from_bytes(*self.as_bytes())).as_bytes(),
- )
- }
-}
-
-make_sbytes! {
- /// Ed25519 secret key seed (32 bytes).
- EddsaSkBytes, EDDSA_SK_LEN
-}
-
-#[cfg(feature = "eddsa")]
-impl EddsaSkBytes {
- /// Derives the corresponding public key.
- pub fn public_key(&self) -> EddsaPkBytes {
- EddsaPkBytes::from_bytes(PkcSecretKey::from_bytes(self.as_bytes()).public_key().to_bytes())
+/// The CometBFT hash of the public key.
+impl From for EddsaPkHash {
+ fn from(public_key: EddsaPkBytes) -> Self {
+ Self::from_bytes(*Hashable::hash(&public_key).as_bytes())
}
}
@@ -171,7 +119,6 @@ mod tests {
assert_eq!(back, hash);
}
- #[cfg(feature = "eddsa")]
#[test]
fn hash_is_truncated_sha256() {
use dashcore_hashes::{sha256, Hash};
@@ -180,7 +127,7 @@ mod tests {
let digest = sha256::Hash::hash(&public_key);
// `EddsaPkHash` holds the wire order, which is the byte-reversal of
// the canonical form the digest is read in.
- let mut canonical = *EddsaPkBytes::from_bytes(public_key).hash().as_bytes();
+ let mut canonical = *EddsaPkHash::from(EddsaPkBytes::from_bytes(public_key)).as_bytes();
canonical.reverse();
assert_eq!(canonical[..], digest.to_byte_array()[..20]);
diff --git a/crypto/src/key.rs b/crypto/src/key.rs
index f2dfe0dd9..a01e8c3a3 100644
--- a/crypto/src/key.rs
+++ b/crypto/src/key.rs
@@ -30,7 +30,7 @@ use crate::base58;
#[non_exhaustive]
pub enum Error {
/// Base58 encoding error
- Base58(base58::Error),
+ Base58(base58::DecodeCheckError),
/// secp256k1-related error
Secp256k1(secp256k1::Error),
/// Invalid key prefix error
@@ -40,7 +40,7 @@ pub enum Error {
/// The base58 decoded correctly but the payload was the wrong length.
InvalidBase58PayloadLength(usize),
/// Hex decoding error
- Hex(hex::Error),
+ Hex(hex::HexToArrayError),
/// `PublicKey` hex should be 66 or 130 digits long.
InvalidHexLength(usize),
/// Something is not supported based on active features
@@ -88,8 +88,8 @@ impl std::error::Error for Error {
}
#[doc(hidden)]
-impl From for Error {
- fn from(e: base58::Error) -> Error {
+impl From for Error {
+ fn from(e: base58::DecodeCheckError) -> Error {
Error::Base58(e)
}
}
@@ -102,8 +102,8 @@ impl From for Error {
}
#[doc(hidden)]
-impl From for Error {
- fn from(e: hex::Error) -> Self {
+impl From for Error {
+ fn from(e: hex::HexToArrayError) -> Self {
Error::Hex(e)
}
}
@@ -400,11 +400,11 @@ impl PrivateKey {
ret[1..33].copy_from_slice(&self.inner[..]);
let privkey = if self.compressed {
ret[33] = 1;
- base58::encode_check(&ret[..])
+ base58::Base58CkString::encode_unbounded(&ret[..])
} else {
- base58::encode_check(&ret[..33])
+ base58::Base58CkString::encode_unbounded(&ret[..33])
};
- fmt.write_str(&privkey)
+ fmt.write_str(privkey.as_str())
}
/// Get WIF encoding of this private key.
diff --git a/crypto/src/lib.rs b/crypto/src/lib.rs
index bcedd9555..b1f873394 100644
--- a/crypto/src/lib.rs
+++ b/crypto/src/lib.rs
@@ -12,35 +12,23 @@
extern crate alloc;
pub extern crate base58ck as base58;
-#[cfg(feature = "bls")]
pub extern crate dash_pkc;
pub extern crate dashcore_hashes as hashes;
pub extern crate secp256k1;
#[cfg(feature = "serde")]
pub extern crate serde;
-#[cfg(feature = "serde")]
-#[macro_use]
-pub(crate) mod serde_utils;
-
pub mod bls;
pub mod ecdsa;
pub mod eddsa;
pub mod key;
pub mod sighash;
-pub mod taproot;
-/// Implements `std::error::Error` for a type whose `Display` carries the message.
-macro_rules! impl_std_error {
- ($type:ty) => {
- impl std::error::Error for $type {}
- };
- ($type:ty, $field:ident) => {
- impl std::error::Error for $type {
- fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
- Some(&self.$field)
- }
- }
+/// Taproot signatures.
+pub mod taproot {
+ pub use bitcoin_crypto::taproot::{
+ ParseSignatureError, SerializedSignature, SigFromSliceError, Signature,
};
+
+ pub type Error = SigFromSliceError;
}
-pub(crate) use impl_std_error;
diff --git a/crypto/src/serde_utils.rs b/crypto/src/serde_utils.rs
deleted file mode 100644
index 41e5b8fe9..000000000
--- a/crypto/src/serde_utils.rs
+++ /dev/null
@@ -1,60 +0,0 @@
-//
-// This file is a part of rust-dashcore. Contains portions from rust-bitcoin.
-// SPDX-License-Identifier: CC0-1.0
-// See the accompanying file LICENSE or https://creativecommons.org/publicdomain/zero/1.0
-//
-
-//! Serde helpers.
-
-macro_rules! serde_string_serialize_impl {
- ($name:ty, $expecting:literal) => {
- impl $crate::serde::Serialize for $name {
- fn serialize(&self, serializer: S) -> Result
- where
- S: $crate::serde::Serializer,
- {
- serializer.collect_str(&self)
- }
- }
- };
-}
-
-macro_rules! serde_string_deserialize_impl {
- ($name:ty, $expecting:literal) => {
- impl<'de> $crate::serde::Deserialize<'de> for $name {
- fn deserialize(deserializer: D) -> Result<$name, D::Error>
- where
- D: $crate::serde::de::Deserializer<'de>,
- {
- use core::fmt::{self, Formatter};
-
- struct Visitor;
- impl<'de> $crate::serde::de::Visitor<'de> for Visitor {
- type Value = $name;
-
- fn expecting(&self, f: &mut Formatter) -> fmt::Result {
- f.write_str($expecting)
- }
-
- fn visit_str(self, v: &str) -> Result
- where
- E: $crate::serde::de::Error,
- {
- v.parse::<$name>().map_err(E::custom)
- }
- }
-
- deserializer.deserialize_str(Visitor)
- }
- }
- };
-}
-
-macro_rules! serde_string_impl {
- ($name:ty, $expecting:literal) => {
- $crate::serde_utils::serde_string_deserialize_impl!($name, $expecting);
- $crate::serde_utils::serde_string_serialize_impl!($name, $expecting);
- };
-}
-
-pub(crate) use {serde_string_deserialize_impl, serde_string_impl, serde_string_serialize_impl};
diff --git a/crypto/src/sighash.rs b/crypto/src/sighash.rs
index 0bbb45ef1..e35f53540 100644
--- a/crypto/src/sighash.rs
+++ b/crypto/src/sighash.rs
@@ -6,12 +6,7 @@
//! Signature hash types.
-use core::{fmt, str};
-use std::string::String;
-
-use hashes::{hash_newtype, sha256d, sha256t_hash_newtype, Hash as _};
-
-use crate::impl_std_error;
+use hashes::{hash_newtype, sha256d, sha256t_hash_newtype};
hash_newtype! {
/// Hash of a transaction according to the legacy signature algorithm.
@@ -33,135 +28,12 @@ sha256t_hash_newtype! {
pub struct TapSighash(_);
}
-/// Hashtype of an input's signature, encoded in the last byte of the signature.
-/// Fixed values so they can be cast as integer types for encoding.
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
-pub enum TapSighashType {
- /// 0x0: Used when not explicitly specified, defaults to [`TapSighashType::All`]
- Default = 0x00,
- /// 0x1: Sign all outputs.
- All = 0x01,
- /// 0x2: Sign no outputs --- anyone can choose the destination.
- None = 0x02,
- /// 0x3: Sign the output whose index matches this input's index. If none exists,
- /// sign the hash `0000000000000000000000000000000000000000000000000000000000000001`.
- /// (This rule is probably an unintentional C++ism, but it's consensus so we have
- /// to follow it.)
- Single = 0x03,
- /// 0x81: Sign all outputs but only this input.
- AllPlusAnyoneCanPay = 0x81,
- /// 0x82: Sign no outputs and only this input.
- NonePlusAnyoneCanPay = 0x82,
- /// 0x83: Sign one output and only this input (see `Single` for what "one output" means).
- SinglePlusAnyoneCanPay = 0x83,
-}
-#[cfg(feature = "serde")]
-crate::serde_utils::serde_string_impl!(TapSighashType, "a TapSighashType data");
-
-impl fmt::Display for TapSighashType {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- use TapSighashType::*;
-
- let s = match self {
- Default => "SIGHASH_DEFAULT",
- All => "SIGHASH_ALL",
- None => "SIGHASH_NONE",
- Single => "SIGHASH_SINGLE",
- AllPlusAnyoneCanPay => "SIGHASH_ALL|SIGHASH_ANYONECANPAY",
- NonePlusAnyoneCanPay => "SIGHASH_NONE|SIGHASH_ANYONECANPAY",
- SinglePlusAnyoneCanPay => "SIGHASH_SINGLE|SIGHASH_ANYONECANPAY",
- };
- f.write_str(s)
- }
-}
-
-impl str::FromStr for TapSighashType {
- type Err = SighashTypeParseError;
-
- fn from_str(s: &str) -> Result {
- use TapSighashType::*;
-
- match s {
- "SIGHASH_DEFAULT" => Ok(Default),
- "SIGHASH_ALL" => Ok(All),
- "SIGHASH_NONE" => Ok(None),
- "SIGHASH_SINGLE" => Ok(Single),
- "SIGHASH_ALL|SIGHASH_ANYONECANPAY" => Ok(AllPlusAnyoneCanPay),
- "SIGHASH_NONE|SIGHASH_ANYONECANPAY" => Ok(NonePlusAnyoneCanPay),
- "SIGHASH_SINGLE|SIGHASH_ANYONECANPAY" => Ok(SinglePlusAnyoneCanPay),
- _ => Err(SighashTypeParseError {
- unrecognized: s.to_owned(),
- }),
- }
- }
-}
-
-/// Hashtype of an input's signature, encoded in the last byte of the signature.
-///
-/// Fixed values so they can be cast as integer types for encoding (see also
-/// [`TapSighashType`]).
-#[derive(PartialEq, Eq, Debug, Copy, Clone, Hash)]
-pub enum EcdsaSighashType {
- /// 0x1: Sign all outputs.
- All = 0x01,
- /// 0x2: Sign no outputs --- anyone can choose the destination.
- None = 0x02,
- /// 0x3: Sign the output whose index matches this input's index. If none exists,
- /// sign the hash `0000000000000000000000000000000000000000000000000000000000000001`.
- /// (This rule is probably an unintentional C++ism, but it's consensus so we have
- /// to follow it.)
- Single = 0x03,
- /// 0x81: Sign all outputs but only this input.
- AllPlusAnyoneCanPay = 0x81,
- /// 0x82: Sign no outputs and only this input.
- NonePlusAnyoneCanPay = 0x82,
- /// 0x83: Sign one output and only this input (see `Single` for what "one output" means).
- SinglePlusAnyoneCanPay = 0x83,
-}
-#[cfg(feature = "serde")]
-crate::serde_utils::serde_string_impl!(EcdsaSighashType, "a EcdsaSighashType data");
-
-impl fmt::Display for EcdsaSighashType {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- use EcdsaSighashType::*;
-
- let s = match self {
- All => "SIGHASH_ALL",
- None => "SIGHASH_NONE",
- Single => "SIGHASH_SINGLE",
- AllPlusAnyoneCanPay => "SIGHASH_ALL|SIGHASH_ANYONECANPAY",
- NonePlusAnyoneCanPay => "SIGHASH_NONE|SIGHASH_ANYONECANPAY",
- SinglePlusAnyoneCanPay => "SIGHASH_SINGLE|SIGHASH_ANYONECANPAY",
- };
- f.write_str(s)
- }
-}
-
-impl str::FromStr for EcdsaSighashType {
- type Err = SighashTypeParseError;
-
- fn from_str(s: &str) -> Result {
- use EcdsaSighashType::*;
-
- match s {
- "SIGHASH_ALL" => Ok(All),
- "SIGHASH_NONE" => Ok(None),
- "SIGHASH_SINGLE" => Ok(Single),
- "SIGHASH_ALL|SIGHASH_ANYONECANPAY" => Ok(AllPlusAnyoneCanPay),
- "SIGHASH_NONE|SIGHASH_ANYONECANPAY" => Ok(NonePlusAnyoneCanPay),
- "SIGHASH_SINGLE|SIGHASH_ANYONECANPAY" => Ok(SinglePlusAnyoneCanPay),
- _ => Err(SighashTypeParseError {
- unrecognized: s.to_owned(),
- }),
- }
- }
-}
+pub use bitcoin_crypto::sighash::{
+ EcdsaSighashType, InvalidSighashTypeError, NonStandardSighashType, NonStandardSighashTypeError,
+ SighashTypeParseError, TapSighashType,
+};
/// Splits a sighash flag into the "real" flag and the `SIGHASH_ANYONECANPAY` bit.
-///
-/// A trait rather than an inherent method so that `dashcore`, which computes
-/// the signature hashes, can reach it without the split becoming part of the
-/// sighash types' own surface.
pub trait SplitAnyoneCanPay {
/// Splits the flag into the "real" sighash flag and the ANYONECANPAY boolean.
fn split_anyonecanpay_flag(self) -> (Self, bool)
@@ -172,7 +44,6 @@ pub trait SplitAnyoneCanPay {
impl SplitAnyoneCanPay for EcdsaSighashType {
fn split_anyonecanpay_flag(self) -> (EcdsaSighashType, bool) {
use EcdsaSighashType::*;
-
match self {
All => (All, false),
None => (None, false),
@@ -180,81 +51,16 @@ impl SplitAnyoneCanPay for EcdsaSighashType {
AllPlusAnyoneCanPay => (All, true),
NonePlusAnyoneCanPay => (None, true),
SinglePlusAnyoneCanPay => (Single, true),
- }
- }
-}
-
-impl EcdsaSighashType {
- /// Creates a [`EcdsaSighashType`] from a raw `u32`.
- ///
- /// **Note**: this replicates consensus behaviour, for current standardness rules correctness
- /// you probably want [`Self::from_standard`].
- ///
- /// This might cause unexpected behavior because it does not roundtrip. That is,
- /// `EcdsaSighashType::from_consensus(n) as u32 != n` for non-standard values of `n`. While
- /// verifying signatures, the user should retain the `n` and use it compute the signature hash
- /// message.
- pub fn from_consensus(n: u32) -> EcdsaSighashType {
- use EcdsaSighashType::*;
-
- // In Bitcoin Core, the SignatureHash function will mask the (int32) value with
- // 0x1f to (apparently) deactivate ACP when checking for SINGLE and NONE bits.
- // We however want to be matching also against on ACP-masked ALL, SINGLE, and NONE.
- // So here we re-activate ACP.
- let mask = 0x1f | 0x80;
- match n & mask {
- // "real" sighashes
- 0x01 => All,
- 0x02 => None,
- 0x03 => Single,
- 0x81 => AllPlusAnyoneCanPay,
- 0x82 => NonePlusAnyoneCanPay,
- 0x83 => SinglePlusAnyoneCanPay,
- // catchalls
- x if x & 0x80 == 0x80 => AllPlusAnyoneCanPay,
- _ => All,
- }
- }
-
- /// Creates a [`EcdsaSighashType`] from a raw `u32`.
- ///
- /// # Errors
- ///
- /// If `n` is a non-standard sighash value.
- pub fn from_standard(n: u32) -> Result {
- use EcdsaSighashType::*;
-
- match n {
- // Standard sighashes, see https://github.com/bitcoin/bitcoin/blob/b805dbb0b9c90dadef0424e5b3bf86ac308e103e/src/script/interpreter.cpp#L189-L198
- 0x01 => Ok(All),
- 0x02 => Ok(None),
- 0x03 => Ok(Single),
- 0x81 => Ok(AllPlusAnyoneCanPay),
- 0x82 => Ok(NonePlusAnyoneCanPay),
- 0x83 => Ok(SinglePlusAnyoneCanPay),
- non_standard => Err(NonStandardSighashType(non_standard)),
- }
- }
-
- /// Converts [`EcdsaSighashType`] to a `u32` sighash flag.
- ///
- /// The returned value is guaranteed to be a valid according to standardness rules.
- pub fn to_u32(self) -> u32 {
- self as u32
- }
-}
-
-impl From for TapSighashType {
- fn from(s: EcdsaSighashType) -> Self {
- use TapSighashType::*;
-
- match s {
- EcdsaSighashType::All => All,
- EcdsaSighashType::None => None,
- EcdsaSighashType::Single => Single,
- EcdsaSighashType::AllPlusAnyoneCanPay => AllPlusAnyoneCanPay,
- EcdsaSighashType::NonePlusAnyoneCanPay => NonePlusAnyoneCanPay,
- EcdsaSighashType::SinglePlusAnyoneCanPay => SinglePlusAnyoneCanPay,
+ // Core reads SINGLE/NONE from the low five bits and treats anything
+ // else as ALL. ANYONECANPAY is the 0x80 bit.
+ NonStandard(n) => {
+ let acp = n.to_u32() & 0x80 == 0x80;
+ match n.to_u32() & 0x1f {
+ 0x02 => (None, acp),
+ 0x03 => (Single, acp),
+ _ => (All, acp),
+ }
+ }
}
}
}
@@ -262,7 +68,6 @@ impl From for TapSighashType {
impl SplitAnyoneCanPay for TapSighashType {
fn split_anyonecanpay_flag(self) -> (TapSighashType, bool) {
use TapSighashType::*;
-
match self {
Default => (Default, false),
All => (All, false),
@@ -275,66 +80,20 @@ impl SplitAnyoneCanPay for TapSighashType {
}
}
-impl TapSighashType {
- /// Constructs a [`TapSighashType`] from a raw `u8`.
- ///
- /// # Errors
- ///
- /// Returns [`InvalidSighashTypeError`] when `hash_ty` names no sighash type.
- pub fn from_consensus_u8(hash_ty: u8) -> Result {
- use TapSighashType::*;
-
- Ok(match hash_ty {
- 0x00 => Default,
- 0x01 => All,
- 0x02 => None,
- 0x03 => Single,
- 0x81 => AllPlusAnyoneCanPay,
- 0x82 => NonePlusAnyoneCanPay,
- 0x83 => SinglePlusAnyoneCanPay,
- x => return Err(InvalidSighashTypeError(x as u32)),
- })
- }
-}
-
-/// Integer is not a consensus valid sighash type.
-#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub struct InvalidSighashTypeError(pub u32);
-
-impl fmt::Display for InvalidSighashTypeError {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "invalid sighash type {}", self.0)
- }
-}
-
-impl_std_error!(InvalidSighashTypeError);
-
-/// This type is consensus valid but an input including it would prevent the transaction from
-/// being relayed on today's Bitcoin network.
-#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub struct NonStandardSighashType(pub u32);
-
-impl fmt::Display for NonStandardSighashType {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "Non standard sighash type {}", self.0)
- }
-}
-
-impl_std_error!(NonStandardSighashType);
-
-/// Error returned for failure during parsing one of the sighash types.
-///
-/// This is currently returned for unrecognized sighash strings.
-#[derive(Debug, Clone)]
-pub struct SighashTypeParseError {
- /// The unrecognized string we attempted to parse.
- pub unrecognized: String,
-}
-
-impl fmt::Display for SighashTypeParseError {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "Unrecognized SIGHASH string '{}'", self.unrecognized)
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn split_follows_core() {
+ for n in 0..=0x1ffu32 {
+ let ty = match n & 0x1f {
+ 0x02 => EcdsaSighashType::None,
+ 0x03 => EcdsaSighashType::Single,
+ _ => EcdsaSighashType::All,
+ };
+ let got = EcdsaSighashType::from_consensus(n).split_anyonecanpay_flag();
+ assert_eq!(got, (ty, n & 0x80 != 0), "sighash flag {n:#04x}");
+ }
}
}
-
-impl_std_error!(SighashTypeParseError);
diff --git a/crypto/src/taproot.rs b/crypto/src/taproot.rs
deleted file mode 100644
index 74362831f..000000000
--- a/crypto/src/taproot.rs
+++ /dev/null
@@ -1,108 +0,0 @@
-//
-// This file is a part of rust-dashcore.
-// Portions written by Andrew Poelstra for rust-bitcoin.
-// SPDX-License-Identifier: CC0-1.0
-// See the accompanying file LICENSE or https://creativecommons.org/publicdomain/zero/1.0
-//
-
-//! Bitcoin taproot keys.
-//!
-//! This module provides taproot keys used in Bitcoin (including reexporting secp256k1 keys).
-//!
-
-use core::fmt;
-
-use internals::write_err;
-#[cfg(feature = "serde")]
-use serde::{Deserialize, Serialize};
-
-pub use secp256k1::{self};
-
-use crate::sighash::TapSighashType;
-
-/// A BIP340-341 serialized taproot signature with the corresponding hash type.
-#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
-#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
-pub struct Signature {
- /// The underlying schnorr signature
- pub sig: secp256k1::schnorr::Signature,
- /// The corresponding hash type
- pub hash_ty: TapSighashType,
-}
-
-impl Signature {
- /// Deserialize from slice
- pub fn from_slice(sl: &[u8]) -> Result {
- let Some((sig, hash_ty)) =
- sl.split_first_chunk::<{ secp256k1::constants::SCHNORR_SIGNATURE_SIZE }>()
- else {
- return Err(Error::InvalidSignatureSize(sl.len()));
- };
- let hash_ty = match hash_ty {
- // Default sighash type is implied by the absence of a trailing byte.
- [] => TapSighashType::Default,
- [hash_ty] => TapSighashType::from_consensus_u8(*hash_ty)
- .map_err(|_| Error::InvalidSighashType(*hash_ty))?,
- _ => return Err(Error::InvalidSignatureSize(sl.len())),
- };
- Ok(Signature {
- sig: secp256k1::schnorr::Signature::from_byte_array(*sig),
- hash_ty,
- })
- }
-
- /// Serialize Signature
- pub fn to_vec(self) -> Vec {
- // TODO: add support to serialize to a writer to SerializedSig
- let mut ser_sig = self.sig.as_ref().to_vec();
- if self.hash_ty == TapSighashType::Default {
- // default sighash type, don't add extra sighash byte
- } else {
- ser_sig.push(self.hash_ty as u8);
- }
- ser_sig
- }
-}
-
-/// A taproot sig related error.
-#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
-#[non_exhaustive]
-pub enum Error {
- /// Base58 encoding error
- InvalidSighashType(u8),
- /// Signature has valid size but does not parse correctly
- Secp256k1(secp256k1::Error),
- /// Invalid taproot signature size
- InvalidSignatureSize(usize),
-}
-
-impl fmt::Display for Error {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match *self {
- Error::InvalidSighashType(hash_ty) => {
- write!(f, "invalid signature hash type {}", hash_ty)
- }
- Error::Secp256k1(ref e) => {
- write_err!(f, "taproot signature has correct len but is malformed"; e)
- }
- Error::InvalidSignatureSize(sz) => write!(f, "invalid taproot signature size: {}", sz),
- }
- }
-}
-
-impl std::error::Error for Error {
- fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
- use self::Error::*;
-
- match self {
- Secp256k1(e) => Some(e),
- InvalidSighashType(_) | InvalidSignatureSize(_) => None,
- }
- }
-}
-
-impl From for Error {
- fn from(e: secp256k1::Error) -> Error {
- Error::Secp256k1(e)
- }
-}
diff --git a/dash-network-seeds/Cargo.toml b/dash-network-seeds/Cargo.toml
index a5ce9bff8..0eed93018 100644
--- a/dash-network-seeds/Cargo.toml
+++ b/dash-network-seeds/Cargo.toml
@@ -1,11 +1,12 @@
[package]
name = "dash-network-seeds"
-version = { workspace = true }
-edition = "2024"
-authors = ["Dash Core Team"]
description = "Hardcoded masternode IP seed lists for Dash mainnet and testnet, differentiated by regular/evo type. Refreshed weekly via CI from the live Dash P2P network."
-license = "MIT"
-repository = "https://github.com/dashpay/rust-dashcore"
+authors.workspace = true
+edition.workspace = true
+license.workspace = true
+repository.workspace = true
+rust-version.workspace = true
+version.workspace = true
[dependencies]
dash-network = { path = "../dash-network" }
diff --git a/dash-network/Cargo.toml b/dash-network/Cargo.toml
index 9aeaea805..44ecb63b3 100644
--- a/dash-network/Cargo.toml
+++ b/dash-network/Cargo.toml
@@ -1,11 +1,12 @@
[package]
name = "dash-network"
-version = { workspace = true }
-edition = "2024"
-authors = ["Dash Core Team"]
description = "The `Network` enum and its pure helpers (magic bytes, activation heights, default P2P ports) extracted from `dashcore` into a minimal-dependency crate so that lightweight consumers can depend on it without pulling in the full protocol library."
-license = "MIT"
-repository = "https://github.com/dashpay/rust-dashcore"
+authors.workspace = true
+edition.workspace = true
+license.workspace = true
+repository.workspace = true
+rust-version.workspace = true
+version.workspace = true
[lib]
name = "dash_network"
@@ -21,7 +22,7 @@ bincode = ["dep:bincode", "dep:bincode_derive"]
ffi = []
[dependencies]
-serde = { version = "1.0.219", default-features = false, features = ["derive"], optional = true }
+serde = { workspace = true, features = ["derive"], optional = true }
bincode = { workspace = true, optional = true }
bincode_derive = { workspace = true, optional = true }
diff --git a/dash-spv-bench/Cargo.toml b/dash-spv-bench/Cargo.toml
index 58aa104b0..e83c004d9 100644
--- a/dash-spv-bench/Cargo.toml
+++ b/dash-spv-bench/Cargo.toml
@@ -1,9 +1,12 @@
[package]
name = "dash-spv-bench"
-version = { workspace = true }
edition = "2021"
-license = "MIT"
publish = false
+authors.workspace = true
+license.workspace = true
+repository.workspace = true
+rust-version.workspace = true
+version.workspace = true
[dependencies]
dash-spv = { path = "../dash-spv" }
diff --git a/dash-spv-ffi/Cargo.toml b/dash-spv-ffi/Cargo.toml
index 19ada2d0e..023995f15 100644
--- a/dash-spv-ffi/Cargo.toml
+++ b/dash-spv-ffi/Cargo.toml
@@ -1,11 +1,12 @@
[package]
name = "dash-spv-ffi"
-version = { workspace = true }
-edition = "2021"
-authors = ["Dash Core Developers"]
-license = "MIT"
description = "FFI bindings for the Dash SPV client"
-repository = "https://github.com/dashpay/rust-dashcore"
+edition = "2021"
+authors.workspace = true
+license.workspace = true
+repository.workspace = true
+rust-version.workspace = true
+version.workspace = true
[lib]
name = "dash_spv_ffi"
@@ -16,7 +17,7 @@ dash-spv = { path = "../dash-spv" }
dashcore = { path = "../dash" }
dash-network = { path = "../dash-network", features = ["ffi"] }
tokio = { version = "1", features = ["full"] }
-hex = "0.4"
+hex = { workspace = true }
tracing = "0.1"
# Use key-wallet-ffi for all wallet-related FFI types
key-wallet-ffi = { path = "../key-wallet-ffi" }
diff --git a/dash-spv-ffi/README.md b/dash-spv-ffi/README.md
index 747c40696..bd782c34d 100644
--- a/dash-spv-ffi/README.md
+++ b/dash-spv-ffi/README.md
@@ -109,4 +109,4 @@ The FFI bindings are thread-safe. The client uses internal synchronization to en
## License
-MIT
+CC0-1.0
diff --git a/dash-spv/Cargo.toml b/dash-spv/Cargo.toml
index ad0e10cb7..cfcc08aba 100644
--- a/dash-spv/Cargo.toml
+++ b/dash-spv/Cargo.toml
@@ -1,12 +1,12 @@
[package]
name = "dash-spv"
-version = { workspace = true }
-edition = "2021"
-authors = ["Dash Core Team"]
description = "Dash SPV (Simplified Payment Verification) client library"
-license = "MIT"
-repository = "https://github.com/dashpay/rust-dashcore"
-rust-version = "1.89"
+edition = "2021"
+authors.workspace = true
+license.workspace = true
+repository.workspace = true
+rust-version.workspace = true
+version.workspace = true
[dependencies]
# Core Dash libraries
@@ -25,13 +25,13 @@ tokio = { version = "1.0", features = ["full"] }
tokio-util = "0.7"
tokio-stream = { version = "0.1", features = ["sync"] }
async-trait = "0.1"
-futures = "0.3"
+futures = { workspace = true }
# Error handling
thiserror = "1.0"
# Serialization
-serde = { version = "1.0", features = ["derive"] }
+serde = { workspace = true, features = ["std", "derive"] }
serde_json = "1.0"
# Logging
@@ -42,10 +42,10 @@ chrono = "0.4.20"
# Utilities
rand = "0.9"
-hex = "0.4"
+hex = { workspace = true }
# Parallelization
-rayon = "1.11"
+rayon = { workspace = true }
# Test utilities (optional)
tempfile = { version = "3.0", optional = true }
@@ -60,7 +60,7 @@ key-wallet-manager = { path = "../key-wallet-manager", features = ["test-utils"]
criterion = { version = "0.8.1", features = ["async_tokio"] }
tempfile = "3.0"
tokio-test = "0.4"
-hex = "0.4"
+hex = { workspace = true }
test-case = "3.3"
[[bench]]
diff --git a/dash-spv/README.md b/dash-spv/README.md
index 247f93c75..1663fe68e 100644
--- a/dash-spv/README.md
+++ b/dash-spv/README.md
@@ -133,3 +133,7 @@ See [docs/PEER_REPUTATION_SYSTEM.md](docs/PEER_REPUTATION_SYSTEM.md) for detaile
6. **Performance**: Async design for better resource utilization
This refactoring transforms an example script into a production-ready library suitable for integration into wallets, explorers, and other Dash applications requiring SPV functionality.
+
+## License
+
+CC0-1.0
diff --git a/dash/Cargo.toml b/dash/Cargo.toml
index 3d1e40e9b..a2c576ecf 100644
--- a/dash/Cargo.toml
+++ b/dash/Cargo.toml
@@ -1,21 +1,20 @@
[package]
name = "dashcore"
-version = { workspace = true }
authors = [
"Samuel Westrich ",
"Anton Suprunchuk ",
"Dmitrii Golubev "
]
-license = "CC0-1.0"
-homepage = "https://github.com/dashevo/rust-dashcore/"
-repository = "https://github.com/dashevo/rust-dashcore/"
-documentation = "https://dashcore.readme.io/docs"
description = "General purpose library for using and interoperating with Dash Core payment chain."
categories = ["cryptography::cryptocurrencies"]
keywords = [ "crypto", "dash" ]
readme = "../README.md"
exclude = ["tests", "contrib"]
-edition = "2024"
+edition.workspace = true
+license.workspace = true
+repository.workspace = true
+rust-version.workspace = true
+version.workspace = true
# Please don't forget to add relevant features to docs.rs below
[features]
@@ -47,14 +46,14 @@ dashcore_hashes = { path = "../hashes" }
dashcore-crypto = { path = "../crypto" }
dash-network = { path = "../dash-network" }
dash-types = { workspace = true, features = ["codec"] }
-secp256k1 = { version = "0.33.1" }
-serde = { version = "1.0.219", default-features = false, features = [ "derive", "alloc", "rc" ], optional = true }
+secp256k1 = { workspace = true }
+serde = { workspace = true, features = ["derive", "alloc", "rc"], optional = true }
base64 = { version = "0.22", optional = true }
bitcoinconsensus = { version = "0.20.2-0.5.0", default-features = false, optional = true }
-hex_lit = "0.1.1"
+hex_lit = { workspace = true }
anyhow = { version= "1.0" }
-hex = { version= "0.4" }
+hex = { workspace = true }
bincode = { workspace = true, optional = true }
bincode_derive = { workspace = true, optional = true }
blake3 = "1.8.1"
@@ -66,7 +65,7 @@ tracing = "0.1"
serde_json = "1.0.140"
serde_test = "1.0.177"
serde_derive = "1.0.219"
-secp256k1 = { features = [ "recovery", "rand" ], version = "0.33.1" }
+secp256k1 = { workspace = true, features = ["recovery", "rand"] }
bincode = { workspace = true, features = ["serde"] }
assert_matches = "1.5.0"
dashcore = { path = ".", features = ["core-block-hash-use-x11", "message_verification", "quorum_validation", "signer"] }
diff --git a/dash/src/address.rs b/dash/src/address.rs
index 08f2b6b7f..bff742223 100644
--- a/dash/src/address.rs
+++ b/dash/src/address.rs
@@ -74,7 +74,7 @@ use crate::taproot::{TapNodeHash, TapTweak};
#[non_exhaustive]
pub enum Error {
/// Base58 encoding error.
- Base58(base58::Error),
+ Base58(base58::DecodeCheckError),
/// The address version byte was not one we recognise.
InvalidAddressVersion(u8),
/// The base58 decoded correctly but the payload was the wrong length.
@@ -178,8 +178,8 @@ impl std::error::Error for Error {
}
#[doc(hidden)]
-impl From for Error {
- fn from(e: base58::Error) -> Error {
+impl From for Error {
+ fn from(e: base58::DecodeCheckError) -> Error {
Error::Base58(e)
}
}
@@ -649,13 +649,13 @@ impl<'a> fmt::Display for AddressEncoding<'a> {
let mut prefixed = [0; 21];
prefixed[0] = self.p2pkh_prefix;
prefixed[1..].copy_from_slice(&hash[..]);
- base58::encode_check_to_fmt(fmt, &prefixed[..])
+ fmt.write_str(base58::Base58CkString::encode_unbounded(&prefixed[..]).as_str())
}
Payload::ScriptHash(hash) => {
let mut prefixed = [0; 21];
prefixed[0] = self.p2sh_prefix;
prefixed[1..].copy_from_slice(&hash[..]);
- base58::encode_check_to_fmt(fmt, &prefixed[..])
+ fmt.write_str(base58::Base58CkString::encode_unbounded(&prefixed[..]).as_str())
}
Payload::WitnessProgram(witness_prog) => {
let (version, prog) = (witness_prog.version(), witness_prog.program());
diff --git a/dash/src/blockdata/script/owned.rs b/dash/src/blockdata/script/owned.rs
index 4df712ecf..77544a4e5 100644
--- a/dash/src/blockdata/script/owned.rs
+++ b/dash/src/blockdata/script/owned.rs
@@ -168,7 +168,7 @@ impl ScriptBuf {
}
/// Creates a [`ScriptBuf`] from a hex string.
- pub fn from_hex(s: &str) -> Result {
+ pub fn from_hex(s: &str) -> Result {
use hashes::hex::FromHex;
let v = Vec::from_hex(s)?;
diff --git a/dash/src/blockdata/transaction/outpoint.rs b/dash/src/blockdata/transaction/outpoint.rs
index 46095882f..ec042542f 100644
--- a/dash/src/blockdata/transaction/outpoint.rs
+++ b/dash/src/blockdata/transaction/outpoint.rs
@@ -58,7 +58,7 @@ impl From for [u8; 36] {
fn from(value: OutPoint) -> Self {
let mut bytes = [0u8; 36];
// Serialize the txid
- let txid_bytes: [u8; 32] = value.txid.to_raw_hash().into(); // Assuming to_raw_hash() returns the hash as sha256d::Hash, which can be converted into [u8; 32]
+ let txid_bytes: [u8; 32] = hashes::Hash::to_byte_array(value.txid.to_raw_hash()); // Assuming to_raw_hash() returns the hash as sha256d::Hash, which can be converted into [u8; 32]
bytes[..32].copy_from_slice(&txid_bytes);
// Serialize the vout
let vout_bytes = value.vout.to_le_bytes();
@@ -152,7 +152,7 @@ impl TryInto> for OutPoint {
#[non_exhaustive]
pub enum ParseOutPointError {
/// Error in TXID part.
- Txid(hashes::hex::Error),
+ Txid(hashes::hex::HexToArrayError),
/// Error in vout part.
Vout(crate::error::ParseIntError),
/// Error in general format.
diff --git a/dash/src/blockdata/witness.rs b/dash/src/blockdata/witness.rs
index 9201318a1..6681b4379 100644
--- a/dash/src/blockdata/witness.rs
+++ b/dash/src/blockdata/witness.rs
@@ -285,7 +285,7 @@ impl Witness {
// Note that a maximal length ECDSA signature is 72 bytes, plus the sighash type makes 73
let mut sig = [0; 73];
sig[..signature.len()].copy_from_slice(signature);
- sig[signature.len()] = hash_type as u8;
+ sig[signature.len()] = hash_type.to_consensus_u8();
self.push(&sig[..signature.len() + 1]);
}
@@ -428,8 +428,8 @@ impl<'de> serde::Deserialize<'de> for Witness {
self,
mut a: A,
) -> Result {
- use hashes::hex::Error::*;
use hashes::hex::FromHex;
+ use hashes::hex::HexToBytesError::*;
use serde::de::{self, Unexpected};
let mut ret = match a.size_hint() {
@@ -439,22 +439,21 @@ impl<'de> serde::Deserialize<'de> for Witness {
while let Some(elem) = a.next_element::()? {
let vec = Vec::::from_hex(&elem).map_err(|e| match e {
- InvalidChar(b) => match core::char::from_u32(b.into()) {
- Some(c) => de::Error::invalid_value(
- Unexpected::Char(c),
- &"a valid hex character",
- ),
- None => de::Error::invalid_value(
- Unexpected::Unsigned(b.into()),
- &"a valid hex character",
- ),
- },
- OddLengthString(len) => {
- de::Error::invalid_length(len, &"an even length string")
+ InvalidChar(e) => {
+ let b = e.invalid_char();
+ match core::char::from_u32(b.into()) {
+ Some(c) => de::Error::invalid_value(
+ Unexpected::Char(c),
+ &"a valid hex character",
+ ),
+ None => de::Error::invalid_value(
+ Unexpected::Unsigned(b.into()),
+ &"a valid hex character",
+ ),
+ }
}
- InvalidLength(expected, got) => {
- let exp = format!("expected length: {}", expected);
- de::Error::invalid_length(got, &exp.as_str())
+ OddLengthString(e) => {
+ de::Error::invalid_length(e.length(), &"an even length string")
}
})?;
ret.push(vec);
diff --git a/dash/src/consensus/encode.rs b/dash/src/consensus/encode.rs
index a95aaa326..ec2b9bcde 100644
--- a/dash/src/consensus/encode.rs
+++ b/dash/src/consensus/encode.rs
@@ -107,7 +107,7 @@ pub enum Error {
/// The script type was non standard
NonStandardScriptPayout(ScriptBuf),
/// Hex error
- Hex(hashes::hex::Error),
+ Hex(hashes::hex::HexToArrayError),
/// Address error
Address(address::Error),
/// Invalid enum value
diff --git a/dash/src/consensus/serde.rs b/dash/src/consensus/serde.rs
index d1a1bc694..0cc35965c 100644
--- a/dash/src/consensus/serde.rs
+++ b/dash/src/consensus/serde.rs
@@ -103,19 +103,21 @@ pub mod hex {
/// Error returned when a hex string decoder can't be created.
#[derive(Debug)]
- pub struct DecodeInitError(hashes::hex::Error);
+ pub struct DecodeInitError(hashes::hex::OddLengthStringError);
/// Error returned when a hex string contains invalid characters.
#[derive(Debug)]
- pub struct DecodeError(hashes::hex::Error);
+ pub struct DecodeError(hashes::hex::InvalidCharError);
/// Hex decoder state.
- pub struct Decoder<'a>(hashes::hex::HexIterator<'a>);
+ pub struct Decoder<'a>(
+ Box> + 'a>,
+ );
impl<'a> Decoder<'a> {
fn new(s: &'a str) -> Result {
- match hashes::hex::HexIterator::new(s) {
- Ok(iter) => Ok(Decoder(iter)),
+ match hashes::hex::HexToBytesIter::new(s) {
+ Ok(iter) => Ok(Decoder(Box::new(iter))),
Err(error) => Err(DecodeInitError(error)),
}
}
@@ -141,32 +143,21 @@ pub mod hex {
impl super::IntoDeError for DecodeInitError {
fn into_de_error(self) -> E {
- use hashes::hex::Error;
-
- match self.0 {
- Error::OddLengthString(len) => {
- E::invalid_length(len, &"an even number of ASCII-encoded hex digits")
- }
- error => panic!("unexpected error: {:?}", error),
- }
+ E::invalid_length(self.0.length(), &"an even number of ASCII-encoded hex digits")
}
}
impl super::IntoDeError for DecodeError {
fn into_de_error(self) -> E {
- use hashes::hex::Error;
use serde::de::Unexpected;
const EXPECTED_CHAR: &str = "an ASCII-encoded hex digit";
- match self.0 {
- Error::InvalidChar(c) if c.is_ascii() => {
- E::invalid_value(Unexpected::Char(c as _), &EXPECTED_CHAR)
- }
- Error::InvalidChar(c) => {
- E::invalid_value(Unexpected::Unsigned(c.into()), &EXPECTED_CHAR)
- }
- error => panic!("unexpected error: {:?}", error),
+ let c = self.0.invalid_char();
+ if c.is_ascii() {
+ E::invalid_value(Unexpected::Char(c as _), &EXPECTED_CHAR)
+ } else {
+ E::invalid_value(Unexpected::Unsigned(c.into()), &EXPECTED_CHAR)
}
}
}
diff --git a/dash/src/crypto/sighash.rs b/dash/src/crypto/sighash.rs
index 9c7886ad3..2440d1cf6 100644
--- a/dash/src/crypto/sighash.rs
+++ b/dash/src/crypto/sighash.rs
@@ -19,7 +19,8 @@ use hashes::{Hash, sha256, sha256d};
pub use dashcore_crypto::sighash::SplitAnyoneCanPay;
pub use dashcore_crypto::sighash::{
EcdsaSighashType, InvalidSighashTypeError, LegacySighash, NonStandardSighashType,
- SegwitV0Sighash, SighashTypeParseError, TapSighash, TapSighashTag, TapSighashType,
+ NonStandardSighashTypeError, SegwitV0Sighash, SighashTypeParseError, TapSighash, TapSighashTag,
+ TapSighashType,
};
use crate::blockdata::transaction::txin::TxIn;
@@ -113,7 +114,7 @@ pub struct ScriptPath<'s> {
}
/// Possible errors in computing the signature message.
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+#[derive(Clone, PartialEq, Eq, Debug)]
#[non_exhaustive]
pub enum Error {
/// Could happen only by using `*_encode_signing_*` methods with custom writers, engines writers
@@ -153,7 +154,7 @@ pub enum Error {
WrongAnnex,
/// Invalid Sighash type.
- InvalidSighashType(u32),
+ InvalidSighashType(InvalidSighashTypeError),
}
impl fmt::Display for Error {
@@ -193,8 +194,8 @@ impl fmt::Display for Error {
WrongAnnex => {
write!(f, "Annex must be at least one byte long and the first bytes must be `0x50`")
}
- InvalidSighashType(hash_ty) => {
- write!(f, "Invalid taproot signature hash type : {} ", hash_ty)
+ InvalidSighashType(e) => {
+ write!(f, "Invalid taproot signature hash type : {} ", e)
}
}
}
@@ -291,7 +292,7 @@ impl<'s> From> for TapLeafHash {
impl From for Error {
fn from(e: InvalidSighashTypeError) -> Self {
- Error::InvalidSighashType(e.0)
+ Error::InvalidSighashType(e)
}
}
@@ -881,8 +882,9 @@ impl<'a> Encodable for Annex<'a> {
}
fn is_invalid_use_of_sighash_single(sighash: u32, input_index: usize, output_len: usize) -> bool {
- let ty = EcdsaSighashType::from_consensus(sighash);
- ty == EcdsaSighashType::Single && input_index >= output_len
+ // Core checks `(nHashType & 0x1f) == SIGHASH_SINGLE`, so ANYONECANPAY
+ // counts as well.
+ EcdsaSighashType::from_consensus(sighash).is_single() && input_index >= output_len
}
#[cfg(test)]
@@ -902,8 +904,6 @@ mod tests {
#[test]
fn sighash_single_bug() {
- const SIGHASH_SINGLE: u32 = 3;
-
// We need a tx with more inputs than outputs.
let tx = Transaction {
version: 1,
@@ -915,10 +915,15 @@ mod tests {
let script = ScriptBuf::new();
let cache = SighashCache::new(&tx);
- let got = cache.legacy_signature_hash(1, &script, SIGHASH_SINGLE).expect("sighash");
- let want = LegacySighash::from_slice(&UINT256_ONE).unwrap();
+ let one = LegacySighash::from_slice(&UINT256_ONE).unwrap();
- assert_eq!(got, want)
+ // Low five bits say SINGLE, with or without ANYONECANPAY.
+ for flag in [0x03, 0x23, 0x83, 0xa3] {
+ let got = cache.legacy_signature_hash(1, &script, flag).expect("sighash");
+ assert_eq!(got, one, "{flag:#x}");
+ }
+ let got = cache.legacy_signature_hash(1, &script, 0x01).expect("sighash");
+ assert_ne!(got, one);
}
#[ignore]
@@ -1461,7 +1466,7 @@ mod tests {
for s in sht_mistakes {
assert_eq!(
TapSighashType::from_str(s).unwrap_err().to_string(),
- format!("Unrecognized SIGHASH string '{}'", s)
+ format!("failed to parse '{}' as SIGHASH string", s)
);
}
}
diff --git a/dash/src/hash_types.rs b/dash/src/hash_types.rs
index 7dc1dbc54..7f359c0ee 100644
--- a/dash/src/hash_types.rs
+++ b/dash/src/hash_types.rs
@@ -75,7 +75,7 @@ mod newtypes {
#[cfg(feature = "core-block-hash-use-x11")]
use hashes::hash_x11;
- use hashes::hex::Error;
+ use hashes::hex::HexToArrayError as Error;
use hashes::{Hash, hash_newtype, hash_newtype_no_ord, hash160, sha256, sha256d};
use crate::alloc::string::ToString;
@@ -400,6 +400,7 @@ mod tests {
use super::*;
use crate::consensus::{deserialize, serialize};
+ use dashcore_crypto::eddsa::EddsaPkBytes;
use serde_derive::{Deserialize, Serialize};
@@ -431,11 +432,10 @@ mod tests {
/// A node id decoded from the wire must compare equal to one derived from
/// the matching Ed25519 public key — the mismatch reported in issue #887.
- #[cfg(feature = "eddsa")]
#[test]
fn decoded_wire_id_matches_derived_id() {
let public_key = [7u8; 32];
- let derived = dashcore_crypto::eddsa::EddsaPkBytes::from_bytes(public_key).hash();
+ let derived = EddsaPkHash::from(EddsaPkBytes::from_bytes(public_key));
let decoded: EddsaPkHash = deserialize(&derived.to_bytes()).expect("decode node id");
assert_eq!(decoded, derived);
diff --git a/dash/src/internal_macros.rs b/dash/src/internal_macros.rs
index 55fb282a4..2c893869d 100644
--- a/dash/src/internal_macros.rs
+++ b/dash/src/internal_macros.rs
@@ -104,26 +104,15 @@ macro_rules! impl_bytes_newtype {
}
impl $crate::hashes::hex::FromHex for $t {
- fn from_byte_iter(iter: I) -> Result
- where
- I: core::iter::Iterator- >
- + core::iter::ExactSizeIterator
- + core::iter::DoubleEndedIterator,
- {
- if iter.len() == $len {
- let mut ret = [0; $len];
- for (n, byte) in iter.enumerate() {
- ret[n] = byte?;
- }
- Ok($t(ret))
- } else {
- Err($crate::hashes::hex::Error::InvalidLength(2 * $len, 2 * iter.len()))
- }
+ type Error = $crate::hashes::hex::HexToArrayError;
+
+ fn from_hex(s: &str) -> Result {
+ Ok($t(<[u8; $len] as $crate::hashes::hex::FromHex>::from_hex(s)?))
}
}
impl core::str::FromStr for $t {
- type Err = $crate::hashes::hex::Error;
+ type Err = $crate::hashes::hex::HexToArrayError;
fn from_str(s: &str) -> Result {
$crate::hashes::hex::FromHex::from_hex(s)
}
diff --git a/dash/src/sml/masternode_list/merkle_roots.rs b/dash/src/sml/masternode_list/merkle_roots.rs
index ba12c7680..1d4e4bcbf 100644
--- a/dash/src/sml/masternode_list/merkle_roots.rs
+++ b/dash/src/sml/masternode_list/merkle_roots.rs
@@ -161,7 +161,7 @@ impl MasternodeList {
pro_tx_hashes.sort_by_key(|&s| s.reverse());
pro_tx_hashes
.into_iter()
- .map(|hash| self.masternodes[hash].entry_hash)
+ .map(|hash| self.masternodes[hash].entry_hash.to_raw_hash())
.collect::>()
})
}
diff --git a/dash/src/sml/masternode_list_entry/qualified_masternode_list_entry.rs b/dash/src/sml/masternode_list_entry/qualified_masternode_list_entry.rs
index 67a9707e0..10bb71776 100644
--- a/dash/src/sml/masternode_list_entry/qualified_masternode_list_entry.rs
+++ b/dash/src/sml/masternode_list_entry/qualified_masternode_list_entry.rs
@@ -2,9 +2,9 @@ use std::cmp::Ordering;
#[cfg(feature = "bincode")]
use bincode::{Decode, Encode};
-use hashes::{Hash, sha256d};
+use hashes::Hash;
-use crate::hash_types::ConfirmedHashHashedWithProRegTx;
+use crate::hash_types::{ConfirmedHashHashedWithProRegTx, Sha256dHash};
use crate::sml::masternode_list_entry::MasternodeListEntry;
/// A structured representation of a masternode list entry with a cached entry hash and a confirmed
@@ -17,7 +17,7 @@ pub struct QualifiedMasternodeListEntry {
/// The underlying masternode list entry
pub masternode_list_entry: MasternodeListEntry,
/// The computed entry hash
- pub entry_hash: sha256d::Hash,
+ pub entry_hash: Sha256dHash,
/// The confirmed hash hashed with the pro_reg_tx if the confirmed hash is set
pub confirmed_hash_hashed_with_pro_reg_tx: Option,
}
@@ -36,7 +36,7 @@ impl PartialOrd for QualifiedMasternodeListEntry {
impl From for QualifiedMasternodeListEntry {
fn from(masternode_list_entry: MasternodeListEntry) -> Self {
- let entry_hash = masternode_list_entry.calculate_entry_hash();
+ let entry_hash = Sha256dHash::from_raw_hash(masternode_list_entry.calculate_entry_hash());
let confirmed_hash_hashed_with_pro_reg_tx =
masternode_list_entry.confirmed_hash.map(|confirmed_hash| {
ConfirmedHashHashedWithProRegTx::hash(
diff --git a/dash/src/sml/message_verification_error.rs b/dash/src/sml/message_verification_error.rs
index 6a64f73c9..05f82cb63 100644
--- a/dash/src/sml/message_verification_error.rs
+++ b/dash/src/sml/message_verification_error.rs
@@ -1,6 +1,6 @@
+use crate::hash_types::Sha256dHash;
#[cfg(feature = "bincode")]
use bincode::{Decode, Encode};
-use hashes::sha256d;
use thiserror::Error;
use crate::QuorumHash;
@@ -34,7 +34,7 @@ pub enum MessageVerificationError {
)]
ThresholdSignatureNotValid(
Box,
- Box,
+ Box,
Box,
QuorumHash,
LLMQType,
diff --git a/dash/src/sml/quorum_entry/verify_message.rs b/dash/src/sml/quorum_entry/verify_message.rs
index c95095f8c..324ee78ef 100644
--- a/dash/src/sml/quorum_entry/verify_message.rs
+++ b/dash/src/sml/quorum_entry/verify_message.rs
@@ -1,4 +1,4 @@
-use hashes::{Hash, sha256d};
+use hashes::Hash;
use crate::bls_sig_utils::{BLSSignature, BlsScheme};
use crate::sml::message_verification_error::MessageVerificationError;
@@ -48,7 +48,7 @@ impl QualifiedQuorumEntry {
.map_err(|e| {
MessageVerificationError::ThresholdSignatureNotValid(
Box::new(signature),
- Box::new(sha256d::Hash::from_byte_array(message_digest)),
+ Box::new(crate::hash_types::Sha256dHash::from_byte_array(message_digest)),
Box::new(self.quorum_entry.quorum_public_key),
self.quorum_entry.quorum_hash,
self.quorum_entry.llmq_type,
diff --git a/dash/src/taproot.rs b/dash/src/taproot.rs
index b9a2b9a71..937a82484 100644
--- a/dash/src/taproot.rs
+++ b/dash/src/taproot.rs
@@ -1778,6 +1778,7 @@ mod test {
#[cfg(feature = "serde")]
use {
crate::internal_macros::hex,
+ serde::{Deserialize, Serialize},
serde_test::Configure,
serde_test::{Token, assert_tokens},
};
@@ -2137,6 +2138,44 @@ mod test {
assert_eq!(leaf_version, leaf_version2);
}
+ /// A tagged hash must accept every shape `ContentDeserializer` can replay,
+ /// which is why `sha256t_hash_newtype!` routes through our `hash_newtype!`
+ /// rather than upstream's.
+ #[test]
+ #[cfg(feature = "serde")]
+ fn serde_round_trip_through_internally_tagged_enum() {
+ #[derive(Debug, PartialEq, Serialize, Deserialize)]
+ struct WithNodeHash {
+ node: TapNodeHash,
+ }
+
+ #[derive(Debug, PartialEq, Serialize, Deserialize)]
+ #[serde(tag = "type")]
+ enum Tagged {
+ A(WithNodeHash),
+ }
+
+ let bytes = hex!("03ba2a4dcd914fed29a1c630c7e811271b081a0e2f2f52cf1c197583dfd46c1b");
+ let original = Tagged::A(WithNodeHash {
+ node: TapNodeHash::from_slice(&bytes).unwrap(),
+ });
+
+ let value = serde_json::to_value(&original).unwrap();
+ let restored: Tagged = serde_json::from_value(value).unwrap();
+ assert_eq!(original, restored);
+
+ let mut object = serde_json::Map::new();
+ object.insert("type".into(), serde_json::Value::String("A".into()));
+ object.insert(
+ "node".into(),
+ serde_json::Value::Array(
+ bytes.iter().map(|b| serde_json::Value::Number((*b).into())).collect(),
+ ),
+ );
+ let from_seq: Tagged = serde_json::from_value(serde_json::Value::Object(object)).unwrap();
+ assert_eq!(from_seq, original);
+ }
+
#[test]
#[cfg(feature = "serde")]
fn test_merkle_branch_serde() {
diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml
index 77f84f70d..dc544a36f 100644
--- a/fuzz/Cargo.toml
+++ b/fuzz/Cargo.toml
@@ -1,10 +1,12 @@
[package]
name = "dash-fuzz"
-edition = "2024"
-version = { workspace = true }
authors = ["Generated by fuzz/generate-files.sh"]
-license = "CC0-1.0"
publish = false
+edition.workspace = true
+license.workspace = true
+repository.workspace = true
+rust-version.workspace = true
+version.workspace = true
[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = ["cfg(fuzzing)"] }
@@ -16,7 +18,7 @@ cargo-fuzz = true
honggfuzz = { version = "0.5", default-features = false }
dashcore = { path = "../dash", features = [ "serde" ] }
-serde = { version = "1.0.219", features = [ "derive" ] }
+serde = { workspace = true, features = ["std", "derive"] }
serde_json = "1.0"
serde_cbor = "0.11"
diff --git a/fuzz/README.md b/fuzz/README.md
index 47d4d2581..03a089229 100644
--- a/fuzz/README.md
+++ b/fuzz/README.md
@@ -85,8 +85,8 @@ The final line is a hex-encoded version of the input that caused the crash. You
can test this directly by editing the `duplicate_crash` test to copy/paste the
hex output into the call to `extend_vec_from_hex`. Then run the test with
- RUSTFLAGS=--cfg=fuzzing cargo test
+ RUSTFLAGS="--cfg=fuzzing --cfg=hashes_fuzz" cargo test
-It is important to add the `cfg=fuzzing` flag, which tells rustc to compile the
-library as though it were running a fuzztest. In particular, this will disable
-or weaken all the cryptography.
+It is important to add the `cfg=fuzzing` and `cfg=hashes_fuzz` flags, which
+tell rustc to compile the library as though it were running a fuzztest. In
+particular, `hashes_fuzz` makes `bitcoin_hashes` weaken its hash functions.
diff --git a/fuzz/fuzz.sh b/fuzz/fuzz.sh
index 13f55fff3..f54a6e0d2 100755
--- a/fuzz/fuzz.sh
+++ b/fuzz/fuzz.sh
@@ -31,7 +31,8 @@ cargo --version
rustc --version
# Ensure we don't trigger ThinLTO/internalization issues with honggfuzz's link flags
-export RUSTFLAGS="${RUSTFLAGS:-} -C lto=no"
+# `bitcoin_hashes` weakens its hashes under `hashes_fuzz`, not `fuzzing`
+export RUSTFLAGS="${RUSTFLAGS:-} -C lto=no --cfg=hashes_fuzz"
# Testing
cargo install --force honggfuzz --no-default-features
diff --git a/fuzz/generate-files.sh b/fuzz/generate-files.sh
index b6c239f6c..cb1723afe 100755
--- a/fuzz/generate-files.sh
+++ b/fuzz/generate-files.sh
@@ -11,11 +11,13 @@ source "$REPO_DIR/fuzz/fuzz-util.sh"
cat > "$REPO_DIR/fuzz/Cargo.toml" <"]
-license = "CC0-1.0"
-repository = "https://github.com/rust-dashcore/dash_hashes/"
-documentation = "https://docs.rs/dash_hashes/"
description = "Hash functions used by the rust-dash eccosystem"
+authors = ["Samuel Westrich "]
+edition = "2021"
categories = ["algorithms"]
keywords = [ "crypto", "dash", "hash", "digest" ]
readme = "README.md"
-edition = "2021"
exclude = ["tests", "contrib"]
+license.workspace = true
+repository.workspace = true
+rust-version.workspace = true
+version.workspace = true
[features]
default = []
-schemars = ["actual-schemars"]
-serde-std = ["serde/std"]
+serde = ["dep:serde", "bitcoin_hashes/serde"]
+serde-std = ["serde", "serde/std"]
x11 = ["rs-x11-hash"]
[package.metadata.docs.rs]
@@ -23,15 +23,10 @@ all-features = true
rustdoc-args = ["--cfg", "docsrs"]
[dependencies]
-internals = { path = "../internals", package = "dashcore-private" }
-
-# Only enable this if you explicitly do not want to use "std", otherwise enable "serde-std".
-serde = { version = "1.0.219", default-features = false, optional = true }
-# Do NOT use this as a feature! Use the `schemars` feature instead. Can only be used with "std" enabled.
-actual-schemars = { package = "schemars", version = "1.0", optional = true }
-
-rs-x11-hash = { version = "0.1.8", optional = true }
bincode = { workspace = true, optional = true }
+bitcoin_hashes = { workspace = true, features = ["std"] }
+rs-x11-hash = { version = "0.1.8", optional = true }
+serde = { workspace = true, optional = true }
[dev-dependencies]
serde_test = "1.0"
diff --git a/hashes/README.md b/hashes/README.md
index 9e72067c1..415257ed2 100644
--- a/hashes/README.md
+++ b/hashes/README.md
@@ -1,17 +1,14 @@
-[](https://travis-ci.org/rust-bitcoin/dashcore_hashes)
+# Dash Hashes Library
-# Bitcoin Hashes Library
-
-This is a simple, no-dependency library which implements the hash functions
-needed by Bitcoin. These are SHA1, SHA256, SHA256d, SHA512, and RIPEMD160. As an
-ancillary thing, it exposes hexadecimal serialization and deserialization,
-since these are needed to display hashes anyway.
+This library re-exports the hash functions from
+[`bitcoin_hashes`](https://docs.rs/bitcoin_hashes/) and adds the Dash-specific
+X11 hash, along with `bincode` and `serde` support for hash newtypes.
[Documentation](https://docs.rs/dashcore_hashes/)
## Minimum Supported Rust Version (MSRV)
-This library should always compile with any combination of features on **Rust 1.48.0**.
+This library should always compile with any combination of features on **Rust 1.89.0**.
## Contributions
diff --git a/hashes/src/bincode_macros.rs b/hashes/src/bincode_macros.rs
index cdf78036e..62aa68ef5 100644
--- a/hashes/src/bincode_macros.rs
+++ b/hashes/src/bincode_macros.rs
@@ -28,7 +28,7 @@ macro_rules! bincode_impl {
impl<$($gen: $gent),*> bincode::Encode for $t<$($gen),*> {
fn encode(&self, encoder: &mut E) -> Result<(), bincode::error::EncodeError> {
// Use the as_byte_array method so that we encode the inner byte array
- self.as_byte_array().encode(encoder)
+ $crate::Hash::as_byte_array(self).encode(encoder)
}
}
@@ -36,7 +36,7 @@ macro_rules! bincode_impl {
fn decode>(decoder: &mut D) -> Result {
// Decode a fixed-length byte array and then reconstruct via from_byte_array
let bytes: [u8; $len] = <[u8; $len]>::decode(decoder)?;
- Ok(Self::from_byte_array(bytes))
+ Ok(::from_byte_array(bytes))
}
}
@@ -53,7 +53,7 @@ macro_rules! bincode_impl {
.map_err(|_| bincode::error::DecodeError::Other("Incorrect byte length".into()))?;
// Construct the hash from the reference (cloned since the type is Copy)
- Ok(Self::from_byte_array(bytes))
+ Ok(::from_byte_array(bytes))
}
}
};
diff --git a/hashes/src/cmp.rs b/hashes/src/cmp.rs
deleted file mode 100644
index d99c57f89..000000000
--- a/hashes/src/cmp.rs
+++ /dev/null
@@ -1,88 +0,0 @@
-//! Useful comparison functions.
-
-/// Compare two slices for equality in fixed time. Panics if the slices are of non-equal length.
-///
-/// This works by XOR'ing each byte of the two inputs together and keeping an OR counter of the
-/// results.
-///
-/// Instead of doing fancy bit twiddling to try to outsmart the compiler and prevent early exits,
-/// which is not guaranteed to remain stable as compilers get ever smarter, we take the hit of
-/// writing each intermediate value to memory with a volatile write and then re-reading it with a
-/// volatile read. This should remain stable across compiler upgrades, but is much slower.
-///
-/// As of rust 1.31.0 disassembly looks completely within reason for this, see
-/// .
-pub fn fixed_time_eq(a: &[u8], b: &[u8]) -> bool {
- assert!(a.len() == b.len());
- let count = a.len();
- let lhs = &a[..count];
- let rhs = &b[..count];
-
- let mut r: u8 = 0;
- for i in 0..count {
- let mut rs = unsafe { core::ptr::read_volatile(&r) };
- rs |= lhs[i] ^ rhs[i];
- unsafe {
- core::ptr::write_volatile(&mut r, rs);
- }
- }
- {
- let mut t = unsafe { core::ptr::read_volatile(&r) };
- t |= t >> 4;
- unsafe {
- core::ptr::write_volatile(&mut r, t);
- }
- }
- {
- let mut t = unsafe { core::ptr::read_volatile(&r) };
- t |= t >> 2;
- unsafe {
- core::ptr::write_volatile(&mut r, t);
- }
- }
- {
- let mut t = unsafe { core::ptr::read_volatile(&r) };
- t |= t >> 1;
- unsafe {
- core::ptr::write_volatile(&mut r, t);
- }
- }
- unsafe { (::core::ptr::read_volatile(&r) & 1) == 0 }
-}
-
-#[test]
-fn eq_test() {
- assert!(fixed_time_eq(&[0b00000000], &[0b00000000]));
- assert!(fixed_time_eq(&[0b00000001], &[0b00000001]));
- assert!(fixed_time_eq(&[0b00000010], &[0b00000010]));
- assert!(fixed_time_eq(&[0b00000100], &[0b00000100]));
- assert!(fixed_time_eq(&[0b00001000], &[0b00001000]));
- assert!(fixed_time_eq(&[0b00010000], &[0b00010000]));
- assert!(fixed_time_eq(&[0b00100000], &[0b00100000]));
- assert!(fixed_time_eq(&[0b01000000], &[0b01000000]));
- assert!(fixed_time_eq(&[0b10000000], &[0b10000000]));
- assert!(fixed_time_eq(&[0b11111111], &[0b11111111]));
-
- assert!(!fixed_time_eq(&[0b00000001], &[0b00000000]));
- assert!(!fixed_time_eq(&[0b00000001], &[0b11111111]));
- assert!(!fixed_time_eq(&[0b00000010], &[0b00000000]));
- assert!(!fixed_time_eq(&[0b00000010], &[0b11111111]));
- assert!(!fixed_time_eq(&[0b00000100], &[0b00000000]));
- assert!(!fixed_time_eq(&[0b00000100], &[0b11111111]));
- assert!(!fixed_time_eq(&[0b00001000], &[0b00000000]));
- assert!(!fixed_time_eq(&[0b00001000], &[0b11111111]));
- assert!(!fixed_time_eq(&[0b00010000], &[0b00000000]));
- assert!(!fixed_time_eq(&[0b00010000], &[0b11111111]));
- assert!(!fixed_time_eq(&[0b00100000], &[0b00000000]));
- assert!(!fixed_time_eq(&[0b00100000], &[0b11111111]));
- assert!(!fixed_time_eq(&[0b01000000], &[0b00000000]));
- assert!(!fixed_time_eq(&[0b01000000], &[0b11111111]));
- assert!(!fixed_time_eq(&[0b10000000], &[0b00000000]));
- assert!(!fixed_time_eq(&[0b10000000], &[0b11111111]));
-
- assert!(fixed_time_eq(&[0b00000000, 0b00000000], &[0b00000000, 0b00000000]));
- assert!(!fixed_time_eq(&[0b00000001, 0b00000000], &[0b00000000, 0b00000000]));
- assert!(!fixed_time_eq(&[0b00000000, 0b00000001], &[0b00000000, 0b00000000]));
- assert!(!fixed_time_eq(&[0b00000000, 0b00000000], &[0b00000001, 0b00000000]));
- assert!(!fixed_time_eq(&[0b00000000, 0b00000000], &[0b00000001, 0b00000001]));
-}
diff --git a/hashes/src/error.rs b/hashes/src/error.rs
deleted file mode 100644
index 2614d26b6..000000000
--- a/hashes/src/error.rs
+++ /dev/null
@@ -1,47 +0,0 @@
-// Bitcoin Hashes Library
-// Written in 2018 by
-// Andrew Poelstra
-//
-// To the extent possible under law, the author(s) have dedicated all
-// copyright and related and neighboring rights to this software to
-// the public domain worldwide. This software is distributed without
-// any warranty.
-//
-// You should have received a copy of the CC0 Public Domain Dedication
-// along with this software.
-// If not, see .
-//
-
-//! Crate error type.
-//!
-
-use core::fmt;
-
-/// Crate error type.
-#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub enum Error {
- /// Tried to create a fixed-length hash from a slice with the wrong size (expected, got).
- InvalidLength(usize, usize),
-}
-
-impl fmt::Display for Error {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- use self::Error::*;
-
- match self {
- InvalidLength(ell, ell2) => {
- write!(f, "invalid slice length {} (expected {})", ell2, ell)
- }
- }
- }
-}
-
-impl std::error::Error for Error {
- fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
- use self::Error::*;
-
- match self {
- InvalidLength(_, _) => None,
- }
- }
-}
diff --git a/hashes/src/hash160.rs b/hashes/src/hash160.rs
deleted file mode 100644
index 3262026d2..000000000
--- a/hashes/src/hash160.rs
+++ /dev/null
@@ -1,123 +0,0 @@
-// Bitcoin Hashes Library
-// Written in 2018 by
-// Andrew Poelstra
-//
-// To the extent possible under law, the author(s) have dedicated all
-// copyright and related and neighboring rights to this software to
-// the public domain worldwide. This software is distributed without
-// any warranty.
-//
-// You should have received a copy of the CC0 Public Domain Dedication
-// along with this software.
-// If not, see .
-//
-
-// This module is largely copied from the rust-crypto ripemd.rs file;
-// while rust-crypto is licensed under Apache, that file specifically
-// was written entirely by Andrew Poelstra, who is re-licensing its
-// contents here as CC0.
-
-//! HASH160 (SHA256 then RIPEMD160) implementation.
-//!
-
-use core::ops::Index;
-use core::slice::SliceIndex;
-use core::str;
-
-use crate::{ripemd160, sha256, Error};
-
-crate::internal_macros::hash_type! {
- 160,
- false,
- "Output of the Bitcoin HASH160 hash function. (RIPEMD160(SHA256))",
- "crate::util::json_hex_string::len_20"
-}
-
-type HashEngine = sha256::HashEngine;
-
-fn from_engine(e: HashEngine) -> Hash {
- use crate::Hash as _;
-
- let sha2 = sha256::Hash::from_engine(e);
- let rmd = ripemd160::Hash::hash(&sha2[..]);
-
- let mut ret = [0; 20];
- ret.copy_from_slice(&rmd[..]);
- Hash(ret)
-}
-
-#[cfg(test)]
-mod tests {
- #[test]
- fn test() {
- use crate::{hash160, Hash, HashEngine};
-
- #[derive(Clone)]
- struct Test {
- input: Vec,
- output: Vec,
- output_str: &'static str,
- }
-
- #[rustfmt::skip]
- let tests = vec![
- // Uncompressed pubkey obtained from Bitcoin key; data from validateaddress
- Test {
- input: vec![
- 0x04, 0xa1, 0x49, 0xd7, 0x6c, 0x5d, 0xe2, 0x7a, 0x2d,
- 0xdb, 0xfa, 0xa1, 0x24, 0x6c, 0x4a, 0xdc, 0xd2, 0xb6,
- 0xf7, 0xaa, 0x29, 0x54, 0xc2, 0xe2, 0x53, 0x03, 0xf5,
- 0x51, 0x54, 0xca, 0xad, 0x91, 0x52, 0xe4, 0xf7, 0xe4,
- 0xb8, 0x5d, 0xf1, 0x69, 0xc1, 0x8a, 0x3c, 0x69, 0x7f,
- 0xbb, 0x2d, 0xc4, 0xec, 0xef, 0x94, 0xac, 0x55, 0xfe,
- 0x81, 0x64, 0xcc, 0xf9, 0x82, 0xa1, 0x38, 0x69, 0x1a,
- 0x55, 0x19,
- ],
- output: vec![
- 0xda, 0x0b, 0x34, 0x52, 0xb0, 0x6f, 0xe3, 0x41,
- 0x62, 0x6a, 0xd0, 0x94, 0x9c, 0x18, 0x3f, 0xbd,
- 0xa5, 0x67, 0x68, 0x26,
- ],
- output_str: "da0b3452b06fe341626ad0949c183fbda5676826",
- },
- ];
-
- for test in tests {
- // Hash through high-level API, check hex encoding/decoding
- let hash = hash160::Hash::hash(&test.input[..]);
- assert_eq!(hash, test.output_str.parse::().expect("parse hex"));
- assert_eq!(&hash[..], &test.output[..]);
- assert_eq!(&hash.to_string(), &test.output_str);
-
- // Hash through engine, checking that we can input byte by byte
- let mut engine = hash160::Hash::engine();
- for ch in test.input {
- engine.input(&[ch]);
- }
- let manual_hash = Hash::from_engine(engine);
- assert_eq!(hash, manual_hash);
- assert_eq!(hash.to_byte_array()[..].as_ref(), test.output.as_slice());
- }
- }
-
- #[cfg(feature = "serde")]
- #[test]
- fn ripemd_serde() {
- use serde_test::{assert_tokens, Configure, Token};
-
- use crate::{hash160, Hash};
-
- #[rustfmt::skip]
- static HASH_BYTES: [u8; 20] = [
- 0x13, 0x20, 0x72, 0xdf,
- 0x69, 0x09, 0x33, 0x83,
- 0x5e, 0xb8, 0xb6, 0xad,
- 0x0b, 0x77, 0xe7, 0xb6,
- 0xf1, 0x4a, 0xca, 0xd7,
- ];
-
- let hash = hash160::Hash::from_slice(&HASH_BYTES).expect("right number of bytes");
- assert_tokens(&hash.compact(), &[Token::BorrowedBytes(&HASH_BYTES[..])]);
- assert_tokens(&hash.readable(), &[Token::Str("132072df690933835eb8b6ad0b77e7b6f14acad7")]);
- }
-}
diff --git a/hashes/src/hash_x11.rs b/hashes/src/hash_x11.rs
index bedeb9670..533d56e42 100644
--- a/hashes/src/hash_x11.rs
+++ b/hashes/src/hash_x11.rs
@@ -15,7 +15,7 @@
// If not, see .
//
-//! An implementation of a hash engine to support the X1 hash,
+//! An implementation of a hash engine to support the X11 hash,
//! which is a wrapper around the rs-x11-hash library.
use core::ops::Index;
@@ -24,54 +24,36 @@ use core::str;
use std::io;
use std::vec::Vec;
-use crate::{hex, Error, HashEngine as _};
+use crate::hex::FromHex as _;
+use crate::{hex, FromSliceError, HashEngine as _};
-crate::internal_macros::hash_type! {
- 256,
- true,
- "Output of the X11 hash function.",
- "crate::util::json_hex_string::len_32"
-}
-
-/// Output of the X11 hash function
-fn from_engine(e: HashEngine) -> Hash {
- Hash(e.midstate().to_byte_array())
-}
+/// Output of the X11 hash function.
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[repr(transparent)]
+pub struct Hash([u8; 32]);
-/// A hashing engine of X11 algorithm, which bytes can be serialized into
-#[derive(Clone, Default)]
-pub struct HashEngine {
- buf: Vec,
- length: usize,
-}
-
-impl crate::HashEngine for HashEngine {
- type MidState = Midstate;
-
- const BLOCK_SIZE: usize = 32;
+crate::hex_fmt_impl!(::DISPLAY_BACKWARD, 32, Hash);
+crate::serde_impl!(Hash, 32);
+crate::bincode_impl!(Hash, 32);
+crate::borrow_slice_impl!(Hash);
- fn midstate(&self) -> Self::MidState {
- Midstate(rs_x11_hash::get_x11_hash(self.buf.as_slice()))
- }
+impl str::FromStr for Hash {
+ type Err = hex::HexToArrayError;
- fn input(&mut self, data: &[u8]) {
- self.buf.extend_from_slice(data);
+ fn from_str(s: &str) -> Result {
+ let mut bytes = <[u8; 32]>::from_hex(s)?;
+ bytes.reverse();
+ Ok(Hash(bytes))
}
+}
- fn n_bytes_hashed(&self) -> usize {
- self.length
+impl AsRef<[u8; 32]> for Hash {
+ fn as_ref(&self) -> &[u8; 32] {
+ &self.0
}
}
-/// Output of the X11 hash function
-#[derive(Copy, Clone, PartialEq, Eq, Default, PartialOrd, Ord, Hash)]
-pub struct Midstate(pub [u8; 32]);
-
-crate::internal_macros::arr_newtype_fmt_impl!(Midstate, 32);
-serde_impl!(Midstate, 32);
-borrow_slice_impl!(Midstate);
-
-impl> Index for Midstate {
+impl> Index for Hash {
type Output = I::Output;
#[inline]
@@ -80,56 +62,67 @@ impl> Index for Midstate {
}
}
-impl str::FromStr for Midstate {
- type Err = hex::Error;
- fn from_str(s: &str) -> Result {
- hex::FromHex::from_hex(s)
+impl From for [u8; 32] {
+ fn from(hash: Hash) -> [u8; 32] {
+ hash.0
}
}
-impl Midstate {
- /// Length of the midstate, in bytes.
- const LEN: usize = 32;
+impl crate::Hash for Hash {
+ type Engine = HashEngine;
+ type Bytes = [u8; 32];
- /// Flag indicating whether user-visible serializations of this hash
- /// should be backward. For some reason Satoshi decided this should be
- /// true for `Sha256dHash`, so here we are.
+ const LEN: usize = 32;
const DISPLAY_BACKWARD: bool = true;
- /// Construct a new [`Midstate`] from the inner value.
- pub const fn from_byte_array(inner: [u8; 32]) -> Self {
- Midstate(inner)
+ fn from_engine(e: HashEngine) -> Self {
+ Hash(e.midstate())
}
- /// Copies a byte slice into the [`Midstate`] object.
- pub fn from_slice(sl: &[u8]) -> Result {
- if sl.len() != Self::LEN {
- Err(Error::InvalidLength(Self::LEN, sl.len()))
- } else {
- let mut ret = [0; 32];
- ret.copy_from_slice(sl);
- Ok(Midstate(ret))
- }
+ fn from_slice(sl: &[u8]) -> Result {
+ // `FromSliceError` is only constructible upstream, so a hash of the
+ // same size checks the length.
+ crate::sha256d::Hash::from_slice(sl).map(|h| Hash(h.to_byte_array()))
}
- /// Unwraps the [`Midstate`] and returns the underlying byte array.
- pub fn to_byte_array(self) -> [u8; 32] {
+ fn to_byte_array(self) -> [u8; 32] {
self.0
}
- /// Unwraps the [`Midstate`] and returns the underlying byte array.
- pub fn into_inner(self) -> [u8; 32] {
- self.0
+ fn as_byte_array(&self) -> &[u8; 32] {
+ &self.0
+ }
+
+ fn from_byte_array(bytes: [u8; 32]) -> Self {
+ Hash(bytes)
+ }
+
+ fn all_zeros() -> Self {
+ Hash([0; 32])
}
}
-impl hex::FromHex for Midstate {
- fn from_byte_iter(iter: I) -> Result
- where
- I: Iterator
- > + ExactSizeIterator + DoubleEndedIterator,
- {
- // DISPLAY_BACKWARD is true
- Ok(Midstate::from_byte_array(hex::FromHex::from_byte_iter(iter.rev())?))
+/// An X11 hashing engine. X11 is not incremental, so the input is buffered.
+#[derive(Clone, Default)]
+pub struct HashEngine {
+ buf: Vec,
+}
+
+impl crate::HashEngine for HashEngine {
+ type MidState = [u8; 32];
+
+ const BLOCK_SIZE: usize = 32;
+
+ fn midstate(&self) -> [u8; 32] {
+ rs_x11_hash::get_x11_hash(self.buf.as_slice())
+ }
+
+ fn input(&mut self, data: &[u8]) {
+ self.buf.extend_from_slice(data);
+ }
+
+ fn n_bytes_hashed(&self) -> usize {
+ self.buf.len()
}
}
@@ -138,6 +131,7 @@ impl io::Write for HashEngine {
self.input(buf);
Ok(buf.len())
}
+
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
diff --git a/hashes/src/hex.rs b/hashes/src/hex.rs
deleted file mode 100644
index 62fa9e08c..000000000
--- a/hashes/src/hex.rs
+++ /dev/null
@@ -1,233 +0,0 @@
-// Bitcoin Hashes Library
-// Written in 2018 by
-// Andrew Poelstra
-//
-// To the extent possible under law, the author(s) have dedicated all
-// copyright and related and neighboring rights to this software to
-// the public domain worldwide. This software is distributed without
-// any warranty.
-//
-// You should have received a copy of the CC0 Public Domain Dedication
-// along with this software.
-// If not, see .
-//
-
-//! Hex encoding and decoding.
-//!
-
-use core::{fmt, str};
-use std::io;
-
-/// Hex decoding error.
-#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub enum Error {
- /// Non-hexadecimal character.
- InvalidChar(u8),
- /// Purported hex string had odd length.
- OddLengthString(usize),
- /// Tried to parse fixed-length hash from a string with the wrong type (expected, got).
- InvalidLength(usize, usize),
-}
-
-impl fmt::Display for Error {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match *self {
- Error::InvalidChar(ch) => write!(f, "invalid hex character {}", ch),
- Error::OddLengthString(ell) => write!(f, "odd hex string length {}", ell),
- Error::InvalidLength(ell, ell2) => {
- write!(f, "bad hex string length {} (expected {})", ell2, ell)
- }
- }
- }
-}
-
-impl std::error::Error for Error {
- fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
- use self::Error::*;
-
- match self {
- InvalidChar(_) | OddLengthString(_) | InvalidLength(_, _) => None,
- }
- }
-}
-
-/// Trait for objects that can be deserialized from hex strings.
-pub trait FromHex: Sized {
- /// Produces an object from a byte iterator.
- fn from_byte_iter(iter: I) -> Result
- where
- I: Iterator
- > + ExactSizeIterator + DoubleEndedIterator;
-
- /// Produces an object from a hex string.
- fn from_hex(s: &str) -> Result {
- Self::from_byte_iter(HexIterator::new(s)?)
- }
-}
-
-/// Iterator over a hex-encoded string slice which decodes hex and yields bytes.
-pub struct HexIterator<'a> {
- /// The `Bytes` iterator whose next two bytes will be decoded to yield
- /// the next byte.
- iter: str::Bytes<'a>,
-}
-
-impl<'a> HexIterator<'a> {
- /// Constructs a new `HexIterator` from a string slice.
- ///
- /// # Errors
- ///
- /// If the input string is of odd length.
- pub fn new(s: &'a str) -> Result, Error> {
- if !s.len().is_multiple_of(2) {
- Err(Error::OddLengthString(s.len()))
- } else {
- Ok(HexIterator {
- iter: s.bytes(),
- })
- }
- }
-}
-
-fn chars_to_hex(hi: u8, lo: u8) -> Result {
- let hih = (hi as char).to_digit(16).ok_or(Error::InvalidChar(hi))?;
- let loh = (lo as char).to_digit(16).ok_or(Error::InvalidChar(lo))?;
-
- let ret = (hih << 4) + loh;
- Ok(ret as u8)
-}
-
-impl<'a> Iterator for HexIterator<'a> {
- type Item = Result;
-
- fn next(&mut self) -> Option> {
- let hi = self.iter.next()?;
- let lo = self.iter.next().unwrap();
- Some(chars_to_hex(hi, lo))
- }
-
- fn size_hint(&self) -> (usize, Option) {
- let (min, max) = self.iter.size_hint();
- (min / 2, max.map(|x| x / 2))
- }
-}
-
-impl<'a> io::Read for HexIterator<'a> {
- fn read(&mut self, buf: &mut [u8]) -> io::Result {
- let mut bytes_read = 0usize;
- for dst in buf {
- match self.next() {
- Some(Ok(src)) => {
- *dst = src;
- bytes_read += 1;
- }
- _ => break,
- }
- }
- Ok(bytes_read)
- }
-}
-
-impl<'a> DoubleEndedIterator for HexIterator<'a> {
- fn next_back(&mut self) -> Option> {
- let lo = self.iter.next_back()?;
- let hi = self.iter.next_back().unwrap();
- Some(chars_to_hex(hi, lo))
- }
-}
-
-impl<'a> ExactSizeIterator for HexIterator<'a> {}
-
-impl FromHex for Vec {
- fn from_byte_iter(iter: I) -> Result
- where
- I: Iterator
- > + ExactSizeIterator + DoubleEndedIterator,
- {
- iter.collect()
- }
-}
-
-macro_rules! impl_fromhex_array {
- ($len:expr) => {
- impl FromHex for [u8; $len] {
- fn from_byte_iter(iter: I) -> Result
- where
- I: Iterator
- > + ExactSizeIterator + DoubleEndedIterator,
- {
- if iter.len() == $len {
- let mut ret = [0; $len];
- for (n, byte) in iter.enumerate() {
- ret[n] = byte?;
- }
- Ok(ret)
- } else {
- Err(Error::InvalidLength(2 * $len, 2 * iter.len()))
- }
- }
- }
- };
-}
-
-impl_fromhex_array!(2);
-impl_fromhex_array!(4);
-impl_fromhex_array!(6);
-impl_fromhex_array!(8);
-impl_fromhex_array!(10);
-impl_fromhex_array!(12);
-impl_fromhex_array!(14);
-impl_fromhex_array!(16);
-impl_fromhex_array!(20);
-impl_fromhex_array!(24);
-impl_fromhex_array!(28);
-impl_fromhex_array!(32);
-impl_fromhex_array!(33);
-impl_fromhex_array!(48);
-impl_fromhex_array!(64);
-impl_fromhex_array!(65);
-impl_fromhex_array!(96);
-impl_fromhex_array!(128);
-impl_fromhex_array!(256);
-impl_fromhex_array!(384);
-impl_fromhex_array!(512);
-
-#[cfg(test)]
-mod tests {
- use internals::hex::exts::DisplayHex;
-
- use super::*;
-
- #[test]
- fn hex_roundtrip() {
- let expected = "0123456789abcdef";
- let expected_up = "0123456789ABCDEF";
-
- let parse: Vec = FromHex::from_hex(expected).expect("parse lowercase string");
- assert_eq!(parse, vec![0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]);
- let ser = parse.to_lower_hex_string();
- assert_eq!(ser, expected);
-
- let parse: Vec = FromHex::from_hex(expected_up).expect("parse uppercase string");
- assert_eq!(parse, vec![0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]);
- let ser = parse.to_lower_hex_string();
- assert_eq!(ser, expected);
-
- let parse: [u8; 8] = FromHex::from_hex(expected_up).expect("parse uppercase string");
- assert_eq!(parse, [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]);
- let ser = parse.to_lower_hex_string();
- assert_eq!(ser, expected);
- }
-
- #[test]
- fn hex_error() {
- let oddlen = "0123456789abcdef0";
- let badchar1 = "Z123456789abcdef";
- let badchar2 = "012Y456789abcdeb";
- let badchar3 = "«23456789abcdef";
-
- assert_eq!(Vec::::from_hex(oddlen), Err(Error::OddLengthString(17)));
- assert_eq!(<[u8; 4]>::from_hex(oddlen), Err(Error::OddLengthString(17)));
- assert_eq!(<[u8; 8]>::from_hex(oddlen), Err(Error::OddLengthString(17)));
- assert_eq!(Vec::::from_hex(badchar1), Err(Error::InvalidChar(b'Z')));
- assert_eq!(Vec::::from_hex(badchar2), Err(Error::InvalidChar(b'Y')));
- assert_eq!(Vec::::from_hex(badchar3), Err(Error::InvalidChar(194)));
- }
-}
diff --git a/hashes/src/hmac.rs b/hashes/src/hmac.rs
deleted file mode 100644
index a01e77f95..000000000
--- a/hashes/src/hmac.rs
+++ /dev/null
@@ -1,400 +0,0 @@
-// Bitcoin Hashes Library
-// Written in 2018 by
-// Andrew Poelstra
-//
-// To the extent possible under law, the author(s) have dedicated all
-// copyright and related and neighboring rights to this software to
-// the public domain worldwide. This software is distributed without
-// any warranty.
-//
-// You should have received a copy of the CC0 Public Domain Dedication
-// along with this software.
-// If not, see .
-//
-
-// This module is largely copied from the rust-crypto ripemd.rs file;
-// while rust-crypto is licensed under Apache, that file specifically
-// was written entirely by Andrew Poelstra, who is re-licensing its
-// contents here as CC0.
-
-//! Hash-based Message Authentication Code (HMAC).
-//!
-
-use core::{borrow, fmt, ops, str};
-
-#[cfg(feature = "serde")]
-use serde::{Deserialize, Deserializer, Serialize, Serializer};
-
-use crate::{Error, Hash, HashEngine};
-
-/// A hash computed from a RFC 2104 HMAC. Parameterized by the underlying hash function.
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
-#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
-#[cfg_attr(feature = "schemars", schemars(transparent))]
-#[repr(transparent)]
-pub struct Hmac(T);
-
-impl str::FromStr for Hmac {
- type Err = ::Err;
- fn from_str(s: &str) -> Result {
- Ok(Hmac(str::FromStr::from_str(s)?))
- }
-}
-
-/// Pair of underlying hash midstates which represent the current state of an `HmacEngine`.
-pub struct HmacMidState {
- /// Midstate of the inner hash engine
- pub inner: ::MidState,
- /// Midstate of the outer hash engine
- pub outer: ::MidState,
-}
-
-/// Pair of underlying hash engines, used for the inner and outer hash of HMAC.
-#[derive(Clone)]
-pub struct HmacEngine {
- iengine: T::Engine,
- oengine: T::Engine,
-}
-
-impl Default for HmacEngine {
- fn default() -> Self {
- HmacEngine::new(&[])
- }
-}
-
-impl HmacEngine {
- /// Constructs a new keyed HMAC from `key`.
- ///
- /// We only support underlying hashes whose block sizes are ≤ 128 bytes.
- ///
- /// # Panics
- ///
- /// Larger hashes will result in a panic.
- pub fn new(key: &[u8]) -> HmacEngine {
- debug_assert!(T::Engine::BLOCK_SIZE <= 128);
-
- let mut ipad = [0x36u8; 128];
- let mut opad = [0x5cu8; 128];
- let mut ret = HmacEngine {
- iengine: ::engine(),
- oengine: ::engine(),
- };
-
- if key.len() > T::Engine::BLOCK_SIZE {
- let hash = ::hash(key);
- for (b_i, b_h) in ipad.iter_mut().zip(&hash[..]) {
- *b_i ^= *b_h;
- }
- for (b_o, b_h) in opad.iter_mut().zip(&hash[..]) {
- *b_o ^= *b_h;
- }
- } else {
- for (b_i, b_h) in ipad.iter_mut().zip(key) {
- *b_i ^= *b_h;
- }
- for (b_o, b_h) in opad.iter_mut().zip(key) {
- *b_o ^= *b_h;
- }
- };
-
- HashEngine::input(&mut ret.iengine, &ipad[..T::Engine::BLOCK_SIZE]);
- HashEngine::input(&mut ret.oengine, &opad[..T::Engine::BLOCK_SIZE]);
- ret
- }
-
- /// A special constructor giving direct access to the underlying "inner" and "outer" engines.
- pub fn from_inner_engines(iengine: T::Engine, oengine: T::Engine) -> HmacEngine {
- HmacEngine {
- iengine,
- oengine,
- }
- }
-}
-
-impl HashEngine for HmacEngine {
- type MidState = HmacMidState;
-
- fn midstate(&self) -> Self::MidState {
- HmacMidState {
- inner: self.iengine.midstate(),
- outer: self.oengine.midstate(),
- }
- }
-
- const BLOCK_SIZE: usize = T::Engine::BLOCK_SIZE;
-
- fn n_bytes_hashed(&self) -> usize {
- self.iengine.n_bytes_hashed()
- }
-
- fn input(&mut self, buf: &[u8]) {
- self.iengine.input(buf)
- }
-}
-
-impl fmt::Debug for Hmac {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- fmt::Debug::fmt(&self.0, f)
- }
-}
-
-impl fmt::Display for Hmac {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- fmt::Display::fmt(&self.0, f)
- }
-}
-
-impl fmt::LowerHex for Hmac {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- fmt::LowerHex::fmt(&self.0, f)
- }
-}
-
-impl ops::Index for Hmac {
- type Output = u8;
- fn index(&self, index: usize) -> &u8 {
- &self.0[index]
- }
-}
-
-impl ops::Index> for Hmac {
- type Output = [u8];
- fn index(&self, index: ops::Range) -> &[u8] {
- &self.0[index]
- }
-}
-
-impl ops::Index> for Hmac {
- type Output = [u8];
- fn index(&self, index: ops::RangeFrom) -> &[u8] {
- &self.0[index]
- }
-}
-
-impl ops::Index> for Hmac {
- type Output = [u8];
- fn index(&self, index: ops::RangeTo) -> &[u8] {
- &self.0[index]
- }
-}
-
-impl ops::Index for Hmac {
- type Output = [u8];
- fn index(&self, index: ops::RangeFull) -> &[u8] {
- &self.0[index]
- }
-}
-
-impl borrow::Borrow<[u8]> for Hmac {
- fn borrow(&self) -> &[u8] {
- &self[..]
- }
-}
-
-impl Hash for Hmac {
- type Engine = HmacEngine;
- type Bytes = T::Bytes;
-
- fn from_engine(mut e: HmacEngine) -> Hmac {
- let ihash = T::from_engine(e.iengine);
- e.oengine.input(&ihash[..]);
- let ohash = T::from_engine(e.oengine);
- Hmac(ohash)
- }
-
- const LEN: usize = T::LEN;
-
- fn from_slice(sl: &[u8]) -> Result, Error> {
- T::from_slice(sl).map(Hmac)
- }
-
- fn to_byte_array(self) -> Self::Bytes {
- self.0.to_byte_array()
- }
-
- fn as_byte_array(&self) -> &Self::Bytes {
- self.0.as_byte_array()
- }
-
- fn from_byte_array(bytes: T::Bytes) -> Self {
- Hmac(T::from_byte_array(bytes))
- }
-
- fn all_zeros() -> Self {
- let zeros = T::all_zeros();
- Hmac(zeros)
- }
-}
-
-#[cfg(feature = "serde")]
-impl Serialize for Hmac {
- fn serialize(&self, s: S) -> Result {
- Serialize::serialize(&self.0, s)
- }
-}
-
-#[cfg(feature = "serde")]
-impl<'de, T: Hash + Deserialize<'de>> Deserialize<'de> for Hmac {
- fn deserialize>(d: D) -> Result, D::Error> {
- let bytes = Deserialize::deserialize(d)?;
- Ok(Hmac(bytes))
- }
-}
-
-#[cfg(test)]
-mod tests {
- #[test]
- fn test() {
- use crate::{sha256, Hash, HashEngine, Hmac, HmacEngine};
-
- #[derive(Clone)]
- struct Test {
- key: Vec,
- input: Vec,
- output: Vec,
- }
-
- #[rustfmt::skip]
- let tests = vec![
- // Test vectors copied from libsecp256k1
- // Sadly the RFC2104 test vectors all use MD5 as their underlying hash function,
- // which of course this library does not support.
- Test {
- key: vec![ 0x0b; 20],
- input: vec![0x48, 0x69, 0x20, 0x54, 0x68, 0x65, 0x72, 0x65],
- output: vec![
- 0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53,
- 0x5c, 0xa8, 0xaf, 0xce, 0xaf, 0x0b, 0xf1, 0x2b,
- 0x88, 0x1d, 0xc2, 0x00, 0xc9, 0x83, 0x3d, 0xa7,
- 0x26, 0xe9, 0x37, 0x6c, 0x2e, 0x32, 0xcf, 0xf7,
- ],
- },
- Test {
- key: vec![ 0x4a, 0x65, 0x66, 0x65 ],
- input: vec![
- 0x77, 0x68, 0x61, 0x74, 0x20, 0x64, 0x6f, 0x20,
- 0x79, 0x61, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x20,
- 0x66, 0x6f, 0x72, 0x20, 0x6e, 0x6f, 0x74, 0x68,
- 0x69, 0x6e, 0x67, 0x3f,
- ],
- output: vec![
- 0x5b, 0xdc, 0xc1, 0x46, 0xbf, 0x60, 0x75, 0x4e,
- 0x6a, 0x04, 0x24, 0x26, 0x08, 0x95, 0x75, 0xc7,
- 0x5a, 0x00, 0x3f, 0x08, 0x9d, 0x27, 0x39, 0x83,
- 0x9d, 0xec, 0x58, 0xb9, 0x64, 0xec, 0x38, 0x43,
- ],
- },
- Test {
- key: vec![ 0xaa; 20 ],
- input: vec![ 0xdd; 50 ],
- output: vec![
- 0x77, 0x3e, 0xa9, 0x1e, 0x36, 0x80, 0x0e, 0x46,
- 0x85, 0x4d, 0xb8, 0xeb, 0xd0, 0x91, 0x81, 0xa7,
- 0x29, 0x59, 0x09, 0x8b, 0x3e, 0xf8, 0xc1, 0x22,
- 0xd9, 0x63, 0x55, 0x14, 0xce, 0xd5, 0x65, 0xfe,
- ],
- },
- Test {
- key: vec![
- 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
- 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
- 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
- 0x19
- ],
- input: vec![ 0xcd; 50 ],
- output: vec![
- 0x82, 0x55, 0x8a, 0x38, 0x9a, 0x44, 0x3c, 0x0e,
- 0xa4, 0xcc, 0x81, 0x98, 0x99, 0xf2, 0x08, 0x3a,
- 0x85, 0xf0, 0xfa, 0xa3, 0xe5, 0x78, 0xf8, 0x07,
- 0x7a, 0x2e, 0x3f, 0xf4, 0x67, 0x29, 0x66, 0x5b,
- ],
- },
- Test {
- key: vec! [ 0xaa; 131 ],
- input: vec![
- 0x54, 0x65, 0x73, 0x74, 0x20, 0x55, 0x73, 0x69,
- 0x6e, 0x67, 0x20, 0x4c, 0x61, 0x72, 0x67, 0x65,
- 0x72, 0x20, 0x54, 0x68, 0x61, 0x6e, 0x20, 0x42,
- 0x6c, 0x6f, 0x63, 0x6b, 0x2d, 0x53, 0x69, 0x7a,
- 0x65, 0x20, 0x4b, 0x65, 0x79, 0x20, 0x2d, 0x20,
- 0x48, 0x61, 0x73, 0x68, 0x20, 0x4b, 0x65, 0x79,
- 0x20, 0x46, 0x69, 0x72, 0x73, 0x74,
- ],
- output: vec![
- 0x60, 0xe4, 0x31, 0x59, 0x1e, 0xe0, 0xb6, 0x7f,
- 0x0d, 0x8a, 0x26, 0xaa, 0xcb, 0xf5, 0xb7, 0x7f,
- 0x8e, 0x0b, 0xc6, 0x21, 0x37, 0x28, 0xc5, 0x14,
- 0x05, 0x46, 0x04, 0x0f, 0x0e, 0xe3, 0x7f, 0x54,
- ],
- },
- Test {
- key: vec! [ 0xaa; 131 ],
- input: vec![
- 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20,
- 0x61, 0x20, 0x74, 0x65, 0x73, 0x74, 0x20, 0x75,
- 0x73, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x20, 0x6c,
- 0x61, 0x72, 0x67, 0x65, 0x72, 0x20, 0x74, 0x68,
- 0x61, 0x6e, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b,
- 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x6b, 0x65,
- 0x79, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x61, 0x20,
- 0x6c, 0x61, 0x72, 0x67, 0x65, 0x72, 0x20, 0x74,
- 0x68, 0x61, 0x6e, 0x20, 0x62, 0x6c, 0x6f, 0x63,
- 0x6b, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x64,
- 0x61, 0x74, 0x61, 0x2e, 0x20, 0x54, 0x68, 0x65,
- 0x20, 0x6b, 0x65, 0x79, 0x20, 0x6e, 0x65, 0x65,
- 0x64, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65,
- 0x20, 0x68, 0x61, 0x73, 0x68, 0x65, 0x64, 0x20,
- 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x20, 0x62,
- 0x65, 0x69, 0x6e, 0x67, 0x20, 0x75, 0x73, 0x65,
- 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65,
- 0x20, 0x48, 0x4d, 0x41, 0x43, 0x20, 0x61, 0x6c,
- 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x2e,
- ],
- output: vec![
- 0x9b, 0x09, 0xff, 0xa7, 0x1b, 0x94, 0x2f, 0xcb,
- 0x27, 0x63, 0x5f, 0xbc, 0xd5, 0xb0, 0xe9, 0x44,
- 0xbf, 0xdc, 0x63, 0x64, 0x4f, 0x07, 0x13, 0x93,
- 0x8a, 0x7f, 0x51, 0x53, 0x5c, 0x3a, 0x35, 0xe2,
- ],
- },
- ];
-
- for test in tests {
- let mut engine = HmacEngine::::new(&test.key);
- engine.input(&test.input);
- let hash = Hmac::::from_engine(engine);
- assert_eq!(&hash[..], &test.output[..]);
- assert_eq!(hash.as_byte_array(), test.output.as_slice());
- }
- }
-
- #[cfg(feature = "serde")]
- #[test]
- fn hmac_sha512_serde() {
- use serde_test::{assert_tokens, Configure, Token};
-
- use crate::{sha512, Hash, Hmac};
-
- #[rustfmt::skip]
- static HASH_BYTES: [u8; 64] = [
- 0x8b, 0x41, 0xe1, 0xb7, 0x8a, 0xd1, 0x15, 0x21,
- 0x11, 0x3c, 0x52, 0xff, 0x18, 0x2a, 0x1b, 0x8e,
- 0x0a, 0x19, 0x57, 0x54, 0xaa, 0x52, 0x7f, 0xcd,
- 0x00, 0xa4, 0x11, 0x62, 0x0b, 0x46, 0xf2, 0x0f,
- 0xff, 0xfb, 0x80, 0x88, 0xcc, 0xf8, 0x54, 0x97,
- 0x12, 0x1a, 0xd4, 0x49, 0x9e, 0x08, 0x45, 0xb8,
- 0x76, 0xf6, 0xdd, 0x66, 0x40, 0x08, 0x8a, 0x2f,
- 0x0b, 0x2d, 0x8a, 0x60, 0x0b, 0xdf, 0x4c, 0x0c,
- ];
-
- let hash = Hmac::::from_slice(&HASH_BYTES).expect("right number of bytes");
- assert_tokens(&hash.compact(), &[Token::BorrowedBytes(&HASH_BYTES[..])]);
- assert_tokens(
- &hash.readable(),
- &[Token::Str(
- "8b41e1b78ad11521113c52ff182a1b8e0a195754aa527fcd00a411620b46f20f\
- fffb8088ccf85497121ad4499e0845b876f6dd6640088a2f0b2d8a600bdf4c0c",
- )],
- );
- }
-}
diff --git a/hashes/src/impls.rs b/hashes/src/impls.rs
deleted file mode 100644
index 15e61e5b8..000000000
--- a/hashes/src/impls.rs
+++ /dev/null
@@ -1,179 +0,0 @@
-// Bitcoin Hashes Library
-// Written in 2019 by
-// Andrew Poelstra
-//
-// To the extent possible under law, the author(s) have dedicated all
-// copyright and related and neighboring rights to this software to
-// the public domain worldwide. This software is distributed without
-// any warranty.
-//
-// You should have received a copy of the CC0 Public Domain Dedication
-// along with this software.
-// If not, see .
-//
-
-use std::io;
-
-use crate::{hmac, ripemd160, sha1, sha256, sha512, siphash24, HashEngine};
-
-impl io::Write for sha1::HashEngine {
- fn flush(&mut self) -> io::Result<()> {
- Ok(())
- }
-
- fn write(&mut self, buf: &[u8]) -> io::Result {
- self.input(buf);
- Ok(buf.len())
- }
-}
-
-impl io::Write for sha256::HashEngine {
- fn flush(&mut self) -> io::Result<()> {
- Ok(())
- }
-
- fn write(&mut self, buf: &[u8]) -> io::Result {
- self.input(buf);
- Ok(buf.len())
- }
-}
-
-impl io::Write for sha512::HashEngine {
- fn flush(&mut self) -> io::Result<()> {
- Ok(())
- }
-
- fn write(&mut self, buf: &[u8]) -> io::Result {
- self.input(buf);
- Ok(buf.len())
- }
-}
-
-impl io::Write for ripemd160::HashEngine {
- fn flush(&mut self) -> io::Result<()> {
- Ok(())
- }
-
- fn write(&mut self, buf: &[u8]) -> io::Result {
- self.input(buf);
- Ok(buf.len())
- }
-}
-
-impl io::Write for siphash24::HashEngine {
- fn flush(&mut self) -> io::Result<()> {
- Ok(())
- }
-
- fn write(&mut self, buf: &[u8]) -> io::Result {
- self.input(buf);
- Ok(buf.len())
- }
-}
-
-impl io::Write for hmac::HmacEngine {
- fn flush(&mut self) -> io::Result<()> {
- Ok(())
- }
-
- fn write(&mut self, buf: &[u8]) -> io::Result {
- self.input(buf);
- Ok(buf.len())
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::io::Write;
- use crate::{hash160, hmac, ripemd160, sha1, sha256, sha256d, sha512, siphash24, Hash};
-
- macro_rules! write_test {
- ($mod:ident, $exp_empty:expr, $exp_256:expr, $exp_64k:expr,) => {
- #[test]
- fn $mod() {
- let mut engine = $mod::Hash::engine();
- engine.write_all(&[]).unwrap();
- assert_eq!(format!("{}", $mod::Hash::from_engine(engine)), $exp_empty);
-
- let mut engine = $mod::Hash::engine();
- engine.write_all(&[1; 256]).unwrap();
- assert_eq!(format!("{}", $mod::Hash::from_engine(engine)), $exp_256);
-
- let mut engine = $mod::Hash::engine();
- engine.write_all(&[99; 64000]).unwrap();
- assert_eq!(format!("{}", $mod::Hash::from_engine(engine)), $exp_64k);
- }
- };
- }
-
- write_test!(
- sha1,
- "da39a3ee5e6b4b0d3255bfef95601890afd80709",
- "ac458b067c6b021c7e9358229b636e9d1e4cb154",
- "e4b66838f9f7b6f91e5be32a02ae78094df402e7",
- );
-
- write_test!(
- sha256,
- "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
- "2661920f2409dd6c8adeb0c44972959f232b6429afa913845d0fd95e7e768234",
- "5c5e904f5d4fd587c7a906bf846e08a927286f388c54c39213a4884695271bbc",
- );
-
- write_test!(
- sha256d,
- "56944c5d3f98413ef45cf54545538103cc9f298e0575820ad3591376e2e0f65d",
- "374000d830c75d10d9417e493a7652920f30efbd300e3fb092f24c28c20baf64",
- "0050d4148ad7a0437ca0643fad5bf4614cd95d9ba21fde52370b37dcc3f03307",
- );
-
- write_test!(
- sha512,
- "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce\
- 47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e",
- "57ecf739d3a7ca647639adae80a05f4f361304bfcbfa1ceba93296b096e74287\
- 45fc10c142cecdd3bb587a3dba598c072f6f78b31cc0a06a3da0105ee51f75d6",
- "dd28f78c53f3bc9bd0c2dca9642a1ad402a70412f985c1f6e54fadb98ce9c458\
- 4761df8d04ed04bb734ba48dd2106bb9ea54524f1394cdd18e6da3166e71c3ee",
- );
-
- write_test!(
- ripemd160,
- "9c1185a5c5e9fc54612808977ee8f548b2258d31",
- "e571a1ca5b780aa52bafdb9ec852544ffca418ba",
- "ddd2ecce739e823629c7d46ab18918e9c4a51c75",
- );
-
- write_test!(
- hash160,
- "b472a266d0bd89c13706a4132ccfb16f7c3b9fcb",
- "671356a1a874695ad3bc20cae440f4360835bd5a",
- "a9608c952c8dbcc20c53803d2ca5ad31d64d9313",
- );
-
- write_test!(siphash24, "d70077739d4b921e", "3a3ccefde9b5b1e3", "ce456e4e4ecbc5bf",);
-
- #[test]
- fn hmac() {
- let mut engine = hmac::HmacEngine::::new(&[0xde, 0xad, 0xbe, 0xef]);
- engine.write_all(&[]).unwrap();
- assert_eq!(
- format!("{}", hmac::Hmac::from_engine(engine)),
- "bf5515149cf797955c4d3194cca42472883281951697c8375d9d9b107f384225"
- );
-
- let mut engine = hmac::HmacEngine::::new(&[0xde, 0xad, 0xbe, 0xef]);
- engine.write_all(&[1; 256]).unwrap();
- assert_eq!(
- format!("{}", hmac::Hmac::from_engine(engine)),
- "59c9aca10c81c73cb4c196d94db741b6bf2050e0153d5a45f2526bff34675ac5"
- );
-
- let mut engine = hmac::HmacEngine::::new(&[0xde, 0xad, 0xbe, 0xef]);
- engine.write_all(&[99; 64000]).unwrap();
- assert_eq!(
- format!("{}", hmac::Hmac::from_engine(engine)),
- "30df499717415a395379a1eaabe50038036e4abb5afc94aa55c952f4aa57be08"
- );
- }
-}
diff --git a/hashes/src/internal_macros.rs b/hashes/src/internal_macros.rs
deleted file mode 100644
index 9ba9dd2e6..000000000
--- a/hashes/src/internal_macros.rs
+++ /dev/null
@@ -1,257 +0,0 @@
-//! Non-public macros
-
-macro_rules! arr_newtype_fmt_impl {
- ($ty:ident, $bytes:expr $(, $gen:ident: $gent:ident)*) => {
- impl<$($gen: $gent),*> $crate::_export::_core::fmt::LowerHex for $ty<$($gen),*> {
- #[inline]
- fn fmt(&self, f: &mut $crate::_export::_core::fmt::Formatter) -> $crate::_export::_core::fmt::Result {
- #[allow(unused)]
- use crate::Hash as _;
- let case = internals::hex::Case::Lower;
- if <$ty<$($gen),*>>::DISPLAY_BACKWARD {
- internals::hex::display::fmt_hex_exact!(f, $bytes, self.0.iter().rev(), case)
- } else {
- internals::hex::display::fmt_hex_exact!(f, $bytes, self.0.iter(), case)
- }
- }
- }
-
- impl<$($gen: $gent),*> $crate::_export::_core::fmt::UpperHex for $ty<$($gen),*> {
- #[inline]
- fn fmt(&self, f: &mut $crate::_export::_core::fmt::Formatter) -> $crate::_export::_core::fmt::Result {
- #[allow(unused)]
- use crate::Hash as _;
- let case = internals::hex::Case::Upper;
- if <$ty<$($gen),*>>::DISPLAY_BACKWARD {
- internals::hex::display::fmt_hex_exact!(f, $bytes, self.0.iter().rev(), case)
- } else {
- internals::hex::display::fmt_hex_exact!(f, $bytes, self.0.iter(), case)
- }
- }
- }
-
- impl<$($gen: $gent),*> $crate::_export::_core::fmt::Display for $ty<$($gen),*> {
- #[inline]
- fn fmt(&self, f: &mut $crate::_export::_core::fmt::Formatter) -> $crate::_export::_core::fmt::Result {
- $crate::_export::_core::fmt::LowerHex::fmt(self, f)
- }
- }
-
- impl<$($gen: $gent),*> $crate::_export::_core::fmt::Debug for $ty<$($gen),*> {
- #[inline]
- fn fmt(&self, f: &mut $crate::_export::_core::fmt::Formatter) -> $crate::_export::_core::fmt::Result {
- write!(f, "{:#}", self)
- }
- }
- }
-}
-pub(crate) use arr_newtype_fmt_impl;
-
-/// Adds trait impls to the type called `Hash` in the current scope.
-///
-/// Implpements various conversion traits as well as the [`crate::Hash`] trait.
-/// Arguments:
-///
-/// * `$bits` - number of bits this hash type has
-/// * `$reverse` - `bool` - `true` if the hash type should be displayed backwards, `false`
-/// otherwise.
-/// * `$gen: $gent` - generic type(s) and trait bound(s)
-///
-/// Restrictions on usage:
-///
-/// * There must be a free-standing `fn from_engine(HashEngine) -> Hash` in the scope
-/// * `fn internal_new([u8; $bits / 8]) -> Self` must exist on `Hash`
-/// * `fn internal_engine() -> HashEngine` must exist on `Hash`
-///
-/// `from_engine` obviously implements the finalization algorithm.
-/// `internal_new` is required so that types with more than one field are constructible.
-/// `internal_engine` is required to initialize the engine for given hash type.
-macro_rules! hash_trait_impls {
- ($bits:expr, $reverse:expr $(, $gen:ident: $gent:ident)*) => {
- impl<$($gen: $gent),*> Hash<$($gen),*> {
- /// Displays hex forwards, regardless of how this type would display it naturally.
- ///
- /// This is mainly intended as an internal method and you shouldn't need it unless
- /// you're doing something special.
- pub fn forward_hex(&self) -> impl '_ + core::fmt::LowerHex + core::fmt::UpperHex {
- internals::hex::display::DisplayHex::as_hex(&self.0)
- }
-
- /// Displays hex backwards, regardless of how this type would display it naturally.
- ///
- /// This is mainly intended as an internal method and you shouldn't need it unless
- /// you're doing something special.
- pub fn backward_hex(&self) -> impl '_ + core::fmt::LowerHex + core::fmt::UpperHex {
- internals::hex::display::DisplayArray::<_, [u8; $bits / 8 * 2]>::new(self.0.iter().rev())
- }
-
- /// Zero cost conversion between a fixed length byte array shared reference and
- /// a shared reference to this Hash type.
- pub fn from_bytes_ref(bytes: &[u8; $bits / 8]) -> &Self {
- // Safety: Sound because Self is #[repr(transparent)] containing [u8; $bits / 8]
- unsafe { &*(bytes as *const _ as *const Self) }
- }
-
- /// Zero cost conversion between a fixed length byte array exclusive reference and
- /// an exclusive reference to this Hash type.
- pub fn from_bytes_mut(bytes: &mut [u8; $bits / 8]) -> &mut Self {
- // Safety: Sound because Self is #[repr(transparent)] containing [u8; $bits / 8]
- unsafe { &mut *(bytes as *mut _ as *mut Self) }
- }
- }
-
- impl<$($gen: $gent),*> str::FromStr for Hash<$($gen),*> {
- type Err = $crate::hex::Error;
- fn from_str(s: &str) -> Result {
- use $crate::hex::{FromHex, HexIterator};
- use $crate::Hash;
-
- let inner: [u8; $bits / 8] = if $reverse {
- FromHex::from_byte_iter(HexIterator::new(s)?.rev())?
- } else {
- FromHex::from_byte_iter(HexIterator::new(s)?)?
- };
- Ok(Self::from_byte_array(inner))
- }
- }
-
- $crate::internal_macros::arr_newtype_fmt_impl!(Hash, $bits / 8 $(, $gen: $gent)*);
- serde_impl!(Hash, $bits / 8 $(, $gen: $gent)*);
- borrow_slice_impl!(Hash $(, $gen: $gent)*);
-
- impl<$($gen: $gent),*> $crate::_export::_core::convert::AsRef<[u8; $bits / 8]> for Hash<$($gen),*> {
- fn as_ref(&self) -> &[u8; $bits / 8] {
- &self.0
- }
- }
-
- impl $(, $gen: $gent)*> Index for Hash<$($gen),*> {
- type Output = I::Output;
-
- #[inline]
- fn index(&self, index: I) -> &Self::Output {
- &self.0[index]
- }
- }
-
- impl<$($gen: $gent),*> From> for [u8; $bits / 8] {
- fn from(value: Hash<$($gen),*>) -> Self { value.0 }
- }
-
- #[cfg(feature = "bincode")]
- impl<$($gen: $gent),*> bincode::Encode for Hash<$($gen),*> {
- fn encode(&self, encoder: &mut E) -> Result<(), bincode::error::EncodeError> {
- use crate::Hash;
- // Use as_byte_array so that we don’t have to consume self
- self.as_byte_array().encode(encoder)
- }
- }
-
- #[cfg(feature = "bincode")]
- impl bincode::Decode for Hash<$($gen),*> {
- fn decode>(decoder: &mut D) -> Result {
- use crate::Hash;
- // Decode a fixed-length byte array and then create the Hash
- let bytes: [u8; $bits / 8] = <[u8; $bits / 8]>::decode(decoder)?;
- Ok(Self::from_byte_array(bytes))
- }
- }
-
- #[cfg(feature = "bincode")]
- impl<'de, C $(, $gen: $gent)*> bincode::BorrowDecode<'de, C> for Hash<$($gen),*> {
- fn borrow_decode>(decoder: &mut D) -> Result {
- use std::convert::TryInto;
- // Decode a borrowed reference to a byte slice
- let bytes: &[u8] = bincode::BorrowDecode::borrow_decode(decoder)?;
-
- // Convert the slice into a fixed-size array
- let bytes: &[u8; $bits / 8] = bytes.try_into().map_err(|_| bincode::error::DecodeError::Other("Incorrect byte length".into()))?;
-
- // Construct the hash from the reference
- Ok(Self::from_bytes_ref(bytes).clone())
- }
- }
-
- impl<$($gen: $gent),*> crate::Hash for Hash<$($gen),*> {
- type Engine = HashEngine;
- type Bytes = [u8; $bits / 8];
-
- const LEN: usize = $bits / 8;
- const DISPLAY_BACKWARD: bool = $reverse;
-
- fn engine() -> Self::Engine {
- Self::internal_engine()
- }
-
- fn from_engine(e: HashEngine) -> Hash<$($gen),*> {
- from_engine(e)
- }
-
- fn from_slice(sl: &[u8]) -> Result, Error> {
- if sl.len() != $bits / 8 {
- Err(Error::InvalidLength(Self::LEN, sl.len()))
- } else {
- let mut ret = [0; $bits / 8];
- ret.copy_from_slice(sl);
- Ok(Self::internal_new(ret))
- }
- }
-
- fn to_byte_array(self) -> Self::Bytes {
- self.0
- }
-
- fn as_byte_array(&self) -> &Self::Bytes {
- &self.0
- }
-
- fn from_byte_array(bytes: Self::Bytes) -> Self {
- Self::internal_new(bytes)
- }
-
- fn all_zeros() -> Self {
- Hash::internal_new([0x00; $bits / 8])
- }
- }
- }
-}
-pub(crate) use hash_trait_impls;
-
-/// Creates a type called `Hash` and implements standard interface for it.
-///
-/// The created type will have all standard derives, `Hash` impl and implementation of
-/// `internal_engine` returning default. The created type has a single field.
-///
-/// Arguments:
-///
-/// * `$bits` - the number of bits of the hash type
-/// * `$reverse` - `true` if the hash should be displayed backwards, `false` otherwise
-/// * `$doc` - doc string to put on the type
-/// * `$schemars` - a literal that goes into `schema_with`.
-///
-/// The `from_engine` free-standing function is still required with this macro. See the doc of
-/// [`hash_trait_impls`].
-macro_rules! hash_type {
- ($bits:expr, $reverse:expr, $doc:literal, $schemars:literal) => {
- #[doc = $doc]
- #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
- #[cfg_attr(feature = "schemars", derive(crate::schemars::JsonSchema))]
- #[repr(transparent)]
- pub struct Hash(
- #[cfg_attr(feature = "schemars", schemars(schema_with = $schemars))] [u8; $bits / 8],
- );
-
- impl Hash {
- fn internal_new(arr: [u8; $bits / 8]) -> Self {
- Hash(arr)
- }
-
- fn internal_engine() -> HashEngine {
- Default::default()
- }
- }
-
- crate::internal_macros::hash_trait_impls!($bits, $reverse);
- };
-}
-pub(crate) use hash_type;
diff --git a/hashes/src/lib.rs b/hashes/src/lib.rs
index be5153cdc..68dfe07ee 100644
--- a/hashes/src/lib.rs
+++ b/hashes/src/lib.rs
@@ -14,10 +14,10 @@
//! Rust hashes library.
//!
-//! This is a simple, no-dependency library which implements the hash functions
-//! needed by Bitcoin. These are SHA256, SHA256d, and RIPEMD160. As an ancillary
-//! thing, it exposes hexadecimal serialization and deserialization, since these
-//! are needed to display hashes anyway.
+//! The hash functions themselves are re-exported from `bitcoin_hashes`. What
+//! this crate adds is the Dash newtype machinery over them: `hash_newtype!`
+//! and its `bincode`, `serde` and hex surface, plus the batch SipHash used by
+//! compact filter matching.
//!
//! ## Commonly used operations
//!
@@ -93,10 +93,8 @@
#[cfg(feature = "serde")]
pub extern crate serde;
-#[cfg(all(test, feature = "serde"))]
-extern crate serde_test;
-// #[cfg(bench)]
-// extern crate test;
+
+pub extern crate bitcoin_hashes;
#[doc(hidden)]
pub mod _export {
@@ -106,146 +104,24 @@ pub mod _export {
}
}
-#[cfg(feature = "schemars")]
-extern crate actual_schemars as schemars;
+// Primitives come straight from upstream.
+// The tag helpers are upstream's verbatim. Only `sha256t_hash_newtype!` stays
+// ours, so that tagged hashes route through our `hash_newtype!`.
+pub use bitcoin_hashes::{
+ cmp, hash160, hex, hmac, ripemd160, sha1, sha256, sha256d, sha512, sha512_256, FromSliceError,
+ Hash, HashEngine, Hmac, HmacEngine,
+};
+pub use bitcoin_hashes::{sha256t_hash_newtype_tag, sha256t_hash_newtype_tag_constructor};
+
+/// Kept under the old Dash name.
+pub type Error = FromSliceError;
-mod internal_macros;
#[macro_use]
mod util;
#[macro_use]
pub mod serde_macros;
mod bincode_macros;
-pub mod cmp;
-pub mod error;
-pub mod hash160;
#[cfg(feature = "x11")]
pub mod hash_x11;
-pub mod hex;
-pub mod hmac;
-mod impls;
-pub mod ripemd160;
-pub mod sha1;
-pub mod sha256;
-pub mod sha256d;
pub mod sha256t;
-pub mod sha512;
-pub mod sha512_256;
pub mod siphash24;
-
-use core::{borrow, fmt, hash, ops};
-
-pub use error::Error;
-pub use hmac::{Hmac, HmacEngine};
-
-/// A hashing engine which bytes can be serialized into.
-pub trait HashEngine: Clone + Default {
- /// Byte array representing the internal state of the hash engine.
- type MidState;
-
- /// Outputs the midstate of the hash engine. This function should not be
- /// used directly unless you really know what you're doing.
- fn midstate(&self) -> Self::MidState;
-
- /// Length of the hash's internal block size, in bytes.
- const BLOCK_SIZE: usize;
-
- /// Add data to the hash engine.
- fn input(&mut self, data: &[u8]);
-
- /// Return the number of bytes already n_bytes_hashed(inputted).
- fn n_bytes_hashed(&self) -> usize;
-}
-
-/// Trait which applies to hashes of all types.
-pub trait Hash:
- Copy
- + Clone
- + PartialEq
- + Eq
- + PartialOrd
- + Ord
- + hash::Hash
- + fmt::Debug
- + fmt::Display
- + fmt::LowerHex
- + ops::Index
- + ops::Index, Output = [u8]>
- + ops::Index, Output = [u8]>
- + ops::Index, Output = [u8]>
- + ops::Index
- + borrow::Borrow<[u8]>
-{
- /// A hashing engine which bytes can be serialized into. It is expected
- /// to implement the `io::Write` trait, and to never return errors under
- /// any conditions.
- type Engine: HashEngine;
-
- /// The byte array that represents the hash internally.
- type Bytes: hex::FromHex + Copy;
-
- /// Constructs a new engine.
- fn engine() -> Self::Engine {
- Self::Engine::default()
- }
-
- /// Produces a hash from the current state of a given engine.
- fn from_engine(e: Self::Engine) -> Self;
-
- /// Length of the hash, in bytes.
- const LEN: usize;
-
- /// Copies a byte slice into a hash object.
- fn from_slice(sl: &[u8]) -> Result;
-
- /// Hashes some bytes.
- fn hash(data: &[u8]) -> Self {
- let mut engine = Self::engine();
- engine.input(data);
- Self::from_engine(engine)
- }
-
- /// Flag indicating whether user-visible serializations of this hash
- /// should be backward. For some reason Satoshi decided this should be
- /// true for `Sha256dHash`, so here we are.
- const DISPLAY_BACKWARD: bool = false;
-
- /// Returns the underlying byte array.
- fn to_byte_array(self) -> Self::Bytes;
-
- /// Returns a reference to the underlying byte array.
- fn as_byte_array(&self) -> &Self::Bytes;
-
- /// Constructs a hash from the underlying byte array.
- fn from_byte_array(bytes: Self::Bytes) -> Self;
-
- /// Returns an all zero hash.
- ///
- /// An all zeros hash is a made up construct because there is not a known input that can create
- /// it, however it is used in various places in Bitcoin e.g., the Bitcoin genesis block's
- /// previous blockhash and the coinbase transaction's outpoint txid.
- fn all_zeros() -> Self;
-}
-
-#[cfg(test)]
-mod tests {
- use crate::{sha256d, Hash};
-
- hash_newtype! {
- /// A test newtype
- struct TestNewtype(sha256d::Hash);
-
- /// A test newtype
- struct TestNewtype2(sha256d::Hash);
- }
-
- #[test]
- fn convert_newtypes() {
- let h1 = TestNewtype::hash(&[]);
- let h2: TestNewtype2 = h1.to_raw_hash().into();
- assert_eq!(&h1[..], &h2[..]);
-
- let h = sha256d::Hash::hash(&[]);
- let h2: TestNewtype = h.to_string().parse().unwrap();
- assert_eq!(h2.to_raw_hash(), h);
- }
-}
diff --git a/hashes/src/ripemd160.rs b/hashes/src/ripemd160.rs
deleted file mode 100644
index 4e532cb1f..000000000
--- a/hashes/src/ripemd160.rs
+++ /dev/null
@@ -1,520 +0,0 @@
-// Bitcoin Hashes Library
-// Written in 2018 by
-// Andrew Poelstra
-//
-// To the extent possible under law, the author(s) have dedicated all
-// copyright and related and neighboring rights to this software to
-// the public domain worldwide. This software is distributed without
-// any warranty.
-//
-// You should have received a copy of the CC0 Public Domain Dedication
-// along with this software.
-// If not, see .
-//
-
-// This module is largely copied from the rust-crypto ripemd.rs file;
-// while rust-crypto is licensed under Apache, that file specifically
-// was written entirely by Andrew Poelstra, who is re-licensing its
-// contents here as CC0.
-
-//! RIPEMD160 implementation.
-//!
-
-use core::ops::Index;
-use core::slice::SliceIndex;
-use core::{cmp, str};
-
-use crate::{Error, HashEngine as _};
-
-crate::internal_macros::hash_type! {
- 160,
- false,
- "Output of the RIPEMD160 hash function.",
- "crate::util::json_hex_string::len_20"
-}
-
-#[cfg(not(fuzzing))]
-fn from_engine(mut e: HashEngine) -> Hash {
- // pad buffer with a single 1-bit then all 0s, until there are exactly 8 bytes remaining
- let data_len = e.length as u64;
-
- let zeroes = [0; BLOCK_SIZE - 8];
- e.input(&[0x80]);
- if e.length % BLOCK_SIZE > zeroes.len() {
- e.input(&zeroes);
- }
- let pad_length = zeroes.len() - (e.length % BLOCK_SIZE);
- e.input(&zeroes[..pad_length]);
- debug_assert_eq!(e.length % BLOCK_SIZE, zeroes.len());
-
- e.input(&(8 * data_len).to_le_bytes());
- debug_assert_eq!(e.length % BLOCK_SIZE, 0);
-
- Hash(e.midstate())
-}
-
-#[cfg(fuzzing)]
-fn from_engine(e: HashEngine) -> Hash {
- let mut res = e.midstate();
- res[0] ^= (e.length & 0xff) as u8;
- Hash(res)
-}
-
-const BLOCK_SIZE: usize = 64;
-
-/// Engine to compute RIPEMD160 hash function.
-#[derive(Clone)]
-pub struct HashEngine {
- buffer: [u8; BLOCK_SIZE],
- h: [u32; 5],
- length: usize,
-}
-
-impl Default for HashEngine {
- fn default() -> Self {
- HashEngine {
- h: [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0],
- length: 0,
- buffer: [0; BLOCK_SIZE],
- }
- }
-}
-
-impl crate::HashEngine for HashEngine {
- type MidState = [u8; 20];
-
- #[cfg(not(fuzzing))]
- fn midstate(&self) -> [u8; 20] {
- let mut ret = [0; 20];
- for (val, ret_bytes) in self.h.iter().zip(ret.as_chunks_mut::<4>().0) {
- *ret_bytes = val.to_le_bytes();
- }
- ret
- }
-
- #[cfg(fuzzing)]
- fn midstate(&self) -> [u8; 20] {
- let mut ret = [0; 20];
- ret.copy_from_slice(&self.buffer[..20]);
- ret
- }
-
- const BLOCK_SIZE: usize = 64;
-
- fn n_bytes_hashed(&self) -> usize {
- self.length
- }
-
- engine_input_impl!();
-}
-
-macro_rules! round(
- ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr,
- $x:expr, $bits:expr, $add:expr, $round:expr) => ({
- $a = $a.wrapping_add($round).wrapping_add($x).wrapping_add($add);
- $a = $a.rotate_left($bits).wrapping_add($e);
- $c = $c.rotate_left(10);
- });
-);
-
-macro_rules! process_block(
- ($h:expr, $data:expr,
- $( round1: h_ordering $f0:expr, $f1:expr, $f2:expr, $f3:expr, $f4:expr;
- data_index $data_index1:expr; roll_shift $bits1:expr; )*
- $( round2: h_ordering $g0:expr, $g1:expr, $g2:expr, $g3:expr, $g4:expr;
- data_index $data_index2:expr; roll_shift $bits2:expr; )*
- $( round3: h_ordering $h0:expr, $h1:expr, $h2:expr, $h3:expr, $h4:expr;
- data_index $data_index3:expr; roll_shift $bits3:expr; )*
- $( round4: h_ordering $i0:expr, $i1:expr, $i2:expr, $i3:expr, $i4:expr;
- data_index $data_index4:expr; roll_shift $bits4:expr; )*
- $( round5: h_ordering $j0:expr, $j1:expr, $j2:expr, $j3:expr, $j4:expr;
- data_index $data_index5:expr; roll_shift $bits5:expr; )*
- $( par_round1: h_ordering $pj0:expr, $pj1:expr, $pj2:expr, $pj3:expr, $pj4:expr;
- data_index $pdata_index1:expr; roll_shift $pbits1:expr; )*
- $( par_round2: h_ordering $pi0:expr, $pi1:expr, $pi2:expr, $pi3:expr, $pi4:expr;
- data_index $pdata_index2:expr; roll_shift $pbits2:expr; )*
- $( par_round3: h_ordering $ph0:expr, $ph1:expr, $ph2:expr, $ph3:expr, $ph4:expr;
- data_index $pdata_index3:expr; roll_shift $pbits3:expr; )*
- $( par_round4: h_ordering $pg0:expr, $pg1:expr, $pg2:expr, $pg3:expr, $pg4:expr;
- data_index $pdata_index4:expr; roll_shift $pbits4:expr; )*
- $( par_round5: h_ordering $pf0:expr, $pf1:expr, $pf2:expr, $pf3:expr, $pf4:expr;
- data_index $pdata_index5:expr; roll_shift $pbits5:expr; )*
- ) => ({
- let mut bb = $h;
- let mut bbb = $h;
-
- // Round 1
- $( round!(bb[$f0], bb[$f1], bb[$f2], bb[$f3], bb[$f4],
- $data[$data_index1], $bits1, 0x00000000,
- bb[$f1] ^ bb[$f2] ^ bb[$f3]); )*
-
- // Round 2
- $( round!(bb[$g0], bb[$g1], bb[$g2], bb[$g3], bb[$g4],
- $data[$data_index2], $bits2, 0x5a827999,
- (bb[$g1] & bb[$g2]) | (!bb[$g1] & bb[$g3])); )*
-
- // Round 3
- $( round!(bb[$h0], bb[$h1], bb[$h2], bb[$h3], bb[$h4],
- $data[$data_index3], $bits3, 0x6ed9eba1,
- (bb[$h1] | !bb[$h2]) ^ bb[$h3]); )*
-
- // Round 4
- $( round!(bb[$i0], bb[$i1], bb[$i2], bb[$i3], bb[$i4],
- $data[$data_index4], $bits4, 0x8f1bbcdc,
- (bb[$i1] & bb[$i3]) | (bb[$i2] & !bb[$i3])); )*
-
- // Round 5
- $( round!(bb[$j0], bb[$j1], bb[$j2], bb[$j3], bb[$j4],
- $data[$data_index5], $bits5, 0xa953fd4e,
- bb[$j1] ^ (bb[$j2] | !bb[$j3])); )*
-
- // Parallel rounds: these are the same as the previous five
- // rounds except that the constants have changed, we work
- // with the other buffer, and they are applied in reverse
- // order.
-
- // Parallel Round 1
- $( round!(bbb[$pj0], bbb[$pj1], bbb[$pj2], bbb[$pj3], bbb[$pj4],
- $data[$pdata_index1], $pbits1, 0x50a28be6,
- bbb[$pj1] ^ (bbb[$pj2] | !bbb[$pj3])); )*
-
- // Porallel Round 2
- $( round!(bbb[$pi0], bbb[$pi1], bbb[$pi2], bbb[$pi3], bbb[$pi4],
- $data[$pdata_index2], $pbits2, 0x5c4dd124,
- (bbb[$pi1] & bbb[$pi3]) | (bbb[$pi2] & !bbb[$pi3])); )*
-
- // Parallel Round 3
- $( round!(bbb[$ph0], bbb[$ph1], bbb[$ph2], bbb[$ph3], bbb[$ph4],
- $data[$pdata_index3], $pbits3, 0x6d703ef3,
- (bbb[$ph1] | !bbb[$ph2]) ^ bbb[$ph3]); )*
-
- // Parallel Round 4
- $( round!(bbb[$pg0], bbb[$pg1], bbb[$pg2], bbb[$pg3], bbb[$pg4],
- $data[$pdata_index4], $pbits4, 0x7a6d76e9,
- (bbb[$pg1] & bbb[$pg2]) | (!bbb[$pg1] & bbb[$pg3])); )*
-
- // Parallel Round 5
- $( round!(bbb[$pf0], bbb[$pf1], bbb[$pf2], bbb[$pf3], bbb[$pf4],
- $data[$pdata_index5], $pbits5, 0x00000000,
- bbb[$pf1] ^ bbb[$pf2] ^ bbb[$pf3]); )*
-
- // Combine results
- bbb[3] = bbb[3].wrapping_add($h[1]).wrapping_add(bb[2]);
- $h[1] = $h[2].wrapping_add(bb[3]).wrapping_add(bbb[4]);
- $h[2] = $h[3].wrapping_add(bb[4]).wrapping_add(bbb[0]);
- $h[3] = $h[4].wrapping_add(bb[0]).wrapping_add(bbb[1]);
- $h[4] = $h[0].wrapping_add(bb[1]).wrapping_add(bbb[2]);
- $h[0] = bbb[3];
- });
-);
-
-impl HashEngine {
- fn process_block(&mut self) {
- debug_assert_eq!(self.buffer.len(), BLOCK_SIZE);
-
- let mut w = [0u32; 16];
- for (w_val, buff_bytes) in w.iter_mut().zip(self.buffer.as_chunks::<4>().0) {
- *w_val = u32::from_le_bytes(*buff_bytes)
- }
-
- process_block!(self.h, w,
- // Round 1
- round1: h_ordering 0, 1, 2, 3, 4; data_index 0; roll_shift 11;
- round1: h_ordering 4, 0, 1, 2, 3; data_index 1; roll_shift 14;
- round1: h_ordering 3, 4, 0, 1, 2; data_index 2; roll_shift 15;
- round1: h_ordering 2, 3, 4, 0, 1; data_index 3; roll_shift 12;
- round1: h_ordering 1, 2, 3, 4, 0; data_index 4; roll_shift 5;
- round1: h_ordering 0, 1, 2, 3, 4; data_index 5; roll_shift 8;
- round1: h_ordering 4, 0, 1, 2, 3; data_index 6; roll_shift 7;
- round1: h_ordering 3, 4, 0, 1, 2; data_index 7; roll_shift 9;
- round1: h_ordering 2, 3, 4, 0, 1; data_index 8; roll_shift 11;
- round1: h_ordering 1, 2, 3, 4, 0; data_index 9; roll_shift 13;
- round1: h_ordering 0, 1, 2, 3, 4; data_index 10; roll_shift 14;
- round1: h_ordering 4, 0, 1, 2, 3; data_index 11; roll_shift 15;
- round1: h_ordering 3, 4, 0, 1, 2; data_index 12; roll_shift 6;
- round1: h_ordering 2, 3, 4, 0, 1; data_index 13; roll_shift 7;
- round1: h_ordering 1, 2, 3, 4, 0; data_index 14; roll_shift 9;
- round1: h_ordering 0, 1, 2, 3, 4; data_index 15; roll_shift 8;
-
- // Round 2
- round2: h_ordering 4, 0, 1, 2, 3; data_index 7; roll_shift 7;
- round2: h_ordering 3, 4, 0, 1, 2; data_index 4; roll_shift 6;
- round2: h_ordering 2, 3, 4, 0, 1; data_index 13; roll_shift 8;
- round2: h_ordering 1, 2, 3, 4, 0; data_index 1; roll_shift 13;
- round2: h_ordering 0, 1, 2, 3, 4; data_index 10; roll_shift 11;
- round2: h_ordering 4, 0, 1, 2, 3; data_index 6; roll_shift 9;
- round2: h_ordering 3, 4, 0, 1, 2; data_index 15; roll_shift 7;
- round2: h_ordering 2, 3, 4, 0, 1; data_index 3; roll_shift 15;
- round2: h_ordering 1, 2, 3, 4, 0; data_index 12; roll_shift 7;
- round2: h_ordering 0, 1, 2, 3, 4; data_index 0; roll_shift 12;
- round2: h_ordering 4, 0, 1, 2, 3; data_index 9; roll_shift 15;
- round2: h_ordering 3, 4, 0, 1, 2; data_index 5; roll_shift 9;
- round2: h_ordering 2, 3, 4, 0, 1; data_index 2; roll_shift 11;
- round2: h_ordering 1, 2, 3, 4, 0; data_index 14; roll_shift 7;
- round2: h_ordering 0, 1, 2, 3, 4; data_index 11; roll_shift 13;
- round2: h_ordering 4, 0, 1, 2, 3; data_index 8; roll_shift 12;
-
- // Round 3
- round3: h_ordering 3, 4, 0, 1, 2; data_index 3; roll_shift 11;
- round3: h_ordering 2, 3, 4, 0, 1; data_index 10; roll_shift 13;
- round3: h_ordering 1, 2, 3, 4, 0; data_index 14; roll_shift 6;
- round3: h_ordering 0, 1, 2, 3, 4; data_index 4; roll_shift 7;
- round3: h_ordering 4, 0, 1, 2, 3; data_index 9; roll_shift 14;
- round3: h_ordering 3, 4, 0, 1, 2; data_index 15; roll_shift 9;
- round3: h_ordering 2, 3, 4, 0, 1; data_index 8; roll_shift 13;
- round3: h_ordering 1, 2, 3, 4, 0; data_index 1; roll_shift 15;
- round3: h_ordering 0, 1, 2, 3, 4; data_index 2; roll_shift 14;
- round3: h_ordering 4, 0, 1, 2, 3; data_index 7; roll_shift 8;
- round3: h_ordering 3, 4, 0, 1, 2; data_index 0; roll_shift 13;
- round3: h_ordering 2, 3, 4, 0, 1; data_index 6; roll_shift 6;
- round3: h_ordering 1, 2, 3, 4, 0; data_index 13; roll_shift 5;
- round3: h_ordering 0, 1, 2, 3, 4; data_index 11; roll_shift 12;
- round3: h_ordering 4, 0, 1, 2, 3; data_index 5; roll_shift 7;
- round3: h_ordering 3, 4, 0, 1, 2; data_index 12; roll_shift 5;
-
- // Round 4
- round4: h_ordering 2, 3, 4, 0, 1; data_index 1; roll_shift 11;
- round4: h_ordering 1, 2, 3, 4, 0; data_index 9; roll_shift 12;
- round4: h_ordering 0, 1, 2, 3, 4; data_index 11; roll_shift 14;
- round4: h_ordering 4, 0, 1, 2, 3; data_index 10; roll_shift 15;
- round4: h_ordering 3, 4, 0, 1, 2; data_index 0; roll_shift 14;
- round4: h_ordering 2, 3, 4, 0, 1; data_index 8; roll_shift 15;
- round4: h_ordering 1, 2, 3, 4, 0; data_index 12; roll_shift 9;
- round4: h_ordering 0, 1, 2, 3, 4; data_index 4; roll_shift 8;
- round4: h_ordering 4, 0, 1, 2, 3; data_index 13; roll_shift 9;
- round4: h_ordering 3, 4, 0, 1, 2; data_index 3; roll_shift 14;
- round4: h_ordering 2, 3, 4, 0, 1; data_index 7; roll_shift 5;
- round4: h_ordering 1, 2, 3, 4, 0; data_index 15; roll_shift 6;
- round4: h_ordering 0, 1, 2, 3, 4; data_index 14; roll_shift 8;
- round4: h_ordering 4, 0, 1, 2, 3; data_index 5; roll_shift 6;
- round4: h_ordering 3, 4, 0, 1, 2; data_index 6; roll_shift 5;
- round4: h_ordering 2, 3, 4, 0, 1; data_index 2; roll_shift 12;
-
- // Round 5
- round5: h_ordering 1, 2, 3, 4, 0; data_index 4; roll_shift 9;
- round5: h_ordering 0, 1, 2, 3, 4; data_index 0; roll_shift 15;
- round5: h_ordering 4, 0, 1, 2, 3; data_index 5; roll_shift 5;
- round5: h_ordering 3, 4, 0, 1, 2; data_index 9; roll_shift 11;
- round5: h_ordering 2, 3, 4, 0, 1; data_index 7; roll_shift 6;
- round5: h_ordering 1, 2, 3, 4, 0; data_index 12; roll_shift 8;
- round5: h_ordering 0, 1, 2, 3, 4; data_index 2; roll_shift 13;
- round5: h_ordering 4, 0, 1, 2, 3; data_index 10; roll_shift 12;
- round5: h_ordering 3, 4, 0, 1, 2; data_index 14; roll_shift 5;
- round5: h_ordering 2, 3, 4, 0, 1; data_index 1; roll_shift 12;
- round5: h_ordering 1, 2, 3, 4, 0; data_index 3; roll_shift 13;
- round5: h_ordering 0, 1, 2, 3, 4; data_index 8; roll_shift 14;
- round5: h_ordering 4, 0, 1, 2, 3; data_index 11; roll_shift 11;
- round5: h_ordering 3, 4, 0, 1, 2; data_index 6; roll_shift 8;
- round5: h_ordering 2, 3, 4, 0, 1; data_index 15; roll_shift 5;
- round5: h_ordering 1, 2, 3, 4, 0; data_index 13; roll_shift 6;
-
- // Porallel Round 1;
- par_round1: h_ordering 0, 1, 2, 3, 4; data_index 5; roll_shift 8;
- par_round1: h_ordering 4, 0, 1, 2, 3; data_index 14; roll_shift 9;
- par_round1: h_ordering 3, 4, 0, 1, 2; data_index 7; roll_shift 9;
- par_round1: h_ordering 2, 3, 4, 0, 1; data_index 0; roll_shift 11;
- par_round1: h_ordering 1, 2, 3, 4, 0; data_index 9; roll_shift 13;
- par_round1: h_ordering 0, 1, 2, 3, 4; data_index 2; roll_shift 15;
- par_round1: h_ordering 4, 0, 1, 2, 3; data_index 11; roll_shift 15;
- par_round1: h_ordering 3, 4, 0, 1, 2; data_index 4; roll_shift 5;
- par_round1: h_ordering 2, 3, 4, 0, 1; data_index 13; roll_shift 7;
- par_round1: h_ordering 1, 2, 3, 4, 0; data_index 6; roll_shift 7;
- par_round1: h_ordering 0, 1, 2, 3, 4; data_index 15; roll_shift 8;
- par_round1: h_ordering 4, 0, 1, 2, 3; data_index 8; roll_shift 11;
- par_round1: h_ordering 3, 4, 0, 1, 2; data_index 1; roll_shift 14;
- par_round1: h_ordering 2, 3, 4, 0, 1; data_index 10; roll_shift 14;
- par_round1: h_ordering 1, 2, 3, 4, 0; data_index 3; roll_shift 12;
- par_round1: h_ordering 0, 1, 2, 3, 4; data_index 12; roll_shift 6;
-
- // Parallel Round 2
- par_round2: h_ordering 4, 0, 1, 2, 3; data_index 6; roll_shift 9;
- par_round2: h_ordering 3, 4, 0, 1, 2; data_index 11; roll_shift 13;
- par_round2: h_ordering 2, 3, 4, 0, 1; data_index 3; roll_shift 15;
- par_round2: h_ordering 1, 2, 3, 4, 0; data_index 7; roll_shift 7;
- par_round2: h_ordering 0, 1, 2, 3, 4; data_index 0; roll_shift 12;
- par_round2: h_ordering 4, 0, 1, 2, 3; data_index 13; roll_shift 8;
- par_round2: h_ordering 3, 4, 0, 1, 2; data_index 5; roll_shift 9;
- par_round2: h_ordering 2, 3, 4, 0, 1; data_index 10; roll_shift 11;
- par_round2: h_ordering 1, 2, 3, 4, 0; data_index 14; roll_shift 7;
- par_round2: h_ordering 0, 1, 2, 3, 4; data_index 15; roll_shift 7;
- par_round2: h_ordering 4, 0, 1, 2, 3; data_index 8; roll_shift 12;
- par_round2: h_ordering 3, 4, 0, 1, 2; data_index 12; roll_shift 7;
- par_round2: h_ordering 2, 3, 4, 0, 1; data_index 4; roll_shift 6;
- par_round2: h_ordering 1, 2, 3, 4, 0; data_index 9; roll_shift 15;
- par_round2: h_ordering 0, 1, 2, 3, 4; data_index 1; roll_shift 13;
- par_round2: h_ordering 4, 0, 1, 2, 3; data_index 2; roll_shift 11;
-
- // Parallel Round 3
- par_round3: h_ordering 3, 4, 0, 1, 2; data_index 15; roll_shift 9;
- par_round3: h_ordering 2, 3, 4, 0, 1; data_index 5; roll_shift 7;
- par_round3: h_ordering 1, 2, 3, 4, 0; data_index 1; roll_shift 15;
- par_round3: h_ordering 0, 1, 2, 3, 4; data_index 3; roll_shift 11;
- par_round3: h_ordering 4, 0, 1, 2, 3; data_index 7; roll_shift 8;
- par_round3: h_ordering 3, 4, 0, 1, 2; data_index 14; roll_shift 6;
- par_round3: h_ordering 2, 3, 4, 0, 1; data_index 6; roll_shift 6;
- par_round3: h_ordering 1, 2, 3, 4, 0; data_index 9; roll_shift 14;
- par_round3: h_ordering 0, 1, 2, 3, 4; data_index 11; roll_shift 12;
- par_round3: h_ordering 4, 0, 1, 2, 3; data_index 8; roll_shift 13;
- par_round3: h_ordering 3, 4, 0, 1, 2; data_index 12; roll_shift 5;
- par_round3: h_ordering 2, 3, 4, 0, 1; data_index 2; roll_shift 14;
- par_round3: h_ordering 1, 2, 3, 4, 0; data_index 10; roll_shift 13;
- par_round3: h_ordering 0, 1, 2, 3, 4; data_index 0; roll_shift 13;
- par_round3: h_ordering 4, 0, 1, 2, 3; data_index 4; roll_shift 7;
- par_round3: h_ordering 3, 4, 0, 1, 2; data_index 13; roll_shift 5;
-
- // Parallel Round 4
- par_round4: h_ordering 2, 3, 4, 0, 1; data_index 8; roll_shift 15;
- par_round4: h_ordering 1, 2, 3, 4, 0; data_index 6; roll_shift 5;
- par_round4: h_ordering 0, 1, 2, 3, 4; data_index 4; roll_shift 8;
- par_round4: h_ordering 4, 0, 1, 2, 3; data_index 1; roll_shift 11;
- par_round4: h_ordering 3, 4, 0, 1, 2; data_index 3; roll_shift 14;
- par_round4: h_ordering 2, 3, 4, 0, 1; data_index 11; roll_shift 14;
- par_round4: h_ordering 1, 2, 3, 4, 0; data_index 15; roll_shift 6;
- par_round4: h_ordering 0, 1, 2, 3, 4; data_index 0; roll_shift 14;
- par_round4: h_ordering 4, 0, 1, 2, 3; data_index 5; roll_shift 6;
- par_round4: h_ordering 3, 4, 0, 1, 2; data_index 12; roll_shift 9;
- par_round4: h_ordering 2, 3, 4, 0, 1; data_index 2; roll_shift 12;
- par_round4: h_ordering 1, 2, 3, 4, 0; data_index 13; roll_shift 9;
- par_round4: h_ordering 0, 1, 2, 3, 4; data_index 9; roll_shift 12;
- par_round4: h_ordering 4, 0, 1, 2, 3; data_index 7; roll_shift 5;
- par_round4: h_ordering 3, 4, 0, 1, 2; data_index 10; roll_shift 15;
- par_round4: h_ordering 2, 3, 4, 0, 1; data_index 14; roll_shift 8;
-
- // Parallel Round 5
- par_round5: h_ordering 1, 2, 3, 4, 0; data_index 12; roll_shift 8;
- par_round5: h_ordering 0, 1, 2, 3, 4; data_index 15; roll_shift 5;
- par_round5: h_ordering 4, 0, 1, 2, 3; data_index 10; roll_shift 12;
- par_round5: h_ordering 3, 4, 0, 1, 2; data_index 4; roll_shift 9;
- par_round5: h_ordering 2, 3, 4, 0, 1; data_index 1; roll_shift 12;
- par_round5: h_ordering 1, 2, 3, 4, 0; data_index 5; roll_shift 5;
- par_round5: h_ordering 0, 1, 2, 3, 4; data_index 8; roll_shift 14;
- par_round5: h_ordering 4, 0, 1, 2, 3; data_index 7; roll_shift 6;
- par_round5: h_ordering 3, 4, 0, 1, 2; data_index 6; roll_shift 8;
- par_round5: h_ordering 2, 3, 4, 0, 1; data_index 2; roll_shift 13;
- par_round5: h_ordering 1, 2, 3, 4, 0; data_index 13; roll_shift 6;
- par_round5: h_ordering 0, 1, 2, 3, 4; data_index 14; roll_shift 5;
- par_round5: h_ordering 4, 0, 1, 2, 3; data_index 0; roll_shift 15;
- par_round5: h_ordering 3, 4, 0, 1, 2; data_index 3; roll_shift 13;
- par_round5: h_ordering 2, 3, 4, 0, 1; data_index 9; roll_shift 11;
- par_round5: h_ordering 1, 2, 3, 4, 0; data_index 11; roll_shift 11;
- );
- }
-}
-
-#[cfg(test)]
-mod tests {
- #[test]
- fn test() {
- use std::convert::TryFrom;
-
- use crate::{ripemd160, Hash, HashEngine};
-
- #[derive(Clone)]
- struct Test {
- input: &'static str,
- output: Vec,
- output_str: &'static str,
- }
-
- #[rustfmt::skip]
- let tests = vec![
- // Test messages from FIPS 180-1
- Test {
- input: "abc",
- output: vec![
- 0x8e, 0xb2, 0x08, 0xf7,
- 0xe0, 0x5d, 0x98, 0x7a,
- 0x9b, 0x04, 0x4a, 0x8e,
- 0x98, 0xc6, 0xb0, 0x87,
- 0xf1, 0x5a, 0x0b, 0xfc,
- ],
- output_str: "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc"
- },
- Test {
- input:
- "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
- output: vec![
- 0x12, 0xa0, 0x53, 0x38,
- 0x4a, 0x9c, 0x0c, 0x88,
- 0xe4, 0x05, 0xa0, 0x6c,
- 0x27, 0xdc, 0xf4, 0x9a,
- 0xda, 0x62, 0xeb, 0x2b,
- ],
- output_str: "12a053384a9c0c88e405a06c27dcf49ada62eb2b"
- },
- // Examples from wikipedia
- Test {
- input: "The quick brown fox jumps over the lazy dog",
- output: vec![
- 0x37, 0xf3, 0x32, 0xf6,
- 0x8d, 0xb7, 0x7b, 0xd9,
- 0xd7, 0xed, 0xd4, 0x96,
- 0x95, 0x71, 0xad, 0x67,
- 0x1c, 0xf9, 0xdd, 0x3b,
- ],
- output_str: "37f332f68db77bd9d7edd4969571ad671cf9dd3b",
- },
- Test {
- input: "The quick brown fox jumps over the lazy cog",
- output: vec![
- 0x13, 0x20, 0x72, 0xdf,
- 0x69, 0x09, 0x33, 0x83,
- 0x5e, 0xb8, 0xb6, 0xad,
- 0x0b, 0x77, 0xe7, 0xb6,
- 0xf1, 0x4a, 0xca, 0xd7,
- ],
- output_str: "132072df690933835eb8b6ad0b77e7b6f14acad7",
- },
- ];
-
- for mut test in tests {
- // Hash through high-level API, check hex encoding/decoding
- let hash = ripemd160::Hash::hash(test.input.as_bytes());
- assert_eq!(hash, test.output_str.parse::().expect("parse hex"));
- assert_eq!(&hash[..], &test.output[..]);
- assert_eq!(&hash.to_string(), &test.output_str);
- assert_eq!(
- ripemd160::Hash::from_bytes_ref(
- <&[u8; 20]>::try_from(&*test.output).expect("known length")
- ),
- &hash
- );
- assert_eq!(
- ripemd160::Hash::from_bytes_mut(
- <&mut [u8; 20]>::try_from(&mut *test.output).expect("known length")
- ),
- &hash
- );
-
- // Hash through engine, checking that we can input byte by byte
- let mut engine = ripemd160::Hash::engine();
- for ch in test.input.as_bytes() {
- engine.input(&[*ch]);
- }
- let manual_hash = ripemd160::Hash::from_engine(engine);
- assert_eq!(hash, manual_hash);
- assert_eq!(hash.as_byte_array(), test.output.as_slice());
- }
- }
-
- #[cfg(feature = "serde")]
- #[test]
- fn ripemd_serde() {
- use serde_test::{assert_tokens, Configure, Token};
-
- use crate::{ripemd160, Hash};
-
- #[rustfmt::skip]
- static HASH_BYTES: [u8; 20] = [
- 0x13, 0x20, 0x72, 0xdf,
- 0x69, 0x09, 0x33, 0x83,
- 0x5e, 0xb8, 0xb6, 0xad,
- 0x0b, 0x77, 0xe7, 0xb6,
- 0xf1, 0x4a, 0xca, 0xd7,
- ];
-
- let hash = ripemd160::Hash::from_slice(&HASH_BYTES).expect("right number of bytes");
- assert_tokens(&hash.compact(), &[Token::BorrowedBytes(&HASH_BYTES[..])]);
- assert_tokens(&hash.readable(), &[Token::Str("132072df690933835eb8b6ad0b77e7b6f14acad7")]);
- }
-}
diff --git a/hashes/src/serde_macros.rs b/hashes/src/serde_macros.rs
index 2f098c6db..ba94298d0 100644
--- a/hashes/src/serde_macros.rs
+++ b/hashes/src/serde_macros.rs
@@ -27,11 +27,10 @@ pub mod serde_details {
/// Single visitor that accepts every shape a hash can arrive in: an ASCII
/// hex string (`visit_str`), a UTF-8 byte slice that decodes as hex
- /// (`visit_bytes` of length `2*N` — note `N` is in BYTES per the macro,
- /// see `serde_impl!` invocation in `internal_macros.rs`), a raw byte
- /// slice of the hash's length-in-bytes (`visit_bytes` of length `N`),
- /// or a length-prefixed sequence of `u8` from non-self-describing
- /// formats (`visit_seq`, used by bincode).
+ /// (`visit_bytes` of length `2*N`, where `N` is in bytes as passed to
+ /// `serde_impl!`), a raw byte slice of the hash's length-in-bytes
+ /// (`visit_bytes` of length `N`), or a length-prefixed sequence of `u8`
+ /// from non-self-describing formats (`visit_seq`, used by bincode).
///
/// Required to interoperate with serde's `ContentDeserializer`, the
/// format-agnostic intermediate buffer serde uses to dispatch
@@ -78,10 +77,9 @@ pub mod serde_details {
E: de::Error,
{
// Disambiguate by length. A correctly-sized raw hash byte string
- // is exactly `N` bytes (`N` is in bytes per the macro — see
- // `serde_impl!` invocation in `internal_macros.rs`); a hex-encoded
- // form of that hash is `2*N` ASCII bytes. Any other length is
- // rejected.
+ // is exactly `N` bytes (`N` is in bytes as passed to
+ // `serde_impl!`); a hex-encoded form of that hash is `2*N` ASCII
+ // bytes. Any other length is rejected.
let raw_len_bytes = ValueT::N;
let hex_len_bytes = raw_len_bytes * 2;
if v.len() == raw_len_bytes {
diff --git a/hashes/src/sha1.rs b/hashes/src/sha1.rs
deleted file mode 100644
index 6bcaf0616..000000000
--- a/hashes/src/sha1.rs
+++ /dev/null
@@ -1,232 +0,0 @@
-// Bitcoin Hashes Library
-// Written in 2018 by
-// Andrew Poelstra
-//
-// To the extent possible under law, the author(s) have dedicated all
-// copyright and related and neighboring rights to this software to
-// the public domain worldwide. This software is distributed without
-// any warranty.
-//
-// You should have received a copy of the CC0 Public Domain Dedication
-// along with this software.
-// If not, see .
-//
-
-//! SHA1 implementation.
-//!
-
-use core::ops::Index;
-use core::slice::SliceIndex;
-use core::{cmp, str};
-
-use crate::{Error, HashEngine as _};
-
-crate::internal_macros::hash_type! {
- 160,
- false,
- "Output of the SHA1 hash function.",
- "crate::util::json_hex_string::len_20"
-}
-
-fn from_engine(mut e: HashEngine) -> Hash {
- // pad buffer with a single 1-bit then all 0s, until there are exactly 8 bytes remaining
- let data_len = e.length as u64;
-
- let zeroes = [0; BLOCK_SIZE - 8];
- e.input(&[0x80]);
- if e.length % BLOCK_SIZE > zeroes.len() {
- e.input(&zeroes);
- }
- let pad_length = zeroes.len() - (e.length % BLOCK_SIZE);
- e.input(&zeroes[..pad_length]);
- debug_assert_eq!(e.length % BLOCK_SIZE, zeroes.len());
-
- e.input(&(8 * data_len).to_be_bytes());
- debug_assert_eq!(e.length % BLOCK_SIZE, 0);
-
- Hash(e.midstate())
-}
-
-const BLOCK_SIZE: usize = 64;
-
-/// Engine to compute SHA1 hash function.
-#[derive(Clone)]
-pub struct HashEngine {
- buffer: [u8; BLOCK_SIZE],
- h: [u32; 5],
- length: usize,
-}
-
-impl Default for HashEngine {
- fn default() -> Self {
- HashEngine {
- h: [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0],
- length: 0,
- buffer: [0; BLOCK_SIZE],
- }
- }
-}
-
-impl crate::HashEngine for HashEngine {
- type MidState = [u8; 20];
-
- #[cfg(not(fuzzing))]
- fn midstate(&self) -> [u8; 20] {
- let mut ret = [0; 20];
- for (val, ret_bytes) in self.h.iter().zip(ret.as_chunks_mut::<4>().0) {
- *ret_bytes = val.to_be_bytes()
- }
- ret
- }
-
- #[cfg(fuzzing)]
- fn midstate(&self) -> [u8; 20] {
- let mut ret = [0; 20];
- ret.copy_from_slice(&self.buffer[..20]);
- ret
- }
-
- const BLOCK_SIZE: usize = 64;
-
- fn n_bytes_hashed(&self) -> usize {
- self.length
- }
-
- engine_input_impl!();
-}
-
-impl HashEngine {
- // Basic unoptimized algorithm from Wikipedia
- fn process_block(&mut self) {
- debug_assert_eq!(self.buffer.len(), BLOCK_SIZE);
-
- let mut w = [0u32; 80];
- for (w_val, buff_bytes) in w.iter_mut().zip(self.buffer.as_chunks::<4>().0) {
- *w_val = u32::from_be_bytes(*buff_bytes)
- }
- for i in 16..80 {
- w[i] = (w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]).rotate_left(1);
- }
-
- let mut a = self.h[0];
- let mut b = self.h[1];
- let mut c = self.h[2];
- let mut d = self.h[3];
- let mut e = self.h[4];
-
- for (i, &wi) in w.iter().enumerate() {
- let (f, k) = match i {
- 0..=19 => ((b & c) | (!b & d), 0x5a827999),
- 20..=39 => (b ^ c ^ d, 0x6ed9eba1),
- 40..=59 => ((b & c) | (b & d) | (c & d), 0x8f1bbcdc),
- 60..=79 => (b ^ c ^ d, 0xca62c1d6),
- _ => unreachable!(),
- };
-
- let new_a =
- a.rotate_left(5).wrapping_add(f).wrapping_add(e).wrapping_add(k).wrapping_add(wi);
- e = d;
- d = c;
- c = b.rotate_left(30);
- b = a;
- a = new_a;
- }
-
- self.h[0] = self.h[0].wrapping_add(a);
- self.h[1] = self.h[1].wrapping_add(b);
- self.h[2] = self.h[2].wrapping_add(c);
- self.h[3] = self.h[3].wrapping_add(d);
- self.h[4] = self.h[4].wrapping_add(e);
- }
-}
-
-#[cfg(test)]
-mod tests {
- #[test]
- fn test() {
- use crate::{sha1, Hash, HashEngine};
-
- #[derive(Clone)]
- struct Test {
- input: &'static str,
- output: Vec,
- output_str: &'static str,
- }
-
- #[rustfmt::skip]
- let tests = vec![
- // Examples from wikipedia
- Test {
- input: "",
- output: vec![
- 0xda, 0x39, 0xa3, 0xee,
- 0x5e, 0x6b, 0x4b, 0x0d,
- 0x32, 0x55, 0xbf, 0xef,
- 0x95, 0x60, 0x18, 0x90,
- 0xaf, 0xd8, 0x07, 0x09,
- ],
- output_str: "da39a3ee5e6b4b0d3255bfef95601890afd80709"
- },
- Test {
- input: "The quick brown fox jumps over the lazy dog",
- output: vec![
- 0x2f, 0xd4, 0xe1, 0xc6,
- 0x7a, 0x2d, 0x28, 0xfc,
- 0xed, 0x84, 0x9e, 0xe1,
- 0xbb, 0x76, 0xe7, 0x39,
- 0x1b, 0x93, 0xeb, 0x12,
- ],
- output_str: "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12",
- },
- Test {
- input: "The quick brown fox jumps over the lazy cog",
- output: vec![
- 0xde, 0x9f, 0x2c, 0x7f,
- 0xd2, 0x5e, 0x1b, 0x3a,
- 0xfa, 0xd3, 0xe8, 0x5a,
- 0x0b, 0xd1, 0x7d, 0x9b,
- 0x10, 0x0d, 0xb4, 0xb3,
- ],
- output_str: "de9f2c7fd25e1b3afad3e85a0bd17d9b100db4b3",
- },
- ];
-
- for test in tests {
- // Hash through high-level API, check hex encoding/decoding
- let hash = sha1::Hash::hash(test.input.as_bytes());
- assert_eq!(hash, test.output_str.parse::().expect("parse hex"));
- assert_eq!(&hash[..], &test.output[..]);
- assert_eq!(&hash.to_string(), &test.output_str);
-
- // Hash through engine, checking that we can input byte by byte
- let mut engine = sha1::Hash::engine();
- for ch in test.input.as_bytes() {
- engine.input(&[*ch]);
- }
- let manual_hash = sha1::Hash::from_engine(engine);
- assert_eq!(hash, manual_hash);
- assert_eq!(hash.as_byte_array(), test.output.as_slice());
- }
- }
-
- #[cfg(feature = "serde")]
- #[test]
- fn sha1_serde() {
- use serde_test::{assert_tokens, Configure, Token};
-
- use crate::{sha1, Hash};
-
- #[rustfmt::skip]
- static HASH_BYTES: [u8; 20] = [
- 0x13, 0x20, 0x72, 0xdf,
- 0x69, 0x09, 0x33, 0x83,
- 0x5e, 0xb8, 0xb6, 0xad,
- 0x0b, 0x77, 0xe7, 0xb6,
- 0xf1, 0x4a, 0xca, 0xd7,
- ];
-
- let hash = sha1::Hash::from_slice(&HASH_BYTES).expect("right number of bytes");
- assert_tokens(&hash.compact(), &[Token::BorrowedBytes(&HASH_BYTES[..])]);
- assert_tokens(&hash.readable(), &[Token::Str("132072df690933835eb8b6ad0b77e7b6f14acad7")]);
- }
-}
diff --git a/hashes/src/sha256.rs b/hashes/src/sha256.rs
deleted file mode 100644
index fac3b2737..000000000
--- a/hashes/src/sha256.rs
+++ /dev/null
@@ -1,725 +0,0 @@
-// Bitcoin Hashes Library
-// Written in 2018 by
-// Andrew Poelstra
-//
-// To the extent possible under law, the author(s) have dedicated all
-// copyright and related and neighboring rights to this software to
-// the public domain worldwide. This software is distributed without
-// any warranty.
-//
-// You should have received a copy of the CC0 Public Domain Dedication
-// along with this software.
-// If not, see .
-//
-
-//! SHA256 implementation.
-//!
-
-use core::ops::Index;
-use core::slice::SliceIndex;
-use core::{cmp, str};
-
-use crate::{hex, sha256d, Error, HashEngine as _};
-
-crate::internal_macros::hash_type! {
- 256,
- false,
- "Output of the SHA256 hash function.",
- "crate::util::json_hex_string::len_32"
-}
-
-#[cfg(not(fuzzing))]
-fn from_engine(mut e: HashEngine) -> Hash {
- // pad buffer with a single 1-bit then all 0s, until there are exactly 8 bytes remaining
- let data_len = e.length as u64;
-
- let zeroes = [0; BLOCK_SIZE - 8];
- e.input(&[0x80]);
- if e.length % BLOCK_SIZE > zeroes.len() {
- e.input(&zeroes);
- }
- let pad_length = zeroes.len() - (e.length % BLOCK_SIZE);
- e.input(&zeroes[..pad_length]);
- debug_assert_eq!(e.length % BLOCK_SIZE, zeroes.len());
-
- e.input(&(8 * data_len).to_be_bytes());
- debug_assert_eq!(e.length % BLOCK_SIZE, 0);
-
- Hash(e.midstate().to_byte_array())
-}
-
-#[cfg(fuzzing)]
-fn from_engine(e: HashEngine) -> Hash {
- let mut hash = e.midstate().to_byte_array();
- if hash == [0; 32] {
- // Assume sha256 is secure and never generate 0-hashes (which represent invalid
- // secp256k1 secret keys, causing downstream application breakage).
- hash[0] = 1;
- }
- Hash(hash)
-}
-
-const BLOCK_SIZE: usize = 64;
-
-/// Engine to compute SHA256 hash function.
-#[derive(Clone)]
-pub struct HashEngine {
- buffer: [u8; BLOCK_SIZE],
- h: [u32; 8],
- length: usize,
-}
-
-impl Default for HashEngine {
- fn default() -> Self {
- HashEngine {
- h: [
- 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab,
- 0x5be0cd19,
- ],
- length: 0,
- buffer: [0; BLOCK_SIZE],
- }
- }
-}
-
-impl crate::HashEngine for HashEngine {
- type MidState = Midstate;
-
- #[cfg(not(fuzzing))]
- fn midstate(&self) -> Midstate {
- let mut ret = [0; 32];
- for (val, ret_bytes) in self.h.iter().zip(ret.as_chunks_mut::<4>().0) {
- *ret_bytes = val.to_be_bytes();
- }
- Midstate(ret)
- }
-
- #[cfg(fuzzing)]
- fn midstate(&self) -> Midstate {
- let mut ret = [0; 32];
- ret.copy_from_slice(&self.buffer[..32]);
- Midstate(ret)
- }
-
- const BLOCK_SIZE: usize = 64;
-
- fn n_bytes_hashed(&self) -> usize {
- self.length
- }
-
- engine_input_impl!();
-}
-
-impl Hash {
- /// Iterate the sha256 algorithm to turn a sha256 hash into a sha256d hash
- pub fn hash_again(&self) -> sha256d::Hash {
- crate::Hash::from_byte_array(::hash(&self.0).0)
- }
-
- /// Computes hash from `bytes` in `const` context.
- ///
- /// Warning: this function is inefficient. It should be only used in `const` context.
- pub const fn const_hash(bytes: &[u8]) -> Self {
- Hash(Midstate::const_hash(bytes, true).0)
- }
-}
-
-/// Output of the SHA256 hash function.
-#[derive(Copy, Clone, PartialEq, Eq, Default, PartialOrd, Ord, Hash)]
-pub struct Midstate(pub [u8; 32]);
-
-crate::internal_macros::arr_newtype_fmt_impl!(Midstate, 32);
-serde_impl!(Midstate, 32);
-borrow_slice_impl!(Midstate);
-
-impl> Index for Midstate {
- type Output = I::Output;
-
- #[inline]
- fn index(&self, index: I) -> &Self::Output {
- &self.0[index]
- }
-}
-
-impl str::FromStr for Midstate {
- type Err = hex::Error;
- fn from_str(s: &str) -> Result {
- hex::FromHex::from_hex(s)
- }
-}
-
-impl Midstate {
- /// Length of the midstate, in bytes.
- const LEN: usize = 32;
-
- /// Flag indicating whether user-visible serializations of this hash
- /// should be backward. For some reason Satoshi decided this should be
- /// true for `Sha256dHash`, so here we are.
- const DISPLAY_BACKWARD: bool = true;
-
- /// Construct a new [`Midstate`] from the inner value.
- pub const fn from_byte_array(inner: [u8; 32]) -> Self {
- Midstate(inner)
- }
-
- /// Copies a byte slice into the [`Midstate`] object.
- pub fn from_slice(sl: &[u8]) -> Result {
- if sl.len() != Self::LEN {
- Err(Error::InvalidLength(Self::LEN, sl.len()))
- } else {
- let mut ret = [0; 32];
- ret.copy_from_slice(sl);
- Ok(Midstate(ret))
- }
- }
-
- /// Unwraps the [`Midstate`] and returns the underlying byte array.
- pub fn to_byte_array(self) -> [u8; 32] {
- self.0
- }
-
- /// Creates midstate for tagged hashes.
- ///
- /// Warning: this function is inefficient. It should be only used in `const` context.
- ///
- /// Computes non-finalized hash of `sha256(tag) || sha256(tag)` for use in
- /// [`sha256t`](super::sha256t). It's provided for use with [`sha256t`](crate::sha256t).
- pub const fn hash_tag(tag: &[u8]) -> Self {
- let hash = Hash::const_hash(tag);
- let mut buf = [0u8; 64];
- let mut i = 0usize;
- while i < buf.len() {
- buf[i] = hash.0[i % hash.0.len()];
- i += 1;
- }
- Self::const_hash(&buf, false)
- }
-}
-
-impl hex::FromHex for Midstate {
- fn from_byte_iter(iter: I) -> Result
- where
- I: Iterator
- > + ExactSizeIterator + DoubleEndedIterator,
- {
- // DISPLAY_BACKWARD is true
- Ok(Midstate::from_byte_array(hex::FromHex::from_byte_iter(iter.rev())?))
- }
-}
-
-macro_rules! Ch( ($x:expr, $y:expr, $z:expr) => ($z ^ ($x & ($y ^ $z))) );
-macro_rules! Maj( ($x:expr, $y:expr, $z:expr) => (($x & $y) | ($z & ($x | $y))) );
-macro_rules! Sigma0( ($x:expr) => ($x.rotate_left(30) ^ $x.rotate_left(19) ^ $x.rotate_left(10)) );
-macro_rules! Sigma1( ($x:expr) => ( $x.rotate_left(26) ^ $x.rotate_left(21) ^ $x.rotate_left(7)) );
-macro_rules! sigma0( ($x:expr) => ($x.rotate_left(25) ^ $x.rotate_left(14) ^ ($x >> 3)) );
-macro_rules! sigma1( ($x:expr) => ($x.rotate_left(15) ^ $x.rotate_left(13) ^ ($x >> 10)) );
-
-macro_rules! round(
- // first round
- ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr, $h:expr, $k:expr, $w:expr) => (
- let t1 = $h.wrapping_add(Sigma1!($e)).wrapping_add(Ch!($e, $f, $g)).wrapping_add($k).wrapping_add($w);
- let t2 = Sigma0!($a).wrapping_add(Maj!($a, $b, $c));
- $d = $d.wrapping_add(t1);
- $h = t1.wrapping_add(t2);
- );
- // later rounds we reassign $w before doing the first-round computation
- ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr, $h:expr, $k:expr, $w:expr, $w1:expr, $w2:expr, $w3:expr) => (
- $w = $w.wrapping_add(sigma1!($w1)).wrapping_add($w2).wrapping_add(sigma0!($w3));
- round!($a, $b, $c, $d, $e, $f, $g, $h, $k, $w);
- )
-);
-
-impl Midstate {
- #[allow(clippy::identity_op)] // more readable
- const fn read_u32(bytes: &[u8], index: usize) -> u32 {
- ((bytes[index + 0] as u32) << 24)
- | ((bytes[index + 1] as u32) << 16)
- | ((bytes[index + 2] as u32) << 8)
- | ((bytes[index + 3] as u32) << 0)
- }
-
- const fn copy_w(bytes: &[u8], index: usize) -> [u32; 16] {
- let mut w = [0u32; 16];
- let mut i = 0;
- while i < 16 {
- w[i] = Self::read_u32(bytes, index + i * 4);
- i += 1;
- }
- w
- }
-
- const fn const_hash(bytes: &[u8], finalize: bool) -> Self {
- let mut state = [
- 0x6a09e667u32,
- 0xbb67ae85,
- 0x3c6ef372,
- 0xa54ff53a,
- 0x510e527f,
- 0x9b05688c,
- 0x1f83d9ab,
- 0x5be0cd19,
- ];
-
- let num_chunks = (bytes.len() + 9).div_ceil(64);
- let mut chunk = 0;
- #[allow(clippy::precedence)]
- while chunk < num_chunks {
- if !finalize && chunk + 1 == num_chunks {
- break;
- }
- let mut w = if chunk * 64 + 64 <= bytes.len() {
- Self::copy_w(bytes, chunk * 64)
- } else {
- let mut buf = [0; 64];
- let mut i = 0;
- let offset = chunk * 64;
- while offset + i < bytes.len() {
- buf[i] = bytes[offset + i];
- i += 1;
- }
- if (bytes.len() % 64 <= 64 - 9) || (chunk + 2 == num_chunks) {
- buf[i] = 0x80;
- }
- #[allow(clippy::identity_op)] // more readable
- #[allow(clippy::erasing_op)]
- if chunk + 1 == num_chunks {
- let bit_len = bytes.len() as u64 * 8;
- buf[64 - 8] = ((bit_len >> 8 * 7) & 0xFF) as u8;
- buf[64 - 7] = ((bit_len >> 8 * 6) & 0xFF) as u8;
- buf[64 - 6] = ((bit_len >> 8 * 5) & 0xFF) as u8;
- buf[64 - 5] = ((bit_len >> 8 * 4) & 0xFF) as u8;
- buf[64 - 4] = ((bit_len >> 8 * 3) & 0xFF) as u8;
- buf[64 - 3] = ((bit_len >> 8 * 2) & 0xFF) as u8;
- buf[64 - 2] = ((bit_len >> 8 * 1) & 0xFF) as u8;
- buf[64 - 1] = ((bit_len >> 8 * 0) & 0xFF) as u8;
- }
- Self::copy_w(&buf, 0)
- };
- chunk += 1;
-
- let mut a = state[0];
- let mut b = state[1];
- let mut c = state[2];
- let mut d = state[3];
- let mut e = state[4];
- let mut f = state[5];
- let mut g = state[6];
- let mut h = state[7];
-
- round!(a, b, c, d, e, f, g, h, 0x428a2f98, w[0]);
- round!(h, a, b, c, d, e, f, g, 0x71374491, w[1]);
- round!(g, h, a, b, c, d, e, f, 0xb5c0fbcf, w[2]);
- round!(f, g, h, a, b, c, d, e, 0xe9b5dba5, w[3]);
- round!(e, f, g, h, a, b, c, d, 0x3956c25b, w[4]);
- round!(d, e, f, g, h, a, b, c, 0x59f111f1, w[5]);
- round!(c, d, e, f, g, h, a, b, 0x923f82a4, w[6]);
- round!(b, c, d, e, f, g, h, a, 0xab1c5ed5, w[7]);
- round!(a, b, c, d, e, f, g, h, 0xd807aa98, w[8]);
- round!(h, a, b, c, d, e, f, g, 0x12835b01, w[9]);
- round!(g, h, a, b, c, d, e, f, 0x243185be, w[10]);
- round!(f, g, h, a, b, c, d, e, 0x550c7dc3, w[11]);
- round!(e, f, g, h, a, b, c, d, 0x72be5d74, w[12]);
- round!(d, e, f, g, h, a, b, c, 0x80deb1fe, w[13]);
- round!(c, d, e, f, g, h, a, b, 0x9bdc06a7, w[14]);
- round!(b, c, d, e, f, g, h, a, 0xc19bf174, w[15]);
-
- round!(a, b, c, d, e, f, g, h, 0xe49b69c1, w[0], w[14], w[9], w[1]);
- round!(h, a, b, c, d, e, f, g, 0xefbe4786, w[1], w[15], w[10], w[2]);
- round!(g, h, a, b, c, d, e, f, 0x0fc19dc6, w[2], w[0], w[11], w[3]);
- round!(f, g, h, a, b, c, d, e, 0x240ca1cc, w[3], w[1], w[12], w[4]);
- round!(e, f, g, h, a, b, c, d, 0x2de92c6f, w[4], w[2], w[13], w[5]);
- round!(d, e, f, g, h, a, b, c, 0x4a7484aa, w[5], w[3], w[14], w[6]);
- round!(c, d, e, f, g, h, a, b, 0x5cb0a9dc, w[6], w[4], w[15], w[7]);
- round!(b, c, d, e, f, g, h, a, 0x76f988da, w[7], w[5], w[0], w[8]);
- round!(a, b, c, d, e, f, g, h, 0x983e5152, w[8], w[6], w[1], w[9]);
- round!(h, a, b, c, d, e, f, g, 0xa831c66d, w[9], w[7], w[2], w[10]);
- round!(g, h, a, b, c, d, e, f, 0xb00327c8, w[10], w[8], w[3], w[11]);
- round!(f, g, h, a, b, c, d, e, 0xbf597fc7, w[11], w[9], w[4], w[12]);
- round!(e, f, g, h, a, b, c, d, 0xc6e00bf3, w[12], w[10], w[5], w[13]);
- round!(d, e, f, g, h, a, b, c, 0xd5a79147, w[13], w[11], w[6], w[14]);
- round!(c, d, e, f, g, h, a, b, 0x06ca6351, w[14], w[12], w[7], w[15]);
- round!(b, c, d, e, f, g, h, a, 0x14292967, w[15], w[13], w[8], w[0]);
-
- round!(a, b, c, d, e, f, g, h, 0x27b70a85, w[0], w[14], w[9], w[1]);
- round!(h, a, b, c, d, e, f, g, 0x2e1b2138, w[1], w[15], w[10], w[2]);
- round!(g, h, a, b, c, d, e, f, 0x4d2c6dfc, w[2], w[0], w[11], w[3]);
- round!(f, g, h, a, b, c, d, e, 0x53380d13, w[3], w[1], w[12], w[4]);
- round!(e, f, g, h, a, b, c, d, 0x650a7354, w[4], w[2], w[13], w[5]);
- round!(d, e, f, g, h, a, b, c, 0x766a0abb, w[5], w[3], w[14], w[6]);
- round!(c, d, e, f, g, h, a, b, 0x81c2c92e, w[6], w[4], w[15], w[7]);
- round!(b, c, d, e, f, g, h, a, 0x92722c85, w[7], w[5], w[0], w[8]);
- round!(a, b, c, d, e, f, g, h, 0xa2bfe8a1, w[8], w[6], w[1], w[9]);
- round!(h, a, b, c, d, e, f, g, 0xa81a664b, w[9], w[7], w[2], w[10]);
- round!(g, h, a, b, c, d, e, f, 0xc24b8b70, w[10], w[8], w[3], w[11]);
- round!(f, g, h, a, b, c, d, e, 0xc76c51a3, w[11], w[9], w[4], w[12]);
- round!(e, f, g, h, a, b, c, d, 0xd192e819, w[12], w[10], w[5], w[13]);
- round!(d, e, f, g, h, a, b, c, 0xd6990624, w[13], w[11], w[6], w[14]);
- round!(c, d, e, f, g, h, a, b, 0xf40e3585, w[14], w[12], w[7], w[15]);
- round!(b, c, d, e, f, g, h, a, 0x106aa070, w[15], w[13], w[8], w[0]);
-
- round!(a, b, c, d, e, f, g, h, 0x19a4c116, w[0], w[14], w[9], w[1]);
- round!(h, a, b, c, d, e, f, g, 0x1e376c08, w[1], w[15], w[10], w[2]);
- round!(g, h, a, b, c, d, e, f, 0x2748774c, w[2], w[0], w[11], w[3]);
- round!(f, g, h, a, b, c, d, e, 0x34b0bcb5, w[3], w[1], w[12], w[4]);
- round!(e, f, g, h, a, b, c, d, 0x391c0cb3, w[4], w[2], w[13], w[5]);
- round!(d, e, f, g, h, a, b, c, 0x4ed8aa4a, w[5], w[3], w[14], w[6]);
- round!(c, d, e, f, g, h, a, b, 0x5b9cca4f, w[6], w[4], w[15], w[7]);
- round!(b, c, d, e, f, g, h, a, 0x682e6ff3, w[7], w[5], w[0], w[8]);
- round!(a, b, c, d, e, f, g, h, 0x748f82ee, w[8], w[6], w[1], w[9]);
- round!(h, a, b, c, d, e, f, g, 0x78a5636f, w[9], w[7], w[2], w[10]);
- round!(g, h, a, b, c, d, e, f, 0x84c87814, w[10], w[8], w[3], w[11]);
- round!(f, g, h, a, b, c, d, e, 0x8cc70208, w[11], w[9], w[4], w[12]);
- round!(e, f, g, h, a, b, c, d, 0x90befffa, w[12], w[10], w[5], w[13]);
- round!(d, e, f, g, h, a, b, c, 0xa4506ceb, w[13], w[11], w[6], w[14]);
- round!(c, d, e, f, g, h, a, b, 0xbef9a3f7, w[14], w[12], w[7], w[15]);
- round!(b, c, d, e, f, g, h, a, 0xc67178f2, w[15], w[13], w[8], w[0]);
-
- state[0] = state[0].wrapping_add(a);
- state[1] = state[1].wrapping_add(b);
- state[2] = state[2].wrapping_add(c);
- state[3] = state[3].wrapping_add(d);
- state[4] = state[4].wrapping_add(e);
- state[5] = state[5].wrapping_add(f);
- state[6] = state[6].wrapping_add(g);
- state[7] = state[7].wrapping_add(h);
- }
- let mut output = [0u8; 32];
- let mut i = 0;
- #[allow(clippy::identity_op)] // more readable
- while i < 8 {
- output[i * 4 + 0] = (state[i + 0] >> 24) as u8;
- output[i * 4 + 1] = (state[i + 0] >> 16) as u8;
- output[i * 4 + 2] = (state[i + 0] >> 8) as u8;
- output[i * 4 + 3] = (state[i + 0] >> 0) as u8;
- i += 1;
- }
- Midstate(output)
- }
-}
-
-impl HashEngine {
- /// Create a new [`HashEngine`] from a [`Midstate`].
- ///
- /// # Panics
- ///
- /// If `length` is not a multiple of the block size.
- pub fn from_midstate(midstate: Midstate, length: usize) -> HashEngine {
- assert!(length.is_multiple_of(BLOCK_SIZE), "length is no multiple of the block size");
-
- let mut ret = [0; 8];
- for (ret_val, midstate_bytes) in ret.iter_mut().zip(midstate[..].as_chunks::<4>().0) {
- *ret_val = u32::from_be_bytes(*midstate_bytes);
- }
-
- HashEngine {
- buffer: [0; BLOCK_SIZE],
- h: ret,
- length,
- }
- }
-
- // Algorithm copied from libsecp256k1
- fn process_block(&mut self) {
- debug_assert_eq!(self.buffer.len(), BLOCK_SIZE);
-
- let mut w = [0u32; 16];
- for (w_val, buff_bytes) in w.iter_mut().zip(self.buffer.as_chunks::<4>().0) {
- *w_val = u32::from_be_bytes(*buff_bytes);
- }
-
- let mut a = self.h[0];
- let mut b = self.h[1];
- let mut c = self.h[2];
- let mut d = self.h[3];
- let mut e = self.h[4];
- let mut f = self.h[5];
- let mut g = self.h[6];
- let mut h = self.h[7];
-
- round!(a, b, c, d, e, f, g, h, 0x428a2f98, w[0]);
- round!(h, a, b, c, d, e, f, g, 0x71374491, w[1]);
- round!(g, h, a, b, c, d, e, f, 0xb5c0fbcf, w[2]);
- round!(f, g, h, a, b, c, d, e, 0xe9b5dba5, w[3]);
- round!(e, f, g, h, a, b, c, d, 0x3956c25b, w[4]);
- round!(d, e, f, g, h, a, b, c, 0x59f111f1, w[5]);
- round!(c, d, e, f, g, h, a, b, 0x923f82a4, w[6]);
- round!(b, c, d, e, f, g, h, a, 0xab1c5ed5, w[7]);
- round!(a, b, c, d, e, f, g, h, 0xd807aa98, w[8]);
- round!(h, a, b, c, d, e, f, g, 0x12835b01, w[9]);
- round!(g, h, a, b, c, d, e, f, 0x243185be, w[10]);
- round!(f, g, h, a, b, c, d, e, 0x550c7dc3, w[11]);
- round!(e, f, g, h, a, b, c, d, 0x72be5d74, w[12]);
- round!(d, e, f, g, h, a, b, c, 0x80deb1fe, w[13]);
- round!(c, d, e, f, g, h, a, b, 0x9bdc06a7, w[14]);
- round!(b, c, d, e, f, g, h, a, 0xc19bf174, w[15]);
-
- round!(a, b, c, d, e, f, g, h, 0xe49b69c1, w[0], w[14], w[9], w[1]);
- round!(h, a, b, c, d, e, f, g, 0xefbe4786, w[1], w[15], w[10], w[2]);
- round!(g, h, a, b, c, d, e, f, 0x0fc19dc6, w[2], w[0], w[11], w[3]);
- round!(f, g, h, a, b, c, d, e, 0x240ca1cc, w[3], w[1], w[12], w[4]);
- round!(e, f, g, h, a, b, c, d, 0x2de92c6f, w[4], w[2], w[13], w[5]);
- round!(d, e, f, g, h, a, b, c, 0x4a7484aa, w[5], w[3], w[14], w[6]);
- round!(c, d, e, f, g, h, a, b, 0x5cb0a9dc, w[6], w[4], w[15], w[7]);
- round!(b, c, d, e, f, g, h, a, 0x76f988da, w[7], w[5], w[0], w[8]);
- round!(a, b, c, d, e, f, g, h, 0x983e5152, w[8], w[6], w[1], w[9]);
- round!(h, a, b, c, d, e, f, g, 0xa831c66d, w[9], w[7], w[2], w[10]);
- round!(g, h, a, b, c, d, e, f, 0xb00327c8, w[10], w[8], w[3], w[11]);
- round!(f, g, h, a, b, c, d, e, 0xbf597fc7, w[11], w[9], w[4], w[12]);
- round!(e, f, g, h, a, b, c, d, 0xc6e00bf3, w[12], w[10], w[5], w[13]);
- round!(d, e, f, g, h, a, b, c, 0xd5a79147, w[13], w[11], w[6], w[14]);
- round!(c, d, e, f, g, h, a, b, 0x06ca6351, w[14], w[12], w[7], w[15]);
- round!(b, c, d, e, f, g, h, a, 0x14292967, w[15], w[13], w[8], w[0]);
-
- round!(a, b, c, d, e, f, g, h, 0x27b70a85, w[0], w[14], w[9], w[1]);
- round!(h, a, b, c, d, e, f, g, 0x2e1b2138, w[1], w[15], w[10], w[2]);
- round!(g, h, a, b, c, d, e, f, 0x4d2c6dfc, w[2], w[0], w[11], w[3]);
- round!(f, g, h, a, b, c, d, e, 0x53380d13, w[3], w[1], w[12], w[4]);
- round!(e, f, g, h, a, b, c, d, 0x650a7354, w[4], w[2], w[13], w[5]);
- round!(d, e, f, g, h, a, b, c, 0x766a0abb, w[5], w[3], w[14], w[6]);
- round!(c, d, e, f, g, h, a, b, 0x81c2c92e, w[6], w[4], w[15], w[7]);
- round!(b, c, d, e, f, g, h, a, 0x92722c85, w[7], w[5], w[0], w[8]);
- round!(a, b, c, d, e, f, g, h, 0xa2bfe8a1, w[8], w[6], w[1], w[9]);
- round!(h, a, b, c, d, e, f, g, 0xa81a664b, w[9], w[7], w[2], w[10]);
- round!(g, h, a, b, c, d, e, f, 0xc24b8b70, w[10], w[8], w[3], w[11]);
- round!(f, g, h, a, b, c, d, e, 0xc76c51a3, w[11], w[9], w[4], w[12]);
- round!(e, f, g, h, a, b, c, d, 0xd192e819, w[12], w[10], w[5], w[13]);
- round!(d, e, f, g, h, a, b, c, 0xd6990624, w[13], w[11], w[6], w[14]);
- round!(c, d, e, f, g, h, a, b, 0xf40e3585, w[14], w[12], w[7], w[15]);
- round!(b, c, d, e, f, g, h, a, 0x106aa070, w[15], w[13], w[8], w[0]);
-
- round!(a, b, c, d, e, f, g, h, 0x19a4c116, w[0], w[14], w[9], w[1]);
- round!(h, a, b, c, d, e, f, g, 0x1e376c08, w[1], w[15], w[10], w[2]);
- round!(g, h, a, b, c, d, e, f, 0x2748774c, w[2], w[0], w[11], w[3]);
- round!(f, g, h, a, b, c, d, e, 0x34b0bcb5, w[3], w[1], w[12], w[4]);
- round!(e, f, g, h, a, b, c, d, 0x391c0cb3, w[4], w[2], w[13], w[5]);
- round!(d, e, f, g, h, a, b, c, 0x4ed8aa4a, w[5], w[3], w[14], w[6]);
- round!(c, d, e, f, g, h, a, b, 0x5b9cca4f, w[6], w[4], w[15], w[7]);
- round!(b, c, d, e, f, g, h, a, 0x682e6ff3, w[7], w[5], w[0], w[8]);
- round!(a, b, c, d, e, f, g, h, 0x748f82ee, w[8], w[6], w[1], w[9]);
- round!(h, a, b, c, d, e, f, g, 0x78a5636f, w[9], w[7], w[2], w[10]);
- round!(g, h, a, b, c, d, e, f, 0x84c87814, w[10], w[8], w[3], w[11]);
- round!(f, g, h, a, b, c, d, e, 0x8cc70208, w[11], w[9], w[4], w[12]);
- round!(e, f, g, h, a, b, c, d, 0x90befffa, w[12], w[10], w[5], w[13]);
- round!(d, e, f, g, h, a, b, c, 0xa4506ceb, w[13], w[11], w[6], w[14]);
- round!(c, d, e, f, g, h, a, b, 0xbef9a3f7, w[14], w[12], w[7], w[15]);
- round!(b, c, d, e, f, g, h, a, 0xc67178f2, w[15], w[13], w[8], w[0]);
-
- self.h[0] = self.h[0].wrapping_add(a);
- self.h[1] = self.h[1].wrapping_add(b);
- self.h[2] = self.h[2].wrapping_add(c);
- self.h[3] = self.h[3].wrapping_add(d);
- self.h[4] = self.h[4].wrapping_add(e);
- self.h[5] = self.h[5].wrapping_add(f);
- self.h[6] = self.h[6].wrapping_add(g);
- self.h[7] = self.h[7].wrapping_add(h);
- }
-}
-
-#[cfg(test)]
-mod tests {
- use crate::{sha256, Hash, HashEngine};
-
- #[test]
- fn test() {
- #[derive(Clone)]
- struct Test {
- input: &'static str,
- output: Vec,
- output_str: &'static str,
- }
-
- #[rustfmt::skip]
- let tests = vec![
- // Examples from wikipedia
- Test {
- input: "",
- output: vec![
- 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14,
- 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24,
- 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c,
- 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55,
- ],
- output_str: "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
- },
- Test {
- input: "The quick brown fox jumps over the lazy dog",
- output: vec![
- 0xd7, 0xa8, 0xfb, 0xb3, 0x07, 0xd7, 0x80, 0x94,
- 0x69, 0xca, 0x9a, 0xbc, 0xb0, 0x08, 0x2e, 0x4f,
- 0x8d, 0x56, 0x51, 0xe4, 0x6d, 0x3c, 0xdb, 0x76,
- 0x2d, 0x02, 0xd0, 0xbf, 0x37, 0xc9, 0xe5, 0x92,
- ],
- output_str: "d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592",
- },
- Test {
- input: "The quick brown fox jumps over the lazy dog.",
- output: vec![
- 0xef, 0x53, 0x7f, 0x25, 0xc8, 0x95, 0xbf, 0xa7,
- 0x82, 0x52, 0x65, 0x29, 0xa9, 0xb6, 0x3d, 0x97,
- 0xaa, 0x63, 0x15, 0x64, 0xd5, 0xd7, 0x89, 0xc2,
- 0xb7, 0x65, 0x44, 0x8c, 0x86, 0x35, 0xfb, 0x6c,
- ],
- output_str: "ef537f25c895bfa782526529a9b63d97aa631564d5d789c2b765448c8635fb6c",
- },
- ];
-
- for test in tests {
- // Hash through high-level API, check hex encoding/decoding
- let hash = sha256::Hash::hash(test.input.as_bytes());
- assert_eq!(hash, test.output_str.parse::().expect("parse hex"));
- assert_eq!(&hash[..], &test.output[..]);
- assert_eq!(&hash.to_string(), &test.output_str);
-
- // Hash through engine, checking that we can input byte by byte
- let mut engine = sha256::Hash::engine();
- for ch in test.input.as_bytes() {
- engine.input(&[*ch]);
- }
- let manual_hash = sha256::Hash::from_engine(engine);
- assert_eq!(hash, manual_hash);
- assert_eq!(hash.to_byte_array()[..].as_ref(), test.output.as_slice());
- }
- }
-
- #[test]
- #[rustfmt::skip]
- fn midstate() {
- // Test vector obtained by doing an asset issuance on Elements
- let mut engine = sha256::Hash::engine();
- // sha256dhash of outpoint
- // 73828cbc65fd68ab78dc86992b76ae50ae2bf8ceedbe8de0483172f0886219f7:0
- engine.input(&[
- 0x9d, 0xd0, 0x1b, 0x56, 0xb1, 0x56, 0x45, 0x14,
- 0x3e, 0xad, 0x15, 0x8d, 0xec, 0x19, 0xf8, 0xce,
- 0xa9, 0x0b, 0xd0, 0xa9, 0xb2, 0xf8, 0x1d, 0x21,
- 0xff, 0xa3, 0xa4, 0xc6, 0x44, 0x81, 0xd4, 0x1c,
- ]);
- // 32 bytes of zeroes representing "new asset"
- engine.input(&[0; 32]);
- assert_eq!(
- engine.midstate(),
- // RPC output
- sha256::Midstate::from_byte_array([
- 0x0b, 0xcf, 0xe0, 0xe5, 0x4e, 0x6c, 0xc7, 0xd3,
- 0x4f, 0x4f, 0x7c, 0x1d, 0xf0, 0xb0, 0xf5, 0x03,
- 0xf2, 0xf7, 0x12, 0x91, 0x2a, 0x06, 0x05, 0xb4,
- 0x14, 0xed, 0x33, 0x7f, 0x7f, 0x03, 0x2e, 0x03,
- ])
- );
- }
-
- #[test]
- fn engine_with_state() {
- let mut engine = sha256::Hash::engine();
- let midstate_engine = sha256::HashEngine::from_midstate(engine.midstate(), 0);
- // Fresh engine and engine initialized with fresh state should have same state
- assert_eq!(engine.h, midstate_engine.h);
-
- // Midstate changes after writing 64 bytes
- engine.input(&[1; 63]);
- assert_eq!(engine.h, midstate_engine.h);
- engine.input(&[2; 1]);
- assert_ne!(engine.h, midstate_engine.h);
-
- // Initializing an engine with midstate from another engine should result in
- // both engines producing the same hashes
- let data_vec = vec![vec![3; 1], vec![4; 63], vec![5; 65], vec![6; 66]];
- for data in data_vec {
- let mut engine = engine.clone();
- let mut midstate_engine =
- sha256::HashEngine::from_midstate(engine.midstate(), engine.length);
- assert_eq!(engine.h, midstate_engine.h);
- assert_eq!(engine.length, midstate_engine.length);
- engine.input(&data);
- midstate_engine.input(&data);
- assert_eq!(engine.h, midstate_engine.h);
- let hash1 = sha256::Hash::from_engine(engine);
- let hash2 = sha256::Hash::from_engine(midstate_engine);
- assert_eq!(hash1, hash2);
- }
-
- // Test that a specific midstate results in a specific hash. Midstate was
- // obtained by applying sha256 to sha256("MuSig coefficient")||sha256("MuSig
- // coefficient").
- #[rustfmt::skip]
- static MIDSTATE: [u8; 32] = [
- 0x0f, 0xd0, 0x69, 0x0c, 0xfe, 0xfe, 0xae, 0x97,
- 0x99, 0x6e, 0xac, 0x7f, 0x5c, 0x30, 0xd8, 0x64,
- 0x8c, 0x4a, 0x05, 0x73, 0xac, 0xa1, 0xa2, 0x2f,
- 0x6f, 0x43, 0xb8, 0x01, 0x85, 0xce, 0x27, 0xcd,
- ];
- #[rustfmt::skip]
- static HASH_EXPECTED: [u8; 32] = [
- 0x18, 0x84, 0xe4, 0x72, 0x40, 0x4e, 0xf4, 0x5a,
- 0xb4, 0x9c, 0x4e, 0xa4, 0x9a, 0xe6, 0x23, 0xa8,
- 0x88, 0x52, 0x7f, 0x7d, 0x8a, 0x06, 0x94, 0x20,
- 0x8f, 0xf1, 0xf7, 0xa9, 0xd5, 0x69, 0x09, 0x59,
- ];
- let midstate_engine =
- sha256::HashEngine::from_midstate(sha256::Midstate::from_byte_array(MIDSTATE), 64);
- let hash = sha256::Hash::from_engine(midstate_engine);
- assert_eq!(hash, sha256::Hash(HASH_EXPECTED));
- }
-
- #[test]
- fn const_hash() {
- assert_eq!(super::Hash::hash(&[]), super::Hash::const_hash(&[]));
-
- let mut bytes = Vec::new();
- for i in 0..256 {
- bytes.push(i as u8);
- assert_eq!(
- super::Hash::hash(&bytes),
- super::Hash::const_hash(&bytes),
- "hashes don't match for length {}",
- i + 1
- );
- }
- }
-
- #[test]
- fn const_midstate() {
- use super::Midstate;
-
- assert_eq!(
- Midstate::hash_tag(b"TapLeaf"),
- Midstate([
- 156, 224, 228, 230, 124, 17, 108, 57, 56, 179, 202, 242, 195, 15, 80, 137, 211,
- 243, 147, 108, 71, 99, 110, 96, 125, 179, 62, 234, 221, 198, 240, 201,
- ])
- )
- }
-
- #[cfg(feature = "serde")]
- #[test]
- fn sha256_serde() {
- use serde_test::{assert_tokens, Configure, Token};
-
- #[rustfmt::skip]
- static HASH_BYTES: [u8; 32] = [
- 0xef, 0x53, 0x7f, 0x25, 0xc8, 0x95, 0xbf, 0xa7,
- 0x82, 0x52, 0x65, 0x29, 0xa9, 0xb6, 0x3d, 0x97,
- 0xaa, 0x63, 0x15, 0x64, 0xd5, 0xd7, 0x89, 0xc2,
- 0xb7, 0x65, 0x44, 0x8c, 0x86, 0x35, 0xfb, 0x6c,
- ];
-
- let hash = sha256::Hash::from_slice(&HASH_BYTES).expect("right number of bytes");
- assert_tokens(&hash.compact(), &[Token::BorrowedBytes(&HASH_BYTES[..])]);
- assert_tokens(
- &hash.readable(),
- &[Token::Str("ef537f25c895bfa782526529a9b63d97aa631564d5d789c2b765448c8635fb6c")],
- );
- }
-
- #[cfg(target_arch = "wasm32")]
- mod wasm_tests {
- extern crate wasm_bindgen_test;
- use self::wasm_bindgen_test::*;
- use super::*;
- #[wasm_bindgen_test]
- fn sha256_tests() {
- test();
- midstate();
- engine_with_state();
- }
- }
-}
diff --git a/hashes/src/sha256d.rs b/hashes/src/sha256d.rs
deleted file mode 100644
index 8bbd5755f..000000000
--- a/hashes/src/sha256d.rs
+++ /dev/null
@@ -1,118 +0,0 @@
-// Bitcoin Hashes Library
-// Written in 2018 by
-// Andrew Poelstra
-//
-// To the extent possible under law, the author(s) have dedicated all
-// copyright and related and neighboring rights to this software to
-// the public domain worldwide. This software is distributed without
-// any warranty.
-//
-// You should have received a copy of the CC0 Public Domain Dedication
-// along with this software.
-// If not, see .
-//
-
-//! SHA256d implementation (double SHA256).
-//!
-
-use core::ops::Index;
-use core::slice::SliceIndex;
-use core::str;
-
-use crate::{sha256, Error};
-
-crate::internal_macros::hash_type! {
- 256,
- true,
- "Output of the SHA256d hash function.",
- "crate::util::json_hex_string::len_32"
-}
-
-type HashEngine = sha256::HashEngine;
-
-fn from_engine(e: sha256::HashEngine) -> Hash {
- use crate::Hash as _;
-
- let sha2 = sha256::Hash::from_engine(e);
- let sha2d = sha256::Hash::hash(&sha2[..]);
-
- let mut ret = [0; 32];
- ret.copy_from_slice(&sha2d[..]);
- Hash(ret)
-}
-
-#[cfg(test)]
-mod tests {
- #[test]
- fn test() {
- use crate::{sha256, sha256d, Hash, HashEngine};
-
- #[derive(Clone)]
- struct Test {
- input: &'static str,
- output: Vec,
- output_str: &'static str,
- }
-
- #[rustfmt::skip]
- let tests = vec![
- // Test vector copied out of rust-dash
- Test {
- input: "",
- output: vec![
- 0x5d, 0xf6, 0xe0, 0xe2, 0x76, 0x13, 0x59, 0xd3,
- 0x0a, 0x82, 0x75, 0x05, 0x8e, 0x29, 0x9f, 0xcc,
- 0x03, 0x81, 0x53, 0x45, 0x45, 0xf5, 0x5c, 0xf4,
- 0x3e, 0x41, 0x98, 0x3f, 0x5d, 0x4c, 0x94, 0x56,
- ],
- output_str: "56944c5d3f98413ef45cf54545538103cc9f298e0575820ad3591376e2e0f65d",
- },
- ];
-
- for test in tests {
- // Hash through high-level API, check hex encoding/decoding
- let hash = sha256d::Hash::hash(test.input.as_bytes());
- assert_eq!(hash, test.output_str.parse::().expect("parse hex"));
- assert_eq!(&hash[..], &test.output[..]);
- assert_eq!(&hash.to_string(), &test.output_str);
-
- // Hash through engine, checking that we can input byte by byte
- let mut engine = sha256d::Hash::engine();
- for ch in test.input.as_bytes() {
- engine.input(&[*ch]);
- }
- let manual_hash = sha256d::Hash::from_engine(engine);
- assert_eq!(hash, manual_hash);
-
- // Hash by computing a sha256 then `hash_again`ing it
- let sha2_hash = sha256::Hash::hash(test.input.as_bytes());
- let sha2d_hash = sha2_hash.hash_again();
- assert_eq!(hash, sha2d_hash);
-
- assert_eq!(hash.to_byte_array()[..].as_ref(), test.output.as_slice());
- }
- }
-
- #[cfg(feature = "serde")]
- #[test]
- fn sha256_serde() {
- use serde_test::{assert_tokens, Configure, Token};
-
- use crate::{sha256d, Hash};
-
- #[rustfmt::skip]
- static HASH_BYTES: [u8; 32] = [
- 0xef, 0x53, 0x7f, 0x25, 0xc8, 0x95, 0xbf, 0xa7,
- 0x82, 0x52, 0x65, 0x29, 0xa9, 0xb6, 0x3d, 0x97,
- 0xaa, 0x63, 0x15, 0x64, 0xd5, 0xd7, 0x89, 0xc2,
- 0xb7, 0x65, 0x44, 0x8c, 0x86, 0x35, 0xfb, 0x6c,
- ];
-
- let hash = sha256d::Hash::from_slice(&HASH_BYTES).expect("right number of bytes");
- assert_tokens(&hash.compact(), &[Token::BorrowedBytes(&HASH_BYTES[..])]);
- assert_tokens(
- &hash.readable(),
- &[Token::Str("6cfb35868c4465b7c289d7d5641563aa973db6a929655282a7bf95c8257f53ef")],
- );
- }
-}
diff --git a/hashes/src/sha256t.rs b/hashes/src/sha256t.rs
index d2e1b0c06..29a92172c 100644
--- a/hashes/src/sha256t.rs
+++ b/hashes/src/sha256t.rs
@@ -1,100 +1,19 @@
-// Bitcoin Hashes Library
-// Written in 2019 by
-// The rust-dash developers.
//
-// To the extent possible under law, the author(s) have dedicated all
-// copyright and related and neighboring rights to this software to
-// the public domain worldwide. This software is distributed without
-// any warranty.
-//
-// You should have received a copy of the CC0 Public Domain Dedication
-// along with this software.
-// If not, see .
+// This file is a part of rust-dashcore. Contains portions from rust-bitcoin.
+// SPDX-License-Identifier: CC0-1.0
+// See the accompanying file LICENSE or https://creativecommons.org/publicdomain/zero/1.0
//
//! SHA256t implementation (tagged SHA256).
-//!
-
-use core::marker::PhantomData;
-use core::ops::Index;
-use core::slice::SliceIndex;
-use core::{cmp, str};
-
-use crate::{sha256, Error};
-
-type HashEngine = sha256::HashEngine;
-
-/// Trait representing a tag that can be used as a context for SHA256t hashes.
-pub trait Tag {
- /// Returns a hash engine that is pre-tagged and is ready to be used for the data.
- fn engine() -> sha256::HashEngine;
-}
-
-/// Output of the SHA256t hash function.
-#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
-#[repr(transparent)]
-pub struct Hash(
- #[cfg_attr(
- feature = "schemars",
- schemars(schema_with = "crate::util::json_hex_string::len_32")
- )]
- [u8; 32],
- #[cfg_attr(feature = "schemars", schemars(skip))] PhantomData,
-);
-
-impl Hash {
- fn internal_new(arr: [u8; 32]) -> Self {
- Hash(arr, Default::default())
- }
- fn internal_engine() -> HashEngine {
- T::engine()
- }
-}
-
-impl Copy for Hash {}
-impl Clone for Hash {
- fn clone(&self) -> Self {
- *self
- }
-}
-impl PartialEq for Hash {
- fn eq(&self, other: &Hash) -> bool {
- self.0 == other.0
- }
-}
-impl Eq for Hash {}
-impl Default for Hash {
- fn default() -> Self {
- Hash([0; 32], PhantomData)
- }
-}
-impl PartialOrd for Hash {
- fn partial_cmp(&self, other: &Hash) -> Option {
- Some(cmp::Ord::cmp(self, other))
- }
-}
-impl Ord for Hash {
- fn cmp(&self, other: &Hash) -> cmp::Ordering {
- cmp::Ord::cmp(&self.0, &other.0)
- }
-}
-impl core::hash::Hash for Hash {
- fn hash