Merge rust-bitcoin/rust-bitcoin#3981: Do not implement `Default` for `HmacEngine`

18619a6d0b api: Run just check-api (Tobin C. Harding)
1eb8f1f9e0 Add a Hmac::engine function (Tobin C. Harding)
c352d376ed Do not implement Default for HmacEngine (Tobin C. Harding)

Pull request description:

  The `HmacEngine` should be created using a key. Currently we are providing a `Default` impl that uses `&[]` as the key. This is, I believe, a hangover from when we had a `Default` trait bound somewhere else. It is incorrect and an API footgun - remove it.

  Note this PR includes changes to the bench code in `hmac` that highlights the footgun - pity the poor user we even shot ourselves.

  Patch 2 adds a constructor `Hmac::engine` and uses it in the bench code.

ACKs for top commit:
  Kixunil:
    ACK 18619a6d0b
  apoelstra:
    ACK 18619a6d0b0bca7b7e3603e260b254b4aae6cebf; successfully ran local tests

Tree-SHA512: c96640e7ffba52d5b13b76a6dd9e1381788efcf56ee76300c5111541466bab8018d2546bcecf237c42dbd82e9372a0e43e1ecec37147508e879365d92a4c1451
This commit is contained in:
merge-script 2025-01-31 20:29:55 +00:00
commit e45bc0056c
No known key found for this signature in database
GPG Key ID: C588D63CE41B97C1
5 changed files with 20 additions and 33 deletions

View File

