Skip to content

Commit a7bfff4

Browse files
committed
Merge #488: Release 9.0.0
a113e35 Release 9.0.0 (sanket1729) 63ceb5b Add psbt example for sign and finalize (sanket1729) 8f86992 Don't run rawpkh logic through pkh (sanket1729) 815fd1c Bug fix: pkh->pk lookup API (sanket1729) 43abc43 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 a113e35 Tree-SHA512: 373d80c5bc03032635ce0dfe6426b17970f1590012482ad3cc76b37337fe2f53e51b32e1fe11c449ec38bf4d4a0ba62d38f7316a148773e2b1854b8f9f1a877c
2 parents 61210a0 + a113e35 commit a7bfff4

File tree

7 files changed

+293
-31
lines changed

7 files changed

+293
-31
lines changed

CHANGELOG.md

+7
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

+5-1
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

+1
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

+179
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

+2-2
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)