Skip to content

Commit 998972a

Browse files
committed
a113e35923dc094b2554209d2042ac8d7683ebb7 Release 9.0.0 (sanket1729) 63ceb5b38d641c543f01f955728627ea2a89444a Add psbt example for sign and finalize (sanket1729) 8f869926714c5c7273b217bd3f72d5cab26d6560 Don't run rawpkh logic through pkh (sanket1729) 815fd1c9b368f800bb67d1ecdd49c533394d4b8c Bug fix: pkh->pk lookup API (sanket1729) 43abc43bb0b83ca9da61f80ed3cc848e4e34d762 Use expr_raw_pk_h for Terminal::RawPkH (sanket1729) Pull request description: - Cleanup some pkh code in satisfaction - Fixes #483 - Fixes another bug dealing with dissatisfaction of thresh inside pkh - Adds example test vector from discussions - release 9.0.0 with above fixes ACKs for top commit: apoelstra: ACK a113e35923dc094b2554209d2042ac8d7683ebb7 Tree-SHA512: 373d80c5bc03032635ce0dfe6426b17970f1590012482ad3cc76b37337fe2f53e51b32e1fe11c449ec38bf4d4a0ba62d38f7316a148773e2b1854b8f9f1a877c
2 parents b9ff307 + 376ece9 commit 998972a

File tree

7 files changed

+293
-31
lines changed

7 files changed

+293
-31
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
# 9.0.0 - November 5, 2022
2+
3+
- Fixed a bug dealing with dissatisfying pkh inside thresh
4+
- Changed the signature of `Satisfier::lookup_raw_pkh_pk` API. Only custom implementations
5+
of `Satisfier` need to be updated. The psbt APIs are unchanged.
6+
- Fixed a bug related to display of `raw_pk_h`. These descriptors are experimental
7+
and only usable by opting via `ExtParams` while parsing string.
18
# 8.0.0 - October 20, 2022
29

310
This release contains several significant API overhauls, as well as a bump

Cargo.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "miniscript"
3-
version = "8.0.0"
3+
version = "9.0.0"
44
authors = ["Andrew Poelstra <[email protected]>, Sanket Kanjalkar <[email protected]>"]
55
license = "CC0-1.0"
66
homepage = "https://github.com/rust-bitcoin/rust-miniscript/"
@@ -60,3 +60,7 @@ required-features = ["std"]
6060
[[example]]
6161
name = "taproot"
6262
required-features = ["compiler","std"]
63+
64+
[[example]]
65+
name = "psbt_sign_finalize"
66+
required-features = ["std"]

contrib/test.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ then
6868
cargo run --example psbt
6969
cargo run --example xpub_descriptors
7070
cargo run --example taproot --features=compiler
71+
cargo run --example psbt_sign_finalize
7172
fi
7273

7374
if [ "$DO_NO_STD" = true ]

