Implement TryFrom sha256::Hash for TaprootMerkleBranch

TryFrom` became available in Rust 1.34 so we can use it now we have
bumped our MSRV.

Add a macro for implementing `TryFrom` for various lists of
`sha256::Hash` types. Use the macro to for vec, slice, and boxed slice.
This commit is contained in:
Tobin C. Harding 2022-05-25 17:16:54 +10:00
parent 6b7b440cff
commit af16286679
2 changed files with 36 additions and 7 deletions

View File

@ -1113,7 +1113,7 @@ mod tests {
} else { } else {
Some(hex_hash!(TapBranchHash, inp["given"]["merkleRoot"].as_str().unwrap())) Some(hex_hash!(TapBranchHash, inp["given"]["merkleRoot"].as_str().unwrap()))
}; };
let hash_ty = SchnorrSighashType::from_u8(inp["given"]["hashType"].as_u64().unwrap() as u8).unwrap(); let hash_ty = SchnorrSighashType::try_from(inp["given"]["hashType"].as_u64().unwrap() as u8).unwrap();
let expected_internal_pk = hex_hash!(XOnlyPublicKey, inp["intermediary"]["internalPubkey"].as_str().unwrap()); let expected_internal_pk = hex_hash!(XOnlyPublicKey, inp["intermediary"]["internalPubkey"].as_str().unwrap());
let expected_tweak = hex_hash!(TapTweakHash, inp["intermediary"]["tweak"].as_str().unwrap()); let expected_tweak = hex_hash!(TapTweakHash, inp["intermediary"]["tweak"].as_str().unwrap());
@ -1124,7 +1124,7 @@ mod tests {
let (expected_key_spend_sig, expected_hash_ty) = if sig_str.len() == 128 { let (expected_key_spend_sig, expected_hash_ty) = if sig_str.len() == 128 {
(secp256k1::schnorr::Signature::from_str(sig_str).unwrap(), SchnorrSighashType::Default) (secp256k1::schnorr::Signature::from_str(sig_str).unwrap(), SchnorrSighashType::Default)
} else { } else {
let hash_ty = SchnorrSighashType::from_u8(Vec::<u8>::from_hex(&sig_str[128..]).unwrap()[0]).unwrap(); let hash_ty = SchnorrSighashType::try_from(Vec::<u8>::from_hex(&sig_str[128..]).unwrap()[0]).unwrap();
(secp256k1::schnorr::Signature::from_str(&sig_str[..128]).unwrap(), hash_ty) (secp256k1::schnorr::Signature::from_str(&sig_str[..128]).unwrap(), hash_ty)
}; };

View File

@ -20,6 +20,7 @@ use crate::prelude::*;
use crate::io; use crate::io;
use secp256k1::{self, Secp256k1}; use secp256k1::{self, Secp256k1};
use core::convert::TryFrom;
use core::fmt; use core::fmt;
use core::cmp::Reverse; use core::cmp::Reverse;
@ -672,6 +673,18 @@ impl TaprootMerkleBranch {
} }
} }
/// Creates a merkle proof from list of hashes.
///
/// # Errors
/// If inner proof length is more than [`TAPROOT_CONTROL_MAX_NODE_COUNT`] (128).
fn from_collection<T: AsRef<[sha256::Hash]> + Into<Vec<sha256::Hash>>>(collection: T) -> Result<Self, TaprootError> {
if collection.as_ref().len() > TAPROOT_CONTROL_MAX_NODE_COUNT {
Err(TaprootError::InvalidMerkleTreeDepth(collection.as_ref().len()))
} else {
Ok(TaprootMerkleBranch(collection.into()))
}
}
/// Serializes to a writer. /// Serializes to a writer.
/// ///
/// # Returns /// # Returns
@ -704,12 +717,9 @@ impl TaprootMerkleBranch {
/// # Errors /// # Errors
/// ///
/// If inner proof length is more than [`TAPROOT_CONTROL_MAX_NODE_COUNT`] (128). /// If inner proof length is more than [`TAPROOT_CONTROL_MAX_NODE_COUNT`] (128).
#[deprecated(since = "0.29.0", note = "use try_from instead")]
pub fn from_inner(inner: Vec<sha256::Hash>) -> Result<Self, TaprootError> { pub fn from_inner(inner: Vec<sha256::Hash>) -> Result<Self, TaprootError> {
if inner.len() > TAPROOT_CONTROL_MAX_NODE_COUNT { Self::try_from(inner)
Err(TaprootError::InvalidMerkleTreeDepth(inner.len()))
} else {
Ok(TaprootMerkleBranch(inner))
}
} }
/// Returns the inner list of hashes. /// Returns the inner list of hashes.
@ -718,6 +728,25 @@ impl TaprootMerkleBranch {
} }
} }
macro_rules! impl_try_from {
($from:ty) => {
impl TryFrom<$from> for TaprootMerkleBranch {
type Error = TaprootError;
/// Creates a merkle proof from list of hashes.
///
/// # Errors
/// If inner proof length is more than [`TAPROOT_CONTROL_MAX_NODE_COUNT`] (128).
fn try_from(v: $from) -> Result<Self, Self::Error> {
TaprootMerkleBranch::from_collection(v)
}
}
}
}
impl_try_from!(&[sha256::Hash]);
impl_try_from!(Vec<sha256::Hash>);
impl_try_from!(Box<[sha256::Hash]>);
/// Control block data structure used in Tapscript satisfaction. /// Control block data structure used in Tapscript satisfaction.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]