Skip to content

Allow custom sighash flags in tapscript sig verification (align with forfeit tx pattern) #984

@arkanaai

Description

@arkanaai

Summary

VerifyTapscriptSigs in pkg/ark-lib/txutils/utils.go hardcodes txscript.SigHashDefault when computing the sighash for signature verification. This means any tapscript input signed with a non-default sighash type (e.g. SIGHASH_ALL, SIGHASH_SINGLE, SIGHASH_NONE, or their ANYONECANPAY variants) will fail verification even when the sighash type is correctly encoded in the PSBT.

Current Behavior

In pkg/ark-lib/txutils/utils.go:

sighash, err = txscript.CalcTapscriptSignaturehash(
    txSigHashes,
    txscript.SigHashDefault,   // ← hardcoded
    tx.UnsignedTx,
    inputIndex,
    prevoutFetcher,
    leaf,
)

The sighash type embedded in each TaprootScriptSpendSig entry is ignored.

Expected Behavior

The sighash type should be read from the PSBT sig entry (tapscriptSig.SigHash), exactly as the forfeit tx verification path does in internal/infrastructure/tx-builder/covenantless/builder.go:

preimage, err := txscript.CalcTapscriptSignaturehash(
    txSigHashes,
    tapScriptSig.SigHash,   // ← reads from PSBT sig
    ptx.UnsignedTx,
    index,
    prevoutFetcher,
    txscript.NewBaseTapLeaf(tapLeaf.Script),
)

The signing path in pkg/arkd-wallet/core/application/wallet/service.go already respects input.SighashType from the PSBT when producing signatures, so the signing and verification halves are inconsistent.

Motivation

This is needed to support closures (e.g. smart contract scripts, complex spending conditions) that require non-default sighash semantics — the same flexibility the forfeit tx path already has. Without it, any future closure type that commits to a specific sighash flag cannot be verified through the general VerifyTapscriptSigs utility.

Fix

In pkg/ark-lib/txutils/utils.go, replace the hardcoded txscript.SigHashDefault with tapscriptSig.SigHash:

sighash, err = txscript.CalcTapscriptSignaturehash(
    txSigHashes,
    tapscriptSig.SigHash,
    tx.UnsignedTx,
    inputIndex,
    prevoutFetcher,
    leaf,
)

Relevant Files

  • pkg/ark-lib/txutils/utils.goVerifyTapscriptSigs (needs fix)
  • internal/infrastructure/tx-builder/covenantless/builder.goverifyTapscriptPartialSigs (reference implementation)
  • pkg/arkd-wallet/core/application/wallet/service.go — signing already handles custom sighash types
  • pkg/ark-lib/script/closure.go — closure types currently document SIGHASH_DEFAULT assumption in comments (should be updated)

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions