crypto/bn256: unmarshal constraint + start pure go impl

This commit is contained in:
Péter Szilágyi 2018-03-01 12:31:01 +02:00
parent cfe82ab087
commit 231a8e2258
No known key found for this signature in database
GPG key ID: E9AE538CEDF8293D
7 changed files with 265 additions and 39 deletions

View file

@ -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:

View file

@ -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)

View file

@ -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
View 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)

View file

@ -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
View 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
View 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)
}
}