Merge rust-bitcoin/rust-bitcoin#2715: psbt: Use macro to hash instead of relying on `Hash` trait

9e4b092fce psbt: Use macro instead of function (Tobin C. Harding)

Pull request description:

  We have a private function that makes use of the `Hash` trait to generically hash map entries. This usage makes patching the `hashes` module difficult. We can achieve the same thing by using a macro and passing in the concrete type.

  This is an internal change, no effect on logic or public API.

ACKs for top commit:
  apoelstra:
    ACK 9e4b092fce

Tree-SHA512: 8b788fa91d21bbae556c746c2e55e6e9395e022bedf13193555ef7482109b6ef5032b233c5f37543a31ebda49d9b4761c161ca0db501472047eb661a48e944b7
This commit is contained in:
Andrew Poelstra 2024-05-28 16:26:14 +00:00
commit 3c7ac53e89
No known key found for this signature in database
GPG Key ID: C588D63CE41B97C1
2 changed files with 36 additions and 54 deletions

View File

@ -111,6 +111,30 @@ macro_rules! impl_psbt_insert_pair {
};
}
#[rustfmt::skip]
macro_rules! psbt_insert_hash_pair {
(&mut $slf:ident.$map:ident <= $raw_key:ident|$raw_value:ident|$hash:path|$hash_type_error:path) => {
if $raw_key.key.is_empty() {
return Err(psbt::Error::InvalidKey($raw_key));
}
let key_val: $hash = Deserialize::deserialize(&$raw_key.key)?;
match $slf.$map.entry(key_val) {
btree_map::Entry::Vacant(empty_key) => {
let val: Vec<u8> = Deserialize::deserialize(&$raw_value)?;
if <$hash as hashes::Hash>::hash(&val) != key_val {
return Err(psbt::Error::InvalidPreimageHashPair {
preimage: val.into_boxed_slice(),
hash: Box::from(key_val.borrow()),
hash_type: $hash_type_error,
});
}
empty_key.insert(val);
}
btree_map::Entry::Occupied(_) => return Err(psbt::Error::DuplicateKey($raw_key)),
}
}
}
#[rustfmt::skip]
macro_rules! impl_psbt_get_pair {
($rv:ident.push($slf:ident.$unkeyed_name:ident, $unkeyed_typeval:ident)) => {

View File

@ -300,36 +300,24 @@ impl Input {
}
}
PSBT_IN_RIPEMD160 => {
psbt_insert_hash_pair(
&mut self.ripemd160_preimages,
raw_key,
raw_value,
error::PsbtHash::Ripemd,
)?;
psbt_insert_hash_pair! {
&mut self.ripemd160_preimages <= raw_key|raw_value|ripemd160::Hash|error::PsbtHash::Ripemd
}
}
PSBT_IN_SHA256 => {
psbt_insert_hash_pair(
&mut self.sha256_preimages,
raw_key,
raw_value,
error::PsbtHash::Sha256,
)?;
psbt_insert_hash_pair! {
&mut self.sha256_preimages <= raw_key|raw_value|sha256::Hash|error::PsbtHash::Sha256
}
}
PSBT_IN_HASH160 => {
psbt_insert_hash_pair(
&mut self.hash160_preimages,
raw_key,
raw_value,
error::PsbtHash::Hash160,
)?;
psbt_insert_hash_pair! {
&mut self.hash160_preimages <= raw_key|raw_value|hash160::Hash|error::PsbtHash::Hash160
}
}
PSBT_IN_HASH256 => {
psbt_insert_hash_pair(
&mut self.hash256_preimages,
raw_key,
raw_value,
error::PsbtHash::Hash256,
)?;
psbt_insert_hash_pair! {
&mut self.hash256_preimages <= raw_key|raw_value|sha256d::Hash|error::PsbtHash::Hash256
}
}
PSBT_IN_TAP_KEY_SIG => {
impl_psbt_insert_pair! {
@ -505,36 +493,6 @@ impl Map for Input {
impl_psbtmap_ser_de_serialize!(Input);
fn psbt_insert_hash_pair<H>(
map: &mut BTreeMap<H, Vec<u8>>,
raw_key: raw::Key,
raw_value: Vec<u8>,
hash_type: error::PsbtHash,
) -> Result<(), Error>
where
H: hashes::Hash + Deserialize,
{
if raw_key.key.is_empty() {
return Err(psbt::Error::InvalidKey(raw_key));
}
let key_val: H = Deserialize::deserialize(&raw_key.key)?;
match map.entry(key_val) {
btree_map::Entry::Vacant(empty_key) => {
let val: Vec<u8> = Deserialize::deserialize(&raw_value)?;
if <H as hashes::Hash>::hash(&val) != key_val {
return Err(psbt::Error::InvalidPreimageHashPair {
preimage: val.into_boxed_slice(),
hash: Box::from(key_val.as_ref()),
hash_type,
});
}
empty_key.insert(val);
Ok(())
}
btree_map::Entry::Occupied(_) => Err(psbt::Error::DuplicateKey(raw_key)),
}
}
#[cfg(test)]
mod test {
use super::*;