Skip to content

Commit 537f123

Browse files
committed
Update Control block verification
1 parent 34b712a commit 537f123

File tree

2 files changed

+38
-40
lines changed

2 files changed

+38
-40
lines changed

src/interpreter/error.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,6 @@ pub enum Error {
9797
SchnorrSig(bitcoin::SchnorrSigError),
9898
/// Errors in signature hash calculations
9999
SighashError(bitcoin::util::sighash::Error),
100-
/// Taproot Annex Unsupported
101-
TapAnnexUnsupported,
102100
/// An uncompressed public key was encountered in a context where it is
103101
/// disallowed (e.g. in a Segwit script or p2wpkh output)
104102
UncompressedPubkey,
@@ -246,7 +244,6 @@ impl fmt::Display for Error {
246244
Error::Secp(ref e) => fmt::Display::fmt(e, f),
247245
Error::SchnorrSig(ref s) => write!(f, "Schnorr sig error: {}", s),
248246
Error::SighashError(ref e) => fmt::Display::fmt(e, f),
249-
Error::TapAnnexUnsupported => f.write_str("Encounter Annex element"),
250247
Error::UncompressedPubkey => {
251248
f.write_str("uncompressed pubkey in non-legacy descriptor")
252249
}

src/interpreter/inner.rs

Lines changed: 38 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,18 @@ pub(super) fn from_txdata<'txin>(
208208
} else {
209209
let output_key = bitcoin::XOnlyPublicKey::from_slice(&spk[2..])
210210
.map_err(|_| Error::XOnlyPublicKeyParseError)?;
211+
if wit_stack.len() >= 2 {
212+
let has_annex = wit_stack
213+
.last()
214+
.and_then(|x| x.as_push().ok())
215+
.map(|x| x.len() > 0 && x[0] == TAPROOT_ANNEX_PREFIX)
216+
.unwrap_or(false);
217+
if has_annex {
218+
wit_stack.pop();
219+
} else {
220+
// no annex
221+
}
222+
}
211223
if wit_stack.len() == 1 {
212224
// Key spend
213225
Ok((
@@ -216,47 +228,36 @@ pub(super) fn from_txdata<'txin>(
216228
None, // Tr script code None
217229
))
218230
} else {
219-
// wit_stack.len() >=2
220-
// Check for annex
221231
let ctrl_blk = wit_stack.pop().ok_or(Error::UnexpectedStackEnd)?;
222232
let ctrl_blk = ctrl_blk.as_push()?;
223233
let tap_script = wit_stack.pop().ok_or(Error::UnexpectedStackEnd)?;
224-
if ctrl_blk.len() > 0 && ctrl_blk[0] == TAPROOT_ANNEX_PREFIX {
225-
// Annex is non-standard, bitcoin consensus rules ignore it.
226-
// Our sighash structure and signature verification
227-
// does not support annex, return error
228-
return Err(Error::TapAnnexUnsupported);
229-
} else if wit_stack.len() >= 2 {
230-
let ctrl_blk = ControlBlock::from_slice(ctrl_blk)
231-
.map_err(|e| Error::ControlBlockParse(e))?;
232-
let tap_script = script_from_stackelem::<Tap>(&tap_script)?;
233-
let ms = tap_script.to_no_checks_ms();
234-
// Creating new contexts is cheap
235-
let secp = bitcoin::secp256k1::Secp256k1::verification_only();
236-
let tap_script = tap_script.encode();
237-
// Should not really need to call dangerous assumed tweaked here.
238-
// Should be fixed after RC
239-
if ctrl_blk.verify_taproot_commitment(
240-
&secp,
241-
&output_key.dangerous_assume_tweaked(),
242-
&tap_script,
243-
) {
244-
Ok((
245-
Inner::Script(ms, ScriptType::Tr),
246-
wit_stack,
247-
// Tapscript is returned as a "scriptcode". This is a hack, but avoids adding yet
248-
// another enum just for taproot, and this function is not a publicly exposed API,
249-
// so it's easy enough to keep track of all uses.
250-
//
251-
// In particular, this return value will be put into the `script_code` member of
252-
// the `Interpreter` script; the iterpreter logic does the right thing with it.
253-
Some(tap_script),
254-
))
255-
} else {
256-
return Err(Error::ControlBlockVerificationError);
257-
}
234+
let ctrl_blk =
235+
ControlBlock::from_slice(ctrl_blk).map_err(|e| Error::ControlBlockParse(e))?;
236+
let tap_script = script_from_stackelem::<Tap>(&tap_script)?;
237+
let ms = tap_script.to_no_checks_ms();
238+
// Creating new contexts is cheap
239+
let secp = bitcoin::secp256k1::Secp256k1::verification_only();
240+
let tap_script = tap_script.encode();
241+
// Should not really need to call dangerous assumed tweaked here.
242+
// Should be fixed after RC
243+
if ctrl_blk.verify_taproot_commitment(
244+
&secp,
245+
&output_key.dangerous_assume_tweaked(),
246+
&tap_script,
247+
) {
248+
Ok((
249+
Inner::Script(ms, ScriptType::Tr),
250+
wit_stack,
251+
// Tapscript is returned as a "scriptcode". This is a hack, but avoids adding yet
252+
// another enum just for taproot, and this function is not a publicly exposed API,
253+
// so it's easy enough to keep track of all uses.
254+
//
255+
// In particular, this return value will be put into the `script_code` member of
256+
// the `Interpreter` script; the iterpreter logic does the right thing with it.
257+
Some(tap_script),
258+
))
258259
} else {
259-
return Err(Error::UnexpectedStackBoolean);
260+
return Err(Error::ControlBlockVerificationError);
260261
}
261262
}
262263
}

0 commit comments

Comments
 (0)