Skip to content

Commit 8aed9dd

Browse files
committed
Make BitcoinECSig a struct
1 parent 8e780c5 commit 8aed9dd

File tree

9 files changed

+81
-50
lines changed

9 files changed

+81
-50
lines changed

examples/sign_multisig.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ extern crate bitcoin;
1818
extern crate miniscript;
1919

2020
use bitcoin::secp256k1; // secp256k1 re-exported from rust-bitcoin
21-
use miniscript::DescriptorTrait;
21+
use miniscript::{BitcoinECSig, DescriptorTrait};
2222
use std::collections::HashMap;
2323
use std::str::FromStr;
2424

@@ -60,19 +60,19 @@ fn main() {
6060
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6161
]).expect("key 3"),
6262
];
63-
let bitcoin_sig = (
63+
let bitcoin_sig = BitcoinECSig {
6464
// copied at random off the blockchain; this is not actually a valid
6565
// signature for this transaction; Miniscript does not verify
66-
secp256k1::Signature::from_str(
66+
sig: secp256k1::Signature::from_str(
6767
"3045\
6868
0221\
6969
00f7c3648c390d87578cd79c8016940aa8e3511c4104cb78daa8fb8e429375efc1\
7070
0220\
7171
531d75c136272f127a5dc14acc0722301cbddc222262934151f140da345af177",
7272
)
7373
.unwrap(),
74-
bitcoin::SigHashType::All,
75-
);
74+
hash_ty: bitcoin::SigHashType::All,
75+
};
7676

7777
let descriptor_str = format!(
7878
"wsh(multi(2,{},{},{}))",

examples/verify_tx.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ fn main() {
140140
// Restrict to sighash_all just to demonstrate how to add additional filters
141141
// `&_` needed here because of https://github.com/rust-lang/rust/issues/79187
142142
let vfyfn = move |pk: &_, bitcoinsig: miniscript::BitcoinECSig| {
143-
bitcoinsig.1 == bitcoin::SigHashType::All && vfyfn(pk, bitcoinsig)
143+
bitcoinsig.hash_ty == bitcoin::SigHashType::All && vfyfn(pk, bitcoinsig)
144144
};
145145

146146
println!("\nExample two");
@@ -167,8 +167,9 @@ fn main() {
167167
)
168168
.unwrap();
169169

170-
let iter = interpreter.iter(|pk, (sig, sighashtype)| {
171-
sighashtype == bitcoin::SigHashType::All && secp.verify(&message, &sig, &pk.key).is_ok()
170+
let iter = interpreter.iter(|pk, btc_sig| {
171+
btc_sig.hash_ty == bitcoin::SigHashType::All
172+
&& secp.verify(&message, &btc_sig.sig, &pk.key).is_ok()
172173
});
173174
println!("\nExample three");
174175
for elem in iter {

src/descriptor/bare.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -324,11 +324,9 @@ impl<Pk: MiniscriptKey> DescriptorTrait<Pk> for Pkh<Pk> {
324324
Pk: ToPublicKey,
325325
S: Satisfier<Pk>,
326326
{
327-
if let Some(sig) = satisfier.lookup_ec_sig(&self.pk) {
328-
let mut sig_vec = sig.0.serialize_der().to_vec();
329-
sig_vec.push(sig.1.as_u32() as u8);
327+
if let Some(btc_sig) = satisfier.lookup_ec_sig(&self.pk) {
330328
let script_sig = script::Builder::new()
331-
.push_slice(&sig_vec[..])
329+
.push_slice(&btc_sig.serialize())
332330
.push_key(&self.pk.to_public_key())
333331
.into_script();
334332
let witness = vec![];

src/descriptor/mod.rs

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -926,7 +926,10 @@ mod tests {
926926
impl Satisfier<bitcoin::PublicKey> for SimpleSat {
927927
fn lookup_ec_sig(&self, pk: &bitcoin::PublicKey) -> Option<BitcoinECSig> {
928928
if *pk == self.pk {
929-
Some((self.sig, bitcoin::SigHashType::All))
929+
Some(BitcoinECSig {
930+
sig: self.sig,
931+
hash_ty: bitcoin::SigHashType::All,
932+
})
930933
} else {
931934
None
932935
}
@@ -1135,8 +1138,20 @@ mod tests {
11351138
let satisfier = {
11361139
let mut satisfier = HashMap::with_capacity(2);
11371140

1138-
satisfier.insert(a, (sig_a.clone(), ::bitcoin::SigHashType::All));
1139-
satisfier.insert(b, (sig_b.clone(), ::bitcoin::SigHashType::All));
1141+
satisfier.insert(
1142+
a,
1143+
BitcoinECSig {
1144+
sig: sig_a.clone(),
1145+
hash_ty: bitcoin::SigHashType::All,
1146+
},
1147+
);
1148+
satisfier.insert(
1149+
b,
1150+
BitcoinECSig {
1151+
sig: sig_b.clone(),
1152+
hash_ty: bitcoin::SigHashType::All,
1153+
},
1154+
);
11401155

11411156
satisfier
11421157
};

src/descriptor/segwitv0.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -422,11 +422,9 @@ impl<Pk: MiniscriptKey> DescriptorTrait<Pk> for Wpkh<Pk> {
422422
Pk: ToPublicKey,
423423
S: Satisfier<Pk>,
424424
{
425-
if let Some(sig) = satisfier.lookup_ec_sig(&self.pk) {
426-
let mut sig_vec = sig.0.serialize_der().to_vec();
427-
sig_vec.push(sig.1.as_u32() as u8);
425+
if let Some(btc_sig) = satisfier.lookup_ec_sig(&self.pk) {
428426
let script_sig = Script::new();
429-
let witness = vec![sig_vec, self.pk.to_public_key().to_bytes()];
427+
let witness = vec![btc_sig.serialize(), self.pk.to_public_key().to_bytes()];
430428
Ok((witness, script_sig))
431429
} else {
432430
Err(Error::MissingSig(self.pk.to_public_key()))

src/interpreter/mod.rs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -216,18 +216,18 @@ impl<'txin> Interpreter<'txin> {
216216
)?,
217217
];
218218

219-
Ok(move |pk: &bitcoin::PublicKey, (sig, sighash_type)| {
219+
Ok(move |pk: &bitcoin::PublicKey, btc_sig: BitcoinECSig| {
220220
// This is an awkward way to do this lookup, but it lets us do exhaustiveness
221221
// checking in case future rust-bitcoin versions add new sighash types
222-
let sighash = match sighash_type {
222+
let sighash = match btc_sig.hash_ty {
223223
bitcoin::SigHashType::All => sighashes[0],
224224
bitcoin::SigHashType::None => sighashes[1],
225225
bitcoin::SigHashType::Single => sighashes[2],
226226
bitcoin::SigHashType::AllPlusAnyoneCanPay => sighashes[3],
227227
bitcoin::SigHashType::NonePlusAnyoneCanPay => sighashes[4],
228228
bitcoin::SigHashType::SinglePlusAnyoneCanPay => sighashes[5],
229229
};
230-
secp.verify(&sighash, &sig, &pk.key).is_ok()
230+
secp.verify(&sighash, &btc_sig.sig, &pk.key).is_ok()
231231
})
232232
}
233233
}
@@ -757,10 +757,11 @@ where
757757
F: FnOnce(&bitcoin::PublicKey, BitcoinECSig) -> bool,
758758
{
759759
if let Some((sighash_byte, sig)) = sigser.split_last() {
760-
let sighashtype = bitcoin::SigHashType::from_u32_standard(*sighash_byte as u32)
760+
let hash_ty = bitcoin::SigHashType::from_u32_standard(*sighash_byte as u32)
761761
.map_err(|_| Error::NonStandardSigHash([sig, &[*sighash_byte]].concat().to_vec()))?;
762762
let sig = secp256k1::Signature::from_der(sig)?;
763-
if verify_sig(pk, (sig, sighashtype)) {
763+
let btc_sig = BitcoinECSig { sig, hash_ty };
764+
if verify_sig(pk, btc_sig) {
764765
Ok(sig)
765766
} else {
766767
Err(Error::InvalidSignature(*pk))
@@ -823,8 +824,9 @@ mod tests {
823824
#[test]
824825
fn sat_constraints() {
825826
let (pks, der_sigs, secp_sigs, sighash, secp) = setup_keys_sigs(10);
826-
let vfyfn_ =
827-
|pk: &bitcoin::PublicKey, (sig, _)| secp.verify(&sighash, &sig, &pk.key).is_ok();
827+
let vfyfn_ = |pk: &bitcoin::PublicKey, btc_sig: BitcoinECSig| {
828+
secp.verify(&sighash, &btc_sig.sig, &pk.key).is_ok()
829+
};
828830

829831
fn from_stack<'txin, 'elem, F>(
830832
verify_fn: F,

src/miniscript/satisfy.rs

Lines changed: 34 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -34,21 +34,41 @@ use Miniscript;
3434
use ScriptContext;
3535
use Terminal;
3636

37-
/// Type alias for a signature/hashtype pair
38-
pub type BitcoinECSig = (secp256k1::Signature, bitcoin::SigHashType);
37+
/// Type for a signature/hashtype pair
38+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
39+
pub struct BitcoinECSig {
40+
/// The underlying signature
41+
pub sig: secp256k1::Signature,
42+
/// The associated hash type
43+
pub hash_ty: bitcoin::SigHashType,
44+
}
3945
/// Type alias for 32 byte Preimage.
4046
pub type Preimage32 = [u8; 32];
4147

42-
/// Helper function to create BitcoinECSig from Rawsig
43-
/// Useful for downstream when implementing Satisfier.
44-
/// Returns underlying secp if the Signature is not of correct format
45-
pub fn bitcoin_ecsig_from_rawsig(rawsig: &[u8]) -> Result<BitcoinECSig, ::interpreter::Error> {
46-
let (flag, sig) = rawsig.split_last().unwrap();
47-
let flag = bitcoin::SigHashType::from_u32_standard(*flag as u32)
48-
.map_err(|_| ::interpreter::Error::NonStandardSigHash([sig, &[*flag]].concat().to_vec()))?;
49-
let sig = secp256k1::Signature::from_der(sig)?;
50-
Ok((sig, flag))
48+
impl BitcoinECSig {
49+
/// Helper function to create BitcoinECSig from Rawsig
50+
/// Useful for downstream when implementing Satisfier.
51+
/// Returns underlying secp if the Signature is not of correct format
52+
pub fn from_rawsig(rawsig: &[u8]) -> Result<BitcoinECSig, ::interpreter::Error> {
53+
let (flag, sig) = rawsig.split_last().unwrap();
54+
let flag = bitcoin::SigHashType::from_u32_standard(*flag as u32).map_err(|_| {
55+
::interpreter::Error::NonStandardSigHash([sig, &[*flag]].concat().to_vec())
56+
})?;
57+
let sig = secp256k1::Signature::from_der(sig)?;
58+
Ok(BitcoinECSig {
59+
sig: sig,
60+
hash_ty: flag,
61+
})
62+
}
63+
64+
/// Serialize BitcoinECSig
65+
pub fn serialize(&self) -> Vec<u8> {
66+
let mut ret = self.sig.serialize_der().to_vec();
67+
ret.push(self.hash_ty.as_u32() as u8);
68+
ret
69+
}
5170
}
71+
5272
/// Trait describing a lookup table for signatures, hash preimages, etc.
5373
/// Every method has a default implementation that simply returns `None`
5474
/// on every query. Users are expected to override the methods that they
@@ -403,11 +423,7 @@ impl Witness {
403423
/// Turn a signature into (part of) a satisfaction
404424
fn signature<Pk: ToPublicKey, S: Satisfier<Pk>>(sat: S, pk: &Pk) -> Self {
405425
match sat.lookup_ec_sig(pk) {
406-
Some((sig, hashtype)) => {
407-
let mut ret = sig.serialize_der().to_vec();
408-
ret.push(hashtype.as_u32() as u8);
409-
Witness::Stack(vec![ret])
410-
}
426+
Some(sig) => Witness::Stack(vec![sig.serialize()]),
411427
// Signatures cannot be forged
412428
None => Witness::Impossible,
413429
}
@@ -426,10 +442,8 @@ impl Witness {
426442
/// Turn a key/signature pair related to a pkh into (part of) a satisfaction
427443
fn pkh_signature<Pk: ToPublicKey, S: Satisfier<Pk>>(sat: S, pkh: &Pk::Hash) -> Self {
428444
match sat.lookup_pkh_ec_sig(pkh) {
429-
Some((pk, (sig, hashtype))) => {
430-
let mut ret = sig.serialize_der().to_vec();
431-
ret.push(hashtype.as_u32() as u8);
432-
Witness::Stack(vec![ret.to_vec(), pk.to_public_key().to_bytes()])
445+
Some((pk, btc_sig)) => {
446+
Witness::Stack(vec![btc_sig.serialize(), pk.to_public_key().to_bytes()])
433447
}
434448
None => Witness::Impossible,
435449
}

src/policy/compiler.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1363,7 +1363,10 @@ mod tests {
13631363
assert_eq!(abs.n_keys(), 5);
13641364
assert_eq!(abs.minimum_n_keys(), Some(3));
13651365

1366-
let bitcoinsig = (sig, SigHashType::All);
1366+
let bitcoinsig = BitcoinECSig {
1367+
sig: sig,
1368+
hash_ty: SigHashType::All,
1369+
};
13671370
let mut sigvec = sig.serialize_der().to_vec();
13681371
sigvec.push(1); // sighash all
13691372

src/psbt/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ use bitcoin::Script;
2929

3030
use interpreter;
3131
use miniscript::limits::SEQUENCE_LOCKTIME_DISABLE_FLAG;
32-
use miniscript::satisfy::{bitcoin_ecsig_from_rawsig, After, Older};
32+
use miniscript::satisfy::{After, Older};
3333
use Satisfier;
3434
use {BitcoinECSig, Preimage32};
3535
use {MiniscriptKey, ToPublicKey};
@@ -230,7 +230,7 @@ impl<'psbt, Pk: MiniscriptKey + ToPublicKey> Satisfier<Pk> for PsbtInputSatisfie
230230
{
231231
// We have already previously checked that all signatures have the
232232
// correct sighash flag.
233-
bitcoin_ecsig_from_rawsig(rawsig).ok()
233+
BitcoinECSig::from_rawsig(rawsig).ok()
234234
} else {
235235
None
236236
}
@@ -244,7 +244,7 @@ impl<'psbt, Pk: MiniscriptKey + ToPublicKey> Satisfier<Pk> for PsbtInputSatisfie
244244
.next()
245245
{
246246
// If the mapping is incorrect, return None
247-
bitcoin_ecsig_from_rawsig(sig)
247+
BitcoinECSig::from_rawsig(sig)
248248
.ok()
249249
.map(|bitcoinsig| (*pk, bitcoinsig))
250250
} else {

0 commit comments

Comments
 (0)