btcd/txscript/taproot.go
Olaoluwa Osuntokun abeaf4e334
txscript: introduce new signatureVerifier interface to abstract over 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.
2022-03-15 18:22:48 -07:00

50 lines
1.4 KiB
Go

package txscript
import (
"fmt"
"github.com/btcsuite/btcd/wire"
)
// VerifyTaprootKeySpend attempts to verify a top-level taproot key spend,
// returning a non-nil error if the passed signature is invalid. If a sigCache
// is passed in, then the sig cache will be consulted to skip full verification
// of a signature that has already been seen. Witness program here should be
// the 32-byte x-only schnorr output public key.
//
// NOTE: The TxSigHashes MUST be passed in and fully populated.
func VerifyTaprootKeySpend(witnessProgram []byte, rawSig []byte, tx *wire.MsgTx,
inputIndex int, prevOuts PrevOutputFetcher, hashCache *TxSigHashes,
sigCache *SigCache) error {
// First, we'll need to extract the public key from the witness
// program.
rawKey := witnessProgram
// Extract the annex if it exists, so we can compute the proper proper
// sighash below.
var annex []byte
witness := tx.TxIn[inputIndex].Witness
if isAnnexedWitness(witness) {
annex, _ = extractAnnex(witness)
}
// Now that we have the public key, we can create a new top-level
// keyspend verifier that'll handle all the sighash and schnorr
// specifics for us.
keySpendVerifier, err := newTaprootSigVerifier(
rawKey, rawSig, tx, inputIndex, prevOuts, sigCache,
hashCache, annex,
)
if err != nil {
return err
}
valid := keySpendVerifier.Verify()
if valid {
return nil
}
// TODO(roasbeef): add proper error
return fmt.Errorf("invalid sig")
}