Skip to content

support BIP342 script-path taproot sighash#1

Open
fmoletta-muun wants to merge 3 commits into
release-0.15-taproot-patchfrom
0.15.4-taproot-sighash
Open

support BIP342 script-path taproot sighash#1
fmoletta-muun wants to merge 3 commits into
release-0.15-taproot-patchfrom
0.15.4-taproot-sighash

Conversation

@fmoletta-muun

Copy link
Copy Markdown
Collaborator

hashForTaprootSignature only handled key-path (BIP341) spends. Allow a non-null scriptCode, interpreted as the 32-byte tapleaf hash, to produce the script-path sighash: set spend_type to 0x02 and append the ext_flag=1 extension (tapleaf_hash || key_version || codesep_pos). Key-path behaviour is unchanged.

Add testSigHashTaprootScriptPath, whose golden value is cross-checked against btcd's txscript.CalcTapscriptSignaturehash (the same oracle reproduces the existing key-path vector exactly).

hashForTaprootSignature only handled key-path (BIP341) spends. Allow a
non-null scriptCode, interpreted as the 32-byte tapleaf hash, to produce
the script-path sighash: set spend_type to 0x02 and append the ext_flag=1
extension (tapleaf_hash || key_version || codesep_pos). Key-path behaviour
is unchanged.

Add testSigHashTaprootScriptPath, whose golden value is cross-checked
against btcd's txscript.CalcTapscriptSignaturehash (the same oracle
reproduces the existing key-path vector exactly).
@fmoletta-muun fmoletta-muun requested a review from champo July 3, 2026 15:22
@fmoletta-muun fmoletta-muun self-assigned this Jul 3, 2026
@fmoletta-muun fmoletta-muun added the enhancement New feature or request label Jul 3, 2026
Comment on lines +533 to +537
final List<TransactionOutput> prevOuts = new ArrayList<>();
prevOuts.add(new TransactionOutput(
RegTestParams.get(), null, Coin.valueOf(2_236_761L), p2trScript));
prevOuts.add(new TransactionOutput(
RegTestParams.get(), null, Coin.valueOf(3_275_592L), p2trScript));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test is failing because the value of 2_236_761L is incorrect (with 2_236_249L the test passes). Maybe we can reuse the parsing from the test that is above this one:

final List<TransactionOutput> prevOuts = new ArrayList<>();
new Message(RegTestParams.get(), Hex.decode(prevOutsHex), 0, 0) {
@Override
protected void parse() throws ProtocolException {
this.length = 1;
final long length = readVarInt();
for (long i = 0; i < length; i++) {
final BigInteger value = readUint64();
final byte[] script = readByteArray();
prevOuts.add(new TransactionOutput(
RegTestParams.get(),
null,
Coin.valueOf(value.longValue()),
script
));
}
}
};

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed by using the parsing logic 8701562

Comment on lines 1399 to 1403
public synchronized Sha256Hash hashForTaprootSignature(
int inputIndex,
byte[] scriptCode,
List<TransactionOutput> prevOutputs,
byte sigHashType){

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Considering we don't modify this code often and for future readability I think we should modify the argument scriptCode to tapLeafHash. Also I would add a nice doc comment to this function documenting that we don't support OP_CODESEPARATOR and what each argument is similar to what the library has for other functions:

}
/**
* <p>Calculates a signature hash, that is, a hash of a simplified form of the transaction. How exactly the transaction
* is simplified is specified by the type and anyoneCanPay parameters.</p>
*
* <p>This is a low level API and when using the regular {@link Wallet} class you don't have to call this yourself.
* When working with more complex transaction types and contracts, it can be necessary. When signing a Witness output
* the scriptCode should be the script encoded into the scriptSig field, for normal transactions, it's the
* scriptPubKey of the output you're signing for. (See BIP143: https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki)</p>
*
* @param inputIndex input the signature is being calculated for. Tx signatures are always relative to an input.
* @param scriptCode the script that should be in the given input during signing.
* @param prevValue the value of the coin being spent
* @param type Should be SigHash.ALL
* @param anyoneCanPay should be false.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added doc here 52b1f21

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants