Skip to content

Commit

Permalink
Handle output map
Browse files Browse the repository at this point in the history
Signed-off-by: Jean-Pierre De Jesus DIAZ <[email protected]>
  • Loading branch information
jeandudey committed Oct 25, 2023
1 parent 373526e commit 86bfd15
Show file tree
Hide file tree
Showing 4 changed files with 172 additions and 74 deletions.
63 changes: 4 additions & 59 deletions psbt/src/parser/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,14 @@
use bitcoin_hashes::{hash160, ripemd160, sha256, sha256d};

use nom::branch::alt;
use nom::bytes::complete::take;
use nom::combinator::{eof, map, map_res, rest};
use nom::error::{ErrorKind, FromExternalError, ParseError};
use nom::combinator::{eof, map, rest};
use nom::error::{FromExternalError, ParseError};
use nom::multi::{fold_many0, length_value};
use nom::number::complete::le_u32;
use nom::sequence::tuple;
use nom::Err;
use nom::IResult;

use secp256k1::{ecdsa, schnorr, PublicKey, XOnlyPublicKey};
use secp256k1::{schnorr, PublicKey, XOnlyPublicKey};

use foundation_bip32::{parser::key_source, KeySource};

Expand All @@ -23,6 +21,7 @@ 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::transaction::{transaction, Transaction};
use crate::taproot::{TapNodeHash, TaprootScriptSignature};

Expand Down Expand Up @@ -168,60 +167,6 @@ where
parser(i)
}

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>,
{
let mut parser = map_res(take(32usize), |data| XOnlyPublicKey::from_slice(data));
parser(i)
}

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,
))),
}
}

fn ecdsa_signature<'a, Error>(i: &'a [u8]) -> IResult<&'a [u8], ecdsa::Signature, Error>
where
Error: ParseError<&'a [u8]>,
Error: FromExternalError<&'a [u8], secp256k1::Error>,
{
match ecdsa::Signature::from_der(i) {
Ok(p) => Ok((&i[i.len()..], p)),
Err(e) => Err(Err::Failure(Error::from_external_error(
i,
ErrorKind::Fail,
e,
))),
}
}

fn schnorr_signature<'a, Error>(i: &'a [u8]) -> IResult<&'a [u8], schnorr::Signature, Error>
where
Error: ParseError<&'a [u8]>,
Error: FromExternalError<&'a [u8], secp256k1::Error>,
{
match schnorr::Signature::from_slice(i) {
Ok(p) => Ok((&i[i.len()..], p)),
Err(e) => Err(Err::Failure(Error::from_external_error(
i,
ErrorKind::Fail,
e,
))),
}
}

#[derive(Debug, Default)]
pub struct InputMap<'a> {
pub non_witness_utxo: Option<Transaction>,
Expand Down
29 changes: 14 additions & 15 deletions psbt/src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,17 @@
//!
//! When more data is needed it can be simply read from a file.

mod compact_size;
mod global;
mod hash;
mod input;
mod keypair;
mod multi;
mod transaction;

pub use self::compact_size::*;
pub use self::global::*;
pub use self::hash::*;
pub use self::input::*;
pub mod compact_size;
pub mod global;
pub mod hash;
pub mod input;
pub mod keypair;
pub mod multi;
pub mod output;
// NOTE: Can't name this secp256k1 or else we can't refer to
// secp256k1::Error :-). might be a bug with Rust.
pub mod secp;
pub mod transaction;

use nom::{
bytes::complete::tag,
Expand All @@ -49,7 +48,7 @@ where
{
let magic = tag(b"psbt\xff");
let global_map = terminated(
global_map(f),
global::global_map(f),
context("no terminator at the end of global map", tag(b"\x00")),
);

Expand All @@ -61,7 +60,7 @@ where
fallback_lock_time: global_map.fallback_locktime,
tx_modifiable: global_map
.tx_modifiable
.unwrap_or_else(|| TxModifiable::empty()),
.unwrap_or_else(|| global::TxModifiable::empty()),
})
}

Expand All @@ -76,7 +75,7 @@ pub struct Psbt {
/// time.
pub fallback_lock_time: Option<u32>,
/// Flags indicating which parts of the transaction that are modifiable.
pub tx_modifiable: TxModifiable,
pub tx_modifiable: global::TxModifiable,
}

#[cfg(test)]
Expand Down
89 changes: 89 additions & 0 deletions psbt/src/parser/output.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// SPDX-FileCopyrightText: © 2023 Foundation Devices, Inc. <[email protected]>
// SPDX-License-Identifier: GPL-3.0-or-later

use nom::branch::alt;
use nom::combinator::{eof, map, rest};
use nom::error::{FromExternalError, ParseError};
use nom::number::complete::le_u64;
use nom::multi::fold_many0;
use nom::IResult;

use secp256k1::{PublicKey, XOnlyPublicKey};

use foundation_bip32::{parser::key_source, KeySource};

