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) }, } }