Merge rust-bitcoin/rust-bitcoin#755: Update to secp256k1 0.21.2
91470f56c8
Uncomment sighash test (sanket1729)2178c7367c
Update to secp256k1 0.21.2 (sanket1729) Pull request description: ACKs for top commit: Kixunil: ACK91470f56c8
dr-orlovsky: utACK91470f56c8
in order to unlock the rest of PRs required for Taproot, which depend on this. Tree-SHA512: ea04a2ae14aee078f33e49e3283cd5c4dad5b118aef75b8e7c6dd00620c66e89096ff2fbd8b450d75b43a98cd20b350dad05c288687683272fa4878a6d9c83c2
This commit is contained in:
commit
7010672569
|
@ -35,7 +35,7 @@ rustdoc-args = ["--cfg", "docsrs"]
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bech32 = { version = "0.8.1", default-features = false }
|
bech32 = { version = "0.8.1", default-features = false }
|
||||||
bitcoin_hashes = { version = "0.10.0", default-features = false }
|
bitcoin_hashes = { version = "0.10.0", default-features = false }
|
||||||
secp256k1 = { version = "0.20.3", default-features = false }
|
secp256k1 = { version = "0.21.2", default-features = false }
|
||||||
core2 = { version = "0.3.0", optional = true, default-features = false }
|
core2 = { version = "0.3.0", optional = true, default-features = false }
|
||||||
|
|
||||||
base64-compat = { version = "1.0.0", optional = true }
|
base64-compat = { version = "1.0.0", optional = true }
|
||||||
|
@ -46,7 +46,7 @@ hashbrown = { version = "0.8", optional = true }
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
serde_json = "<1.0.45"
|
serde_json = "<1.0.45"
|
||||||
serde_test = "1"
|
serde_test = "1"
|
||||||
secp256k1 = { version = "0.20.0", features = [ "recovery", "rand-std" ] }
|
secp256k1 = { version = "0.21.2", features = [ "recovery", "rand-std" ] }
|
||||||
bincode = "1.3.1"
|
bincode = "1.3.1"
|
||||||
# We need to pin ryu (transitive dep from serde_json) to stay compatible with Rust 1.22.0
|
# We need to pin ryu (transitive dep from serde_json) to stay compatible with Rust 1.22.0
|
||||||
ryu = "<1.0.5"
|
ryu = "<1.0.5"
|
||||||
|
|
|
@ -879,7 +879,7 @@ mod tests {
|
||||||
use blockdata::script::Script;
|
use blockdata::script::Script;
|
||||||
use network::constants::Network::{Bitcoin, Testnet};
|
use network::constants::Network::{Bitcoin, Testnet};
|
||||||
use util::ecdsa::PublicKey;
|
use util::ecdsa::PublicKey;
|
||||||
use secp256k1::schnorrsig;
|
use secp256k1::XOnlyPublicKey;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
@ -1266,7 +1266,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn p2tr_from_untweaked(){
|
fn p2tr_from_untweaked(){
|
||||||
//Test case from BIP-086
|
//Test case from BIP-086
|
||||||
let internal_key = schnorrsig::PublicKey::from_str("cc8a4bc64d897bddc5fbc2f670f7a8ba0b386779106cf1223c6fc5d7cd6fc115").unwrap();
|
let internal_key = XOnlyPublicKey::from_str("cc8a4bc64d897bddc5fbc2f670f7a8ba0b386779106cf1223c6fc5d7cd6fc115").unwrap();
|
||||||
let secp = Secp256k1::verification_only();
|
let secp = Secp256k1::verification_only();
|
||||||
let address = Address::p2tr(&secp, internal_key, None, Network::Bitcoin);
|
let address = Address::p2tr(&secp, internal_key, None, Network::Bitcoin);
|
||||||
assert_eq!(address.to_string(), "bc1p5cyxnuxmeuwuvkwfem96lqzszd02n6xdcjrs20cac6yqjjwudpxqkedrcr");
|
assert_eq!(address.to_string(), "bc1p5cyxnuxmeuwuvkwfem96lqzszd02n6xdcjrs20cac6yqjjwudpxqkedrcr");
|
||||||
|
|
|
@ -419,7 +419,7 @@ impl<'de> ::serde::Deserialize<'de> for PublicKey {
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
pub struct EcdsaSig {
|
pub struct EcdsaSig {
|
||||||
/// The underlying ECDSA Signature
|
/// The underlying ECDSA Signature
|
||||||
pub sig: secp256k1::Signature,
|
pub sig: secp256k1::ecdsa::Signature,
|
||||||
/// The corresponding hash type
|
/// The corresponding hash type
|
||||||
pub hash_ty: EcdsaSigHashType,
|
pub hash_ty: EcdsaSigHashType,
|
||||||
}
|
}
|
||||||
|
@ -432,7 +432,7 @@ impl EcdsaSig {
|
||||||
.ok_or(EcdsaSigError::EmptySignature)?;
|
.ok_or(EcdsaSigError::EmptySignature)?;
|
||||||
let hash_ty = EcdsaSigHashType::from_u32_standard(*hash_ty as u32)
|
let hash_ty = EcdsaSigHashType::from_u32_standard(*hash_ty as u32)
|
||||||
.map_err(|_| EcdsaSigError::NonStandardSigHashType(*hash_ty))?;
|
.map_err(|_| EcdsaSigError::NonStandardSigHashType(*hash_ty))?;
|
||||||
let sig = secp256k1::Signature::from_der(sig)
|
let sig = secp256k1::ecdsa::Signature::from_der(sig)
|
||||||
.map_err(EcdsaSigError::Secp256k1)?;
|
.map_err(EcdsaSigError::Secp256k1)?;
|
||||||
Ok(EcdsaSig { sig, hash_ty })
|
Ok(EcdsaSig { sig, hash_ty })
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,7 @@ mod message_signing {
|
||||||
|
|
||||||
use hashes::sha256d;
|
use hashes::sha256d;
|
||||||
use secp256k1;
|
use secp256k1;
|
||||||
use secp256k1::recovery::{RecoveryId, RecoverableSignature};
|
use secp256k1::ecdsa::{RecoveryId, RecoverableSignature};
|
||||||
|
|
||||||
use util::ecdsa::PublicKey;
|
use util::ecdsa::PublicKey;
|
||||||
use util::address::{Address, AddressType};
|
use util::address::{Address, AddressType};
|
||||||
|
@ -146,7 +146,7 @@ mod message_signing {
|
||||||
msg_hash: sha256d::Hash
|
msg_hash: sha256d::Hash
|
||||||
) -> Result<PublicKey, secp256k1::Error> {
|
) -> Result<PublicKey, secp256k1::Error> {
|
||||||
let msg = secp256k1::Message::from_slice(&msg_hash[..])?;
|
let msg = secp256k1::Message::from_slice(&msg_hash[..])?;
|
||||||
let pubkey = secp_ctx.recover(&msg, &self.signature)?;
|
let pubkey = secp_ctx.recover_ecdsa(&msg, &self.signature)?;
|
||||||
Ok(PublicKey {
|
Ok(PublicKey {
|
||||||
key: pubkey,
|
key: pubkey,
|
||||||
compressed: self.compressed,
|
compressed: self.compressed,
|
||||||
|
|
|
@ -19,6 +19,7 @@ use io;
|
||||||
use blockdata::script::Script;
|
use blockdata::script::Script;
|
||||||
use blockdata::transaction::{EcdsaSigHashType, Transaction, TxOut};
|
use blockdata::transaction::{EcdsaSigHashType, Transaction, TxOut};
|
||||||
use consensus::encode;
|
use consensus::encode;
|
||||||
|
use secp256k1::XOnlyPublicKey;
|
||||||
use util::bip32::KeySource;
|
use util::bip32::KeySource;
|
||||||
use hashes::{self, hash160, ripemd160, sha256, sha256d};
|
use hashes::{self, hash160, ripemd160, sha256, sha256d};
|
||||||
use util::ecdsa::PublicKey;
|
use util::ecdsa::PublicKey;
|
||||||
|
@ -123,15 +124,15 @@ pub struct Input {
|
||||||
pub tap_key_sig: Option<schnorr::SchnorrSig>,
|
pub tap_key_sig: Option<schnorr::SchnorrSig>,
|
||||||
/// Map of <xonlypubkey>|<leafhash> with signature
|
/// Map of <xonlypubkey>|<leafhash> with signature
|
||||||
#[cfg_attr(feature = "serde", serde(with = "::serde_utils::btreemap_as_seq"))]
|
#[cfg_attr(feature = "serde", serde(with = "::serde_utils::btreemap_as_seq"))]
|
||||||
pub tap_script_sigs: BTreeMap<(schnorr::PublicKey, TapLeafHash), schnorr::SchnorrSig>,
|
pub tap_script_sigs: BTreeMap<(XOnlyPublicKey, TapLeafHash), schnorr::SchnorrSig>,
|
||||||
/// Map of Control blocks to Script version pair
|
/// Map of Control blocks to Script version pair
|
||||||
#[cfg_attr(feature = "serde", serde(with = "::serde_utils::btreemap_as_seq"))]
|
#[cfg_attr(feature = "serde", serde(with = "::serde_utils::btreemap_as_seq"))]
|
||||||
pub tap_scripts: BTreeMap<ControlBlock, (Script, LeafVersion)>,
|
pub tap_scripts: BTreeMap<ControlBlock, (Script, LeafVersion)>,
|
||||||
/// Map of tap root x only keys to origin info and leaf hashes contained in it
|
/// Map of tap root x only keys to origin info and leaf hashes contained in it
|
||||||
#[cfg_attr(feature = "serde", serde(with = "::serde_utils::btreemap_as_seq"))]
|
#[cfg_attr(feature = "serde", serde(with = "::serde_utils::btreemap_as_seq"))]
|
||||||
pub tap_key_origins: BTreeMap<schnorr::PublicKey, (Vec<TapLeafHash>, KeySource)>,
|
pub tap_key_origins: BTreeMap<XOnlyPublicKey, (Vec<TapLeafHash>, KeySource)>,
|
||||||
/// Taproot Internal key
|
/// Taproot Internal key
|
||||||
pub tap_internal_key : Option<schnorr::PublicKey>,
|
pub tap_internal_key : Option<XOnlyPublicKey>,
|
||||||
/// Taproot Merkle root
|
/// Taproot Merkle root
|
||||||
pub tap_merkle_root : Option<TapBranchHash>,
|
pub tap_merkle_root : Option<TapBranchHash>,
|
||||||
/// Proprietary key-value pairs for this input.
|
/// Proprietary key-value pairs for this input.
|
||||||
|
@ -214,7 +215,7 @@ impl Map for Input {
|
||||||
}
|
}
|
||||||
PSBT_IN_TAP_SCRIPT_SIG => {
|
PSBT_IN_TAP_SCRIPT_SIG => {
|
||||||
impl_psbt_insert_pair! {
|
impl_psbt_insert_pair! {
|
||||||
self.tap_script_sigs <= <raw_key: (schnorr::PublicKey, TapLeafHash)>|<raw_value: schnorr::SchnorrSig>
|
self.tap_script_sigs <= <raw_key: (XOnlyPublicKey, TapLeafHash)>|<raw_value: schnorr::SchnorrSig>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PSBT_IN_TAP_LEAF_SCRIPT=> {
|
PSBT_IN_TAP_LEAF_SCRIPT=> {
|
||||||
|
@ -224,12 +225,12 @@ impl Map for Input {
|
||||||
}
|
}
|
||||||
PSBT_IN_TAP_BIP32_DERIVATION => {
|
PSBT_IN_TAP_BIP32_DERIVATION => {
|
||||||
impl_psbt_insert_pair! {
|
impl_psbt_insert_pair! {
|
||||||
self.tap_key_origins <= <raw_key: schnorr::PublicKey>|< raw_value: (Vec<TapLeafHash>, KeySource)>
|
self.tap_key_origins <= <raw_key: XOnlyPublicKey>|< raw_value: (Vec<TapLeafHash>, KeySource)>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PSBT_IN_TAP_INTERNAL_KEY => {
|
PSBT_IN_TAP_INTERNAL_KEY => {
|
||||||
impl_psbt_insert_pair! {
|
impl_psbt_insert_pair! {
|
||||||
self.tap_internal_key <= <raw_key: _>|< raw_value: schnorr::PublicKey>
|
self.tap_internal_key <= <raw_key: _>|< raw_value: XOnlyPublicKey>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PSBT_IN_TAP_MERKLE_ROOT => {
|
PSBT_IN_TAP_MERKLE_ROOT => {
|
||||||
|
@ -314,7 +315,7 @@ impl Map for Input {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_psbt_get_pair! {
|
impl_psbt_get_pair! {
|
||||||
rv.push(self.tap_script_sigs as <PSBT_IN_TAP_SCRIPT_SIG, (schnorr::PublicKey, TapLeafHash)>|<Vec<u8>>)
|
rv.push(self.tap_script_sigs as <PSBT_IN_TAP_SCRIPT_SIG, (XOnlyPublicKey, TapLeafHash)>|<Vec<u8>>)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_psbt_get_pair! {
|
impl_psbt_get_pair! {
|
||||||
|
@ -323,11 +324,11 @@ impl Map for Input {
|
||||||
|
|
||||||
impl_psbt_get_pair! {
|
impl_psbt_get_pair! {
|
||||||
rv.push(self.tap_key_origins as <PSBT_IN_TAP_BIP32_DERIVATION,
|
rv.push(self.tap_key_origins as <PSBT_IN_TAP_BIP32_DERIVATION,
|
||||||
schnorr::PublicKey>|<(Vec<TapLeafHash>, KeySource)>)
|
XOnlyPublicKey>|<(Vec<TapLeafHash>, KeySource)>)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_psbt_get_pair! {
|
impl_psbt_get_pair! {
|
||||||
rv.push(self.tap_internal_key as <PSBT_IN_TAP_INTERNAL_KEY, _>|<schnorr::PublicKey>)
|
rv.push(self.tap_internal_key as <PSBT_IN_TAP_INTERNAL_KEY, _>|<XOnlyPublicKey>)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_psbt_get_pair! {
|
impl_psbt_get_pair! {
|
||||||
|
|
|
@ -18,6 +18,7 @@ use io;
|
||||||
|
|
||||||
use blockdata::script::Script;
|
use blockdata::script::Script;
|
||||||
use consensus::encode;
|
use consensus::encode;
|
||||||
|
use secp256k1::XOnlyPublicKey;
|
||||||
use util::bip32::KeySource;
|
use util::bip32::KeySource;
|
||||||
use util::ecdsa::PublicKey;
|
use util::ecdsa::PublicKey;
|
||||||
use util::psbt;
|
use util::psbt;
|
||||||
|
@ -25,7 +26,6 @@ use util::psbt::map::Map;
|
||||||
use util::psbt::raw;
|
use util::psbt::raw;
|
||||||
use util::psbt::Error;
|
use util::psbt::Error;
|
||||||
|
|
||||||
use schnorr;
|
|
||||||
use util::taproot::TapLeafHash;
|
use util::taproot::TapLeafHash;
|
||||||
|
|
||||||
use util::taproot::{NodeInfo, TaprootBuilder};
|
use util::taproot::{NodeInfo, TaprootBuilder};
|
||||||
|
@ -59,12 +59,12 @@ pub struct Output {
|
||||||
#[cfg_attr(feature = "serde", serde(with = "::serde_utils::btreemap_as_seq"))]
|
#[cfg_attr(feature = "serde", serde(with = "::serde_utils::btreemap_as_seq"))]
|
||||||
pub bip32_derivation: BTreeMap<PublicKey, KeySource>,
|
pub bip32_derivation: BTreeMap<PublicKey, KeySource>,
|
||||||
/// The internal pubkey
|
/// The internal pubkey
|
||||||
pub tap_internal_key: Option<schnorr::PublicKey>,
|
pub tap_internal_key: Option<XOnlyPublicKey>,
|
||||||
/// Taproot Output tree
|
/// Taproot Output tree
|
||||||
pub tap_tree: Option<TapTree>,
|
pub tap_tree: Option<TapTree>,
|
||||||
/// Map of tap root x only keys to origin info and leaf hashes contained in it
|
/// Map of tap root x only keys to origin info and leaf hashes contained in it
|
||||||
#[cfg_attr(feature = "serde", serde(with = "::serde_utils::btreemap_as_seq"))]
|
#[cfg_attr(feature = "serde", serde(with = "::serde_utils::btreemap_as_seq"))]
|
||||||
pub tap_key_origins: BTreeMap<schnorr::PublicKey, (Vec<TapLeafHash>, KeySource)>,
|
pub tap_key_origins: BTreeMap<XOnlyPublicKey, (Vec<TapLeafHash>, KeySource)>,
|
||||||
/// Proprietary key-value pairs for this output.
|
/// Proprietary key-value pairs for this output.
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "serde",
|
feature = "serde",
|
||||||
|
@ -148,7 +148,7 @@ impl Map for Output {
|
||||||
}
|
}
|
||||||
PSBT_OUT_TAP_INTERNAL_KEY => {
|
PSBT_OUT_TAP_INTERNAL_KEY => {
|
||||||
impl_psbt_insert_pair! {
|
impl_psbt_insert_pair! {
|
||||||
self.tap_internal_key <= <raw_key: _>|<raw_value: schnorr::PublicKey>
|
self.tap_internal_key <= <raw_key: _>|<raw_value: XOnlyPublicKey>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PSBT_OUT_TAP_TREE => {
|
PSBT_OUT_TAP_TREE => {
|
||||||
|
@ -158,7 +158,7 @@ impl Map for Output {
|
||||||
}
|
}
|
||||||
PSBT_OUT_TAP_BIP32_DERIVATION => {
|
PSBT_OUT_TAP_BIP32_DERIVATION => {
|
||||||
impl_psbt_insert_pair! {
|
impl_psbt_insert_pair! {
|
||||||
self.tap_key_origins <= <raw_key: schnorr::PublicKey>|< raw_value: (Vec<TapLeafHash>, KeySource)>
|
self.tap_key_origins <= <raw_key: XOnlyPublicKey>|< raw_value: (Vec<TapLeafHash>, KeySource)>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => match self.unknown.entry(raw_key) {
|
_ => match self.unknown.entry(raw_key) {
|
||||||
|
|
|
@ -25,7 +25,7 @@ use io;
|
||||||
use blockdata::script::Script;
|
use blockdata::script::Script;
|
||||||
use blockdata::transaction::{EcdsaSigHashType, Transaction, TxOut};
|
use blockdata::transaction::{EcdsaSigHashType, Transaction, TxOut};
|
||||||
use consensus::encode::{self, serialize, Decodable, Encodable, deserialize_partial};
|
use consensus::encode::{self, serialize, Decodable, Encodable, deserialize_partial};
|
||||||
use secp256k1::schnorrsig;
|
use secp256k1::{self, XOnlyPublicKey};
|
||||||
use util::bip32::{ChildNumber, Fingerprint, KeySource};
|
use util::bip32::{ChildNumber, Fingerprint, KeySource};
|
||||||
use hashes::{hash160, ripemd160, sha256, sha256d, Hash};
|
use hashes::{hash160, ripemd160, sha256, sha256d, Hash};
|
||||||
use util::ecdsa::PublicKey;
|
use util::ecdsa::PublicKey;
|
||||||
|
@ -157,15 +157,15 @@ impl Deserialize for EcdsaSigHashType {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Taproot related ser/deser
|
// Taproot related ser/deser
|
||||||
impl Serialize for schnorr::PublicKey {
|
impl Serialize for XOnlyPublicKey {
|
||||||
fn serialize(&self) -> Vec<u8> {
|
fn serialize(&self) -> Vec<u8> {
|
||||||
schnorr::PublicKey::serialize(&self).to_vec()
|
XOnlyPublicKey::serialize(&self).to_vec()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deserialize for schnorr::PublicKey {
|
impl Deserialize for XOnlyPublicKey {
|
||||||
fn deserialize(bytes: &[u8]) -> Result<Self, encode::Error> {
|
fn deserialize(bytes: &[u8]) -> Result<Self, encode::Error> {
|
||||||
schnorr::PublicKey::from_slice(bytes)
|
XOnlyPublicKey::from_slice(bytes)
|
||||||
.map_err(|_| encode::Error::ParseFailed("Invalid xonly public key"))
|
.map_err(|_| encode::Error::ParseFailed("Invalid xonly public key"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -182,12 +182,12 @@ impl Deserialize for schnorr::SchnorrSig {
|
||||||
65 => {
|
65 => {
|
||||||
let hash_ty = SchnorrSigHashType::from_u8(bytes[64])
|
let hash_ty = SchnorrSigHashType::from_u8(bytes[64])
|
||||||
.map_err(|_| encode::Error::ParseFailed("Invalid Sighash type"))?;
|
.map_err(|_| encode::Error::ParseFailed("Invalid Sighash type"))?;
|
||||||
let sig = schnorrsig::Signature::from_slice(&bytes[..64])
|
let sig = secp256k1::schnorr::Signature::from_slice(&bytes[..64])
|
||||||
.map_err(|_| encode::Error::ParseFailed("Invalid Schnorr signature"))?;
|
.map_err(|_| encode::Error::ParseFailed("Invalid Schnorr signature"))?;
|
||||||
Ok(schnorr::SchnorrSig{ sig, hash_ty })
|
Ok(schnorr::SchnorrSig{ sig, hash_ty })
|
||||||
}
|
}
|
||||||
64 => {
|
64 => {
|
||||||
let sig = schnorrsig::Signature::from_slice(&bytes[..64])
|
let sig = secp256k1::schnorr::Signature::from_slice(&bytes[..64])
|
||||||
.map_err(|_| encode::Error::ParseFailed("Invalid Schnorr signature"))?;
|
.map_err(|_| encode::Error::ParseFailed("Invalid Schnorr signature"))?;
|
||||||
Ok(schnorr::SchnorrSig{ sig, hash_ty: SchnorrSigHashType::Default })
|
Ok(schnorr::SchnorrSig{ sig, hash_ty: SchnorrSigHashType::Default })
|
||||||
}
|
}
|
||||||
|
@ -196,7 +196,7 @@ impl Deserialize for schnorr::SchnorrSig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Serialize for (schnorr::PublicKey, TapLeafHash) {
|
impl Serialize for (XOnlyPublicKey, TapLeafHash) {
|
||||||
fn serialize(&self) -> Vec<u8> {
|
fn serialize(&self) -> Vec<u8> {
|
||||||
let ser_pk = self.0.serialize();
|
let ser_pk = self.0.serialize();
|
||||||
let mut buf = Vec::with_capacity(ser_pk.len() + self.1.as_ref().len());
|
let mut buf = Vec::with_capacity(ser_pk.len() + self.1.as_ref().len());
|
||||||
|
@ -206,12 +206,12 @@ impl Serialize for (schnorr::PublicKey, TapLeafHash) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deserialize for (schnorr::PublicKey, TapLeafHash) {
|
impl Deserialize for (XOnlyPublicKey, TapLeafHash) {
|
||||||
fn deserialize(bytes: &[u8]) -> Result<Self, encode::Error> {
|
fn deserialize(bytes: &[u8]) -> Result<Self, encode::Error> {
|
||||||
if bytes.len() < 32 {
|
if bytes.len() < 32 {
|
||||||
return Err(io::Error::from(io::ErrorKind::UnexpectedEof).into())
|
return Err(io::Error::from(io::ErrorKind::UnexpectedEof).into())
|
||||||
}
|
}
|
||||||
let a: schnorr::PublicKey = Deserialize::deserialize(&bytes[..32])?;
|
let a: XOnlyPublicKey = Deserialize::deserialize(&bytes[..32])?;
|
||||||
let b: TapLeafHash = Deserialize::deserialize(&bytes[32..])?;
|
let b: TapLeafHash = Deserialize::deserialize(&bytes[32..])?;
|
||||||
Ok((a, b))
|
Ok((a, b))
|
||||||
}
|
}
|
||||||
|
@ -266,7 +266,7 @@ impl Serialize for (Vec<TapLeafHash>, KeySource) {
|
||||||
|
|
||||||
impl Deserialize for (Vec<TapLeafHash>, KeySource) {
|
impl Deserialize for (Vec<TapLeafHash>, KeySource) {
|
||||||
fn deserialize(bytes: &[u8]) -> Result<Self, encode::Error> {
|
fn deserialize(bytes: &[u8]) -> Result<Self, encode::Error> {
|
||||||
let (leafhash_vec, consumed) = deserialize_partial::<Vec::<TapLeafHash>>(&bytes)?;
|
let (leafhash_vec, consumed) = deserialize_partial::<Vec<TapLeafHash>>(&bytes)?;
|
||||||
let key_source = KeySource::deserialize(&bytes[consumed..])?;
|
let key_source = KeySource::deserialize(&bytes[consumed..])?;
|
||||||
Ok((leafhash_vec, key_source))
|
Ok((leafhash_vec, key_source))
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,18 +20,18 @@
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use prelude::*;
|
use prelude::*;
|
||||||
|
|
||||||
pub use secp256k1::schnorrsig::{PublicKey, KeyPair};
|
pub use secp256k1::{XOnlyPublicKey, KeyPair};
|
||||||
use secp256k1::{self, Secp256k1, Verification, constants};
|
use secp256k1::{self, Secp256k1, Verification, constants};
|
||||||
use hashes::Hash;
|
use hashes::Hash;
|
||||||
use util::taproot::{TapBranchHash, TapTweakHash};
|
use util::taproot::{TapBranchHash, TapTweakHash};
|
||||||
use SchnorrSigHashType;
|
use SchnorrSigHashType;
|
||||||
|
|
||||||
/// Untweaked Schnorr public key
|
/// Untweaked Schnorr public key
|
||||||
pub type UntweakedPublicKey = PublicKey;
|
pub type UntweakedPublicKey = XOnlyPublicKey;
|
||||||
|
|
||||||
/// Tweaked Schnorr public key
|
/// Tweaked Schnorr public key
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub struct TweakedPublicKey(PublicKey);
|
pub struct TweakedPublicKey(XOnlyPublicKey);
|
||||||
|
|
||||||
impl fmt::LowerHex for TweakedPublicKey {
|
impl fmt::LowerHex for TweakedPublicKey {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
@ -58,7 +58,7 @@ pub trait TapTweak {
|
||||||
///
|
///
|
||||||
/// # Returns
|
/// # Returns
|
||||||
/// The tweaked key and its parity.
|
/// The tweaked key and its parity.
|
||||||
fn tap_tweak<C: Verification>(self, secp: &Secp256k1<C>, merkle_root: Option<TapBranchHash>) -> (TweakedPublicKey, bool);
|
fn tap_tweak<C: Verification>(self, secp: &Secp256k1<C>, merkle_root: Option<TapBranchHash>) -> (TweakedPublicKey, secp256k1::Parity);
|
||||||
|
|
||||||
/// Directly converts an [`UntweakedPublicKey`] to a [`TweakedPublicKey`]
|
/// Directly converts an [`UntweakedPublicKey`] to a [`TweakedPublicKey`]
|
||||||
///
|
///
|
||||||
|
@ -68,7 +68,7 @@ pub trait TapTweak {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TapTweak for UntweakedPublicKey {
|
impl TapTweak for UntweakedPublicKey {
|
||||||
fn tap_tweak<C: Verification>(self, secp: &Secp256k1<C>, merkle_root: Option<TapBranchHash>) -> (TweakedPublicKey, bool) {
|
fn tap_tweak<C: Verification>(self, secp: &Secp256k1<C>, merkle_root: Option<TapBranchHash>) -> (TweakedPublicKey, secp256k1::Parity) {
|
||||||
let tweak_value = TapTweakHash::from_key_and_tweak(self, merkle_root).into_inner();
|
let tweak_value = TapTweakHash::from_key_and_tweak(self, merkle_root).into_inner();
|
||||||
let mut output_key = self.clone();
|
let mut output_key = self.clone();
|
||||||
let parity = output_key.tweak_add_assign(&secp, &tweak_value).expect("Tap tweak failed");
|
let parity = output_key.tweak_add_assign(&secp, &tweak_value).expect("Tap tweak failed");
|
||||||
|
@ -83,19 +83,19 @@ impl TapTweak for UntweakedPublicKey {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TweakedPublicKey {
|
impl TweakedPublicKey {
|
||||||
/// Creates a new [`TweakedPublicKey`] from a [`PublicKey`]. No tweak is applied, consider
|
/// Creates a new [`TweakedPublicKey`] from a [`XOnlyPublicKey`]. No tweak is applied, consider
|
||||||
/// calling `tap_tweak` on an [`UntweakedPublicKey`] instead of using this constructor.
|
/// calling `tap_tweak` on an [`UntweakedPublicKey`] instead of using this constructor.
|
||||||
pub fn dangerous_assume_tweaked(key: PublicKey) -> TweakedPublicKey {
|
pub fn dangerous_assume_tweaked(key: XOnlyPublicKey) -> TweakedPublicKey {
|
||||||
TweakedPublicKey(key)
|
TweakedPublicKey(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the underlying public key.
|
/// Returns the underlying public key.
|
||||||
pub fn into_inner(self) -> PublicKey {
|
pub fn into_inner(self) -> XOnlyPublicKey {
|
||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a reference to underlying public key.
|
/// Returns a reference to underlying public key.
|
||||||
pub fn as_inner(&self) -> &PublicKey {
|
pub fn as_inner(&self) -> &XOnlyPublicKey {
|
||||||
&self.0
|
&self.0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,7 +113,7 @@ impl TweakedPublicKey {
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
pub struct SchnorrSig {
|
pub struct SchnorrSig {
|
||||||
/// The underlying schnorr signature
|
/// The underlying schnorr signature
|
||||||
pub sig: secp256k1::schnorrsig::Signature,
|
pub sig: secp256k1::schnorr::Signature,
|
||||||
/// The corresponding hash type
|
/// The corresponding hash type
|
||||||
pub hash_ty: SchnorrSigHashType,
|
pub hash_ty: SchnorrSigHashType,
|
||||||
}
|
}
|
||||||
|
@ -125,7 +125,7 @@ impl SchnorrSig {
|
||||||
match sl.len() {
|
match sl.len() {
|
||||||
64 => {
|
64 => {
|
||||||
// default type
|
// default type
|
||||||
let sig = secp256k1::schnorrsig::Signature::from_slice(sl)
|
let sig = secp256k1::schnorr::Signature::from_slice(sl)
|
||||||
.map_err(SchnorrSigError::Secp256k1)?;
|
.map_err(SchnorrSigError::Secp256k1)?;
|
||||||
return Ok( SchnorrSig { sig, hash_ty : SchnorrSigHashType::Default });
|
return Ok( SchnorrSig { sig, hash_ty : SchnorrSigHashType::Default });
|
||||||
},
|
},
|
||||||
|
@ -133,7 +133,7 @@ impl SchnorrSig {
|
||||||
let (hash_ty, sig) = sl.split_last().expect("Slice len checked == 65");
|
let (hash_ty, sig) = sl.split_last().expect("Slice len checked == 65");
|
||||||
let hash_ty = SchnorrSigHashType::from_u8(*hash_ty)
|
let hash_ty = SchnorrSigHashType::from_u8(*hash_ty)
|
||||||
.map_err(|_| SchnorrSigError::InvalidSighashType(*hash_ty))?;
|
.map_err(|_| SchnorrSigError::InvalidSighashType(*hash_ty))?;
|
||||||
let sig = secp256k1::schnorrsig::Signature::from_slice(sig)
|
let sig = secp256k1::schnorr::Signature::from_slice(sig)
|
||||||
.map_err(SchnorrSigError::Secp256k1)?;
|
.map_err(SchnorrSigError::Secp256k1)?;
|
||||||
Ok(SchnorrSig { sig, hash_ty })
|
Ok(SchnorrSig { sig, hash_ty })
|
||||||
}
|
}
|
||||||
|
|
|
@ -754,7 +754,7 @@ mod tests {
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use hashes::hex::ToHex;
|
use hashes::hex::ToHex;
|
||||||
use util::taproot::{TapTweakHash, TapSighashHash, TapBranchHash, TapLeafHash};
|
use util::taproot::{TapTweakHash, TapSighashHash, TapBranchHash, TapLeafHash};
|
||||||
use secp256k1::{self, SecretKey};
|
use secp256k1::{self, SecretKey, XOnlyPublicKey};
|
||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
|
|
||||||
use {Script, Transaction, TxIn, TxOut};
|
use {Script, Transaction, TxIn, TxOut};
|
||||||
|
@ -1043,23 +1043,22 @@ mod tests {
|
||||||
};
|
};
|
||||||
let hash_ty = SchnorrSigHashType::from_u8(inp["given"]["hashType"].as_u64().unwrap() as u8).unwrap();
|
let hash_ty = SchnorrSigHashType::from_u8(inp["given"]["hashType"].as_u64().unwrap() as u8).unwrap();
|
||||||
|
|
||||||
use schnorr::PublicKey as XOnlyPubKey;
|
let expected_internal_pk = hex_hash!(XOnlyPublicKey, inp["intermediary"]["internalPubkey"].as_str().unwrap());
|
||||||
let expected_internal_pk = hex_hash!(XOnlyPubKey, 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());
|
||||||
let _expected_tweaked_priv_key = hex_hash!(SecretKey, inp["intermediary"]["tweakedPrivkey"].as_str().unwrap());
|
let expected_tweaked_priv_key = hex_hash!(SecretKey, inp["intermediary"]["tweakedPrivkey"].as_str().unwrap());
|
||||||
let expected_sig_msg = Vec::<u8>::from_hex(inp["intermediary"]["sigMsg"].as_str().unwrap()).unwrap();
|
let expected_sig_msg = Vec::<u8>::from_hex(inp["intermediary"]["sigMsg"].as_str().unwrap()).unwrap();
|
||||||
let expected_sig_hash = hex_hash!(TapSighashHash, inp["intermediary"]["sigHash"].as_str().unwrap());
|
let expected_sig_hash = hex_hash!(TapSighashHash, inp["intermediary"]["sigHash"].as_str().unwrap());
|
||||||
let sig_str = inp["expected"]["witness"][0].as_str().unwrap();
|
let sig_str = inp["expected"]["witness"][0].as_str().unwrap();
|
||||||
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::schnorrsig::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::from_u8(Vec::<u8>::from_hex(&sig_str[128..]).unwrap()[0]).unwrap();
|
||||||
(secp256k1::schnorrsig::Signature::from_str(&sig_str[..128]).unwrap(), hash_ty)
|
(secp256k1::schnorr::Signature::from_str(&sig_str[..128]).unwrap(), hash_ty)
|
||||||
};
|
};
|
||||||
|
|
||||||
// tests
|
// tests
|
||||||
let keypair = secp256k1::schnorrsig::KeyPair::from_secret_key(&secp, internal_priv_key);
|
let keypair = secp256k1::KeyPair::from_secret_key(&secp, internal_priv_key);
|
||||||
let internal_key = XOnlyPubKey::from_keypair(secp, &keypair);
|
let internal_key = XOnlyPublicKey::from_keypair(&keypair);
|
||||||
let tweak = TapTweakHash::from_key_and_tweak(internal_key, merkle_root);
|
let tweak = TapTweakHash::from_key_and_tweak(internal_key, merkle_root);
|
||||||
let mut tweaked_keypair = keypair;
|
let mut tweaked_keypair = keypair;
|
||||||
tweaked_keypair.tweak_add_assign(&secp, &tweak).unwrap();
|
tweaked_keypair.tweak_add_assign(&secp, &tweak).unwrap();
|
||||||
|
@ -1081,7 +1080,7 @@ mod tests {
|
||||||
).unwrap();
|
).unwrap();
|
||||||
|
|
||||||
let msg = secp256k1::Message::from_slice(&sig_hash).unwrap();
|
let msg = secp256k1::Message::from_slice(&sig_hash).unwrap();
|
||||||
let key_spend_sig = secp.schnorrsig_sign_with_aux_rand(&msg, &tweaked_keypair, &[0u8; 32]);
|
let key_spend_sig = secp.sign_schnorr_with_aux_rand(&msg, &tweaked_keypair, &[0u8; 32]);
|
||||||
|
|
||||||
assert_eq!(expected_internal_pk, internal_key);
|
assert_eq!(expected_internal_pk, internal_key);
|
||||||
assert_eq!(expected_tweak, tweak);
|
assert_eq!(expected_tweak, tweak);
|
||||||
|
@ -1089,9 +1088,9 @@ mod tests {
|
||||||
assert_eq!(expected_sig_hash, sig_hash);
|
assert_eq!(expected_sig_hash, sig_hash);
|
||||||
assert_eq!(expected_hash_ty, hash_ty);
|
assert_eq!(expected_hash_ty, hash_ty);
|
||||||
assert_eq!(expected_key_spend_sig, key_spend_sig);
|
assert_eq!(expected_key_spend_sig, key_spend_sig);
|
||||||
// TODO: Uncomment these after a rust-secp release
|
|
||||||
// let tweaked_priv_key = SecretKey::from_keypair(&tweaked_keypair);
|
let tweaked_priv_key = SecretKey::from_keypair(&tweaked_keypair);
|
||||||
// assert_eq!(expected_tweaked_priv_key, tweaked_priv_key);
|
assert_eq!(expected_tweaked_priv_key, tweaked_priv_key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -175,7 +175,7 @@ pub struct TaprootSpendInfo {
|
||||||
/// The Merkle root of the script tree (None if there are no scripts)
|
/// The Merkle root of the script tree (None if there are no scripts)
|
||||||
merkle_root: Option<TapBranchHash>,
|
merkle_root: Option<TapBranchHash>,
|
||||||
/// The sign final output pubkey as per BIP 341
|
/// The sign final output pubkey as per BIP 341
|
||||||
output_key_parity: bool,
|
output_key_parity: secp256k1::Parity,
|
||||||
/// The tweaked output key
|
/// The tweaked output key
|
||||||
output_key: TweakedPublicKey,
|
output_key: TweakedPublicKey,
|
||||||
/// Map from (script, leaf_version) to (sets of) [`TaprootMerkleBranch`].
|
/// Map from (script, leaf_version) to (sets of) [`TaprootMerkleBranch`].
|
||||||
|
@ -288,7 +288,7 @@ impl TaprootSpendInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parity of the output key. See also [`TaprootSpendInfo::output_key`]
|
/// Parity of the output key. See also [`TaprootSpendInfo::output_key`]
|
||||||
pub fn output_key_parity(&self) -> bool {
|
pub fn output_key_parity(&self) -> secp256k1::Parity {
|
||||||
self.output_key_parity
|
self.output_key_parity
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -657,7 +657,7 @@ pub struct ControlBlock {
|
||||||
/// The tapleaf version,
|
/// The tapleaf version,
|
||||||
pub leaf_version: LeafVersion,
|
pub leaf_version: LeafVersion,
|
||||||
/// The parity of the output key (NOT THE INTERNAL KEY WHICH IS ALWAYS XONLY)
|
/// The parity of the output key (NOT THE INTERNAL KEY WHICH IS ALWAYS XONLY)
|
||||||
pub output_key_parity: bool,
|
pub output_key_parity: secp256k1::Parity,
|
||||||
/// The internal key
|
/// The internal key
|
||||||
pub internal_key: UntweakedPublicKey,
|
pub internal_key: UntweakedPublicKey,
|
||||||
/// The merkle proof of a script associated with this leaf
|
/// The merkle proof of a script associated with this leaf
|
||||||
|
@ -679,7 +679,7 @@ impl ControlBlock {
|
||||||
{
|
{
|
||||||
return Err(TaprootError::InvalidControlBlockSize(sl.len()));
|
return Err(TaprootError::InvalidControlBlockSize(sl.len()));
|
||||||
}
|
}
|
||||||
let output_key_parity = (sl[0] & 1) == 1;
|
let output_key_parity = secp256k1::Parity::from((sl[0] & 1) as i32);
|
||||||
let leaf_version = LeafVersion::from_u8(sl[0] & TAPROOT_LEAF_MASK)?;
|
let leaf_version = LeafVersion::from_u8(sl[0] & TAPROOT_LEAF_MASK)?;
|
||||||
let internal_key = UntweakedPublicKey::from_slice(&sl[1..TAPROOT_CONTROL_BASE_SIZE])
|
let internal_key = UntweakedPublicKey::from_slice(&sl[1..TAPROOT_CONTROL_BASE_SIZE])
|
||||||
.map_err(TaprootError::InvalidInternalKey)?;
|
.map_err(TaprootError::InvalidInternalKey)?;
|
||||||
|
@ -700,8 +700,7 @@ impl ControlBlock {
|
||||||
|
|
||||||
/// Serialize to a writer. Returns the number of bytes written
|
/// Serialize to a writer. Returns the number of bytes written
|
||||||
pub fn encode<Write: io::Write>(&self, mut writer: Write) -> io::Result<usize> {
|
pub fn encode<Write: io::Write>(&self, mut writer: Write) -> io::Result<usize> {
|
||||||
let first_byte: u8 =
|
let first_byte: u8 = i32::from(self.output_key_parity) as u8 | self.leaf_version.as_u8();
|
||||||
(if self.output_key_parity { 1 } else { 0 }) | self.leaf_version.as_u8();
|
|
||||||
let mut bytes_written = 0;
|
let mut bytes_written = 0;
|
||||||
bytes_written += writer.write(&[first_byte])?;
|
bytes_written += writer.write(&[first_byte])?;
|
||||||
bytes_written += writer.write(&self.internal_key.serialize())?;
|
bytes_written += writer.write(&self.internal_key.serialize())?;
|
||||||
|
@ -909,9 +908,8 @@ mod test {
|
||||||
use hashes::hex::{FromHex, ToHex};
|
use hashes::hex::{FromHex, ToHex};
|
||||||
use hashes::sha256t::Tag;
|
use hashes::sha256t::Tag;
|
||||||
use hashes::{sha256, Hash, HashEngine};
|
use hashes::{sha256, Hash, HashEngine};
|
||||||
use secp256k1::VerifyOnly;
|
use secp256k1::{VerifyOnly, XOnlyPublicKey};
|
||||||
use core::str::FromStr;
|
use core::str::FromStr;
|
||||||
use schnorr;
|
|
||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
|
|
||||||
fn tag_engine(tag_name: &str) -> sha256::HashEngine {
|
fn tag_engine(tag_name: &str) -> sha256::HashEngine {
|
||||||
|
@ -996,7 +994,7 @@ mod test {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _verify_tap_commitments(secp: &Secp256k1<VerifyOnly>, out_spk_hex: &str, script_hex : &str, control_block_hex: &str) {
|
fn _verify_tap_commitments(secp: &Secp256k1<VerifyOnly>, out_spk_hex: &str, script_hex : &str, control_block_hex: &str) {
|
||||||
let out_pk = schnorr::PublicKey::from_str(&out_spk_hex[4..]).unwrap();
|
let out_pk = XOnlyPublicKey::from_str(&out_spk_hex[4..]).unwrap();
|
||||||
let out_pk = TweakedPublicKey::dangerous_assume_tweaked(out_pk);
|
let out_pk = TweakedPublicKey::dangerous_assume_tweaked(out_pk);
|
||||||
let script = Script::from_hex(script_hex).unwrap();
|
let script = Script::from_hex(script_hex).unwrap();
|
||||||
let control_block = ControlBlock::from_slice(&Vec::<u8>::from_hex(control_block_hex).unwrap()).unwrap();
|
let control_block = ControlBlock::from_slice(&Vec::<u8>::from_hex(control_block_hex).unwrap()).unwrap();
|
||||||
|
@ -1152,7 +1150,7 @@ mod test {
|
||||||
let secp = &secp256k1::Secp256k1::verification_only();
|
let secp = &secp256k1::Secp256k1::verification_only();
|
||||||
|
|
||||||
for arr in data["scriptPubKey"].as_array().unwrap() {
|
for arr in data["scriptPubKey"].as_array().unwrap() {
|
||||||
let internal_key = schnorr::PublicKey::from_str(arr["given"]["internalPubkey"].as_str().unwrap()).unwrap();
|
let internal_key = XOnlyPublicKey::from_str(arr["given"]["internalPubkey"].as_str().unwrap()).unwrap();
|
||||||
// process the tree
|
// process the tree
|
||||||
let script_tree = &arr["given"]["scriptTree"];
|
let script_tree = &arr["given"]["scriptTree"];
|
||||||
let mut merkle_root = None;
|
let mut merkle_root = None;
|
||||||
|
@ -1176,7 +1174,7 @@ mod test {
|
||||||
assert_eq!(ctrl_blk, expected_ctrl_blk);
|
assert_eq!(ctrl_blk, expected_ctrl_blk);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let expected_output_key = schnorr::PublicKey::from_str(arr["intermediary"]["tweakedPubkey"].as_str().unwrap()).unwrap();
|
let expected_output_key = XOnlyPublicKey::from_str(arr["intermediary"]["tweakedPubkey"].as_str().unwrap()).unwrap();
|
||||||
let expected_tweak = TapTweakHash::from_str(arr["intermediary"]["tweak"].as_str().unwrap()).unwrap();
|
let expected_tweak = TapTweakHash::from_str(arr["intermediary"]["tweak"].as_str().unwrap()).unwrap();
|
||||||
let expected_spk = Script::from_str(arr["expected"]["scriptPubKey"].as_str().unwrap()).unwrap();
|
let expected_spk = Script::from_str(arr["expected"]["scriptPubKey"].as_str().unwrap()).unwrap();
|
||||||
let expected_addr = Address::from_str(arr["expected"]["bip350Address"].as_str().unwrap()).unwrap();
|
let expected_addr = Address::from_str(arr["expected"]["bip350Address"].as_str().unwrap()).unwrap();
|
||||||
|
|
Loading…
Reference in New Issue