Merge pull request #783 from nspcc-dev/neo3/movecrypto
Implement Neo.Crypto.* interops
This commit is contained in:
commit
ace5614a3d
17 changed files with 177 additions and 113 deletions
|
@ -14,7 +14,7 @@ var (
|
||||||
builtinFuncs = []string{
|
builtinFuncs = []string{
|
||||||
"len", "append", "SHA256",
|
"len", "append", "SHA256",
|
||||||
"SHA1", "Hash256", "Hash160",
|
"SHA1", "Hash256", "Hash160",
|
||||||
"VerifySignature", "AppCall",
|
"AppCall",
|
||||||
"FromAddress", "Equals",
|
"FromAddress", "Equals",
|
||||||
"panic",
|
"panic",
|
||||||
}
|
}
|
||||||
|
|
|
@ -1063,12 +1063,6 @@ func (c *codegen) convertBuiltin(expr *ast.CallExpr) {
|
||||||
emit.Opcode(c.prog.BinWriter, opcode.SHA256)
|
emit.Opcode(c.prog.BinWriter, opcode.SHA256)
|
||||||
case "SHA1":
|
case "SHA1":
|
||||||
emit.Opcode(c.prog.BinWriter, opcode.SHA1)
|
emit.Opcode(c.prog.BinWriter, opcode.SHA1)
|
||||||
case "Hash256":
|
|
||||||
emit.Opcode(c.prog.BinWriter, opcode.HASH256)
|
|
||||||
case "Hash160":
|
|
||||||
emit.Opcode(c.prog.BinWriter, opcode.HASH160)
|
|
||||||
case "VerifySignature":
|
|
||||||
emit.Opcode(c.prog.BinWriter, opcode.VERIFY)
|
|
||||||
case "AppCall":
|
case "AppCall":
|
||||||
numArgs := len(expr.Args) - 1
|
numArgs := len(expr.Args) - 1
|
||||||
c.emitReverse(numArgs)
|
c.emitReverse(numArgs)
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
package compiler
|
package compiler
|
||||||
|
|
||||||
var syscalls = map[string]map[string]string{
|
var syscalls = map[string]map[string]string{
|
||||||
|
"crypto": {
|
||||||
|
"ECDsaVerify": "Neo.Crypto.ECDsaVerify",
|
||||||
|
},
|
||||||
"storage": {
|
"storage": {
|
||||||
"GetContext": "Neo.Storage.GetContext",
|
"GetContext": "Neo.Storage.GetContext",
|
||||||
"Put": "Neo.Storage.Put",
|
"Put": "Neo.Storage.Put",
|
||||||
|
|
|
@ -33,33 +33,3 @@ func TestSHA1(t *testing.T) {
|
||||||
`
|
`
|
||||||
eval(t, src, []byte{0xfa, 0x13, 0x8a, 0xe3, 0x56, 0xd3, 0x5c, 0x8d, 0x77, 0x8, 0x3c, 0x40, 0x6a, 0x5b, 0xe7, 0x37, 0x45, 0x64, 0x3a, 0xae})
|
eval(t, src, []byte{0xfa, 0x13, 0x8a, 0xe3, 0x56, 0xd3, 0x5c, 0x8d, 0x77, 0x8, 0x3c, 0x40, 0x6a, 0x5b, 0xe7, 0x37, 0x45, 0x64, 0x3a, 0xae})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHash160(t *testing.T) {
|
|
||||||
src := `
|
|
||||||
package foo
|
|
||||||
import (
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/interop/crypto"
|
|
||||||
)
|
|
||||||
func Main() []byte {
|
|
||||||
src := []byte{0x97}
|
|
||||||
hash := crypto.Hash160(src)
|
|
||||||
return hash
|
|
||||||
}
|
|
||||||
`
|
|
||||||
eval(t, src, []byte{0x5f, 0xa4, 0x1c, 0x76, 0xf7, 0xe8, 0xca, 0x72, 0xb7, 0x18, 0xff, 0x59, 0x22, 0x91, 0xc2, 0x3a, 0x3a, 0xf5, 0x58, 0x6c})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestHash256(t *testing.T) {
|
|
||||||
src := `
|
|
||||||
package foo
|
|
||||||
import (
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/interop/crypto"
|
|
||||||
)
|
|
||||||
func Main() []byte {
|
|
||||||
src := []byte{0x97}
|
|
||||||
hash := crypto.Hash256(src)
|
|
||||||
return hash
|
|
||||||
}
|
|
||||||
`
|
|
||||||
eval(t, src, []byte{0xc0, 0x85, 0x26, 0xad, 0x17, 0x36, 0x53, 0xee, 0xb8, 0xc7, 0xf4, 0xae, 0x82, 0x8b, 0x6e, 0xa1, 0x84, 0xac, 0x5a, 0x3, 0x8a, 0xf6, 0xc3, 0x68, 0x23, 0xfa, 0x5f, 0x5d, 0xd9, 0x1b, 0x91, 0xa2})
|
|
||||||
}
|
|
||||||
|
|
|
@ -5,24 +5,28 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// In this test we only check that needed interop
|
||||||
|
// is called with the provided arguments in the right order.
|
||||||
func TestVerifyGood(t *testing.T) {
|
func TestVerifyGood(t *testing.T) {
|
||||||
msg := []byte("test message")
|
msg := []byte("test message")
|
||||||
pub, sig := signMessage(t, msg)
|
pub, sig := signMessage(t, msg)
|
||||||
src := getVerifyProg(pub, sig, msg)
|
src := getVerifyProg(pub, sig, msg)
|
||||||
|
|
||||||
eval(t, src, true)
|
v, p := vmAndCompileInterop(t, src)
|
||||||
}
|
p.interops[vm.InteropNameToID([]byte("Neo.Crypto.ECDsaVerify"))] = func(v *vm.VM) error {
|
||||||
|
assert.Equal(t, msg, v.Estack().Pop().Bytes())
|
||||||
|
assert.Equal(t, pub, v.Estack().Pop().Bytes())
|
||||||
|
assert.Equal(t, sig, v.Estack().Pop().Bytes())
|
||||||
|
v.Estack().PushVal(true)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func TestVerifyBad(t *testing.T) {
|
require.NoError(t, v.Run())
|
||||||
msg := []byte("test message")
|
|
||||||
pub, sig := signMessage(t, msg)
|
|
||||||
sig[0] = ^sig[0]
|
|
||||||
src := getVerifyProg(pub, sig, msg)
|
|
||||||
|
|
||||||
eval(t, src, false)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func signMessage(t *testing.T, msg []byte) ([]byte, []byte) {
|
func signMessage(t *testing.T, msg []byte) ([]byte, []byte) {
|
||||||
|
@ -49,7 +53,7 @@ func getVerifyProg(pub, sig, msg []byte) string {
|
||||||
pub := ` + pubS + `
|
pub := ` + pubS + `
|
||||||
sig := ` + sigS + `
|
sig := ` + sigS + `
|
||||||
msg := ` + msgS + `
|
msg := ` + msgS + `
|
||||||
return crypto.VerifySignature(msg, sig, pub)
|
return crypto.ECDsaVerify(msg, pub, sig)
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
}
|
}
|
||||||
|
|
57
pkg/core/interop/crypto/ecdsa.go
Normal file
57
pkg/core/interop/crypto/ecdsa.go
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
package crypto
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/core/interop"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ECDSAVerify checks ECDSA signature.
|
||||||
|
func ECDSAVerify(ic *interop.Context, v *vm.VM) error {
|
||||||
|
msg := getMessage(ic, v.Estack().Pop().Item())
|
||||||
|
hashToCheck := hash.Sha256(msg).BytesBE()
|
||||||
|
keyb := v.Estack().Pop().Bytes()
|
||||||
|
signature := v.Estack().Pop().Bytes()
|
||||||
|
pkey, err := keys.NewPublicKeyFromBytes(keyb)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
res := pkey.Verify(signature, hashToCheck)
|
||||||
|
v.Estack().PushVal(res)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ECDSACheckMultisig checks multiple ECDSA signatures at once.
|
||||||
|
func ECDSACheckMultisig(ic *interop.Context, v *vm.VM) error {
|
||||||
|
msg := getMessage(ic, v.Estack().Pop().Item())
|
||||||
|
hashToCheck := hash.Sha256(msg).BytesBE()
|
||||||
|
pkeys, err := v.Estack().PopSigElements()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("wrong parameters: %s", err.Error())
|
||||||
|
}
|
||||||
|
sigs, err := v.Estack().PopSigElements()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("wrong parameters: %s", err.Error())
|
||||||
|
}
|
||||||
|
// It's ok to have more keys than there are signatures (it would
|
||||||
|
// just mean that some keys didn't sign), but not the other way around.
|
||||||
|
if len(pkeys) < len(sigs) {
|
||||||
|
return errors.New("more signatures than there are keys")
|
||||||
|
}
|
||||||
|
v.SetCheckedHash(hashToCheck)
|
||||||
|
sigok := vm.CheckMultisigPar(v, pkeys, sigs)
|
||||||
|
v.Estack().PushVal(sigok)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getMessage(_ *interop.Context, item vm.StackItem) []byte {
|
||||||
|
msg, err := item.TryBytes()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return msg
|
||||||
|
}
|
|
@ -628,8 +628,7 @@ func assetCreate(ic *interop.Context, v *vm.VM) error {
|
||||||
if amount != -util.Satoshi() && (int64(amount)%int64(math.Pow10(int(MaxAssetPrecision-precision))) != 0) {
|
if amount != -util.Satoshi() && (int64(amount)%int64(math.Pow10(int(MaxAssetPrecision-precision))) != 0) {
|
||||||
return errors.New("given asset amount has fractional component")
|
return errors.New("given asset amount has fractional component")
|
||||||
}
|
}
|
||||||
owner := &keys.PublicKey{}
|
owner, err := keys.NewPublicKeyFromBytes(v.Estack().Pop().Bytes())
|
||||||
err := owner.DecodeBytes(v.Estack().Pop().Bytes())
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return gherr.Wrap(err, "failed to get owner key")
|
return gherr.Wrap(err, "failed to get owner key")
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/block"
|
"github.com/nspcc-dev/neo-go/pkg/core/block"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/dao"
|
"github.com/nspcc-dev/neo-go/pkg/core/dao"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/interop"
|
"github.com/nspcc-dev/neo-go/pkg/core/interop"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/core/interop/crypto"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/interop/enumerator"
|
"github.com/nspcc-dev/neo-go/pkg/core/interop/enumerator"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/interop/iterator"
|
"github.com/nspcc-dev/neo-go/pkg/core/interop/iterator"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
||||||
|
@ -231,6 +233,67 @@ func TestWitnessGetVerificationScript(t *testing.T) {
|
||||||
require.Equal(t, witness.VerificationScript, value)
|
require.Equal(t, witness.VerificationScript, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestECDSAVerify(t *testing.T) {
|
||||||
|
priv, err := keys.NewPrivateKey()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
chain := newTestChain(t)
|
||||||
|
defer chain.Close()
|
||||||
|
|
||||||
|
ic := chain.newInteropContext(trigger.Application, dao.NewSimple(storage.NewMemoryStore()), nil, nil)
|
||||||
|
runCase := func(t *testing.T, isErr bool, result interface{}, args ...interface{}) {
|
||||||
|
v := vm.New()
|
||||||
|
for i := range args {
|
||||||
|
v.Estack().PushVal(args[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
func() {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
err = fmt.Errorf("panic: %v", r)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
err = crypto.ECDSAVerify(ic, v)
|
||||||
|
}()
|
||||||
|
|
||||||
|
if isErr {
|
||||||
|
require.Error(t, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, 1, v.Estack().Len())
|
||||||
|
require.Equal(t, result, v.Estack().Pop().Value().(bool))
|
||||||
|
}
|
||||||
|
|
||||||
|
msg := []byte("test message")
|
||||||
|
|
||||||
|
t.Run("success", func(t *testing.T) {
|
||||||
|
sign := priv.Sign(msg)
|
||||||
|
runCase(t, false, true, sign, priv.PublicKey().Bytes(), msg)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("missing arguments", func(t *testing.T) {
|
||||||
|
runCase(t, true, false)
|
||||||
|
sign := priv.Sign(msg)
|
||||||
|
runCase(t, true, false, sign)
|
||||||
|
runCase(t, true, false, sign, priv.PublicKey().Bytes())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("invalid signature", func(t *testing.T) {
|
||||||
|
sign := priv.Sign(msg)
|
||||||
|
sign[0] ^= sign[0]
|
||||||
|
runCase(t, false, false, sign, priv.PublicKey().Bytes(), msg)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("invalid public key", func(t *testing.T) {
|
||||||
|
sign := priv.Sign(msg)
|
||||||
|
pub := priv.PublicKey().Bytes()
|
||||||
|
pub = pub[10:]
|
||||||
|
runCase(t, true, false, sign, pub, msg)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestPopInputFromVM(t *testing.T) {
|
func TestPopInputFromVM(t *testing.T) {
|
||||||
v, tx, _, chain := createVMAndTX(t)
|
v, tx, _, chain := createVMAndTX(t)
|
||||||
defer chain.Close()
|
defer chain.Close()
|
||||||
|
|
|
@ -324,8 +324,7 @@ func runtimeCheckWitness(ic *interop.Context, v *vm.VM) error {
|
||||||
hashOrKey := v.Estack().Pop().Bytes()
|
hashOrKey := v.Estack().Pop().Bytes()
|
||||||
hash, err := util.Uint160DecodeBytesBE(hashOrKey)
|
hash, err := util.Uint160DecodeBytesBE(hashOrKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
key := &keys.PublicKey{}
|
key, err := keys.NewPublicKeyFromBytes(hashOrKey)
|
||||||
err = key.DecodeBytes(hashOrKey)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("parameter given is neither a key nor a hash")
|
return errors.New("parameter given is neither a key nor a hash")
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/interop"
|
"github.com/nspcc-dev/neo-go/pkg/core/interop"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/core/interop/crypto"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/interop/enumerator"
|
"github.com/nspcc-dev/neo-go/pkg/core/interop/enumerator"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/interop/iterator"
|
"github.com/nspcc-dev/neo-go/pkg/core/interop/iterator"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||||
|
@ -137,6 +138,8 @@ var neoInterops = []interop.Function{
|
||||||
{Name: "Neo.Contract.GetStorageContext", Func: contractGetStorageContext, Price: 1},
|
{Name: "Neo.Contract.GetStorageContext", Func: contractGetStorageContext, Price: 1},
|
||||||
{Name: "Neo.Contract.IsPayable", Func: contractIsPayable, Price: 1},
|
{Name: "Neo.Contract.IsPayable", Func: contractIsPayable, Price: 1},
|
||||||
{Name: "Neo.Contract.Migrate", Func: contractMigrate, Price: 0},
|
{Name: "Neo.Contract.Migrate", Func: contractMigrate, Price: 0},
|
||||||
|
{Name: "Neo.Crypto.ECDsaVerify", Func: crypto.ECDSAVerify, Price: 1},
|
||||||
|
{Name: "Neo.Crypto.ECDsaCheckMultiSig", Func: crypto.ECDSACheckMultisig, Price: 1},
|
||||||
{Name: "Neo.Enumerator.Concat", Func: enumerator.Concat, Price: 1},
|
{Name: "Neo.Enumerator.Concat", Func: enumerator.Concat, Price: 1},
|
||||||
{Name: "Neo.Enumerator.Create", Func: enumerator.Create, Price: 1},
|
{Name: "Neo.Enumerator.Create", Func: enumerator.Create, Price: 1},
|
||||||
{Name: "Neo.Enumerator.Next", Func: enumerator.Next, Price: 1},
|
{Name: "Neo.Enumerator.Next", Func: enumerator.Next, Price: 1},
|
||||||
|
|
|
@ -83,14 +83,15 @@ func NewPublicKeyFromString(s string) (*PublicKey, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
return NewPublicKeyFromBytes(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewPublicKeyFromBytes returns public key created from b.
|
||||||
|
func NewPublicKeyFromBytes(b []byte) (*PublicKey, error) {
|
||||||
pubKey := new(PublicKey)
|
pubKey := new(PublicKey)
|
||||||
r := io.NewBinReaderFromBuf(b)
|
if err := pubKey.DecodeBytes(b); err != nil {
|
||||||
pubKey.DecodeBinary(r)
|
return nil, err
|
||||||
if r.Err != nil {
|
|
||||||
return nil, r.Err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return pubKey, nil
|
return pubKey, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,16 @@ func TestEncodeDecodePublicKey(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestNewPublicKeyFromBytes(t *testing.T) {
|
||||||
|
priv, err := NewPrivateKey()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
b := priv.PublicKey().Bytes()
|
||||||
|
pub, err := NewPublicKeyFromBytes(b)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, priv.PublicKey(), pub)
|
||||||
|
}
|
||||||
|
|
||||||
func TestDecodeFromString(t *testing.T) {
|
func TestDecodeFromString(t *testing.T) {
|
||||||
str := "03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c"
|
str := "03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c"
|
||||||
pubKey, err := NewPublicKeyFromString(str)
|
pubKey, err := NewPublicKeyFromString(str)
|
||||||
|
|
|
@ -13,17 +13,7 @@ func SHA256(b []byte) []byte {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hash160 computes the sha256 + ripemd160 of b.
|
// ECDsaVerify checks that sig is msg's signature with pub.
|
||||||
func Hash160(b []byte) []byte {
|
func ECDsaVerify(msg []byte, pub []byte, sig []byte) bool {
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hash256 computes the sha256^2 hash of b.
|
|
||||||
func Hash256(b []byte) []byte {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// VerifySignature checks that sig is msg's signature with pub.
|
|
||||||
func VerifySignature(msg []byte, sig []byte, pub []byte) bool {
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
|
@ -424,9 +424,9 @@ func (s *Stack) Roll(n int) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// popSigElements pops keys or signatures from the stack as needed for
|
// PopSigElements pops keys or signatures from the stack as needed for
|
||||||
// CHECKMULTISIG.
|
// CHECKMULTISIG.
|
||||||
func (s *Stack) popSigElements() ([][]byte, error) {
|
func (s *Stack) PopSigElements() ([][]byte, error) {
|
||||||
var num int
|
var num int
|
||||||
var elems [][]byte
|
var elems [][]byte
|
||||||
item := s.Pop()
|
item := s.Pop()
|
||||||
|
|
|
@ -317,37 +317,37 @@ func TestRoll(t *testing.T) {
|
||||||
func TestPopSigElements(t *testing.T) {
|
func TestPopSigElements(t *testing.T) {
|
||||||
s := NewStack("test")
|
s := NewStack("test")
|
||||||
|
|
||||||
_, err := s.popSigElements()
|
_, err := s.PopSigElements()
|
||||||
assert.NotNil(t, err)
|
assert.NotNil(t, err)
|
||||||
|
|
||||||
s.PushVal([]StackItem{})
|
s.PushVal([]StackItem{})
|
||||||
_, err = s.popSigElements()
|
_, err = s.PopSigElements()
|
||||||
assert.NotNil(t, err)
|
assert.NotNil(t, err)
|
||||||
|
|
||||||
s.PushVal([]StackItem{NewBoolItem(false)})
|
s.PushVal([]StackItem{NewBoolItem(false)})
|
||||||
_, err = s.popSigElements()
|
_, err = s.PopSigElements()
|
||||||
assert.NotNil(t, err)
|
assert.NotNil(t, err)
|
||||||
|
|
||||||
b1 := []byte("smth")
|
b1 := []byte("smth")
|
||||||
b2 := []byte("strange")
|
b2 := []byte("strange")
|
||||||
s.PushVal([]StackItem{NewByteArrayItem(b1), NewByteArrayItem(b2)})
|
s.PushVal([]StackItem{NewByteArrayItem(b1), NewByteArrayItem(b2)})
|
||||||
z, err := s.popSigElements()
|
z, err := s.PopSigElements()
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, z, [][]byte{b1, b2})
|
assert.Equal(t, z, [][]byte{b1, b2})
|
||||||
|
|
||||||
s.PushVal(2)
|
s.PushVal(2)
|
||||||
_, err = s.popSigElements()
|
_, err = s.PopSigElements()
|
||||||
assert.NotNil(t, err)
|
assert.NotNil(t, err)
|
||||||
|
|
||||||
s.PushVal(b1)
|
s.PushVal(b1)
|
||||||
s.PushVal(2)
|
s.PushVal(2)
|
||||||
_, err = s.popSigElements()
|
_, err = s.PopSigElements()
|
||||||
assert.NotNil(t, err)
|
assert.NotNil(t, err)
|
||||||
|
|
||||||
s.PushVal(b2)
|
s.PushVal(b2)
|
||||||
s.PushVal(b1)
|
s.PushVal(b1)
|
||||||
s.PushVal(2)
|
s.PushVal(2)
|
||||||
z, err = s.popSigElements()
|
z, err = s.PopSigElements()
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, z, [][]byte{b1, b2})
|
assert.Equal(t, z, [][]byte{b1, b2})
|
||||||
}
|
}
|
||||||
|
|
21
pkg/vm/vm.go
21
pkg/vm/vm.go
|
@ -1235,11 +1235,11 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
|
||||||
v.estack.PushVal(res)
|
v.estack.PushVal(res)
|
||||||
|
|
||||||
case opcode.CHECKMULTISIG:
|
case opcode.CHECKMULTISIG:
|
||||||
pkeys, err := v.estack.popSigElements()
|
pkeys, err := v.estack.PopSigElements()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("wrong parameters: %s", err.Error()))
|
panic(fmt.Sprintf("wrong parameters: %s", err.Error()))
|
||||||
}
|
}
|
||||||
sigs, err := v.estack.popSigElements()
|
sigs, err := v.estack.PopSigElements()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("wrong parameters: %s", err.Error()))
|
panic(fmt.Sprintf("wrong parameters: %s", err.Error()))
|
||||||
}
|
}
|
||||||
|
@ -1252,7 +1252,7 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
|
||||||
panic("VM is not set up properly for signature checks")
|
panic("VM is not set up properly for signature checks")
|
||||||
}
|
}
|
||||||
|
|
||||||
sigok := checkMultisigPar(v, pkeys, sigs)
|
sigok := CheckMultisigPar(v, pkeys, sigs)
|
||||||
v.estack.PushVal(sigok)
|
v.estack.PushVal(sigok)
|
||||||
|
|
||||||
case opcode.NEWMAP:
|
case opcode.NEWMAP:
|
||||||
|
@ -1332,14 +1332,6 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
|
||||||
b := v.estack.Pop().Bytes()
|
b := v.estack.Pop().Bytes()
|
||||||
v.estack.PushVal(hash.Sha256(b).BytesBE())
|
v.estack.PushVal(hash.Sha256(b).BytesBE())
|
||||||
|
|
||||||
case opcode.HASH160:
|
|
||||||
b := v.estack.Pop().Bytes()
|
|
||||||
v.estack.PushVal(hash.Hash160(b).BytesBE())
|
|
||||||
|
|
||||||
case opcode.HASH256:
|
|
||||||
b := v.estack.Pop().Bytes()
|
|
||||||
v.estack.PushVal(hash.DoubleSha256(b).BytesBE())
|
|
||||||
|
|
||||||
case opcode.NOP:
|
case opcode.NOP:
|
||||||
// unlucky ^^
|
// unlucky ^^
|
||||||
|
|
||||||
|
@ -1446,7 +1438,8 @@ func (v *VM) getJumpOffset(ctx *Context, parameter []byte, mod int) int {
|
||||||
return offset
|
return offset
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkMultisigPar(v *VM, pkeys [][]byte, sigs [][]byte) bool {
|
// CheckMultisigPar checks if sigs contains sufficient valid signatures.
|
||||||
|
func CheckMultisigPar(v *VM, pkeys [][]byte, sigs [][]byte) bool {
|
||||||
if len(sigs) == 1 {
|
if len(sigs) == 1 {
|
||||||
return checkMultisig1(v, pkeys, sigs[0])
|
return checkMultisig1(v, pkeys, sigs[0])
|
||||||
}
|
}
|
||||||
|
@ -1595,8 +1588,8 @@ func (v *VM) bytesToPublicKey(b []byte) *keys.PublicKey {
|
||||||
if v.keys[s] != nil {
|
if v.keys[s] != nil {
|
||||||
pkey = v.keys[s]
|
pkey = v.keys[s]
|
||||||
} else {
|
} else {
|
||||||
pkey = &keys.PublicKey{}
|
var err error
|
||||||
err := pkey.DecodeBytes(b)
|
pkey, err = keys.NewPublicKeyFromBytes(b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err.Error())
|
panic(err.Error())
|
||||||
}
|
}
|
||||||
|
|
|
@ -3035,28 +3035,6 @@ func TestSHA256(t *testing.T) {
|
||||||
assert.Equal(t, res, hex.EncodeToString(vm.estack.Pop().Bytes()))
|
assert.Equal(t, res, hex.EncodeToString(vm.estack.Pop().Bytes()))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHASH160(t *testing.T) {
|
|
||||||
// 0x0100 hashes to fbc22d517f38e7612798ece8e5957cf6c41d8caf
|
|
||||||
res := "fbc22d517f38e7612798ece8e5957cf6c41d8caf"
|
|
||||||
prog := makeProgram(opcode.PUSHBYTES2, 1, 0,
|
|
||||||
opcode.HASH160)
|
|
||||||
vm := load(prog)
|
|
||||||
runVM(t, vm)
|
|
||||||
assert.Equal(t, 1, vm.estack.Len())
|
|
||||||
assert.Equal(t, res, hex.EncodeToString(vm.estack.Pop().Bytes()))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestHASH256(t *testing.T) {
|
|
||||||
// 0x0100 hashes to 677b2d718464ee0121475600b929c0b4155667486577d1320b18c2dc7d4b4f99
|
|
||||||
res := "677b2d718464ee0121475600b929c0b4155667486577d1320b18c2dc7d4b4f99"
|
|
||||||
prog := makeProgram(opcode.PUSHBYTES2, 1, 0,
|
|
||||||
opcode.HASH256)
|
|
||||||
vm := load(prog)
|
|
||||||
runVM(t, vm)
|
|
||||||
assert.Equal(t, 1, vm.estack.Len())
|
|
||||||
assert.Equal(t, res, hex.EncodeToString(vm.estack.Pop().Bytes()))
|
|
||||||
}
|
|
||||||
|
|
||||||
var opcodesTestCases = map[opcode.Opcode][]struct {
|
var opcodesTestCases = map[opcode.Opcode][]struct {
|
||||||
name string
|
name string
|
||||||
args []interface{}
|
args []interface{}
|
||||||
|
|
Loading…
Reference in a new issue