dcrd/txscript/sign_test.go
Dave Collins 1e34495ddb
txscript: Use dcrutil/v2.
This udpates the txscript module to use v2 of the dcrutil module and v2
of the chaincfg module since dcrutil/v2 requires it.

While here, it also modifies the signing functions to accept the new
dcrutil.AddressParams instead of a pointer to a chaincfg.Params struct
in order to remove the tight coupling between txscript and chaincfg at
the API boundary.

It also updates the tests accordingly.
2019-06-24 15:13:39 -05:00

2332 lines
62 KiB
Go

// Copyright (c) 2013-2016 The btcsuite developers
// Copyright (c) 2015-2019 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package txscript
import (
"crypto/rand"
"errors"
"fmt"
mrand "math/rand"
"testing"
"github.com/decred/dcrd/chaincfg/chainhash"
"github.com/decred/dcrd/chaincfg/v2"
"github.com/decred/dcrd/chaincfg/v2/chainec"
"github.com/decred/dcrd/dcrec"
"github.com/decred/dcrd/dcrutil/v2"
"github.com/decred/dcrd/wire"
)
// testingParams defines the chain params to use throughout these tests so it
// can more easily be changed if desired.
var testingParams = chaincfg.RegNetParams()
const testValueIn = 12345
type addressToKey struct {
key *chainec.PrivateKey
compressed bool
}
func mkGetKey(keys map[string]addressToKey) KeyDB {
if keys == nil {
return KeyClosure(func(addr dcrutil.Address) (chainec.PrivateKey,
bool, error) {
return nil, false, errors.New("nope 1")
})
}
return KeyClosure(func(addr dcrutil.Address) (chainec.PrivateKey,
bool, error) {
a2k, ok := keys[addr.Address()]
if !ok {
return nil, false, errors.New("nope 2")
}
return *a2k.key, a2k.compressed, nil
})
}
func mkGetKeyPub(keys map[string]addressToKey) KeyDB {
if keys == nil {
return KeyClosure(func(addr dcrutil.Address) (chainec.PrivateKey,
bool, error) {
return nil, false, errors.New("nope 1")
})
}
return KeyClosure(func(addr dcrutil.Address) (chainec.PrivateKey,
bool, error) {
a2k, ok := keys[addr.String()]
if !ok {
return nil, false, errors.New("nope 2")
}
return *a2k.key, a2k.compressed, nil
})
}
func mkGetScript(scripts map[string][]byte) ScriptDB {
if scripts == nil {
return ScriptClosure(func(addr dcrutil.Address) (
[]byte, error) {
return nil, errors.New("nope 3")
})
}
return ScriptClosure(func(addr dcrutil.Address) ([]byte,
error) {
script, ok := scripts[addr.Address()]
if !ok {
return nil, errors.New("nope 4")
}
return script, nil
})
}
func checkScripts(msg string, tx *wire.MsgTx, idx int, sigScript, pkScript []byte) error {
tx.TxIn[idx].SignatureScript = sigScript
var scriptFlags ScriptFlags
vm, err := NewEngine(pkScript, tx, idx, scriptFlags, 0, nil)
if err != nil {
return fmt.Errorf("failed to make script engine for %s: %v",
msg, err)
}
err = vm.Execute()
if err != nil {
return fmt.Errorf("invalid script signature for %s: %v", msg,
err)
}
return nil
}
func signAndCheck(msg string, tx *wire.MsgTx, idx int, pkScript []byte,
hashType SigHashType, kdb KeyDB, sdb ScriptDB,
suite dcrec.SignatureType) error {
sigScript, err := SignTxOutput(testingParams, tx, idx, pkScript,
hashType, kdb, sdb, nil, suite)
if err != nil {
return fmt.Errorf("failed to sign output %s: %v", msg, err)
}
return checkScripts(msg, tx, idx, sigScript, pkScript)
}
func signBadAndCheck(msg string, tx *wire.MsgTx, idx int, pkScript []byte,
hashType SigHashType, kdb KeyDB, sdb ScriptDB,
suite dcrec.SignatureType) error {
// Setup a PRNG.
randScriptHash := chainhash.HashB(pkScript)
tRand := mrand.New(mrand.NewSource(int64(randScriptHash[0])))
sigScript, err := SignTxOutput(testingParams, tx,
idx, pkScript, hashType, kdb, sdb, nil, suite)
if err != nil {
return fmt.Errorf("failed to sign output %s: %v", msg, err)
}
// Be sure to reset the value in when we're done creating the
// corrupted signature for that flag.
tx.TxIn[0].ValueIn = testValueIn
// Corrupt a random bit in the signature.
pos := tRand.Intn(len(sigScript) - 1)
bitPos := tRand.Intn(7)
sigScript[pos] ^= 1 << uint8(bitPos)
return checkScripts(msg, tx, idx, sigScript, pkScript)
}
func TestSignTxOutput(t *testing.T) {
t.Parallel()
// make key
// make script based on key.
// sign with magic pixie dust.
hashTypes := []SigHashType{
SigHashAll,
SigHashNone,
SigHashSingle,
SigHashAll | SigHashAnyOneCanPay,
SigHashNone | SigHashAnyOneCanPay,
SigHashSingle | SigHashAnyOneCanPay,
}
signatureSuites := []dcrec.SignatureType{
dcrec.STEcdsaSecp256k1,
dcrec.STEd25519,
dcrec.STSchnorrSecp256k1,
}
tx := &wire.MsgTx{
SerType: wire.TxSerializeFull,
Version: 1,
TxIn: []*wire.TxIn{
{
PreviousOutPoint: wire.OutPoint{
Hash: chainhash.Hash{},
Index: 0,
Tree: 0,
},
Sequence: 4294967295,
ValueIn: testValueIn,
BlockHeight: 78901,
BlockIndex: 23456,
},
{
PreviousOutPoint: wire.OutPoint{
Hash: chainhash.Hash{},
Index: 1,
Tree: 0,
},
Sequence: 4294967295,
ValueIn: testValueIn,
BlockHeight: 78901,
BlockIndex: 23456,
},
{
PreviousOutPoint: wire.OutPoint{
Hash: chainhash.Hash{},
Index: 2,
Tree: 0,
},
Sequence: 4294967295,
ValueIn: testValueIn,
BlockHeight: 78901,
BlockIndex: 23456,
},
},
TxOut: []*wire.TxOut{
{
Version: wire.DefaultPkScriptVersion,
Value: 1,
},
{
Version: wire.DefaultPkScriptVersion,
Value: 2,
},
{
Version: wire.DefaultPkScriptVersion,
Value: 3,
},
},
LockTime: 0,
Expiry: 0,
}
// Pay to Pubkey Hash (uncompressed)
secp256k1 := chainec.Secp256k1
for _, hashType := range hashTypes {
for _, suite := range signatureSuites {
for i := range tx.TxIn {
var keyDB, pkBytes []byte
var key chainec.PrivateKey
var pk chainec.PublicKey
switch suite {
case dcrec.STEcdsaSecp256k1:
keyDB, _, _, _ = secp256k1.GenerateKey(rand.Reader)
key, pk = secp256k1.PrivKeyFromBytes(keyDB)
pkBytes = pk.SerializeUncompressed()
case dcrec.STEd25519:
keyDB, _, _, _ = chainec.Edwards.GenerateKey(rand.Reader)
key, pk = chainec.Edwards.PrivKeyFromBytes(keyDB)
pkBytes = pk.SerializeUncompressed()
case dcrec.STSchnorrSecp256k1:
keyDB, _, _, _ = chainec.SecSchnorr.GenerateKey(
rand.Reader)
key, pk = chainec.SecSchnorr.PrivKeyFromBytes(keyDB)
pkBytes = pk.Serialize()
}
msg := fmt.Sprintf("%d:%d:%d", hashType, i, suite)
address, err := dcrutil.NewAddressPubKeyHash(
dcrutil.Hash160(pkBytes), testingParams,
suite)
if err != nil {
t.Errorf("failed to make address for %s: %v",
msg, err)
break
}
pkScript, err := PayToAddrScript(address)
if err != nil {
t.Errorf("failed to make pkscript "+
"for %s: %v", msg, err)
}
if err := signAndCheck(msg, tx, i, pkScript, hashType,
mkGetKey(map[string]addressToKey{
address.Address(): {&key, false},
}), mkGetScript(nil), suite); err != nil {
t.Error(err)
break
}
if err := signBadAndCheck(msg, tx, i, pkScript, hashType,
mkGetKey(map[string]addressToKey{
address.Address(): {&key, false},
}), mkGetScript(nil), suite); err == nil {
t.Errorf("corrupted signature validated %s: %v",
msg, err)
break
}
}
}
}
// Pay to Pubkey Hash (uncompressed) (merging with correct)
for _, hashType := range hashTypes {
for _, suite := range signatureSuites {
for i := range tx.TxIn {
var keyDB, pkBytes []byte
var key chainec.PrivateKey
var pk chainec.PublicKey
switch suite {
case dcrec.STEcdsaSecp256k1:
keyDB, _, _, _ = secp256k1.GenerateKey(rand.Reader)
key, pk = secp256k1.PrivKeyFromBytes(keyDB)
pkBytes = pk.SerializeUncompressed()
case dcrec.STEd25519:
keyDB, _, _, _ = chainec.Edwards.GenerateKey(rand.Reader)
key, pk = chainec.Edwards.PrivKeyFromBytes(keyDB)
pkBytes = pk.SerializeUncompressed()
case dcrec.STSchnorrSecp256k1:
keyDB, _, _, _ = chainec.SecSchnorr.GenerateKey(rand.Reader)
key, pk = chainec.SecSchnorr.PrivKeyFromBytes(keyDB)
pkBytes = pk.Serialize()
}
msg := fmt.Sprintf("%d:%d:%d", hashType, i, suite)
address, err := dcrutil.NewAddressPubKeyHash(
dcrutil.Hash160(pkBytes), testingParams,
suite)
if err != nil {
t.Errorf("failed to make address for %s: %v",
msg, err)
break
}
pkScript, err := PayToAddrScript(address)
if err != nil {
t.Errorf("failed to make pkscript "+
"for %s: %v", msg, err)
}
sigScript, err := SignTxOutput(
testingParams, tx, i, pkScript,
hashType, mkGetKey(map[string]addressToKey{
address.Address(): {&key, false},
}), mkGetScript(nil), nil, suite)
if err != nil {
t.Errorf("failed to sign output %s: %v", msg,
err)
break
}
// by the above loop, this should be valid, now sign
// again and merge.
sigScript, err = SignTxOutput(
testingParams, tx, i, pkScript,
hashType, mkGetKey(map[string]addressToKey{
address.Address(): {&key, false},
}), mkGetScript(nil), sigScript, suite)
if err != nil {
t.Errorf("failed to sign output %s a "+
"second time: %v", msg, err)
break
}
err = checkScripts(msg, tx, i, sigScript, pkScript)
if err != nil {
t.Errorf("twice signed script invalid for "+
"%s: %v", msg, err)
break
}
}
}
}
// Pay to Pubkey Hash (compressed)
for _, hashType := range hashTypes {
for _, suite := range signatureSuites {
for i := range tx.TxIn {
var keyDB, pkBytes []byte
var key chainec.PrivateKey
var pk chainec.PublicKey
switch suite {
case dcrec.STEcdsaSecp256k1:
keyDB, _, _, _ = secp256k1.GenerateKey(rand.Reader)
key, pk = secp256k1.PrivKeyFromBytes(keyDB)
pkBytes = pk.SerializeCompressed()
case dcrec.STEd25519:
keyDB, _, _, _ = chainec.Edwards.GenerateKey(rand.Reader)
key, pk = chainec.Edwards.PrivKeyFromBytes(keyDB)
pkBytes = pk.SerializeCompressed()
case dcrec.STSchnorrSecp256k1:
keyDB, _, _, _ = chainec.SecSchnorr.GenerateKey(rand.Reader)
key, pk = chainec.SecSchnorr.PrivKeyFromBytes(keyDB)
pkBytes = pk.SerializeCompressed()
}
msg := fmt.Sprintf("%d:%d:%d", hashType, i, suite)
address, err := dcrutil.NewAddressPubKeyHash(
dcrutil.Hash160(pkBytes), testingParams,
suite)
if err != nil {
t.Errorf("failed to make address for %s: %v",
msg, err)
break
}
pkScript, err := PayToAddrScript(address)
if err != nil {
t.Errorf("failed to make pkscript "+
"for %s: %v", msg, err)
}
if err := signAndCheck(msg, tx, i, pkScript, hashType,
mkGetKey(map[string]addressToKey{
address.Address(): {&key, true},
}), mkGetScript(nil), suite); err != nil {
t.Error(err)
break
}
if err := signBadAndCheck(msg, tx, i, pkScript, hashType,
mkGetKey(map[string]addressToKey{
address.Address(): {&key, true},
}), mkGetScript(nil), suite); err == nil {
t.Errorf("corrupted signature validated %s: %v",
msg, err)
break
}
}
}
}
// Pay to Pubkey Hash (compressed) with duplicate merge
for _, hashType := range hashTypes {
for _, suite := range signatureSuites {
for i := range tx.TxIn {
var keyDB, pkBytes []byte
var key chainec.PrivateKey
var pk chainec.PublicKey
switch suite {
case dcrec.STEcdsaSecp256k1:
keyDB, _, _, _ = secp256k1.GenerateKey(rand.Reader)
key, pk = secp256k1.PrivKeyFromBytes(keyDB)
pkBytes = pk.SerializeCompressed()
case dcrec.STEd25519:
keyDB, _, _, _ = chainec.Edwards.GenerateKey(rand.Reader)
key, pk = chainec.Edwards.PrivKeyFromBytes(keyDB)
pkBytes = pk.SerializeCompressed()
case dcrec.STSchnorrSecp256k1:
keyDB, _, _, _ = chainec.SecSchnorr.GenerateKey(rand.Reader)
key, pk = chainec.SecSchnorr.PrivKeyFromBytes(keyDB)
pkBytes = pk.SerializeCompressed()
}
msg := fmt.Sprintf("%d:%d:%d", hashType, i, suite)
address, err := dcrutil.NewAddressPubKeyHash(
dcrutil.Hash160(pkBytes), testingParams,
suite)
if err != nil {
t.Errorf("failed to make address for %s: %v",
msg, err)
break
}
pkScript, err := PayToAddrScript(address)
if err != nil {
t.Errorf("failed to make pkscript "+
"for %s: %v", msg, err)
}
sigScript, err := SignTxOutput(testingParams,
tx, i, pkScript, hashType,
mkGetKey(map[string]addressToKey{
address.Address(): {&key, true},
}), mkGetScript(nil), nil, suite)
if err != nil {
t.Errorf("failed to sign output %s: %v", msg,
err)
break
}
// by the above loop, this should be valid, now sign
// again and merge.
sigScript, err = SignTxOutput(testingParams,
tx, i, pkScript,
hashType, mkGetKey(map[string]addressToKey{
address.Address(): {&key, true},
}), mkGetScript(nil), sigScript, suite)
if err != nil {
t.Errorf("failed to sign output %s a "+
"second time: %v", msg, err)
break
}
err = checkScripts(msg, tx, i, sigScript, pkScript)
if err != nil {
t.Errorf("twice signed script invalid for "+
"%s: %v", msg, err)
break
}
}
}
}
// Pay to Pubkey Hash for a ticket(SStx) (compressed)
for _, hashType := range hashTypes {
for i := range tx.TxIn {
msg := fmt.Sprintf("%d:%d", hashType, i)
keyDB, _, _, err := secp256k1.GenerateKey(rand.Reader)
if err != nil {
t.Errorf("failed to generate key: %v", err)
break
}
key, pk := secp256k1.PrivKeyFromBytes(keyDB)
pkBytes := pk.SerializeCompressed()
address, err := dcrutil.NewAddressPubKeyHash(
dcrutil.Hash160(pkBytes), testingParams,
dcrec.STEcdsaSecp256k1)
if err != nil {
t.Errorf("failed to make address for %s: %v",
msg, err)
break
}
pkScript, err := PayToSStx(address)
if err != nil {
t.Errorf("failed to make pkscript "+
"for %s: %v", msg, err)
}
if err := signAndCheck(msg, tx, i, pkScript, hashType,
mkGetKey(map[string]addressToKey{
address.Address(): {&key, true},
}), mkGetScript(nil),
dcrec.STEcdsaSecp256k1); err != nil {
t.Error(err)
break
}
if err := signBadAndCheck(msg, tx, i, pkScript, hashType,
mkGetKey(map[string]addressToKey{
address.Address(): {&key, true},
}), mkGetScript(nil),
dcrec.STEcdsaSecp256k1); err == nil {
t.Errorf("corrupted signature validated %s: %v",
msg, err)
break
}
}
}
// Pay to Pubkey Hash for a ticket change (SStx change) (compressed)
for _, hashType := range hashTypes {
for i := range tx.TxIn {
msg := fmt.Sprintf("%d:%d", hashType, i)
keyDB, _, _, err := secp256k1.GenerateKey(rand.Reader)
if err != nil {
t.Errorf("failed to generate key: %v", err)
break
}
key, pk := secp256k1.PrivKeyFromBytes(keyDB)
pkBytes := pk.SerializeCompressed()
address, err := dcrutil.NewAddressPubKeyHash(
dcrutil.Hash160(pkBytes), testingParams,
dcrec.STEcdsaSecp256k1)
if err != nil {
t.Errorf("failed to make address for %s: %v",
msg, err)
break
}
pkScript, err := PayToSStxChange(address)
if err != nil {
t.Errorf("failed to make pkscript "+
"for %s: %v", msg, err)
}
if err := signAndCheck(msg, tx, i, pkScript, hashType,
mkGetKey(map[string]addressToKey{
address.Address(): {&key, true},
}), mkGetScript(nil),
dcrec.STEcdsaSecp256k1); err != nil {
t.Error(err)
break
}
if err := signBadAndCheck(msg, tx, i, pkScript, hashType,
mkGetKey(map[string]addressToKey{
address.Address(): {&key, true},
}), mkGetScript(nil),
dcrec.STEcdsaSecp256k1); err == nil {
t.Errorf("corrupted signature validated %s: %v",
msg, err)
break
}
}
}
// Pay to Pubkey Hash for a ticket spending (SSGen) (compressed)
for _, hashType := range hashTypes {
for i := range tx.TxIn {
msg := fmt.Sprintf("%d:%d", hashType, i)
keyDB, _, _, err := secp256k1.GenerateKey(rand.Reader)
if err != nil {
t.Errorf("failed to generate key: %v", err)
break
}
key, pk := secp256k1.PrivKeyFromBytes(keyDB)
pkBytes := pk.SerializeCompressed()
address, err := dcrutil.NewAddressPubKeyHash(
dcrutil.Hash160(pkBytes), testingParams,
dcrec.STEcdsaSecp256k1)
if err != nil {
t.Errorf("failed to make address for %s: %v",
msg, err)
break
}
pkScript, err := PayToSSGen(address)
if err != nil {
t.Errorf("failed to make pkscript "+
"for %s: %v", msg, err)
}
if err := signAndCheck(msg, tx, i, pkScript, hashType,
mkGetKey(map[string]addressToKey{
address.Address(): {&key, true},
}), mkGetScript(nil),
dcrec.STEcdsaSecp256k1); err != nil {
t.Error(err)
break
}
if err := signBadAndCheck(msg, tx, i, pkScript, hashType,
mkGetKey(map[string]addressToKey{
address.Address(): {&key, true},
}), mkGetScript(nil),
dcrec.STEcdsaSecp256k1); err == nil {
t.Errorf("corrupted signature validated %s: %v",
msg, err)
break
}
}
}
// Pay to Pubkey Hash for a ticket revocation (SSRtx) (compressed)
for _, hashType := range hashTypes {
for i := range tx.TxIn {
msg := fmt.Sprintf("%d:%d", hashType, i)
keyDB, _, _, err := secp256k1.GenerateKey(rand.Reader)
if err != nil {
t.Errorf("failed to generate key: %v", err)
break
}
key, pk := secp256k1.PrivKeyFromBytes(keyDB)
pkBytes := pk.SerializeCompressed()
address, err := dcrutil.NewAddressPubKeyHash(
dcrutil.Hash160(pkBytes), testingParams,
dcrec.STEcdsaSecp256k1)
if err != nil {
t.Errorf("failed to make address for %s: %v",
msg, err)
break
}
pkScript, err := PayToSSRtx(address)
if err != nil {
t.Errorf("failed to make pkscript "+
"for %s: %v", msg, err)
}
if err := signAndCheck(msg, tx, i, pkScript, hashType,
mkGetKey(map[string]addressToKey{
address.Address(): {&key, true},
}), mkGetScript(nil),
dcrec.STEcdsaSecp256k1); err != nil {
t.Error(err)
break
}
if err := signBadAndCheck(msg, tx, i, pkScript, hashType,
mkGetKey(map[string]addressToKey{
address.Address(): {&key, true},
}), mkGetScript(nil),
dcrec.STEcdsaSecp256k1); err == nil {
t.Errorf("corrupted signature validated %s: %v",
msg, err)
break
}
}
}
// Pay to PubKey (uncompressed)
for _, hashType := range hashTypes {
for _, suite := range signatureSuites {
for i := range tx.TxIn {
msg := fmt.Sprintf("%d:%d:%d", hashType, i, suite)
keyDB, _, _, err := secp256k1.GenerateKey(rand.Reader)
if err != nil {
t.Errorf("failed to generate key: %v", err)
break
}
key, pk := secp256k1.PrivKeyFromBytes(keyDB)
// For address generation, consensus rules require using
// a compressed public key. Look up ExtractPkScriptAddrs
// for more details
address, err := dcrutil.NewAddressSecpPubKeyCompressed(pk,
testingParams)
if err != nil {
t.Errorf("failed to make address for %s: %v",
msg, err)
break
}
pkScript, err := PayToAddrScript(address)
if err != nil {
t.Errorf("failed to make pkscript "+
"for %s: %v", msg, err)
}
if err := signAndCheck(msg, tx, i, pkScript, hashType,
mkGetKey(map[string]addressToKey{
address.Address(): {&key, false},
}), mkGetScript(nil), suite); err != nil {
t.Error(err)
break
}
if err := signBadAndCheck(msg, tx, i, pkScript, hashType,
mkGetKey(map[string]addressToKey{
address.Address(): {&key, false},
}), mkGetScript(nil), suite); err == nil {
t.Errorf("corrupted signature validated %s: %v",
msg, err)
break
}
}
}
}
// Pay to PubKey (uncompressed)
for _, hashType := range hashTypes {
for _, suite := range signatureSuites {
for i := range tx.TxIn {
var keyDB, pkBytes []byte
var key chainec.PrivateKey
var pk chainec.PublicKey
var address dcrutil.Address
var err error
msg := fmt.Sprintf("%d:%d:%d", hashType, i, suite)
switch suite {
case dcrec.STEcdsaSecp256k1:
keyDB, _, _, _ = secp256k1.GenerateKey(rand.Reader)
key, pk = secp256k1.PrivKeyFromBytes(keyDB)
// For address generation, consensus rules require using
// a compressed public key. Look up ExtractPkScriptAddrs
// for more details
address, err = dcrutil.NewAddressSecpPubKeyCompressed(pk,
testingParams)
if err != nil {
t.Errorf("failed to make address for %s: %v",
msg, err)
}
case dcrec.STEd25519:
keyDB, _, _, _ = chainec.Edwards.GenerateKey(rand.Reader)
key, pk = chainec.Edwards.PrivKeyFromBytes(keyDB)
pkBytes = pk.SerializeUncompressed()
address, err = dcrutil.NewAddressEdwardsPubKey(pkBytes,
testingParams)
if err != nil {
t.Errorf("failed to make address for %s: %v",
msg, err)
}
case dcrec.STSchnorrSecp256k1:
keyDB, _, _, _ = chainec.SecSchnorr.GenerateKey(rand.Reader)
key, pk = chainec.SecSchnorr.PrivKeyFromBytes(keyDB)
pkBytes = pk.Serialize()
address, err = dcrutil.NewAddressSecSchnorrPubKey(pkBytes,
testingParams)
if err != nil {
t.Errorf("failed to make address for %s: %v",
msg, err)
}
}
pkScript, err := PayToAddrScript(address)
if err != nil {
t.Errorf("failed to make pkscript "+
"for %s: %v", msg, err)
}
sigScript, err := SignTxOutput(testingParams,
tx, i, pkScript, hashType,
mkGetKeyPub(map[string]addressToKey{
address.String(): {&key, false},
}), mkGetScript(nil), nil, suite)
if err != nil {
t.Errorf("failed to sign output %s: %v", msg,
err)
}
// by the above loop, this should be valid, now sign
// again and merge.
sigScript, err = SignTxOutput(testingParams,
tx, i, pkScript, hashType,
mkGetKeyPub(map[string]addressToKey{
address.String(): {&key, false},
}), mkGetScript(nil), sigScript, suite)
if err != nil {
t.Errorf("failed to sign output %s a "+
"second time: %v", msg, err)
}
err = checkScripts(msg, tx, i, sigScript, pkScript)
if err != nil {
t.Errorf("twice signed script invalid for "+
"%s: %v", msg, err)
}
}
}
}
// Pay to PubKey (compressed)
for _, hashType := range hashTypes {
for _, suite := range signatureSuites {
for i := range tx.TxIn {
var keyDB, pkBytes []byte
var key chainec.PrivateKey
var pk chainec.PublicKey
var address dcrutil.Address
var err error
msg := fmt.Sprintf("%d:%d:%d", hashType, i, suite)
switch suite {
case dcrec.STEcdsaSecp256k1:
keyDB, _, _, _ = secp256k1.GenerateKey(rand.Reader)
key, pk = secp256k1.PrivKeyFromBytes(keyDB)
// For address generation, consensus rules require using
// a compressed public key. Look up ExtractPkScriptAddrs
// for more details
address, err = dcrutil.NewAddressSecpPubKeyCompressed(pk,
testingParams)
if err != nil {
t.Errorf("failed to make address for %s: %v",
msg, err)
}
case dcrec.STEd25519:
keyDB, _, _, _ = chainec.Edwards.GenerateKey(rand.Reader)
key, pk = chainec.Edwards.PrivKeyFromBytes(keyDB)
pkBytes = pk.SerializeCompressed()
address, err = dcrutil.NewAddressEdwardsPubKey(pkBytes,
testingParams)
if err != nil {
t.Errorf("failed to make address for %s: %v",
msg, err)
}
case dcrec.STSchnorrSecp256k1:
keyDB, _, _, _ = chainec.SecSchnorr.GenerateKey(rand.Reader)
key, pk = chainec.SecSchnorr.PrivKeyFromBytes(keyDB)
pkBytes = pk.Serialize()
address, err = dcrutil.NewAddressSecSchnorrPubKey(pkBytes,
testingParams)
if err != nil {
t.Errorf("failed to make address for %s: %v",
msg, err)
}
}
pkScript, err := PayToAddrScript(address)
if err != nil {
t.Errorf("failed to make pkscript "+
"for %s: %v", msg, err)
}
if err := signAndCheck(msg, tx, i, pkScript, hashType,
mkGetKeyPub(map[string]addressToKey{
address.String(): {&key, true},
}), mkGetScript(nil), suite); err != nil {
t.Error(err)
break
}
if err := signBadAndCheck(msg, tx, i, pkScript, hashType,
mkGetKeyPub(map[string]addressToKey{
address.String(): {&key, true},
}), mkGetScript(nil), suite); err == nil {
t.Errorf("corrupted signature validated %s: %v",
msg, err)
break
}
}
}
}
// Pay to PubKey (compressed) with duplicate merge
for _, hashType := range hashTypes {
for _, suite := range signatureSuites {
for i := range tx.TxIn {
var keyDB, pkBytes []byte
var key chainec.PrivateKey
var pk chainec.PublicKey
var address dcrutil.Address
var err error
msg := fmt.Sprintf("%d:%d:%d", hashType, i, suite)
switch suite {
case dcrec.STEcdsaSecp256k1:
keyDB, _, _, _ = secp256k1.GenerateKey(rand.Reader)
key, pk = secp256k1.PrivKeyFromBytes(keyDB)
address, err = dcrutil.NewAddressSecpPubKeyCompressed(pk,
testingParams)
if err != nil {
t.Errorf("failed to make address for %s: %v",
msg, err)
}
case dcrec.STEd25519:
keyDB, _, _, _ = chainec.Edwards.GenerateKey(rand.Reader)
key, pk = chainec.Edwards.PrivKeyFromBytes(keyDB)
pkBytes = pk.SerializeCompressed()
address, err = dcrutil.NewAddressEdwardsPubKey(pkBytes,
testingParams)
if err != nil {
t.Errorf("failed to make address for %s: %v",
msg, err)
}
case dcrec.STSchnorrSecp256k1:
keyDB, _, _, _ = chainec.SecSchnorr.GenerateKey(rand.Reader)
key, pk = chainec.SecSchnorr.PrivKeyFromBytes(keyDB)
pkBytes = pk.Serialize()
address, err = dcrutil.NewAddressSecSchnorrPubKey(pkBytes,
testingParams)
if err != nil {
t.Errorf("failed to make address for %s: %v",
msg, err)
}
}
pkScript, err := PayToAddrScript(address)
if err != nil {
t.Errorf("failed to make pkscript "+
"for %s: %v", msg, err)
}
sigScript, err := SignTxOutput(testingParams,
tx, i, pkScript, hashType,
mkGetKey(map[string]addressToKey{
address.Address(): {&key, true},
}), mkGetScript(nil), nil, suite)
if err != nil {
t.Errorf("failed to sign output %s: %v", msg,
err)
break
}
// by the above loop, this should be valid, now sign
// again and merge.
sigScript, err = SignTxOutput(testingParams,
tx, i, pkScript, hashType,
mkGetKey(map[string]addressToKey{
address.Address(): {&key, true},
}), mkGetScript(nil), sigScript, suite)
if err != nil {
t.Errorf("failed to sign output %s a "+
"second time: %v", msg, err)
break
}
err = checkScripts(msg, tx, i, sigScript, pkScript)
if err != nil {
t.Errorf("twice signed script invalid for "+
"%s: %v", msg, err)
break
}
}
}
}
// As before, but with p2sh now.
// Pay to Pubkey Hash (uncompressed)
for _, hashType := range hashTypes {
for _, suite := range signatureSuites {
for i := range tx.TxIn {
var keyDB, pkBytes []byte
var key chainec.PrivateKey
var pk chainec.PublicKey
switch suite {
case dcrec.STEcdsaSecp256k1:
keyDB, _, _, _ = secp256k1.GenerateKey(rand.Reader)
key, pk = secp256k1.PrivKeyFromBytes(keyDB)
pkBytes = pk.SerializeUncompressed()
case dcrec.STEd25519:
keyDB, _, _, _ = chainec.Edwards.GenerateKey(rand.Reader)
key, pk = chainec.Edwards.PrivKeyFromBytes(keyDB)
pkBytes = pk.SerializeUncompressed()
case dcrec.STSchnorrSecp256k1:
keyDB, _, _, _ = chainec.SecSchnorr.GenerateKey(rand.Reader)
key, pk = chainec.SecSchnorr.PrivKeyFromBytes(keyDB)
pkBytes = pk.Serialize()
}
msg := fmt.Sprintf("%d:%d:%d", hashType, i, suite)
address, err := dcrutil.NewAddressPubKeyHash(
dcrutil.Hash160(pkBytes), testingParams, suite)
if err != nil {
t.Errorf("failed to make address for %s: %v",
msg, err)
break
}
pkScript, err := PayToAddrScript(address)
if err != nil {
t.Errorf("failed to make pkscript "+
"for %s: %v", msg, err)
break
}
scriptAddr, err := dcrutil.NewAddressScriptHash(
pkScript, testingParams)
if err != nil {
t.Errorf("failed to make p2sh addr for %s: %v",
msg, err)
break
}
scriptPkScript, err := PayToAddrScript(
scriptAddr)
if err != nil {
t.Errorf("failed to make script pkscript for "+
"%s: %v", msg, err)
break
}
if err := signAndCheck(msg, tx, i, scriptPkScript,
hashType,
mkGetKey(map[string]addressToKey{
address.Address(): {&key, false},
}), mkGetScript(map[string][]byte{
scriptAddr.Address(): pkScript,
}), suite); err != nil {
t.Error(err)
break
}
if err := signBadAndCheck(msg, tx, i, pkScript, hashType,
mkGetKey(map[string]addressToKey{
address.Address(): {&key, false},
}), mkGetScript(nil), suite); err == nil {
t.Errorf("corrupted signature validated %s: %v",
msg, err)
break
}
}
}
}
// Pay to Pubkey Hash (uncompressed) with duplicate merge
for _, hashType := range hashTypes {
for _, suite := range signatureSuites {
for i := range tx.TxIn {
var keyDB, pkBytes []byte
var key chainec.PrivateKey
var pk chainec.PublicKey
switch suite {
case dcrec.STEcdsaSecp256k1:
keyDB, _, _, _ = secp256k1.GenerateKey(rand.Reader)
key, pk = secp256k1.PrivKeyFromBytes(keyDB)
pkBytes = pk.SerializeUncompressed()
case dcrec.STEd25519:
keyDB, _, _, _ = chainec.Edwards.GenerateKey(rand.Reader)
key, pk = chainec.Edwards.PrivKeyFromBytes(keyDB)
pkBytes = pk.SerializeUncompressed()
case dcrec.STSchnorrSecp256k1:
keyDB, _, _, _ = chainec.SecSchnorr.GenerateKey(rand.Reader)
key, pk = chainec.SecSchnorr.PrivKeyFromBytes(keyDB)
pkBytes = pk.Serialize()
}
msg := fmt.Sprintf("%d:%d:%d", hashType, i, suite)
address, err := dcrutil.NewAddressPubKeyHash(
dcrutil.Hash160(pkBytes), testingParams, suite)
if err != nil {
t.Errorf("failed to make address for %s: %v",
msg, err)
break
}
pkScript, err := PayToAddrScript(address)
if err != nil {
t.Errorf("failed to make pkscript "+
"for %s: %v", msg, err)
break
}
scriptAddr, err := dcrutil.NewAddressScriptHash(
pkScript, testingParams)
if err != nil {
t.Errorf("failed to make p2sh addr for %s: %v",
msg, err)
break
}
scriptPkScript, err := PayToAddrScript(
scriptAddr)
if err != nil {
t.Errorf("failed to make script pkscript for "+
"%s: %v", msg, err)
break
}
_, err = SignTxOutput(testingParams, tx, i,
scriptPkScript, hashType,
mkGetKey(map[string]addressToKey{
address.Address(): {&key, false},
}), mkGetScript(map[string][]byte{
scriptAddr.Address(): pkScript,
}), nil, suite)
if err != nil {
t.Errorf("failed to sign output %s: %v", msg,
err)
break
}
// by the above loop, this should be valid, now sign
// again and merge.
sigScript, err := SignTxOutput(testingParams,
tx, i, scriptPkScript, hashType,
mkGetKey(map[string]addressToKey{
address.Address(): {&key, false},
}), mkGetScript(map[string][]byte{
scriptAddr.Address(): pkScript,
}), nil, suite)
if err != nil {
t.Errorf("failed to sign output %s a "+
"second time: %v", msg, err)
break
}
err = checkScripts(msg, tx, i, sigScript, scriptPkScript)
if err != nil {
t.Errorf("twice signed script invalid for "+
"%s: %v", msg, err)
break
}
}
}
}
// Pay to Pubkey Hash (compressed)
for _, hashType := range hashTypes {
for _, suite := range signatureSuites {
for i := range tx.TxIn {
var keyDB, pkBytes []byte
var key chainec.PrivateKey
var pk chainec.PublicKey
switch suite {
case dcrec.STEcdsaSecp256k1:
keyDB, _, _, _ = secp256k1.GenerateKey(rand.Reader)
key, pk = secp256k1.PrivKeyFromBytes(keyDB)
pkBytes = pk.SerializeCompressed()
case dcrec.STEd25519:
keyDB, _, _, _ = chainec.Edwards.GenerateKey(rand.Reader)
key, pk = chainec.Edwards.PrivKeyFromBytes(keyDB)
pkBytes = pk.SerializeCompressed()
case dcrec.STSchnorrSecp256k1:
keyDB, _, _, _ = chainec.SecSchnorr.GenerateKey(rand.Reader)
key, pk = chainec.SecSchnorr.PrivKeyFromBytes(keyDB)
pkBytes = pk.SerializeCompressed()
}
msg := fmt.Sprintf("%d:%d:%d", hashType, i, suite)
address, err := dcrutil.NewAddressPubKeyHash(
dcrutil.Hash160(pkBytes), testingParams, suite)
if err != nil {
t.Errorf("failed to make address for %s: %v",
msg, err)
break
}
pkScript, err := PayToAddrScript(address)
if err != nil {
t.Errorf("failed to make pkscript "+
"for %s: %v", msg, err)
}
scriptAddr, err := dcrutil.NewAddressScriptHash(
pkScript, testingParams)
if err != nil {
t.Errorf("failed to make p2sh addr for %s: %v",
msg, err)
break
}
scriptPkScript, err := PayToAddrScript(
scriptAddr)
if err != nil {
t.Errorf("failed to make script pkscript for "+
"%s: %v", msg, err)
break
}
if err := signAndCheck(msg, tx, i, scriptPkScript,
hashType,
mkGetKey(map[string]addressToKey{
address.Address(): {&key, true},
}), mkGetScript(map[string][]byte{
scriptAddr.Address(): pkScript,
}), suite); err != nil {
t.Error(err)
break
}
if err := signBadAndCheck(msg, tx, i, pkScript, hashType,
mkGetKey(map[string]addressToKey{
address.Address(): {&key, true},
}), mkGetScript(nil), suite); err == nil {
t.Errorf("corrupted signature validated %s: %v",
msg, err)
break
}
}
}
}
// Pay to Pubkey Hash (compressed) with duplicate merge
for _, hashType := range hashTypes {
for _, suite := range signatureSuites {
for i := range tx.TxIn {
var keyDB, pkBytes []byte
var key chainec.PrivateKey
var pk chainec.PublicKey
switch suite {
case dcrec.STEcdsaSecp256k1:
keyDB, _, _, _ = secp256k1.GenerateKey(rand.Reader)
key, pk = secp256k1.PrivKeyFromBytes(keyDB)
pkBytes = pk.SerializeCompressed()
case dcrec.STEd25519:
keyDB, _, _, _ = chainec.Edwards.GenerateKey(rand.Reader)
key, pk = chainec.Edwards.PrivKeyFromBytes(keyDB)
pkBytes = pk.SerializeCompressed()
case dcrec.STSchnorrSecp256k1:
keyDB, _, _, _ = chainec.SecSchnorr.GenerateKey(rand.Reader)
key, pk = chainec.SecSchnorr.PrivKeyFromBytes(keyDB)
pkBytes = pk.SerializeCompressed()
}
msg := fmt.Sprintf("%d:%d:%d", hashType, i, suite)
address, err := dcrutil.NewAddressPubKeyHash(
dcrutil.Hash160(pkBytes), testingParams, suite)
if err != nil {
t.Errorf("failed to make address for %s: %v",
msg, err)
break
}
pkScript, err := PayToAddrScript(address)
if err != nil {
t.Errorf("failed to make pkscript "+
"for %s: %v", msg, err)
}
scriptAddr, err := dcrutil.NewAddressScriptHash(
pkScript, testingParams)
if err != nil {
t.Errorf("failed to make p2sh addr for %s: %v",
msg, err)
break
}
scriptPkScript, err := PayToAddrScript(
scriptAddr)
if err != nil {
t.Errorf("failed to make script pkscript for "+
"%s: %v", msg, err)
break
}
_, err = SignTxOutput(testingParams,
tx, i, scriptPkScript, hashType,
mkGetKey(map[string]addressToKey{
address.Address(): {&key, true},
}), mkGetScript(map[string][]byte{
scriptAddr.Address(): pkScript,
}), nil, suite)
if err != nil {
t.Errorf("failed to sign output %s: %v", msg,
err)
break
}
// by the above loop, this should be valid, now sign
// again and merge.
sigScript, err := SignTxOutput(testingParams,
tx, i, scriptPkScript, hashType,
mkGetKey(map[string]addressToKey{
address.Address(): {&key, true},
}), mkGetScript(map[string][]byte{
scriptAddr.Address(): pkScript,
}), nil, suite)
if err != nil {
t.Errorf("failed to sign output %s a "+
"second time: %v", msg, err)
break
}
err = checkScripts(msg, tx, i, sigScript, scriptPkScript)
if err != nil {
t.Errorf("twice signed script invalid for "+
"%s: %v", msg, err)
break
}
}
}
}
// Pay to PubKey (uncompressed)
for _, hashType := range hashTypes {
for _, suite := range signatureSuites {
for i := range tx.TxIn {
var keyDB, pkBytes []byte
var key chainec.PrivateKey
var pk chainec.PublicKey
var address dcrutil.Address
var err error
msg := fmt.Sprintf("%d:%d:%d", hashType, i, suite)
switch suite {
case dcrec.STEcdsaSecp256k1:
keyDB, _, _, _ = secp256k1.GenerateKey(rand.Reader)
key, pk = secp256k1.PrivKeyFromBytes(keyDB)
// For address generation, consensus rules require using
// a compressed public key. Look up ExtractPkScriptAddrs
// for more details
address, err = dcrutil.NewAddressSecpPubKeyCompressed(pk,
testingParams)
if err != nil {
t.Errorf("failed to make address for %s: %v",
msg, err)
}
case dcrec.STEd25519:
keyDB, _, _, _ = chainec.Edwards.GenerateKey(rand.Reader)
key, pk = chainec.Edwards.PrivKeyFromBytes(keyDB)
pkBytes = pk.SerializeUncompressed()
address, err = dcrutil.NewAddressEdwardsPubKey(pkBytes,
testingParams)
if err != nil {
t.Errorf("failed to make address for %s: %v",
msg, err)
}
case dcrec.STSchnorrSecp256k1:
keyDB, _, _, _ = chainec.SecSchnorr.GenerateKey(rand.Reader)
key, pk = chainec.SecSchnorr.PrivKeyFromBytes(keyDB)
pkBytes = pk.Serialize()
address, err = dcrutil.NewAddressSecSchnorrPubKey(pkBytes,
testingParams)
if err != nil {
t.Errorf("failed to make address for %s: %v",
msg, err)
}
}
pkScript, err := PayToAddrScript(address)
if err != nil {
t.Errorf("failed to make pkscript "+
"for %s: %v", msg, err)
}
scriptAddr, err := dcrutil.NewAddressScriptHash(
pkScript, testingParams)
if err != nil {
t.Errorf("failed to make p2sh addr for %s: %v",
msg, err)
}
scriptPkScript, err := PayToAddrScript(
scriptAddr)
if err != nil {
t.Errorf("failed to make script pkscript for "+
"%s: %v", msg, err)
}
if err := signAndCheck(msg, tx, i, scriptPkScript,
hashType,
mkGetKey(map[string]addressToKey{
address.Address(): {&key, false},
}), mkGetScript(map[string][]byte{
scriptAddr.Address(): pkScript,
}), suite); err != nil {
t.Error(err)
}
if err := signBadAndCheck(msg, tx, i, pkScript, hashType,
mkGetKey(map[string]addressToKey{
address.Address(): {&key, false},
}), mkGetScript(nil), suite); err == nil {
t.Errorf("corrupted signature validated %s: %v",
msg, err)
break
}
}
}
}
// Pay to PubKey (uncompressed) with duplicate merge
for _, hashType := range hashTypes {
for _, suite := range signatureSuites {
for i := range tx.TxIn {
var keyDB, pkBytes []byte
var key chainec.PrivateKey
var pk chainec.PublicKey
var address dcrutil.Address
var err error
msg := fmt.Sprintf("%d:%d:%d", hashType, i, suite)
switch suite {
case dcrec.STEcdsaSecp256k1:
keyDB, _, _, _ = secp256k1.GenerateKey(rand.Reader)
key, pk = secp256k1.PrivKeyFromBytes(keyDB)
// For address generation, consensus rules require using
// a compressed public key. Look up ExtractPkScriptAddrs
// for more details
address, err = dcrutil.NewAddressSecpPubKeyCompressed(pk,
testingParams)
if err != nil {
t.Errorf("failed to make address for %s: %v",
msg, err)
}
case dcrec.STEd25519:
keyDB, _, _, _ = chainec.Edwards.GenerateKey(rand.Reader)
key, pk = chainec.Edwards.PrivKeyFromBytes(keyDB)
pkBytes = pk.SerializeUncompressed()
address, err = dcrutil.NewAddressEdwardsPubKey(pkBytes,
testingParams)
if err != nil {
t.Errorf("failed to make address for %s: %v",
msg, err)
}
case dcrec.STSchnorrSecp256k1:
keyDB, _, _, _ = chainec.SecSchnorr.GenerateKey(rand.Reader)
key, pk = chainec.SecSchnorr.PrivKeyFromBytes(keyDB)
pkBytes = pk.Serialize()
address, err = dcrutil.NewAddressSecSchnorrPubKey(pkBytes,
testingParams)
if err != nil {
t.Errorf("failed to make address for %s: %v",
msg, err)
}
}
pkScript, err := PayToAddrScript(address)
if err != nil {
t.Errorf("failed to make pkscript "+
"for %s: %v", msg, err)
}
scriptAddr, err := dcrutil.NewAddressScriptHash(
pkScript, testingParams)
if err != nil {
t.Errorf("failed to make p2sh addr for %s: %v",
msg, err)
}
scriptPkScript, err := PayToAddrScript(
scriptAddr)
if err != nil {
t.Errorf("failed to make script pkscript for "+
"%s: %v", msg, err)
}
_, err = SignTxOutput(testingParams,
tx, i, scriptPkScript, hashType,
mkGetKey(map[string]addressToKey{
address.Address(): {&key, false},
}), mkGetScript(map[string][]byte{
scriptAddr.Address(): pkScript,
}), nil, suite)
if err != nil {
t.Errorf("failed to sign output %s: %v", msg,
err)
break
}
// by the above loop, this should be valid, now sign
// again and merge.
sigScript, err := SignTxOutput(testingParams,
tx, i, scriptPkScript, hashType,
mkGetKey(map[string]addressToKey{
address.Address(): {&key, false},
}), mkGetScript(map[string][]byte{
scriptAddr.Address(): pkScript,
}), nil, suite)
if err != nil {
t.Errorf("failed to sign output %s a "+
"second time: %v", msg, err)
break
}
err = checkScripts(msg, tx, i, sigScript, scriptPkScript)
if err != nil {
t.Errorf("twice signed script invalid for "+
"%s: %v", msg, err)
break
}
}
}
}
// Pay to PubKey (compressed)
for _, hashType := range hashTypes {
for _, suite := range signatureSuites {
for i := range tx.TxIn {
var keyDB, pkBytes []byte
var key chainec.PrivateKey
var pk chainec.PublicKey
var address dcrutil.Address
var err error
msg := fmt.Sprintf("%d:%d:%d", hashType, i, suite)
switch suite {
case dcrec.STEcdsaSecp256k1:
keyDB, _, _, _ = secp256k1.GenerateKey(rand.Reader)
key, pk = secp256k1.PrivKeyFromBytes(keyDB)
address, err = dcrutil.NewAddressSecpPubKeyCompressed(pk,
testingParams)
if err != nil {
t.Errorf("failed to make address for %s: %v",
msg, err)
}
case dcrec.STEd25519:
keyDB, _, _, _ = chainec.Edwards.GenerateKey(rand.Reader)
key, pk = chainec.Edwards.PrivKeyFromBytes(keyDB)
pkBytes = pk.SerializeCompressed()
address, err = dcrutil.NewAddressEdwardsPubKey(pkBytes,
testingParams)
if err != nil {
t.Errorf("failed to make address for %s: %v",
msg, err)
}
case dcrec.STSchnorrSecp256k1:
keyDB, _, _, _ = chainec.SecSchnorr.GenerateKey(rand.Reader)
key, pk = chainec.SecSchnorr.PrivKeyFromBytes(keyDB)
pkBytes = pk.Serialize()
address, err = dcrutil.NewAddressSecSchnorrPubKey(pkBytes,
testingParams)
if err != nil {
t.Errorf("failed to make address for %s: %v",
msg, err)
}
}
pkScript, err := PayToAddrScript(address)
if err != nil {
t.Errorf("failed to make pkscript "+
"for %s: %v", msg, err)
}
scriptAddr, err := dcrutil.NewAddressScriptHash(
pkScript, testingParams)
if err != nil {
t.Errorf("failed to make p2sh addr for %s: %v",
msg, err)
break
}
scriptPkScript, err := PayToAddrScript(
scriptAddr)
if err != nil {
t.Errorf("failed to make script pkscript for "+
"%s: %v", msg, err)
break
}
if err := signAndCheck(msg, tx, i, scriptPkScript,
hashType,
mkGetKey(map[string]addressToKey{
address.Address(): {&key, true},
}), mkGetScript(map[string][]byte{
scriptAddr.Address(): pkScript,
}), suite); err != nil {
t.Error(err)
break
}
if err := signBadAndCheck(msg, tx, i, pkScript, hashType,
mkGetKey(map[string]addressToKey{
address.Address(): {&key, false},
}), mkGetScript(nil), suite); err == nil {
t.Errorf("corrupted signature validated %s: %v",
msg, err)
break
}
}
}
}
// Pay to PubKey (compressed)
for _, hashType := range hashTypes {
for _, suite := range signatureSuites {
for i := range tx.TxIn {
var keyDB, pkBytes []byte
var key chainec.PrivateKey
var pk chainec.PublicKey
var address dcrutil.Address
var err error
msg := fmt.Sprintf("%d:%d:%d", hashType, i, suite)
switch suite {
case dcrec.STEcdsaSecp256k1:
keyDB, _, _, _ = secp256k1.GenerateKey(rand.Reader)
key, pk = secp256k1.PrivKeyFromBytes(keyDB)
address, err = dcrutil.NewAddressSecpPubKeyCompressed(pk,
testingParams)
if err != nil {
t.Errorf("failed to make address for %s: %v",
msg, err)
}
case dcrec.STEd25519:
keyDB, _, _, _ = chainec.Edwards.GenerateKey(rand.Reader)
key, pk = chainec.Edwards.PrivKeyFromBytes(keyDB)
pkBytes = pk.SerializeCompressed()
address, err = dcrutil.NewAddressEdwardsPubKey(pkBytes,
testingParams)
if err != nil {
t.Errorf("failed to make address for %s: %v",
msg, err)
}
case dcrec.STSchnorrSecp256k1:
keyDB, _, _, _ = chainec.SecSchnorr.GenerateKey(rand.Reader)
key, pk = chainec.SecSchnorr.PrivKeyFromBytes(keyDB)
pkBytes = pk.Serialize()
address, err = dcrutil.NewAddressSecSchnorrPubKey(pkBytes,
testingParams)
if err != nil {
t.Errorf("failed to make address for %s: %v",
msg, err)
}
}
pkScript, err := PayToAddrScript(address)
if err != nil {
t.Errorf("failed to make pkscript "+
"for %s: %v", msg, err)
}
scriptAddr, err := dcrutil.NewAddressScriptHash(
pkScript, testingParams)
if err != nil {
t.Errorf("failed to make p2sh addr for %s: %v",
msg, err)
break
}
scriptPkScript, err := PayToAddrScript(
scriptAddr)
if err != nil {
t.Errorf("failed to make script pkscript for "+
"%s: %v", msg, err)
break
}
_, err = SignTxOutput(testingParams,
tx, i, scriptPkScript, hashType,
mkGetKey(map[string]addressToKey{
address.Address(): {&key, true},
}), mkGetScript(map[string][]byte{
scriptAddr.Address(): pkScript,
}), nil, suite)
if err != nil {
t.Errorf("failed to sign output %s: %v", msg,
err)
break
}
// by the above loop, this should be valid, now sign
// again and merge.
sigScript, err := SignTxOutput(testingParams,
tx, i, scriptPkScript, hashType,
mkGetKey(map[string]addressToKey{
address.Address(): {&key, true},
}), mkGetScript(map[string][]byte{
scriptAddr.Address(): pkScript,
}), nil, suite)
if err != nil {
t.Errorf("failed to sign output %s a "+
"second time: %v", msg, err)
break
}
err = checkScripts(msg, tx, i, sigScript, scriptPkScript)
if err != nil {
t.Errorf("twice signed script invalid for "+
"%s: %v", msg, err)
break
}
}
}
}
// Basic Multisig
for _, hashType := range hashTypes {
for i := range tx.TxIn {
msg := fmt.Sprintf("%d:%d", hashType, i)
keyDB1, _, _, err := secp256k1.GenerateKey(rand.Reader)
if err != nil {
t.Errorf("failed to generate key: %v", err)
break
}
key1, pk1 := secp256k1.PrivKeyFromBytes(keyDB1)
address1, err := dcrutil.NewAddressSecpPubKeyCompressed(pk1,
testingParams)
if err != nil {
t.Errorf("failed to make address for %s: %v",
msg, err)
break
}
keyDB2, _, _, err := secp256k1.GenerateKey(rand.Reader)
if err != nil {
t.Errorf("failed to generate key: %v", err)
break
}
key2, pk2 := secp256k1.PrivKeyFromBytes(keyDB2)
address2, err := dcrutil.NewAddressSecpPubKeyCompressed(pk2,
testingParams)
if err != nil {
t.Errorf("failed to make address 2 for %s: %v",
msg, err)
break
}
pkScript, err := MultiSigScript(
[]*dcrutil.AddressSecpPubKey{address1, address2},
2)
if err != nil {
t.Errorf("failed to make pkscript "+
"for %s: %v", msg, err)
}
scriptAddr, err := dcrutil.NewAddressScriptHash(
pkScript, testingParams)
if err != nil {
t.Errorf("failed to make p2sh addr for %s: %v",
msg, err)
break
}
scriptPkScript, err := PayToAddrScript(scriptAddr)
if err != nil {
t.Errorf("failed to make script pkscript for "+
"%s: %v", msg, err)
break
}
if err := signAndCheck(msg, tx, i, scriptPkScript,
hashType,
mkGetKey(map[string]addressToKey{
address1.Address(): {&key1, true},
address2.Address(): {&key2, true},
}), mkGetScript(map[string][]byte{
scriptAddr.Address(): pkScript,
}), dcrec.STEcdsaSecp256k1); err != nil {
t.Error(err)
break
}
if err := signBadAndCheck(msg, tx, i, pkScript, hashType,
mkGetKey(map[string]addressToKey{
address1.Address(): {&key1, true},
address2.Address(): {&key2, true},
}), mkGetScript(nil),
dcrec.STEcdsaSecp256k1); err == nil {
t.Errorf("corrupted signature validated %s: %v",
msg, err)
break
}
}
}
// Two part multisig, sign with one key then the other.
for _, hashType := range hashTypes {
for i := range tx.TxIn {
msg := fmt.Sprintf("%d:%d", hashType, i)
keyDB1, _, _, err := secp256k1.GenerateKey(rand.Reader)
if err != nil {
t.Errorf("failed to generate key: %v", err)
break
}
key1, pk1 := secp256k1.PrivKeyFromBytes(keyDB1)
address1, err := dcrutil.NewAddressSecpPubKeyCompressed(pk1,
testingParams)
if err != nil {
t.Errorf("failed to make address for %s: %v",
msg, err)
break
}
keyDB2, _, _, err := secp256k1.GenerateKey(rand.Reader)
if err != nil {
t.Errorf("failed to generate key: %v", err)
break
}
key2, pk2 := secp256k1.PrivKeyFromBytes(keyDB2)
address2, err := dcrutil.NewAddressSecpPubKeyCompressed(pk2,
testingParams)
if err != nil {
t.Errorf("failed to make address 2 for %s: %v",
msg, err)
break
}
pkScript, err := MultiSigScript(
[]*dcrutil.AddressSecpPubKey{address1, address2},
2)
if err != nil {
t.Errorf("failed to make pkscript "+
"for %s: %v", msg, err)
}
scriptAddr, err := dcrutil.NewAddressScriptHash(
pkScript, testingParams)
if err != nil {
t.Errorf("failed to make p2sh addr for %s: %v",
msg, err)
break
}
scriptPkScript, err := PayToAddrScript(scriptAddr)
if err != nil {
t.Errorf("failed to make script pkscript for "+
"%s: %v", msg, err)
break
}
sigScript, err := SignTxOutput(testingParams, tx, i,
scriptPkScript, hashType,
mkGetKey(map[string]addressToKey{
address1.Address(): {&key1, true},
}), mkGetScript(map[string][]byte{
scriptAddr.Address(): pkScript,
}), nil, dcrec.STEcdsaSecp256k1)
if err != nil {
t.Errorf("failed to sign output %s: %v", msg,
err)
break
}
// Only 1 out of 2 signed, this *should* fail.
if checkScripts(msg, tx, i, sigScript,
scriptPkScript) == nil {
t.Errorf("part signed script valid for %s", msg)
break
}
// Sign with the other key and merge
sigScript, err = SignTxOutput(testingParams, tx, i,
scriptPkScript, hashType,
mkGetKey(map[string]addressToKey{
address2.Address(): {&key2, true},
}), mkGetScript(map[string][]byte{
scriptAddr.Address(): pkScript,
}), sigScript, dcrec.STEcdsaSecp256k1)
if err != nil {
t.Errorf("failed to sign output %s: %v", msg, err)
break
}
err = checkScripts(msg, tx, i, sigScript,
scriptPkScript)
if err != nil {
t.Errorf("fully signed script invalid for "+
"%s: %v", msg, err)
break
}
}
}
// Two part multisig, sign with one key then both, check key dedup
// correctly.
for _, hashType := range hashTypes {
for i := range tx.TxIn {
msg := fmt.Sprintf("%d:%d", hashType, i)
keyDB1, _, _, err := secp256k1.GenerateKey(rand.Reader)
if err != nil {
t.Errorf("failed to generate key: %v", err)
break
}
key1, pk1 := secp256k1.PrivKeyFromBytes(keyDB1)
address1, err := dcrutil.NewAddressSecpPubKeyCompressed(pk1,
testingParams)
if err != nil {
t.Errorf("failed to make address for %s: %v",
msg, err)
break
}
keyDB2, _, _, err := secp256k1.GenerateKey(rand.Reader)
if err != nil {
t.Errorf("failed to generate key: %v", err)
break
}
key2, pk2 := secp256k1.PrivKeyFromBytes(keyDB2)
address2, err := dcrutil.NewAddressSecpPubKeyCompressed(pk2,
testingParams)
if err != nil {
t.Errorf("failed to make address 2 for %s: %v",
msg, err)
break
}
pkScript, err := MultiSigScript(
[]*dcrutil.AddressSecpPubKey{address1, address2},
2)
if err != nil {
t.Errorf("failed to make pkscript "+
"for %s: %v", msg, err)
}
scriptAddr, err := dcrutil.NewAddressScriptHash(
pkScript, testingParams)
if err != nil {
t.Errorf("failed to make p2sh addr for %s: %v",
msg, err)
break
}
scriptPkScript, err := PayToAddrScript(scriptAddr)
if err != nil {
t.Errorf("failed to make script pkscript for "+
"%s: %v", msg, err)
break
}
sigScript, err := SignTxOutput(testingParams, tx, i,
scriptPkScript, hashType,
mkGetKey(map[string]addressToKey{
address1.Address(): {&key1, true},
}), mkGetScript(map[string][]byte{
scriptAddr.Address(): pkScript,
}), nil, dcrec.STEcdsaSecp256k1)
if err != nil {
t.Errorf("failed to sign output %s: %v", msg,
err)
break
}
// Only 1 out of 2 signed, this *should* fail.
if checkScripts(msg, tx, i, sigScript,
scriptPkScript) == nil {
t.Errorf("part signed script valid for %s", msg)
break
}
// Sign with the other key and merge
sigScript, err = SignTxOutput(testingParams, tx, i,
scriptPkScript, hashType,
mkGetKey(map[string]addressToKey{
address1.Address(): {&key1, true},
address2.Address(): {&key2, true},
}), mkGetScript(map[string][]byte{
scriptAddr.Address(): pkScript,
}), sigScript, dcrec.STEcdsaSecp256k1)
if err != nil {
t.Errorf("failed to sign output %s: %v", msg, err)
break
}
// Now we should pass.
err = checkScripts(msg, tx, i, sigScript,
scriptPkScript)
if err != nil {
t.Errorf("fully signed script invalid for "+
"%s: %v", msg, err)
break
}
}
}
}
type tstInput struct {
txout *wire.TxOut
sigscriptGenerates bool
inputValidates bool
indexOutOfRange bool
}
type tstSigScript struct {
name string
inputs []tstInput
hashType SigHashType
compress bool
scriptAtWrongIndex bool
}
var coinbaseOutPoint = &wire.OutPoint{
Index: (1 << 32) - 1,
}
// Pregenerated private key, with associated public key and pkScripts
// for the uncompressed and compressed hash160.
var (
privKeyD = []byte{0x6b, 0x0f, 0xd8, 0xda, 0x54, 0x22, 0xd0, 0xb7,
0xb4, 0xfc, 0x4e, 0x55, 0xd4, 0x88, 0x42, 0xb3, 0xa1, 0x65,
0xac, 0x70, 0x7f, 0x3d, 0xa4, 0x39, 0x5e, 0xcb, 0x3b, 0xb0,
0xd6, 0x0e, 0x06, 0x92}
_, thisPubKey = chainec.Secp256k1.PrivKeyFromBytes(privKeyD)
thisAddressUnc, _ = dcrutil.NewAddressPubKeyHash(
dcrutil.Hash160(thisPubKey.SerializeUncompressed()),
testingParams, dcrec.STEcdsaSecp256k1)
uncompressedPkScript, _ = PayToAddrScript(thisAddressUnc)
thisAddressCom, _ = dcrutil.NewAddressPubKeyHash(
dcrutil.Hash160(thisPubKey.SerializeCompressed()),
testingParams, dcrec.STEcdsaSecp256k1)
compressedPkScript, _ = PayToAddrScript(thisAddressCom)
shortPkScript = []byte{0x76, 0xa9, 0x14, 0xd1, 0x7c, 0xb5,
0xeb, 0xa4, 0x02, 0xcb, 0x68, 0xe0, 0x69, 0x56, 0xbf, 0x32,
0x53, 0x90, 0x0e, 0x0a, 0x88, 0xac}
)
// Pretend output amounts.
const coinbaseVal = 2500000000
const fee = 5000000
var sigScriptTests = []tstSigScript{
{
name: "one input uncompressed",
inputs: []tstInput{
{
txout: wire.NewTxOut(coinbaseVal, uncompressedPkScript),
sigscriptGenerates: true,
inputValidates: true,
indexOutOfRange: false,
},
},
hashType: SigHashAll,
compress: false,
scriptAtWrongIndex: false,
},
{
name: "two inputs uncompressed",
inputs: []tstInput{
{
txout: wire.NewTxOut(coinbaseVal, uncompressedPkScript),
sigscriptGenerates: true,
inputValidates: true,
indexOutOfRange: false,
},
{
txout: wire.NewTxOut(coinbaseVal+fee, uncompressedPkScript),
sigscriptGenerates: true,
inputValidates: true,
indexOutOfRange: false,
},
},
hashType: SigHashAll,
compress: false,
scriptAtWrongIndex: false,
},
{
name: "one input compressed",
inputs: []tstInput{
{
txout: wire.NewTxOut(coinbaseVal, compressedPkScript),
sigscriptGenerates: true,
inputValidates: true,
indexOutOfRange: false,
},
},
hashType: SigHashAll,
compress: true,
scriptAtWrongIndex: false,
},
{
name: "two inputs compressed",
inputs: []tstInput{
{
txout: wire.NewTxOut(coinbaseVal, compressedPkScript),
sigscriptGenerates: true,
inputValidates: true,
indexOutOfRange: false,
},
{
txout: wire.NewTxOut(coinbaseVal+fee, compressedPkScript),
sigscriptGenerates: true,
inputValidates: true,
indexOutOfRange: false,
},
},
hashType: SigHashAll,
compress: true,
scriptAtWrongIndex: false,
},
{
name: "hashType SigHashNone",
inputs: []tstInput{
{
txout: wire.NewTxOut(coinbaseVal, uncompressedPkScript),
sigscriptGenerates: true,
inputValidates: true,
indexOutOfRange: false,
},
},
hashType: SigHashNone,
compress: false,
scriptAtWrongIndex: false,
},
{
name: "hashType SigHashSingle",
inputs: []tstInput{
{
txout: wire.NewTxOut(coinbaseVal, uncompressedPkScript),
sigscriptGenerates: true,
inputValidates: true,
indexOutOfRange: false,
},
},
hashType: SigHashSingle,
compress: false,
scriptAtWrongIndex: false,
},
{
name: "hashType SigHashAnyoneCanPay",
inputs: []tstInput{
{
txout: wire.NewTxOut(coinbaseVal, uncompressedPkScript),
sigscriptGenerates: true,
inputValidates: true,
indexOutOfRange: false,
},
},
hashType: SigHashAnyOneCanPay | SigHashAll,
compress: false,
scriptAtWrongIndex: false,
},
{
name: "hashType non-standard",
inputs: []tstInput{
{
txout: wire.NewTxOut(coinbaseVal, uncompressedPkScript),
sigscriptGenerates: true,
inputValidates: false,
indexOutOfRange: false,
},
},
hashType: 0x04,
compress: false,
scriptAtWrongIndex: false,
},
{
name: "invalid compression",
inputs: []tstInput{
{
txout: wire.NewTxOut(coinbaseVal, uncompressedPkScript),
sigscriptGenerates: true,
inputValidates: false,
indexOutOfRange: false,
},
},
hashType: SigHashAll,
compress: true,
scriptAtWrongIndex: false,
},
{
name: "short PkScript",
inputs: []tstInput{
{
txout: wire.NewTxOut(coinbaseVal, shortPkScript),
sigscriptGenerates: false,
indexOutOfRange: false,
},
},
hashType: SigHashAll,
compress: false,
scriptAtWrongIndex: false,
},
{
name: "valid script at wrong index",
inputs: []tstInput{
{
txout: wire.NewTxOut(coinbaseVal, uncompressedPkScript),
sigscriptGenerates: true,
inputValidates: true,
indexOutOfRange: false,
},
{
txout: wire.NewTxOut(coinbaseVal+fee, uncompressedPkScript),
sigscriptGenerates: true,
inputValidates: true,
indexOutOfRange: false,
},
},
hashType: SigHashAll,
compress: false,
scriptAtWrongIndex: true,
},
{
name: "index out of range",
inputs: []tstInput{
{
txout: wire.NewTxOut(coinbaseVal, uncompressedPkScript),
sigscriptGenerates: true,
inputValidates: true,
indexOutOfRange: false,
},
{
txout: wire.NewTxOut(coinbaseVal+fee, uncompressedPkScript),
sigscriptGenerates: true,
inputValidates: true,
indexOutOfRange: false,
},
},
hashType: SigHashAll,
compress: false,
scriptAtWrongIndex: true,
},
}
// Test the sigscript generation for valid and invalid inputs, all
// hashTypes, and with and without compression. This test creates
// sigscripts to spend fake coinbase inputs, as sigscripts cannot be
// created for the MsgTxs in txTests, since they come from the blockchain
// and we don't have the private keys.
func TestSignatureScript(t *testing.T) {
t.Parallel()
privKey, _ := chainec.Secp256k1.PrivKeyFromBytes(privKeyD)
nexttest:
for i := range sigScriptTests {
tx := wire.NewMsgTx()
output := wire.NewTxOut(500, []byte{OP_RETURN})
tx.AddTxOut(output)
for range sigScriptTests[i].inputs {
txin := wire.NewTxIn(coinbaseOutPoint, 500, nil)
tx.AddTxIn(txin)
}
var script []byte
var err error
for j := range tx.TxIn {
var idx int
if sigScriptTests[i].inputs[j].indexOutOfRange {
t.Errorf("at test %v", sigScriptTests[i].name)
idx = len(sigScriptTests[i].inputs)
} else {
idx = j
}
script, err = SignatureScript(tx, idx,
sigScriptTests[i].inputs[j].txout.PkScript,
sigScriptTests[i].hashType, privKey,
sigScriptTests[i].compress)
if (err == nil) != sigScriptTests[i].inputs[j].sigscriptGenerates {
if err == nil {
t.Errorf("passed test '%v' incorrectly",
sigScriptTests[i].name)
} else {
t.Errorf("failed test '%v': %v",
sigScriptTests[i].name, err)
}
continue nexttest
}
if !sigScriptTests[i].inputs[j].sigscriptGenerates {
// done with this test
continue nexttest
}
tx.TxIn[j].SignatureScript = script
}
// If testing using a correct sigscript but for an incorrect
// index, use last input script for first input. Requires > 0
// inputs for test.
if sigScriptTests[i].scriptAtWrongIndex {
tx.TxIn[0].SignatureScript = script
sigScriptTests[i].inputs[0].inputValidates = false
}
// Validate tx input scripts
var scriptFlags ScriptFlags
for j := range tx.TxIn {
vm, err := NewEngine(sigScriptTests[i].inputs[j].txout.
PkScript, tx, j, scriptFlags, 0,
nil)
if err != nil {
t.Errorf("cannot create script vm for test %v: %v",
sigScriptTests[i].name, err)
continue nexttest
}
err = vm.Execute()
if (err == nil) != sigScriptTests[i].inputs[j].inputValidates {
if err == nil {
t.Errorf("passed test '%v' validation incorrectly: %v",
sigScriptTests[i].name, err)
} else {
t.Errorf("failed test '%v' validation: %v",
sigScriptTests[i].name, err)
}
continue nexttest
}
}
}
}