Skip to content

Commit

Permalink
txscript: introduce new signatureVerifier interface to abstract over …
Browse files Browse the repository at this point in the history
…schnorr/ecdsa

In this commit, we add a new signatureVerifier interface that will allow
us to consolidate a lot of code as we'll now have 4 distinct sig+sighash
types to verify:
  1. pre-segwit
  2. segwit v0
  3. segwit v1 (taproot key spend)
  4. tapscript spends

We'll need to be able to handle 3 of the cases for the modified
OP_CHECKSIG operator. This new abstraction allows us to keep the
implementation of the function somewhat succinct.

In this commit we implement a verifier for #3 which is needed to verify
the top-level taproot keyspend. We expose the verifier using a new
VerifyTaprootKeySpend function.
  • Loading branch information
Roasbeef committed Mar 16, 2022
1 parent 1cd509d commit abeaf4e
Show file tree
Hide file tree
Showing 4 changed files with 573 additions and 0 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ require (

require (
github.com/aead/siphash v1.0.1 // indirect
github.com/decred/dcrd/crypto/blake256 v1.0.0 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23 // indirect
Expand Down
42 changes: 42 additions & 0 deletions txscript/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"strings"

"github.com/btcsuite/btcd/btcec/v2"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
)

Expand Down Expand Up @@ -117,6 +118,46 @@ const (
// halforder is used to tame ECDSA malleability (see BIP0062).
var halfOrder = new(big.Int).Rsh(btcec.S256().N, 1)

// taprootExecutionCtx houses the special context-specific information we need
// to validate a taproot script spend. This includes the annex, the running sig
// op count tally, and other relevant information.
type taprootExecutionCtx struct {
annex []byte

codeSepPos uint32

tapLeafHash chainhash.Hash

sigOpsBudget uint32
}

// sigOpsDelta is both the starting budget for sig ops for tapscript
// verification, as well as the decrease in the total budget when we encounter
// a signature.
const sigOpsDelta = 50

// tallysigOp attempts to decrease the current sig ops budget by sigOpsDelta.
// An error is returned if after subtracting the delta, the budget is below
// zero.
func (t *taprootExecutionCtx) tallysigOp() error {
t.sigOpsBudget -= sigOpsDelta

if t.sigOpsBudget == 0 {
return fmt.Errorf("max sig ops exceeded")
}

return nil
}

// newTaprootExecutionCtx returns a fresh instance of the taproot execution
// context.
func newTaprootExecutionCtx(inputWitnessSize uint32) *taprootExecutionCtx {
return &taprootExecutionCtx{
codeSepPos: blankCodeSepValue,
sigOpsBudget: sigOpsDelta + inputWitnessSize,
}
}

// Engine is the virtual machine that executes scripts.
type Engine struct {
// The following fields are set when the engine is created and must not be
Expand Down Expand Up @@ -201,6 +242,7 @@ type Engine struct {
witnessVersion int
witnessProgram []byte
inputAmount int64
taprootCtx *taprootExecutionCtx
}

// hasFlag returns whether the script engine instance has the passed flag set.
Expand Down
Loading

0 comments on commit abeaf4e

Please sign in to comment.