mirror of
https://github.com/FlipsideCrypto/dcrd.git
synced 2026-02-06 10:56:47 +00:00
2332 lines
63 KiB
Go
2332 lines
63 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"
|
|
"github.com/decred/dcrd/chaincfg/chainec"
|
|
"github.com/decred/dcrd/chaincfg/chainhash"
|
|
"github.com/decred/dcrd/dcrec"
|
|
"github.com/decred/dcrd/dcrutil"
|
|
"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.EncodeAddress()]
|
|
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.EncodeAddress()]
|
|
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.EncodeAddress(): {&key, false},
|
|
}), mkGetScript(nil), suite); err != nil {
|
|
t.Error(err)
|
|
break
|
|
}
|
|
|
|
if err := signBadAndCheck(msg, tx, i, pkScript, hashType,
|
|
mkGetKey(map[string]addressToKey{
|
|
address.EncodeAddress(): {&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.EncodeAddress(): {&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.EncodeAddress(): {&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.EncodeAddress(): {&key, true},
|
|
}), mkGetScript(nil), suite); err != nil {
|
|
t.Error(err)
|
|
break
|
|
}
|
|
|
|
if err := signBadAndCheck(msg, tx, i, pkScript, hashType,
|
|
mkGetKey(map[string]addressToKey{
|
|
address.EncodeAddress(): {&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.EncodeAddress(): {&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.EncodeAddress(): {&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.EncodeAddress(): {&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.EncodeAddress(): {&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.EncodeAddress(): {&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.EncodeAddress(): {&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.EncodeAddress(): {&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.EncodeAddress(): {&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.EncodeAddress(): {&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.EncodeAddress(): {&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.EncodeAddress(): {&key, false},
|
|
}), mkGetScript(nil), suite); err != nil {
|
|
t.Error(err)
|
|
break
|
|
}
|
|
|
|
if err := signBadAndCheck(msg, tx, i, pkScript, hashType,
|
|
mkGetKey(map[string]addressToKey{
|
|
address.EncodeAddress(): {&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.EncodeAddress(): {&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.EncodeAddress(): {&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.EncodeAddress(): {&key, false},
|
|
}), mkGetScript(map[string][]byte{
|
|
scriptAddr.EncodeAddress(): pkScript,
|
|
}), suite); err != nil {
|
|
t.Error(err)
|
|
break
|
|
}
|
|
|
|
if err := signBadAndCheck(msg, tx, i, pkScript, hashType,
|
|
mkGetKey(map[string]addressToKey{
|
|
address.EncodeAddress(): {&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.EncodeAddress(): {&key, false},
|
|
}), mkGetScript(map[string][]byte{
|
|
scriptAddr.EncodeAddress(): 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.EncodeAddress(): {&key, false},
|
|
}), mkGetScript(map[string][]byte{
|
|
scriptAddr.EncodeAddress(): 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.EncodeAddress(): {&key, true},
|
|
}), mkGetScript(map[string][]byte{
|
|
scriptAddr.EncodeAddress(): pkScript,
|
|
}), suite); err != nil {
|
|
t.Error(err)
|
|
break
|
|
}
|
|
|
|
if err := signBadAndCheck(msg, tx, i, pkScript, hashType,
|
|
mkGetKey(map[string]addressToKey{
|
|
address.EncodeAddress(): {&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.EncodeAddress(): {&key, true},
|
|
}), mkGetScript(map[string][]byte{
|
|
scriptAddr.EncodeAddress(): 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.EncodeAddress(): {&key, true},
|
|
}), mkGetScript(map[string][]byte{
|
|
scriptAddr.EncodeAddress(): 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.EncodeAddress(): {&key, false},
|
|
}), mkGetScript(map[string][]byte{
|
|
scriptAddr.EncodeAddress(): pkScript,
|
|
}), suite); err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
if err := signBadAndCheck(msg, tx, i, pkScript, hashType,
|
|
mkGetKey(map[string]addressToKey{
|
|
address.EncodeAddress(): {&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.EncodeAddress(): {&key, false},
|
|
}), mkGetScript(map[string][]byte{
|
|
scriptAddr.EncodeAddress(): 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.EncodeAddress(): {&key, false},
|
|
}), mkGetScript(map[string][]byte{
|
|
scriptAddr.EncodeAddress(): 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.EncodeAddress(): {&key, true},
|
|
}), mkGetScript(map[string][]byte{
|
|
scriptAddr.EncodeAddress(): pkScript,
|
|
}), suite); err != nil {
|
|
t.Error(err)
|
|
break
|
|
}
|
|
|
|
if err := signBadAndCheck(msg, tx, i, pkScript, hashType,
|
|
mkGetKey(map[string]addressToKey{
|
|
address.EncodeAddress(): {&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.EncodeAddress(): {&key, true},
|
|
}), mkGetScript(map[string][]byte{
|
|
scriptAddr.EncodeAddress(): 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.EncodeAddress(): {&key, true},
|
|
}), mkGetScript(map[string][]byte{
|
|
scriptAddr.EncodeAddress(): 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.EncodeAddress(): {&key1, true},
|
|
address2.EncodeAddress(): {&key2, true},
|
|
}), mkGetScript(map[string][]byte{
|
|
scriptAddr.EncodeAddress(): pkScript,
|
|
}), dcrec.STEcdsaSecp256k1); err != nil {
|
|
t.Error(err)
|
|
break
|
|
}
|
|
|
|
if err := signBadAndCheck(msg, tx, i, pkScript, hashType,
|
|
mkGetKey(map[string]addressToKey{
|
|
address1.EncodeAddress(): {&key1, true},
|
|
address2.EncodeAddress(): {&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.EncodeAddress(): {&key1, true},
|
|
}), mkGetScript(map[string][]byte{
|
|
scriptAddr.EncodeAddress(): 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.EncodeAddress(): {&key2, true},
|
|
}), mkGetScript(map[string][]byte{
|
|
scriptAddr.EncodeAddress(): 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.EncodeAddress(): {&key1, true},
|
|
}), mkGetScript(map[string][]byte{
|
|
scriptAddr.EncodeAddress(): 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.EncodeAddress(): {&key1, true},
|
|
address2.EncodeAddress(): {&key2, true},
|
|
}), mkGetScript(map[string][]byte{
|
|
scriptAddr.EncodeAddress(): 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
|
|
}
|
|
}
|
|
}
|
|
}
|