pczt: Add fields necessary for signing transparent spends

These follow the equivalent fields in BIP 174 and BIP 370.
This commit is contained in:
Jack Grigg 2024-11-08 08:36:51 +00:00
parent 6ca554898b
commit 694649863a
2 changed files with 98 additions and 2 deletions

View File

@ -1,3 +1,5 @@
use std::collections::BTreeMap;
use crate::Pczt;
pub struct Combiner {
@ -54,6 +56,29 @@ pub(crate) fn merge_optional<T: PartialEq>(lhs: &mut Option<T>, rhs: Option<T>)
true
}
/// Merges two maps together.
///
/// Returns `false` if the values cannot be merged.
pub(crate) fn merge_map<K: Ord, V: PartialEq>(
lhs: &mut BTreeMap<K, V>,
rhs: BTreeMap<K, V>,
) -> bool {
for (key, rhs_value) in rhs.into_iter() {
if let Some(lhs_value) = lhs.get_mut(&key) {
// If the key is present in both maps, and their values are not equal, fail.
// Here we differ from BIP 174.
if lhs_value != &rhs_value {
return false;
}
} else {
lhs.insert(key, rhs_value);
}
}
// Success!
true
}
/// Errors that can occur while combining PCZTs.
#[derive(Debug)]
pub enum Error {

View File

@ -1,4 +1,6 @@
use crate::roles::combiner::merge_optional;
use std::collections::BTreeMap;
use crate::roles::combiner::{merge_map, merge_optional};
#[cfg(feature = "transparent")]
use {
@ -58,6 +60,51 @@ pub(crate) struct Input {
// needed for computing the binding signatures.
pub(crate) value: u64,
pub(crate) script_pubkey: Vec<u8>,
/// The script required to spend this output, if it is P2SH.
///
/// Set to `None` if this is a P2PKH output.
pub(crate) redeem_script: Option<Vec<u8>>,
/// A map from a pubkey to a signature created by it.
///
/// - Each pubkey should appear in `script_pubkey` or `redeem_script`.
/// - Each entry is set by a Signer, and should contain an ECDSA signature that is
/// valid under the corresponding pubkey.
/// - These are required by the Spend Finalizer to assemble `script_sig`.
pub(crate) partial_signatures: BTreeMap<[u8; 33], Vec<u8>>,
/// The sighash type to be used for this input.
///
/// - Signers must use this sighash type to produce their signatures. Signers that
/// cannot produce signatures for this sighash type must not provide a signature.
/// - Spend Finalizers must fail to finalize inputs which have signatures not matching
/// this sighash type.
pub(crate) sighash_type: u8,
/// Mappings of the form `key = RIPEMD160(value)`.
///
/// - These may be used by the Signer to inspect parts of `script_pubkey` or
/// `redeem_script`.
pub(crate) ripemd160_preimages: BTreeMap<[u8; 20], Vec<u8>>,
/// Mappings of the form `key = SHA256(value)`.
///
/// - These may be used by the Signer to inspect parts of `script_pubkey` or
/// `redeem_script`.
pub(crate) sha256_preimages: BTreeMap<[u8; 32], Vec<u8>>,
/// Mappings of the form `key = RIPEMD160(SHA256(value))`.
///
/// - These may be used by the Signer to inspect parts of `script_pubkey` or
/// `redeem_script`.
pub(crate) hash160_preimages: BTreeMap<[u8; 20], Vec<u8>>,
/// Mappings of the form `key = SHA256(SHA256(value))`.
///
/// - These may be used by the Signer to inspect parts of `script_pubkey` or
/// `redeem_script`.
pub(crate) hash256_preimages: BTreeMap<[u8; 32], Vec<u8>>,
}
#[derive(Clone, Debug)]
@ -70,6 +117,11 @@ pub(crate) struct Output {
//
pub(crate) value: u64,
pub(crate) script_pubkey: Vec<u8>,
/// The script required to spend this output, if it is P2SH.
///
/// Set to `None` if this is a P2PKH output.
pub(crate) redeem_script: Option<Vec<u8>>,
}
impl Bundle {
@ -101,12 +153,20 @@ impl Bundle {
script_sig,
value,
script_pubkey,
redeem_script,
partial_signatures,
sighash_type,
ripemd160_preimages,
sha256_preimages,
hash160_preimages,
hash256_preimages,
} = rhs;
if lhs.prevout_txid != prevout_txid
|| lhs.prevout_index != prevout_index
|| lhs.value != value
|| lhs.script_pubkey != script_pubkey
|| lhs.sighash_type != sighash_type
{
return None;
}
@ -117,7 +177,13 @@ impl Bundle {
&mut lhs.required_height_lock_time,
required_height_lock_time,
)
&& merge_optional(&mut lhs.script_sig, script_sig))
&& merge_optional(&mut lhs.script_sig, script_sig)
&& merge_optional(&mut lhs.redeem_script, redeem_script)
&& merge_map(&mut lhs.partial_signatures, partial_signatures)
&& merge_map(&mut lhs.ripemd160_preimages, ripemd160_preimages)
&& merge_map(&mut lhs.sha256_preimages, sha256_preimages)
&& merge_map(&mut lhs.hash160_preimages, hash160_preimages)
&& merge_map(&mut lhs.hash256_preimages, hash256_preimages))
{
return None;
}
@ -128,11 +194,16 @@ impl Bundle {
let Output {
value,
script_pubkey,
redeem_script,
} = rhs;
if lhs.value != value || lhs.script_pubkey != script_pubkey {
return None;
}
if !merge_optional(&mut lhs.redeem_script, redeem_script) {
return None;
}
}
Some(self)