mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-18 01:43:47 +00:00
crypto/bn256: unmarshal constraint + start pure go impl
This commit is contained in:
parent
cfe82ab087
commit
231a8e2258
7 changed files with 265 additions and 39 deletions
13
.travis.yml
13
.travis.yml
|
|
@ -26,6 +26,19 @@ matrix:
|
||||||
- go run build/ci.go install
|
- go run build/ci.go install
|
||||||
- go run build/ci.go test -coverage
|
- go run build/ci.go test -coverage
|
||||||
|
|
||||||
|
- os: linux
|
||||||
|
dist: trusty
|
||||||
|
sudo: required
|
||||||
|
go: 1.9.x
|
||||||
|
env:
|
||||||
|
- 386
|
||||||
|
script:
|
||||||
|
- sudo modprobe fuse
|
||||||
|
- sudo chmod 666 /dev/fuse
|
||||||
|
- sudo chown root:$USER /etc/fuse.conf
|
||||||
|
- GOARCH=386 go run build/ci.go install
|
||||||
|
- GOARCH=386 go run build/ci.go test -coverage
|
||||||
|
|
||||||
- os: osx
|
- os: osx
|
||||||
go: 1.9.x
|
go: 1.9.x
|
||||||
script:
|
script:
|
||||||
|
|
|
||||||
|
|
@ -120,19 +120,23 @@ func (e *G1) Marshal() []byte {
|
||||||
func (e *G1) Unmarshal(m []byte) ([]byte, error) {
|
func (e *G1) Unmarshal(m []byte) ([]byte, error) {
|
||||||
// Each value is a 256-bit number.
|
// Each value is a 256-bit number.
|
||||||
const numBytes = 256 / 8
|
const numBytes = 256 / 8
|
||||||
|
|
||||||
if len(m) < 2*numBytes {
|
if len(m) < 2*numBytes {
|
||||||
return nil, errors.New("bn256: not enough data")
|
return nil, errors.New("bn256: not enough data")
|
||||||
}
|
}
|
||||||
|
// Unmarshal the points and check their caps
|
||||||
if e.p == nil {
|
if e.p == nil {
|
||||||
e.p = &curvePoint{}
|
e.p = &curvePoint{}
|
||||||
} else {
|
} else {
|
||||||
e.p.x, e.p.y = gfP{0}, gfP{0}
|
e.p.x, e.p.y = gfP{0}, gfP{0}
|
||||||
}
|
}
|
||||||
|
var err error
|
||||||
e.p.x.Unmarshal(m)
|
if err = e.p.x.Unmarshal(m); err != nil {
|
||||||
e.p.y.Unmarshal(m[numBytes:])
|
return nil, err
|
||||||
|
}
|
||||||
|
if err = e.p.y.Unmarshal(m[numBytes:]); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Encode into Montgomery form and ensure it's on the curve
|
||||||
montEncode(&e.p.x, &e.p.x)
|
montEncode(&e.p.x, &e.p.x)
|
||||||
montEncode(&e.p.y, &e.p.y)
|
montEncode(&e.p.y, &e.p.y)
|
||||||
|
|
||||||
|
|
@ -252,19 +256,27 @@ func (e *G2) Marshal() []byte {
|
||||||
func (e *G2) Unmarshal(m []byte) ([]byte, error) {
|
func (e *G2) Unmarshal(m []byte) ([]byte, error) {
|
||||||
// Each value is a 256-bit number.
|
// Each value is a 256-bit number.
|
||||||
const numBytes = 256 / 8
|
const numBytes = 256 / 8
|
||||||
|
|
||||||
if len(m) < 4*numBytes {
|
if len(m) < 4*numBytes {
|
||||||
return nil, errors.New("bn256: not enough data")
|
return nil, errors.New("bn256: not enough data")
|
||||||
}
|
}
|
||||||
|
// Unmarshal the points and check their caps
|
||||||
if e.p == nil {
|
if e.p == nil {
|
||||||
e.p = &twistPoint{}
|
e.p = &twistPoint{}
|
||||||
}
|
}
|
||||||
|
var err error
|
||||||
e.p.x.x.Unmarshal(m)
|
if err = e.p.x.x.Unmarshal(m); err != nil {
|
||||||
e.p.x.y.Unmarshal(m[numBytes:])
|
return nil, err
|
||||||
e.p.y.x.Unmarshal(m[2*numBytes:])
|
}
|
||||||
e.p.y.y.Unmarshal(m[3*numBytes:])
|
if err = e.p.x.y.Unmarshal(m[numBytes:]); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err = e.p.y.x.Unmarshal(m[2*numBytes:]); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err = e.p.y.y.Unmarshal(m[3*numBytes:]); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Encode into Montgomery form and ensure it's on the curve
|
||||||
montEncode(&e.p.x.x, &e.p.x.x)
|
montEncode(&e.p.x.x, &e.p.x.x)
|
||||||
montEncode(&e.p.x.y, &e.p.x.y)
|
montEncode(&e.p.x.y, &e.p.x.y)
|
||||||
montEncode(&e.p.y.x, &e.p.y.x)
|
montEncode(&e.p.y.x, &e.p.y.x)
|
||||||
|
|
@ -283,7 +295,6 @@ func (e *G2) Unmarshal(m []byte) ([]byte, error) {
|
||||||
return nil, errors.New("bn256: malformed point")
|
return nil, errors.New("bn256: malformed point")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return m[4*numBytes:], nil
|
return m[4*numBytes:], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -416,18 +427,43 @@ func (e *GT) Unmarshal(m []byte) ([]byte, error) {
|
||||||
e.p = &gfP12{}
|
e.p = &gfP12{}
|
||||||
}
|
}
|
||||||
|
|
||||||
e.p.x.x.x.Unmarshal(m)
|
var err error
|
||||||
e.p.x.x.y.Unmarshal(m[numBytes:])
|
if err = e.p.x.x.x.Unmarshal(m); err != nil {
|
||||||
e.p.x.y.x.Unmarshal(m[2*numBytes:])
|
return nil, err
|
||||||
e.p.x.y.y.Unmarshal(m[3*numBytes:])
|
}
|
||||||
e.p.x.z.x.Unmarshal(m[4*numBytes:])
|
if err = e.p.x.x.y.Unmarshal(m[numBytes:]); err != nil {
|
||||||
e.p.x.z.y.Unmarshal(m[5*numBytes:])
|
return nil, err
|
||||||
e.p.y.x.x.Unmarshal(m[6*numBytes:])
|
}
|
||||||
e.p.y.x.y.Unmarshal(m[7*numBytes:])
|
if err = e.p.x.y.x.Unmarshal(m[2*numBytes:]); err != nil {
|
||||||
e.p.y.y.x.Unmarshal(m[8*numBytes:])
|
return nil, err
|
||||||
e.p.y.y.y.Unmarshal(m[9*numBytes:])
|
}
|
||||||
e.p.y.z.x.Unmarshal(m[10*numBytes:])
|
if err = e.p.x.y.y.Unmarshal(m[3*numBytes:]); err != nil {
|
||||||
e.p.y.z.y.Unmarshal(m[11*numBytes:])
|
return nil, err
|
||||||
|
}
|
||||||
|
if err = e.p.x.z.x.Unmarshal(m[4*numBytes:]); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err = e.p.x.z.y.Unmarshal(m[5*numBytes:]); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err = e.p.y.x.x.Unmarshal(m[6*numBytes:]); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err = e.p.y.x.y.Unmarshal(m[7*numBytes:]); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err = e.p.y.y.x.Unmarshal(m[8*numBytes:]); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err = e.p.y.y.y.Unmarshal(m[9*numBytes:]); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err = e.p.y.z.x.Unmarshal(m[10*numBytes:]); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err = e.p.y.z.y.Unmarshal(m[11*numBytes:]); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
montEncode(&e.p.x.x.x, &e.p.x.x.x)
|
montEncode(&e.p.x.x.x, &e.p.x.x.x)
|
||||||
montEncode(&e.p.x.x.y, &e.p.x.x.y)
|
montEncode(&e.p.x.x.y, &e.p.x.x.y)
|
||||||
montEncode(&e.p.x.y.x, &e.p.x.y.x)
|
montEncode(&e.p.x.y.x, &e.p.x.y.x)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,9 @@
|
||||||
package bn256
|
package bn256
|
||||||
|
|
||||||
import "fmt"
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
type gfP [4]uint64
|
type gfP [4]uint64
|
||||||
|
|
||||||
|
|
@ -55,25 +58,24 @@ func (e *gfP) Marshal(out []byte) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *gfP) Unmarshal(in []byte) {
|
func (e *gfP) Unmarshal(in []byte) error {
|
||||||
|
// Unmarshal the bytes into little endian form
|
||||||
for w := uint(0); w < 4; w++ {
|
for w := uint(0); w < 4; w++ {
|
||||||
for b := uint(0); b < 8; b++ {
|
for b := uint(0); b < 8; b++ {
|
||||||
e[3-w] += uint64(in[8*w+b]) << (56 - 8*b)
|
e[3-w] += uint64(in[8*w+b]) << (56 - 8*b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Ensure the point respects the curve modulus
|
||||||
|
for i := 3; i >= 0; i-- {
|
||||||
|
if e[i] < p2[i] {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if e[i] > p2[i] {
|
||||||
|
return errors.New("bn256: coordinate exceeds modulus")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return errors.New("bn256: coordinate equals modulus")
|
||||||
}
|
}
|
||||||
|
|
||||||
func montEncode(c, a *gfP) { gfpMul(c, a, r2) }
|
func montEncode(c, a *gfP) { gfpMul(c, a, r2) }
|
||||||
func montDecode(c, a *gfP) { gfpMul(c, a, &gfP{1}) }
|
func montDecode(c, a *gfP) { gfpMul(c, a, &gfP{1}) }
|
||||||
|
|
||||||
// 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)
|
|
||||||
|
|
|
||||||
15
crypto/bn256/gfp_amd64.go
Normal file
15
crypto/bn256/gfp_amd64.go
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
// +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)
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
// +build amd64,!appengine,!gccgo
|
||||||
|
|
||||||
#include "gfp.h"
|
#include "gfp.h"
|
||||||
#include "mul.h"
|
#include "mul.h"
|
||||||
#include "mul_bmi2.h"
|
#include "mul_bmi2.h"
|
||||||
98
crypto/bn256/gfp_pure.go
Normal file
98
crypto/bn256/gfp_pure.go
Normal file
|
|
@ -0,0 +1,98 @@
|
||||||
|
// +build !amd64 appengine gccgo
|
||||||
|
|
||||||
|
package bn256
|
||||||
|
|
||||||
|
func gfpNeg(c, a *gfP) {
|
||||||
|
// c = p - a
|
||||||
|
c[0] = p2[0] - a[0]
|
||||||
|
c[1] = p2[1] - a[1]
|
||||||
|
if p2[0] < a[0] {
|
||||||
|
c[1]--
|
||||||
|
}
|
||||||
|
c[2] = p2[2] - a[2]
|
||||||
|
if p2[1] < a[1] {
|
||||||
|
c[2]--
|
||||||
|
}
|
||||||
|
c[3] = p2[3] - a[3]
|
||||||
|
if p2[2] < a[2] {
|
||||||
|
c[3]--
|
||||||
|
}
|
||||||
|
// c < p ? c : c-p
|
||||||
|
gfpCarry(c, p2[3] < a[3])
|
||||||
|
}
|
||||||
|
|
||||||
|
func gfpAdd(c, a, b *gfP) {
|
||||||
|
// c = a + b
|
||||||
|
c[0] = a[0] + b[0]
|
||||||
|
c[1] = a[1] + b[1]
|
||||||
|
if c[0] < a[0] {
|
||||||
|
c[1]++
|
||||||
|
}
|
||||||
|
c[2] = a[2] + b[2]
|
||||||
|
if c[1] < a[1] {
|
||||||
|
c[2]++
|
||||||
|
}
|
||||||
|
c[3] = a[3] + b[3]
|
||||||
|
if c[2] < a[2] {
|
||||||
|
c[3]++
|
||||||
|
}
|
||||||
|
// c < p ? c : c-p
|
||||||
|
gfpCarry(c, c[3] < a[3])
|
||||||
|
}
|
||||||
|
|
||||||
|
func gfpSub(c, a, b *gfP) {
|
||||||
|
// c = a - b
|
||||||
|
c[0] = a[0] - b[0]
|
||||||
|
c[1] = a[1] - b[1]
|
||||||
|
if c[0] > a[0] {
|
||||||
|
c[1]--
|
||||||
|
}
|
||||||
|
c[2] = a[2] - b[2]
|
||||||
|
if c[1] > a[1] {
|
||||||
|
c[2]--
|
||||||
|
}
|
||||||
|
c[3] = a[3] - b[3]
|
||||||
|
if c[2] > a[2] {
|
||||||
|
c[3]--
|
||||||
|
}
|
||||||
|
// c < p ? c : c-p
|
||||||
|
gfpCarry(c, c[3] < a[3])
|
||||||
|
}
|
||||||
|
|
||||||
|
func gfpMul(c, a, b *gfP) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func gfpCarry(c *gfP, carry bool) {
|
||||||
|
if c[3] < p2[3] {
|
||||||
|
return
|
||||||
|
} else if c[3] == p2[3] {
|
||||||
|
if c[2] < p2[3] {
|
||||||
|
return
|
||||||
|
} else if c[2] == p2[2] {
|
||||||
|
if c[1] < p2[1] {
|
||||||
|
return
|
||||||
|
} else if c[1] == p2[1] {
|
||||||
|
if c[0] < p2[0] {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if c[0] < p2[0] {
|
||||||
|
c[1]--
|
||||||
|
}
|
||||||
|
c[0] -= p2[0]
|
||||||
|
|
||||||
|
if c[1] < p2[1] {
|
||||||
|
c[2]--
|
||||||
|
}
|
||||||
|
c[1] -= p2[1]
|
||||||
|
|
||||||
|
if c[2] < p2[2] {
|
||||||
|
c[3]--
|
||||||
|
}
|
||||||
|
c[2] -= p2[2]
|
||||||
|
|
||||||
|
c[3] -= p2[3]
|
||||||
|
}
|
||||||
60
crypto/bn256/gfp_test.go
Normal file
60
crypto/bn256/gfp_test.go
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
package bn256
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Tests that negation works the same way on both assembly-optimized and pure Go
|
||||||
|
// implementation.
|
||||||
|
func TestGFpNeg(t *testing.T) {
|
||||||
|
n := &gfP{0x0123456789abcdef, 0xfedcba9876543210, 0xdeadbeefdeadbeef, 0xfeebdaedfeebdaed}
|
||||||
|
w := &gfP{0xfedcba9876543211, 0x0123456789abcdef, 0x2152411021524110, 0x0114251201142512}
|
||||||
|
h := &gfP{}
|
||||||
|
|
||||||
|
gfpNeg(h, n)
|
||||||
|
if *h != *w {
|
||||||
|
t.Errorf("negation mismatch: have %#x, want %#x", *h, *w)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tests that addition works the same way on both assembly-optimized and pure Go
|
||||||
|
// implementation.
|
||||||
|
func TestGFpAdd(t *testing.T) {
|
||||||
|
a := &gfP{0x0123456789abcdef, 0xfedcba9876543210, 0xdeadbeefdeadbeef, 0xfeebdaedfeebdaed}
|
||||||
|
b := &gfP{0xfedcba9876543210, 0x0123456789abcdef, 0xfeebdaedfeebdaed, 0xdeadbeefdeadbeef}
|
||||||
|
w := &gfP{0xc3df73e9278302b8, 0x687e956e978e3572, 0x254954275c18417f, 0xad354b6afc67f9b4}
|
||||||
|
h := &gfP{}
|
||||||
|
|
||||||
|
gfpAdd(h, a, b)
|
||||||
|
if *h != *w {
|
||||||
|
t.Errorf("addition mismatch: have %#x, want %#x", *h, *w)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tests that subtraction works the same way on both assembly-optimized and pure Go
|
||||||
|
// implementation.
|
||||||
|
func TestGFpSub(t *testing.T) {
|
||||||
|
a := &gfP{0x0123456789abcdef, 0xfedcba9876543210, 0xdeadbeefdeadbeef, 0xfeebdaedfeebdaed}
|
||||||
|
b := &gfP{0xfedcba9876543210, 0x0123456789abcdef, 0xfeebdaedfeebdaed, 0xdeadbeefdeadbeef}
|
||||||
|
w := &gfP{0x02468acf13579bdf, 0xfdb97530eca86420, 0xdfc1e401dfc1e402, 0x203e1bfe203e1bfd}
|
||||||
|
h := &gfP{}
|
||||||
|
|
||||||
|
gfpSub(h, a, b)
|
||||||
|
if *h != *w {
|
||||||
|
t.Errorf("subtraction mismatch: have %#x, want %#x", *h, *w)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tests that multiplication works the same way on both assembly-optimized and pure Go
|
||||||
|
// implementation.
|
||||||
|
func TestGFpMul(t *testing.T) {
|
||||||
|
a := &gfP{0x0123456789abcdef, 0xfedcba9876543210, 0xdeadbeefdeadbeef, 0xfeebdaedfeebdaed}
|
||||||
|
b := &gfP{0xfedcba9876543210, 0x0123456789abcdef, 0xfeebdaedfeebdaed, 0xdeadbeefdeadbeef}
|
||||||
|
w := &gfP{0xcbcbd377f7ad22d3, 0x3b89ba5d849379bf, 0x87b61627bd38b6d2, 0xc44052a2a0e654b2}
|
||||||
|
h := &gfP{}
|
||||||
|
|
||||||
|
gfpMul(h, a, b)
|
||||||
|
if *h != *w {
|
||||||
|
t.Errorf("multiplication mismatch: have %#x, want %#x", *h, *w)
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue