Add script pubkey version to signature hash (#1360)

* Replace 0xffff with math.MaxUint16 on version checks

* Add script version to the signature hash

Co-authored-by: Ori Newman <orinewman1@gmail.com>
This commit is contained in:
Elichai Turkel 2021-01-06 11:51:12 +02:00 committed by GitHub
parent d8293ef635
commit 4577023e44
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 30 additions and 22 deletions

View File

@ -4,6 +4,7 @@ import (
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/utils/blockheader"
"github.com/pkg/errors"
"math"
)
// DomainBlockHeaderToDbBlockHeader converts BlockHeader to DbBlockHeader
@ -38,7 +39,7 @@ func DbBlockHeaderToDomainBlockHeader(dbBlockHeader *DbBlockHeader) (externalapi
if err != nil {
return nil, err
}
if dbBlockHeader.Version > 0xffff {
if dbBlockHeader.Version > math.MaxUint16 {
return nil, errors.Errorf("Invalid header version - bigger then uint16")
}

View File

@ -3,6 +3,7 @@ package serialization
import (
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/pkg/errors"
"math"
)
// DomainTransactionToDbTransaction converts DomainTransaction to DbTransaction
@ -73,7 +74,7 @@ func DbTransactionToDomainTransaction(dbTransaction *DbTransaction) (*externalap
}
}
if dbTransaction.Version > 0xFFFF {
if dbTransaction.Version > math.MaxUint16 {
return nil, errors.Errorf("The transaction version is bigger then uint16.")
}
return &externalapi.DomainTransaction{

View File

@ -4,6 +4,7 @@ import (
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/utils/utxo"
"github.com/pkg/errors"
"math"
)
// ScriptPublicKeyToDBScriptPublicKey converts ScriptPublicKey to DBScriptPublicKey
@ -13,7 +14,7 @@ func ScriptPublicKeyToDBScriptPublicKey(scriptPublicKey *externalapi.ScriptPubli
// DBScriptPublicKeyToScriptPublicKey convert DbScriptPublicKey ro ScriptPublicKey
func DBScriptPublicKeyToScriptPublicKey(dbScriptPublicKey *DbScriptPublicKey) (*externalapi.ScriptPublicKey, error) {
if dbScriptPublicKey.Version > 0xFFFF {
if dbScriptPublicKey.Version > math.MaxUint16 {
return nil, errors.Errorf("The version on ScriptPublicKey is bigger then uint16.")
}
return &externalapi.ScriptPublicKey{Script: dbScriptPublicKey.Script, Version: uint16(dbScriptPublicKey.Version)}, nil

View File

@ -39,7 +39,7 @@ const (
// Engine is the virtual machine that executes scripts.
type Engine struct {
isKnownVersion bool
scriptVersion uint16
scripts [][]parsedOpcode
scriptIdx int
scriptOff int
@ -315,7 +315,7 @@ func (vm *Engine) Step() (done bool, err error) {
// 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) {
if !vm.isKnownVersion {
if vm.scriptVersion > constants.MaxScriptPublicKeyVersion {
log.Tracef("The version of the scriptPublicKey is higher than the known version - the Execute function returns true.")
return nil
}
@ -454,13 +454,11 @@ func NewEngine(scriptPubKey *externalapi.ScriptPublicKey, tx *externalapi.Domain
return nil, scriptError(ErrEvalFalse,
"false stack entry at end of script execution")
}
vm := Engine{flags: flags, sigCache: sigCache}
vm := Engine{scriptVersion: scriptPubKey.Version, flags: flags, sigCache: sigCache}
if scriptPubKey.Version > constants.MaxScriptPublicKeyVersion {
vm.isKnownVersion = false
if vm.scriptVersion > constants.MaxScriptPublicKeyVersion {
return &vm, nil
}
vm.isKnownVersion = true
parsedScriptSig, err := parseScriptAndVerifySize(scriptSig)
if err != nil {
return nil, err

View File

@ -2034,7 +2034,7 @@ func opcodeCheckSig(op *parsedOpcode, vm *Engine) error {
script := vm.currentScript()
// Generate the signature hash based on the signature hash type.
sigHash, err := calcSignatureHash(script, hashType, &vm.tx, vm.txIdx)
sigHash, err := calcSignatureHash(script, vm.scriptVersion, hashType, &vm.tx, vm.txIdx)
if err != nil {
vm.dstack.PushBool(false)
return nil
@ -2241,7 +2241,7 @@ func opcodeCheckMultiSig(op *parsedOpcode, vm *Engine) error {
}
// Generate the signature hash based on the signature hash type.
sigHash, err := calcSignatureHash(script, hashType, &vm.tx, vm.txIdx)
sigHash, err := calcSignatureHash(script, vm.scriptVersion, hashType, &vm.tx, vm.txIdx)
if err != nil {
return err
}

View File

@ -6,6 +6,7 @@ package txscript
import (
"bytes"
"encoding/binary"
"fmt"
"github.com/kaspanet/kaspad/domain/consensus/utils/constants"
@ -295,13 +296,13 @@ func CalcSignatureHash(script *externalapi.ScriptPublicKey, hashType SigHashType
if err != nil {
return nil, errors.Errorf("cannot parse output script: %s", err)
}
return calcSignatureHash(parsedScript, hashType, tx, idx)
return calcSignatureHash(parsedScript, script.Version, 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 *externalapi.DomainTransaction, idx int) (*externalapi.DomainHash, error) {
func calcSignatureHash(prevScriptPublicKey []parsedOpcode, scriptVersion uint16, hashType SigHashType, tx *externalapi.DomainTransaction, idx int) (*externalapi.DomainHash, error) {
// The SigHashSingle signature type signs only the corresponding input
// and output (the output with the same index number as the input).
//
@ -320,8 +321,10 @@ func calcSignatureHash(script []parsedOpcode, hashType SigHashType, tx *external
if i == idx {
// UnparseScript cannot fail here because removeOpcode
// above only returns a valid script.
sigScript, _ := unparseScript(script)
txCopy.Inputs[idx].SignatureScript = sigScript
sigScript, _ := unparseScript(prevScriptPublicKey)
var version [2]byte
binary.LittleEndian.PutUint16(version[:], scriptVersion)
txCopy.Inputs[idx].SignatureScript = append(version[:], sigScript...)
} else {
txCopy.Inputs[i].SignatureScript = nil
}

View File

@ -4,6 +4,7 @@ import (
"github.com/kaspanet/kaspad/app/appmessage"
"github.com/kaspanet/kaspad/util/mstime"
"github.com/pkg/errors"
"math"
)
func (x *BlockHeaderMessage) toAppMessage() (*appmessage.MsgBlockHeader, error) {
@ -31,7 +32,7 @@ func (x *BlockHeaderMessage) toAppMessage() (*appmessage.MsgBlockHeader, error)
if err != nil {
return nil, err
}
if x.Version > 0xffff {
if x.Version > math.MaxUint16 {
return nil, errors.Errorf("Invalid block header version - bigger then uint16")
}
return &appmessage.MsgBlockHeader{

View File

@ -4,6 +4,7 @@ import (
"github.com/kaspanet/kaspad/app/appmessage"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/pkg/errors"
"math"
)
func (x *KaspadMessage_Transaction) toAppMessage() (appmessage.Message, error) {
@ -30,7 +31,7 @@ func (x *TransactionMessage) toAppMessage() (appmessage.Message, error) {
outputs := make([]*appmessage.TxOut, len(x.Outputs))
for i, protoOutput := range x.Outputs {
if protoOutput.ScriptPublicKey.Version > 0xFFFF {
if protoOutput.ScriptPublicKey.Version > math.MaxUint16 {
return nil, errors.Errorf("The version on ScriptPublicKey is bigger then uint16.")
}
outputs[i] = &appmessage.TxOut{
@ -55,7 +56,7 @@ func (x *TransactionMessage) toAppMessage() (appmessage.Message, error) {
return nil, err
}
}
if x.Version > 0xffff {
if x.Version > math.MaxUint16 {
return nil, errors.Errorf("Invalid transaction version - bigger then uint16")
}
return &appmessage.MsgTx{

View File

@ -3,6 +3,7 @@ package protowire
import (
"github.com/kaspanet/kaspad/app/appmessage"
"github.com/pkg/errors"
"math"
)
func (x *KaspadMessage_GetBlockRequest) toAppMessage() (appmessage.Message, error) {
@ -72,7 +73,7 @@ func (x *BlockVerboseData) toAppMessage() (*appmessage.BlockVerboseData, error)
transactionVerboseData[i] = appTransactionVerboseDatum
}
if x.Version > 0xffff {
if x.Version > math.MaxUint16 {
return nil, errors.Errorf("Invalid block header version - bigger then uint16")
}
@ -154,7 +155,7 @@ func (x *TransactionVerboseData) toAppMessage() (*appmessage.TransactionVerboseD
ScriptPubKey: scriptPubKey,
}
}
if x.Version > 0xffff {
if x.Version > math.MaxUint16 {
return nil, errors.Errorf("Invalid transaction version - bigger then uint16")
}
return &appmessage.TransactionVerboseData{

View File

@ -3,6 +3,7 @@ package protowire
import (
"github.com/kaspanet/kaspad/app/appmessage"
"github.com/pkg/errors"
"math"
)
func (x *KaspadMessage_SubmitTransactionRequest) toAppMessage() (appmessage.Message, error) {
@ -71,7 +72,7 @@ func (x *RpcTransaction) toAppMessage() (*appmessage.RPCTransaction, error) {
}
}
if x.Version > 0xffff {
if x.Version > math.MaxUint16 {
return nil, errors.Errorf("Invalid RPC txn version - bigger then uint16")
}
@ -89,7 +90,7 @@ func (x *RpcTransaction) toAppMessage() (*appmessage.RPCTransaction, error) {
// ConvertFromAppMsgRPCScriptPubKeyToRPCScriptPubKey converts from RpcScriptPubKey to RPCScriptPublicKey.
func ConvertFromAppMsgRPCScriptPubKeyToRPCScriptPubKey(toConvert *RpcScriptPublicKey) (*appmessage.RPCScriptPublicKey, error) {
if toConvert.Version > 0xffff {
if toConvert.Version > math.MaxUint16 {
return nil, errors.Errorf("Invalid header version - bigger then uint16")
}
version := uint16(toConvert.Version)