From 425fcee727a974a64e2c8db9ad96fe4625c3fc41 Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Mon, 13 Nov 2023 17:35:42 +0100 Subject: [PATCH] fixup! SFT-UNKN: Add foundation-psbt crate. --- psbt/src/parser/global.rs | 73 +++++----- psbt/src/parser/hash.rs | 82 ++++++++---- psbt/src/parser/input.rs | 234 +++++++++++++++++++-------------- psbt/src/parser/keypair.rs | 8 +- psbt/src/parser/mod.rs | 12 +- psbt/src/parser/output.rs | 7 +- psbt/src/parser/secp.rs | 19 +-- psbt/src/parser/transaction.rs | 15 ++- psbt/src/transaction.rs | 8 +- 9 files changed, 264 insertions(+), 194 deletions(-) diff --git a/psbt/src/parser/global.rs b/psbt/src/parser/global.rs index a29b476..a5b72ba 100644 --- a/psbt/src/parser/global.rs +++ b/psbt/src/parser/global.rs @@ -23,31 +23,34 @@ use crate::parser::keypair::key_pair; use crate::parser::transaction::transaction; use crate::transaction::Transaction; -#[rustfmt::skip] -pub fn global_map<'a, F, Error>(mut xpub_event: F) -> impl FnMut(&'a [u8]) -> IResult<&'a [u8], GlobalMap<'a>, Error> +pub fn global_map<'a, F, Error>( + mut xpub_event: F, +) -> impl FnMut(&'a [u8]) -> IResult<&'a [u8], GlobalMap<'a>, Error> where F: FnMut(ExtendedPublicKey, KeySource<&'a [u8]>), - Error: ContextError<&'a [u8]>, - Error: ParseError<&'a [u8]>, - Error: FromExternalError<&'a [u8], secp256k1::Error>, + Error: ContextError<&'a [u8]> + + ParseError<&'a [u8]> + + FromExternalError<&'a [u8], secp256k1::Error> + + FromExternalError<&'a [u8], bitcoin_hashes::FromSliceError>, { let keypairs = fold_many0( global_key_pair(), GlobalMap::default, move |mut map, key_pair| { match key_pair { - KeyPair::UnsignedTx(v) => map.transaction = Some(v), + KeyPair::UnsignedTx(v) => map.transaction = Some(v), KeyPair::Xpub { key, source } => xpub_event(key, source), - KeyPair::TxVersion(v) => map.transaction_version = Some(v), - KeyPair::FallbackLocktime(v) => map.fallback_locktime = Some(v), - KeyPair::InputCount(v) => map.input_count = Some(v), - KeyPair::OutputCount(v) => map.output_count = Some(v), - KeyPair::TxModifiable(v) => map.tx_modifiable = Some(v), - KeyPair::Version(v) => map.version = v, + KeyPair::TxVersion(v) => map.transaction_version = Some(v), + KeyPair::FallbackLocktime(v) => map.fallback_locktime = Some(v), + KeyPair::InputCount(v) => map.input_count = Some(v), + KeyPair::OutputCount(v) => map.output_count = Some(v), + KeyPair::TxModifiable(v) => map.tx_modifiable = Some(v), + KeyPair::Version(v) => map.version = v, }; map - }); + }, + ); verify( terminated(keypairs, context("separator", tag(b"\x00"))), @@ -62,39 +65,43 @@ where 1 => true, // Make sure that these fields exist and make sure that version 0 fields // are excluded. - 2 => map.transaction.is_none() && map.input_count.is_some() && map.output_count.is_some(), + 2 => { + map.transaction.is_none() + && map.input_count.is_some() + && map.output_count.is_some() + } // Don't verify what we don't know. _ => true, } - } + }, ) } -#[rustfmt::skip] fn global_key_pair<'a, Error>() -> impl FnMut(&'a [u8]) -> IResult<&'a [u8], KeyPair, Error> where - Error: ParseError<&'a [u8]>, - Error: FromExternalError<&'a [u8], secp256k1::Error>, + Error: ParseError<&'a [u8]> + + FromExternalError<&'a [u8], secp256k1::Error> + + FromExternalError<&'a [u8], bitcoin_hashes::FromSliceError>, { - let unsigned_tx = key_pair(0x00, eof, transaction()); - let xpub = key_pair(0x01, extended_public_key, key_source); - let xpub = verify(xpub, |(k, v)| usize::from(k.depth) == v.path.len()); - let tx_version = key_pair(0x02, eof, le_u32); + let unsigned_tx = key_pair(0x00, eof, transaction()); + let xpub = key_pair(0x01, extended_public_key, key_source); + let xpub = verify(xpub, |(k, v)| usize::from(k.depth) == v.path.len()); + let tx_version = key_pair(0x02, eof, le_u32); let fallback_locktime = key_pair(0x03, eof, le_u32); - let input_count = key_pair(0x04, eof, compact_size); - let output_count = key_pair(0x05, eof, compact_size); - let tx_modifiable = key_pair(0x06, eof, tx_modifiable); - let version = key_pair(0xFB, eof, le_u32); + let input_count = key_pair(0x04, eof, compact_size); + let output_count = key_pair(0x05, eof, compact_size); + let tx_modifiable = key_pair(0x06, eof, tx_modifiable); + let version = key_pair(0xFB, eof, le_u32); alt(( - map(unsigned_tx, |(_, v)| KeyPair::UnsignedTx(v)), - map(xpub, |(k, v)| KeyPair::Xpub { key: k, source: v }), - map(tx_version, |(_, v)| KeyPair::TxVersion(v)), + map(unsigned_tx, |(_, v)| KeyPair::UnsignedTx(v)), + map(xpub, |(k, v)| KeyPair::Xpub { key: k, source: v }), + map(tx_version, |(_, v)| KeyPair::TxVersion(v)), map(fallback_locktime, |(_, v)| KeyPair::FallbackLocktime(v)), - map(input_count, |(_, v)| KeyPair::InputCount(v)), - map(output_count, |(_, v)| KeyPair::OutputCount(v)), - map(tx_modifiable, |(_, v)| KeyPair::TxModifiable(v)), - map(version, |(_, v)| KeyPair::Version(v)), + map(input_count, |(_, v)| KeyPair::InputCount(v)), + map(output_count, |(_, v)| KeyPair::OutputCount(v)), + map(tx_modifiable, |(_, v)| KeyPair::TxModifiable(v)), + map(version, |(_, v)| KeyPair::Version(v)), )) } diff --git a/psbt/src/parser/hash.rs b/psbt/src/parser/hash.rs index 56b8db2..51e79c3 100644 --- a/psbt/src/parser/hash.rs +++ b/psbt/src/parser/hash.rs @@ -1,19 +1,44 @@ -use crate::{hash_types, taproot}; +// SPDX-FileCopyrightText: © 2023 Foundation Devices, Inc. +// SPDX-License-Identifier: GPL-3.0-or-later + use nom::{ - bytes::complete::take, - combinator::map_res, - error::{FromExternalError, ParseError}, - IResult, + error::ParseError, multi::fill, number::complete::u8, IResult, InputIter, InputLength, Slice, }; +use bitcoin_hashes::Hash; + +use crate::{hash_types, taproot}; + /// Parses a [`bitcoin_hashes::Hash`]. -pub fn hash<'a, Hash, Error>(i: &'a [u8]) -> IResult<&'a [u8], Hash, Error> +/// +/// # Why N instead of [`bitcoin_hashes::Hash::LEN`]. +/// +/// NOTE(jeandudey): Using `N` because on Rust 1.70.0 it somehow can't use the +/// associated constant `LEN` of `bitcoin_hashes::Hash`` trait and shows the +/// following error: +/// +/// ```text +/// error: generic parameters may not be used in const operations +/// +/// let mut buf = [0; Hash::LEN]; +/// ``` +/// +/// Maybe a bug, perhaps report this upstream, I think rustc is broken in +/// this edge case. +/// +/// Ideally one would use fill with the aforementioned `buf` variable to +/// avoid this verbose loop. +pub fn hash(i: Input) -> IResult where + Input: + Clone + PartialEq + InputLength + InputIter + Slice>, Hash: bitcoin_hashes::Hash, - Error: ParseError<&'a [u8]>, - Error: FromExternalError<&'a [u8], bitcoin_hashes::FromSliceError>, + Error: ParseError, { - map_res(take(Hash::LEN), Hash::from_slice)(i) + let mut buf = [0; N]; + let (next_i, ()) = fill(u8, &mut buf)(i)?; + let hash = Hash::from_slice(&buf).expect("should have the correct length"); + Ok((next_i, hash)) } /// Define an alias for a hash parser. @@ -25,14 +50,14 @@ where macro_rules! define_hash_aliases { ($($name:ident),* $(,)?) => { $( - pub fn $name<'a, Error>( - i: &'a [u8], - ) -> IResult<&'a [u8], ::bitcoin_hashes::$name::Hash, Error> + pub fn $name( + i: Input, + ) -> IResult where - Error: ParseError<&'a [u8]>, - Error: FromExternalError<&'a [u8], bitcoin_hashes::FromSliceError>, + Input: Clone + PartialEq + InputLength + InputIter + Slice>, + Error: ParseError, { - hash::<'a, ::bitcoin_hashes::$name::Hash, Error>(i) + hash::<_, ::bitcoin_hashes::$name::Hash, Error, { ::bitcoin_hashes::$name::Hash::LEN }>(i) } )* }; @@ -45,26 +70,29 @@ define_hash_aliases! { hash160, } -pub fn taproot_leaf_hash<'a, Error>(i: &'a [u8]) -> IResult<&'a [u8], taproot::LeafHash, Error> +pub fn taproot_leaf_hash(i: Input) -> IResult where - Error: ParseError<&'a [u8]>, - Error: FromExternalError<&'a [u8], bitcoin_hashes::FromSliceError>, + Input: + Clone + PartialEq + InputLength + InputIter + Slice>, + Error: ParseError, { - hash::<'a, taproot::LeafHash, Error>(i) + hash::<_, taproot::LeafHash, Error, { taproot::LeafHash::LEN }>(i) } -pub fn taproot_node_hash<'a, Error>(i: &'a [u8]) -> IResult<&'a [u8], taproot::TapNodeHash, Error> +pub fn taproot_node_hash(i: Input) -> IResult where - Error: ParseError<&'a [u8]>, - Error: FromExternalError<&'a [u8], bitcoin_hashes::FromSliceError>, + Input: + Clone + PartialEq + InputLength + InputIter + Slice>, + Error: ParseError, { - hash::<'a, taproot::TapNodeHash, Error>(i) + hash::<_, taproot::TapNodeHash, Error, { taproot::TapNodeHash::LEN }>(i) } -pub fn txid<'a, Error>(i: &'a [u8]) -> IResult<&'a [u8], hash_types::Txid, Error> +pub fn txid(i: Input) -> IResult where - Error: ParseError<&'a [u8]>, - Error: FromExternalError<&'a [u8], bitcoin_hashes::FromSliceError>, + Input: + Clone + PartialEq + InputLength + InputIter + Slice>, + Error: ParseError, { - hash::<'a, hash_types::Txid, Error>(i) + hash::<_, hash_types::Txid, Error, { hash_types::Txid::LEN }>(i) } diff --git a/psbt/src/parser/input.rs b/psbt/src/parser/input.rs index cfc95ea..96e772e 100644 --- a/psbt/src/parser/input.rs +++ b/psbt/src/parser/input.rs @@ -6,15 +6,18 @@ use bitcoin_hashes::{hash160, ripemd160, sha256, sha256d}; use nom::branch::alt; use nom::bytes::complete::tag; use nom::combinator::{eof, map, rest}; -use nom::error::{FromExternalError, ParseError}; -use nom::multi::{fold_many0, length_value}; +use nom::error::{ErrorKind, FromExternalError, ParseError}; +use nom::multi::length_value; use nom::number::complete::le_u32; -use nom::sequence::{terminated, tuple}; -use nom::IResult; +use nom::sequence::tuple; +use nom::{Err, IResult, InputLength}; use secp256k1::{schnorr, PublicKey, XOnlyPublicKey}; -use foundation_bip32::{parser::key_source, KeySource}; +use foundation_bip32::{ + parser::{key_source, public_key}, + KeySource, +}; use crate::hash_types::Txid; use crate::parser::compact_size::compact_size; @@ -22,119 +25,157 @@ use crate::parser::hash::{ hash160, ripemd160, sha256, sha256d, taproot_leaf_hash, taproot_node_hash, txid, }; use crate::parser::keypair::key_pair; -use crate::parser::secp::{ecdsa_signature, public_key, schnorr_signature, x_only_public_key}; +use crate::parser::secp::{ecdsa_signature, schnorr_signature, x_only_public_key}; use crate::parser::transaction::transaction; use crate::taproot::{TapNodeHash, TaprootScriptSignature}; use crate::transaction::Transaction; -#[rustfmt::skip] +/// Insert `value` into `option` if it's not set already, if already set +/// return an error. +fn insert(option: &mut Option, value: T, input: I) -> Result<(), Err> +where + E: ParseError, +{ + match option { + Some(_) => Err(Err::Failure(E::from_error_kind(input, ErrorKind::Fail))), + None => { + *option = Some(value); + Ok(()) + } + } +} + pub fn input_map<'a, Error>(i: &'a [u8]) -> IResult<&'a [u8], InputMap<'a>, Error> where Error: ParseError<&'a [u8]>, Error: FromExternalError<&'a [u8], secp256k1::Error>, - Error: FromExternalError<&'a [u8], bitcoin_hashes::FromSliceError>, { - let keypairs = fold_many0( - input_key_pair, - InputMap::default, - |mut map, key_pair| { - match key_pair { - KeyPair::NonWitnessUtxo(v) => map.non_witness_utxo = Some(v), - KeyPair::WitnessUtxo(v) => map.witness_utxo = Some(v), - KeyPair::PartialSig(_) => (), // TODO - KeyPair::SighashType(v) => map.sighash_type = Some(v), - KeyPair::RedeemScript(v) => map.redeem_script = Some(v), - KeyPair::WitnessScript(v) => map.witness_script = Some(v), - KeyPair::Bip32Derivation(_, _) => (), // TODO - KeyPair::FinalScriptsig(v) => map.final_scriptsig = Some(v), - KeyPair::FinalScriptwitness(v) => map.final_scriptwitness = Some(v), - KeyPair::PorCommitment(v) => map.por_commitment = Some(v), - KeyPair::Ripemd160(_) => (), // TODO - KeyPair::Sha256(_) => (), // TODO - KeyPair::Hash160(_) => (), // TODO - KeyPair::Hash256(_) => (), // TODO - KeyPair::PreviousTxid(v) => map.previous_txid = Some(v), - KeyPair::OutputIndex(v) => map.output_index = Some(v), - KeyPair::Sequence(v) => map.sequence = Some(v), - KeyPair::RequiredTimeLocktime(v) => map.required_time_locktime = Some(v), - KeyPair::RequiredHeightLocktime(v) => map.required_height_locktime = Some(v), - KeyPair::TapKeySig(v) => map.tap_key_sig = Some(v), - KeyPair::TapScriptSig(_, _) => (), // TODO - KeyPair::TapLeafScript(_, _) => (), // TODO - KeyPair::TapBip32Derivation(_, _) => (), // TODO - KeyPair::TapInternalKey(v) => map.tap_internal_key = Some(v), - KeyPair::TapMerkleRoot(v) => map.tap_merkle_root = Some(v), - }; - - map - }, - ); - - terminated(keypairs, tag("\x00"))(i) + let mut map = InputMap::default(); + let mut input = i; + + loop { + let i_ = input.clone(); + let len = input.input_len(); + + let key_pair = match input_key_pair(i_) { + Ok((i, k)) => { + // infinite loop check: the parser must always consume. + if i.input_len() == len { + return Err(Err::Error(Error::from_error_kind(input, ErrorKind::Many0))); + } + + input = i; + k + } + Err(Err::Error(_)) => { + break; + } + Err(e) => { + return Err(e); + } + }; + + match key_pair { + KeyPair::NonWitnessUtxo(v) => insert(&mut map.non_witness_utxo, v, i_)?, + KeyPair::WitnessUtxo(v) => insert(&mut map.witness_utxo, v, i_)?, + KeyPair::PartialSig(_) => (), // TODO + KeyPair::SighashType(v) => insert(&mut map.sighash_type, v, i_)?, + KeyPair::RedeemScript(v) => insert(&mut map.redeem_script, v, i_)?, + KeyPair::WitnessScript(v) => insert(&mut map.witness_script, v, i_)?, + KeyPair::Bip32Derivation(_, _) => (), // TODO + KeyPair::FinalScriptsig(v) => insert(&mut map.final_scriptsig, v, i_)?, + KeyPair::FinalScriptwitness(v) => insert(&mut map.final_scriptwitness, v, i_)?, + KeyPair::PorCommitment(v) => insert(&mut map.por_commitment, v, i_)?, + KeyPair::Ripemd160(_) => (), // TODO + KeyPair::Sha256(_) => (), // TODO + KeyPair::Hash160(_) => (), // TODO + KeyPair::Hash256(_) => (), // TODO + KeyPair::PreviousTxid(v) => insert(&mut map.previous_txid, v, i_)?, + KeyPair::OutputIndex(v) => insert(&mut map.output_index, v, i_)?, + KeyPair::Sequence(v) => insert(&mut map.sequence, v, i_)?, + KeyPair::RequiredTimeLocktime(v) => insert(&mut map.required_time_locktime, v, i_)?, + KeyPair::RequiredHeightLocktime(v) => insert(&mut map.required_height_locktime, v, i_)?, + KeyPair::TapKeySig(v) => insert(&mut map.tap_key_sig, v, i_)?, + KeyPair::TapScriptSig(_, _) => (), // TODO + KeyPair::TapLeafScript(_, _) => (), // TODO + KeyPair::TapBip32Derivation(_, _) => (), // TODO + KeyPair::TapInternalKey(v) => insert(&mut map.tap_internal_key, v, i_)?, + KeyPair::TapMerkleRoot(v) => insert(&mut map.tap_merkle_root, v, i_)?, + }; + } + + // match the terminator. + let (input, _) = tag("\x00")(input)?; + + Ok((input, map)) } -#[rustfmt::skip] fn input_key_pair<'a, Error>(i: &'a [u8]) -> IResult<&'a [u8], KeyPair, Error> where Error: ParseError<&'a [u8]>, Error: FromExternalError<&'a [u8], secp256k1::Error>, - Error: FromExternalError<&'a [u8], bitcoin_hashes::FromSliceError>, { - let non_witness_utxo = key_pair(0x00, eof, transaction()); // TODO - let witness_utxo = key_pair(0x01, eof, witness_utxo); - let partial_sig = key_pair(0x02, public_key, ecdsa_signature); - let sighash_type = key_pair(0x03, eof, le_u32); - let redeem_script = key_pair(0x04, eof, rest); - let witness_script = key_pair(0x05, eof, rest); - let bip32_derivation = key_pair(0x06, public_key, key_source); - let final_scriptsig = key_pair(0x07, eof, rest); - let final_scriptwitness = key_pair(0x08, eof, rest); - let por_commitment = key_pair(0x09, eof, rest); - let ripemd160 = key_pair(0x0a, ripemd160, rest); - let sha256 = key_pair(0x0b, sha256, rest); - let hash160 = key_pair(0x0c, hash160, rest); - let hash256 = key_pair(0x0d, sha256d, rest); - let previous_txid = key_pair(0x0e, eof, txid); - let output_index = key_pair(0x0f, eof, le_u32); - let sequence = key_pair(0x10, eof, le_u32); - let required_time_locktime = key_pair(0x11, eof, le_u32); + let non_witness_utxo = key_pair(0x00, eof, transaction()); // TODO + let witness_utxo = key_pair(0x01, eof, witness_utxo); + let partial_sig = key_pair(0x02, public_key, ecdsa_signature); + let sighash_type = key_pair(0x03, eof, le_u32); + let redeem_script = key_pair(0x04, eof, rest); + let witness_script = key_pair(0x05, eof, rest); + let bip32_derivation = key_pair(0x06, public_key, key_source); + let final_scriptsig = key_pair(0x07, eof, rest); + let final_scriptwitness = key_pair(0x08, eof, rest); + let por_commitment = key_pair(0x09, eof, rest); + let ripemd160 = key_pair(0x0a, ripemd160, rest); + let sha256 = key_pair(0x0b, sha256, rest); + let hash160 = key_pair(0x0c, hash160, rest); + let hash256 = key_pair(0x0d, sha256d, rest); + let previous_txid = key_pair(0x0e, eof, txid); + let output_index = key_pair(0x0f, eof, le_u32); + let sequence = key_pair(0x10, eof, le_u32); + let required_time_locktime = key_pair(0x11, eof, le_u32); let required_height_locktime = key_pair(0x12, eof, le_u32); - let tap_key_sig = key_pair(0x13, eof, schnorr_signature); - let tap_script_sig = key_pair(0x14, tap_script_sig, schnorr_signature); - let tap_leaf_script = key_pair(0x15, rest, rest); // TODO - let tap_bip32_derivation = key_pair(0x16, x_only_public_key, rest); // TODO - let tap_internal_key = key_pair(0x17, eof, x_only_public_key); - let tap_merkle_root = key_pair(0x18, eof, taproot_node_hash); + let tap_key_sig = key_pair(0x13, eof, schnorr_signature); + let tap_script_sig = key_pair(0x14, tap_script_sig, schnorr_signature); + let tap_leaf_script = key_pair(0x15, rest, rest); // TODO + let tap_bip32_derivation = key_pair(0x16, x_only_public_key, rest); // TODO + let tap_internal_key = key_pair(0x17, eof, x_only_public_key); + let tap_merkle_root = key_pair(0x18, eof, taproot_node_hash); alt(( - map(non_witness_utxo, |(_, v)| KeyPair::NonWitnessUtxo(v)), - map(witness_utxo, |(_, v)| KeyPair::WitnessUtxo(v)), - map(partial_sig, |(k, _)| KeyPair::PartialSig(k)), - map(sighash_type, |(_, v)| KeyPair::SighashType(v)), - map(redeem_script, |(_, v)| KeyPair::RedeemScript(v)), - map(witness_script, |(_, v)| KeyPair::WitnessScript(v)), - map(bip32_derivation, |(k, v)| KeyPair::Bip32Derivation(k, v)), - map(final_scriptsig, |(_, v)| KeyPair::FinalScriptsig(v)), - map(final_scriptwitness, |(_, v)| KeyPair::FinalScriptwitness(v)), - map(por_commitment, |(_, v)| KeyPair::PorCommitment(v)), - map(ripemd160, |(k, _)| KeyPair::Ripemd160(k)), // TODO - map(sha256, |(k, _)| KeyPair::Sha256(k)), // TODO - map(hash160, |(k, _)| KeyPair::Hash160(k)), // TODO - map(hash256, |(k, _)| KeyPair::Hash256(k)), // TODO - map(previous_txid, |(_, v)| KeyPair::PreviousTxid(v)), - map(output_index, |(_, v)| KeyPair::OutputIndex(v)), - map(sequence, |(_, v)| KeyPair::Sequence(v)), - map(required_time_locktime, |(_, v)| KeyPair::RequiredTimeLocktime(v)), - map(required_height_locktime, |(_, v)| KeyPair::RequiredHeightLocktime(v)), - map(tap_key_sig, |(_, v)| KeyPair::TapKeySig(v)), + map(non_witness_utxo, |(_, v)| KeyPair::NonWitnessUtxo(v)), + map(witness_utxo, |(_, v)| KeyPair::WitnessUtxo(v)), + map(partial_sig, |(k, _)| KeyPair::PartialSig(k)), + map(sighash_type, |(_, v)| KeyPair::SighashType(v)), + map(redeem_script, |(_, v)| KeyPair::RedeemScript(v)), + map(witness_script, |(_, v)| KeyPair::WitnessScript(v)), + map(bip32_derivation, |(k, v)| KeyPair::Bip32Derivation(k, v)), + map(final_scriptsig, |(_, v)| KeyPair::FinalScriptsig(v)), + map(final_scriptwitness, |(_, v)| KeyPair::FinalScriptwitness(v)), + map(por_commitment, |(_, v)| KeyPair::PorCommitment(v)), + map(ripemd160, |(k, _)| KeyPair::Ripemd160(k)), // TODO + map(sha256, |(k, _)| KeyPair::Sha256(k)), // TODO + map(hash160, |(k, _)| KeyPair::Hash160(k)), // TODO + map(hash256, |(k, _)| KeyPair::Hash256(k)), // TODO + map(previous_txid, |(_, v)| KeyPair::PreviousTxid(v)), + map(output_index, |(_, v)| KeyPair::OutputIndex(v)), + map(sequence, |(_, v)| KeyPair::Sequence(v)), + map(required_time_locktime, |(_, v)| { + KeyPair::RequiredTimeLocktime(v) + }), + map(required_height_locktime, |(_, v)| { + KeyPair::RequiredHeightLocktime(v) + }), + map(tap_key_sig, |(_, v)| KeyPair::TapKeySig(v)), // This nesting is needed because `Alt` can only handle tuples up to // 21 elements. alt(( - map(tap_script_sig, |(k, v)| KeyPair::TapScriptSig(k, v)), - map(tap_leaf_script, |(k, v)| KeyPair::TapLeafScript(k, v)), - map(tap_bip32_derivation, |(k, v)| KeyPair::TapBip32Derivation(k, v)), - map(tap_internal_key, |(_, v)| KeyPair::TapInternalKey(v)), - map(tap_merkle_root, |(_, v)| KeyPair::TapMerkleRoot(v)), + map(tap_script_sig, |(k, v)| KeyPair::TapScriptSig(k, v)), + map(tap_leaf_script, |(k, v)| KeyPair::TapLeafScript(k, v)), + map(tap_bip32_derivation, |(k, v)| { + KeyPair::TapBip32Derivation(k, v) + }), + map(tap_internal_key, |(_, v)| KeyPair::TapInternalKey(v)), + map(tap_merkle_root, |(_, v)| KeyPair::TapMerkleRoot(v)), )), ))(i) } @@ -158,7 +199,6 @@ fn tap_script_sig<'a, Error>(i: &'a [u8]) -> IResult<&'a [u8], TaprootScriptSign where Error: ParseError<&'a [u8]>, Error: FromExternalError<&'a [u8], secp256k1::Error>, - Error: FromExternalError<&'a [u8], bitcoin_hashes::FromSliceError>, { let fields = tuple((x_only_public_key, taproot_leaf_hash)); let mut parser = map(fields, |(x_only_public_key, leaf_hash)| { diff --git a/psbt/src/parser/keypair.rs b/psbt/src/parser/keypair.rs index 756e266..a033bdf 100644 --- a/psbt/src/parser/keypair.rs +++ b/psbt/src/parser/keypair.rs @@ -21,8 +21,8 @@ where E: ParseError<&'a [u8]>, { let value = length_value( - verify(compact_size, |&v| { - println!(" = {v}"); + verify(compact_size, |&_v| { + //println!(" = {v}"); true }), value, @@ -41,13 +41,13 @@ where E: ParseError<&'a [u8]>, { let key_type = verify(compact_size, move |&k| { - println!(" = {k}"); + //println!(" = {k}"); k == key_type }); // This verification makes sure that the length is not a separator of a map. let length = verify(compact_size, |&v| { - println!(" = {v}"); + //println!(" = {v}"); v != 0x00 }); diff --git a/psbt/src/parser/mod.rs b/psbt/src/parser/mod.rs index 14305a3..5711b44 100644 --- a/psbt/src/parser/mod.rs +++ b/psbt/src/parser/mod.rs @@ -36,6 +36,8 @@ use nom::{ use foundation_bip32::{ExtendedPublicKey, KeySource}; +use crate::transaction::Transaction; + /// Parse a Partially Signed Bitcoin Transaction (PSBT). pub fn psbt<'a, F, Error>(xpub_event: F) -> impl FnMut(&'a [u8]) -> IResult<&[u8], Psbt, Error> where @@ -60,8 +62,7 @@ where let input_ = input.clone(); match input::input_map(input_) { - Ok((i, txin)) => { - println!("txin: {:?}", txin); + Ok((i, _txin)) => { input = i; } Err(Err::Error(e)) => { @@ -75,8 +76,7 @@ where let input_ = input.clone(); match output::output_map(input_) { - Ok((i, o)) => { - println!("{:?}", o); + Ok((i, _o)) => { input = i; } Err(Err::Error(e)) => { @@ -89,6 +89,7 @@ where Ok(( i, Psbt { + transaction: global_map.transaction, version: global_map.version, transaction_version: global_map.transaction_version.unwrap_or(0), fallback_lock_time: global_map.fallback_locktime, @@ -102,7 +103,8 @@ where /// A Partially Signed Bitcoin Transaction (PSBT). #[derive(Debug)] -pub struct Psbt { +pub struct Psbt<'a> { + pub transaction: Option>, /// Version of the PSBT file. pub version: u32, /// The version of the transaction. diff --git a/psbt/src/parser/output.rs b/psbt/src/parser/output.rs index f626835..e62820b 100644 --- a/psbt/src/parser/output.rs +++ b/psbt/src/parser/output.rs @@ -12,10 +12,13 @@ use nom::IResult; use secp256k1::{PublicKey, XOnlyPublicKey}; -use foundation_bip32::{parser::key_source, KeySource}; +use foundation_bip32::{ + parser::{key_source, public_key}, + KeySource, +}; use crate::parser::keypair::key_pair; -use crate::parser::secp::{public_key, x_only_public_key}; +use crate::parser::secp::x_only_public_key; #[rustfmt::skip] pub fn output_map<'a, Error>(i: &'a [u8]) -> IResult<&'a [u8], OutputMap<'a>, Error> diff --git a/psbt/src/parser/secp.rs b/psbt/src/parser/secp.rs index 0b36f5e..77e987c 100644 --- a/psbt/src/parser/secp.rs +++ b/psbt/src/parser/secp.rs @@ -9,29 +9,14 @@ use nom::error::ParseError; use nom::Err; use nom::IResult; -use secp256k1::{ecdsa, schnorr, PublicKey, XOnlyPublicKey}; +use secp256k1::{ecdsa, schnorr, XOnlyPublicKey}; pub fn x_only_public_key<'a, Error>(i: &'a [u8]) -> IResult<&'a [u8], XOnlyPublicKey, Error> where Error: ParseError<&'a [u8]>, Error: FromExternalError<&'a [u8], secp256k1::Error>, { - map_res(take(32usize), |data| XOnlyPublicKey::from_slice(data))(i) -} - -pub fn public_key<'a, Error>(i: &'a [u8]) -> IResult<&'a [u8], PublicKey, Error> -where - Error: ParseError<&'a [u8]>, - Error: FromExternalError<&'a [u8], secp256k1::Error>, -{ - match PublicKey::from_slice(i) { - Ok(p) => Ok((&i[i.len()..], p)), - Err(e) => Err(Err::Failure(Error::from_external_error( - i, - ErrorKind::Fail, - e, - ))), - } + map_res(take(32usize), XOnlyPublicKey::from_slice)(i) } pub fn ecdsa_signature<'a, Error>(i: &'a [u8]) -> IResult<&'a [u8], ecdsa::Signature, Error> diff --git a/psbt/src/parser/transaction.rs b/psbt/src/parser/transaction.rs index 2f52d88..b2c4f28 100644 --- a/psbt/src/parser/transaction.rs +++ b/psbt/src/parser/transaction.rs @@ -2,17 +2,17 @@ // SPDX-License-Identifier: GPL-3.0-or-later use nom::{ - bytes::complete::take, combinator::map, error::{ErrorKind, ParseError}, multi::length_data, number::complete::le_i64, number::complete::{le_i32, le_u32}, sequence::tuple, - Err, IResult, + Err, IResult, InputIter, InputLength, Slice, }; use crate::parser::compact_size::compact_size; +use crate::parser::hash::txid; use crate::transaction::{Input, Inputs, Output, OutputPoint, Transaction}; /// Parses a raw bitcoin transaction. @@ -94,10 +94,13 @@ where } /// Parses a raw bitcoin transaction output point of a transaction input. -pub fn output_point<'a, Error: ParseError<&'a [u8]>>( - i: &'a [u8], -) -> IResult<&[u8], OutputPoint, Error> { - let hash = take(32usize); +pub fn output_point(i: Input) -> IResult +where + Input: + Clone + PartialEq + InputLength + InputIter + Slice>, + Error: ParseError, +{ + let hash = txid; let index = le_u32; let mut parser = map(tuple((hash, index)), |(hash, index)| OutputPoint { hash, diff --git a/psbt/src/transaction.rs b/psbt/src/transaction.rs index ce740e1..561bb11 100644 --- a/psbt/src/transaction.rs +++ b/psbt/src/transaction.rs @@ -1,6 +1,8 @@ // SPDX-FileCopyrightText: © 2023 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later +use crate::hash_types::Txid; + /// A raw bitcoin transaction. #[derive(Debug, Clone)] pub struct Transaction<'a> { @@ -13,7 +15,7 @@ pub struct Transaction<'a> { /// A transaction input. #[derive(Debug)] pub struct Input<'a> { - pub previous_output: OutputPoint<'a>, + pub previous_output: OutputPoint, pub script_sig: &'a [u8], pub sequence: u32, } @@ -29,9 +31,9 @@ pub struct Output<'a> { /// Points to the output of a transaction. #[derive(Debug)] -pub struct OutputPoint<'a> { +pub struct OutputPoint { /// The transaction ID of the transaction holding the output to spend. - pub hash: &'a [u8], + pub hash: Txid, /// The output index number of the transaction to spend from the /// transaction. pub index: u32,