diff options
-rw-r--r-- | core/vm/runtime/doc.go | 18 | ||||
-rw-r--r-- | core/vm/runtime/env.go | 106 | ||||
-rw-r--r-- | core/vm/runtime/runtime.go | 121 | ||||
-rw-r--r-- | core/vm/runtime/runtime_example_test.go | 34 | ||||
-rw-r--r-- | core/vm/runtime/runtime_test.go | 120 | ||||
-rw-r--r-- | crypto/secp256k1/panic_cb.go | 33 | ||||
-rw-r--r-- | crypto/secp256k1/secp256.go | 122 | ||||
-rw-r--r-- | crypto/secp256k1/secp256_test.go | 15 | ||||
-rw-r--r-- | rpc/api/utils.go | 2 |
9 files changed, 489 insertions, 82 deletions
diff --git a/core/vm/runtime/doc.go b/core/vm/runtime/doc.go new file mode 100644 index 000000000..a3b464a7d --- /dev/null +++ b/core/vm/runtime/doc.go @@ -0,0 +1,18 @@ +// Copyright 2014 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library 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 go-ethereum library 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 go-ethereum library. If not, see <http://www.gnu.org/licenses/>. + +// Package runtime provides a basic execution model for executing EVM code. +package runtime diff --git a/core/vm/runtime/env.go b/core/vm/runtime/env.go new file mode 100644 index 000000000..22f9ea14d --- /dev/null +++ b/core/vm/runtime/env.go @@ -0,0 +1,106 @@ +// Copyright 2014 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library 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 go-ethereum library 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 go-ethereum library. If not, see <http://www.gnu.org/licenses/>. + +package runtime + +import ( + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/vm" +) + +// Env is a basic runtime environment required for running the EVM. +type Env struct { + depth int + state *state.StateDB + + origin common.Address + coinbase common.Address + + number *big.Int + time *big.Int + difficulty *big.Int + gasLimit *big.Int + + logs []vm.StructLog + + getHashFn func(uint64) common.Hash +} + +// NewEnv returns a new vm.Environment +func NewEnv(cfg *Config, state *state.StateDB) vm.Environment { + return &Env{ + state: state, + origin: cfg.Origin, + coinbase: cfg.Coinbase, + number: cfg.BlockNumber, + time: cfg.Time, + difficulty: cfg.Difficulty, + gasLimit: cfg.GasLimit, + } +} + +func (self *Env) StructLogs() []vm.StructLog { + return self.logs +} + +func (self *Env) AddStructLog(log vm.StructLog) { + self.logs = append(self.logs, log) +} + +func (self *Env) Origin() common.Address { return self.origin } +func (self *Env) BlockNumber() *big.Int { return self.number } +func (self *Env) Coinbase() common.Address { return self.coinbase } +func (self *Env) Time() *big.Int { return self.time } +func (self *Env) Difficulty() *big.Int { return self.difficulty } +func (self *Env) Db() vm.Database { return self.state } +func (self *Env) GasLimit() *big.Int { return self.gasLimit } +func (self *Env) VmType() vm.Type { return vm.StdVmTy } +func (self *Env) GetHash(n uint64) common.Hash { + return self.getHashFn(n) +} +func (self *Env) AddLog(log *vm.Log) { + self.state.AddLog(log) +} +func (self *Env) Depth() int { return self.depth } +func (self *Env) SetDepth(i int) { self.depth = i } +func (self *Env) CanTransfer(from common.Address, balance *big.Int) bool { + return self.state.GetBalance(from).Cmp(balance) >= 0 +} +func (self *Env) MakeSnapshot() vm.Database { + return self.state.Copy() +} +func (self *Env) SetSnapshot(copy vm.Database) { + self.state.Set(copy.(*state.StateDB)) +} + +func (self *Env) Transfer(from, to vm.Account, amount *big.Int) { + core.Transfer(from, to, amount) +} + +func (self *Env) Call(caller vm.ContractRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) { + return core.Call(self, caller, addr, data, gas, price, value) +} +func (self *Env) CallCode(caller vm.ContractRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) { + return core.CallCode(self, caller, addr, data, gas, price, value) +} + +func (self *Env) Create(caller vm.ContractRef, data []byte, gas, price, value *big.Int) ([]byte, common.Address, error) { + return core.Create(self, caller, data, gas, price, value) +} diff --git a/core/vm/runtime/runtime.go b/core/vm/runtime/runtime.go new file mode 100644 index 000000000..dd3aa1b0b --- /dev/null +++ b/core/vm/runtime/runtime.go @@ -0,0 +1,121 @@ +// Copyright 2014 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library 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 go-ethereum library 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 go-ethereum library. If not, see <http://www.gnu.org/licenses/>. + +package runtime + +import ( + "math/big" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/ethdb" +) + +// Config is a basic type specifing certain configuration flags for running +// the EVM. +type Config struct { + Difficulty *big.Int + Origin common.Address + Coinbase common.Address + BlockNumber *big.Int + Time *big.Int + GasLimit *big.Int + GasPrice *big.Int + Value *big.Int + DisableJit bool // "disable" so it's enabled by default + Debug bool + + GetHashFn func(n uint64) common.Hash +} + +// sets defaults on the config +func setDefaults(cfg *Config) { + if cfg.Difficulty == nil { + cfg.Difficulty = new(big.Int) + } + if cfg.Time == nil { + cfg.Time = big.NewInt(time.Now().Unix()) + } + if cfg.GasLimit == nil { + cfg.GasLimit = new(big.Int).Set(common.MaxBig) + } + if cfg.GasPrice == nil { + cfg.GasPrice = new(big.Int) + } + if cfg.Value == nil { + cfg.Value = new(big.Int) + } + if cfg.BlockNumber == nil { + cfg.BlockNumber = new(big.Int) + } + if cfg.GetHashFn == nil { + cfg.GetHashFn = func(n uint64) common.Hash { + return common.BytesToHash(crypto.Sha3([]byte(new(big.Int).SetUint64(n).String()))) + } + } +} + +// Execute executes the code using the input as call data during the execution. +// It returns the EVM's return value, the new state and an error if it failed. +// +// Executes sets up a in memory, temporarily, environment for the execution of +// the given code. It enabled the JIT by default and make sure that it's restored +// to it's original state afterwards. +func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) { + if cfg == nil { + cfg = new(Config) + } + setDefaults(cfg) + + // defer the call to setting back the original values + defer func(debug, forceJit, enableJit bool) { + vm.Debug = debug + vm.ForceJit = forceJit + vm.EnableJit = enableJit + }(vm.Debug, vm.ForceJit, vm.EnableJit) + + vm.ForceJit = !cfg.DisableJit + vm.EnableJit = !cfg.DisableJit + vm.Debug = cfg.Debug + + var ( + db, _ = ethdb.NewMemDatabase() + statedb, _ = state.New(common.Hash{}, db) + vmenv = NewEnv(cfg, statedb) + sender = statedb.CreateAccount(cfg.Origin) + receiver = statedb.CreateAccount(common.StringToAddress("contract")) + ) + // set the receiver's (the executing contract) code for execution. + receiver.SetCode(code) + + // Call the code with the given configuration. + ret, err := vmenv.Call( + sender, + receiver.Address(), + input, + cfg.GasLimit, + cfg.GasPrice, + cfg.Value, + ) + + if cfg.Debug { + vm.StdErrFormat(vmenv.StructLogs()) + } + return ret, statedb, err +} diff --git a/core/vm/runtime/runtime_example_test.go b/core/vm/runtime/runtime_example_test.go new file mode 100644 index 000000000..b7d0ddc38 --- /dev/null +++ b/core/vm/runtime/runtime_example_test.go @@ -0,0 +1,34 @@ +// Copyright 2015 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library 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 go-ethereum library 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 go-ethereum library. If not, see <http://www.gnu.org/licenses/>. + +package runtime_test + +import ( + "fmt" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/vm/runtime" +) + +func ExampleExecute() { + ret, _, err := runtime.Execute(common.Hex2Bytes("6060604052600a8060106000396000f360606040526008565b00"), nil, nil) + if err != nil { + fmt.Println(err) + } + fmt.Println(ret) + // Output: + // [96 96 96 64 82 96 8 86 91 0] +} diff --git a/core/vm/runtime/runtime_test.go b/core/vm/runtime/runtime_test.go new file mode 100644 index 000000000..773a0163e --- /dev/null +++ b/core/vm/runtime/runtime_test.go @@ -0,0 +1,120 @@ +// Copyright 2015 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library 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 go-ethereum library 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 go-ethereum library. If not, see <http://www.gnu.org/licenses/>. + +package runtime + +import ( + "strings" + "testing" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/vm" +) + +func TestDefaults(t *testing.T) { + cfg := new(Config) + setDefaults(cfg) + + if cfg.Difficulty == nil { + t.Error("expected difficulty to be non nil") + } + + if cfg.Time == nil { + t.Error("expected time to be non nil") + } + if cfg.GasLimit == nil { + t.Error("expected time to be non nil") + } + if cfg.GasPrice == nil { + t.Error("expected time to be non nil") + } + if cfg.Value == nil { + t.Error("expected time to be non nil") + } + if cfg.GetHashFn == nil { + t.Error("expected time to be non nil") + } + if cfg.BlockNumber == nil { + t.Error("expected block number to be non nil") + } +} + +func TestEnvironment(t *testing.T) { + defer func() { + if r := recover(); r != nil { + t.Fatalf("crashed with: %v", r) + } + }() + + Execute([]byte{ + byte(vm.DIFFICULTY), + byte(vm.TIMESTAMP), + byte(vm.GASLIMIT), + byte(vm.PUSH1), + byte(vm.ORIGIN), + byte(vm.BLOCKHASH), + byte(vm.COINBASE), + }, nil, nil) +} + +func TestRestoreDefaults(t *testing.T) { + Execute(nil, nil, &Config{Debug: true}) + if vm.ForceJit { + t.Error("expected force jit to be disabled") + } + + if vm.Debug { + t.Error("expected debug to be disabled") + } + + if vm.EnableJit { + t.Error("expected jit to be disabled") + } +} + +func BenchmarkCall(b *testing.B) { + var definition = `[{"constant":true,"inputs":[],"name":"seller","outputs":[{"name":"","type":"address"}],"type":"function"},{"constant":false,"inputs":[],"name":"abort","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"value","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[],"name":"refund","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"buyer","outputs":[{"name":"","type":"address"}],"type":"function"},{"constant":false,"inputs":[],"name":"confirmReceived","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"state","outputs":[{"name":"","type":"uint8"}],"type":"function"},{"constant":false,"inputs":[],"name":"confirmPurchase","outputs":[],"type":"function"},{"inputs":[],"type":"constructor"},{"anonymous":false,"inputs":[],"name":"Aborted","type":"event"},{"anonymous":false,"inputs":[],"name":"PurchaseConfirmed","type":"event"},{"anonymous":false,"inputs":[],"name":"ItemReceived","type":"event"},{"anonymous":false,"inputs":[],"name":"Refunded","type":"event"}]` + + var code = common.Hex2Bytes("6060604052361561006c5760e060020a600035046308551a53811461007457806335a063b4146100865780633fa4f245146100a6578063590e1ae3146100af5780637150d8ae146100cf57806373fac6f0146100e1578063c19d93fb146100fe578063d696069714610112575b610131610002565b610133600154600160a060020a031681565b610131600154600160a060020a0390811633919091161461015057610002565b61014660005481565b610131600154600160a060020a039081163391909116146102d557610002565b610133600254600160a060020a031681565b610131600254600160a060020a0333811691161461023757610002565b61014660025460ff60a060020a9091041681565b61013160025460009060ff60a060020a9091041681146101cc57610002565b005b600160a060020a03166060908152602090f35b6060908152602090f35b60025460009060a060020a900460ff16811461016b57610002565b600154600160a060020a03908116908290301631606082818181858883f150506002805460a060020a60ff02191660a160020a179055506040517f72c874aeff0b183a56e2b79c71b46e1aed4dee5e09862134b8821ba2fddbf8bf9250a150565b80546002023414806101dd57610002565b6002805460a060020a60ff021973ffffffffffffffffffffffffffffffffffffffff1990911633171660a060020a1790557fd5d55c8a68912e9a110618df8d5e2e83b8d83211c57a8ddd1203df92885dc881826060a15050565b60025460019060a060020a900460ff16811461025257610002565b60025460008054600160a060020a0390921691606082818181858883f150508354604051600160a060020a0391821694503090911631915082818181858883f150506002805460a060020a60ff02191660a160020a179055506040517fe89152acd703c9d8c7d28829d443260b411454d45394e7995815140c8cbcbcf79250a150565b60025460019060a060020a900460ff1681146102f057610002565b6002805460008054600160a060020a0390921692909102606082818181858883f150508354604051600160a060020a0391821694503090911631915082818181858883f150506002805460a060020a60ff02191660a160020a179055506040517f8616bbbbad963e4e65b1366f1d75dfb63f9e9704bbbf91fb01bec70849906cf79250a15056") + + abi, err := abi.JSON(strings.NewReader(definition)) + if err != nil { + b.Fatal(err) + } + + cpurchase, err := abi.Pack("confirmPurchase") + if err != nil { + b.Fatal(err) + } + creceived, err := abi.Pack("confirmReceived") + if err != nil { + b.Fatal(err) + } + refund, err := abi.Pack("refund") + if err != nil { + b.Fatal(err) + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + for j := 0; j < 400; j++ { + Execute(code, cpurchase, nil) + Execute(code, creceived, nil) + Execute(code, refund, nil) + } + } +} diff --git a/crypto/secp256k1/panic_cb.go b/crypto/secp256k1/panic_cb.go new file mode 100644 index 000000000..e0e9034ee --- /dev/null +++ b/crypto/secp256k1/panic_cb.go @@ -0,0 +1,33 @@ +// Copyright 2015 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library 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 go-ethereum library 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 go-ethereum library. If not, see <http://www.gnu.org/licenses/>. + +package secp256k1 + +import "C" +import "unsafe" + +// Callbacks for converting libsecp256k1 internal faults into +// recoverable Go panics. + +//export secp256k1GoPanicIllegal +func secp256k1GoPanicIllegal(msg *C.char, data unsafe.Pointer) { + panic("illegal argument: " + C.GoString(msg)) +} + +//export secp256k1GoPanicError +func secp256k1GoPanicError(msg *C.char, data unsafe.Pointer) { + panic("internal error: " + C.GoString(msg)) +} diff --git a/crypto/secp256k1/secp256.go b/crypto/secp256k1/secp256.go index a2104016a..41a5608a5 100644 --- a/crypto/secp256k1/secp256.go +++ b/crypto/secp256k1/secp256.go @@ -20,11 +20,11 @@ package secp256k1 /* #cgo CFLAGS: -I./libsecp256k1 -#cgo darwin CFLAGS: -I/usr/local/include -I/opt/pkg/include +#cgo darwin CFLAGS: -I/usr/local/include #cgo freebsd CFLAGS: -I/usr/local/include #cgo linux,arm CFLAGS: -I/usr/local/arm/include #cgo LDFLAGS: -lgmp -#cgo darwin LDFLAGS: -L/usr/local/lib -L/opt/pkg/lib +#cgo darwin LDFLAGS: -L/usr/local/lib #cgo freebsd LDFLAGS: -L/usr/local/lib #cgo linux,arm LDFLAGS: -L/usr/local/arm/lib #define USE_NUM_GMP @@ -35,11 +35,14 @@ package secp256k1 #define NDEBUG #include "./libsecp256k1/src/secp256k1.c" #include "./libsecp256k1/src/modules/recovery/main_impl.h" + +typedef void (*callbackFunc) (const char* msg, void* data); +extern void secp256k1GoPanicIllegal(const char* msg, void* data); +extern void secp256k1GoPanicError(const char* msg, void* data); */ import "C" import ( - "bytes" "errors" "unsafe" @@ -62,8 +65,16 @@ var context *C.secp256k1_context func init() { // around 20 ms on a modern CPU. context = C.secp256k1_context_create(3) // SECP256K1_START_SIGN | SECP256K1_START_VERIFY + C.secp256k1_context_set_illegal_callback(context, C.callbackFunc(C.secp256k1GoPanicIllegal), nil) + C.secp256k1_context_set_error_callback(context, C.callbackFunc(C.secp256k1GoPanicError), nil) } +var ( + ErrInvalidMsgLen = errors.New("invalid message length for signature recovery") + ErrInvalidSignatureLen = errors.New("invalid signature length") + ErrInvalidRecoveryID = errors.New("invalid signature recovery id") +) + func GenerateKeyPair() ([]byte, []byte) { var seckey []byte = randentropy.GetEntropyCSPRNG(32) var seckey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&seckey[0])) @@ -177,69 +188,20 @@ func VerifySeckeyValidity(seckey []byte) error { return nil } -func VerifySignatureValidity(sig []byte) bool { - //64+1 - if len(sig) != 65 { - return false - } - //malleability check, highest bit must be 1 - if (sig[32] & 0x80) == 0x80 { - return false - } - //recovery id check - if sig[64] >= 4 { - return false - } - - return true -} - -//for compressed signatures, does not need pubkey -func VerifySignature(msg []byte, sig []byte, pubkey1 []byte) error { - if msg == nil || sig == nil || pubkey1 == nil { - return errors.New("inputs must be non-nil") - } - if len(sig) != 65 { - return errors.New("invalid signature length") - } - if len(pubkey1) != 65 { - return errors.New("Invalid public key length") - } - - //to enforce malleability, highest bit of S must be 0 - //S starts at 32nd byte - if (sig[32] & 0x80) == 0x80 { //highest bit must be 1 - return errors.New("Signature not malleable") - } - - if sig[64] >= 4 { - return errors.New("Recover byte invalid") - } - - // if pubkey recovered, signature valid - pubkey2, err := RecoverPubkey(msg, sig) - if err != nil { - return err - } - if len(pubkey2) != 65 { - return errors.New("Invalid recovered public key length") - } - if !bytes.Equal(pubkey1, pubkey2) { - return errors.New("Public key does not match recovered public key") - } - - return nil -} - -// recovers a public key from the signature +// RecoverPubkey returns the the public key of the signer. +// msg must be the 32-byte hash of the message to be signed. +// sig must be a 65-byte compact ECDSA signature containing the +// recovery id as the last element. func RecoverPubkey(msg []byte, sig []byte) ([]byte, error) { - if len(sig) != 65 { - return nil, errors.New("Invalid signature length") + if len(msg) != 32 { + return nil, ErrInvalidMsgLen + } + if err := checkSignature(sig); err != nil { + return nil, err } msg_ptr := (*C.uchar)(unsafe.Pointer(&msg[0])) sig_ptr := (*C.uchar)(unsafe.Pointer(&sig[0])) - pubkey := make([]byte, 64) /* this slice is used for both the recoverable signature and the @@ -248,17 +210,15 @@ func RecoverPubkey(msg []byte, sig []byte) ([]byte, error) { pubkey recovery is one bottleneck during load in Ethereum */ bytes65 := make([]byte, 65) - pubkey_ptr := (*C.secp256k1_pubkey)(unsafe.Pointer(&pubkey[0])) recoverable_sig_ptr := (*C.secp256k1_ecdsa_recoverable_signature)(unsafe.Pointer(&bytes65[0])) - recid := C.int(sig[64]) + ret := C.secp256k1_ecdsa_recoverable_signature_parse_compact( context, recoverable_sig_ptr, sig_ptr, recid) - if ret == C.int(0) { return nil, errors.New("Failed to parse signature") } @@ -269,20 +229,28 @@ func RecoverPubkey(msg []byte, sig []byte) ([]byte, error) { recoverable_sig_ptr, msg_ptr, ) - if ret == C.int(0) { return nil, errors.New("Failed to recover public key") - } else { - serialized_pubkey_ptr := (*C.uchar)(unsafe.Pointer(&bytes65[0])) - - var output_len C.size_t - C.secp256k1_ec_pubkey_serialize( // always returns 1 - context, - serialized_pubkey_ptr, - &output_len, - pubkey_ptr, - 0, // SECP256K1_EC_COMPRESSED - ) - return bytes65, nil } + + serialized_pubkey_ptr := (*C.uchar)(unsafe.Pointer(&bytes65[0])) + var output_len C.size_t + C.secp256k1_ec_pubkey_serialize( // always returns 1 + context, + serialized_pubkey_ptr, + &output_len, + pubkey_ptr, + 0, // SECP256K1_EC_COMPRESSED + ) + return bytes65, nil +} + +func checkSignature(sig []byte) error { + if len(sig) != 65 { + return ErrInvalidSignatureLen + } + if sig[64] >= 4 { + return ErrInvalidRecoveryID + } + return nil } diff --git a/crypto/secp256k1/secp256_test.go b/crypto/secp256k1/secp256_test.go index 45c448f3c..cb71ea5e7 100644 --- a/crypto/secp256k1/secp256_test.go +++ b/crypto/secp256k1/secp256_test.go @@ -56,6 +56,17 @@ func TestSignatureValidity(t *testing.T) { } } +func TestInvalidRecoveryID(t *testing.T) { + _, seckey := GenerateKeyPair() + msg := randentropy.GetEntropyCSPRNG(32) + sig, _ := Sign(msg, seckey) + sig[64] = 99 + _, err := RecoverPubkey(msg, sig) + if err != ErrInvalidRecoveryID { + t.Fatalf("got %q, want %q", err, ErrInvalidRecoveryID) + } +} + func TestSignAndRecover(t *testing.T) { pubkey1, seckey := GenerateKeyPair() msg := randentropy.GetEntropyCSPRNG(32) @@ -70,10 +81,6 @@ func TestSignAndRecover(t *testing.T) { if !bytes.Equal(pubkey1, pubkey2) { t.Errorf("pubkey mismatch: want: %x have: %x", pubkey1, pubkey2) } - err = VerifySignature(msg, sig, pubkey1) - if err != nil { - t.Errorf("signature verification error: %s", err) - } } func TestRandomMessagesWithSameKey(t *testing.T) { diff --git a/rpc/api/utils.go b/rpc/api/utils.go index 5a3ade46b..8351e88d3 100644 --- a/rpc/api/utils.go +++ b/rpc/api/utils.go @@ -130,7 +130,7 @@ var ( }, "shh": []string{ "post", - "newIdentify", + "newIdentity", "hasIdentity", "newGroup", "addToGroup", |