examples/psbt_sign_finalize.rs

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
use std::collections::BTreeMap;
2+
use std::str::FromStr;
3+
4+
use bitcoin::consensus::serialize;
5+
use bitcoin::util::sighash::SighashCache;
6+
use bitcoin::{PackedLockTime, PrivateKey};
7+
use bitcoind::bitcoincore_rpc::jsonrpc::base64;
8+
use bitcoind::bitcoincore_rpc::RawTx;
9+
use miniscript::bitcoin::consensus::encode::deserialize;
10+
use miniscript::bitcoin::hashes::hex::FromHex;
11+
use miniscript::bitcoin::util::psbt;
12+
use miniscript::bitcoin::util::psbt::PartiallySignedTransaction as Psbt;
13+
use miniscript::bitcoin::{
14+
self, secp256k1, Address, Network, OutPoint, Script, Sequence, Transaction, TxIn, TxOut,
15+
};
16+
use miniscript::psbt::{PsbtExt, PsbtInputExt};
17+
use miniscript::Descriptor;
18+
19+
fn main() {
20+
let secp256k1 = secp256k1::Secp256k1::new();
21+
22+
let s = "wsh(t:or_c(pk(027a3565454fe1b749bccaef22aff72843a9c3efefd7b16ac54537a0c23f0ec0de),v:thresh(1,pkh(032d672a1a91cc39d154d366cd231983661b0785c7f27bc338447565844f4a6813),a:pkh(03417129311ed34c242c012cd0a3e0b9bca0065f742d0dfb63c78083ea6a02d4d9),a:pkh(025a687659658baeabdfc415164528065be7bcaade19342241941e556557f01e28))))#7hut9ukn";
23+
let bridge_descriptor = Descriptor::from_str(&s).unwrap();
24+
//let bridge_descriptor = Descriptor::<bitcoin::PublicKey>::from_str(&s).expect("parse descriptor string");
25+
assert!(bridge_descriptor.sanity_check().is_ok());
26+
println!(
27+
"Bridge pubkey script: {}",
28+
bridge_descriptor.script_pubkey()
29+
);
30+
println!(
31+
"Bridge address: {}",
32+
bridge_descriptor.address(Network::Regtest).unwrap()
33+
);
34+
println!(
35+
"Weight for witness satisfaction cost {}",
36+
bridge_descriptor.max_satisfaction_weight().unwrap()
37+
);
38+
39+
let master_private_key_str = "cQhdvB3McbBJdx78VSSumqoHQiSXs75qwLptqwxSQBNBMDxafvaw";
40+
let _master_private_key =
41+
PrivateKey::from_str(master_private_key_str).expect("Can't create private key");
42+
println!(
43+
"Master public key: {}",
44+
_master_private_key.public_key(&secp256k1)
45+
);
46+
47+
let backup1_private_key_str = "cWA34TkfWyHa3d4Vb2jNQvsWJGAHdCTNH73Rht7kAz6vQJcassky";
48+
let backup1_private =
49+
PrivateKey::from_str(backup1_private_key_str).expect("Can't create private key");
50+
51+
println!(
52+
"Backup1 public key: {}",
53+
backup1_private.public_key(&secp256k1)
54+
);
55+
56+
let backup2_private_key_str = "cPJFWUKk8sdL7pcDKrmNiWUyqgovimmhaaZ8WwsByDaJ45qLREkh";
57+
let backup2_private =
58+
PrivateKey::from_str(backup2_private_key_str).expect("Can't create private key");
59+
60+
println!(
61+
"Backup2 public key: {}",
62+
backup2_private.public_key(&secp256k1)
63+
);
64+
65+
let backup3_private_key_str = "cT5cH9UVm81W5QAf5KABXb23RKNSMbMzMx85y6R2mF42L94YwKX6";
66+
let _backup3_private =
67+
PrivateKey::from_str(backup3_private_key_str).expect("Can't create private key");
68+
69+
println!(
70+
"Backup3 public key: {}",
71+
_backup3_private.public_key(&secp256k1)
72+
);
73+
74+
let spend_tx = Transaction {
75+
version: 2,
76+
lock_time: PackedLockTime(5000),
77+
input: vec![],
78+
output: vec![],
79+
};
80+
81+
// Spend one input and spend one output for simplicity.
82+
let mut psbt = Psbt {
83+
unsigned_tx: spend_tx,
84+
unknown: BTreeMap::new(),
85+
proprietary: BTreeMap::new(),
86+
xpub: BTreeMap::new(),
87+
version: 0,
88+
inputs: vec![],
89+
outputs: vec![],
90+
};
91+
92+
let hex_tx = "020000000001018ff27041f3d738f5f84fd5ee62f1c5b36afebfb15f6da0c9d1382ddd0eaaa23c0000000000feffffff02b3884703010000001600142ca3b4e53f17991582d47b15a053b3201891df5200e1f50500000000220020c0ebf552acd2a6f5dee4e067daaef17b3521e283aeaa44a475278617e3d2238a0247304402207b820860a9d425833f729775880b0ed59dd12b64b9a3d1ab677e27e4d6b370700220576003163f8420fe0b9dc8df726cff22cbc191104a2d4ae4f9dfedb087fcec72012103817e1da42a7701df4db94db8576f0e3605f3ab3701608b7e56f92321e4d8999100000000";
93+
let depo_tx: Transaction = deserialize(&Vec::<u8>::from_hex(hex_tx).unwrap()).unwrap();
94+
95+
let receiver = Address::from_str("bcrt1qsdks5za4t6sevaph6tz9ddfjzvhkdkxe9tfrcy").unwrap();
96+
97+
let amount = 100000000;
98+
99+
let (outpoint, witness_utxo) = get_vout(&depo_tx, bridge_descriptor.script_pubkey());
100+
101+
let mut txin = TxIn::default();
102+
txin.previous_output = outpoint;
103+
104+
txin.sequence = Sequence::from_height(26); //Sequence::MAX; //
105+
psbt.unsigned_tx.input.push(txin);
106+
107+
psbt.unsigned_tx.output.push(TxOut {
108+
script_pubkey: receiver.script_pubkey(),
109+
value: amount / 5 - 500,
110+
});
111+
112+
psbt.unsigned_tx.output.push(TxOut {
113+
script_pubkey: bridge_descriptor.script_pubkey(),
114+
value: amount * 4 / 5,
115+
});
116+
117+
// Generating signatures & witness data
118+
119+
let mut input = psbt::Input::default();
120+
input
121+
.update_with_descriptor_unchecked(&bridge_descriptor)
122+
.unwrap();
123+
124+
input.witness_utxo = Some(witness_utxo.clone());
125+
psbt.inputs.push(input);
126+
psbt.outputs.push(psbt::Output::default());
127+
128+
let mut sighash_cache = SighashCache::new(&psbt.unsigned_tx);
129+
130+
let msg = psbt
131+
.sighash_msg(0, &mut sighash_cache, None)
132+
.unwrap()
133+
.to_secp_msg();
134+
135+
// Fixme: Take a parameter
136+
let hash_ty = bitcoin::EcdsaSighashType::All;
137+
138+
let sk1 = backup1_private.inner;
139+
let sk2 = backup2_private.inner;
140+
141+
// Finally construct the signature and add to psbt
142+
let sig1 = secp256k1.sign_ecdsa(&msg, &sk1);
143+
let pk1 = backup1_private.public_key(&secp256k1);
144+
assert!(secp256k1.verify_ecdsa(&msg, &sig1, &pk1.inner).is_ok());
145+
146+
// Second key just in case
147+
let sig2 = secp256k1.sign_ecdsa(&msg, &sk2);
148+
let pk2 = backup2_private.public_key(&secp256k1);
149+
assert!(secp256k1.verify_ecdsa(&msg, &sig2, &pk2.inner).is_ok());
150+
151+
psbt.inputs[0].partial_sigs.insert(
152+
pk1,
153+
bitcoin::EcdsaSig {
154+
sig: sig1,
155+
hash_ty: hash_ty,
156+
},
157+
);
158+
159+
println!("{:#?}", psbt);
160+
161+
let serialized = serialize(&psbt);
162+
println!("{}", base64::encode(&serialized));
163+
164+
psbt.finalize_mut(&secp256k1).unwrap();
165+
println!("{:#?}", psbt);
166+
167+
let tx = psbt.extract_tx();
168+
println!("{}", tx.raw_hex());
169+
}
170+
171+
// Find the Outpoint by spk
172+
fn get_vout(tx: &Transaction, spk: Script) -> (OutPoint, TxOut) {
173+
for (i, txout) in tx.clone().output.into_iter().enumerate() {
174+
if spk == txout.script_pubkey {
175+
return (OutPoint::new(tx.txid(), i as u32), txout);
176+
}
177+
}
178+
panic!("Only call get vout on functions which have the expected outpoint");
179+
}

