Skip to content

Commit

Permalink
crypto/bn256: full switchover to cloudflare's code (ethereum#16301)
Browse files Browse the repository at this point in the history
* crypto/bn256: full switchover to cloudflare's code

* crypto/bn256: only use cloudflare for optimized architectures

* crypto/bn256: upstream fallback for non-optimized code

* .travis, build: drop support for Go 1.8 (need type aliases)

* crypto/bn256/cloudflare: enable curve mul lattice optimization
  • Loading branch information
karalabe committed Mar 19, 2018
1 parent 0965761 commit 1203c6a
Show file tree
Hide file tree
Showing 22 changed files with 783 additions and 174 deletions.
11 changes: 0 additions & 11 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,6 @@ go_import_path: github.com/ethereum/go-ethereum
sudo: false
matrix:
include:
- os: linux
dist: trusty
sudo: required
go: 1.8.x
script:
- sudo modprobe fuse
- sudo chmod 666 /dev/fuse
- sudo chown root:$USER /etc/fuse.conf
- go run build/ci.go install
- go run build/ci.go test -coverage

- os: linux
dist: trusty
sudo: required
Expand Down
16 changes: 3 additions & 13 deletions build/ci.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down Expand Up @@ -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)
Expand Down
38 changes: 5 additions & 33 deletions crypto/bn256/bn256_other.go → crypto/bn256/bn256_fast.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 <http://www.gnu.org/licenses/>.

// +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)
}
138 changes: 138 additions & 0 deletions crypto/bn256/bn256_fuzz.go
Original file line number Diff line number Diff line change
@@ -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 <http://www.gnu.org/licenses/>.

// +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
}
38 changes: 5 additions & 33 deletions crypto/bn256/bn256_amd64.go → crypto/bn256/bn256_slow.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 <http://www.gnu.org/licenses/>.

// +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)
}
2 changes: 0 additions & 2 deletions crypto/bn256/cloudflare/bn256_test.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// +build amd64,!appengine,!gccgo

package bn256

import (
Expand Down
19 changes: 14 additions & 5 deletions crypto/bn256/cloudflare/curve.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,15 +183,24 @@ func (c *curvePoint) Double(a *curvePoint) {
}

func (c *curvePoint) Mul(a *curvePoint, scalar *big.Int) {
sum, t := &curvePoint{}, &curvePoint{}
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])

multiScalar := curveLattice.Multi(scalar)

sum := &curvePoint{}
sum.SetInfinity()
t := &curvePoint{}

for i := scalar.BitLen(); i >= 0; i-- {
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)
Expand Down
2 changes: 0 additions & 2 deletions crypto/bn256/cloudflare/example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand Down
32 changes: 0 additions & 32 deletions crypto/bn256/cloudflare/gfp.h

This file was deleted.

15 changes: 0 additions & 15 deletions crypto/bn256/cloudflare/gfp_amd64.go

This file was deleted.

Loading

0 comments on commit 1203c6a

Please sign in to comment.