@ -458,10 +458,10 @@ impl<T: bitcoin_hashes::GeneralHash> bitcoin_hashes::GeneralHash for bitcoin_has
impl<T: bitcoin_hashes::GeneralHash> bitcoin_hashes::Hash for bitcoin_hashes::hmac::Hmac<T>
impl<T: bitcoin_hashes::GeneralHash> bitcoin_hashes::HashEngine for bitcoin_hashes::hmac::HmacEngine<T>
impl<T: bitcoin_hashes::GeneralHash> bitcoin_hashes::hkdf::Hkdf<T> where <T as bitcoin_hashes::GeneralHash>::Engine: core::default::Default
impl<T: bitcoin_hashes::GeneralHash> bitcoin_hashes::hmac::Hmac<T>
impl<T: bitcoin_hashes::GeneralHash> bitcoin_hashes::hmac::HmacEngine<T>
impl<T: bitcoin_hashes::GeneralHash> bitcoin_io::Write for bitcoin_hashes::hmac::HmacEngine<T>
impl<T: bitcoin_hashes::GeneralHash> core::convert::AsRef<[u8]> for bitcoin_hashes::hmac::Hmac<T>
impl<T: bitcoin_hashes::GeneralHash> core::default::Default for bitcoin_hashes::hmac::HmacEngine<T> where <T as bitcoin_hashes::GeneralHash>::Engine: core::default::Default
impl<T: bitcoin_hashes::GeneralHash> core::marker::StructuralPartialEq for bitcoin_hashes::hmac::Hmac<T>
impl<T: bitcoin_hashes::GeneralHash> std::io::Write for bitcoin_hashes::hmac::HmacEngine<T>
impl<T: bitcoin_hashes::sha256t::Tag> bitcoin_hashes::GeneralHash for bitcoin_hashes::sha256t::Hash<T>
@ -668,6 +668,7 @@ pub fn bitcoin_hashes::hmac::Hmac<T>::as_ref(&self) -> &[u8]
pub fn bitcoin_hashes::hmac::Hmac<T>::clone(&self) -> bitcoin_hashes::hmac::Hmac<T>
pub fn bitcoin_hashes::hmac::Hmac<T>::cmp(&self, other: &bitcoin_hashes::hmac::Hmac<T>) -> core::cmp::Ordering
pub fn bitcoin_hashes::hmac::Hmac<T>::deserialize<D: serde::de::Deserializer<'de>>(d: D) -> core::result::Result<bitcoin_hashes::hmac::Hmac<T>, <D as serde::de::Deserializer>::Error>
pub fn bitcoin_hashes::hmac::Hmac<T>::engine(key: &[u8]) -> bitcoin_hashes::hmac::HmacEngine<T> where <T as bitcoin_hashes::GeneralHash>::Engine: core::default::Default
pub fn bitcoin_hashes::hmac::Hmac<T>::eq(&self, other: &bitcoin_hashes::hmac::Hmac<T>) -> bool
pub fn bitcoin_hashes::hmac::Hmac<T>::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result
pub fn bitcoin_hashes::hmac::Hmac<T>::from_byte_array(bytes: <T as bitcoin_hashes::Hash>::Bytes) -> Self
@ -679,7 +680,6 @@ pub fn bitcoin_hashes::hmac::Hmac<T>::partial_cmp(&self, other: &bitcoin_hashes:
pub fn bitcoin_hashes::hmac::Hmac<T>::serialize<S: serde::ser::Serializer>(&self, s: S) -> core::result::Result<<S as serde::ser::Serializer>::Ok, <S as serde::ser::Serializer>::Error>
pub fn bitcoin_hashes::hmac::Hmac<T>::to_byte_array(self) -> Self::Bytes
pub fn bitcoin_hashes::hmac::HmacEngine<T>::clone(&self) -> bitcoin_hashes::hmac::HmacEngine<T>
pub fn bitcoin_hashes::hmac::HmacEngine<T>::default() -> Self
pub fn bitcoin_hashes::hmac::HmacEngine<T>::flush(&mut self) -> bitcoin_io::Result<()>
pub fn bitcoin_hashes::hmac::HmacEngine<T>::flush(&mut self) -> std::io::error::Result<()>
pub fn bitcoin_hashes::hmac::HmacEngine<T>::from_inner_engines(iengine: <T as bitcoin_hashes::GeneralHash>::Engine, oengine: <T as bitcoin_hashes::GeneralHash>::Engine) -> bitcoin_hashes::hmac::HmacEngine<T>

View File

@ -416,9 +416,9 @@ impl<T: bitcoin_hashes::GeneralHash> bitcoin_hashes::GeneralHash for bitcoin_has
impl<T: bitcoin_hashes::GeneralHash> bitcoin_hashes::Hash for bitcoin_hashes::hmac::Hmac<T>
impl<T: bitcoin_hashes::GeneralHash> bitcoin_hashes::HashEngine for bitcoin_hashes::hmac::HmacEngine<T>
impl<T: bitcoin_hashes::GeneralHash> bitcoin_hashes::hkdf::Hkdf<T> where <T as bitcoin_hashes::GeneralHash>::Engine: core::default::Default
impl<T: bitcoin_hashes::GeneralHash> bitcoin_hashes::hmac::Hmac<T>
impl<T: bitcoin_hashes::GeneralHash> bitcoin_hashes::hmac::HmacEngine<T>
impl<T: bitcoin_hashes::GeneralHash> core::convert::AsRef<[u8]> for bitcoin_hashes::hmac::Hmac<T>
impl<T: bitcoin_hashes::GeneralHash> core::default::Default for bitcoin_hashes::hmac::HmacEngine<T> where <T as bitcoin_hashes::GeneralHash>::Engine: core::default::Default
impl<T: bitcoin_hashes::GeneralHash> core::marker::StructuralPartialEq for bitcoin_hashes::hmac::Hmac<T>
impl<T: bitcoin_hashes::sha256t::Tag> bitcoin_hashes::GeneralHash for bitcoin_hashes::sha256t::Hash<T>
impl<T: bitcoin_hashes::sha256t::Tag> bitcoin_hashes::Hash for bitcoin_hashes::sha256t::Hash<T>
@ -597,6 +597,7 @@ pub fn bitcoin_hashes::hmac::Hmac<T>::as_byte_array(&self) -> &Self::Bytes
pub fn bitcoin_hashes::hmac::Hmac<T>::as_ref(&self) -> &[u8]
pub fn bitcoin_hashes::hmac::Hmac<T>::clone(&self) -> bitcoin_hashes::hmac::Hmac<T>
pub fn bitcoin_hashes::hmac::Hmac<T>::cmp(&self, other: &bitcoin_hashes::hmac::Hmac<T>) -> core::cmp::Ordering
pub fn bitcoin_hashes::hmac::Hmac<T>::engine(key: &[u8]) -> bitcoin_hashes::hmac::HmacEngine<T> where <T as bitcoin_hashes::GeneralHash>::Engine: core::default::Default
pub fn bitcoin_hashes::hmac::Hmac<T>::eq(&self, other: &bitcoin_hashes::hmac::Hmac<T>) -> bool
pub fn bitcoin_hashes::hmac::Hmac<T>::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result
pub fn bitcoin_hashes::hmac::Hmac<T>::from_byte_array(bytes: <T as bitcoin_hashes::Hash>::Bytes) -> Self
@ -607,7 +608,6 @@ pub fn bitcoin_hashes::hmac::Hmac<T>::hash<__H: core::hash::Hasher>(&self, state
pub fn bitcoin_hashes::hmac::Hmac<T>::partial_cmp(&self, other: &bitcoin_hashes::hmac::Hmac<T>) -> core::option::Option<core::cmp::Ordering>
pub fn bitcoin_hashes::hmac::Hmac<T>::to_byte_array(self) -> Self::Bytes
pub fn bitcoin_hashes::hmac::HmacEngine<T>::clone(&self) -> bitcoin_hashes::hmac::HmacEngine<T>
pub fn bitcoin_hashes::hmac::HmacEngine<T>::default() -> Self
pub fn bitcoin_hashes::hmac::HmacEngine<T>::from_inner_engines(iengine: <T as bitcoin_hashes::GeneralHash>::Engine, oengine: <T as bitcoin_hashes::GeneralHash>::Engine) -> bitcoin_hashes::hmac::HmacEngine<T>
pub fn bitcoin_hashes::hmac::HmacEngine<T>::input(&mut self, buf: &[u8])
pub fn bitcoin_hashes::hmac::HmacEngine<T>::n_bytes_hashed(&self) -> u64

View File

@ -380,9 +380,9 @@ impl<T: bitcoin_hashes::GeneralHash> bitcoin_hashes::GeneralHash for bitcoin_has
impl<T: bitcoin_hashes::GeneralHash> bitcoin_hashes::Hash for bitcoin_hashes::hmac::Hmac<T>
impl<T: bitcoin_hashes::GeneralHash> bitcoin_hashes::HashEngine for bitcoin_hashes::hmac::HmacEngine<T>
impl<T: bitcoin_hashes::GeneralHash> bitcoin_hashes::hkdf::Hkdf<T> where <T as bitcoin_hashes::GeneralHash>::Engine: core::default::Default
impl<T: bitcoin_hashes::GeneralHash> bitcoin_hashes::hmac::Hmac<T>
impl<T: bitcoin_hashes::GeneralHash> bitcoin_hashes::hmac::HmacEngine<T>
impl<T: bitcoin_hashes::GeneralHash> core::convert::AsRef<[u8]> for bitcoin_hashes::hmac::Hmac<T>
impl<T: bitcoin_hashes::GeneralHash> core::default::Default for bitcoin_hashes::hmac::HmacEngine<T> where <T as bitcoin_hashes::GeneralHash>::Engine: core::default::Default
impl<T: bitcoin_hashes::GeneralHash> core::marker::StructuralPartialEq for bitcoin_hashes::hmac::Hmac<T>
impl<T: bitcoin_hashes::sha256t::Tag> bitcoin_hashes::GeneralHash for bitcoin_hashes::sha256t::Hash<T>
impl<T: bitcoin_hashes::sha256t::Tag> bitcoin_hashes::Hash for bitcoin_hashes::sha256t::Hash<T>
@ -554,6 +554,7 @@ pub fn bitcoin_hashes::hmac::Hmac<T>::as_byte_array(&self) -> &Self::Bytes
pub fn bitcoin_hashes::hmac::Hmac<T>::as_ref(&self) -> &[u8]
pub fn bitcoin_hashes::hmac::Hmac<T>::clone(&self) -> bitcoin_hashes::hmac::Hmac<T>
pub fn bitcoin_hashes::hmac::Hmac<T>::cmp(&self, other: &bitcoin_hashes::hmac::Hmac<T>) -> core::cmp::Ordering
pub fn bitcoin_hashes::hmac::Hmac<T>::engine(key: &[u8]) -> bitcoin_hashes::hmac::HmacEngine<T> where <T as bitcoin_hashes::GeneralHash>::Engine: core::default::Default
pub fn bitcoin_hashes::hmac::Hmac<T>::eq(&self, other: &bitcoin_hashes::hmac::Hmac<T>) -> bool
pub fn bitcoin_hashes::hmac::Hmac<T>::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result
pub fn bitcoin_hashes::hmac::Hmac<T>::from_byte_array(bytes: <T as bitcoin_hashes::Hash>::Bytes) -> Self
@ -564,7 +565,6 @@ pub fn bitcoin_hashes::hmac::Hmac<T>::hash<__H: core::hash::Hasher>(&self, state
pub fn bitcoin_hashes::hmac::Hmac<T>::partial_cmp(&self, other: &bitcoin_hashes::hmac::Hmac<T>) -> core::option::Option<core::cmp::Ordering>
pub fn bitcoin_hashes::hmac::Hmac<T>::to_byte_array(self) -> Self::Bytes
pub fn bitcoin_hashes::hmac::HmacEngine<T>::clone(&self) -> bitcoin_hashes::hmac::HmacEngine<T>
pub fn bitcoin_hashes::hmac::HmacEngine<T>::default() -> Self
pub fn bitcoin_hashes::hmac::HmacEngine<T>::from_inner_engines(iengine: <T as bitcoin_hashes::GeneralHash>::Engine, oengine: <T as bitcoin_hashes::GeneralHash>::Engine) -> bitcoin_hashes::hmac::HmacEngine<T>
pub fn bitcoin_hashes::hmac::HmacEngine<T>::input(&mut self, buf: &[u8])
pub fn bitcoin_hashes::hmac::HmacEngine<T>::n_bytes_hashed(&self) -> u64

View File

@ -19,6 +19,16 @@ use crate::{FromSliceError, GeneralHash, Hash, HashEngine};
#[repr(transparent)]
pub struct Hmac<T: GeneralHash>(T);
impl<T: GeneralHash> 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;
fn from_str(s: &str) -> Result<Self, Self::Err> { Ok(Hmac(str::FromStr::from_str(s)?)) }
@ -31,15 +41,8 @@ pub struct HmacEngine<T: GeneralHash> {
oengine: T::Engine,
}
impl<T: GeneralHash> Default for HmacEngine<T>
where
<T as GeneralHash>::Engine: Default,
{
fn default() -> Self { HmacEngine::new(&[]) }
}
impl<T: GeneralHash> HmacEngine<T> {
/// Constructs a new keyed HMAC from `key`.
/// Constructs a new keyed HMAC engine from `key`.
///
/// We only support underlying hashes whose block sizes are ≤ 128 bytes.
///
@ -328,7 +331,7 @@ mod benches {
#[bench]
pub fn hmac_sha256_10(bh: &mut Bencher) {
let mut engine = Hmac::<sha256::Hash>::engine();
let mut engine = Hmac::<sha256::Hash>::engine(&[]);
let bytes = [1u8; 10];
bh.iter(|| {
engine.input(&bytes);
@ -338,7 +341,7 @@ mod benches {
#[bench]
pub fn hmac_sha256_1k(bh: &mut Bencher) {
let mut engine = Hmac::<sha256::Hash>::engine();
let mut engine = Hmac::<sha256::Hash>::engine(&[]);
let bytes = [1u8; 1024];
bh.iter(|| {
engine.input(&bytes);
@ -348,7 +351,7 @@ mod benches {
#[bench]
pub fn hmac_sha256_64k(bh: &mut Bencher) {
let mut engine = Hmac::<sha256::Hash>::engine();
let mut engine = Hmac::<sha256::Hash>::engine(&[]);
let bytes = [1u8; 65536];
bh.iter(|| {
engine.input(&bytes);

View File

@ -56,22 +56,6 @@ fn regression_sha256t() {
assert_eq!(got, want);
}
#[test]
fn regression_hmac_sha256_with_default_key() {
let hash = Hmac::<sha256::Hash>::hash(DATA.as_bytes());
let got = format!("{}", hash);
let want = "58cc7ed8567bd86eba61f7ed2d5a4edab1774dc10488e57de2eb007a2d9ae82d";
assert_eq!(got, want);
}
#[test]
fn regression_hmac_sha512_with_default_key() {
let hash = Hmac::<sha512::Hash>::hash(DATA.as_bytes());
let got = format!("{}", hash);
let want = "5f5db2f3e1178bf19af5db38a0ed04dc5bc52d641648542886eea9b6bbec0db658ed7a5799ca18f5bc1949f39d24151a32990ee85974e40bb8a35e2288f494ce";
assert_eq!(got, want);
}
#[test]
fn regression_hmac_sha256_with_key() {
let mut engine = HmacEngine::<sha256::Hash>::new(HMAC_KEY);