From 546864fec23c1d6018cb6044dafd865d56220a21 Mon Sep 17 00:00:00 2001 From: tanyuan <1067598718@qq.com> Date: Thu, 20 Jun 2019 15:47:24 +0800 Subject: [PATCH] add verifySig and verifyMutiSig Api support (#829) * add verifySig and verifyMutiSig Api support * Update verify muti signs * fix return error * fix error pop * add verifysig_test.go and update multi sig (#6) * remove unused code * remove unused code * update verify muti sig to API * fix error name * Verify sig (#8) * update verifysig_test.go * update verifysig_test.go 2nd --- smartcontract/service/neovm/config.go | 4 + smartcontract/service/neovm/neovm_service.go | 1 + smartcontract/service/neovm/runtime.go | 50 +++++++++ smartcontract/test/verifysig_test.go | 111 +++++++++++++++++++ vm/neovm/opcode_exec.go | 2 +- 5 files changed, 167 insertions(+), 1 deletion(-) create mode 100644 smartcontract/test/verifysig_test.go diff --git a/smartcontract/service/neovm/config.go b/smartcontract/service/neovm/config.go index 597ee993..6c0f3ecd 100644 --- a/smartcontract/service/neovm/config.go +++ b/smartcontract/service/neovm/config.go @@ -36,6 +36,7 @@ var ( STORAGE_PUT_GAS uint64 = 4000 STORAGE_DELETE_GAS uint64 = 100 RUNTIME_CHECKWITNESS_GAS uint64 = 200 + RUNTIME_VERIFYMUTISIG_GAS uint64 = 400 RUNTIME_ADDRESSTOBASE58_GAS uint64 = 40 RUNTIME_BASE58TOADDRESS_GAS uint64 = 30 APPCALL_GAS uint64 = 10 @@ -102,6 +103,7 @@ var ( RUNTIME_BASE58TOADDRESS_NAME = "Ontology.Runtime.Base58ToAddress" RUNTIME_ADDRESSTOBASE58_NAME = "Ontology.Runtime.AddressToBase58" RUNTIME_GETCURRENTBLOCKHASH_NAME = "Ontology.Runtime.GetCurrentBlockHash" + RUNTIME_VERIFYMUTISIG_NAME = "Ontology.Runtime.VerifyMutiSig" NATIVE_INVOKE_NAME = "Ontology.Native.Invoke" @@ -191,5 +193,7 @@ func initGAS_TABLE() *sync.Map { m.Store(RUNTIME_BASE58TOADDRESS_NAME, RUNTIME_BASE58TOADDRESS_GAS) m.Store(RUNTIME_ADDRESSTOBASE58_NAME, RUNTIME_ADDRESSTOBASE58_GAS) + m.Store(RUNTIME_VERIFYMUTISIG_NAME, RUNTIME_VERIFYMUTISIG_GAS) + return &m } diff --git a/smartcontract/service/neovm/neovm_service.go b/smartcontract/service/neovm/neovm_service.go index d882454f..8b4ea205 100644 --- a/smartcontract/service/neovm/neovm_service.go +++ b/smartcontract/service/neovm/neovm_service.go @@ -73,6 +73,7 @@ var ( RUNTIME_GETTRIGGER_NAME: {Execute: RuntimeGetTrigger}, RUNTIME_SERIALIZE_NAME: {Execute: RuntimeSerialize, Validator: validatorSerialize}, RUNTIME_DESERIALIZE_NAME: {Execute: RuntimeDeserialize, Validator: validatorDeserialize}, + RUNTIME_VERIFYMUTISIG_NAME: {Execute: RuntimeVerifyMutiSig}, NATIVE_INVOKE_NAME: {Execute: NativeInvoke}, STORAGE_GET_NAME: {Execute: StorageGet}, STORAGE_PUT_NAME: {Execute: StoragePut}, diff --git a/smartcontract/service/neovm/runtime.go b/smartcontract/service/neovm/runtime.go index d3d4550d..820a55c7 100644 --- a/smartcontract/service/neovm/runtime.go +++ b/smartcontract/service/neovm/runtime.go @@ -27,6 +27,7 @@ import ( "github.com/ontio/ontology-crypto/keypair" "github.com/ontio/ontology/common" "github.com/ontio/ontology/common/serialization" + "github.com/ontio/ontology/core/signature" "github.com/ontio/ontology/core/types" "github.com/ontio/ontology/errors" scommon "github.com/ontio/ontology/smartcontract/common" @@ -96,6 +97,55 @@ func RuntimeDeserialize(service *NeoVmService, engine *vm.ExecutionEngine) error return nil } +func RuntimeVerifyMutiSig(service *NeoVmService, engine *vm.ExecutionEngine) error { + if vm.EvaluationStackCount(engine) < 4 { + return errors.NewErr("[RuntimeVerifyMutiSig] Too few input parameters") + } + data, err := vm.PopByteArray(engine) + if err != nil { + return err + } + arr1, err := vm.PopArray(engine) + if err != nil { + return err + } + pks := make([]keypair.PublicKey, 0, len(arr1)) + for i := 0; i < len(arr1); i++ { + value, err := arr1[i].GetByteArray() + if err != nil { + return err + } + pk, err := keypair.DeserializePublicKey(value) + if err != nil { + return err + } + pks = append(pks, pk) + } + + m, err := vm.PopInt(engine) + if err != nil { + return err + } + arr2, err := vm.PopArray(engine) + if err != nil { + return err + } + signs := make([][]byte, 0, len(arr2)) + for i := 0; i < len(arr2); i++ { + value, err := arr2[i].GetByteArray() + if err != nil { + return err + } + signs = append(signs, value) + } + if err := signature.VerifyMultiSignature(data, pks, m, signs); err != nil { + vm.PushData(engine, false) + } else { + vm.PushData(engine, true) + } + return nil +} + // RuntimeNotify put smart contract execute event notify to notifications func RuntimeNotify(service *NeoVmService, engine *vm.ExecutionEngine) error { item := vm.PopStackItem(engine) diff --git a/smartcontract/test/verifysig_test.go b/smartcontract/test/verifysig_test.go new file mode 100644 index 00000000..fc0cfec8 --- /dev/null +++ b/smartcontract/test/verifysig_test.go @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2018 The ontology Authors + * This file is part of The ontology library. + * + * The ontology is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The ontology is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The ontology. If not, see . + */ + +package test + +import ( + "fmt" + "github.com/ontio/ontology-crypto/keypair" + "github.com/ontio/ontology/account" + "github.com/ontio/ontology/common" + "github.com/ontio/ontology/core/signature" + "github.com/ontio/ontology/smartcontract" + svm "github.com/ontio/ontology/smartcontract/service/neovm" + "github.com/ontio/ontology/vm/neovm" + vtypes "github.com/ontio/ontology/vm/neovm/types" + "testing" +) + +func TestVerifySig(t *testing.T) { + /** + # the code of source python. + Cversion = '2.0.0' + from ontology.interop.Ontology.Runtime import VerifyMutiSig + + def Main(data, pks_list, m, sig_list): + return VerifyMutiSig(data, pks_list, m, sig_list) + **/ + code := `52c56b05322e302e306a00527ac46c59c56b6a00527ac46a51527ac46a52527ac46a53527ac46a54527ac46a54c36a53c36a52c36a51c3681e4f6e746f6c6f67792e52756e74696d652e5665726966794d7574695369676c75660111c56b6a00527ac46a51527ac46a51c300947600a0640c00c16a52527ac4620e007562030000c56a52527ac46a52c3c0517d9c7c75641c00006a53527ac46a52c300c36a54527ac4516a55527ac4625c006a52c3c0527d9c7c756421006a52c300c36a53527ac46a52c351c36a54527ac4516a55527ac4616232006a52c3c0537d9c7c756424006a52c300c36a53527ac46a52c351c36a54527ac46a52c352c36a55527ac462050000f100c176c96a56527ac46a53c36a57527ac46a57c36a54c37d9f7c756419006a56c36a57c3c86a57c36a55c3936a57527ac462e0ff6a56c36c7566` + + data_pre := []byte{1, 2, 3} + data := neovm.NewStackItem(vtypes.NewByteArray(data_pre)) + pks_list := make([]vtypes.StackItems, 0) + sigs_list := make([]vtypes.StackItems, 0) + + accs := make([]*account.Account, 0) + N := 4 + for i := 0; i < N; i++ { + accs = append(accs, account.NewAccount("")) + } + + for _, acc := range accs { + sig, _ := signature.Sign(acc, data_pre) + key0 := neovm.NewStackItem(vtypes.NewByteArray(sig)) + sigs_list = append(sigs_list, key0) + + pk := keypair.SerializePublicKey(acc.PublicKey) + key1 := neovm.NewStackItem(vtypes.NewByteArray(pk)) + pks_list = append(pks_list, key1) + } + + hex, err := common.HexToBytes(code) + + if err != nil { + t.Fatal("hex to byte error:", err) + } + + config := &smartcontract.Config{ + Time: 10, + Height: 10, + Tx: nil, + } + sc := smartcontract.SmartContract{ + Config: config, + Gas: 100000, + } + engine, err := sc.NewExecuteEngine(hex) + + if err != nil { + t.Fatal("hex to byte error:", err) + } + + var service *svm.NeoVmService + service = engine.(*svm.NeoVmService) + e := service.Engine + neovm.PushData(e, sigs_list) + neovm.PushData(e, N) + neovm.PushData(e, pks_list) + neovm.PushData(e, data) + + _, err = engine.Invoke() + if err != nil { + t.Fatal("multisignature inovke err:", err) + } + + arr, err := neovm.PopBoolean(e) + if err != nil { + t.Fatal("multisignature PopBoolean err:", err) + } + + if !arr { + t.Fatal("multisignature failed") + } + + fmt.Printf("multisignature passed\n") + +} diff --git a/vm/neovm/opcode_exec.go b/vm/neovm/opcode_exec.go index ea97065c..81598c11 100644 --- a/vm/neovm/opcode_exec.go +++ b/vm/neovm/opcode_exec.go @@ -130,7 +130,7 @@ var ( HASH256: {Opcode: HASH256, Name: "HASH256", Exec: opHash, Validator: validateCount1}, VERIFY: {Opcode: VERIFY, Name: "VERIFY"}, //CHECKSIG: {Opcode: CHECKSIG, Name: "CHECKSIG", Exec: opCheckSig, Validator: validateCount2}, - //CHECKMULTISIG: {Opcode: CHECKMULTISIG, Name: "CHECKMULTISIG", Exec: opCheckMultiSig, Validator: validateCount2}, + //CHECKMULTISIG: {Opcode: CHECKMULTISIG, Name: "CHECKMULTISIG"}, //Array ARRAYSIZE: {Opcode: ARRAYSIZE, Name: "ARRAYSIZE", Exec: opArraySize, Validator: validateCount1},