From bd3735939306c831f7b98f34606000c3fdfe6182 Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Wed, 22 Jan 2020 18:24:58 +0300 Subject: [PATCH] compiler: implement ECDSA signature verification Add VerifySignature interop for signature verification. It is converted to VERIFY opcode. --- pkg/compiler/analysis.go | 1 + pkg/compiler/codegen.go | 2 ++ pkg/compiler/verify_test.go | 55 ++++++++++++++++++++++++++++++++++++ pkg/interop/crypto/crypto.go | 5 ++++ 4 files changed, 63 insertions(+) create mode 100644 pkg/compiler/verify_test.go diff --git a/pkg/compiler/analysis.go b/pkg/compiler/analysis.go index f57abf85d..da05ad2f6 100644 --- a/pkg/compiler/analysis.go +++ b/pkg/compiler/analysis.go @@ -14,6 +14,7 @@ var ( builtinFuncs = []string{ "len", "append", "SHA256", "SHA1", "Hash256", "Hash160", + "VerifySignature", "FromAddress", "Equals", } ) diff --git a/pkg/compiler/codegen.go b/pkg/compiler/codegen.go index d0923956e..ee4b57562 100644 --- a/pkg/compiler/codegen.go +++ b/pkg/compiler/codegen.go @@ -666,6 +666,8 @@ func (c *codegen) convertBuiltin(expr *ast.CallExpr) { emitOpcode(c.prog.BinWriter, opcode.HASH256) case "Hash160": emitOpcode(c.prog.BinWriter, opcode.HASH160) + case "VerifySignature": + emitOpcode(c.prog.BinWriter, opcode.VERIFY) case "Equals": emitOpcode(c.prog.BinWriter, opcode.EQUAL) case "FromAddress": diff --git a/pkg/compiler/verify_test.go b/pkg/compiler/verify_test.go new file mode 100644 index 000000000..276e2fab2 --- /dev/null +++ b/pkg/compiler/verify_test.go @@ -0,0 +1,55 @@ +package compiler_test + +import ( + "fmt" + "testing" + + "github.com/CityOfZion/neo-go/pkg/crypto/keys" + "github.com/stretchr/testify/require" +) + +func TestVerifyGood(t *testing.T) { + msg := []byte("test message") + pub, sig := signMessage(t, msg) + src := getVerifyProg(pub, sig, msg) + + eval(t, src, true) +} + +func TestVerifyBad(t *testing.T) { + 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) { + key, err := keys.NewPrivateKey() + require.NoError(t, err) + + sig := key.Sign(msg) + pub := key.PublicKey().Bytes() + + return pub, sig +} + +func getVerifyProg(pub, sig, msg []byte) string { + pubS := fmt.Sprintf("%#v", pub) + sigS := fmt.Sprintf("%#v", sig) + msgS := fmt.Sprintf("%#v", msg) + + return ` + package hello + + import "github.com/CityOfZion/neo-go/pkg/interop/crypto" + + func Main() bool { + pub := ` + pubS + ` + sig := ` + sigS + ` + msg := ` + msgS + ` + return crypto.VerifySignature(msg, sig, pub) + } + ` +} diff --git a/pkg/interop/crypto/crypto.go b/pkg/interop/crypto/crypto.go index 6877fd46e..abfe586e8 100644 --- a/pkg/interop/crypto/crypto.go +++ b/pkg/interop/crypto/crypto.go @@ -22,3 +22,8 @@ func Hash160(b []byte) []byte { 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 +}