aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.travis.yml4
-rw-r--r--Makefile44
-rw-r--r--README.md2
-rw-r--r--accounts/abi/abi.go146
-rw-r--r--accounts/abi/abi_test.go47
-rw-r--r--accounts/abi/argument.go48
-rw-r--r--accounts/abi/method.go76
-rw-r--r--accounts/abi/numbers.go2
-rw-r--r--accounts/abi/type.go12
-rw-r--r--cmd/geth/library.c24
-rw-r--r--cmd/geth/library.go46
-rw-r--r--cmd/geth/main.go3
-rw-r--r--core/blockchain.go34
-rw-r--r--core/blockchain_test.go43
-rw-r--r--core/chain_makers.go4
-rw-r--r--core/events.go3
-rw-r--r--crypto/crypto.go26
-rw-r--r--crypto/crypto_test.go8
-rw-r--r--crypto/ecies/asn1.go7
-rw-r--r--crypto/ecies/ecies.go1
-rw-r--r--crypto/ecies/ecies_test.go121
-rw-r--r--crypto/ecies/params.go14
-rw-r--r--crypto/key.go21
-rw-r--r--crypto/secp256k1/README.md25
-rw-r--r--crypto/secp256k1/curve.go (renamed from crypto/curve.go)168
-rw-r--r--crypto/secp256k1/curve_test.go39
-rw-r--r--crypto/secp256k1/pubkey_scalar_mul.h56
-rw-r--r--crypto/secp256k1/secp256.go33
-rw-r--r--crypto/secp256k1/secp256_test.go33
-rw-r--r--p2p/discover/node.go2
-rw-r--r--p2p/rlpx.go4
-rw-r--r--p2p/rlpx_test.go2
-rw-r--r--p2p/server.go2
-rw-r--r--whisper/message_test.go9
34 files changed, 766 insertions, 343 deletions
diff --git a/.travis.yml b/.travis.yml
index 13211f736..c1d545c54 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -20,10 +20,6 @@ env:
global:
- secure: "U2U1AmkU4NJBgKR/uUAebQY87cNL0+1JHjnLOmmXwxYYyj5ralWb1aSuSH3qSXiT93qLBmtaUkuv9fberHVqrbAeVlztVdUsKAq7JMQH+M99iFkC9UiRMqHmtjWJ0ok4COD1sRYixxi21wb/JrMe3M1iL4QJVS61iltjHhVdM64="
sudo: false
-addons:
- apt:
- packages:
- - libgmp3-dev
notifications:
webhooks:
urls:
diff --git a/Makefile b/Makefile
index 12802647e..d5d3825d8 100644
--- a/Makefile
+++ b/Makefile
@@ -3,15 +3,13 @@
# don't need to bother with make.
.PHONY: geth geth-cross evm all test travis-test-with-coverage xgo clean
-.PHONY: geth-linux geth-linux-arm geth-linux-arm-5 geth-linux-arm-6 geth-linux-arm-7 geth-linux-386 geth-linux-amd64
+.PHONY: geth-linux geth-linux-386 geth-linux-amd64
+.PHONY: geth-linux-arm geth-linux-arm-5 geth-linux-arm-6 geth-linux-arm-7 geth-linux-arm64
.PHONY: geth-darwin geth-darwin-386 geth-darwin-amd64
.PHONY: geth-windows geth-windows-386 geth-windows-amd64
-.PHONY: geth-android geth-ios
+.PHONY: geth-android geth-ios geth-ios-sim
GOBIN = build/bin
-
-CROSSDEPS = https://gmplib.org/download/gmp/gmp-6.1.0.tar.bz2
-MODE ?= default
GO ?= latest
geth:
@@ -28,45 +26,50 @@ geth-linux: geth-linux-386 geth-linux-amd64 geth-linux-arm
@ls -l $(GOBIN)/geth-linux-*
geth-linux-386: xgo
- build/env.sh $(GOBIN)/xgo --go=$(GO) --buildmode=$(MODE) --dest=$(GOBIN) --deps=$(CROSSDEPS) --targets=linux/386 -v $(shell build/flags.sh) ./cmd/geth
+ build/env.sh $(GOBIN)/xgo --go=$(GO) --dest=$(GOBIN) --targets=linux/386 -v $(shell build/flags.sh) ./cmd/geth
@echo "Linux 386 cross compilation done:"
@ls -l $(GOBIN)/geth-linux-* | grep 386
geth-linux-amd64: xgo
- build/env.sh $(GOBIN)/xgo --go=$(GO) --buildmode=$(MODE) --dest=$(GOBIN) --deps=$(CROSSDEPS) --targets=linux/amd64 -v $(shell build/flags.sh) ./cmd/geth
+ build/env.sh $(GOBIN)/xgo --go=$(GO) --dest=$(GOBIN) --targets=linux/amd64 -v $(shell build/flags.sh) ./cmd/geth
@echo "Linux amd64 cross compilation done:"
@ls -l $(GOBIN)/geth-linux-* | grep amd64
-geth-linux-arm: geth-linux-arm-5 geth-linux-arm-6 geth-linux-arm-7
+geth-linux-arm: geth-linux-arm-5 geth-linux-arm-6 geth-linux-arm-7 geth-linux-arm64
@echo "Linux ARM cross compilation done:"
@ls -l $(GOBIN)/geth-linux-* | grep arm
geth-linux-arm-5: xgo
- build/env.sh $(GOBIN)/xgo --go=$(GO) --buildmode=$(MODE) --dest=$(GOBIN) --deps=$(CROSSDEPS) --targets=linux/arm-5 -v $(shell build/flags.sh) ./cmd/geth
+ build/env.sh $(GOBIN)/xgo --go=$(GO) --dest=$(GOBIN) --targets=linux/arm-5 -v $(shell build/flags.sh) ./cmd/geth
@echo "Linux ARMv5 cross compilation done:"
@ls -l $(GOBIN)/geth-linux-* | grep arm-5
geth-linux-arm-6: xgo
- build/env.sh $(GOBIN)/xgo --go=$(GO) --buildmode=$(MODE) --dest=$(GOBIN) --deps=$(CROSSDEPS) --targets=linux/arm-6 -v $(shell build/flags.sh) ./cmd/geth
+ build/env.sh $(GOBIN)/xgo --go=$(GO) --dest=$(GOBIN) --targets=linux/arm-6 -v $(shell build/flags.sh) ./cmd/geth
@echo "Linux ARMv6 cross compilation done:"
@ls -l $(GOBIN)/geth-linux-* | grep arm-6
geth-linux-arm-7: xgo
- build/env.sh $(GOBIN)/xgo --go=$(GO) --buildmode=$(MODE) --dest=$(GOBIN) --deps=$(CROSSDEPS) --targets=linux/arm-7 -v $(shell build/flags.sh) ./cmd/geth
+ build/env.sh $(GOBIN)/xgo --go=$(GO) --dest=$(GOBIN) --targets=linux/arm-7 -v $(shell build/flags.sh) ./cmd/geth
@echo "Linux ARMv7 cross compilation done:"
@ls -l $(GOBIN)/geth-linux-* | grep arm-7
+geth-linux-arm64: xgo
+ build/env.sh $(GOBIN)/xgo --go=$(GO) --dest=$(GOBIN) --targets=linux/arm64 -v $(shell build/flags.sh) ./cmd/geth
+ @echo "Linux ARM64 cross compilation done:"
+ @ls -l $(GOBIN)/geth-linux-* | grep arm64
+
geth-darwin: geth-darwin-386 geth-darwin-amd64
@echo "Darwin cross compilation done:"
@ls -l $(GOBIN)/geth-darwin-*
geth-darwin-386: xgo
- build/env.sh $(GOBIN)/xgo --go=$(GO) --buildmode=$(MODE) --dest=$(GOBIN) --deps=$(CROSSDEPS) --targets=darwin/386 -v $(shell build/flags.sh) ./cmd/geth
+ build/env.sh $(GOBIN)/xgo --go=$(GO) --dest=$(GOBIN) --targets=darwin/386 -v $(shell build/flags.sh) ./cmd/geth
@echo "Darwin 386 cross compilation done:"
@ls -l $(GOBIN)/geth-darwin-* | grep 386
geth-darwin-amd64: xgo
- build/env.sh $(GOBIN)/xgo --go=$(GO) --buildmode=$(MODE) --dest=$(GOBIN) --deps=$(CROSSDEPS) --targets=darwin/amd64 -v $(shell build/flags.sh) ./cmd/geth
+ build/env.sh $(GOBIN)/xgo --go=$(GO) --dest=$(GOBIN) --targets=darwin/amd64 -v $(shell build/flags.sh) ./cmd/geth
@echo "Darwin amd64 cross compilation done:"
@ls -l $(GOBIN)/geth-darwin-* | grep amd64
@@ -75,23 +78,28 @@ geth-windows: geth-windows-386 geth-windows-amd64
@ls -l $(GOBIN)/geth-windows-*
geth-windows-386: xgo
- build/env.sh $(GOBIN)/xgo --go=$(GO) --buildmode=$(MODE) --dest=$(GOBIN) --deps=$(CROSSDEPS) --targets=windows/386 -v $(shell build/flags.sh) ./cmd/geth
+ build/env.sh $(GOBIN)/xgo --go=$(GO) --dest=$(GOBIN) --targets=windows/386 -v $(shell build/flags.sh) ./cmd/geth
@echo "Windows 386 cross compilation done:"
@ls -l $(GOBIN)/geth-windows-* | grep 386
geth-windows-amd64: xgo
- build/env.sh $(GOBIN)/xgo --go=$(GO) --buildmode=$(MODE) --dest=$(GOBIN) --deps=$(CROSSDEPS) --targets=windows/amd64 -v $(shell build/flags.sh) ./cmd/geth
+ build/env.sh $(GOBIN)/xgo --go=$(GO) --dest=$(GOBIN) --targets=windows/amd64 -v $(shell build/flags.sh) ./cmd/geth
@echo "Windows amd64 cross compilation done:"
@ls -l $(GOBIN)/geth-windows-* | grep amd64
geth-android: xgo
- build/env.sh $(GOBIN)/xgo --go=$(GO) --buildmode=$(MODE) --dest=$(GOBIN) --deps=$(CROSSDEPS) --targets=android/* -v $(shell build/flags.sh) ./cmd/geth
+ build/env.sh $(GOBIN)/xgo --go=$(GO) --dest=$(GOBIN) --targets=android/* -v $(shell build/flags.sh) ./cmd/geth
@echo "Android cross compilation done:"
@ls -l $(GOBIN)/geth-android-*
geth-ios: xgo
- build/env.sh $(GOBIN)/xgo --go=$(GO) --buildmode=$(MODE) --dest=$(GOBIN) --deps=$(CROSSDEPS) --depsargs=--disable-assembly --targets=ios/* -v $(shell build/flags.sh) ./cmd/geth
- @echo "iOS cross compilation done:"
+ build/env.sh $(GOBIN)/xgo --go=$(GO) --dest=$(GOBIN) --targets=ios-7.0/* -v $(shell build/flags.sh) ./cmd/geth
+ @echo "iOS framework cross compilation done:"
+ @ls -l $(GOBIN)/geth-ios-*
+
+geth-ios-sim: xgo
+ build/env.sh $(GOBIN)/xgo --go=$(GO) --dest=$(GOBIN) --targets=ios-7.0/amd64 -v $(shell build/flags.sh) ./cmd/geth
+ @echo "iOS framework simulator-only cross compilation done:"
@ls -l $(GOBIN)/geth-ios-*
evm:
diff --git a/README.md b/README.md
index 717e726e3..2d60e0564 100644
--- a/README.md
+++ b/README.md
@@ -30,7 +30,7 @@ For prerequisites and detailed build instructions please read the
[Installation Instructions](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum)
on the wiki.
-Building geth requires two external dependencies, Go and GMP.
+Building geth requires both a Go and a C compiler.
You can install them using your favourite package manager.
Once the dependencies are installed, run
diff --git a/accounts/abi/abi.go b/accounts/abi/abi.go
index 3f05bfe2d..635dc43fe 100644
--- a/accounts/abi/abi.go
+++ b/accounts/abi/abi.go
@@ -20,75 +20,17 @@ import (
"encoding/json"
"fmt"
"io"
- "strings"
+ "math"
- "github.com/ethereum/go-ethereum/crypto"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/logger"
+ "github.com/ethereum/go-ethereum/logger/glog"
)
-// Callable method given a `Name` and whether the method is a constant.
-// If the method is `Const` no transaction needs to be created for this
-// particular Method call. It can easily be simulated using a local VM.
-// For example a `Balance()` method only needs to retrieve something
-// from the storage and therefor requires no Tx to be send to the
-// network. A method such as `Transact` does require a Tx and thus will
-// be flagged `true`.
-// Input specifies the required input parameters for this gives method.
-type Method struct {
- Name string
- Const bool
- Inputs []Argument
- Return Type // not yet implemented
-}
-
-// Returns the methods string signature according to the ABI spec.
-//
-// Example
-//
-// function foo(uint32 a, int b) = "foo(uint32,int256)"
-//
-// Please note that "int" is substitute for its canonical representation "int256"
-func (m Method) String() (out string) {
- out += m.Name
- types := make([]string, len(m.Inputs))
- i := 0
- for _, input := range m.Inputs {
- types[i] = input.Type.String()
- i++
- }
- out += "(" + strings.Join(types, ",") + ")"
-
- return
-}
-
-func (m Method) Id() []byte {
- return crypto.Sha3([]byte(m.String()))[:4]
-}
-
-// Argument holds the name of the argument and the corresponding type.
-// Types are used when packing and testing arguments.
-type Argument struct {
- Name string
- Type Type
-}
-
-func (a *Argument) UnmarshalJSON(data []byte) error {
- var extarg struct {
- Name string
- Type string
- }
- err := json.Unmarshal(data, &extarg)
- if err != nil {
- return fmt.Errorf("argument json err: %v", err)
- }
-
- a.Type, err = NewType(extarg.Type)
- if err != nil {
- return err
- }
- a.Name = extarg.Name
-
- return nil
-}
+// Executer is an executer method for performing state executions. It takes one
+// argument which is the input data and expects output data to be returned as
+// multiple 32 byte word length concatenated slice
+type Executer func(datain []byte) []byte
// The ABI holds information about a contract's context and available
// invokable methods. It will allow you to type check function calls and
@@ -97,6 +39,18 @@ type ABI struct {
Methods map[string]Method
}
+// JSON returns a parsed ABI interface and error if it failed.
+func JSON(reader io.Reader) (ABI, error) {
+ dec := json.NewDecoder(reader)
+
+ var abi ABI
+ if err := dec.Decode(&abi); err != nil {
+ return ABI{}, err
+ }
+
+ return abi, nil
+}
+
// tests, tests whether the given input would result in a successful
// call. Checks argument list count and matches input to `input`.
func (abi ABI) pack(name string, args ...interface{}) ([]byte, error) {
@@ -145,6 +99,55 @@ func (abi ABI) Pack(name string, args ...interface{}) ([]byte, error) {
return packed, nil
}
+// toGoType parses the input and casts it to the proper type defined by the ABI
+// argument in t.
+func toGoType(t Argument, input []byte) interface{} {
+ switch t.Type.T {
+ case IntTy:
+ return common.BytesToBig(input)
+ case UintTy:
+ return common.BytesToBig(input)
+ case BoolTy:
+ return common.BytesToBig(input).Uint64() > 0
+ case AddressTy:
+ return common.BytesToAddress(input)
+ case HashTy:
+ return common.BytesToHash(input)
+ }
+ return nil
+}
+
+// Call executes a call and attemps to parse the return values and returns it as
+// an interface. It uses the executer method to perform the actual call since
+// the abi knows nothing of the lower level calling mechanism.
+//
+// Call supports all abi types and includes multiple return values. When only
+// one item is returned a single interface{} will be returned, if a contract
+// method returns multiple values an []interface{} slice is returned.
+func (abi ABI) Call(executer Executer, name string, args ...interface{}) interface{} {
+ callData, err := abi.Pack(name, args...)
+ if err != nil {
+ glog.V(logger.Debug).Infoln("pack error:", err)
+ return nil
+ }
+
+ output := executer(callData)
+
+ method := abi.Methods[name]
+ ret := make([]interface{}, int(math.Max(float64(len(method.Outputs)), float64(len(output)/32))))
+ for i := 0; i < len(ret); i += 32 {
+ index := i / 32
+ ret[index] = toGoType(method.Outputs[index], output[i:i+32])
+ }
+
+ // return single interface
+ if len(ret) == 1 {
+ return ret[0]
+ }
+
+ return ret
+}
+
func (abi *ABI) UnmarshalJSON(data []byte) error {
var methods []Method
if err := json.Unmarshal(data, &methods); err != nil {
@@ -158,14 +161,3 @@ func (abi *ABI) UnmarshalJSON(data []byte) error {
return nil
}
-
-func JSON(reader io.Reader) (ABI, error) {
- dec := json.NewDecoder(reader)
-
- var abi ABI
- if err := dec.Decode(&abi); err != nil {
- return ABI{}, err
- }
-
- return abi, nil
-}
diff --git a/accounts/abi/abi_test.go b/accounts/abi/abi_test.go
index 96dd3ee62..d514fb8c7 100644
--- a/accounts/abi/abi_test.go
+++ b/accounts/abi/abi_test.go
@@ -92,12 +92,12 @@ func TestReader(t *testing.T) {
exp := ABI{
Methods: map[string]Method{
"balance": Method{
- "balance", true, nil, Type{},
+ "balance", true, nil, nil,
},
"send": Method{
"send", false, []Argument{
Argument{"amount", Uint256},
- }, Type{},
+ }, nil,
},
},
}
@@ -238,10 +238,10 @@ func TestTestAddress(t *testing.T) {
func TestMethodSignature(t *testing.T) {
String, _ := NewType("string")
String32, _ := NewType("string32")
- m := Method{"foo", false, []Argument{Argument{"bar", String32}, Argument{"baz", String}}, Type{}}
+ m := Method{"foo", false, []Argument{Argument{"bar", String32}, Argument{"baz", String}}, nil}
exp := "foo(string32,string)"
- if m.String() != exp {
- t.Error("signature mismatch", exp, "!=", m.String())
+ if m.Sig() != exp {
+ t.Error("signature mismatch", exp, "!=", m.Sig())
}
idexp := crypto.Sha3([]byte(exp))[:4]
@@ -250,10 +250,10 @@ func TestMethodSignature(t *testing.T) {
}
uintt, _ := NewType("uint")
- m = Method{"foo", false, []Argument{Argument{"bar", uintt}}, Type{}}
+ m = Method{"foo", false, []Argument{Argument{"bar", uintt}}, nil}
exp = "foo(uint256)"
- if m.String() != exp {
- t.Error("signature mismatch", exp, "!=", m.String())
+ if m.Sig() != exp {
+ t.Error("signature mismatch", exp, "!=", m.Sig())
}
}
@@ -393,3 +393,34 @@ func TestBytes(t *testing.T) {
t.Error("expected error")
}
}
+
+func TestReturn(t *testing.T) {
+ const definition = `[
+ { "name" : "balance", "const" : true, "inputs" : [], "outputs" : [ { "name": "", "type": "hash" } ] },
+ { "name" : "name", "const" : true, "inputs" : [], "outputs" : [ { "name": "", "type": "address" } ] }
+
+]`
+
+ abi, err := JSON(strings.NewReader(definition))
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ r := abi.Call(func([]byte) []byte {
+ t := make([]byte, 32)
+ t[0] = 1
+ return t
+ }, "balance")
+ if _, ok := r.(common.Hash); !ok {
+ t.Errorf("expected type common.Hash, got %T", r)
+ }
+
+ r = abi.Call(func([]byte) []byte {
+ t := make([]byte, 32)
+ t[0] = 1
+ return t
+ }, "name")
+ if _, ok := r.(common.Address); !ok {
+ t.Errorf("expected type common.Address, got %T", r)
+ }
+}
diff --git a/accounts/abi/argument.go b/accounts/abi/argument.go
new file mode 100644
index 000000000..8907b2979
--- /dev/null
+++ b/accounts/abi/argument.go
@@ -0,0 +1,48 @@
+// 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 abi
+
+import (
+ "encoding/json"
+ "fmt"
+)
+
+// Argument holds the name of the argument and the corresponding type.
+// Types are used when packing and testing arguments.
+type Argument struct {
+ Name string
+ Type Type
+}
+
+func (a *Argument) UnmarshalJSON(data []byte) error {
+ var extarg struct {
+ Name string
+ Type string
+ }
+ err := json.Unmarshal(data, &extarg)
+ if err != nil {
+ return fmt.Errorf("argument json err: %v", err)
+ }
+
+ a.Type, err = NewType(extarg.Type)
+ if err != nil {
+ return err
+ }
+ a.Name = extarg.Name
+
+ return nil
+}
diff --git a/accounts/abi/method.go b/accounts/abi/method.go
new file mode 100644
index 000000000..63194e788
--- /dev/null
+++ b/accounts/abi/method.go
@@ -0,0 +1,76 @@
+// 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 abi
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/ethereum/go-ethereum/crypto"
+)
+
+// Callable method given a `Name` and whether the method is a constant.
+// If the method is `Const` no transaction needs to be created for this
+// particular Method call. It can easily be simulated using a local VM.
+// For example a `Balance()` method only needs to retrieve something
+// from the storage and therefor requires no Tx to be send to the
+// network. A method such as `Transact` does require a Tx and thus will
+// be flagged `true`.
+// Input specifies the required input parameters for this gives method.
+type Method struct {
+ Name string
+ Const bool
+ Inputs []Argument
+ Outputs []Argument
+}
+
+// Sig returns the methods string signature according to the ABI spec.
+//
+// Example
+//
+// function foo(uint32 a, int b) = "foo(uint32,int256)"
+//
+// Please note that "int" is substitute for its canonical representation "int256"
+func (m Method) Sig() string {
+ types := make([]string, len(m.Inputs))
+ i := 0
+ for _, input := range m.Inputs {
+ types[i] = input.Type.String()
+ i++
+ }
+ return fmt.Sprintf("%v(%v)", m.Name, strings.Join(types, ","))
+}
+
+func (m Method) String() string {
+ inputs := make([]string, len(m.Inputs))
+ for i, input := range m.Inputs {
+ inputs[i] = fmt.Sprintf("%v %v", input.Name, input.Type)
+ }
+ outputs := make([]string, len(m.Outputs))
+ for i, output := range m.Outputs {
+ if len(output.Name) > 0 {
+ outputs[i] = fmt.Sprintf("%v ", output.Name)
+ }
+ outputs[i] += output.Type.String()
+ }
+
+ return fmt.Sprintf("function %v(%v) returns(%v)", m.Name, strings.Join(inputs, ", "), strings.Join(outputs, ", "))
+}
+
+func (m Method) Id() []byte {
+ return crypto.Sha3([]byte(m.Sig()))[:4]
+}
diff --git a/accounts/abi/numbers.go b/accounts/abi/numbers.go
index 2a7049425..c37cd5f68 100644
--- a/accounts/abi/numbers.go
+++ b/accounts/abi/numbers.go
@@ -37,6 +37,8 @@ var int8_t = reflect.TypeOf(int8(0))
var int16_t = reflect.TypeOf(int16(0))
var int32_t = reflect.TypeOf(int32(0))
var int64_t = reflect.TypeOf(int64(0))
+var hash_t = reflect.TypeOf(common.Hash{})
+var address_t = reflect.TypeOf(common.Address{})
var uint_ts = reflect.TypeOf([]uint(nil))
var uint8_ts = reflect.TypeOf([]uint8(nil))
diff --git a/accounts/abi/type.go b/accounts/abi/type.go
index 16d7491e7..8f0238fc9 100644
--- a/accounts/abi/type.go
+++ b/accounts/abi/type.go
@@ -31,6 +31,7 @@ const (
BoolTy
SliceTy
AddressTy
+ HashTy
RealTy
)
@@ -121,7 +122,7 @@ func NewType(t string) (typ Type, err error) {
typ.Kind = reflect.Invalid
case "address":
typ.Kind = reflect.Slice
- typ.Type = byte_ts
+ typ.Type = address_t
typ.Size = 20
typ.T = AddressTy
case "string":
@@ -130,6 +131,11 @@ func NewType(t string) (typ Type, err error) {
if vsize > 0 {
typ.Size = 32
}
+ case "hash":
+ typ.Kind = reflect.Slice
+ typ.Size = 32
+ typ.Type = hash_t
+ typ.T = HashTy
case "bytes":
typ.Kind = reflect.Slice
typ.Type = byte_ts
@@ -206,9 +212,9 @@ func (t Type) pack(v interface{}) ([]byte, error) {
}
case reflect.Array:
if v, ok := value.Interface().(common.Address); ok {
- return t.pack(v[:])
+ return common.LeftPadBytes(v[:], 32), nil
} else if v, ok := value.Interface().(common.Hash); ok {
- return t.pack(v[:])
+ return v[:], nil
}
}
diff --git a/cmd/geth/library.c b/cmd/geth/library.c
new file mode 100644
index 000000000..f738621a8
--- /dev/null
+++ b/cmd/geth/library.c
@@ -0,0 +1,24 @@
+// Copyright 2015 The go-ethereum Authors
+// This file is part of go-ethereum.
+//
+// go-ethereum is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// go-ethereum 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 General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
+
+// Simple wrapper to translate the API exposed methods and types to inthernal
+// Go versions of the same types.
+
+#include "_cgo_export.h"
+
+int run(const char* args) {
+ return doRun((char*)args);
+}
diff --git a/cmd/geth/library.go b/cmd/geth/library.go
new file mode 100644
index 000000000..b8ffaaed7
--- /dev/null
+++ b/cmd/geth/library.go
@@ -0,0 +1,46 @@
+// Copyright 2015 The go-ethereum Authors
+// This file is part of go-ethereum.
+//
+// go-ethereum is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// go-ethereum 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 General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
+
+// Contains a simple library definition to allow creating a Geth instance from
+// straight C code.
+
+package main
+
+// #ifdef __cplusplus
+// extern "C" {
+// #endif
+//
+// extern int run(const char*);
+//
+// #ifdef __cplusplus
+// }
+// #endif
+import "C"
+import (
+ "fmt"
+ "os"
+ "strings"
+)
+
+//export doRun
+func doRun(args *C.char) C.int {
+ // This is equivalent to geth.main, just modified to handle the function arg passing
+ if err := app.Run(strings.Split("geth "+C.GoString(args), " ")); err != nil {
+ fmt.Fprintln(os.Stderr, err)
+ return -1
+ }
+ return 0
+}
diff --git a/cmd/geth/main.go b/cmd/geth/main.go
index bb291ccde..f2bb27552 100644
--- a/cmd/geth/main.go
+++ b/cmd/geth/main.go
@@ -341,6 +341,8 @@ JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Conso
utils.ExtraDataFlag,
}
app.Before = func(ctx *cli.Context) error {
+ runtime.GOMAXPROCS(runtime.NumCPU())
+
utils.SetupLogger(ctx)
utils.SetupNetwork(ctx)
utils.SetupVM(ctx)
@@ -354,7 +356,6 @@ JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Conso
}
func main() {
- runtime.GOMAXPROCS(runtime.NumCPU())
defer logger.Flush()
if err := app.Run(os.Args); err != nil {
fmt.Fprintln(os.Stderr, err)
diff --git a/core/blockchain.go b/core/blockchain.go
index 5a6795b3e..9d526e352 100644
--- a/core/blockchain.go
+++ b/core/blockchain.go
@@ -980,6 +980,18 @@ func (self *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain
glog.Fatal(errs[index])
return
}
+ if err := WriteTransactions(self.chainDb, block); err != nil {
+ errs[index] = fmt.Errorf("failed to write individual transactions: %v", err)
+ atomic.AddInt32(&failed, 1)
+ glog.Fatal(errs[index])
+ return
+ }
+ if err := WriteReceipts(self.chainDb, receipts); err != nil {
+ errs[index] = fmt.Errorf("failed to write individual receipts: %v", err)
+ atomic.AddInt32(&failed, 1)
+ glog.Fatal(errs[index])
+ return
+ }
atomic.AddInt32(&stats.processed, 1)
}
}
@@ -1240,6 +1252,17 @@ func (self *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
oldStart = oldBlock
newStart = newBlock
deletedTxs types.Transactions
+ deletedLogs vm.Logs
+ // collectLogs collects the logs that were generated during the
+ // processing of the block that corresponds with the given hash.
+ // These logs are later announced as deleted.
+ collectLogs = func(h common.Hash) {
+ // Coalesce logs
+ receipts := GetBlockReceipts(self.chainDb, h)
+ for _, receipt := range receipts {
+ deletedLogs = append(deletedLogs, receipt.Logs...)
+ }
+ }
)
// first reduce whoever is higher bound
@@ -1247,6 +1270,8 @@ func (self *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
// reduce old chain
for oldBlock = oldBlock; oldBlock != nil && oldBlock.NumberU64() != newBlock.NumberU64(); oldBlock = self.GetBlock(oldBlock.ParentHash()) {
deletedTxs = append(deletedTxs, oldBlock.Transactions()...)
+
+ collectLogs(oldBlock.Hash())
}
} else {
// reduce new chain and append new chain blocks for inserting later on
@@ -1269,6 +1294,7 @@ func (self *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
}
newChain = append(newChain, newBlock)
deletedTxs = append(deletedTxs, oldBlock.Transactions()...)
+ collectLogs(oldBlock.Hash())
oldBlock, newBlock = self.GetBlock(oldBlock.ParentHash()), self.GetBlock(newBlock.ParentHash())
if oldBlock == nil {
@@ -1302,7 +1328,6 @@ func (self *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
if err := WriteMipmapBloom(self.chainDb, block.NumberU64(), receipts); err != nil {
return err
}
-
addedTxs = append(addedTxs, block.Transactions()...)
}
@@ -1316,7 +1341,12 @@ func (self *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
}
// Must be posted in a goroutine because of the transaction pool trying
// to acquire the chain manager lock
- go self.eventMux.Post(RemovedTransactionEvent{diff})
+ if len(diff) > 0 {
+ go self.eventMux.Post(RemovedTransactionEvent{diff})
+ }
+ if len(deletedLogs) > 0 {
+ go self.eventMux.Post(RemovedLogEvent{deletedLogs})
+ }
return nil
}
diff --git a/core/blockchain_test.go b/core/blockchain_test.go
index 6e1c5fdc7..b4ac1696a 100644
--- a/core/blockchain_test.go
+++ b/core/blockchain_test.go
@@ -963,3 +963,46 @@ func TestChainTxReorgs(t *testing.T) {
}
}
}
+
+func TestLogReorgs(t *testing.T) {
+ params.MinGasLimit = big.NewInt(125000) // Minimum the gas limit may ever be.
+ params.GenesisGasLimit = big.NewInt(3141592) // Gas limit of the Genesis block.
+
+ var (
+ key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
+ addr1 = crypto.PubkeyToAddress(key1.PublicKey)
+ db, _ = ethdb.NewMemDatabase()
+ // this code generates a log
+ code = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00")
+ )
+ genesis := WriteGenesisBlockForTesting(db,
+ GenesisAccount{addr1, big.NewInt(10000000000000)},
+ )
+
+ evmux := &event.TypeMux{}
+ blockchain, _ := NewBlockChain(db, FakePow{}, evmux)
+
+ subs := evmux.Subscribe(RemovedLogEvent{})
+ chain, _ := GenerateChain(genesis, db, 2, func(i int, gen *BlockGen) {
+ if i == 1 {
+ tx, err := types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), big.NewInt(1000000), new(big.Int), code).SignECDSA(key1)
+ if err != nil {
+ t.Fatalf("failed to create tx: %v", err)
+ }
+ gen.AddTx(tx)
+ }
+ })
+ if _, err := blockchain.InsertChain(chain); err != nil {
+ t.Fatalf("failed to insert chain: %v", err)
+ }
+
+ chain, _ = GenerateChain(genesis, db, 3, func(i int, gen *BlockGen) {})
+ if _, err := blockchain.InsertChain(chain); err != nil {
+ t.Fatalf("failed to insert forked chain: %v", err)
+ }
+
+ ev := <-subs.Chan()
+ if len(ev.Data.(RemovedLogEvent).Logs) == 0 {
+ t.Error("expected logs")
+ }
+}
diff --git a/core/chain_makers.go b/core/chain_makers.go
index 6d3152d97..4f6fa3989 100644
--- a/core/chain_makers.go
+++ b/core/chain_makers.go
@@ -90,6 +90,7 @@ func (b *BlockGen) AddTx(tx *types.Transaction) {
if b.gasPool == nil {
b.SetCoinbase(common.Address{})
}
+ b.statedb.StartRecord(tx.Hash(), common.Hash{}, len(b.txs))
_, gas, err := ApplyMessage(NewEnv(b.statedb, nil, tx, b.header), tx, b.gasPool)
if err != nil {
panic(err)
@@ -97,8 +98,7 @@ func (b *BlockGen) AddTx(tx *types.Transaction) {
root := b.statedb.IntermediateRoot()
b.header.GasUsed.Add(b.header.GasUsed, gas)
receipt := types.NewReceipt(root.Bytes(), b.header.GasUsed)
- logs := b.statedb.GetLogs(tx.Hash())
- receipt.Logs = logs
+ receipt.Logs = b.statedb.GetLogs(tx.Hash())
receipt.Bloom = types.CreateBloom(types.Receipts{receipt})
b.txs = append(b.txs, tx)
b.receipts = append(b.receipts, receipt)
diff --git a/core/events.go b/core/events.go
index 8cf230dda..1a760c71c 100644
--- a/core/events.go
+++ b/core/events.go
@@ -39,6 +39,9 @@ type NewMinedBlockEvent struct{ Block *types.Block }
// RemovedTransactionEvent is posted when a reorg happens
type RemovedTransactionEvent struct{ Txs types.Transactions }
+// RemovedLogEvent is posted when a reorg happens
+type RemovedLogEvent struct{ Logs vm.Logs }
+
// ChainSplit is posted when a new head is detected
type ChainSplitEvent struct {
Block *types.Block
diff --git a/crypto/crypto.go b/crypto/crypto.go
index 8685d62d3..7d7623753 100644
--- a/crypto/crypto.go
+++ b/crypto/crypto.go
@@ -43,14 +43,6 @@ import (
"golang.org/x/crypto/ripemd160"
)
-var secp256k1n *big.Int
-
-func init() {
- // specify the params for the s256 curve
- ecies.AddParamsForCurve(S256(), ecies.ECIES_AES128_SHA256)
- secp256k1n = common.String2Big("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141")
-}
-
func Sha3(data ...[]byte) []byte {
d := sha3.NewKeccak256()
for _, b := range data {
@@ -99,9 +91,9 @@ func ToECDSA(prv []byte) *ecdsa.PrivateKey {
}
priv := new(ecdsa.PrivateKey)
- priv.PublicKey.Curve = S256()
+ priv.PublicKey.Curve = secp256k1.S256()
priv.D = common.BigD(prv)
- priv.PublicKey.X, priv.PublicKey.Y = S256().ScalarBaseMult(prv)
+ priv.PublicKey.X, priv.PublicKey.Y = secp256k1.S256().ScalarBaseMult(prv)
return priv
}
@@ -116,15 +108,15 @@ func ToECDSAPub(pub []byte) *ecdsa.PublicKey {
if len(pub) == 0 {
return nil
}
- x, y := elliptic.Unmarshal(S256(), pub)
- return &ecdsa.PublicKey{S256(), x, y}
+ x, y := elliptic.Unmarshal(secp256k1.S256(), pub)
+ return &ecdsa.PublicKey{secp256k1.S256(), x, y}
}
func FromECDSAPub(pub *ecdsa.PublicKey) []byte {
if pub == nil || pub.X == nil || pub.Y == nil {
return nil
}
- return elliptic.Marshal(S256(), pub.X, pub.Y)
+ return elliptic.Marshal(secp256k1.S256(), pub.X, pub.Y)
}
// HexToECDSA parses a secp256k1 private key.
@@ -168,7 +160,7 @@ func SaveECDSA(file string, key *ecdsa.PrivateKey) error {
}
func GenerateKey() (*ecdsa.PrivateKey, error) {
- return ecdsa.GenerateKey(S256(), rand.Reader)
+ return ecdsa.GenerateKey(secp256k1.S256(), rand.Reader)
}
func ValidateSignatureValues(v byte, r, s *big.Int) bool {
@@ -176,7 +168,7 @@ func ValidateSignatureValues(v byte, r, s *big.Int) bool {
return false
}
vint := uint32(v)
- if r.Cmp(secp256k1n) < 0 && s.Cmp(secp256k1n) < 0 && (vint == 27 || vint == 28) {
+ if r.Cmp(secp256k1.N) < 0 && s.Cmp(secp256k1.N) < 0 && (vint == 27 || vint == 28) {
return true
} else {
return false
@@ -189,8 +181,8 @@ func SigToPub(hash, sig []byte) (*ecdsa.PublicKey, error) {
return nil, err
}
- x, y := elliptic.Unmarshal(S256(), s)
- return &ecdsa.PublicKey{S256(), x, y}, nil
+ x, y := elliptic.Unmarshal(secp256k1.S256(), s)
+ return &ecdsa.PublicKey{secp256k1.S256(), x, y}, nil
}
func Sign(hash []byte, prv *ecdsa.PrivateKey) (sig []byte, err error) {
diff --git a/crypto/crypto_test.go b/crypto/crypto_test.go
index fdd9c1ee8..d5e19a4bb 100644
--- a/crypto/crypto_test.go
+++ b/crypto/crypto_test.go
@@ -181,7 +181,7 @@ func TestValidateSignatureValues(t *testing.T) {
minusOne := big.NewInt(-1)
one := common.Big1
zero := common.Big0
- secp256k1nMinus1 := new(big.Int).Sub(secp256k1n, common.Big1)
+ secp256k1nMinus1 := new(big.Int).Sub(secp256k1.N, common.Big1)
// correct v,r,s
check(true, 27, one, one)
@@ -208,9 +208,9 @@ func TestValidateSignatureValues(t *testing.T) {
// correct sig with max r,s
check(true, 27, secp256k1nMinus1, secp256k1nMinus1)
// correct v, combinations of incorrect r,s at upper limit
- check(false, 27, secp256k1n, secp256k1nMinus1)
- check(false, 27, secp256k1nMinus1, secp256k1n)
- check(false, 27, secp256k1n, secp256k1n)
+ check(false, 27, secp256k1.N, secp256k1nMinus1)
+ check(false, 27, secp256k1nMinus1, secp256k1.N)
+ check(false, 27, secp256k1.N, secp256k1.N)
// current callers ensures r,s cannot be negative, but let's test for that too
// as crypto package could be used stand-alone
diff --git a/crypto/ecies/asn1.go b/crypto/ecies/asn1.go
index 6eaf3d2ca..40dabd329 100644
--- a/crypto/ecies/asn1.go
+++ b/crypto/ecies/asn1.go
@@ -41,6 +41,8 @@ import (
"fmt"
"hash"
"math/big"
+
+ "github.com/ethereum/go-ethereum/crypto/secp256k1"
)
var (
@@ -81,6 +83,7 @@ func doScheme(base, v []int) asn1.ObjectIdentifier {
type secgNamedCurve asn1.ObjectIdentifier
var (
+ secgNamedCurveS256 = secgNamedCurve{1, 3, 132, 0, 10}
secgNamedCurveP256 = secgNamedCurve{1, 2, 840, 10045, 3, 1, 7}
secgNamedCurveP384 = secgNamedCurve{1, 3, 132, 0, 34}
secgNamedCurveP521 = secgNamedCurve{1, 3, 132, 0, 35}
@@ -116,6 +119,8 @@ func (curve secgNamedCurve) Equal(curve2 secgNamedCurve) bool {
func namedCurveFromOID(curve secgNamedCurve) elliptic.Curve {
switch {
+ case curve.Equal(secgNamedCurveS256):
+ return secp256k1.S256()
case curve.Equal(secgNamedCurveP256):
return elliptic.P256()
case curve.Equal(secgNamedCurveP384):
@@ -134,6 +139,8 @@ func oidFromNamedCurve(curve elliptic.Curve) (secgNamedCurve, bool) {
return secgNamedCurveP384, true
case elliptic.P521():
return secgNamedCurveP521, true
+ case secp256k1.S256():
+ return secgNamedCurveS256, true
}
return nil, false
diff --git a/crypto/ecies/ecies.go b/crypto/ecies/ecies.go
index a3b520dd5..65dc5b38b 100644
--- a/crypto/ecies/ecies.go
+++ b/crypto/ecies/ecies.go
@@ -125,6 +125,7 @@ func (prv *PrivateKey) GenerateShared(pub *PublicKey, skLen, macLen int) (sk []b
if skLen+macLen > MaxSharedKeyLength(pub) {
return nil, ErrSharedKeyTooBig
}
+
x, _ := pub.Curve.ScalarMult(pub.X, pub.Y, prv.D.Bytes())
if x == nil {
return nil, ErrSharedKeyIsPointAtInfinity
diff --git a/crypto/ecies/ecies_test.go b/crypto/ecies/ecies_test.go
index 1c391f938..6a0ea3f02 100644
--- a/crypto/ecies/ecies_test.go
+++ b/crypto/ecies/ecies_test.go
@@ -31,13 +31,18 @@ package ecies
import (
"bytes"
+ "crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/sha256"
+ "encoding/hex"
"flag"
"fmt"
"io/ioutil"
+ "math/big"
"testing"
+
+ "github.com/ethereum/go-ethereum/crypto/secp256k1"
)
var dumpEnc bool
@@ -65,7 +70,6 @@ func TestKDF(t *testing.T) {
}
}
-var skLen int
var ErrBadSharedKeys = fmt.Errorf("ecies: shared keys don't match")
// cmpParams compares a set of ECIES parameters. We assume, as per the
@@ -117,7 +121,7 @@ func TestSharedKey(t *testing.T) {
fmt.Println(err.Error())
t.FailNow()
}
- skLen = MaxSharedKeyLength(&prv1.PublicKey) / 2
+ skLen := MaxSharedKeyLength(&prv1.PublicKey) / 2
prv2, err := GenerateKey(rand.Reader, DefaultCurve, nil)
if err != nil {
@@ -143,6 +147,44 @@ func TestSharedKey(t *testing.T) {
}
}
+func TestSharedKeyPadding(t *testing.T) {
+ // sanity checks
+ prv0 := hexKey("1adf5c18167d96a1f9a0b1ef63be8aa27eaf6032c233b2b38f7850cf5b859fd9")
+ prv1 := hexKey("97a076fc7fcd9208240668e31c9abee952cbb6e375d1b8febc7499d6e16f1a")
+ x0, _ := new(big.Int).SetString("1a8ed022ff7aec59dc1b440446bdda5ff6bcb3509a8b109077282b361efffbd8", 16)
+ x1, _ := new(big.Int).SetString("6ab3ac374251f638d0abb3ef596d1dc67955b507c104e5f2009724812dc027b8", 16)
+ y0, _ := new(big.Int).SetString("e040bd480b1deccc3bc40bd5b1fdcb7bfd352500b477cb9471366dbd4493f923", 16)
+ y1, _ := new(big.Int).SetString("8ad915f2b503a8be6facab6588731fefeb584fd2dfa9a77a5e0bba1ec439e4fa", 16)
+
+ if prv0.PublicKey.X.Cmp(x0) != 0 {
+ t.Errorf("mismatched prv0.X:\nhave: %x\nwant: %x\n", prv0.PublicKey.X.Bytes(), x0.Bytes())
+ }
+ if prv0.PublicKey.Y.Cmp(y0) != 0 {
+ t.Errorf("mismatched prv0.Y:\nhave: %x\nwant: %x\n", prv0.PublicKey.Y.Bytes(), y0.Bytes())
+ }
+ if prv1.PublicKey.X.Cmp(x1) != 0 {
+ t.Errorf("mismatched prv1.X:\nhave: %x\nwant: %x\n", prv1.PublicKey.X.Bytes(), x1.Bytes())
+ }
+ if prv1.PublicKey.Y.Cmp(y1) != 0 {
+ t.Errorf("mismatched prv1.Y:\nhave: %x\nwant: %x\n", prv1.PublicKey.Y.Bytes(), y1.Bytes())
+ }
+
+ // test shared secret generation
+ sk1, err := prv0.GenerateShared(&prv1.PublicKey, 16, 16)
+ if err != nil {
+ fmt.Println(err.Error())
+ }
+
+ sk2, err := prv1.GenerateShared(&prv0.PublicKey, 16, 16)
+ if err != nil {
+ t.Fatal(err.Error())
+ }
+
+ if !bytes.Equal(sk1, sk2) {
+ t.Fatal(ErrBadSharedKeys.Error())
+ }
+}
+
// Verify that the key generation code fails when too much key data is
// requested.
func TestTooBigSharedKey(t *testing.T) {
@@ -158,13 +200,13 @@ func TestTooBigSharedKey(t *testing.T) {
t.FailNow()
}
- _, err = prv1.GenerateShared(&prv2.PublicKey, skLen*2, skLen*2)
+ _, err = prv1.GenerateShared(&prv2.PublicKey, 32, 32)
if err != ErrSharedKeyTooBig {
fmt.Println("ecdh: shared key should be too large for curve")
t.FailNow()
}
- _, err = prv2.GenerateShared(&prv1.PublicKey, skLen*2, skLen*2)
+ _, err = prv2.GenerateShared(&prv1.PublicKey, 32, 32)
if err != ErrSharedKeyTooBig {
fmt.Println("ecdh: shared key should be too large for curve")
t.FailNow()
@@ -176,25 +218,21 @@ func TestTooBigSharedKey(t *testing.T) {
func TestMarshalPublic(t *testing.T) {
prv, err := GenerateKey(rand.Reader, DefaultCurve, nil)
if err != nil {
- fmt.Println(err.Error())
- t.FailNow()
+ t.Fatalf("GenerateKey error: %s", err)
}
out, err := MarshalPublic(&prv.PublicKey)
if err != nil {
- fmt.Println(err.Error())
- t.FailNow()
+ t.Fatalf("MarshalPublic error: %s", err)
}
pub, err := UnmarshalPublic(out)
if err != nil {
- fmt.Println(err.Error())
- t.FailNow()
+ t.Fatalf("UnmarshalPublic error: %s", err)
}
if !cmpPublic(prv.PublicKey, *pub) {
- fmt.Println("ecies: failed to unmarshal public key")
- t.FailNow()
+ t.Fatal("ecies: failed to unmarshal public key")
}
}
@@ -304,9 +342,26 @@ func BenchmarkGenSharedKeyP256(b *testing.B) {
fmt.Println(err.Error())
b.FailNow()
}
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ _, err := prv.GenerateShared(&prv.PublicKey, 16, 16)
+ if err != nil {
+ fmt.Println(err.Error())
+ b.FailNow()
+ }
+ }
+}
+// Benchmark the generation of S256 shared keys.
+func BenchmarkGenSharedKeyS256(b *testing.B) {
+ prv, err := GenerateKey(rand.Reader, secp256k1.S256(), nil)
+ if err != nil {
+ fmt.Println(err.Error())
+ b.FailNow()
+ }
+ b.ResetTimer()
for i := 0; i < b.N; i++ {
- _, err := prv.GenerateShared(&prv.PublicKey, skLen, skLen)
+ _, err := prv.GenerateShared(&prv.PublicKey, 16, 16)
if err != nil {
fmt.Println(err.Error())
b.FailNow()
@@ -511,3 +566,43 @@ func TestBasicKeyValidation(t *testing.T) {
}
}
}
+
+// Verify GenerateShared against static values - useful when
+// debugging changes in underlying libs
+func TestSharedKeyStatic(t *testing.T) {
+ prv1 := hexKey("7ebbc6a8358bc76dd73ebc557056702c8cfc34e5cfcd90eb83af0347575fd2ad")
+ prv2 := hexKey("6a3d6396903245bba5837752b9e0348874e72db0c4e11e9c485a81b4ea4353b9")
+
+ skLen := MaxSharedKeyLength(&prv1.PublicKey) / 2
+
+ sk1, err := prv1.GenerateShared(&prv2.PublicKey, skLen, skLen)
+ if err != nil {
+ fmt.Println(err.Error())
+ t.FailNow()
+ }
+
+ sk2, err := prv2.GenerateShared(&prv1.PublicKey, skLen, skLen)
+ if err != nil {
+ fmt.Println(err.Error())
+ t.FailNow()
+ }
+
+ if !bytes.Equal(sk1, sk2) {
+ fmt.Println(ErrBadSharedKeys.Error())
+ t.FailNow()
+ }
+
+ sk, _ := hex.DecodeString("167ccc13ac5e8a26b131c3446030c60fbfac6aa8e31149d0869f93626a4cdf62")
+ if !bytes.Equal(sk1, sk) {
+ t.Fatalf("shared secret mismatch: want: %x have: %x", sk, sk1)
+ }
+}
+
+// TODO: remove after refactoring packages crypto and crypto/ecies
+func hexKey(prv string) *PrivateKey {
+ priv := new(ecdsa.PrivateKey)
+ priv.PublicKey.Curve = secp256k1.S256()
+ priv.D, _ = new(big.Int).SetString(prv, 16)
+ priv.PublicKey.X, priv.PublicKey.Y = secp256k1.S256().ScalarBaseMult(priv.D.Bytes())
+ return ImportECDSA(priv)
+}
diff --git a/crypto/ecies/params.go b/crypto/ecies/params.go
index 97ddb0973..511c53ebc 100644
--- a/crypto/ecies/params.go
+++ b/crypto/ecies/params.go
@@ -41,13 +41,12 @@ import (
"crypto/sha512"
"fmt"
"hash"
-)
-// The default curve for this package is the NIST P256 curve, which
-// provides security equivalent to AES-128.
-var DefaultCurve = elliptic.P256()
+ "github.com/ethereum/go-ethereum/crypto/secp256k1"
+)
var (
+ DefaultCurve = secp256k1.S256()
ErrUnsupportedECDHAlgorithm = fmt.Errorf("ecies: unsupported ECDH algorithm")
ErrUnsupportedECIESParameters = fmt.Errorf("ecies: unsupported ECIES parameters")
)
@@ -101,9 +100,10 @@ var (
)
var paramsFromCurve = map[elliptic.Curve]*ECIESParams{
- elliptic.P256(): ECIES_AES128_SHA256,
- elliptic.P384(): ECIES_AES256_SHA384,
- elliptic.P521(): ECIES_AES256_SHA512,
+ secp256k1.S256(): ECIES_AES128_SHA256,
+ elliptic.P256(): ECIES_AES128_SHA256,
+ elliptic.P384(): ECIES_AES256_SHA384,
+ elliptic.P521(): ECIES_AES256_SHA512,
}
func AddParamsForCurve(curve elliptic.Curve, params *ECIESParams) {
diff --git a/crypto/key.go b/crypto/key.go
index 4ec43dfd7..8e2d8553b 100644
--- a/crypto/key.go
+++ b/crypto/key.go
@@ -25,6 +25,7 @@ import (
"strings"
"github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/crypto/secp256k1"
"github.com/pborman/uuid"
)
@@ -49,17 +50,17 @@ type plainKeyJSON struct {
}
type encryptedKeyJSONV3 struct {
- Address string `json:"address"`
- Crypto cryptoJSON
- Id string `json:"id"`
- Version int `json:"version"`
+ Address string `json:"address"`
+ Crypto cryptoJSON `json:"crypto"`
+ Id string `json:"id"`
+ Version int `json:"version"`
}
type encryptedKeyJSONV1 struct {
- Address string `json:"address"`
- Crypto cryptoJSON
- Id string `json:"id"`
- Version string `json:"version"`
+ Address string `json:"address"`
+ Crypto cryptoJSON `json:"crypto"`
+ Id string `json:"id"`
+ Version string `json:"version"`
}
type cryptoJSON struct {
@@ -137,7 +138,7 @@ func NewKey(rand io.Reader) *Key {
panic("key generation: could not read from random source: " + err.Error())
}
reader := bytes.NewReader(randBytes)
- privateKeyECDSA, err := ecdsa.GenerateKey(S256(), reader)
+ privateKeyECDSA, err := ecdsa.GenerateKey(secp256k1.S256(), reader)
if err != nil {
panic("key generation: ecdsa.GenerateKey failed: " + err.Error())
}
@@ -155,7 +156,7 @@ func NewKeyForDirectICAP(rand io.Reader) *Key {
panic("key generation: could not read from random source: " + err.Error())
}
reader := bytes.NewReader(randBytes)
- privateKeyECDSA, err := ecdsa.GenerateKey(S256(), reader)
+ privateKeyECDSA, err := ecdsa.GenerateKey(secp256k1.S256(), reader)
if err != nil {
panic("key generation: ecdsa.GenerateKey failed: " + err.Error())
}
diff --git a/crypto/secp256k1/README.md b/crypto/secp256k1/README.md
deleted file mode 100644
index 5a86147d4..000000000
--- a/crypto/secp256k1/README.md
+++ /dev/null
@@ -1,25 +0,0 @@
-secp256k1-go
-=======
-
-golang secp256k1 library
-
-Implements cryptographic operations for the secp256k1 ECDSA curve used by Bitcoin.
-
-Installing
-===
-
-GMP library headers are required to build. On Debian-based systems, the package is called `libgmp-dev`.
-
-```
-sudo apt-get install libgmp-dev
-```
-
-Now compiles with cgo!
-
-Test
-===
-
-To run tests do
-```
-go tests
-``` \ No newline at end of file
diff --git a/crypto/curve.go b/crypto/secp256k1/curve.go
index 48f3f5e9c..6e44a6771 100644
--- a/crypto/curve.go
+++ b/crypto/secp256k1/curve.go
@@ -29,15 +29,22 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-package crypto
+package secp256k1
import (
"crypto/elliptic"
"io"
"math/big"
"sync"
+ "unsafe"
)
+/*
+#include "libsecp256k1/include/secp256k1.h"
+extern int secp256k1_pubkey_scalar_mul(const secp256k1_context* ctx, const unsigned char *point, const unsigned char *scalar);
+*/
+import "C"
+
// This code is from https://github.com/ThePiachu/GoBit and implements
// several Koblitz elliptic curves over prime fields.
//
@@ -211,44 +218,37 @@ func (BitCurve *BitCurve) doubleJacobian(x, y, z *big.Int) (*big.Int, *big.Int,
return x3, y3, z3
}
-//TODO: double check if it is okay
-// ScalarMult returns k*(Bx,By) where k is a number in big-endian form.
-func (BitCurve *BitCurve) ScalarMult(Bx, By *big.Int, k []byte) (*big.Int, *big.Int) {
- // We have a slight problem in that the identity of the group (the
- // point at infinity) cannot be represented in (x, y) form on a finite
- // machine. Thus the standard add/double algorithm has to be tweaked
- // slightly: our initial state is not the identity, but x, and we
- // ignore the first true bit in |k|. If we don't find any true bits in
- // |k|, then we return nil, nil, because we cannot return the identity
- // element.
-
- Bz := new(big.Int).SetInt64(1)
- x := Bx
- y := By
- z := Bz
-
- seenFirstTrue := false
- for _, byte := range k {
- for bitNum := 0; bitNum < 8; bitNum++ {
- if seenFirstTrue {
- x, y, z = BitCurve.doubleJacobian(x, y, z)
- }
- if byte&0x80 == 0x80 {
- if !seenFirstTrue {
- seenFirstTrue = true
- } else {
- x, y, z = BitCurve.addJacobian(Bx, By, Bz, x, y, z)
- }
- }
- byte <<= 1
- }
+func (BitCurve *BitCurve) ScalarMult(Bx, By *big.Int, scalar []byte) (*big.Int, *big.Int) {
+ // Ensure scalar is exactly 32 bytes. We pad always, even if
+ // scalar is 32 bytes long, to avoid a timing side channel.
+ if len(scalar) > 32 {
+ panic("can't handle scalars > 256 bits")
}
-
- if !seenFirstTrue {
+ padded := make([]byte, 32)
+ copy(padded[32-len(scalar):], scalar)
+ scalar = padded
+
+ // Do the multiplication in C, updating point.
+ point := make([]byte, 64)
+ readBits(point[:32], Bx)
+ readBits(point[32:], By)
+ pointPtr := (*C.uchar)(unsafe.Pointer(&point[0]))
+ scalarPtr := (*C.uchar)(unsafe.Pointer(&scalar[0]))
+ res := C.secp256k1_pubkey_scalar_mul(context, pointPtr, scalarPtr)
+
+ // Unpack the result and clear temporaries.
+ x := new(big.Int).SetBytes(point[:32])
+ y := new(big.Int).SetBytes(point[32:])
+ for i := range point {
+ point[i] = 0
+ }
+ for i := range padded {
+ scalar[i] = 0
+ }
+ if res != 1 {
return nil, nil
}
-
- return BitCurve.affineFromJacobian(x, y, z)
+ return x, y
}
// ScalarBaseMult returns k*G, where G is the base point of the group and k is
@@ -312,86 +312,24 @@ func (BitCurve *BitCurve) Unmarshal(data []byte) (x, y *big.Int) {
return
}
-//curve parameters taken from:
-//http://www.secg.org/collateral/sec2_final.pdf
-
-var initonce sync.Once
-var ecp160k1 *BitCurve
-var ecp192k1 *BitCurve
-var ecp224k1 *BitCurve
-var ecp256k1 *BitCurve
-
-func initAll() {
- initS160()
- initS192()
- initS224()
- initS256()
-}
-
-func initS160() {
- // See SEC 2 section 2.4.1
- ecp160k1 = new(BitCurve)
- ecp160k1.P, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73", 16)
- ecp160k1.N, _ = new(big.Int).SetString("0100000000000000000001B8FA16DFAB9ACA16B6B3", 16)
- ecp160k1.B, _ = new(big.Int).SetString("0000000000000000000000000000000000000007", 16)
- ecp160k1.Gx, _ = new(big.Int).SetString("3B4C382CE37AA192A4019E763036F4F5DD4D7EBB", 16)
- ecp160k1.Gy, _ = new(big.Int).SetString("938CF935318FDCED6BC28286531733C3F03C4FEE", 16)
- ecp160k1.BitSize = 160
-}
-
-func initS192() {
- // See SEC 2 section 2.5.1
- ecp192k1 = new(BitCurve)
- ecp192k1.P, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFEE37", 16)
- ecp192k1.N, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFE26F2FC170F69466A74DEFD8D", 16)
- ecp192k1.B, _ = new(big.Int).SetString("000000000000000000000000000000000000000000000003", 16)
- ecp192k1.Gx, _ = new(big.Int).SetString("DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D", 16)
- ecp192k1.Gy, _ = new(big.Int).SetString("9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D", 16)
- ecp192k1.BitSize = 192
-}
-
-func initS224() {
- // See SEC 2 section 2.6.1
- ecp224k1 = new(BitCurve)
- ecp224k1.P, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFE56D", 16)
- ecp224k1.N, _ = new(big.Int).SetString("010000000000000000000000000001DCE8D2EC6184CAF0A971769FB1F7", 16)
- ecp224k1.B, _ = new(big.Int).SetString("00000000000000000000000000000000000000000000000000000005", 16)
- ecp224k1.Gx, _ = new(big.Int).SetString("A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C", 16)
- ecp224k1.Gy, _ = new(big.Int).SetString("7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5", 16)
- ecp224k1.BitSize = 224
-}
-
-func initS256() {
- // See SEC 2 section 2.7.1
- ecp256k1 = new(BitCurve)
- ecp256k1.P, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", 16)
- ecp256k1.N, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", 16)
- ecp256k1.B, _ = new(big.Int).SetString("0000000000000000000000000000000000000000000000000000000000000007", 16)
- ecp256k1.Gx, _ = new(big.Int).SetString("79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", 16)
- ecp256k1.Gy, _ = new(big.Int).SetString("483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8", 16)
- ecp256k1.BitSize = 256
-}
-
-// S160 returns a BitCurve which implements secp160k1 (see SEC 2 section 2.4.1)
-func S160() *BitCurve {
- initonce.Do(initAll)
- return ecp160k1
-}
-
-// S192 returns a BitCurve which implements secp192k1 (see SEC 2 section 2.5.1)
-func S192() *BitCurve {
- initonce.Do(initAll)
- return ecp192k1
-}
-
-// S224 returns a BitCurve which implements secp224k1 (see SEC 2 section 2.6.1)
-func S224() *BitCurve {
- initonce.Do(initAll)
- return ecp224k1
-}
+var (
+ initonce sync.Once
+ theCurve *BitCurve
+)
// S256 returns a BitCurve which implements secp256k1 (see SEC 2 section 2.7.1)
func S256() *BitCurve {
- initonce.Do(initAll)
- return ecp256k1
+ initonce.Do(func() {
+ // See SEC 2 section 2.7.1
+ // curve parameters taken from:
+ // http://www.secg.org/collateral/sec2_final.pdf
+ theCurve = new(BitCurve)
+ theCurve.P, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", 16)
+ theCurve.N, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", 16)
+ theCurve.B, _ = new(big.Int).SetString("0000000000000000000000000000000000000000000000000000000000000007", 16)
+ theCurve.Gx, _ = new(big.Int).SetString("79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", 16)
+ theCurve.Gy, _ = new(big.Int).SetString("483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8", 16)
+ theCurve.BitSize = 256
+ })
+ return theCurve
}
diff --git a/crypto/secp256k1/curve_test.go b/crypto/secp256k1/curve_test.go
new file mode 100644
index 000000000..d915ee852
--- /dev/null
+++ b/crypto/secp256k1/curve_test.go
@@ -0,0 +1,39 @@
+// 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 (
+ "bytes"
+ "encoding/hex"
+ "math/big"
+ "testing"
+)
+
+func TestReadBits(t *testing.T) {
+ check := func(input string) {
+ want, _ := hex.DecodeString(input)
+ int, _ := new(big.Int).SetString(input, 16)
+ buf := make([]byte, len(want))
+ readBits(buf, int)
+ if !bytes.Equal(buf, want) {
+ t.Errorf("have: %x\nwant: %x", buf, want)
+ }
+ }
+ check("000000000000000000000000000000000000000000000000000000FEFCF3F8F0")
+ check("0000000000012345000000000000000000000000000000000000FEFCF3F8F0")
+ check("18F8F8F1000111000110011100222004330052300000000000000000FEFCF3F8F0")
+}
diff --git a/crypto/secp256k1/pubkey_scalar_mul.h b/crypto/secp256k1/pubkey_scalar_mul.h
new file mode 100644
index 000000000..0511545ec
--- /dev/null
+++ b/crypto/secp256k1/pubkey_scalar_mul.h
@@ -0,0 +1,56 @@
+// 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/>.
+
+/** Multiply point by scalar in constant time.
+ * Returns: 1: multiplication was successful
+ * 0: scalar was invalid (zero or overflow)
+ * Args: ctx: pointer to a context object (cannot be NULL)
+ * Out: point: the multiplied point (usually secret)
+ * In: point: pointer to a 64-byte bytepublic point,
+ encoded as two 256bit big-endian numbers.
+ * scalar: a 32-byte scalar with which to multiply the point
+ */
+int secp256k1_pubkey_scalar_mul(const secp256k1_context* ctx, unsigned char *point, const unsigned char *scalar) {
+ int ret = 0;
+ int overflow = 0;
+ secp256k1_fe feX, feY;
+ secp256k1_gej res;
+ secp256k1_ge ge;
+ secp256k1_scalar s;
+ ARG_CHECK(point != NULL);
+ ARG_CHECK(scalar != NULL);
+ (void)ctx;
+
+ secp256k1_fe_set_b32(&feX, point);
+ secp256k1_fe_set_b32(&feY, point+32);
+ secp256k1_ge_set_xy(&ge, &feX, &feY);
+ secp256k1_scalar_set_b32(&s, scalar, &overflow);
+ if (overflow || secp256k1_scalar_is_zero(&s)) {
+ ret = 0;
+ } else {
+ secp256k1_ecmult_const(&res, &ge, &s);
+ secp256k1_ge_set_gej(&ge, &res);
+ /* Note: can't use secp256k1_pubkey_save here because it is not constant time. */
+ secp256k1_fe_normalize(&ge.x);
+ secp256k1_fe_normalize(&ge.y);
+ secp256k1_fe_get_b32(point, &ge.x);
+ secp256k1_fe_get_b32(point+32, &ge.y);
+ ret = 1;
+ }
+ secp256k1_scalar_clear(&s);
+ return ret;
+}
+
diff --git a/crypto/secp256k1/secp256.go b/crypto/secp256k1/secp256.go
index 41a5608a5..97b4bd8da 100644
--- a/crypto/secp256k1/secp256.go
+++ b/crypto/secp256k1/secp256.go
@@ -20,14 +20,8 @@ package secp256k1
/*
#cgo CFLAGS: -I./libsecp256k1
-#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
-#cgo freebsd LDFLAGS: -L/usr/local/lib
-#cgo linux,arm LDFLAGS: -L/usr/local/arm/lib
-#define USE_NUM_GMP
+#cgo CFLAGS: -I./libsecp256k1/src/
+#define USE_NUM_NONE
#define USE_FIELD_10X26
#define USE_FIELD_INV_BUILTIN
#define USE_SCALAR_8X32
@@ -35,6 +29,7 @@ package secp256k1
#define NDEBUG
#include "./libsecp256k1/src/secp256k1.c"
#include "./libsecp256k1/src/modules/recovery/main_impl.h"
+#include "pubkey_scalar_mul.h"
typedef void (*callbackFunc) (const char* msg, void* data);
extern void secp256k1GoPanicIllegal(const char* msg, void* data);
@@ -44,6 +39,7 @@ import "C"
import (
"errors"
+ "math/big"
"unsafe"
"github.com/ethereum/go-ethereum/crypto/randentropy"
@@ -56,13 +52,16 @@ import (
> store private keys in buffer and shuffle (deters persistance on swap disc)
> byte permutation (changing)
> xor with chaning random block (to deter scanning memory for 0x63) (stream cipher?)
- > on disk: store keys in wallets
*/
// holds ptr to secp256k1_context_struct (see secp256k1/include/secp256k1.h)
-var context *C.secp256k1_context
+var (
+ context *C.secp256k1_context
+ N *big.Int
+)
func init() {
+ N, _ = new(big.Int).SetString("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", 16)
// 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)
@@ -78,7 +77,6 @@ var (
func GenerateKeyPair() ([]byte, []byte) {
var seckey []byte = randentropy.GetEntropyCSPRNG(32)
var seckey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&seckey[0]))
-
var pubkey64 []byte = make([]byte, 64) // secp256k1_pubkey
var pubkey65 []byte = make([]byte, 65) // 65 byte uncompressed pubkey
pubkey64_ptr := (*C.secp256k1_pubkey)(unsafe.Pointer(&pubkey64[0]))
@@ -254,3 +252,16 @@ func checkSignature(sig []byte) error {
}
return nil
}
+
+// reads num into buf as big-endian bytes.
+func readBits(buf []byte, num *big.Int) {
+ const wordLen = int(unsafe.Sizeof(big.Word(0)))
+ i := len(buf)
+ for _, d := range num.Bits() {
+ for j := 0; j < wordLen && i > 0; j++ {
+ i--
+ buf[i] = byte(d)
+ d >>= 8
+ }
+ }
+}
diff --git a/crypto/secp256k1/secp256_test.go b/crypto/secp256k1/secp256_test.go
index cb71ea5e7..fc6fc9b32 100644
--- a/crypto/secp256k1/secp256_test.go
+++ b/crypto/secp256k1/secp256_test.go
@@ -24,7 +24,7 @@ import (
"github.com/ethereum/go-ethereum/crypto/randentropy"
)
-const TestCount = 10000
+const TestCount = 1000
func TestPrivkeyGenerate(t *testing.T) {
_, seckey := GenerateKeyPair()
@@ -86,10 +86,7 @@ func TestSignAndRecover(t *testing.T) {
func TestRandomMessagesWithSameKey(t *testing.T) {
pubkey, seckey := GenerateKeyPair()
keys := func() ([]byte, []byte) {
- // Sign function zeroes the privkey so we need a new one in each call
- newkey := make([]byte, len(seckey))
- copy(newkey, seckey)
- return pubkey, newkey
+ return pubkey, seckey
}
signAndRecoverWithRandomMessages(t, keys)
}
@@ -209,30 +206,32 @@ func compactSigCheck(t *testing.T, sig []byte) {
}
}
-// godep go test -v -run=XXX -bench=BenchmarkSignRandomInputEachRound
+// godep go test -v -run=XXX -bench=BenchmarkSign
// add -benchtime=10s to benchmark longer for more accurate average
-func BenchmarkSignRandomInputEachRound(b *testing.B) {
+
+// to avoid compiler optimizing the benchmarked function call
+var err error
+
+func BenchmarkSign(b *testing.B) {
for i := 0; i < b.N; i++ {
- b.StopTimer()
_, seckey := GenerateKeyPair()
msg := randentropy.GetEntropyCSPRNG(32)
b.StartTimer()
- if _, err := Sign(msg, seckey); err != nil {
- b.Fatal(err)
- }
+ _, e := Sign(msg, seckey)
+ err = e
+ b.StopTimer()
}
}
-//godep go test -v -run=XXX -bench=BenchmarkRecoverRandomInputEachRound
-func BenchmarkRecoverRandomInputEachRound(b *testing.B) {
+//godep go test -v -run=XXX -bench=BenchmarkECRec
+func BenchmarkRecover(b *testing.B) {
for i := 0; i < b.N; i++ {
- b.StopTimer()
_, seckey := GenerateKeyPair()
msg := randentropy.GetEntropyCSPRNG(32)
sig, _ := Sign(msg, seckey)
b.StartTimer()
- if _, err := RecoverPubkey(msg, sig); err != nil {
- b.Fatal(err)
- }
+ _, e := RecoverPubkey(msg, sig)
+ err = e
+ b.StopTimer()
}
}
diff --git a/p2p/discover/node.go b/p2p/discover/node.go
index a14f29424..dd19df3a2 100644
--- a/p2p/discover/node.go
+++ b/p2p/discover/node.go
@@ -210,7 +210,7 @@ func PubkeyID(pub *ecdsa.PublicKey) NodeID {
// Pubkey returns the public key represented by the node ID.
// It returns an error if the ID is not a point on the curve.
func (id NodeID) Pubkey() (*ecdsa.PublicKey, error) {
- p := &ecdsa.PublicKey{Curve: crypto.S256(), X: new(big.Int), Y: new(big.Int)}
+ p := &ecdsa.PublicKey{Curve: secp256k1.S256(), X: new(big.Int), Y: new(big.Int)}
half := len(id) / 2
p.X.SetBytes(id[:half])
p.Y.SetBytes(id[half:])
diff --git a/p2p/rlpx.go b/p2p/rlpx.go
index aaa733854..8f429d6ec 100644
--- a/p2p/rlpx.go
+++ b/p2p/rlpx.go
@@ -277,7 +277,7 @@ func newInitiatorHandshake(remoteID discover.NodeID) (*encHandshake, error) {
return nil, err
}
// generate random keypair to use for signing
- randpriv, err := ecies.GenerateKey(rand.Reader, crypto.S256(), nil)
+ randpriv, err := ecies.GenerateKey(rand.Reader, secp256k1.S256(), nil)
if err != nil {
return nil, err
}
@@ -376,7 +376,7 @@ func decodeAuthMsg(prv *ecdsa.PrivateKey, token []byte, auth []byte) (*encHandsh
var err error
h := new(encHandshake)
// generate random keypair for session
- h.randomPrivKey, err = ecies.GenerateKey(rand.Reader, crypto.S256(), nil)
+ h.randomPrivKey, err = ecies.GenerateKey(rand.Reader, secp256k1.S256(), nil)
if err != nil {
return nil, err
}
diff --git a/p2p/rlpx_test.go b/p2p/rlpx_test.go
index 900353f0e..7cc7548e2 100644
--- a/p2p/rlpx_test.go
+++ b/p2p/rlpx_test.go
@@ -93,6 +93,7 @@ func testEncHandshake(token []byte) error {
go func() {
r := result{side: "initiator"}
defer func() { output <- r }()
+ defer fd0.Close()
dest := &discover.Node{ID: discover.PubkeyID(&prv1.PublicKey)}
r.id, r.err = c0.doEncHandshake(prv0, dest)
@@ -107,6 +108,7 @@ func testEncHandshake(token []byte) error {
go func() {
r := result{side: "receiver"}
defer func() { output <- r }()
+ defer fd1.Close()
r.id, r.err = c1.doEncHandshake(prv1, nil)
if r.err != nil {
diff --git a/p2p/server.go b/p2p/server.go
index ee670b10e..7991585f1 100644
--- a/p2p/server.go
+++ b/p2p/server.go
@@ -337,7 +337,7 @@ func (srv *Server) Start() (err error) {
srv.ntab = ntab
}
- dynPeers := srv.MaxPeers / 2
+ dynPeers := (srv.MaxPeers + 1) / 2
if !srv.Discovery {
dynPeers = 0
}
diff --git a/whisper/message_test.go b/whisper/message_test.go
index 6ff95efff..d70da40a4 100644
--- a/whisper/message_test.go
+++ b/whisper/message_test.go
@@ -23,6 +23,7 @@ import (
"time"
"github.com/ethereum/go-ethereum/crypto"
+ "github.com/ethereum/go-ethereum/crypto/secp256k1"
)
// Tests whether a message can be wrapped without any identity or encryption.
@@ -72,8 +73,8 @@ func TestMessageCleartextSignRecover(t *testing.T) {
if pubKey == nil {
t.Fatalf("failed to recover public key")
}
- p1 := elliptic.Marshal(crypto.S256(), key.PublicKey.X, key.PublicKey.Y)
- p2 := elliptic.Marshal(crypto.S256(), pubKey.X, pubKey.Y)
+ p1 := elliptic.Marshal(secp256k1.S256(), key.PublicKey.X, key.PublicKey.Y)
+ p2 := elliptic.Marshal(secp256k1.S256(), pubKey.X, pubKey.Y)
if !bytes.Equal(p1, p2) {
t.Fatalf("public key mismatch: have 0x%x, want 0x%x", p2, p1)
}
@@ -150,8 +151,8 @@ func TestMessageFullCrypto(t *testing.T) {
if pubKey == nil {
t.Fatalf("failed to recover public key")
}
- p1 := elliptic.Marshal(crypto.S256(), fromKey.PublicKey.X, fromKey.PublicKey.Y)
- p2 := elliptic.Marshal(crypto.S256(), pubKey.X, pubKey.Y)
+ p1 := elliptic.Marshal(secp256k1.S256(), fromKey.PublicKey.X, fromKey.PublicKey.Y)
+ p2 := elliptic.Marshal(secp256k1.S256(), pubKey.X, pubKey.Y)
if !bytes.Equal(p1, p2) {
t.Fatalf("public key mismatch: have 0x%x, want 0x%x", p2, p1)
}