aaf187427e
This commit implements full witness program validation for the currently defined version 0 witness programs. This includes validation logic for nested p2sh, p2wsh, and p2wkh. Additionally, when in witness validation mode, an additional set of constrains are enforced such as using the new sighash digest algorithm and enforcing clean stack behavior within witness programs.
927 lines
30 KiB
Go
927 lines
30 KiB
Go
// Copyright (c) 2013-2017 The btcsuite developers
|
|
// Use of this source code is governed by an ISC
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package txscript
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/sha256"
|
|
"fmt"
|
|
"math/big"
|
|
|
|
"github.com/btcsuite/btcd/btcec"
|
|
"github.com/btcsuite/btcd/wire"
|
|
)
|
|
|
|
// ScriptFlags is a bitmask defining additional operations or tests that will be
|
|
// done when executing a script pair.
|
|
type ScriptFlags uint32
|
|
|
|
const (
|
|
// ScriptBip16 defines whether the bip16 threshold has passed and thus
|
|
// pay-to-script hash transactions will be fully validated.
|
|
ScriptBip16 ScriptFlags = 1 << iota
|
|
|
|
// ScriptStrictMultiSig defines whether to verify the stack item
|
|
// used by CHECKMULTISIG is zero length.
|
|
ScriptStrictMultiSig
|
|
|
|
// ScriptDiscourageUpgradableNops defines whether to verify that
|
|
// NOP1 through NOP10 are reserved for future soft-fork upgrades. This
|
|
// flag must not be used for consensus critical code nor applied to
|
|
// blocks as this flag is only for stricter standard transaction
|
|
// checks. This flag is only applied when the above opcodes are
|
|
// executed.
|
|
ScriptDiscourageUpgradableNops
|
|
|
|
// ScriptVerifyCheckLockTimeVerify defines whether to verify that
|
|
// a transaction output is spendable based on the locktime.
|
|
// This is BIP0065.
|
|
ScriptVerifyCheckLockTimeVerify
|
|
|
|
// ScriptVerifyCheckSequenceVerify defines whether to allow execution
|
|
// pathways of a script to be restricted based on the age of the output
|
|
// being spent. This is BIP0112.
|
|
ScriptVerifyCheckSequenceVerify
|
|
|
|
// ScriptVerifyCleanStack defines that the stack must contain only
|
|
// one stack element after evaluation and that the element must be
|
|
// true if interpreted as a boolean. This is rule 6 of BIP0062.
|
|
// This flag should never be used without the ScriptBip16 flag nor the
|
|
// ScriptVerifyWitness flag.
|
|
ScriptVerifyCleanStack
|
|
|
|
// ScriptVerifyDERSignatures defines that signatures are required
|
|
// to compily with the DER format.
|
|
ScriptVerifyDERSignatures
|
|
|
|
// ScriptVerifyLowS defines that signtures are required to comply with
|
|
// the DER format and whose S value is <= order / 2. This is rule 5
|
|
// of BIP0062.
|
|
ScriptVerifyLowS
|
|
|
|
// ScriptVerifyMinimalData defines that signatures must use the smallest
|
|
// push operator. This is both rules 3 and 4 of BIP0062.
|
|
ScriptVerifyMinimalData
|
|
|
|
// ScriptVerifyNullFail defines that signatures must be empty if
|
|
// a CHECKSIG or CHECKMULTISIG operation fails.
|
|
ScriptVerifyNullFail
|
|
|
|
// ScriptVerifySigPushOnly defines that signature scripts must contain
|
|
// only pushed data. This is rule 2 of BIP0062.
|
|
ScriptVerifySigPushOnly
|
|
|
|
// ScriptVerifyStrictEncoding defines that signature scripts and
|
|
// public keys must follow the strict encoding requirements.
|
|
ScriptVerifyStrictEncoding
|
|
|
|
// ScriptVerifyWitness defines whether or not to verify a transaction
|
|
// output using a witness program template.
|
|
ScriptVerifyWitness
|
|
|
|
// ScriptVerifyDiscourageUpgradeableWitnessProgram makes witness
|
|
// program with versions 2-16 non-standard.
|
|
ScriptVerifyDiscourageUpgradeableWitnessProgram
|
|
)
|
|
|
|
const (
|
|
// MaxStackSize is the maximum combined height of stack and alt stack
|
|
// during execution.
|
|
MaxStackSize = 1000
|
|
|
|
// MaxScriptSize is the maximum allowed length of a raw script.
|
|
MaxScriptSize = 10000
|
|
|
|
// payToWitnessPubKeyHashDataSize is the size of the witness program's
|
|
// data push for a pay-to-witness-pub-key-hash output.
|
|
payToWitnessPubKeyHashDataSize = 20
|
|
|
|
// payToWitnessScriptHashDataSize is the size of the witness program's
|
|
// data push for a pay-to-witness-script-hash output.
|
|
payToWitnessScriptHashDataSize = 32
|
|
)
|
|
|
|
// halforder is used to tame ECDSA malleability (see BIP0062).
|
|
var halfOrder = new(big.Int).Rsh(btcec.S256().N, 1)
|
|
|
|
// Engine is the virtual machine that executes scripts.
|
|
type Engine struct {
|
|
scripts [][]parsedOpcode
|
|
scriptIdx int
|
|
scriptOff int
|
|
lastCodeSep int
|
|
dstack stack // data stack
|
|
astack stack // alt stack
|
|
tx wire.MsgTx
|
|
txIdx int
|
|
condStack []int
|
|
numOps int
|
|
flags ScriptFlags
|
|
sigCache *SigCache
|
|
hashCache *TxSigHashes
|
|
bip16 bool // treat execution as pay-to-script-hash
|
|
savedFirstStack [][]byte // stack from first script for bip16 scripts
|
|
witness bool // treat execution as a witness program
|
|
witnessVersion int
|
|
witnessProgram []byte
|
|
inputAmount int64
|
|
}
|
|
|
|
// hasFlag returns whether the script engine instance has the passed flag set.
|
|
func (vm *Engine) hasFlag(flag ScriptFlags) bool {
|
|
return vm.flags&flag == flag
|
|
}
|
|
|
|
// isBranchExecuting returns whether or not the current conditional branch is
|
|
// actively executing. For example, when the data stack has an OP_FALSE on it
|
|
// and an OP_IF is encountered, the branch is inactive until an OP_ELSE or
|
|
// OP_ENDIF is encountered. It properly handles nested conditionals.
|
|
func (vm *Engine) isBranchExecuting() bool {
|
|
if len(vm.condStack) == 0 {
|
|
return true
|
|
}
|
|
return vm.condStack[len(vm.condStack)-1] == OpCondTrue
|
|
}
|
|
|
|
// executeOpcode peforms execution on the passed opcode. It takes into account
|
|
// whether or not it is hidden by conditionals, but some rules still must be
|
|
// tested in this case.
|
|
func (vm *Engine) executeOpcode(pop *parsedOpcode) error {
|
|
// Disabled opcodes are fail on program counter.
|
|
if pop.isDisabled() {
|
|
str := fmt.Sprintf("attempt to execute disabled opcode %s",
|
|
pop.opcode.name)
|
|
return scriptError(ErrDisabledOpcode, str)
|
|
}
|
|
|
|
// Always-illegal opcodes are fail on program counter.
|
|
if pop.alwaysIllegal() {
|
|
str := fmt.Sprintf("attempt to execute reserved opcode %s",
|
|
pop.opcode.name)
|
|
return scriptError(ErrReservedOpcode, str)
|
|
}
|
|
|
|
// Note that this includes OP_RESERVED which counts as a push operation.
|
|
if pop.opcode.value > OP_16 {
|
|
vm.numOps++
|
|
if vm.numOps > MaxOpsPerScript {
|
|
str := fmt.Sprintf("exceeded max operation limit of %d",
|
|
MaxOpsPerScript)
|
|
return scriptError(ErrTooManyOperations, str)
|
|
}
|
|
|
|
} else if len(pop.data) > MaxScriptElementSize {
|
|
str := fmt.Sprintf("element size %d exceeds max allowed size %d",
|
|
len(pop.data), MaxScriptElementSize)
|
|
return scriptError(ErrElementTooBig, str)
|
|
}
|
|
|
|
// Nothing left to do when this is not a conditional opcode and it is
|
|
// not in an executing branch.
|
|
if !vm.isBranchExecuting() && !pop.isConditional() {
|
|
return nil
|
|
}
|
|
|
|
// Ensure all executed data push opcodes use the minimal encoding when
|
|
// the minimal data verification flag is set.
|
|
if vm.dstack.verifyMinimalData && vm.isBranchExecuting() &&
|
|
pop.opcode.value >= 0 && pop.opcode.value <= OP_PUSHDATA4 {
|
|
|
|
if err := pop.checkMinimalDataPush(); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return pop.opcode.opfunc(pop, vm)
|
|
}
|
|
|
|
// disasm is a helper function to produce the output for DisasmPC and
|
|
// DisasmScript. It produces the opcode prefixed by the program counter at the
|
|
// provided position in the script. It does no error checking and leaves that
|
|
// to the caller to provide a valid offset.
|
|
func (vm *Engine) disasm(scriptIdx int, scriptOff int) string {
|
|
return fmt.Sprintf("%02x:%04x: %s", scriptIdx, scriptOff,
|
|
vm.scripts[scriptIdx][scriptOff].print(false))
|
|
}
|
|
|
|
// validPC returns an error if the current script position is valid for
|
|
// execution, nil otherwise.
|
|
func (vm *Engine) validPC() error {
|
|
if vm.scriptIdx >= len(vm.scripts) {
|
|
str := fmt.Sprintf("past input scripts %v:%v %v:xxxx",
|
|
vm.scriptIdx, vm.scriptOff, len(vm.scripts))
|
|
return scriptError(ErrInvalidProgramCounter, str)
|
|
}
|
|
if vm.scriptOff >= len(vm.scripts[vm.scriptIdx]) {
|
|
str := fmt.Sprintf("past input scripts %v:%v %v:%04d",
|
|
vm.scriptIdx, vm.scriptOff, vm.scriptIdx,
|
|
len(vm.scripts[vm.scriptIdx]))
|
|
return scriptError(ErrInvalidProgramCounter, str)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// curPC returns either the current script and offset, or an error if the
|
|
// position isn't valid.
|
|
func (vm *Engine) curPC() (script int, off int, err error) {
|
|
err = vm.validPC()
|
|
if err != nil {
|
|
return 0, 0, err
|
|
}
|
|
return vm.scriptIdx, vm.scriptOff, nil
|
|
}
|
|
|
|
// verifyWitnessProgram validates the stored witness program using the passed
|
|
// witness as input.
|
|
func (vm *Engine) verifyWitnessProgram(witness [][]byte) error {
|
|
if vm.witnessVersion == 0 {
|
|
switch len(vm.witnessProgram) {
|
|
case payToWitnessPubKeyHashDataSize: // P2WKH
|
|
// The witness stack should consist of exactly two
|
|
// items: the signature, and the pubkey.
|
|
if len(witness) != 2 {
|
|
err := fmt.Sprintf("should have exactly two "+
|
|
"items in witness, instead have %v", len(witness))
|
|
return scriptError(ErrWitnessScriptMismatch, err)
|
|
}
|
|
|
|
// Now we'll resume execution as if it were a regular
|
|
// p2pkh transaction.
|
|
pkScript, err := payToPubKeyHashScript(vm.witnessProgram)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
pops, err := parseScript(pkScript)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Set the stack to the provided witness stack, then
|
|
// append the pkScript generated above as the next
|
|
// script to execute.
|
|
vm.scripts = append(vm.scripts, pops)
|
|
vm.SetStack(witness)
|
|
|
|
case payToWitnessScriptHashDataSize: // P2WSH
|
|
|
|
// Additionally, The witness stack MUST NOT be empty at
|
|
// this point.
|
|
if len(witness) == 0 {
|
|
return scriptError(ErrWitnessProgramEmpty, "witness "+
|
|
"program empty passed empty witness")
|
|
}
|
|
|
|
// Obtain the witness script which should be the last
|
|
// element in the passed stack. The size of the script
|
|
// MUST NOT exceed the max script size.
|
|
witnessScript := witness[len(witness)-1]
|
|
if len(witnessScript) > MaxScriptSize {
|
|
str := fmt.Sprintf("witnessScript size %d "+
|
|
"is larger than max allowed size %d",
|
|
len(witnessScript), MaxScriptSize)
|
|
return scriptError(ErrScriptTooBig, str)
|
|
}
|
|
|
|
// Ensure that the serialized pkScript at the end of
|
|
// the witness stack matches the witness program.
|
|
witnessHash := sha256.Sum256(witnessScript)
|
|
if !bytes.Equal(witnessHash[:], vm.witnessProgram) {
|
|
return scriptError(ErrWitnessScriptMismatch,
|
|
"witness program hash mismatch")
|
|
}
|
|
|
|
// With all the validity checks passed, parse the
|
|
// script into individual op-codes so w can execute it
|
|
// as the next script.
|
|
pops, err := parseScript(witnessScript)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// The hash matched successfully, so use the witness as
|
|
// the stack, and set the witnessScript to be the next
|
|
// script executed.
|
|
vm.scripts = append(vm.scripts, pops)
|
|
vm.SetStack(witness[:len(witness)-1])
|
|
|
|
default:
|
|
errStr := fmt.Sprintf("length of witness program "+
|
|
"must either be %v or %v bytes, instead is %v bytes",
|
|
payToWitnessPubKeyHashDataSize,
|
|
payToWitnessScriptHashDataSize,
|
|
len(vm.witnessProgram))
|
|
return scriptError(ErrWitnessProgramWrongLength, errStr)
|
|
}
|
|
} else if vm.hasFlag(ScriptVerifyDiscourageUpgradeableWitnessProgram) {
|
|
return fmt.Errorf("new witness program versions invalid: %v",
|
|
vm.witnessVersion)
|
|
} else {
|
|
// If we encounter an unknown witness program version and we
|
|
// aren't discouraging future unknown witness based soft-forks,
|
|
// then we de-activate the segwit behavior within the VM for
|
|
// the remainder of execution.
|
|
vm.witness = false
|
|
}
|
|
|
|
if vm.witness {
|
|
// All elements within the witness stack must not be greater
|
|
// than the maximum bytes which are allowed to be pushed onto
|
|
// the stack.
|
|
for _, witElement := range vm.GetStack() {
|
|
if len(witElement) > MaxScriptElementSize {
|
|
str := fmt.Sprintf("element size %d exceeds "+
|
|
"max allowed size %d", len(witElement),
|
|
MaxScriptElementSize)
|
|
return scriptError(ErrElementTooBig, str)
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// DisasmPC returns the string for the disassembly of the opcode that will be
|
|
// next to execute when Step() is called.
|
|
func (vm *Engine) DisasmPC() (string, error) {
|
|
scriptIdx, scriptOff, err := vm.curPC()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return vm.disasm(scriptIdx, scriptOff), nil
|
|
}
|
|
|
|
// DisasmScript returns the disassembly string for the script at the requested
|
|
// offset index. Index 0 is the signature script and 1 is the public key
|
|
// script.
|
|
func (vm *Engine) DisasmScript(idx int) (string, error) {
|
|
if idx >= len(vm.scripts) {
|
|
str := fmt.Sprintf("script index %d >= total scripts %d", idx,
|
|
len(vm.scripts))
|
|
return "", scriptError(ErrInvalidIndex, str)
|
|
}
|
|
|
|
var disstr string
|
|
for i := range vm.scripts[idx] {
|
|
disstr = disstr + vm.disasm(idx, i) + "\n"
|
|
}
|
|
return disstr, nil
|
|
}
|
|
|
|
// CheckErrorCondition returns nil if the running script has ended and was
|
|
// successful, leaving a a true boolean on the stack. An error otherwise,
|
|
// including if the script has not finished.
|
|
func (vm *Engine) CheckErrorCondition(finalScript bool) error {
|
|
// Check execution is actually done. When pc is past the end of script
|
|
// array there are no more scripts to run.
|
|
if vm.scriptIdx < len(vm.scripts) {
|
|
return scriptError(ErrScriptUnfinished,
|
|
"error check when script unfinished")
|
|
}
|
|
|
|
// If we're in witness execution mode, and this was the final script,
|
|
// then the stack MUST be clean in order to maintain compatibility with
|
|
// BIP16.
|
|
if finalScript && vm.witness && vm.dstack.Depth() != 1 {
|
|
return ErrStackCleanStack
|
|
}
|
|
|
|
if finalScript && vm.hasFlag(ScriptVerifyCleanStack) &&
|
|
vm.dstack.Depth() != 1 {
|
|
|
|
str := fmt.Sprintf("stack contains %d unexpected items",
|
|
vm.dstack.Depth()-1)
|
|
return scriptError(ErrCleanStack, str)
|
|
} else if vm.dstack.Depth() < 1 {
|
|
return scriptError(ErrEmptyStack,
|
|
"stack empty at end of script execution")
|
|
}
|
|
|
|
v, err := vm.dstack.PopBool()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if !v {
|
|
// Log interesting data.
|
|
log.Tracef("%v", newLogClosure(func() string {
|
|
dis0, _ := vm.DisasmScript(0)
|
|
dis1, _ := vm.DisasmScript(1)
|
|
return fmt.Sprintf("scripts failed: script0: %s\n"+
|
|
"script1: %s", dis0, dis1)
|
|
}))
|
|
return scriptError(ErrEvalFalse,
|
|
"false stack entry at end of script execution")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Step will execute the next instruction and move the program counter to the
|
|
// next opcode in the script, or the next script if the current has ended. Step
|
|
// will return true in the case that the last opcode was successfully executed.
|
|
//
|
|
// The result of calling Step or any other method is undefined if an error is
|
|
// returned.
|
|
func (vm *Engine) Step() (done bool, err error) {
|
|
// Verify that it is pointing to a valid script address.
|
|
err = vm.validPC()
|
|
if err != nil {
|
|
return true, err
|
|
}
|
|
opcode := &vm.scripts[vm.scriptIdx][vm.scriptOff]
|
|
vm.scriptOff++
|
|
|
|
// Execute the opcode while taking into account several things such as
|
|
// disabled opcodes, illegal opcodes, maximum allowed operations per
|
|
// script, maximum script element sizes, and conditionals.
|
|
err = vm.executeOpcode(opcode)
|
|
if err != nil {
|
|
return true, err
|
|
}
|
|
|
|
// The number of elements in the combination of the data and alt stacks
|
|
// must not exceed the maximum number of stack elements allowed.
|
|
combinedStackSize := vm.dstack.Depth() + vm.astack.Depth()
|
|
if combinedStackSize > MaxStackSize {
|
|
str := fmt.Sprintf("combined stack size %d > max allowed %d",
|
|
combinedStackSize, MaxStackSize)
|
|
return false, scriptError(ErrStackOverflow, str)
|
|
}
|
|
|
|
// Prepare for next instruction.
|
|
if vm.scriptOff >= len(vm.scripts[vm.scriptIdx]) {
|
|
// Illegal to have an `if' that straddles two scripts.
|
|
if err == nil && len(vm.condStack) != 0 {
|
|
return false, scriptError(ErrUnbalancedConditional,
|
|
"end of script reached in conditional execution")
|
|
}
|
|
|
|
// Alt stack doesn't persist.
|
|
_ = vm.astack.DropN(vm.astack.Depth())
|
|
|
|
vm.numOps = 0 // number of ops is per script.
|
|
vm.scriptOff = 0
|
|
if vm.scriptIdx == 0 && vm.bip16 {
|
|
vm.scriptIdx++
|
|
vm.savedFirstStack = vm.GetStack()
|
|
} else if vm.scriptIdx == 1 && vm.bip16 {
|
|
// Put us past the end for CheckErrorCondition()
|
|
vm.scriptIdx++
|
|
// Check script ran successfully and pull the script
|
|
// out of the first stack and execute that.
|
|
err := vm.CheckErrorCondition(false)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
script := vm.savedFirstStack[len(vm.savedFirstStack)-1]
|
|
pops, err := parseScript(script)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
vm.scripts = append(vm.scripts, pops)
|
|
|
|
// Set stack to be the stack from first script minus the
|
|
// script itself
|
|
vm.SetStack(vm.savedFirstStack[:len(vm.savedFirstStack)-1])
|
|
} else if (vm.scriptIdx == 1 && vm.witness) ||
|
|
(vm.scriptIdx == 2 && vm.witness && vm.bip16) { // Nested P2SH.
|
|
vm.scriptIdx++
|
|
|
|
witness := vm.tx.TxIn[vm.txIdx].Witness
|
|
if err := vm.verifyWitnessProgram(witness); err != nil {
|
|
return false, err
|
|
}
|
|
} else {
|
|
vm.scriptIdx++
|
|
}
|
|
// there are zero length scripts in the wild
|
|
if vm.scriptIdx < len(vm.scripts) && vm.scriptOff >= len(vm.scripts[vm.scriptIdx]) {
|
|
vm.scriptIdx++
|
|
}
|
|
vm.lastCodeSep = 0
|
|
if vm.scriptIdx >= len(vm.scripts) {
|
|
return true, nil
|
|
}
|
|
}
|
|
return false, nil
|
|
}
|
|
|
|
// Execute will execute all scripts in the script engine and return either nil
|
|
// for successful validation or an error if one occurred.
|
|
func (vm *Engine) Execute() (err error) {
|
|
done := false
|
|
for !done {
|
|
log.Tracef("%v", newLogClosure(func() string {
|
|
dis, err := vm.DisasmPC()
|
|
if err != nil {
|
|
return fmt.Sprintf("stepping (%v)", err)
|
|
}
|
|
return fmt.Sprintf("stepping %v", dis)
|
|
}))
|
|
|
|
done, err = vm.Step()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
log.Tracef("%v", newLogClosure(func() string {
|
|
var dstr, astr string
|
|
|
|
// if we're tracing, dump the stacks.
|
|
if vm.dstack.Depth() != 0 {
|
|
dstr = "Stack:\n" + vm.dstack.String()
|
|
}
|
|
if vm.astack.Depth() != 0 {
|
|
astr = "AltStack:\n" + vm.astack.String()
|
|
}
|
|
|
|
return dstr + astr
|
|
}))
|
|
}
|
|
|
|
return vm.CheckErrorCondition(true)
|
|
}
|
|
|
|
// subScript returns the script since the last OP_CODESEPARATOR.
|
|
func (vm *Engine) subScript() []parsedOpcode {
|
|
return vm.scripts[vm.scriptIdx][vm.lastCodeSep:]
|
|
}
|
|
|
|
// checkHashTypeEncoding returns whether or not the passed hashtype adheres to
|
|
// the strict encoding requirements if enabled.
|
|
func (vm *Engine) checkHashTypeEncoding(hashType SigHashType) error {
|
|
if !vm.hasFlag(ScriptVerifyStrictEncoding) {
|
|
return nil
|
|
}
|
|
|
|
sigHashType := hashType & ^SigHashAnyOneCanPay
|
|
if sigHashType < SigHashAll || sigHashType > SigHashSingle {
|
|
str := fmt.Sprintf("invalid hash type 0x%x", hashType)
|
|
return scriptError(ErrInvalidSigHashType, str)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// checkPubKeyEncoding returns whether or not the passed public key adheres to
|
|
// the strict encoding requirements if enabled.
|
|
func (vm *Engine) checkPubKeyEncoding(pubKey []byte) error {
|
|
if !vm.hasFlag(ScriptVerifyStrictEncoding) {
|
|
return nil
|
|
}
|
|
|
|
if len(pubKey) == 33 && (pubKey[0] == 0x02 || pubKey[0] == 0x03) {
|
|
// Compressed
|
|
return nil
|
|
}
|
|
if len(pubKey) == 65 && pubKey[0] == 0x04 {
|
|
// Uncompressed
|
|
return nil
|
|
}
|
|
return scriptError(ErrPubKeyType, "unsupported public key type")
|
|
}
|
|
|
|
// checkSignatureEncoding returns whether or not the passed signature adheres to
|
|
// the strict encoding requirements if enabled.
|
|
func (vm *Engine) checkSignatureEncoding(sig []byte) error {
|
|
if !vm.hasFlag(ScriptVerifyDERSignatures) &&
|
|
!vm.hasFlag(ScriptVerifyLowS) &&
|
|
!vm.hasFlag(ScriptVerifyStrictEncoding) {
|
|
|
|
return nil
|
|
}
|
|
|
|
// The format of a DER encoded signature is as follows:
|
|
//
|
|
// 0x30 <total length> 0x02 <length of R> <R> 0x02 <length of S> <S>
|
|
// - 0x30 is the ASN.1 identifier for a sequence
|
|
// - Total length is 1 byte and specifies length of all remaining data
|
|
// - 0x02 is the ASN.1 identifier that specifies an integer follows
|
|
// - Length of R is 1 byte and specifies how many bytes R occupies
|
|
// - R is the arbitrary length big-endian encoded number which
|
|
// represents the R value of the signature. DER encoding dictates
|
|
// that the value must be encoded using the minimum possible number
|
|
// of bytes. This implies the first byte can only be null if the
|
|
// highest bit of the next byte is set in order to prevent it from
|
|
// being interpreted as a negative number.
|
|
// - 0x02 is once again the ASN.1 integer identifier
|
|
// - Length of S is 1 byte and specifies how many bytes S occupies
|
|
// - S is the arbitrary length big-endian encoded number which
|
|
// represents the S value of the signature. The encoding rules are
|
|
// identical as those for R.
|
|
|
|
// Minimum length is when both numbers are 1 byte each.
|
|
// 0x30 + <1-byte> + 0x02 + 0x01 + <byte> + 0x2 + 0x01 + <byte>
|
|
if len(sig) < 8 {
|
|
// Too short
|
|
str := fmt.Sprintf("malformed signature: too short: %d < 8",
|
|
len(sig))
|
|
return scriptError(ErrSigDER, str)
|
|
}
|
|
|
|
// Maximum length is when both numbers are 33 bytes each. It is 33
|
|
// bytes because a 256-bit integer requires 32 bytes and an additional
|
|
// leading null byte might required if the high bit is set in the value.
|
|
// 0x30 + <1-byte> + 0x02 + 0x21 + <33 bytes> + 0x2 + 0x21 + <33 bytes>
|
|
if len(sig) > 72 {
|
|
// Too long
|
|
str := fmt.Sprintf("malformed signature: too long: %d > 72",
|
|
len(sig))
|
|
return scriptError(ErrSigDER, str)
|
|
}
|
|
if sig[0] != 0x30 {
|
|
// Wrong type
|
|
str := fmt.Sprintf("malformed signature: format has wrong "+
|
|
"type: 0x%x", sig[0])
|
|
return scriptError(ErrSigDER, str)
|
|
}
|
|
if int(sig[1]) != len(sig)-2 {
|
|
// Invalid length
|
|
str := fmt.Sprintf("malformed signature: bad length: %d != %d",
|
|
sig[1], len(sig)-2)
|
|
return scriptError(ErrSigDER, str)
|
|
}
|
|
|
|
rLen := int(sig[3])
|
|
|
|
// Make sure S is inside the signature.
|
|
if rLen+5 > len(sig) {
|
|
return scriptError(ErrSigDER,
|
|
"malformed signature: S out of bounds")
|
|
}
|
|
|
|
sLen := int(sig[rLen+5])
|
|
|
|
// The length of the elements does not match the length of the
|
|
// signature.
|
|
if rLen+sLen+6 != len(sig) {
|
|
return scriptError(ErrSigDER,
|
|
"malformed signature: invalid R length")
|
|
}
|
|
|
|
// R elements must be integers.
|
|
if sig[2] != 0x02 {
|
|
return scriptError(ErrSigDER,
|
|
"malformed signature: missing first integer marker")
|
|
}
|
|
|
|
// Zero-length integers are not allowed for R.
|
|
if rLen == 0 {
|
|
return scriptError(ErrSigDER,
|
|
"malformed signature: R length is zero")
|
|
}
|
|
|
|
// R must not be negative.
|
|
if sig[4]&0x80 != 0 {
|
|
return scriptError(ErrSigDER,
|
|
"malformed signature: R value is negative")
|
|
}
|
|
|
|
// Null bytes at the start of R are not allowed, unless R would
|
|
// otherwise be interpreted as a negative number.
|
|
if rLen > 1 && sig[4] == 0x00 && sig[5]&0x80 == 0 {
|
|
return scriptError(ErrSigDER,
|
|
"malformed signature: invalid R value")
|
|
}
|
|
|
|
// S elements must be integers.
|
|
if sig[rLen+4] != 0x02 {
|
|
return scriptError(ErrSigDER,
|
|
"malformed signature: missing second integer marker")
|
|
}
|
|
|
|
// Zero-length integers are not allowed for S.
|
|
if sLen == 0 {
|
|
return scriptError(ErrSigDER,
|
|
"malformed signature: S length is zero")
|
|
}
|
|
|
|
// S must not be negative.
|
|
if sig[rLen+6]&0x80 != 0 {
|
|
return scriptError(ErrSigDER,
|
|
"malformed signature: S value is negative")
|
|
}
|
|
|
|
// Null bytes at the start of S are not allowed, unless S would
|
|
// otherwise be interpreted as a negative number.
|
|
if sLen > 1 && sig[rLen+6] == 0x00 && sig[rLen+7]&0x80 == 0 {
|
|
return scriptError(ErrSigDER,
|
|
"malformed signature: invalid S value")
|
|
}
|
|
|
|
// Verify the S value is <= half the order of the curve. This check is
|
|
// done because when it is higher, the complement modulo the order can
|
|
// be used instead which is a shorter encoding by 1 byte. Further,
|
|
// without enforcing this, it is possible to replace a signature in a
|
|
// valid transaction with the complement while still being a valid
|
|
// signature that verifies. This would result in changing the
|
|
// transaction hash and thus is source of malleability.
|
|
if vm.hasFlag(ScriptVerifyLowS) {
|
|
sValue := new(big.Int).SetBytes(sig[rLen+6 : rLen+6+sLen])
|
|
if sValue.Cmp(halfOrder) > 0 {
|
|
return scriptError(ErrSigHighS,
|
|
"signature is not canonical due to "+
|
|
"unnecessarily high S value")
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// getStack returns the contents of stack as a byte array bottom up
|
|
func getStack(stack *stack) [][]byte {
|
|
array := make([][]byte, stack.Depth())
|
|
for i := range array {
|
|
// PeekByteArry can't fail due to overflow, already checked
|
|
array[len(array)-i-1], _ = stack.PeekByteArray(int32(i))
|
|
}
|
|
return array
|
|
}
|
|
|
|
// setStack sets the stack to the contents of the array where the last item in
|
|
// the array is the top item in the stack.
|
|
func setStack(stack *stack, data [][]byte) {
|
|
// This can not error. Only errors are for invalid arguments.
|
|
_ = stack.DropN(stack.Depth())
|
|
|
|
for i := range data {
|
|
stack.PushByteArray(data[i])
|
|
}
|
|
}
|
|
|
|
// GetStack returns the contents of the primary stack as an array. where the
|
|
// last item in the array is the top of the stack.
|
|
func (vm *Engine) GetStack() [][]byte {
|
|
return getStack(&vm.dstack)
|
|
}
|
|
|
|
// SetStack sets the contents of the primary stack to the contents of the
|
|
// provided array where the last item in the array will be the top of the stack.
|
|
func (vm *Engine) SetStack(data [][]byte) {
|
|
setStack(&vm.dstack, data)
|
|
}
|
|
|
|
// GetAltStack returns the contents of the alternate stack as an array where the
|
|
// last item in the array is the top of the stack.
|
|
func (vm *Engine) GetAltStack() [][]byte {
|
|
return getStack(&vm.astack)
|
|
}
|
|
|
|
// SetAltStack sets the contents of the alternate stack to the contents of the
|
|
// provided array where the last item in the array will be the top of the stack.
|
|
func (vm *Engine) SetAltStack(data [][]byte) {
|
|
setStack(&vm.astack, data)
|
|
}
|
|
|
|
// NewEngine returns a new script engine for the provided public key script,
|
|
// transaction, and input index. The flags modify the behavior of the script
|
|
// engine according to the description provided by each flag.
|
|
func NewEngine(scriptPubKey []byte, tx *wire.MsgTx, txIdx int, flags ScriptFlags,
|
|
sigCache *SigCache, hashCache *TxSigHashes, inputAmount int64) (*Engine, error) {
|
|
|
|
// The provided transaction input index must refer to a valid input.
|
|
if txIdx < 0 || txIdx >= len(tx.TxIn) {
|
|
str := fmt.Sprintf("transaction input index %d is negative or "+
|
|
">= %d", txIdx, len(tx.TxIn))
|
|
return nil, scriptError(ErrInvalidIndex, str)
|
|
}
|
|
scriptSig := tx.TxIn[txIdx].SignatureScript
|
|
|
|
// When both the signature script and public key script are empty the
|
|
// result is necessarily an error since the stack would end up being
|
|
// empty which is equivalent to a false top element. Thus, just return
|
|
// the relevant error now as an optimization.
|
|
if len(scriptSig) == 0 && len(scriptPubKey) == 0 {
|
|
return nil, scriptError(ErrEvalFalse,
|
|
"false stack entry at end of script execution")
|
|
}
|
|
|
|
// The clean stack flag (ScriptVerifyCleanStack) is not allowed without
|
|
// either the the pay-to-script-hash (P2SH) evaluation (ScriptBip16)
|
|
// flag or the Segregated Witness (ScriptVerifyWitness) flag.
|
|
//
|
|
// Recall that evaluating a P2SH script without the flag set results in
|
|
// non-P2SH evaluation which leaves the P2SH inputs on the stack.
|
|
// Thus, allowing the clean stack flag without the P2SH flag would make
|
|
// it possible to have a situation where P2SH would not be a soft fork
|
|
// when it should be. The same goes for segwit which will pull in
|
|
// additional scripts for execution from the witness stack.
|
|
vm := Engine{flags: flags, sigCache: sigCache, hashCache: hashCache,
|
|
inputAmount: inputAmount}
|
|
if vm.hasFlag(ScriptVerifyCleanStack) && (!vm.hasFlag(ScriptBip16) &&
|
|
!vm.hasFlag(ScriptVerifyWitness)) {
|
|
return nil, scriptError(ErrInvalidFlags,
|
|
"invalid flags combination")
|
|
}
|
|
|
|
// The signature script must only contain data pushes when the
|
|
// associated flag is set.
|
|
if vm.hasFlag(ScriptVerifySigPushOnly) && !IsPushOnlyScript(scriptSig) {
|
|
return nil, scriptError(ErrNotPushOnly,
|
|
"signature script is not push only")
|
|
}
|
|
|
|
// The engine stores the scripts in parsed form using a slice. This
|
|
// allows multiple scripts to be executed in sequence. For example,
|
|
// with a pay-to-script-hash transaction, there will be ultimately be
|
|
// a third script to execute.
|
|
scripts := [][]byte{scriptSig, scriptPubKey}
|
|
vm.scripts = make([][]parsedOpcode, len(scripts))
|
|
for i, scr := range scripts {
|
|
if len(scr) > MaxScriptSize {
|
|
str := fmt.Sprintf("script size %d is larger than max "+
|
|
"allowed size %d", len(scr), MaxScriptSize)
|
|
return nil, scriptError(ErrScriptTooBig, str)
|
|
}
|
|
var err error
|
|
vm.scripts[i], err = parseScript(scr)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
// Advance the program counter to the public key script if the signature
|
|
// script is empty since there is nothing to execute for it in that
|
|
// case.
|
|
if len(scripts[0]) == 0 {
|
|
vm.scriptIdx++
|
|
}
|
|
|
|
if vm.hasFlag(ScriptBip16) && isScriptHash(vm.scripts[1]) {
|
|
// Only accept input scripts that push data for P2SH.
|
|
if !isPushOnly(vm.scripts[0]) {
|
|
return nil, scriptError(ErrNotPushOnly,
|
|
"pay to script hash is not push only")
|
|
}
|
|
vm.bip16 = true
|
|
}
|
|
if vm.hasFlag(ScriptVerifyMinimalData) {
|
|
vm.dstack.verifyMinimalData = true
|
|
vm.astack.verifyMinimalData = true
|
|
}
|
|
|
|
// Check to see if we should execute in witness verification mode
|
|
// according to the set flags. We check both the pkScript, and sigScript
|
|
// here since in the case of nested p2sh, the scriptSig will be a valid
|
|
// witness program. For nested p2sh, all the bytes after the first data
|
|
// push should *exactly* match the witness program template.
|
|
if vm.hasFlag(ScriptVerifyWitness) {
|
|
// If witness evaluation is enabled, then P2SH MUST also be
|
|
// active.
|
|
if !vm.hasFlag(ScriptBip16) {
|
|
errStr := "P2SH must be enabled to do witness verification"
|
|
return nil, scriptError(ErrInvalidFlags, errStr)
|
|
}
|
|
|
|
var witProgram []byte
|
|
|
|
switch {
|
|
case isWitnessProgram(vm.scripts[1]):
|
|
// The scriptSig must be *empty* for all native witness
|
|
// programs, otherwise we introduce malleability.
|
|
if len(scriptSig) != 0 {
|
|
errStr := "native witness program cannot " +
|
|
"also have a signature script"
|
|
return nil, scriptError(ErrWitnessMalleated, errStr)
|
|
}
|
|
|
|
witProgram = scriptPubKey
|
|
case len(tx.TxIn[txIdx].Witness) != 0 && vm.bip16:
|
|
// The sigScript MUST be *exactly* a single canonical
|
|
// data push of the witness program, otherwise we
|
|
// reintroduce malleability.
|
|
sigPops := vm.scripts[0]
|
|
if len(sigPops) == 1 && canonicalPush(sigPops[0]) &&
|
|
IsWitnessProgram(sigPops[0].data) {
|
|
|
|
witProgram = sigPops[0].data
|
|
} else {
|
|
errStr := "signature script for witness " +
|
|
"nested p2sh is not canonical"
|
|
return nil, scriptError(ErrWitnessMalleatedP2SH, errStr)
|
|
}
|
|
}
|
|
|
|
if witProgram != nil {
|
|
var err error
|
|
vm.witnessVersion, vm.witnessProgram, err = ExtractWitnessProgramInfo(witProgram)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
} else {
|
|
// If we didn't find a witness program in either the
|
|
// pkScript or as a datapush within the sigScript, then
|
|
// there MUST NOT be any witness data associated with
|
|
// the input being validated.
|
|
if !vm.witness && len(tx.TxIn[txIdx].Witness) != 0 {
|
|
errStr := "non-witness inputs cannot have a witness"
|
|
return nil, scriptError(ErrWitnessUnexpected, errStr)
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
vm.tx = *tx
|
|
vm.txIdx = txIdx
|
|
|
|
return &vm, nil
|
|
}
|