src/miniscript/astelem.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> fmt::Debug for Terminal<Pk, Ctx> {
253253
match *self {
254254
Terminal::PkK(ref pk) => write!(f, "pk_k({:?})", pk),
255255
Terminal::PkH(ref pk) => write!(f, "pk_h({:?})", pk),
256-
Terminal::RawPkH(ref pkh) => write!(f, "pk_h({:?})", pkh),
256+
Terminal::RawPkH(ref pkh) => write!(f, "expr_raw_pk_h({:?})", pkh),
257257
Terminal::After(t) => write!(f, "after({})", t),
258258
Terminal::Older(t) => write!(f, "older({})", t),
259259
Terminal::Sha256(ref h) => write!(f, "sha256({})", h),
@@ -307,7 +307,7 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> fmt::Display for Terminal<Pk, Ctx> {
307307
match *self {
308308
Terminal::PkK(ref pk) => write!(f, "pk_k({})", pk),
309309
Terminal::PkH(ref pk) => write!(f, "pk_h({})", pk),
310-
Terminal::RawPkH(ref pkh) => write!(f, "pk_h({})", pkh),
310+
Terminal::RawPkH(ref pkh) => write!(f, "expr_raw_pk_h({})", pkh),
311311
Terminal::After(t) => write!(f, "after({})", t),
312312
Terminal::Older(t) => write!(f, "older({})", t),
313313
Terminal::Sha256(ref h) => write!(f, "sha256({})", h),

0 commit comments

Comments
 (0)