Merge rust-bitcoin/rust-bitcoin#4085: Remove the `GeneralHash` trait
95ad91cdb6
hashes: Remove the GeneralHash trait (Tobin C. Harding)6426e59c63
Remove unused trait import (Tobin C. Harding)791501eabc
io: Use function in place of GeneralHashExt (Tobin C. Harding)2b6ef31469
hashes: Add hash_byte_chunks function to modules (Tobin C. Harding)d3846895d7
hashes: Add hash function to modules (Tobin C. Harding)e1bac7da55
Bound HmacEngine on HashEngine (Tobin C. Harding)ab63b7a0ff
Add Hash type and finalize method to HashEngine (Tobin C. Harding)84623ffaf9
Add hash_again regression test (Tobin C. Harding) Pull request description: This is the done as part of #4051. Requires some surgery on the `Hmac` and `Hkdf` types as well as a few other patches to maintain the logic that is currently provided by the trait. Final patch is a pure red diff - enjoy. ACKs for top commit: Kixunil: ACK95ad91cdb6
apoelstra: ACK 95ad91cdb64c8870d3eb992090bab7a70d1369b9; successfully ran local tests Tree-SHA512: bfd215de51c115144c6f5b3430b17dad5d770a8c876fe3775af2828ec620a1f4e4155e63bb18dac244a82c3840413a615d55a0fef91b6949d3de319aa5bb8c2f
This commit is contained in:
commit
5581c49e0f
|
@ -10,7 +10,7 @@ use core::ops::Index;
|
||||||
use core::str::FromStr;
|
use core::str::FromStr;
|
||||||
use core::{fmt, slice};
|
use core::{fmt, slice};
|
||||||
|
|
||||||
use hashes::{hash160, hash_newtype, sha512, GeneralHash, HashEngine, Hmac, HmacEngine};
|
use hashes::{hash160, hash_newtype, sha512, HashEngine, Hmac, HmacEngine};
|
||||||
use internals::write_err;
|
use internals::write_err;
|
||||||
use secp256k1::{Secp256k1, XOnlyPublicKey};
|
use secp256k1::{Secp256k1, XOnlyPublicKey};
|
||||||
|
|
||||||
|
@ -584,9 +584,9 @@ impl From<InvalidBase58PayloadLengthError> for Error {
|
||||||
impl Xpriv {
|
impl Xpriv {
|
||||||
/// Constructs a new master key from a seed value
|
/// Constructs a new master key from a seed value
|
||||||
pub fn new_master(network: impl Into<NetworkKind>, seed: &[u8]) -> Result<Xpriv, Error> {
|
pub fn new_master(network: impl Into<NetworkKind>, seed: &[u8]) -> Result<Xpriv, Error> {
|
||||||
let mut hmac_engine: HmacEngine<sha512::Hash> = HmacEngine::new(b"Bitcoin seed");
|
let mut engine = HmacEngine::<sha512::HashEngine>::new(b"Bitcoin seed");
|
||||||
hmac_engine.input(seed);
|
engine.input(seed);
|
||||||
let hmac_result: Hmac<sha512::Hash> = Hmac::from_engine(hmac_engine);
|
let hmac = engine.finalize();
|
||||||
|
|
||||||
Ok(Xpriv {
|
Ok(Xpriv {
|
||||||
network: network.into(),
|
network: network.into(),
|
||||||
|
@ -594,9 +594,9 @@ impl Xpriv {
|
||||||
parent_fingerprint: Default::default(),
|
parent_fingerprint: Default::default(),
|
||||||
child_number: ChildNumber::ZERO_NORMAL,
|
child_number: ChildNumber::ZERO_NORMAL,
|
||||||
private_key: secp256k1::SecretKey::from_byte_array(
|
private_key: secp256k1::SecretKey::from_byte_array(
|
||||||
&hmac_result.as_ref()[..32].try_into().expect("Slice should be exactly 32 bytes"),
|
&hmac.as_ref()[..32].try_into().expect("Slice should be exactly 32 bytes"),
|
||||||
)?,
|
)?,
|
||||||
chain_code: ChainCode::from_hmac(hmac_result),
|
chain_code: ChainCode::from_hmac(hmac),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -650,25 +650,25 @@ impl Xpriv {
|
||||||
|
|
||||||
/// Private->Private child key derivation
|
/// Private->Private child key derivation
|
||||||
fn ckd_priv<C: secp256k1::Signing>(&self, secp: &Secp256k1<C>, i: ChildNumber) -> Xpriv {
|
fn ckd_priv<C: secp256k1::Signing>(&self, secp: &Secp256k1<C>, i: ChildNumber) -> Xpriv {
|
||||||
let mut hmac_engine: HmacEngine<sha512::Hash> = HmacEngine::new(&self.chain_code[..]);
|
let mut engine = HmacEngine::<sha512::HashEngine>::new(&self.chain_code[..]);
|
||||||
match i {
|
match i {
|
||||||
ChildNumber::Normal { .. } => {
|
ChildNumber::Normal { .. } => {
|
||||||
// Non-hardened key: compute public data and use that
|
// Non-hardened key: compute public data and use that
|
||||||
hmac_engine.input(
|
engine.input(
|
||||||
&secp256k1::PublicKey::from_secret_key(secp, &self.private_key).serialize()[..],
|
&secp256k1::PublicKey::from_secret_key(secp, &self.private_key).serialize()[..],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
ChildNumber::Hardened { .. } => {
|
ChildNumber::Hardened { .. } => {
|
||||||
// Hardened key: use only secret data to prevent public derivation
|
// Hardened key: use only secret data to prevent public derivation
|
||||||
hmac_engine.input(&[0u8]);
|
engine.input(&[0u8]);
|
||||||
hmac_engine.input(&self.private_key[..]);
|
engine.input(&self.private_key[..]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hmac_engine.input(&u32::from(i).to_be_bytes());
|
engine.input(&u32::from(i).to_be_bytes());
|
||||||
let hmac_result: Hmac<sha512::Hash> = Hmac::from_engine(hmac_engine);
|
let hmac: Hmac<sha512::Hash> = engine.finalize();
|
||||||
let sk = secp256k1::SecretKey::from_byte_array(
|
let sk = secp256k1::SecretKey::from_byte_array(
|
||||||
&hmac_result.as_ref()[..32].try_into().expect("statistically impossible to hit"),
|
&hmac.as_ref()[..32].try_into().expect("statistically impossible to hit"),
|
||||||
)
|
)
|
||||||
.expect("statistically impossible to hit");
|
.expect("statistically impossible to hit");
|
||||||
let tweaked =
|
let tweaked =
|
||||||
|
@ -680,7 +680,7 @@ impl Xpriv {
|
||||||
parent_fingerprint: self.fingerprint(secp),
|
parent_fingerprint: self.fingerprint(secp),
|
||||||
child_number: i,
|
child_number: i,
|
||||||
private_key: tweaked,
|
private_key: tweaked,
|
||||||
chain_code: ChainCode::from_hmac(hmac_result),
|
chain_code: ChainCode::from_hmac(hmac),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -812,18 +812,15 @@ impl Xpub {
|
||||||
match i {
|
match i {
|
||||||
ChildNumber::Hardened { .. } => Err(Error::CannotDeriveFromHardenedKey),
|
ChildNumber::Hardened { .. } => Err(Error::CannotDeriveFromHardenedKey),
|
||||||
ChildNumber::Normal { index: n } => {
|
ChildNumber::Normal { index: n } => {
|
||||||
let mut hmac_engine: HmacEngine<sha512::Hash> =
|
let mut engine = HmacEngine::<sha512::HashEngine>::new(&self.chain_code[..]);
|
||||||
HmacEngine::new(&self.chain_code[..]);
|
engine.input(&self.public_key.serialize()[..]);
|
||||||
hmac_engine.input(&self.public_key.serialize()[..]);
|
engine.input(&n.to_be_bytes());
|
||||||
hmac_engine.input(&n.to_be_bytes());
|
|
||||||
|
|
||||||
let hmac_result: Hmac<sha512::Hash> = Hmac::from_engine(hmac_engine);
|
let hmac = engine.finalize();
|
||||||
let private_key = secp256k1::SecretKey::from_byte_array(
|
let private_key = secp256k1::SecretKey::from_byte_array(
|
||||||
&hmac_result.as_ref()[..32]
|
&hmac.as_ref()[..32].try_into().expect("Slice should be exactly 32 bytes"),
|
||||||
.try_into()
|
|
||||||
.expect("Slice should be exactly 32 bytes"),
|
|
||||||
)?;
|
)?;
|
||||||
let chain_code = ChainCode::from_hmac(hmac_result);
|
let chain_code = ChainCode::from_hmac(hmac);
|
||||||
Ok((private_key, chain_code))
|
Ok((private_key, chain_code))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
use core::mem;
|
use core::mem;
|
||||||
|
|
||||||
use hashes::{sha256, sha256d, GeneralHash, Hash};
|
use hashes::{sha256, sha256d, Hash};
|
||||||
use hex::DisplayHex as _;
|
use hex::DisplayHex as _;
|
||||||
use internals::{compact_size, ToU64};
|
use internals::{compact_size, ToU64};
|
||||||
use io::{BufRead, Cursor, Read, Write};
|
use io::{BufRead, Cursor, Read, Write};
|
||||||
|
@ -629,7 +629,7 @@ impl Decodable for Box<[u8]> {
|
||||||
|
|
||||||
/// Does a double-SHA256 on `data` and returns the first 4 bytes.
|
/// Does a double-SHA256 on `data` and returns the first 4 bytes.
|
||||||
fn sha2_checksum(data: &[u8]) -> [u8; 4] {
|
fn sha2_checksum(data: &[u8]) -> [u8; 4] {
|
||||||
let checksum = <sha256d::Hash as GeneralHash>::hash(data);
|
let checksum = sha256d::hash(data);
|
||||||
let checksum = checksum.to_byte_array();
|
let checksum = checksum.to_byte_array();
|
||||||
[checksum[0], checksum[1], checksum[2], checksum[3]]
|
[checksum[0], checksum[1], checksum[2], checksum[3]]
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,15 +113,15 @@ macro_rules! impl_psbt_insert_pair {
|
||||||
|
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
macro_rules! psbt_insert_hash_pair {
|
macro_rules! psbt_insert_hash_pair {
|
||||||
(&mut $slf:ident.$map:ident <= $raw_key:ident|$raw_value:ident|$hash:path|$hash_type_error:path) => {
|
(&mut $slf:ident.$map:ident <= $raw_key:ident|$raw_value:ident|$hash:ident|$hash_type_error:path) => {
|
||||||
if $raw_key.key_data.is_empty() {
|
if $raw_key.key_data.is_empty() {
|
||||||
return Err($crate::psbt::Error::InvalidKey($raw_key));
|
return Err($crate::psbt::Error::InvalidKey($raw_key));
|
||||||
}
|
}
|
||||||
let key_val: $hash = Deserialize::deserialize(&$raw_key.key_data)?;
|
let key_val: $hash::Hash = Deserialize::deserialize(&$raw_key.key_data)?;
|
||||||
match $slf.$map.entry(key_val) {
|
match $slf.$map.entry(key_val) {
|
||||||
btree_map::Entry::Vacant(empty_key) => {
|
btree_map::Entry::Vacant(empty_key) => {
|
||||||
let val: Vec<u8> = Deserialize::deserialize(&$raw_value)?;
|
let val: Vec<u8> = Deserialize::deserialize(&$raw_value)?;
|
||||||
if <$hash as hashes::GeneralHash>::hash(&val) != key_val {
|
if $hash::hash(&val) != key_val {
|
||||||
return Err($crate::psbt::Error::InvalidPreimageHashPair {
|
return Err($crate::psbt::Error::InvalidPreimageHashPair {
|
||||||
preimage: val.into_boxed_slice(),
|
preimage: val.into_boxed_slice(),
|
||||||
hash: Box::from(key_val.borrow()),
|
hash: Box::from(key_val.borrow()),
|
||||||
|
|
|
@ -317,22 +317,22 @@ impl Input {
|
||||||
}
|
}
|
||||||
PSBT_IN_RIPEMD160 => {
|
PSBT_IN_RIPEMD160 => {
|
||||||
psbt_insert_hash_pair! {
|
psbt_insert_hash_pair! {
|
||||||
&mut self.ripemd160_preimages <= raw_key|raw_value|ripemd160::Hash|error::PsbtHash::Ripemd
|
&mut self.ripemd160_preimages <= raw_key|raw_value|ripemd160|error::PsbtHash::Ripemd
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PSBT_IN_SHA256 => {
|
PSBT_IN_SHA256 => {
|
||||||
psbt_insert_hash_pair! {
|
psbt_insert_hash_pair! {
|
||||||
&mut self.sha256_preimages <= raw_key|raw_value|sha256::Hash|error::PsbtHash::Sha256
|
&mut self.sha256_preimages <= raw_key|raw_value|sha256|error::PsbtHash::Sha256
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PSBT_IN_HASH160 => {
|
PSBT_IN_HASH160 => {
|
||||||
psbt_insert_hash_pair! {
|
psbt_insert_hash_pair! {
|
||||||
&mut self.hash160_preimages <= raw_key|raw_value|hash160::Hash|error::PsbtHash::Hash160
|
&mut self.hash160_preimages <= raw_key|raw_value|hash160|error::PsbtHash::Hash160
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PSBT_IN_HASH256 => {
|
PSBT_IN_HASH256 => {
|
||||||
psbt_insert_hash_pair! {
|
psbt_insert_hash_pair! {
|
||||||
&mut self.hash256_preimages <= raw_key|raw_value|sha256d::Hash|error::PsbtHash::Hash256
|
&mut self.hash256_preimages <= raw_key|raw_value|sha256d|error::PsbtHash::Hash256
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PSBT_IN_TAP_KEY_SIG => {
|
PSBT_IN_TAP_KEY_SIG => {
|
||||||
|
|
|
@ -38,9 +38,13 @@ impl Default for HashEngine {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl crate::HashEngine for HashEngine {
|
impl crate::HashEngine for HashEngine {
|
||||||
|
type Hash = Hash;
|
||||||
|
type Bytes = [u8; 20];
|
||||||
const BLOCK_SIZE: usize = 64; // Same as sha256::HashEngine::BLOCK_SIZE;
|
const BLOCK_SIZE: usize = 64; // Same as sha256::HashEngine::BLOCK_SIZE;
|
||||||
|
|
||||||
fn input(&mut self, data: &[u8]) { self.0.input(data) }
|
fn input(&mut self, data: &[u8]) { self.0.input(data) }
|
||||||
fn n_bytes_hashed(&self) -> u64 { self.0.n_bytes_hashed() }
|
fn n_bytes_hashed(&self) -> u64 { self.0.n_bytes_hashed() }
|
||||||
|
fn finalize(self) -> Self::Hash { Hash::from_engine(self) }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -128,7 +132,7 @@ mod tests {
|
||||||
mod benches {
|
mod benches {
|
||||||
use test::Bencher;
|
use test::Bencher;
|
||||||
|
|
||||||
use crate::{hash160, GeneralHash as _, Hash as _, HashEngine};
|
use crate::{hash160, Hash as _, HashEngine};
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
pub fn hash160_10(bh: &mut Bencher) {
|
pub fn hash160_10(bh: &mut Bencher) {
|
||||||
|
|
|
@ -11,7 +11,7 @@ use alloc::vec;
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
|
|
||||||
use crate::{GeneralHash, HashEngine, Hmac, HmacEngine, IsByteArray};
|
use crate::{HashEngine, Hmac, HmacEngine, IsByteArray};
|
||||||
|
|
||||||
/// Output keying material max length multiple.
|
/// Output keying material max length multiple.
|
||||||
const MAX_OUTPUT_BLOCKS: usize = 255;
|
const MAX_OUTPUT_BLOCKS: usize = 255;
|
||||||
|
@ -33,20 +33,20 @@ impl std::error::Error for MaxLengthError {}
|
||||||
|
|
||||||
/// HMAC-based Extract-and-Expand Key Derivation Function (HKDF).
|
/// HMAC-based Extract-and-Expand Key Derivation Function (HKDF).
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub struct Hkdf<T: GeneralHash> {
|
pub struct Hkdf<T: HashEngine> {
|
||||||
/// Pseudorandom key based on the extract step.
|
/// Pseudorandom key based on the extract step.
|
||||||
prk: Hmac<T>,
|
prk: Hmac<T::Hash>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: GeneralHash> Hkdf<T>
|
impl<T: HashEngine> Hkdf<T>
|
||||||
where
|
where
|
||||||
<T as GeneralHash>::Engine: Default,
|
T: Default,
|
||||||
{
|
{
|
||||||
/// Initialize a HKDF by performing the extract step.
|
/// Initialize a HKDF by performing the extract step.
|
||||||
pub fn new(salt: &[u8], ikm: &[u8]) -> Self {
|
pub fn new(salt: &[u8], ikm: &[u8]) -> Self {
|
||||||
let mut hmac_engine: HmacEngine<T> = HmacEngine::new(salt);
|
let mut engine: HmacEngine<T> = HmacEngine::new(salt);
|
||||||
hmac_engine.input(ikm);
|
engine.input(ikm);
|
||||||
Self { prk: Hmac::from_engine(hmac_engine) }
|
Self { prk: engine.finalize() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Expand the key to generate output key material in okm.
|
/// Expand the key to generate output key material in okm.
|
||||||
|
@ -65,19 +65,19 @@ where
|
||||||
let total_blocks = (okm.len() + T::Bytes::LEN - 1) / T::Bytes::LEN;
|
let total_blocks = (okm.len() + T::Bytes::LEN - 1) / T::Bytes::LEN;
|
||||||
|
|
||||||
while counter <= total_blocks as u8 {
|
while counter <= total_blocks as u8 {
|
||||||
let mut hmac_engine: HmacEngine<T> = HmacEngine::new(self.prk.as_ref());
|
let mut engine: HmacEngine<T> = HmacEngine::new(self.prk.as_ref());
|
||||||
|
|
||||||
// First block does not have a previous block,
|
// First block does not have a previous block,
|
||||||
// all other blocks include last block in the HMAC input.
|
// all other blocks include last block in the HMAC input.
|
||||||
if counter != 1u8 {
|
if counter != 1u8 {
|
||||||
let previous_start_index = (counter as usize - 2) * T::Bytes::LEN;
|
let previous_start_index = (counter as usize - 2) * T::Bytes::LEN;
|
||||||
let previous_end_index = (counter as usize - 1) * T::Bytes::LEN;
|
let previous_end_index = (counter as usize - 1) * T::Bytes::LEN;
|
||||||
hmac_engine.input(&okm[previous_start_index..previous_end_index]);
|
engine.input(&okm[previous_start_index..previous_end_index]);
|
||||||
}
|
}
|
||||||
hmac_engine.input(info);
|
engine.input(info);
|
||||||
hmac_engine.input(&[counter]);
|
engine.input(&[counter]);
|
||||||
|
|
||||||
let t = Hmac::from_engine(hmac_engine);
|
let t = engine.finalize();
|
||||||
let start_index = (counter as usize - 1) * T::Bytes::LEN;
|
let start_index = (counter as usize - 1) * T::Bytes::LEN;
|
||||||
// Last block might not take full hash length.
|
// Last block might not take full hash length.
|
||||||
let end_index = if counter == (total_blocks as u8) {
|
let end_index = if counter == (total_blocks as u8) {
|
||||||
|
@ -106,7 +106,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: GeneralHash> fmt::Debug for Hkdf<T> {
|
impl<T: HashEngine> fmt::Debug for Hkdf<T> {
|
||||||
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
|
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
|
||||||
use crate::{sha256t, sha256t_tag};
|
use crate::{sha256t, sha256t_tag};
|
||||||
|
|
||||||
|
@ -141,7 +141,7 @@ mod tests {
|
||||||
let ikm = Vec::from_hex("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b").unwrap();
|
let ikm = Vec::from_hex("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b").unwrap();
|
||||||
let info = Vec::from_hex("f0f1f2f3f4f5f6f7f8f9").unwrap();
|
let info = Vec::from_hex("f0f1f2f3f4f5f6f7f8f9").unwrap();
|
||||||
|
|
||||||
let hkdf = Hkdf::<sha256::Hash>::new(&salt, &ikm);
|
let hkdf = Hkdf::<sha256::HashEngine>::new(&salt, &ikm);
|
||||||
let mut okm = [0u8; 42];
|
let mut okm = [0u8; 42];
|
||||||
hkdf.expand(&info, &mut okm).unwrap();
|
hkdf.expand(&info, &mut okm).unwrap();
|
||||||
|
|
||||||
|
@ -163,7 +163,7 @@ mod tests {
|
||||||
"b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"
|
"b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"
|
||||||
).unwrap();
|
).unwrap();
|
||||||
|
|
||||||
let hkdf = Hkdf::<sha256::Hash>::new(&salt, &ikm);
|
let hkdf = Hkdf::<sha256::HashEngine>::new(&salt, &ikm);
|
||||||
let mut okm = [0u8; 82];
|
let mut okm = [0u8; 82];
|
||||||
hkdf.expand(&info, &mut okm).unwrap();
|
hkdf.expand(&info, &mut okm).unwrap();
|
||||||
|
|
||||||
|
@ -179,7 +179,7 @@ mod tests {
|
||||||
let ikm = Vec::from_hex("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b").unwrap();
|
let ikm = Vec::from_hex("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b").unwrap();
|
||||||
let info = Vec::from_hex("f0f1f2f3f4f5f6f7f8f9").unwrap();
|
let info = Vec::from_hex("f0f1f2f3f4f5f6f7f8f9").unwrap();
|
||||||
|
|
||||||
let hkdf = Hkdf::<sha256::Hash>::new(&salt, &ikm);
|
let hkdf = Hkdf::<sha256::HashEngine>::new(&salt, &ikm);
|
||||||
let mut okm = [0u8; 256 * 32];
|
let mut okm = [0u8; 256 * 32];
|
||||||
let e = hkdf.expand(&info, &mut okm);
|
let e = hkdf.expand(&info, &mut okm);
|
||||||
|
|
||||||
|
@ -192,7 +192,7 @@ mod tests {
|
||||||
let ikm = Vec::from_hex("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b").unwrap();
|
let ikm = Vec::from_hex("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b").unwrap();
|
||||||
let info = Vec::from_hex("f0f1f2f3f4f5f6f7f8f9").unwrap();
|
let info = Vec::from_hex("f0f1f2f3f4f5f6f7f8f9").unwrap();
|
||||||
|
|
||||||
let hkdf = Hkdf::<sha256::Hash>::new(&salt, &ikm);
|
let hkdf = Hkdf::<sha256::HashEngine>::new(&salt, &ikm);
|
||||||
let mut okm = [0u8; 1];
|
let mut okm = [0u8; 1];
|
||||||
hkdf.expand(&info, &mut okm).unwrap();
|
hkdf.expand(&info, &mut okm).unwrap();
|
||||||
|
|
||||||
|
@ -205,7 +205,7 @@ mod tests {
|
||||||
let ikm = Vec::from_hex("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b").unwrap();
|
let ikm = Vec::from_hex("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b").unwrap();
|
||||||
let info = Vec::from_hex("f0f1f2f3f4f5f6f7f8f9").unwrap();
|
let info = Vec::from_hex("f0f1f2f3f4f5f6f7f8f9").unwrap();
|
||||||
|
|
||||||
let hkdf = Hkdf::<sha256::Hash>::new(&salt, &ikm);
|
let hkdf = Hkdf::<sha256::HashEngine>::new(&salt, &ikm);
|
||||||
let okm = hkdf.expand_to_len(&info, 42).unwrap();
|
let okm = hkdf.expand_to_len(&info, 42).unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -219,7 +219,7 @@ mod tests {
|
||||||
let salt = Vec::from_hex("000102030405060708090a0b0c").unwrap();
|
let salt = Vec::from_hex("000102030405060708090a0b0c").unwrap();
|
||||||
let ikm = Vec::from_hex("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b").unwrap();
|
let ikm = Vec::from_hex("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b").unwrap();
|
||||||
|
|
||||||
let hkdf = Hkdf::<sha256::Hash>::new(&salt, &ikm);
|
let hkdf = Hkdf::<sha256::HashEngine>::new(&salt, &ikm);
|
||||||
let debug = alloc::format!("{:?}", hkdf);
|
let debug = alloc::format!("{:?}", hkdf);
|
||||||
|
|
||||||
assert_eq!(debug, "Hkdf(#ec7bd36ab2ed4045)");
|
assert_eq!(debug, "Hkdf(#ec7bd36ab2ed4045)");
|
||||||
|
|
|
@ -12,36 +12,26 @@ use core::{convert, fmt, str};
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||||
|
|
||||||
use crate::{GeneralHash, Hash, HashEngine};
|
use crate::{Hash, HashEngine};
|
||||||
|
|
||||||
/// A hash computed from a RFC 2104 HMAC. Parameterized by the underlying hash function.
|
/// A hash computed from a RFC 2104 HMAC. Parameterized by the underlying hash function.
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
pub struct Hmac<T: GeneralHash>(T);
|
pub struct Hmac<T: Hash>(T);
|
||||||
|
|
||||||
impl<T: GeneralHash> Hmac<T> {
|
impl<T: Hash + str::FromStr> str::FromStr for Hmac<T> {
|
||||||
/// Constructs a new keyed HMAC engine from `key`.
|
|
||||||
pub fn engine(key: &[u8]) -> HmacEngine<T>
|
|
||||||
where
|
|
||||||
<T as GeneralHash>::Engine: Default,
|
|
||||||
{
|
|
||||||
HmacEngine::new(key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: GeneralHash + str::FromStr> str::FromStr for Hmac<T> {
|
|
||||||
type Err = <T as str::FromStr>::Err;
|
type Err = <T as str::FromStr>::Err;
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> { Ok(Hmac(str::FromStr::from_str(s)?)) }
|
fn from_str(s: &str) -> Result<Self, Self::Err> { Ok(Hmac(str::FromStr::from_str(s)?)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Pair of underlying hash engines, used for the inner and outer hash of HMAC.
|
/// Pair of underlying hash engines, used for the inner and outer hash of HMAC.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct HmacEngine<T: GeneralHash> {
|
pub struct HmacEngine<T: HashEngine> {
|
||||||
iengine: T::Engine,
|
iengine: T,
|
||||||
oengine: T::Engine,
|
oengine: T,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: GeneralHash> HmacEngine<T> {
|
impl<T: HashEngine> HmacEngine<T> {
|
||||||
/// Constructs a new keyed HMAC engine from `key`.
|
/// Constructs a new keyed HMAC engine from `key`.
|
||||||
///
|
///
|
||||||
/// We only support underlying hashes whose block sizes are ≤ 128 bytes.
|
/// We only support underlying hashes whose block sizes are ≤ 128 bytes.
|
||||||
|
@ -51,24 +41,23 @@ impl<T: GeneralHash> HmacEngine<T> {
|
||||||
/// Larger hashes will result in a panic.
|
/// Larger hashes will result in a panic.
|
||||||
pub fn new(key: &[u8]) -> HmacEngine<T>
|
pub fn new(key: &[u8]) -> HmacEngine<T>
|
||||||
where
|
where
|
||||||
<T as GeneralHash>::Engine: Default,
|
T: Default,
|
||||||
{
|
{
|
||||||
debug_assert!(T::Engine::BLOCK_SIZE <= 128);
|
debug_assert!(T::BLOCK_SIZE <= 128);
|
||||||
|
|
||||||
let mut ipad = [0x36u8; 128];
|
let mut ipad = [0x36u8; 128];
|
||||||
let mut opad = [0x5cu8; 128];
|
let mut opad = [0x5cu8; 128];
|
||||||
let mut ret = HmacEngine {
|
let mut ret = HmacEngine { iengine: T::default(), oengine: T::default() };
|
||||||
iengine: <T as GeneralHash>::engine(),
|
|
||||||
oengine: <T as GeneralHash>::engine(),
|
|
||||||
};
|
|
||||||
|
|
||||||
if key.len() > T::Engine::BLOCK_SIZE {
|
if key.len() > T::BLOCK_SIZE {
|
||||||
let hash = <T as GeneralHash>::hash(key);
|
let mut engine = T::default();
|
||||||
let hash = hash.as_byte_array().as_ref();
|
engine.input(key);
|
||||||
for (b_i, b_h) in ipad.iter_mut().zip(hash) {
|
let hash = engine.finalize();
|
||||||
|
|
||||||
|
for (b_i, b_h) in ipad.iter_mut().zip(hash.as_ref()) {
|
||||||
*b_i ^= *b_h;
|
*b_i ^= *b_h;
|
||||||
}
|
}
|
||||||
for (b_o, b_h) in opad.iter_mut().zip(hash) {
|
for (b_o, b_h) in opad.iter_mut().zip(hash.as_ref()) {
|
||||||
*b_o ^= *b_h;
|
*b_o ^= *b_h;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -80,54 +69,49 @@ impl<T: GeneralHash> HmacEngine<T> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
HashEngine::input(&mut ret.iengine, &ipad[..T::Engine::BLOCK_SIZE]);
|
ret.iengine.input(&ipad[..T::BLOCK_SIZE]);
|
||||||
HashEngine::input(&mut ret.oengine, &opad[..T::Engine::BLOCK_SIZE]);
|
ret.oengine.input(&opad[..T::BLOCK_SIZE]);
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A special constructor giving direct access to the underlying "inner" and "outer" engines.
|
/// 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<T> {
|
pub fn from_inner_engines(iengine: T, oengine: T) -> HmacEngine<T> {
|
||||||
HmacEngine { iengine, oengine }
|
HmacEngine { iengine, oengine }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: GeneralHash> HashEngine for HmacEngine<T> {
|
impl<T: HashEngine> HashEngine for HmacEngine<T> {
|
||||||
const BLOCK_SIZE: usize = T::Engine::BLOCK_SIZE;
|
type Hash = Hmac<T::Hash>;
|
||||||
|
type Bytes = T::Bytes;
|
||||||
|
const BLOCK_SIZE: usize = T::BLOCK_SIZE;
|
||||||
|
|
||||||
fn n_bytes_hashed(&self) -> u64 { self.iengine.n_bytes_hashed() }
|
fn n_bytes_hashed(&self) -> u64 { self.iengine.n_bytes_hashed() }
|
||||||
|
|
||||||
fn input(&mut self, buf: &[u8]) { self.iengine.input(buf) }
|
fn input(&mut self, buf: &[u8]) { self.iengine.input(buf) }
|
||||||
|
fn finalize(mut self) -> Self::Hash {
|
||||||
|
let ihash = self.iengine.finalize();
|
||||||
|
self.oengine.input(ihash.as_ref());
|
||||||
|
Hmac(self.oengine.finalize())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: GeneralHash + fmt::Debug> fmt::Debug for Hmac<T> {
|
impl<T: Hash + fmt::Debug> fmt::Debug for Hmac<T> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(&self.0, f) }
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(&self.0, f) }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: GeneralHash + fmt::Display> fmt::Display for Hmac<T> {
|
impl<T: Hash + fmt::Display> fmt::Display for Hmac<T> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) }
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: GeneralHash + fmt::LowerHex> fmt::LowerHex for Hmac<T> {
|
impl<T: Hash + fmt::LowerHex> fmt::LowerHex for Hmac<T> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(&self.0, f) }
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(&self.0, f) }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: GeneralHash> convert::AsRef<[u8]> for Hmac<T> {
|
impl<T: Hash> convert::AsRef<[u8]> for Hmac<T> {
|
||||||
// Calling as_byte_array is more reliable
|
// Calling as_byte_array is more reliable
|
||||||
fn as_ref(&self) -> &[u8] { self.0.as_byte_array().as_ref() }
|
fn as_ref(&self) -> &[u8] { self.0.as_byte_array().as_ref() }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: GeneralHash> GeneralHash for Hmac<T> {
|
impl<T: Hash> Hash for Hmac<T> {
|
||||||
type Engine = HmacEngine<T>;
|
|
||||||
|
|
||||||
fn from_engine(mut e: HmacEngine<T>) -> Hmac<T> {
|
|
||||||
let ihash = T::from_engine(e.iengine);
|
|
||||||
e.oengine.input(ihash.as_byte_array().as_ref());
|
|
||||||
let ohash = T::from_engine(e.oengine);
|
|
||||||
Hmac(ohash)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: GeneralHash> Hash for Hmac<T> {
|
|
||||||
type Bytes = T::Bytes;
|
type Bytes = T::Bytes;
|
||||||
|
|
||||||
fn from_byte_array(bytes: T::Bytes) -> Self { Hmac(T::from_byte_array(bytes)) }
|
fn from_byte_array(bytes: T::Bytes) -> Self { Hmac(T::from_byte_array(bytes)) }
|
||||||
|
@ -143,14 +127,14 @@ impl<T: GeneralHash> Hash for Hmac<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
impl<T: GeneralHash + Serialize> Serialize for Hmac<T> {
|
impl<T: Hash + Serialize> Serialize for Hmac<T> {
|
||||||
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
|
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
|
||||||
Serialize::serialize(&self.0, s)
|
Serialize::serialize(&self.0, s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
impl<'de, T: GeneralHash + Deserialize<'de>> Deserialize<'de> for Hmac<T> {
|
impl<'de, T: Hash + Deserialize<'de>> Deserialize<'de> for Hmac<T> {
|
||||||
fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Hmac<T>, D::Error> {
|
fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Hmac<T>, D::Error> {
|
||||||
let bytes = Deserialize::deserialize(d)?;
|
let bytes = Deserialize::deserialize(d)?;
|
||||||
Ok(Hmac(bytes))
|
Ok(Hmac(bytes))
|
||||||
|
@ -165,14 +149,14 @@ crate::internal_macros::impl_write!(
|
||||||
Ok(buf.len())
|
Ok(buf.len())
|
||||||
},
|
},
|
||||||
|_us| { Ok(()) },
|
|_us| { Ok(()) },
|
||||||
T: crate::GeneralHash
|
T: crate::HashEngine
|
||||||
);
|
);
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test() {
|
fn test() {
|
||||||
use crate::{sha256, GeneralHash as _, Hash as _, HashEngine, Hmac, HmacEngine};
|
use crate::{sha256, Hash as _, HashEngine, HmacEngine};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct Test {
|
struct Test {
|
||||||
|
@ -287,9 +271,9 @@ mod tests {
|
||||||
];
|
];
|
||||||
|
|
||||||
for test in tests {
|
for test in tests {
|
||||||
let mut engine = HmacEngine::<sha256::Hash>::new(test.key);
|
let mut engine = HmacEngine::<sha256::HashEngine>::new(test.key);
|
||||||
engine.input(test.input);
|
engine.input(test.input);
|
||||||
let hash = Hmac::<sha256::Hash>::from_engine(engine);
|
let hash = engine.finalize();
|
||||||
assert_eq!(hash.as_ref(), test.output);
|
assert_eq!(hash.as_ref(), test.output);
|
||||||
assert_eq!(hash.to_byte_array(), test.output);
|
assert_eq!(hash.to_byte_array(), test.output);
|
||||||
}
|
}
|
||||||
|
@ -330,11 +314,11 @@ mod tests {
|
||||||
mod benches {
|
mod benches {
|
||||||
use test::Bencher;
|
use test::Bencher;
|
||||||
|
|
||||||
use crate::{sha256, GeneralHash as _, HashEngine, Hmac};
|
use crate::{sha256, HashEngine as _, HmacEngine};
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
pub fn hmac_sha256_10(bh: &mut Bencher) {
|
pub fn hmac_sha256_10(bh: &mut Bencher) {
|
||||||
let mut engine = Hmac::<sha256::Hash>::engine(&[]);
|
let mut engine = HmacEngine::<sha256::HashEngine>::new(&[]);
|
||||||
let bytes = [1u8; 10];
|
let bytes = [1u8; 10];
|
||||||
bh.iter(|| {
|
bh.iter(|| {
|
||||||
engine.input(&bytes);
|
engine.input(&bytes);
|
||||||
|
@ -344,7 +328,7 @@ mod benches {
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
pub fn hmac_sha256_1k(bh: &mut Bencher) {
|
pub fn hmac_sha256_1k(bh: &mut Bencher) {
|
||||||
let mut engine = Hmac::<sha256::Hash>::engine(&[]);
|
let mut engine = HmacEngine::<sha256::HashEngine>::new(&[]);
|
||||||
let bytes = [1u8; 1024];
|
let bytes = [1u8; 1024];
|
||||||
bh.iter(|| {
|
bh.iter(|| {
|
||||||
engine.input(&bytes);
|
engine.input(&bytes);
|
||||||
|
@ -354,7 +338,7 @@ mod benches {
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
pub fn hmac_sha256_64k(bh: &mut Bencher) {
|
pub fn hmac_sha256_64k(bh: &mut Bencher) {
|
||||||
let mut engine = Hmac::<sha256::Hash>::engine(&[]);
|
let mut engine = HmacEngine::<sha256::HashEngine>::new(&[]);
|
||||||
let bytes = [1u8; 65536];
|
let bytes = [1u8; 65536];
|
||||||
bh.iter(|| {
|
bh.iter(|| {
|
||||||
engine.input(&bytes);
|
engine.input(&bytes);
|
||||||
|
|
|
@ -26,12 +26,6 @@ macro_rules! hash_trait_impls {
|
||||||
#[cfg(not(feature = "hex"))]
|
#[cfg(not(feature = "hex"))]
|
||||||
$crate::impl_debug_only!(Hash, { $bits / 8 }, $reverse $(, $gen: $gent)*);
|
$crate::impl_debug_only!(Hash, { $bits / 8 }, $reverse $(, $gen: $gent)*);
|
||||||
|
|
||||||
impl<$($gen: $gent),*> $crate::GeneralHash for Hash<$($gen),*> {
|
|
||||||
type Engine = HashEngine<$($gen),*>;
|
|
||||||
|
|
||||||
fn from_engine(e: Self::Engine) -> Hash<$($gen),*> { Self::from_engine(e) }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
$crate::serde_impl!(Hash, { $bits / 8} $(, $gen: $gent)*);
|
$crate::serde_impl!(Hash, { $bits / 8} $(, $gen: $gent)*);
|
||||||
|
|
||||||
|
@ -71,6 +65,30 @@ pub(crate) use hash_trait_impls;
|
||||||
/// [`hash_trait_impls`].
|
/// [`hash_trait_impls`].
|
||||||
macro_rules! general_hash_type {
|
macro_rules! general_hash_type {
|
||||||
($bits:expr, $reverse:expr, $doc:literal) => {
|
($bits:expr, $reverse:expr, $doc:literal) => {
|
||||||
|
/// Hashes some bytes.
|
||||||
|
pub fn hash(data: &[u8]) -> Hash {
|
||||||
|
use crate::HashEngine as _;
|
||||||
|
|
||||||
|
let mut engine = Hash::engine();
|
||||||
|
engine.input(data);
|
||||||
|
engine.finalize()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Hashes all the byte slices retrieved from the iterator together.
|
||||||
|
pub fn hash_byte_chunks<B, I>(byte_slices: I) -> Hash
|
||||||
|
where
|
||||||
|
B: AsRef<[u8]>,
|
||||||
|
I: IntoIterator<Item = B>,
|
||||||
|
{
|
||||||
|
use crate::HashEngine as _;
|
||||||
|
|
||||||
|
let mut engine = Hash::engine();
|
||||||
|
for slice in byte_slices {
|
||||||
|
engine.input(slice.as_ref());
|
||||||
|
}
|
||||||
|
engine.finalize()
|
||||||
|
}
|
||||||
|
|
||||||
$crate::internal_macros::hash_type_no_default!($bits, $reverse, $doc);
|
$crate::internal_macros::hash_type_no_default!($bits, $reverse, $doc);
|
||||||
|
|
||||||
impl Hash {
|
impl Hash {
|
||||||
|
@ -82,7 +100,7 @@ macro_rules! general_hash_type {
|
||||||
|
|
||||||
/// Hashes some bytes.
|
/// Hashes some bytes.
|
||||||
#[allow(clippy::self_named_constructors)] // Hash is a noun and a verb.
|
#[allow(clippy::self_named_constructors)] // Hash is a noun and a verb.
|
||||||
pub fn hash(data: &[u8]) -> Self { <Self as $crate::GeneralHash>::hash(data) }
|
pub fn hash(data: &[u8]) -> Self { hash(data) }
|
||||||
|
|
||||||
/// Hashes all the byte slices retrieved from the iterator together.
|
/// Hashes all the byte slices retrieved from the iterator together.
|
||||||
pub fn hash_byte_chunks<B, I>(byte_slices: I) -> Self
|
pub fn hash_byte_chunks<B, I>(byte_slices: I) -> Self
|
||||||
|
@ -90,7 +108,7 @@ macro_rules! general_hash_type {
|
||||||
B: AsRef<[u8]>,
|
B: AsRef<[u8]>,
|
||||||
I: IntoIterator<Item = B>,
|
I: IntoIterator<Item = B>,
|
||||||
{
|
{
|
||||||
<Self as $crate::GeneralHash>::hash_byte_chunks(byte_slices)
|
hash_byte_chunks(byte_slices)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -186,6 +186,15 @@ pub type HkdfSha512 = Hkdf<sha512::Hash>;
|
||||||
|
|
||||||
/// A hashing engine which bytes can be serialized into.
|
/// A hashing engine which bytes can be serialized into.
|
||||||
pub trait HashEngine: Clone {
|
pub trait HashEngine: Clone {
|
||||||
|
/// The `Hash` type returned when finalizing this engine.
|
||||||
|
type Hash: Hash;
|
||||||
|
|
||||||
|
/// The byte array that is used internally in `finalize`.
|
||||||
|
type Bytes: Copy + IsByteArray;
|
||||||
|
|
||||||
|
/// Length of the hash, in bytes.
|
||||||
|
const LEN: usize = Self::Bytes::LEN;
|
||||||
|
|
||||||
/// Length of the hash's internal block size, in bytes.
|
/// Length of the hash's internal block size, in bytes.
|
||||||
const BLOCK_SIZE: usize;
|
const BLOCK_SIZE: usize;
|
||||||
|
|
||||||
|
@ -194,52 +203,9 @@ pub trait HashEngine: Clone {
|
||||||
|
|
||||||
/// Return the number of bytes already input into the engine.
|
/// Return the number of bytes already input into the engine.
|
||||||
fn n_bytes_hashed(&self) -> u64;
|
fn n_bytes_hashed(&self) -> u64;
|
||||||
}
|
|
||||||
|
|
||||||
/// Trait describing hash digests which can be constructed by hashing arbitrary data.
|
/// Finalizes this engine.
|
||||||
///
|
fn finalize(self) -> Self::Hash;
|
||||||
/// Some methods have been bound to engines which implement Default, which is
|
|
||||||
/// generally an unkeyed hash function.
|
|
||||||
pub trait GeneralHash: Hash {
|
|
||||||
/// 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;
|
|
||||||
|
|
||||||
/// Constructs a new engine.
|
|
||||||
fn engine() -> Self::Engine
|
|
||||||
where
|
|
||||||
Self::Engine: Default,
|
|
||||||
{
|
|
||||||
Self::Engine::default()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Produces a hash from the current state of a given engine.
|
|
||||||
fn from_engine(e: Self::Engine) -> Self;
|
|
||||||
|
|
||||||
/// Hashes some bytes.
|
|
||||||
fn hash(data: &[u8]) -> Self
|
|
||||||
where
|
|
||||||
Self::Engine: Default,
|
|
||||||
{
|
|
||||||
let mut engine = Self::engine();
|
|
||||||
engine.input(data);
|
|
||||||
Self::from_engine(engine)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Hashes all the byte slices retrieved from the iterator together.
|
|
||||||
fn hash_byte_chunks<B, I>(byte_slices: I) -> Self
|
|
||||||
where
|
|
||||||
B: AsRef<[u8]>,
|
|
||||||
I: IntoIterator<Item = B>,
|
|
||||||
Self::Engine: Default,
|
|
||||||
{
|
|
||||||
let mut engine = Self::engine();
|
|
||||||
for slice in byte_slices {
|
|
||||||
engine.input(slice.as_ref());
|
|
||||||
}
|
|
||||||
Self::from_engine(engine)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Trait which applies to hashes of all types.
|
/// Trait which applies to hashes of all types.
|
||||||
|
|
|
@ -87,9 +87,11 @@ impl Default for HashEngine {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl crate::HashEngine for HashEngine {
|
impl crate::HashEngine for HashEngine {
|
||||||
|
type Hash = Hash;
|
||||||
|
type Bytes = [u8; 20];
|
||||||
const BLOCK_SIZE: usize = 64;
|
const BLOCK_SIZE: usize = 64;
|
||||||
|
|
||||||
fn n_bytes_hashed(&self) -> u64 { self.bytes_hashed }
|
fn n_bytes_hashed(&self) -> u64 { self.bytes_hashed }
|
||||||
|
|
||||||
crate::internal_macros::engine_input_impl!();
|
crate::internal_macros::engine_input_impl!();
|
||||||
|
fn finalize(self) -> Self::Hash { Hash::from_engine(self) }
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,9 +79,13 @@ impl Default for HashEngine {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl crate::HashEngine for HashEngine {
|
impl crate::HashEngine for HashEngine {
|
||||||
|
type Hash = Hash;
|
||||||
|
type Bytes = [u8; 20];
|
||||||
const BLOCK_SIZE: usize = 64;
|
const BLOCK_SIZE: usize = 64;
|
||||||
|
|
||||||
fn n_bytes_hashed(&self) -> u64 { self.bytes_hashed }
|
fn n_bytes_hashed(&self) -> u64 { self.bytes_hashed }
|
||||||
|
|
||||||
crate::internal_macros::engine_input_impl!();
|
crate::internal_macros::engine_input_impl!();
|
||||||
|
|
||||||
|
fn finalize(self) -> Self::Hash { Hash::from_engine(self) }
|
||||||
}
|
}
|
||||||
|
|
|
@ -128,19 +128,19 @@ impl Default for HashEngine {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl crate::HashEngine for HashEngine {
|
impl crate::HashEngine for HashEngine {
|
||||||
|
type Hash = Hash;
|
||||||
|
type Bytes = [u8; 32];
|
||||||
const BLOCK_SIZE: usize = 64;
|
const BLOCK_SIZE: usize = 64;
|
||||||
|
|
||||||
fn n_bytes_hashed(&self) -> u64 { self.bytes_hashed }
|
fn n_bytes_hashed(&self) -> u64 { self.bytes_hashed }
|
||||||
|
|
||||||
crate::internal_macros::engine_input_impl!();
|
crate::internal_macros::engine_input_impl!();
|
||||||
|
fn finalize(self) -> Self::Hash { Hash::from_engine(self) }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Hash {
|
impl Hash {
|
||||||
/// Iterate the sha256 algorithm to turn a sha256 hash into a sha256d hash
|
/// Iterate the sha256 algorithm to turn a sha256 hash into a sha256d hash
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn hash_again(&self) -> sha256d::Hash {
|
pub fn hash_again(&self) -> sha256d::Hash { sha256d::Hash::from_byte_array(hash(&self.0).0) }
|
||||||
crate::Hash::from_byte_array(<Self as crate::GeneralHash>::hash(&self.0).0)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Computes hash from `bytes` in `const` context.
|
/// Computes hash from `bytes` in `const` context.
|
||||||
///
|
///
|
||||||
|
|
|
@ -33,9 +33,13 @@ impl Default for HashEngine {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl crate::HashEngine for HashEngine {
|
impl crate::HashEngine for HashEngine {
|
||||||
|
type Hash = Hash;
|
||||||
|
type Bytes = [u8; 32];
|
||||||
const BLOCK_SIZE: usize = 64; // Same as sha256::HashEngine::BLOCK_SIZE;
|
const BLOCK_SIZE: usize = 64; // Same as sha256::HashEngine::BLOCK_SIZE;
|
||||||
|
|
||||||
fn input(&mut self, data: &[u8]) { self.0.input(data) }
|
fn input(&mut self, data: &[u8]) { self.0.input(data) }
|
||||||
fn n_bytes_hashed(&self) -> u64 { self.0.n_bytes_hashed() }
|
fn n_bytes_hashed(&self) -> u64 { self.0.n_bytes_hashed() }
|
||||||
|
fn finalize(self) -> Self::Hash { Hash::from_engine(self) }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -9,6 +9,34 @@ use core::marker::PhantomData;
|
||||||
use crate::sha256::Midstate;
|
use crate::sha256::Midstate;
|
||||||
use crate::{sha256, HashEngine as _};
|
use crate::{sha256, HashEngine as _};
|
||||||
|
|
||||||
|
/// Hashes some bytes.
|
||||||
|
pub fn hash<T>(data: &[u8]) -> Hash<T>
|
||||||
|
where
|
||||||
|
T: Tag,
|
||||||
|
{
|
||||||
|
use crate::HashEngine as _;
|
||||||
|
|
||||||
|
let mut engine = HashEngine::default();
|
||||||
|
engine.input(data);
|
||||||
|
engine.finalize()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Hashes all the byte slices retrieved from the iterator together.
|
||||||
|
pub fn hash_byte_chunks<B, I, T>(byte_slices: I) -> Hash<T>
|
||||||
|
where
|
||||||
|
B: AsRef<[u8]>,
|
||||||
|
I: IntoIterator<Item = B>,
|
||||||
|
T: Tag,
|
||||||
|
{
|
||||||
|
use crate::HashEngine as _;
|
||||||
|
|
||||||
|
let mut engine = HashEngine::default();
|
||||||
|
for slice in byte_slices {
|
||||||
|
engine.input(slice.as_ref());
|
||||||
|
}
|
||||||
|
engine.finalize()
|
||||||
|
}
|
||||||
|
|
||||||
/// Trait representing a tag that can be used as a context for SHA256t hashes.
|
/// Trait representing a tag that can be used as a context for SHA256t hashes.
|
||||||
pub trait Tag {
|
pub trait Tag {
|
||||||
/// The [`Midstate`] after pre-tagging the hash engine.
|
/// The [`Midstate`] after pre-tagging the hash engine.
|
||||||
|
@ -133,9 +161,13 @@ impl<T: Tag> Clone for HashEngine<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Tag> crate::HashEngine for HashEngine<T> {
|
impl<T: Tag> crate::HashEngine for HashEngine<T> {
|
||||||
|
type Hash = Hash<T>;
|
||||||
|
type Bytes = [u8; 32];
|
||||||
const BLOCK_SIZE: usize = 64; // Same as sha256::HashEngine::BLOCK_SIZE;
|
const BLOCK_SIZE: usize = 64; // Same as sha256::HashEngine::BLOCK_SIZE;
|
||||||
|
|
||||||
fn input(&mut self, data: &[u8]) { self.0.input(data) }
|
fn input(&mut self, data: &[u8]) { self.0.input(data) }
|
||||||
fn n_bytes_hashed(&self) -> u64 { self.0.n_bytes_hashed() }
|
fn n_bytes_hashed(&self) -> u64 { self.0.n_bytes_hashed() }
|
||||||
|
fn finalize(self) -> Self::Hash { Hash::from_engine(self) }
|
||||||
}
|
}
|
||||||
|
|
||||||
crate::internal_macros::impl_write!(
|
crate::internal_macros::impl_write!(
|
||||||
|
|
|
@ -30,11 +30,13 @@ impl Default for HashEngine {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl crate::HashEngine for HashEngine {
|
impl crate::HashEngine for HashEngine {
|
||||||
|
type Hash = Hash;
|
||||||
|
type Bytes = [u8; 48];
|
||||||
const BLOCK_SIZE: usize = sha512::BLOCK_SIZE;
|
const BLOCK_SIZE: usize = sha512::BLOCK_SIZE;
|
||||||
|
|
||||||
fn n_bytes_hashed(&self) -> u64 { self.0.n_bytes_hashed() }
|
fn n_bytes_hashed(&self) -> u64 { self.0.n_bytes_hashed() }
|
||||||
|
|
||||||
fn input(&mut self, inp: &[u8]) { self.0.input(inp); }
|
fn input(&mut self, inp: &[u8]) { self.0.input(inp); }
|
||||||
|
fn finalize(self) -> Self::Hash { Hash::from_engine(self) }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -120,9 +120,11 @@ impl HashEngine {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl crate::HashEngine for HashEngine {
|
impl crate::HashEngine for HashEngine {
|
||||||
|
type Hash = Hash;
|
||||||
|
type Bytes = [u8; 64];
|
||||||
const BLOCK_SIZE: usize = 128;
|
const BLOCK_SIZE: usize = 128;
|
||||||
|
|
||||||
fn n_bytes_hashed(&self) -> u64 { self.bytes_hashed }
|
fn n_bytes_hashed(&self) -> u64 { self.bytes_hashed }
|
||||||
|
|
||||||
crate::internal_macros::engine_input_impl!();
|
crate::internal_macros::engine_input_impl!();
|
||||||
|
fn finalize(self) -> Self::Hash { Hash::from_engine(self) }
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,11 +40,13 @@ impl Default for HashEngine {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl crate::HashEngine for HashEngine {
|
impl crate::HashEngine for HashEngine {
|
||||||
|
type Hash = Hash;
|
||||||
|
type Bytes = [u8; 64];
|
||||||
const BLOCK_SIZE: usize = sha512::BLOCK_SIZE;
|
const BLOCK_SIZE: usize = sha512::BLOCK_SIZE;
|
||||||
|
|
||||||
fn n_bytes_hashed(&self) -> u64 { self.0.n_bytes_hashed() }
|
fn n_bytes_hashed(&self) -> u64 { self.0.n_bytes_hashed() }
|
||||||
|
|
||||||
fn input(&mut self, inp: &[u8]) { self.0.input(inp); }
|
fn input(&mut self, inp: &[u8]) { self.0.input(inp); }
|
||||||
|
fn finalize(self) -> Self::Hash { Hash::from_engine(self) }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -121,6 +121,8 @@ impl HashEngine {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl crate::HashEngine for HashEngine {
|
impl crate::HashEngine for HashEngine {
|
||||||
|
type Hash = Hash;
|
||||||
|
type Bytes = [u8; 8];
|
||||||
const BLOCK_SIZE: usize = 8;
|
const BLOCK_SIZE: usize = 8;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -165,6 +167,8 @@ impl crate::HashEngine for HashEngine {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn n_bytes_hashed(&self) -> u64 { self.bytes_hashed }
|
fn n_bytes_hashed(&self) -> u64 { self.bytes_hashed }
|
||||||
|
|
||||||
|
fn finalize(self) -> Self::Hash { Hash::from_engine(self) }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Hash {
|
impl Hash {
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
use bitcoin_hashes::{
|
use bitcoin_hashes::{
|
||||||
hash160, ripemd160, sha1, sha256, sha256d, sha256t, sha384, sha512, sha512_256, siphash24,
|
hash160, ripemd160, sha1, sha256, sha256d, sha256t, sha384, sha512, sha512_256, siphash24,
|
||||||
GeneralHash as _, HashEngine as _, Hmac, HmacEngine,
|
HashEngine as _, HmacEngine,
|
||||||
};
|
};
|
||||||
|
|
||||||
const DATA: &str = "arbitrary data to hash as a regression test";
|
const DATA: &str = "arbitrary data to hash as a regression test";
|
||||||
|
@ -57,9 +57,9 @@ fn regression_sha256t() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn regression_hmac_sha256_with_key() {
|
fn regression_hmac_sha256_with_key() {
|
||||||
let mut engine = HmacEngine::<sha256::Hash>::new(HMAC_KEY);
|
let mut engine = HmacEngine::<sha256::HashEngine>::new(HMAC_KEY);
|
||||||
engine.input(DATA.as_bytes());
|
engine.input(DATA.as_bytes());
|
||||||
let hash = Hmac::from_engine(engine);
|
let hash = engine.finalize();
|
||||||
|
|
||||||
let got = format!("{}", hash);
|
let got = format!("{}", hash);
|
||||||
let want = "d159cecaf4adf90b6a641bab767e4817d3a51c414acea3682686c35ec0b37b52";
|
let want = "d159cecaf4adf90b6a641bab767e4817d3a51c414acea3682686c35ec0b37b52";
|
||||||
|
@ -68,9 +68,9 @@ fn regression_hmac_sha256_with_key() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn regression_hmac_sha512_with_key() {
|
fn regression_hmac_sha512_with_key() {
|
||||||
let mut engine = HmacEngine::<sha512::Hash>::new(HMAC_KEY);
|
let mut engine = HmacEngine::<sha512::HashEngine>::new(HMAC_KEY);
|
||||||
engine.input(DATA.as_bytes());
|
engine.input(DATA.as_bytes());
|
||||||
let hash = Hmac::from_engine(engine);
|
let hash = engine.finalize();
|
||||||
|
|
||||||
let got = format!("{}", hash);
|
let got = format!("{}", hash);
|
||||||
let want = "8511773748f89ba22c07fb3a2981a12c1823695119de41f4a62aead6b848bd34939acf16475c35ed7956114fead3e794cc162ecd35e447a4dabc3227d55f757b";
|
let want = "8511773748f89ba22c07fb3a2981a12c1823695119de41f4a62aead6b848bd34939acf16475c35ed7956114fead3e794cc162ecd35e447a4dabc3227d55f757b";
|
||||||
|
@ -87,3 +87,13 @@ fn regression_siphash24_with_key() {
|
||||||
let want = "e823ed82311d601a";
|
let want = "e823ed82311d601a";
|
||||||
assert_eq!(got, want);
|
assert_eq!(got, want);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn regression_sha256_hash_again() {
|
||||||
|
let hash = sha256::Hash::hash(b"Don't explain your philosophy. Embody it.");
|
||||||
|
let again = hash.hash_again();
|
||||||
|
|
||||||
|
let got = format!("{}", again);
|
||||||
|
let want = "28273103bcd88ab99e2b1007174770ff3f0ea91ee4b3ac942879ed1a2d264b4c";
|
||||||
|
assert_eq!(got, want);
|
||||||
|
}
|
||||||
|
|
|
@ -10,9 +10,11 @@
|
||||||
use hashes::hmac::HmacEngine;
|
use hashes::hmac::HmacEngine;
|
||||||
use hashes::{
|
use hashes::{
|
||||||
hash160, ripemd160, sha1, sha256, sha256d, sha256t, sha384, sha512, sha512_256, siphash24,
|
hash160, ripemd160, sha1, sha256, sha256d, sha256t, sha384, sha512, sha512_256, siphash24,
|
||||||
GeneralHash, HashEngine as _,
|
HashEngine as _,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use crate::BufRead;
|
||||||
|
|
||||||
macro_rules! impl_write {
|
macro_rules! impl_write {
|
||||||
($ty: ty, $write_fn: expr, $flush_fn: expr $(, $bounded_ty: ident : $bounds: path),*) => {
|
($ty: ty, $write_fn: expr, $flush_fn: expr $(, $bounded_ty: ident : $bounds: path),*) => {
|
||||||
// `std::io::Write` is implemented in `bitcoin_hashes` because of the orphan rule.
|
// `std::io::Write` is implemented in `bitcoin_hashes` because of the orphan rule.
|
||||||
|
@ -128,43 +130,28 @@ impl_write!(
|
||||||
Ok(buf.len())
|
Ok(buf.len())
|
||||||
},
|
},
|
||||||
|_us| { Ok(()) },
|
|_us| { Ok(()) },
|
||||||
T: hashes::GeneralHash
|
T: hashes::HashEngine
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Hashes data from a reader.
|
/// Hashes data from a reader.
|
||||||
///
|
pub fn hash_reader<T>(reader: &mut impl BufRead) -> Result<T::Hash, crate::Error>
|
||||||
/// Adds functionality to a [`hashes::GeneralHash`] type to support hashing data read from a
|
where
|
||||||
/// buffered reader.
|
T: hashes::HashEngine + Default,
|
||||||
pub trait GeneralHashExt: GeneralHash + sealed::Sealed {
|
{
|
||||||
/// Hashes the entire contents of the `reader`.
|
let mut engine = T::default();
|
||||||
fn hash_reader<R: crate::BufRead>(reader: &mut R) -> Result<Self, crate::Error>
|
loop {
|
||||||
where
|
let bytes = reader.fill_buf()?;
|
||||||
Self::Engine: Default,
|
|
||||||
{
|
|
||||||
let mut engine = Self::engine(); // This calls `Self::Engine::default()`.
|
|
||||||
loop {
|
|
||||||
let bytes = reader.fill_buf()?;
|
|
||||||
|
|
||||||
let read = bytes.len();
|
let read = bytes.len();
|
||||||
// Empty slice means EOF.
|
// Empty slice means EOF.
|
||||||
if read == 0 {
|
if read == 0 {
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
engine.input(bytes);
|
|
||||||
reader.consume(read);
|
|
||||||
}
|
}
|
||||||
Ok(Self::from_engine(engine))
|
|
||||||
|
engine.input(bytes);
|
||||||
|
reader.consume(read);
|
||||||
}
|
}
|
||||||
}
|
Ok(engine.finalize())
|
||||||
|
|
||||||
impl<T: GeneralHash> GeneralHashExt for T {}
|
|
||||||
|
|
||||||
mod sealed {
|
|
||||||
/// Used to seal the `GeneralHashExt` trait.
|
|
||||||
pub trait Sealed {}
|
|
||||||
|
|
||||||
impl<T: hashes::GeneralHash> Sealed for T {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -172,7 +159,7 @@ mod sealed {
|
||||||
mod tests {
|
mod tests {
|
||||||
use alloc::format;
|
use alloc::format;
|
||||||
|
|
||||||
use hashes::{hmac, Hmac};
|
use hashes::hmac;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{Cursor, Write as _};
|
use crate::{Cursor, Write as _};
|
||||||
|
@ -257,24 +244,24 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn hmac() {
|
fn hmac() {
|
||||||
let mut engine = hmac::HmacEngine::<sha256::Hash>::new(&[0xde, 0xad, 0xbe, 0xef]);
|
let mut engine = hmac::HmacEngine::<sha256::HashEngine>::new(&[0xde, 0xad, 0xbe, 0xef]);
|
||||||
engine.write_all(&[]).unwrap();
|
engine.write_all(&[]).unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
format!("{}", hmac::Hmac::from_engine(engine)),
|
format!("{}", engine.finalize()),
|
||||||
"bf5515149cf797955c4d3194cca42472883281951697c8375d9d9b107f384225"
|
"bf5515149cf797955c4d3194cca42472883281951697c8375d9d9b107f384225"
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut engine = hmac::HmacEngine::<sha256::Hash>::new(&[0xde, 0xad, 0xbe, 0xef]);
|
let mut engine = hmac::HmacEngine::<sha256::HashEngine>::new(&[0xde, 0xad, 0xbe, 0xef]);
|
||||||
engine.write_all(&[1; 256]).unwrap();
|
engine.write_all(&[1; 256]).unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
format!("{}", hmac::Hmac::from_engine(engine)),
|
format!("{}", engine.finalize()),
|
||||||
"59c9aca10c81c73cb4c196d94db741b6bf2050e0153d5a45f2526bff34675ac5"
|
"59c9aca10c81c73cb4c196d94db741b6bf2050e0153d5a45f2526bff34675ac5"
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut engine = hmac::HmacEngine::<sha256::Hash>::new(&[0xde, 0xad, 0xbe, 0xef]);
|
let mut engine = hmac::HmacEngine::<sha256::HashEngine>::new(&[0xde, 0xad, 0xbe, 0xef]);
|
||||||
engine.write_all(&[99; 64000]).unwrap();
|
engine.write_all(&[99; 64000]).unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
format!("{}", hmac::Hmac::from_engine(engine)),
|
format!("{}", engine.finalize()),
|
||||||
"30df499717415a395379a1eaabe50038036e4abb5afc94aa55c952f4aa57be08"
|
"30df499717415a395379a1eaabe50038036e4abb5afc94aa55c952f4aa57be08"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -308,7 +295,7 @@ mod tests {
|
||||||
assert_eq!(got, $want);
|
assert_eq!(got, $want);
|
||||||
|
|
||||||
let mut reader = Cursor::new(DATA);
|
let mut reader = Cursor::new(DATA);
|
||||||
let hash_from_reader = $module::Hash::hash_reader(&mut reader).unwrap();
|
let hash_from_reader = $crate::hash_reader::<$module::HashEngine>(&mut reader).unwrap();
|
||||||
assert_eq!(hash_from_reader, hash)
|
assert_eq!(hash_from_reader, hash)
|
||||||
}
|
}
|
||||||
)*
|
)*
|
||||||
|
@ -345,9 +332,9 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn regression_hmac_sha256_with_key() {
|
fn regression_hmac_sha256_with_key() {
|
||||||
let mut engine = HmacEngine::<sha256::Hash>::new(HMAC_KEY);
|
let mut engine = HmacEngine::<sha256::HashEngine>::new(HMAC_KEY);
|
||||||
engine.input(DATA.as_bytes());
|
engine.input(DATA.as_bytes());
|
||||||
let hash = Hmac::from_engine(engine);
|
let hash = engine.finalize();
|
||||||
|
|
||||||
let got = format!("{}", hash);
|
let got = format!("{}", hash);
|
||||||
let want = "d159cecaf4adf90b6a641bab767e4817d3a51c414acea3682686c35ec0b37b52";
|
let want = "d159cecaf4adf90b6a641bab767e4817d3a51c414acea3682686c35ec0b37b52";
|
||||||
|
@ -356,9 +343,9 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn regression_hmac_sha512_with_key() {
|
fn regression_hmac_sha512_with_key() {
|
||||||
let mut engine = HmacEngine::<sha512::Hash>::new(HMAC_KEY);
|
let mut engine = HmacEngine::<sha512::HashEngine>::new(HMAC_KEY);
|
||||||
engine.input(DATA.as_bytes());
|
engine.input(DATA.as_bytes());
|
||||||
let hash = Hmac::from_engine(engine);
|
let hash = engine.finalize();
|
||||||
|
|
||||||
let got = format!("{}", hash);
|
let got = format!("{}", hash);
|
||||||
let want = "8511773748f89ba22c07fb3a2981a12c1823695119de41f4a62aead6b848bd34939acf16475c35ed7956114fead3e794cc162ecd35e447a4dabc3227d55f757b";
|
let want = "8511773748f89ba22c07fb3a2981a12c1823695119de41f4a62aead6b848bd34939acf16475c35ed7956114fead3e794cc162ecd35e447a4dabc3227d55f757b";
|
||||||
|
|
|
@ -46,7 +46,7 @@ pub use bridge::{FromStd, ToStd};
|
||||||
#[rustfmt::skip] // Keep public re-exports separate.
|
#[rustfmt::skip] // Keep public re-exports separate.
|
||||||
pub use self::error::{Error, ErrorKind};
|
pub use self::error::{Error, ErrorKind};
|
||||||
#[cfg(feature = "hashes")]
|
#[cfg(feature = "hashes")]
|
||||||
pub use self::hash::GeneralHashExt;
|
pub use self::hash::hash_reader;
|
||||||
|
|
||||||
/// Result type returned by functions in this crate.
|
/// Result type returned by functions in this crate.
|
||||||
pub type Result<T> = core::result::Result<T, Error>;
|
pub type Result<T> = core::result::Result<T, Error>;
|
||||||
|
|
Loading…
Reference in New Issue