txscript: Introduce raw script sighash calc func.
This introduces a new function named calcSignatureHashRaw which accepts the raw script bytes to calculate the script hash versus requiring the parsed opcode only to unparse them later in order to make it more flexible for working with raw scripts. Since there are several places in the rest of the code that currently only have access to the parsed opcodes, this modifies the existing calcSignatureHash to first unparse the script before calling the new function. Backport of decred/dcrd:f306a72a16eaabfb7054a26f9d9f850b87b00279
This commit is contained in:
parent
ce08988514
commit
07c1a9343d
4 changed files with 49 additions and 14 deletions
|
@ -2198,7 +2198,10 @@ func opcodeCheckSig(op *parsedOpcode, vm *Engine) error {
|
|||
// to sign itself.
|
||||
subScript = removeOpcodeByData(subScript, fullSigBytes)
|
||||
|
||||
hash = calcSignatureHash(subScript, hashType, &vm.tx, vm.txIdx)
|
||||
hash, err = calcSignatureHash(subScript, hashType, &vm.tx, vm.txIdx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
pubKey, err := btcec.ParsePubKey(pkBytes, btcec.S256())
|
||||
|
@ -2467,7 +2470,10 @@ func opcodeCheckMultiSig(op *parsedOpcode, vm *Engine) error {
|
|||
return err
|
||||
}
|
||||
} else {
|
||||
hash = calcSignatureHash(script, hashType, &vm.tx, vm.txIdx)
|
||||
hash, err = calcSignatureHash(script, hashType, &vm.tx, vm.txIdx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
var valid bool
|
||||
|
|
|
@ -863,8 +863,13 @@ func TestCalcSignatureHash(t *testing.T) {
|
|||
}
|
||||
|
||||
hashType := SigHashType(testVecF64ToUint32(test[3].(float64)))
|
||||
hash := calcSignatureHash(parsedScript, hashType, &tx,
|
||||
hash, err := calcSignatureHash(parsedScript, hashType, &tx,
|
||||
int(test[2].(float64)))
|
||||
if err != nil {
|
||||
t.Errorf("TestCalcSignatureHash failed test #%d: "+
|
||||
"Failed to compute sighash: %v", i, err)
|
||||
continue
|
||||
}
|
||||
|
||||
expectedHash, _ := chainhash.NewHashFromStr(test[4].(string))
|
||||
if !bytes.Equal(hash, expectedHash[:]) {
|
||||
|
|
|
@ -572,13 +572,12 @@ func CalcSignatureHash(script []byte, hashType SigHashType, tx *wire.MsgTx, idx
|
|||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot parse output script: %v", err)
|
||||
}
|
||||
return calcSignatureHash(parsedScript, hashType, tx, idx), nil
|
||||
return calcSignatureHash(parsedScript, hashType, tx, idx)
|
||||
}
|
||||
|
||||
// calcSignatureHash will, given a script and hash type for the current script
|
||||
// engine instance, calculate the signature hash to be used for signing and
|
||||
// verification.
|
||||
func calcSignatureHash(script []parsedOpcode, hashType SigHashType, tx *wire.MsgTx, idx int) []byte {
|
||||
// calcSignatureHashRaw computes the signature hash for the specified input of
|
||||
// the target transaction observing the desired signature hash type.
|
||||
func calcSignatureHashRaw(sigScript []byte, hashType SigHashType, tx *wire.MsgTx, idx int) []byte {
|
||||
// The SigHashSingle signature type signs only the corresponding input
|
||||
// and output (the output with the same index number as the input).
|
||||
//
|
||||
|
@ -606,17 +605,24 @@ func calcSignatureHash(script []parsedOpcode, hashType SigHashType, tx *wire.Msg
|
|||
}
|
||||
|
||||
// Remove all instances of OP_CODESEPARATOR from the script.
|
||||
script = removeOpcode(script, OP_CODESEPARATOR)
|
||||
filteredScript := make([]byte, 0, len(sigScript))
|
||||
const scriptVersion = 0
|
||||
tokenizer := MakeScriptTokenizer(scriptVersion, sigScript)
|
||||
var prevOffset int32
|
||||
for tokenizer.Next() {
|
||||
if tokenizer.Opcode() != OP_CODESEPARATOR {
|
||||
filteredScript = append(filteredScript,
|
||||
sigScript[prevOffset:tokenizer.ByteIndex()]...)
|
||||
}
|
||||
prevOffset = tokenizer.ByteIndex()
|
||||
}
|
||||
|
||||
// Make a shallow copy of the transaction, zeroing out the script for
|
||||
// all inputs that are not currently being processed.
|
||||
txCopy := shallowCopyTx(tx)
|
||||
for i := range txCopy.TxIn {
|
||||
if i == idx {
|
||||
// UnparseScript cannot fail here because removeOpcode
|
||||
// above only returns a valid script.
|
||||
sigScript, _ := unparseScript(script)
|
||||
txCopy.TxIn[idx].SignatureScript = sigScript
|
||||
txCopy.TxIn[idx].SignatureScript = filteredScript
|
||||
} else {
|
||||
txCopy.TxIn[i].SignatureScript = nil
|
||||
}
|
||||
|
@ -670,6 +676,21 @@ func calcSignatureHash(script []parsedOpcode, hashType SigHashType, tx *wire.Msg
|
|||
return chainhash.DoubleHashB(wbuf.Bytes())
|
||||
}
|
||||
|
||||
// calcSignatureHash computes the signature hash for the specified input of the
|
||||
// target transaction observing the desired signature hash type.
|
||||
//
|
||||
// DEPRECATED: Use calcSignatureHashRaw instead
|
||||
func calcSignatureHash(prevOutScript []parsedOpcode, hashType SigHashType,
|
||||
tx *wire.MsgTx, idx int) ([]byte, error) {
|
||||
|
||||
sigScript, err := unparseScript(prevOutScript)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return calcSignatureHashRaw(sigScript, hashType, tx, idx), nil
|
||||
}
|
||||
|
||||
// asSmallInt returns the passed opcode, which must be true according to
|
||||
// isSmallInt(), as an integer.
|
||||
func asSmallInt(op *opcode) int {
|
||||
|
|
|
@ -345,7 +345,10 @@ sigLoop:
|
|||
// however, assume no sigs etc are in the script since that
|
||||
// would make the transaction nonstandard and thus not
|
||||
// MultiSigTy, so we just need to hash the full thing.
|
||||
hash := calcSignatureHash(pkPops, hashType, tx, idx)
|
||||
hash, err := calcSignatureHash(pkPops, hashType, tx, idx)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("cannot compute sighash: %v", err))
|
||||
}
|
||||
|
||||
for _, addr := range addresses {
|
||||
// All multisig addresses should be pubkey addresses
|
||||
|
|
Loading…
Reference in a new issue