use crate::parser::keypair::key_pair;
use crate::parser::secp::{public_key, x_only_public_key};

pub fn output_map<'a, Error>(i: &'a [u8]) -> IResult<&'a [u8], OutputMap<'a>, Error>
where
Error: ParseError<&'a [u8]>,
Error: FromExternalError<&'a [u8], secp256k1::Error>,
{
fold_many0(
output_key_pair,
OutputMap::default,
|mut map, key_pair| {
match key_pair {
KeyPair::RedeemScript(v) => map.redeem_script = Some(v),
KeyPair::WitnessScript(v) => map.witness_script = Some(v),
KeyPair::Bip32Derivation(_, _) => (), // TODO
KeyPair::Amount(v) => map.amount = Some(v),
KeyPair::Script(v) => map.script = Some(v),
KeyPair::TapInternalKey(v) => map.tap_internal_key = Some(v),
KeyPair::TapTree(v) => map.tap_tree = Some(v),
KeyPair::TapBip32Derivation(_, _) => (), // TODO
};

map
},
)(i)
}

#[rustfmt::skip]
fn output_key_pair<'a, Error>(i: &'a [u8]) -> IResult<&'a [u8], KeyPair<'a>, Error>
where
Error: ParseError<&'a [u8]>,
Error: FromExternalError<&'a [u8], secp256k1::Error>,
{
let redeem_script = key_pair(0x00, eof, rest);
let witness_script = key_pair(0x01, eof, rest);
let bip32_derivation = key_pair(0x02, public_key, key_source);
let amount = key_pair(0x03, eof, le_u64);
let script = key_pair(0x04, eof, rest);
let tap_internal_key = key_pair(0x05, eof, x_only_public_key);
let tap_tree = key_pair(0x06, eof, rest);
let tap_bip32_derivation = key_pair(0x06, x_only_public_key, rest);

alt((
map(redeem_script, |(_, v)| KeyPair::RedeemScript(v)),
map(witness_script, |(_, v)| KeyPair::WitnessScript(v)),
map(bip32_derivation, |(k, v)| KeyPair::Bip32Derivation(k, v)),
map(amount, |(_, v)| KeyPair::Amount(v)),
map(script, |(_, v)| KeyPair::Script(v)),
map(tap_internal_key, |(_, v)| KeyPair::TapInternalKey(v)),
map(tap_tree, |(_, v)| KeyPair::TapTree(v)),
map(tap_bip32_derivation, |(k, v)| KeyPair::TapBip32Derivation(k, v)),
))(i)
}

#[derive(Debug, Default)]
pub struct OutputMap<'a> {
pub redeem_script: Option<&'a [u8]>,
pub witness_script: Option<&'a [u8]>,
pub amount: Option<u64>,
pub script: Option<&'a [u8]>,
pub tap_internal_key: Option<XOnlyPublicKey>,
pub tap_tree: Option<&'a [u8]>,
}

enum KeyPair<'a> {
RedeemScript(&'a [u8]),
WitnessScript(&'a [u8]),
Bip32Derivation(PublicKey, KeySource<'a>),
Amount(u64),
Script(&'a [u8]),
TapInternalKey(XOnlyPublicKey),
TapTree(&'a [u8]),
TapBip32Derivation(XOnlyPublicKey, &'a [u8]),
}
65 changes: 65 additions & 0 deletions psbt/src/parser/secp.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// SPDX-FileCopyrightText: © 2023 Foundation Devices, Inc. <[email protected]>
// SPDX-License-Identifier: GPL-3.0-or-later

use nom::bytes::complete::take;
use nom::combinator::map_res;
use nom::error::ErrorKind;
use nom::error::FromExternalError;
use nom::error::ParseError;
use nom::Err;
use nom::IResult;

use secp256k1::{ecdsa, schnorr, PublicKey, 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,
))),
}
}

pub fn ecdsa_signature<'a, Error>(i: &'a [u8]) -> IResult<&'a [u8], ecdsa::Signature, Error>
where
Error: ParseError<&'a [u8]>,
Error: FromExternalError<&'a [u8], secp256k1::Error>,
{
match ecdsa::Signature::from_der(i) {
Ok(p) => Ok((&i[i.len()..], p)),
Err(e) => Err(Err::Failure(Error::from_external_error(
i,
ErrorKind::Fail,
e,
))),
}
}

pub fn schnorr_signature<'a, Error>(i: &'a [u8]) -> IResult<&'a [u8], schnorr::Signature, Error>
where
Error: ParseError<&'a [u8]>,
Error: FromExternalError<&'a [u8], secp256k1::Error>,
{
match schnorr::Signature::from_slice(i) {
Ok(p) => Ok((&i[i.len()..], p)),
Err(e) => Err(Err::Failure(Error::from_external_error(
i,
ErrorKind::Fail,
e,
))),
}
}

0 comments on commit 86bfd15

Please sign in to comment.