diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index a7b6176552..79c7a53014 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -9,3 +9,4 @@ les/ @zsfelfoldi
light/ @zsfelfoldi
mobile/ @karalabe
p2p/ @fjl @zsfelfoldi
+whisper/ @gballet @gluk256
diff --git a/.github/no-response.yml b/.github/no-response.yml
new file mode 100644
index 0000000000..a6227159d1
--- /dev/null
+++ b/.github/no-response.yml
@@ -0,0 +1,11 @@
+# Number of days of inactivity before an Issue is closed for lack of response
+daysUntilClose: 30
+# Label requiring a response
+responseRequiredLabel: more-information-needed
+# Comment to post when closing an Issue for lack of response. Set to `false` to disable
+closeComment: >
+ This issue has been automatically closed because there has been no response
+ to our request for more information from the original author. With only the
+ information that is currently in the issue, we don't have enough information
+ to take action. Please reach out if you have or find the answers we need so
+ that we can investigate further.
diff --git a/.travis.yml b/.travis.yml
index 82cf320291..b3757ff7d9 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -17,7 +17,7 @@ matrix:
- os: linux
dist: trusty
sudo: required
- go: "1.10"
+ go: 1.9.x
script:
- sudo modprobe fuse
- sudo chmod 666 /dev/fuse
diff --git a/accounts/abi/abi_test.go b/accounts/abi/abi_test.go
index 35e0094ddd..8018df7756 100644
--- a/accounts/abi/abi_test.go
+++ b/accounts/abi/abi_test.go
@@ -621,14 +621,16 @@ func TestBareEvents(t *testing.T) {
// TestUnpackEvent is based on this contract:
// contract T {
// event received(address sender, uint amount, bytes memo);
+// event receivedAddr(address sender);
// function receive(bytes memo) external payable {
// received(msg.sender, msg.value, memo);
+// receivedAddr(msg.sender);
// }
// }
// When receive("X") is called with sender 0x00... and value 1, it produces this tx receipt:
// receipt{status=1 cgas=23949 bloom=00000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000040200000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 logs=[log: b6818c8064f645cd82d99b59a1a267d6d61117ef [75fd880d39c1daf53b6547ab6cb59451fc6452d27caa90e5b6649dd8293b9eed] 000000000000000000000000376c47978271565f56deb45495afa69e59c16ab200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000158 9ae378b6d4409eada347a5dc0c180f186cb62dc68fcc0f043425eb917335aa28 0 95d429d309bb9d753954195fe2d69bd140b4ae731b9b5b605c34323de162cf00 0]}
func TestUnpackEvent(t *testing.T) {
- const abiJSON = `[{"constant":false,"inputs":[{"name":"memo","type":"bytes"}],"name":"receive","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"memo","type":"bytes"}],"name":"received","type":"event"}]`
+ const abiJSON = `[{"constant":false,"inputs":[{"name":"memo","type":"bytes"}],"name":"receive","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"memo","type":"bytes"}],"name":"received","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"sender","type":"address"}],"name":"receivedAddr","type":"event"}]`
abi, err := JSON(strings.NewReader(abiJSON))
if err != nil {
t.Fatal(err)
@@ -656,6 +658,17 @@ func TestUnpackEvent(t *testing.T) {
} else {
t.Logf("len(data): %d; received event: %+v", len(data), ev)
}
+
+ type ReceivedAddrEvent struct {
+ Address common.Address
+ }
+ var receivedAddrEv ReceivedAddrEvent
+ err = abi.Unpack(&receivedAddrEv, "receivedAddr", data)
+ if err != nil {
+ t.Error(err)
+ } else {
+ t.Logf("len(data): %d; received event: %+v", len(data), receivedAddrEv)
+ }
}
func TestABI_MethodById(t *testing.T) {
diff --git a/accounts/abi/argument.go b/accounts/abi/argument.go
index 1b480da609..512d8fdfa7 100644
--- a/accounts/abi/argument.go
+++ b/accounts/abi/argument.go
@@ -113,16 +113,8 @@ func (arguments Arguments) unpackTuple(v interface{}, marshalledValues []interfa
}
// If the output interface is a struct, make sure names don't collide
if kind == reflect.Struct {
- exists := make(map[string]bool)
- for _, arg := range arguments {
- field := capitalise(arg.Name)
- if field == "" {
- return fmt.Errorf("abi: purely underscored output cannot unpack to struct")
- }
- if exists[field] {
- return fmt.Errorf("abi: multiple outputs mapping to the same struct field '%s'", field)
- }
- exists[field] = true
+ if err := requireUniqueStructFieldNames(arguments); err != nil {
+ return err
}
}
for i, arg := range arguments.NonIndexed() {
@@ -131,14 +123,9 @@ func (arguments Arguments) unpackTuple(v interface{}, marshalledValues []interfa
switch kind {
case reflect.Struct:
- name := capitalise(arg.Name)
- for j := 0; j < typ.NumField(); j++ {
- // TODO read tags: `abi:"fieldName"`
- if typ.Field(j).Name == name {
- if err := set(value.Field(j), reflectValue, arg); err != nil {
- return err
- }
- }
+ err := unpackStruct(value, reflectValue, arg)
+ if err != nil {
+ return err
}
case reflect.Slice, reflect.Array:
if value.Len() < i {
@@ -165,8 +152,20 @@ func (arguments Arguments) unpackAtomic(v interface{}, marshalledValues []interf
return fmt.Errorf("abi: wrong length, expected single value, got %d", len(marshalledValues))
}
elem := reflect.ValueOf(v).Elem()
+ kind := elem.Kind()
reflectValue := reflect.ValueOf(marshalledValues[0])
+
+ if kind == reflect.Struct {
+ //make sure names don't collide
+ if err := requireUniqueStructFieldNames(arguments); err != nil {
+ return err
+ }
+
+ return unpackStruct(elem, reflectValue, arguments[0])
+ }
+
return set(elem, reflectValue, arguments.NonIndexed()[0])
+
}
// Computes the full size of an array;
@@ -278,3 +277,18 @@ func capitalise(input string) string {
}
return strings.ToUpper(input[:1]) + input[1:]
}
+
+//unpackStruct extracts each argument into its corresponding struct field
+func unpackStruct(value, reflectValue reflect.Value, arg Argument) error {
+ name := capitalise(arg.Name)
+ typ := value.Type()
+ for j := 0; j < typ.NumField(); j++ {
+ // TODO read tags: `abi:"fieldName"`
+ if typ.Field(j).Name == name {
+ if err := set(value.Field(j), reflectValue, arg); err != nil {
+ return err
+ }
+ }
+ }
+ return nil
+}
diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go
index fe7dea4da1..2b5c5fc4a4 100644
--- a/accounts/abi/bind/backends/simulated.go
+++ b/accounts/abi/bind/backends/simulated.go
@@ -307,9 +307,9 @@ func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx *types.Transa
blocks, _ := core.GenerateChain(b.config, b.blockchain.CurrentBlock(), ethash.NewFaker(), b.database, 1, func(number int, block *core.BlockGen) {
for _, tx := range b.pendingBlock.Transactions() {
- block.AddTx(tx)
+ block.AddTxWithChain(b.blockchain, tx)
}
- block.AddTx(tx)
+ block.AddTxWithChain(b.blockchain, tx)
})
statedb, _ := b.blockchain.State()
diff --git a/accounts/abi/reflect.go b/accounts/abi/reflect.go
index 7a9cdacd54..2e6bf7098f 100644
--- a/accounts/abi/reflect.go
+++ b/accounts/abi/reflect.go
@@ -110,3 +110,19 @@ func requireUnpackKind(v reflect.Value, t reflect.Type, k reflect.Kind,
}
return nil
}
+
+// requireUniqueStructFieldNames makes sure field names don't collide
+func requireUniqueStructFieldNames(args Arguments) error {
+ exists := make(map[string]bool)
+ for _, arg := range args {
+ field := capitalise(arg.Name)
+ if field == "" {
+ return fmt.Errorf("abi: purely underscored output cannot unpack to struct")
+ }
+ if exists[field] {
+ return fmt.Errorf("abi: multiple outputs mapping to the same struct field '%s'", field)
+ }
+ exists[field] = true
+ }
+ return nil
+}
diff --git a/build/ci.go b/build/ci.go
index 24b58c1ae4..1881a596e9 100644
--- a/build/ci.go
+++ b/build/ci.go
@@ -182,13 +182,13 @@ func doInstall(cmdline []string) {
// Check Go version. People regularly open issues about compilation
// failure with outdated Go. This should save them the trouble.
if !strings.Contains(runtime.Version(), "devel") {
- // Figure out the minor version number since we can't textually compare (1.10 < 1.8)
+ // Figure out the minor version number since we can't textually compare (1.10 < 1.9)
var minor int
fmt.Sscanf(strings.TrimPrefix(runtime.Version(), "go1."), "%d", &minor)
- if minor < 8 {
+ if minor < 9 {
log.Println("You have Go version", runtime.Version())
- log.Println("go-ethereum requires at least Go version 1.8 and cannot")
+ log.Println("go-ethereum requires at least Go version 1.9 and cannot")
log.Println("be compiled with an earlier version. Please upgrade your Go installation.")
os.Exit(1)
}
@@ -262,16 +262,6 @@ func goTool(subcmd string, args ...string) *exec.Cmd {
func goToolArch(arch string, cc string, subcmd string, args ...string) *exec.Cmd {
cmd := build.GoTool(subcmd, args...)
- if subcmd == "build" || subcmd == "install" || subcmd == "test" {
- // Go CGO has a Windows linker error prior to 1.8 (https://github.com/golang/go/issues/8756).
- // Work around issue by allowing multiple definitions for <1.8 builds.
- var minor int
- fmt.Sscanf(strings.TrimPrefix(runtime.Version(), "go1."), "%d", &minor)
-
- if runtime.GOOS == "windows" && minor < 8 {
- cmd.Args = append(cmd.Args, []string{"-ldflags", "-extldflags -Wl,--allow-multiple-definition"}...)
- }
- }
cmd.Env = []string{"GOPATH=" + build.GOPATH()}
if arch == "" || arch == runtime.GOARCH {
cmd.Env = append(cmd.Env, "GOBIN="+GOBIN)
@@ -736,7 +726,7 @@ func doAndroidArchive(cmdline []string) {
log.Fatal("Please ensure ANDROID_NDK points to your Android NDK")
}
// Build the Android archive and Maven resources
- build.MustRun(goTool("get", "golang.org/x/mobile/cmd/gomobile"))
+ build.MustRun(goTool("get", "golang.org/x/mobile/cmd/gomobile", "golang.org/x/mobile/cmd/gobind"))
build.MustRun(gomobileTool("init", "--ndk", os.Getenv("ANDROID_NDK")))
build.MustRun(gomobileTool("bind", "--target", "android", "--javapkg", "org.ethereum", "-v", "github.com/ethereum/go-ethereum/mobile"))
@@ -787,9 +777,10 @@ func gomobileTool(subcmd string, args ...string) *exec.Cmd {
cmd.Args = append(cmd.Args, args...)
cmd.Env = []string{
"GOPATH=" + build.GOPATH(),
+ "PATH=" + GOBIN + string(os.PathListSeparator) + os.Getenv("PATH"),
}
for _, e := range os.Environ() {
- if strings.HasPrefix(e, "GOPATH=") {
+ if strings.HasPrefix(e, "GOPATH=") || strings.HasPrefix(e, "PATH=") {
continue
}
cmd.Env = append(cmd.Env, e)
@@ -856,7 +847,7 @@ func doXCodeFramework(cmdline []string) {
env := build.Env()
// Build the iOS XCode framework
- build.MustRun(goTool("get", "golang.org/x/mobile/cmd/gomobile"))
+ build.MustRun(goTool("get", "golang.org/x/mobile/cmd/gomobile", "golang.org/x/mobile/cmd/gobind"))
build.MustRun(gomobileTool("init"))
bind := gomobileTool("bind", "--target", "ios", "--tags", "ios", "-v", "github.com/ethereum/go-ethereum/mobile")
diff --git a/containers/vagrant/.gitignore b/containers/vagrant/.gitignore
deleted file mode 100644
index 8000dd9db4..0000000000
--- a/containers/vagrant/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-.vagrant
diff --git a/containers/vagrant/Vagrantfile b/containers/vagrant/Vagrantfile
deleted file mode 100644
index 72ec366e21..0000000000
--- a/containers/vagrant/Vagrantfile
+++ /dev/null
@@ -1,38 +0,0 @@
-# -*- mode: ruby -*-
-# vi: set ft=ruby :
-
-require 'yaml'
-
-VAGRANTFILE_API_VERSION = 2
-VM_RAM = 2048
-
-Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
-
- config.vm.define "ubuntu", :primary => true do |ubuntu|
- ubuntu.vm.box = "ubuntu/trusty64"
- ubuntu.vm.provision "shell", :path => "provisioners/shell/ubuntu.sh"
- end
-
- config.vm.define "debian", :primary => true do |debian|
- debian.vm.box = "debian/jessie64"
- debian.vm.provision "shell", :path => "provisioners/shell/debian.sh"
- end
-
- config.vm.define "centos", :autostart => false do |centos|
- centos.vm.box = "centos/7"
- centos.vm.provision "shell", :path => "provisioners/shell/centos.sh"
- end
-
- config.vm.provider "virtualbox" do |vb|
- vb.memory = VM_RAM
- end
-
- config.vm.provider "libvirt" do |lv|
- lv.memory = VM_RAM
-
- config.vm.synced_folder ".", "/home/vagrant/sync", :disabled => true
- end
-
- config.vm.synced_folder ".", "/vagrant", :disabled => true
- config.vm.synced_folder "../../", "/home/vagrant/go/src/github.com/ethereum/go-ethereum"
-end
diff --git a/containers/vagrant/provisioners/shell/centos.sh b/containers/vagrant/provisioners/shell/centos.sh
deleted file mode 100755
index 744da4bfd4..0000000000
--- a/containers/vagrant/provisioners/shell/centos.sh
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/bin/bash
-
-sudo yum install -y git wget
-sudo yum update -y
-
-wget --continue https://storage.googleapis.com/golang/go1.8.1.linux-amd64.tar.gz
-sudo tar -C /usr/local -xzf go1.8.1.linux-amd64.tar.gz
-
-GETH_PATH="~vagrant/go/src/github.com/ethereum/go-ethereum/build/bin/"
-
-echo "export PATH=$PATH:/usr/local/go/bin:$GETH_PATH" >> ~vagrant/.bashrc
diff --git a/containers/vagrant/provisioners/shell/debian.sh b/containers/vagrant/provisioners/shell/debian.sh
deleted file mode 100755
index 1c1793336d..0000000000
--- a/containers/vagrant/provisioners/shell/debian.sh
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/bin/bash
-
-sudo apt-get install -y build-essential git-all wget
-sudo apt-get update
-
-wget --continue https://storage.googleapis.com/golang/go1.8.1.linux-amd64.tar.gz
-sudo tar -C /usr/local -xzf go1.8.1.linux-amd64.tar.gz
-
-GETH_PATH="~vagrant/go/src/github.com/ethereum/go-ethereum/build/bin/"
-
-echo "export PATH=$PATH:/usr/local/go/bin:$GETH_PATH" >> ~vagrant/.bashrc
diff --git a/containers/vagrant/provisioners/shell/ubuntu.sh b/containers/vagrant/provisioners/shell/ubuntu.sh
deleted file mode 100755
index 1c1793336d..0000000000
--- a/containers/vagrant/provisioners/shell/ubuntu.sh
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/bin/bash
-
-sudo apt-get install -y build-essential git-all wget
-sudo apt-get update
-
-wget --continue https://storage.googleapis.com/golang/go1.8.1.linux-amd64.tar.gz
-sudo tar -C /usr/local -xzf go1.8.1.linux-amd64.tar.gz
-
-GETH_PATH="~vagrant/go/src/github.com/ethereum/go-ethereum/build/bin/"
-
-echo "export PATH=$PATH:/usr/local/go/bin:$GETH_PATH" >> ~vagrant/.bashrc
diff --git a/core/asm/compiler.go b/core/asm/compiler.go
index 318c4e4d80..1b9025a549 100644
--- a/core/asm/compiler.go
+++ b/core/asm/compiler.go
@@ -122,7 +122,7 @@ func (c *Compiler) next() token {
}
// compile line compiles a single line instruction e.g.
-// "push 1", "jump @labal".
+// "push 1", "jump @label".
func (c *Compiler) compileLine() error {
n := c.next()
if n.typ != lineStart {
diff --git a/core/asm/lexer.go b/core/asm/lexer.go
index 4054999504..4d62159e55 100644
--- a/core/asm/lexer.go
+++ b/core/asm/lexer.go
@@ -48,7 +48,7 @@ const (
lineEnd // emitted when a line ends
invalidStatement // any invalid statement
element // any element during element parsing
- label // label is emitted when a labal is found
+ label // label is emitted when a label is found
labelDef // label definition is emitted when a new label is found
number // number is emitted when a number is found
stringValue // stringValue is emitted when a string has been found
diff --git a/core/chain_makers.go b/core/chain_makers.go
index 6744428ffb..31c9e3fb77 100644
--- a/core/chain_makers.go
+++ b/core/chain_makers.go
@@ -82,11 +82,23 @@ func (b *BlockGen) SetExtra(data []byte) {
// added. Notably, contract code relying on the BLOCKHASH instruction
// will panic during execution.
func (b *BlockGen) AddTx(tx *types.Transaction) {
+ b.AddTxWithChain(nil, tx)
+}
+
+// AddTxWithChain adds a transaction to the generated block. If no coinbase has
+// been set, the block's coinbase is set to the zero address.
+//
+// AddTxWithChain panics if the transaction cannot be executed. In addition to
+// the protocol-imposed limitations (gas limit, etc.), there are some
+// further limitations on the content of transactions that can be
+// added. If contract code relies on the BLOCKHASH instruction,
+// the block in chain will be returned.
+func (b *BlockGen) AddTxWithChain(bc *BlockChain, tx *types.Transaction) {
if b.gasPool == nil {
b.SetCoinbase(common.Address{})
}
b.statedb.Prepare(tx.Hash(), common.Hash{}, len(b.txs))
- receipt, _, err := ApplyTransaction(b.config, nil, &b.header.Coinbase, b.gasPool, b.statedb, b.header, tx, &b.header.GasUsed, vm.Config{})
+ receipt, _, err := ApplyTransaction(b.config, bc, &b.header.Coinbase, b.gasPool, b.statedb, b.header, tx, &b.header.GasUsed, vm.Config{})
if err != nil {
panic(err)
}
diff --git a/crypto/bn256/bn256_other.go b/crypto/bn256/bn256_fast.go
similarity index 68%
rename from crypto/bn256/bn256_other.go
rename to crypto/bn256/bn256_fast.go
index 81977a0a81..a8dfa8f67d 100644
--- a/crypto/bn256/bn256_other.go
+++ b/crypto/bn256/bn256_fast.go
@@ -14,50 +14,22 @@
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see .
-// +build !amd64 appengine gccgo
+// +build amd64 arm64
// Package bn256 implements the Optimal Ate pairing over a 256-bit Barreto-Naehrig curve.
package bn256
-import (
- "math/big"
-
- "github.com/ethereum/go-ethereum/crypto/bn256/google"
-)
+import "github.com/ethereum/go-ethereum/crypto/bn256/cloudflare"
// G1 is an abstract cyclic group. The zero value is suitable for use as the
// output of an operation, but cannot be used as an input.
-type G1 struct {
- bn256.G1
-}
-
-// Add sets e to a+b and then returns e.
-func (e *G1) Add(a, b *G1) *G1 {
- e.G1.Add(&a.G1, &b.G1)
- return e
-}
-
-// ScalarMult sets e to a*k and then returns e.
-func (e *G1) ScalarMult(a *G1, k *big.Int) *G1 {
- e.G1.ScalarMult(&a.G1, k)
- return e
-}
+type G1 = bn256.G1
// G2 is an abstract cyclic group. The zero value is suitable for use as the
// output of an operation, but cannot be used as an input.
-type G2 struct {
- bn256.G2
-}
+type G2 = bn256.G2
// PairingCheck calculates the Optimal Ate pairing for a set of points.
func PairingCheck(a []*G1, b []*G2) bool {
- as := make([]*bn256.G1, len(a))
- for i, p := range a {
- as[i] = &p.G1
- }
- bs := make([]*bn256.G2, len(b))
- for i, p := range b {
- bs[i] = &p.G2
- }
- return bn256.PairingCheck(as, bs)
+ return bn256.PairingCheck(a, b)
}
diff --git a/crypto/bn256/bn256_fuzz.go b/crypto/bn256/bn256_fuzz.go
new file mode 100644
index 0000000000..f360b0541f
--- /dev/null
+++ b/crypto/bn256/bn256_fuzz.go
@@ -0,0 +1,138 @@
+// Copyright 2018 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 .
+
+// +build gofuzz
+
+package bn256
+
+import (
+ "bytes"
+ "math/big"
+
+ cloudflare "github.com/ethereum/go-ethereum/crypto/bn256/cloudflare"
+ google "github.com/ethereum/go-ethereum/crypto/bn256/google"
+)
+
+// FuzzAdd fuzzez bn256 addition between the Google and Cloudflare libraries.
+func FuzzAdd(data []byte) int {
+ // Ensure we have enough data in the first place
+ if len(data) != 128 {
+ return 0
+ }
+ // Ensure both libs can parse the first curve point
+ xc := new(cloudflare.G1)
+ _, errc := xc.Unmarshal(data[:64])
+
+ xg := new(google.G1)
+ _, errg := xg.Unmarshal(data[:64])
+
+ if (errc == nil) != (errg == nil) {
+ panic("parse mismatch")
+ } else if errc != nil {
+ return 0
+ }
+ // Ensure both libs can parse the second curve point
+ yc := new(cloudflare.G1)
+ _, errc = yc.Unmarshal(data[64:])
+
+ yg := new(google.G1)
+ _, errg = yg.Unmarshal(data[64:])
+
+ if (errc == nil) != (errg == nil) {
+ panic("parse mismatch")
+ } else if errc != nil {
+ return 0
+ }
+ // Add the two points and ensure they result in the same output
+ rc := new(cloudflare.G1)
+ rc.Add(xc, yc)
+
+ rg := new(google.G1)
+ rg.Add(xg, yg)
+
+ if !bytes.Equal(rc.Marshal(), rg.Marshal()) {
+ panic("add mismatch")
+ }
+ return 0
+}
+
+// FuzzMul fuzzez bn256 scalar multiplication between the Google and Cloudflare
+// libraries.
+func FuzzMul(data []byte) int {
+ // Ensure we have enough data in the first place
+ if len(data) != 96 {
+ return 0
+ }
+ // Ensure both libs can parse the curve point
+ pc := new(cloudflare.G1)
+ _, errc := pc.Unmarshal(data[:64])
+
+ pg := new(google.G1)
+ _, errg := pg.Unmarshal(data[:64])
+
+ if (errc == nil) != (errg == nil) {
+ panic("parse mismatch")
+ } else if errc != nil {
+ return 0
+ }
+ // Add the two points and ensure they result in the same output
+ rc := new(cloudflare.G1)
+ rc.ScalarMult(pc, new(big.Int).SetBytes(data[64:]))
+
+ rg := new(google.G1)
+ rg.ScalarMult(pg, new(big.Int).SetBytes(data[64:]))
+
+ if !bytes.Equal(rc.Marshal(), rg.Marshal()) {
+ panic("scalar mul mismatch")
+ }
+ return 0
+}
+
+func FuzzPair(data []byte) int {
+ // Ensure we have enough data in the first place
+ if len(data) != 192 {
+ return 0
+ }
+ // Ensure both libs can parse the curve point
+ pc := new(cloudflare.G1)
+ _, errc := pc.Unmarshal(data[:64])
+
+ pg := new(google.G1)
+ _, errg := pg.Unmarshal(data[:64])
+
+ if (errc == nil) != (errg == nil) {
+ panic("parse mismatch")
+ } else if errc != nil {
+ return 0
+ }
+ // Ensure both libs can parse the twist point
+ tc := new(cloudflare.G2)
+ _, errc = tc.Unmarshal(data[64:])
+
+ tg := new(google.G2)
+ _, errg = tg.Unmarshal(data[64:])
+
+ if (errc == nil) != (errg == nil) {
+ panic("parse mismatch")
+ } else if errc != nil {
+ return 0
+ }
+ // Pair the two points and ensure thet result in the same output
+ if cloudflare.PairingCheck([]*cloudflare.G1{pc}, []*cloudflare.G2{tc}) != google.PairingCheck([]*google.G1{pg}, []*google.G2{tg}) {
+ panic("pair mismatch")
+ }
+ return 0
+}
diff --git a/crypto/bn256/bn256_amd64.go b/crypto/bn256/bn256_slow.go
similarity index 67%
rename from crypto/bn256/bn256_amd64.go
rename to crypto/bn256/bn256_slow.go
index 35b4839c24..61373763b8 100644
--- a/crypto/bn256/bn256_amd64.go
+++ b/crypto/bn256/bn256_slow.go
@@ -14,50 +14,22 @@
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see .
-// +build amd64,!appengine,!gccgo
+// +build !amd64,!arm64
// Package bn256 implements the Optimal Ate pairing over a 256-bit Barreto-Naehrig curve.
package bn256
-import (
- "math/big"
-
- "github.com/ethereum/go-ethereum/crypto/bn256/cloudflare"
-)
+import "github.com/ethereum/go-ethereum/crypto/bn256/google"
// G1 is an abstract cyclic group. The zero value is suitable for use as the
// output of an operation, but cannot be used as an input.
-type G1 struct {
- bn256.G1
-}
-
-// Add sets e to a+b and then returns e.
-func (e *G1) Add(a, b *G1) *G1 {
- e.G1.Add(&a.G1, &b.G1)
- return e
-}
-
-// ScalarMult sets e to a*k and then returns e.
-func (e *G1) ScalarMult(a *G1, k *big.Int) *G1 {
- e.G1.ScalarMult(&a.G1, k)
- return e
-}
+type G1 = bn256.G1
// G2 is an abstract cyclic group. The zero value is suitable for use as the
// output of an operation, but cannot be used as an input.
-type G2 struct {
- bn256.G2
-}
+type G2 = bn256.G2
// PairingCheck calculates the Optimal Ate pairing for a set of points.
func PairingCheck(a []*G1, b []*G2) bool {
- as := make([]*bn256.G1, len(a))
- for i, p := range a {
- as[i] = &p.G1
- }
- bs := make([]*bn256.G2, len(b))
- for i, p := range b {
- bs[i] = &p.G2
- }
- return bn256.PairingCheck(as, bs)
+ return bn256.PairingCheck(a, b)
}
diff --git a/crypto/bn256/cloudflare/bn256_test.go b/crypto/bn256/cloudflare/bn256_test.go
index 369a3edaac..0c8016d86c 100644
--- a/crypto/bn256/cloudflare/bn256_test.go
+++ b/crypto/bn256/cloudflare/bn256_test.go
@@ -1,5 +1,3 @@
-// +build amd64,!appengine,!gccgo
-
package bn256
import (
diff --git a/crypto/bn256/cloudflare/curve.go b/crypto/bn256/cloudflare/curve.go
index b6aecc0a68..18e9b38f3f 100644
--- a/crypto/bn256/cloudflare/curve.go
+++ b/crypto/bn256/cloudflare/curve.go
@@ -183,15 +183,24 @@ func (c *curvePoint) Double(a *curvePoint) {
}
func (c *curvePoint) Mul(a *curvePoint, scalar *big.Int) {
- sum, t := &curvePoint{}, &curvePoint{}
- sum.SetInfinity()
+ precomp := [1 << 2]*curvePoint{nil, {}, {}, {}}
+ precomp[1].Set(a)
+ precomp[2].Set(a)
+ gfpMul(&precomp[2].x, &precomp[2].x, xiTo2PSquaredMinus2Over3)
+ precomp[3].Add(precomp[1], precomp[2])
- for i := scalar.BitLen(); i >= 0; i-- {
+ multiScalar := curveLattice.Multi(scalar)
+
+ sum := &curvePoint{}
+ sum.SetInfinity()
+ t := &curvePoint{}
+
+ for i := len(multiScalar) - 1; i >= 0; i-- {
t.Double(sum)
- if scalar.Bit(i) != 0 {
- sum.Add(t, a)
- } else {
+ if multiScalar[i] == 0 {
sum.Set(t)
+ } else {
+ sum.Add(t, precomp[multiScalar[i]])
}
}
c.Set(sum)
diff --git a/crypto/bn256/cloudflare/example_test.go b/crypto/bn256/cloudflare/example_test.go
index 2ee545c673..b2d19807a2 100644
--- a/crypto/bn256/cloudflare/example_test.go
+++ b/crypto/bn256/cloudflare/example_test.go
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build amd64,!appengine,!gccgo
-
package bn256
import (
diff --git a/crypto/bn256/cloudflare/gfp.h b/crypto/bn256/cloudflare/gfp.h
deleted file mode 100644
index 66f5a4d07d..0000000000
--- a/crypto/bn256/cloudflare/gfp.h
+++ /dev/null
@@ -1,32 +0,0 @@
-#define storeBlock(a0,a1,a2,a3, r) \
- MOVQ a0, 0+r \
- MOVQ a1, 8+r \
- MOVQ a2, 16+r \
- MOVQ a3, 24+r
-
-#define loadBlock(r, a0,a1,a2,a3) \
- MOVQ 0+r, a0 \
- MOVQ 8+r, a1 \
- MOVQ 16+r, a2 \
- MOVQ 24+r, a3
-
-#define gfpCarry(a0,a1,a2,a3,a4, b0,b1,b2,b3,b4) \
- \ // b = a-p
- MOVQ a0, b0 \
- MOVQ a1, b1 \
- MOVQ a2, b2 \
- MOVQ a3, b3 \
- MOVQ a4, b4 \
- \
- SUBQ ·p2+0(SB), b0 \
- SBBQ ·p2+8(SB), b1 \
- SBBQ ·p2+16(SB), b2 \
- SBBQ ·p2+24(SB), b3 \
- SBBQ $0, b4 \
- \
- \ // if b is negative then return a
- \ // else return b
- CMOVQCC b0, a0 \
- CMOVQCC b1, a1 \
- CMOVQCC b2, a2 \
- CMOVQCC b3, a3
diff --git a/crypto/bn256/cloudflare/gfp_amd64.go b/crypto/bn256/cloudflare/gfp_amd64.go
deleted file mode 100644
index ac4f1a9c62..0000000000
--- a/crypto/bn256/cloudflare/gfp_amd64.go
+++ /dev/null
@@ -1,15 +0,0 @@
-// +build amd64,!appengine,!gccgo
-
-package bn256
-
-// go:noescape
-func gfpNeg(c, a *gfP)
-
-//go:noescape
-func gfpAdd(c, a, b *gfP)
-
-//go:noescape
-func gfpSub(c, a, b *gfP)
-
-//go:noescape
-func gfpMul(c, a, b *gfP)
diff --git a/crypto/bn256/cloudflare/gfp_amd64.s b/crypto/bn256/cloudflare/gfp_amd64.s
index 2d0176f2ec..3a785d200b 100644
--- a/crypto/bn256/cloudflare/gfp_amd64.s
+++ b/crypto/bn256/cloudflare/gfp_amd64.s
@@ -1,8 +1,40 @@
-// +build amd64,!appengine,!gccgo
+// +build amd64,!generic
-#include "gfp.h"
-#include "mul.h"
-#include "mul_bmi2.h"
+#define storeBlock(a0,a1,a2,a3, r) \
+ MOVQ a0, 0+r \
+ MOVQ a1, 8+r \
+ MOVQ a2, 16+r \
+ MOVQ a3, 24+r
+
+#define loadBlock(r, a0,a1,a2,a3) \
+ MOVQ 0+r, a0 \
+ MOVQ 8+r, a1 \
+ MOVQ 16+r, a2 \
+ MOVQ 24+r, a3
+
+#define gfpCarry(a0,a1,a2,a3,a4, b0,b1,b2,b3,b4) \
+ \ // b = a-p
+ MOVQ a0, b0 \
+ MOVQ a1, b1 \
+ MOVQ a2, b2 \
+ MOVQ a3, b3 \
+ MOVQ a4, b4 \
+ \
+ SUBQ ·p2+0(SB), b0 \
+ SBBQ ·p2+8(SB), b1 \
+ SBBQ ·p2+16(SB), b2 \
+ SBBQ ·p2+24(SB), b3 \
+ SBBQ $0, b4 \
+ \
+ \ // if b is negative then return a
+ \ // else return b
+ CMOVQCC b0, a0 \
+ CMOVQCC b1, a1 \
+ CMOVQCC b2, a2 \
+ CMOVQCC b3, a3
+
+#include "mul_amd64.h"
+#include "mul_bmi2_amd64.h"
TEXT ·gfpNeg(SB),0,$0-16
MOVQ ·p2+0(SB), R8
diff --git a/crypto/bn256/cloudflare/gfp_arm64.s b/crypto/bn256/cloudflare/gfp_arm64.s
new file mode 100644
index 0000000000..c65e80168c
--- /dev/null
+++ b/crypto/bn256/cloudflare/gfp_arm64.s
@@ -0,0 +1,113 @@
+// +build arm64,!generic
+
+#define storeBlock(a0,a1,a2,a3, r) \
+ MOVD a0, 0+r \
+ MOVD a1, 8+r \
+ MOVD a2, 16+r \
+ MOVD a3, 24+r
+
+#define loadBlock(r, a0,a1,a2,a3) \
+ MOVD 0+r, a0 \
+ MOVD 8+r, a1 \
+ MOVD 16+r, a2 \
+ MOVD 24+r, a3
+
+#define loadModulus(p0,p1,p2,p3) \
+ MOVD ·p2+0(SB), p0 \
+ MOVD ·p2+8(SB), p1 \
+ MOVD ·p2+16(SB), p2 \
+ MOVD ·p2+24(SB), p3
+
+#include "mul_arm64.h"
+
+TEXT ·gfpNeg(SB),0,$0-16
+ MOVD a+8(FP), R0
+ loadBlock(0(R0), R1,R2,R3,R4)
+ loadModulus(R5,R6,R7,R8)
+
+ SUBS R1, R5, R1
+ SBCS R2, R6, R2
+ SBCS R3, R7, R3
+ SBCS R4, R8, R4
+
+ SUBS R5, R1, R5
+ SBCS R6, R2, R6
+ SBCS R7, R3, R7
+ SBCS R8, R4, R8
+
+ CSEL CS, R5, R1, R1
+ CSEL CS, R6, R2, R2
+ CSEL CS, R7, R3, R3
+ CSEL CS, R8, R4, R4
+
+ MOVD c+0(FP), R0
+ storeBlock(R1,R2,R3,R4, 0(R0))
+ RET
+
+TEXT ·gfpAdd(SB),0,$0-24
+ MOVD a+8(FP), R0
+ loadBlock(0(R0), R1,R2,R3,R4)
+ MOVD b+16(FP), R0
+ loadBlock(0(R0), R5,R6,R7,R8)
+ loadModulus(R9,R10,R11,R12)
+ MOVD ZR, R0
+
+ ADDS R5, R1
+ ADCS R6, R2
+ ADCS R7, R3
+ ADCS R8, R4
+ ADCS ZR, R0
+
+ SUBS R9, R1, R5
+ SBCS R10, R2, R6
+ SBCS R11, R3, R7
+ SBCS R12, R4, R8
+ SBCS ZR, R0, R0
+
+ CSEL CS, R5, R1, R1
+ CSEL CS, R6, R2, R2
+ CSEL CS, R7, R3, R3
+ CSEL CS, R8, R4, R4
+
+ MOVD c+0(FP), R0
+ storeBlock(R1,R2,R3,R4, 0(R0))
+ RET
+
+TEXT ·gfpSub(SB),0,$0-24
+ MOVD a+8(FP), R0
+ loadBlock(0(R0), R1,R2,R3,R4)
+ MOVD b+16(FP), R0
+ loadBlock(0(R0), R5,R6,R7,R8)
+ loadModulus(R9,R10,R11,R12)
+
+ SUBS R5, R1
+ SBCS R6, R2
+ SBCS R7, R3
+ SBCS R8, R4
+
+ CSEL CS, ZR, R9, R9
+ CSEL CS, ZR, R10, R10
+ CSEL CS, ZR, R11, R11
+ CSEL CS, ZR, R12, R12
+
+ ADDS R9, R1
+ ADCS R10, R2
+ ADCS R11, R3
+ ADCS R12, R4
+
+ MOVD c+0(FP), R0
+ storeBlock(R1,R2,R3,R4, 0(R0))
+ RET
+
+TEXT ·gfpMul(SB),0,$0-24
+ MOVD a+8(FP), R0
+ loadBlock(0(R0), R1,R2,R3,R4)
+ MOVD b+16(FP), R0
+ loadBlock(0(R0), R5,R6,R7,R8)
+
+ mul(R9,R10,R11,R12,R13,R14,R15,R16)
+ gfpReduce()
+
+ MOVD c+0(FP), R0
+ storeBlock(R1,R2,R3,R4, 0(R0))
+ RET
diff --git a/crypto/bn256/cloudflare/gfp_decl.go b/crypto/bn256/cloudflare/gfp_decl.go
new file mode 100644
index 0000000000..6a8a4fddb6
--- /dev/null
+++ b/crypto/bn256/cloudflare/gfp_decl.go
@@ -0,0 +1,18 @@
+// +build amd64,!generic arm64,!generic
+
+package bn256
+
+// This file contains forward declarations for the architecture-specific
+// assembly implementations of these functions, provided that they exist.
+
+// go:noescape
+func gfpNeg(c, a *gfP)
+
+//go:noescape
+func gfpAdd(c, a, b *gfP)
+
+//go:noescape
+func gfpSub(c, a, b *gfP)
+
+//go:noescape
+func gfpMul(c, a, b *gfP)
diff --git a/crypto/bn256/cloudflare/gfp_generic.go b/crypto/bn256/cloudflare/gfp_generic.go
new file mode 100644
index 0000000000..8e6be95961
--- /dev/null
+++ b/crypto/bn256/cloudflare/gfp_generic.go
@@ -0,0 +1,173 @@
+// +build !amd64,!arm64 generic
+
+package bn256
+
+func gfpCarry(a *gfP, head uint64) {
+ b := &gfP{}
+
+ var carry uint64
+ for i, pi := range p2 {
+ ai := a[i]
+ bi := ai - pi - carry
+ b[i] = bi
+ carry = (pi&^ai | (pi|^ai)&bi) >> 63
+ }
+ carry = carry &^ head
+
+ // If b is negative, then return a.
+ // Else return b.
+ carry = -carry
+ ncarry := ^carry
+ for i := 0; i < 4; i++ {
+ a[i] = (a[i] & carry) | (b[i] & ncarry)
+ }
+}
+
+func gfpNeg(c, a *gfP) {
+ var carry uint64
+ for i, pi := range p2 {
+ ai := a[i]
+ ci := pi - ai - carry
+ c[i] = ci
+ carry = (ai&^pi | (ai|^pi)&ci) >> 63
+ }
+ gfpCarry(c, 0)
+}
+
+func gfpAdd(c, a, b *gfP) {
+ var carry uint64
+ for i, ai := range a {
+ bi := b[i]
+ ci := ai + bi + carry
+ c[i] = ci
+ carry = (ai&bi | (ai|bi)&^ci) >> 63
+ }
+ gfpCarry(c, carry)
+}
+
+func gfpSub(c, a, b *gfP) {
+ t := &gfP{}
+
+ var carry uint64
+ for i, pi := range p2 {
+ bi := b[i]
+ ti := pi - bi - carry
+ t[i] = ti
+ carry = (bi&^pi | (bi|^pi)&ti) >> 63
+ }
+
+ carry = 0
+ for i, ai := range a {
+ ti := t[i]
+ ci := ai + ti + carry
+ c[i] = ci
+ carry = (ai&ti | (ai|ti)&^ci) >> 63
+ }
+ gfpCarry(c, carry)
+}
+
+func mul(a, b [4]uint64) [8]uint64 {
+ const (
+ mask16 uint64 = 0x0000ffff
+ mask32 uint64 = 0xffffffff
+ )
+
+ var buff [32]uint64
+ for i, ai := range a {
+ a0, a1, a2, a3 := ai&mask16, (ai>>16)&mask16, (ai>>32)&mask16, ai>>48
+
+ for j, bj := range b {
+ b0, b2 := bj&mask32, bj>>32
+
+ off := 4 * (i + j)
+ buff[off+0] += a0 * b0
+ buff[off+1] += a1 * b0
+ buff[off+2] += a2*b0 + a0*b2
+ buff[off+3] += a3*b0 + a1*b2
+ buff[off+4] += a2 * b2
+ buff[off+5] += a3 * b2
+ }
+ }
+
+ for i := uint(1); i < 4; i++ {
+ shift := 16 * i
+
+ var head, carry uint64
+ for j := uint(0); j < 8; j++ {
+ block := 4 * j
+
+ xi := buff[block]
+ yi := (buff[block+i] << shift) + head
+ zi := xi + yi + carry
+ buff[block] = zi
+ carry = (xi&yi | (xi|yi)&^zi) >> 63
+
+ head = buff[block+i] >> (64 - shift)
+ }
+ }
+
+ return [8]uint64{buff[0], buff[4], buff[8], buff[12], buff[16], buff[20], buff[24], buff[28]}
+}
+
+func halfMul(a, b [4]uint64) [4]uint64 {
+ const (
+ mask16 uint64 = 0x0000ffff
+ mask32 uint64 = 0xffffffff
+ )
+
+ var buff [18]uint64
+ for i, ai := range a {
+ a0, a1, a2, a3 := ai&mask16, (ai>>16)&mask16, (ai>>32)&mask16, ai>>48
+
+ for j, bj := range b {
+ if i+j > 3 {
+ break
+ }
+ b0, b2 := bj&mask32, bj>>32
+
+ off := 4 * (i + j)
+ buff[off+0] += a0 * b0
+ buff[off+1] += a1 * b0
+ buff[off+2] += a2*b0 + a0*b2
+ buff[off+3] += a3*b0 + a1*b2
+ buff[off+4] += a2 * b2
+ buff[off+5] += a3 * b2
+ }
+ }
+
+ for i := uint(1); i < 4; i++ {
+ shift := 16 * i
+
+ var head, carry uint64
+ for j := uint(0); j < 4; j++ {
+ block := 4 * j
+
+ xi := buff[block]
+ yi := (buff[block+i] << shift) + head
+ zi := xi + yi + carry
+ buff[block] = zi
+ carry = (xi&yi | (xi|yi)&^zi) >> 63
+
+ head = buff[block+i] >> (64 - shift)
+ }
+ }
+
+ return [4]uint64{buff[0], buff[4], buff[8], buff[12]}
+}
+
+func gfpMul(c, a, b *gfP) {
+ T := mul(*a, *b)
+ m := halfMul([4]uint64{T[0], T[1], T[2], T[3]}, np)
+ t := mul([4]uint64{m[0], m[1], m[2], m[3]}, p2)
+
+ var carry uint64
+ for i, Ti := range T {
+ ti := t[i]
+ zi := Ti + ti + carry
+ T[i] = zi
+ carry = (Ti&ti | (Ti|ti)&^zi) >> 63
+ }
+
+ *c = gfP{T[4], T[5], T[6], T[7]}
+ gfpCarry(c, carry)
+}
diff --git a/crypto/bn256/cloudflare/gfp_pure.go b/crypto/bn256/cloudflare/gfp_pure.go
deleted file mode 100644
index 8fa5d30534..0000000000
--- a/crypto/bn256/cloudflare/gfp_pure.go
+++ /dev/null
@@ -1,19 +0,0 @@
-// +build !amd64 appengine gccgo
-
-package bn256
-
-func gfpNeg(c, a *gfP) {
- panic("unsupported architecture")
-}
-
-func gfpAdd(c, a, b *gfP) {
- panic("unsupported architecture")
-}
-
-func gfpSub(c, a, b *gfP) {
- panic("unsupported architecture")
-}
-
-func gfpMul(c, a, b *gfP) {
- panic("unsupported architecture")
-}
diff --git a/crypto/bn256/cloudflare/gfp_test.go b/crypto/bn256/cloudflare/gfp_test.go
index aff5e0531f..16ab2a8410 100644
--- a/crypto/bn256/cloudflare/gfp_test.go
+++ b/crypto/bn256/cloudflare/gfp_test.go
@@ -1,5 +1,3 @@
-// +build amd64,!appengine,!gccgo
-
package bn256
import (
diff --git a/crypto/bn256/cloudflare/lattice.go b/crypto/bn256/cloudflare/lattice.go
new file mode 100644
index 0000000000..f9ace4d9fc
--- /dev/null
+++ b/crypto/bn256/cloudflare/lattice.go
@@ -0,0 +1,115 @@
+package bn256
+
+import (
+ "math/big"
+)
+
+var half = new(big.Int).Rsh(Order, 1)
+
+var curveLattice = &lattice{
+ vectors: [][]*big.Int{
+ {bigFromBase10("147946756881789319000765030803803410728"), bigFromBase10("147946756881789319010696353538189108491")},
+ {bigFromBase10("147946756881789319020627676272574806254"), bigFromBase10("-147946756881789318990833708069417712965")},
+ },
+ inverse: []*big.Int{
+ bigFromBase10("147946756881789318990833708069417712965"),
+ bigFromBase10("147946756881789319010696353538189108491"),
+ },
+ det: bigFromBase10("43776485743678550444492811490514550177096728800832068687396408373151616991234"),
+}
+
+var targetLattice = &lattice{
+ vectors: [][]*big.Int{
+ {bigFromBase10("9931322734385697761"), bigFromBase10("9931322734385697761"), bigFromBase10("9931322734385697763"), bigFromBase10("9931322734385697764")},
+ {bigFromBase10("4965661367192848881"), bigFromBase10("4965661367192848881"), bigFromBase10("4965661367192848882"), bigFromBase10("-9931322734385697762")},
+ {bigFromBase10("-9931322734385697762"), bigFromBase10("-4965661367192848881"), bigFromBase10("4965661367192848881"), bigFromBase10("-4965661367192848882")},
+ {bigFromBase10("9931322734385697763"), bigFromBase10("-4965661367192848881"), bigFromBase10("-4965661367192848881"), bigFromBase10("-4965661367192848881")},
+ },
+ inverse: []*big.Int{
+ bigFromBase10("734653495049373973658254490726798021314063399421879442165"),
+ bigFromBase10("147946756881789319000765030803803410728"),
+ bigFromBase10("-147946756881789319005730692170996259609"),
+ bigFromBase10("1469306990098747947464455738335385361643788813749140841702"),
+ },
+ det: new(big.Int).Set(Order),
+}
+
+type lattice struct {
+ vectors [][]*big.Int
+ inverse []*big.Int
+ det *big.Int
+}
+
+// decompose takes a scalar mod Order as input and finds a short, positive decomposition of it wrt to the lattice basis.
+func (l *lattice) decompose(k *big.Int) []*big.Int {
+ n := len(l.inverse)
+
+ // Calculate closest vector in lattice to with Babai's rounding.
+ c := make([]*big.Int, n)
+ for i := 0; i < n; i++ {
+ c[i] = new(big.Int).Mul(k, l.inverse[i])
+ round(c[i], l.det)
+ }
+
+ // Transform vectors according to c and subtract .
+ out := make([]*big.Int, n)
+ temp := new(big.Int)
+
+ for i := 0; i < n; i++ {
+ out[i] = new(big.Int)
+
+ for j := 0; j < n; j++ {
+ temp.Mul(c[j], l.vectors[j][i])
+ out[i].Add(out[i], temp)
+ }
+
+ out[i].Neg(out[i])
+ out[i].Add(out[i], l.vectors[0][i]).Add(out[i], l.vectors[0][i])
+ }
+ out[0].Add(out[0], k)
+
+ return out
+}
+
+func (l *lattice) Precompute(add func(i, j uint)) {
+ n := uint(len(l.vectors))
+ total := uint(1) << n
+
+ for i := uint(0); i < n; i++ {
+ for j := uint(0); j < total; j++ {
+ if (j>>i)&1 == 1 {
+ add(i, j)
+ }
+ }
+ }
+}
+
+func (l *lattice) Multi(scalar *big.Int) []uint8 {
+ decomp := l.decompose(scalar)
+
+ maxLen := 0
+ for _, x := range decomp {
+ if x.BitLen() > maxLen {
+ maxLen = x.BitLen()
+ }
+ }
+
+ out := make([]uint8, maxLen)
+ for j, x := range decomp {
+ for i := 0; i < maxLen; i++ {
+ out[i] += uint8(x.Bit(i)) << uint(j)
+ }
+ }
+
+ return out
+}
+
+// round sets num to num/denom rounded to the nearest integer.
+func round(num, denom *big.Int) {
+ r := new(big.Int)
+ num.DivMod(num, denom, r)
+
+ if r.Cmp(half) == 1 {
+ num.Add(num, big.NewInt(1))
+ }
+}
diff --git a/crypto/bn256/cloudflare/lattice_test.go b/crypto/bn256/cloudflare/lattice_test.go
new file mode 100644
index 0000000000..4d52ad9b27
--- /dev/null
+++ b/crypto/bn256/cloudflare/lattice_test.go
@@ -0,0 +1,29 @@
+package bn256
+
+import (
+ "crypto/rand"
+
+ "testing"
+)
+
+func TestLatticeReduceCurve(t *testing.T) {
+ k, _ := rand.Int(rand.Reader, Order)
+ ks := curveLattice.decompose(k)
+
+ if ks[0].BitLen() > 130 || ks[1].BitLen() > 130 {
+ t.Fatal("reduction too large")
+ } else if ks[0].Sign() < 0 || ks[1].Sign() < 0 {
+ t.Fatal("reduction must be positive")
+ }
+}
+
+func TestLatticeReduceTarget(t *testing.T) {
+ k, _ := rand.Int(rand.Reader, Order)
+ ks := targetLattice.decompose(k)
+
+ if ks[0].BitLen() > 66 || ks[1].BitLen() > 66 || ks[2].BitLen() > 66 || ks[3].BitLen() > 66 {
+ t.Fatal("reduction too large")
+ } else if ks[0].Sign() < 0 || ks[1].Sign() < 0 || ks[2].Sign() < 0 || ks[3].Sign() < 0 {
+ t.Fatal("reduction must be positive")
+ }
+}
diff --git a/crypto/bn256/cloudflare/main_test.go b/crypto/bn256/cloudflare/main_test.go
index f0d59a4041..0230f1b199 100644
--- a/crypto/bn256/cloudflare/main_test.go
+++ b/crypto/bn256/cloudflare/main_test.go
@@ -1,5 +1,3 @@
-// +build amd64,!appengine,!gccgo
-
package bn256
import (
diff --git a/crypto/bn256/cloudflare/mul.h b/crypto/bn256/cloudflare/mul_amd64.h
similarity index 100%
rename from crypto/bn256/cloudflare/mul.h
rename to crypto/bn256/cloudflare/mul_amd64.h
diff --git a/crypto/bn256/cloudflare/mul_arm64.h b/crypto/bn256/cloudflare/mul_arm64.h
new file mode 100644
index 0000000000..75d5221731
--- /dev/null
+++ b/crypto/bn256/cloudflare/mul_arm64.h
@@ -0,0 +1,133 @@
+#define mul(c0,c1,c2,c3,c4,c5,c6,c7) \
+ MUL R1, R5, c0 \
+ UMULH R1, R5, c1 \
+ MUL R1, R6, R0 \
+ ADDS R0, c1 \
+ UMULH R1, R6, c2 \
+ MUL R1, R7, R0 \
+ ADCS R0, c2 \
+ UMULH R1, R7, c3 \
+ MUL R1, R8, R0 \
+ ADCS R0, c3 \
+ UMULH R1, R8, c4 \
+ ADCS ZR, c4 \
+ \
+ MUL R2, R5, R25 \
+ UMULH R2, R5, R26 \
+ MUL R2, R6, R0 \
+ ADDS R0, R26 \
+ UMULH R2, R6, R27 \
+ MUL R2, R7, R0 \
+ ADCS R0, R27 \
+ UMULH R2, R7, R29 \
+ MUL R2, R8, R0 \
+ ADCS R0, R29 \
+ UMULH R2, R8, c5 \
+ ADCS ZR, c5 \
+ ADDS R25, c1 \
+ ADCS R26, c2 \
+ ADCS R27, c3 \
+ ADCS R29, c4 \
+ ADCS ZR, c5 \
+ \
+ MUL R3, R5, R25 \
+ UMULH R3, R5, R26 \
+ MUL R3, R6, R0 \
+ ADDS R0, R26 \
+ UMULH R3, R6, R27 \
+ MUL R3, R7, R0 \
+ ADCS R0, R27 \
+ UMULH R3, R7, R29 \
+ MUL R3, R8, R0 \
+ ADCS R0, R29 \
+ UMULH R3, R8, c6 \
+ ADCS ZR, c6 \
+ ADDS R25, c2 \
+ ADCS R26, c3 \
+ ADCS R27, c4 \
+ ADCS R29, c5 \
+ ADCS ZR, c6 \
+ \
+ MUL R4, R5, R25 \
+ UMULH R4, R5, R26 \
+ MUL R4, R6, R0 \
+ ADDS R0, R26 \
+ UMULH R4, R6, R27 \
+ MUL R4, R7, R0 \
+ ADCS R0, R27 \
+ UMULH R4, R7, R29 \
+ MUL R4, R8, R0 \
+ ADCS R0, R29 \
+ UMULH R4, R8, c7 \
+ ADCS ZR, c7 \
+ ADDS R25, c3 \
+ ADCS R26, c4 \
+ ADCS R27, c5 \
+ ADCS R29, c6 \
+ ADCS ZR, c7
+
+#define gfpReduce() \
+ \ // m = (T * N') mod R, store m in R1:R2:R3:R4
+ MOVD ·np+0(SB), R17 \
+ MOVD ·np+8(SB), R18 \
+ MOVD ·np+16(SB), R19 \
+ MOVD ·np+24(SB), R20 \
+ \
+ MUL R9, R17, R1 \
+ UMULH R9, R17, R2 \
+ MUL R9, R18, R0 \
+ ADDS R0, R2 \
+ UMULH R9, R18, R3 \
+ MUL R9, R19, R0 \
+ ADCS R0, R3 \
+ UMULH R9, R19, R4 \
+ MUL R9, R20, R0 \
+ ADCS R0, R4 \
+ \
+ MUL R10, R17, R21 \
+ UMULH R10, R17, R22 \
+ MUL R10, R18, R0 \
+ ADDS R0, R22 \
+ UMULH R10, R18, R23 \
+ MUL R10, R19, R0 \
+ ADCS R0, R23 \
+ ADDS R21, R2 \
+ ADCS R22, R3 \
+ ADCS R23, R4 \
+ \
+ MUL R11, R17, R21 \
+ UMULH R11, R17, R22 \
+ MUL R11, R18, R0 \
+ ADDS R0, R22 \
+ ADDS R21, R3 \
+ ADCS R22, R4 \
+ \
+ MUL R12, R17, R21 \
+ ADDS R21, R4 \
+ \
+ \ // m * N
+ loadModulus(R5,R6,R7,R8) \
+ mul(R17,R18,R19,R20,R21,R22,R23,R24) \
+ \
+ \ // Add the 512-bit intermediate to m*N
+ MOVD ZR, R25 \
+ ADDS R9, R17 \
+ ADCS R10, R18 \
+ ADCS R11, R19 \
+ ADCS R12, R20 \
+ ADCS R13, R21 \
+ ADCS R14, R22 \
+ ADCS R15, R23 \
+ ADCS R16, R24 \
+ ADCS ZR, R25 \
+ \
+ \ // Our output is R21:R22:R23:R24. Reduce mod p if necessary.
+ SUBS R5, R21, R10 \
+ SBCS R6, R22, R11 \
+ SBCS R7, R23, R12 \
+ SBCS R8, R24, R13 \
+ \
+ CSEL CS, R10, R21, R1 \
+ CSEL CS, R11, R22, R2 \
+ CSEL CS, R12, R23, R3 \
+ CSEL CS, R13, R24, R4
diff --git a/crypto/bn256/cloudflare/mul_bmi2.h b/crypto/bn256/cloudflare/mul_bmi2_amd64.h
similarity index 100%
rename from crypto/bn256/cloudflare/mul_bmi2.h
rename to crypto/bn256/cloudflare/mul_bmi2_amd64.h
diff --git a/miner/miner.go b/miner/miner.go
index fec0a40f5a..d9256e9787 100644
--- a/miner/miner.go
+++ b/miner/miner.go
@@ -105,8 +105,7 @@ out:
func (self *Miner) Start(coinbase common.Address) {
atomic.StoreInt32(&self.shouldStart, 1)
- self.worker.setEtherbase(coinbase)
- self.coinbase = coinbase
+ self.SetEtherbase(coinbase)
if atomic.LoadInt32(&self.canStart) == 0 {
log.Info("Network syncing, will start miner afterwards")
diff --git a/rpc/http.go b/rpc/http.go
index a46d8c2b39..9805d69b63 100644
--- a/rpc/http.go
+++ b/rpc/http.go
@@ -27,16 +27,16 @@ import (
"mime"
"net"
"net/http"
+ "strings"
"sync"
"time"
"github.com/rs/cors"
- "strings"
)
const (
- contentType = "application/json"
- maxHTTPRequestContentLength = 1024 * 128
+ contentType = "application/json"
+ maxRequestContentLength = 1024 * 128
)
var nullAddr, _ = net.ResolveTCPAddr("tcp", "127.0.0.1:0")
@@ -182,8 +182,8 @@ func validateRequest(r *http.Request) (int, error) {
if r.Method == http.MethodPut || r.Method == http.MethodDelete {
return http.StatusMethodNotAllowed, errors.New("method not allowed")
}
- if r.ContentLength > maxHTTPRequestContentLength {
- err := fmt.Errorf("content length too large (%d>%d)", r.ContentLength, maxHTTPRequestContentLength)
+ if r.ContentLength > maxRequestContentLength {
+ err := fmt.Errorf("content length too large (%d>%d)", r.ContentLength, maxRequestContentLength)
return http.StatusRequestEntityTooLarge, err
}
mt, _, err := mime.ParseMediaType(r.Header.Get("content-type"))
diff --git a/rpc/http_test.go b/rpc/http_test.go
index aed84f6835..b3f694d8af 100644
--- a/rpc/http_test.go
+++ b/rpc/http_test.go
@@ -32,7 +32,7 @@ func TestHTTPErrorResponseWithPut(t *testing.T) {
}
func TestHTTPErrorResponseWithMaxContentLength(t *testing.T) {
- body := make([]rune, maxHTTPRequestContentLength+1)
+ body := make([]rune, maxRequestContentLength+1)
testHTTPErrorResponse(t,
http.MethodPost, contentType, string(body), http.StatusRequestEntityTooLarge)
}
diff --git a/rpc/json.go b/rpc/json.go
index 2e7fd599e2..837011f51b 100644
--- a/rpc/json.go
+++ b/rpc/json.go
@@ -76,13 +76,13 @@ type jsonNotification struct {
// jsonCodec reads and writes JSON-RPC messages to the underlying connection. It
// also has support for parsing arguments and serializing (result) objects.
type jsonCodec struct {
- closer sync.Once // close closed channel once
- closed chan interface{} // closed on Close
- decMu sync.Mutex // guards d
- d *json.Decoder // decodes incoming requests
- encMu sync.Mutex // guards e
- e *json.Encoder // encodes responses
- rw io.ReadWriteCloser // connection
+ closer sync.Once // close closed channel once
+ closed chan interface{} // closed on Close
+ decMu sync.Mutex // guards the decoder
+ decode func(v interface{}) error // decoder to allow multiple transports
+ encMu sync.Mutex // guards the encoder
+ encode func(v interface{}) error // encoder to allow multiple transports
+ rw io.ReadWriteCloser // connection
}
func (err *jsonError) Error() string {
@@ -96,11 +96,29 @@ func (err *jsonError) ErrorCode() int {
return err.Code
}
-// NewJSONCodec creates a new RPC server codec with support for JSON-RPC 2.0
+// NewCodec creates a new RPC server codec with support for JSON-RPC 2.0 based
+// on explicitly given encoding and decoding methods.
+func NewCodec(rwc io.ReadWriteCloser, encode, decode func(v interface{}) error) ServerCodec {
+ return &jsonCodec{
+ closed: make(chan interface{}),
+ encode: encode,
+ decode: decode,
+ rw: rwc,
+ }
+}
+
+// NewJSONCodec creates a new RPC server codec with support for JSON-RPC 2.0.
func NewJSONCodec(rwc io.ReadWriteCloser) ServerCodec {
- d := json.NewDecoder(rwc)
- d.UseNumber()
- return &jsonCodec{closed: make(chan interface{}), d: d, e: json.NewEncoder(rwc), rw: rwc}
+ enc := json.NewEncoder(rwc)
+ dec := json.NewDecoder(rwc)
+ dec.UseNumber()
+
+ return &jsonCodec{
+ closed: make(chan interface{}),
+ encode: enc.Encode,
+ decode: dec.Decode,
+ rw: rwc,
+ }
}
// isBatch returns true when the first non-whitespace characters is '['
@@ -123,14 +141,12 @@ func (c *jsonCodec) ReadRequestHeaders() ([]rpcRequest, bool, Error) {
defer c.decMu.Unlock()
var incomingMsg json.RawMessage
- if err := c.d.Decode(&incomingMsg); err != nil {
+ if err := c.decode(&incomingMsg); err != nil {
return nil, false, &invalidRequestError{err.Error()}
}
-
if isBatch(incomingMsg) {
return parseBatchRequest(incomingMsg)
}
-
return parseRequest(incomingMsg)
}
@@ -338,7 +354,7 @@ func (c *jsonCodec) Write(res interface{}) error {
c.encMu.Lock()
defer c.encMu.Unlock()
- return c.e.Encode(res)
+ return c.encode(res)
}
// Close the underlying connection
diff --git a/rpc/websocket.go b/rpc/websocket.go
index 4214fc86a0..a6e1cec28a 100644
--- a/rpc/websocket.go
+++ b/rpc/websocket.go
@@ -17,8 +17,10 @@
package rpc
import (
+ "bytes"
"context"
"crypto/tls"
+ "encoding/json"
"fmt"
"net"
"net/http"
@@ -32,6 +34,23 @@ import (
"gopkg.in/fatih/set.v0"
)
+// websocketJSONCodec is a custom JSON codec with payload size enforcement and
+// special number parsing.
+var websocketJSONCodec = websocket.Codec{
+ // Marshal is the stock JSON marshaller used by the websocket library too.
+ Marshal: func(v interface{}) ([]byte, byte, error) {
+ msg, err := json.Marshal(v)
+ return msg, websocket.TextFrame, err
+ },
+ // Unmarshal is a specialized unmarshaller to properly convert numbers.
+ Unmarshal: func(msg []byte, payloadType byte, v interface{}) error {
+ dec := json.NewDecoder(bytes.NewReader(msg))
+ dec.UseNumber()
+
+ return dec.Decode(v)
+ },
+}
+
// WebsocketHandler returns a handler that serves JSON-RPC to WebSocket connections.
//
// allowedOrigins should be a comma-separated list of allowed origin URLs.
@@ -40,7 +59,16 @@ func (srv *Server) WebsocketHandler(allowedOrigins []string) http.Handler {
return websocket.Server{
Handshake: wsHandshakeValidator(allowedOrigins),
Handler: func(conn *websocket.Conn) {
- srv.ServeCodec(NewJSONCodec(conn), OptionMethodInvocation|OptionSubscriptions)
+ // Create a custom encode/decode pair to enforce payload size and number encoding
+ conn.MaxPayloadBytes = maxRequestContentLength
+
+ encoder := func(v interface{}) error {
+ return websocketJSONCodec.Send(conn, v)
+ }
+ decoder := func(v interface{}) error {
+ return websocketJSONCodec.Receive(conn, v)
+ }
+ srv.ServeCodec(NewCodec(conn, encoder, decoder), OptionMethodInvocation|OptionSubscriptions)
},
}
}