core/vm, crypto/bn256: switch over to cloudflare library

This commit is contained in:
Péter Szilágyi 2018-02-26 15:20:15 +02:00
parent 5a150e1b77
commit cfe82ab087
No known key found for this signature in database
GPG key ID: E9AE538CEDF8293D
15 changed files with 1397 additions and 1493 deletions

View file

@ -251,26 +251,12 @@ func (c *bigModExp) Run(input []byte) ([]byte, error) {
return common.LeftPadBytes(base.Exp(base, exp, mod).Bytes(), int(modLen)), nil return common.LeftPadBytes(base.Exp(base, exp, mod).Bytes(), int(modLen)), nil
} }
var (
// errNotOnCurve is returned if a point being unmarshalled as a bn256 elliptic
// curve point is not on the curve.
errNotOnCurve = errors.New("point not on elliptic curve")
// errInvalidCurvePoint is returned if a point being unmarshalled as a bn256
// elliptic curve point is invalid.
errInvalidCurvePoint = errors.New("invalid elliptic curve point")
)
// newCurvePoint unmarshals a binary blob into a bn256 elliptic curve point, // newCurvePoint unmarshals a binary blob into a bn256 elliptic curve point,
// returning it, or an error if the point is invalid. // returning it, or an error if the point is invalid.
func newCurvePoint(blob []byte) (*bn256.G1, error) { func newCurvePoint(blob []byte) (*bn256.G1, error) {
p, onCurve := new(bn256.G1).Unmarshal(blob) p := new(bn256.G1)
if !onCurve { if _, err := p.Unmarshal(blob); err != nil {
return nil, errNotOnCurve return nil, err
}
gx, gy, _, _ := p.CurvePoints()
if gx.Cmp(bn256.P) >= 0 || gy.Cmp(bn256.P) >= 0 {
return nil, errInvalidCurvePoint
} }
return p, nil return p, nil
} }
@ -278,14 +264,9 @@ func newCurvePoint(blob []byte) (*bn256.G1, error) {
// newTwistPoint unmarshals a binary blob into a bn256 elliptic curve point, // newTwistPoint unmarshals a binary blob into a bn256 elliptic curve point,
// returning it, or an error if the point is invalid. // returning it, or an error if the point is invalid.
func newTwistPoint(blob []byte) (*bn256.G2, error) { func newTwistPoint(blob []byte) (*bn256.G2, error) {
p, onCurve := new(bn256.G2).Unmarshal(blob) p := new(bn256.G2)
if !onCurve { if _, err := p.Unmarshal(blob); err != nil {
return nil, errNotOnCurve return nil, err
}
x2, y2, _, _ := p.CurvePoints()
if x2.Real().Cmp(bn256.P) >= 0 || x2.Imag().Cmp(bn256.P) >= 0 ||
y2.Real().Cmp(bn256.P) >= 0 || y2.Imag().Cmp(bn256.P) >= 0 {
return nil, errInvalidCurvePoint
} }
return p, nil return p, nil
} }

View file

@ -1,14 +1,11 @@
// Copyright 2012 The Go Authors. All rights reserved. // Package bn256 implements a particular bilinear group at the 128-bit security
// Use of this source code is governed by a BSD-style // level.
// license that can be found in the LICENSE file.
// Package bn256 implements a particular bilinear group at the 128-bit security level.
// //
// Bilinear groups are the basis of many of the new cryptographic protocols // Bilinear groups are the basis of many of the new cryptographic protocols that
// that have been proposed over the past decade. They consist of a triplet of // have been proposed over the past decade. They consist of a triplet of groups
// groups (G₁, G₂ and GT) such that there exists a function e(g₁ˣ,g₂ʸ)=gTˣʸ // (G₁, G₂ and GT) such that there exists a function e(g₁ˣ,g₂ʸ)=gTˣʸ (where gₓ
// (where gₓ is a generator of the respective group). That function is called // is a generator of the respective group). That function is called a pairing
// a pairing function. // function.
// //
// This package specifically implements the Optimal Ate pairing over a 256-bit // This package specifically implements the Optimal Ate pairing over a 256-bit
// Barreto-Naehrig curve as described in // Barreto-Naehrig curve as described in
@ -18,12 +15,19 @@ package bn256
import ( import (
"crypto/rand" "crypto/rand"
"errors"
"io" "io"
"math/big" "math/big"
) )
// BUG(agl): this implementation is not constant time. func randomK(r io.Reader) (k *big.Int, err error) {
// TODO(agl): keep GF(p²) elements in Mongomery form. for {
k, err = rand.Int(r, Order)
if k.Sign() > 0 || err != nil {
return
}
}
}
// G1 is an abstract cyclic group. The zero value is suitable for use as the // 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. // output of an operation, but cannot be used as an input.
@ -33,18 +37,10 @@ type G1 struct {
// RandomG1 returns x and g₁ˣ where x is a random, non-zero number read from r. // RandomG1 returns x and g₁ˣ where x is a random, non-zero number read from r.
func RandomG1(r io.Reader) (*big.Int, *G1, error) { func RandomG1(r io.Reader) (*big.Int, *G1, error) {
var k *big.Int k, err := randomK(r)
var err error
for {
k, err = rand.Int(r, Order)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
if k.Sign() > 0 {
break
}
}
return k, new(G1).ScalarBaseMult(k), nil return k, new(G1).ScalarBaseMult(k), nil
} }
@ -53,98 +49,108 @@ func (g *G1) String() string {
return "bn256.G1" + g.p.String() return "bn256.G1" + g.p.String()
} }
// CurvePoints returns p's curve points in big integer // ScalarBaseMult sets e to g*k where g is the generator of the group and then
func (e *G1) CurvePoints() (*big.Int, *big.Int, *big.Int, *big.Int) { // returns e.
return e.p.x, e.p.y, e.p.z, e.p.t
}
// ScalarBaseMult sets e to g*k where g is the generator of the group and
// then returns e.
func (e *G1) ScalarBaseMult(k *big.Int) *G1 { func (e *G1) ScalarBaseMult(k *big.Int) *G1 {
if e.p == nil { if e.p == nil {
e.p = newCurvePoint(nil) e.p = &curvePoint{}
} }
e.p.Mul(curveGen, k, new(bnPool)) e.p.Mul(curveGen, k)
return e return e
} }
// ScalarMult sets e to a*k and then returns e. // ScalarMult sets e to a*k and then returns e.
func (e *G1) ScalarMult(a *G1, k *big.Int) *G1 { func (e *G1) ScalarMult(a *G1, k *big.Int) *G1 {
if e.p == nil { if e.p == nil {
e.p = newCurvePoint(nil) e.p = &curvePoint{}
} }
e.p.Mul(a.p, k, new(bnPool)) e.p.Mul(a.p, k)
return e return e
} }
// Add sets e to a+b and then returns e. // Add sets e to a+b and then returns e.
// BUG(agl): this function is not complete: a==b fails.
func (e *G1) Add(a, b *G1) *G1 { func (e *G1) Add(a, b *G1) *G1 {
if e.p == nil { if e.p == nil {
e.p = newCurvePoint(nil) e.p = &curvePoint{}
} }
e.p.Add(a.p, b.p, new(bnPool)) e.p.Add(a.p, b.p)
return e return e
} }
// Neg sets e to -a and then returns e. // Neg sets e to -a and then returns e.
func (e *G1) Neg(a *G1) *G1 { func (e *G1) Neg(a *G1) *G1 {
if e.p == nil { if e.p == nil {
e.p = newCurvePoint(nil) e.p = &curvePoint{}
} }
e.p.Negative(a.p) e.p.Neg(a.p)
return e return e
} }
// Marshal converts n to a byte slice. // Set sets e to a and then returns e.
func (n *G1) Marshal() []byte { func (e *G1) Set(a *G1) *G1 {
n.p.MakeAffine(nil) if e.p == nil {
e.p = &curvePoint{}
xBytes := new(big.Int).Mod(n.p.x, P).Bytes() }
yBytes := new(big.Int).Mod(n.p.y, P).Bytes() e.p.Set(a.p)
return e
}
// Marshal converts e to a byte slice.
func (e *G1) Marshal() []byte {
// Each value is a 256-bit number. // Each value is a 256-bit number.
const numBytes = 256 / 8 const numBytes = 256 / 8
e.p.MakeAffine()
ret := make([]byte, numBytes*2) ret := make([]byte, numBytes*2)
copy(ret[1*numBytes-len(xBytes):], xBytes) if e.p.IsInfinity() {
copy(ret[2*numBytes-len(yBytes):], yBytes) return ret
}
temp := &gfP{}
montDecode(temp, &e.p.x)
temp.Marshal(ret)
montDecode(temp, &e.p.y)
temp.Marshal(ret[numBytes:])
return ret return ret
} }
// Unmarshal sets e to the result of converting the output of Marshal back into // Unmarshal sets e to the result of converting the output of Marshal back into
// a group element and then returns e. // a group element and then returns e.
func (e *G1) Unmarshal(m []byte) (*G1, bool) { 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, false return nil, errors.New("bn256: not enough data")
} }
if e.p == nil { if e.p == nil {
e.p = newCurvePoint(nil) e.p = &curvePoint{}
} else {
e.p.x, e.p.y = gfP{0}, gfP{0}
} }
e.p.x.SetBytes(m[0*numBytes : 1*numBytes]) e.p.x.Unmarshal(m)
e.p.y.SetBytes(m[1*numBytes : 2*numBytes]) e.p.y.Unmarshal(m[numBytes:])
montEncode(&e.p.x, &e.p.x)
montEncode(&e.p.y, &e.p.y)
if e.p.x.Sign() == 0 && e.p.y.Sign() == 0 { zero := gfP{0}
if e.p.x == zero && e.p.y == zero {
// This is the point at infinity. // This is the point at infinity.
e.p.y.SetInt64(1) e.p.y = *newGFp(1)
e.p.z.SetInt64(0) e.p.z = gfP{0}
e.p.t.SetInt64(0) e.p.t = gfP{0}
} else { } else {
e.p.z.SetInt64(1) e.p.z = *newGFp(1)
e.p.t.SetInt64(1) e.p.t = *newGFp(1)
if !e.p.IsOnCurve() { if !e.p.IsOnCurve() {
return nil, false return nil, errors.New("bn256: malformed point")
} }
} }
return m[2*numBytes:], nil
return e, true
} }
// G2 is an abstract cyclic group. The zero value is suitable for use as the // G2 is an abstract cyclic group. The zero value is suitable for use as the
@ -153,107 +159,118 @@ type G2 struct {
p *twistPoint p *twistPoint
} }
// RandomG1 returns x and g₂ˣ where x is a random, non-zero number read from r. // RandomG2 returns x and g₂ˣ where x is a random, non-zero number read from r.
func RandomG2(r io.Reader) (*big.Int, *G2, error) { func RandomG2(r io.Reader) (*big.Int, *G2, error) {
var k *big.Int k, err := randomK(r)
var err error
for {
k, err = rand.Int(r, Order)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
if k.Sign() > 0 {
break
}
}
return k, new(G2).ScalarBaseMult(k), nil return k, new(G2).ScalarBaseMult(k), nil
} }
func (g *G2) String() string { func (e *G2) String() string {
return "bn256.G2" + g.p.String() return "bn256.G2" + e.p.String()
} }
// CurvePoints returns the curve points of p which includes the real // ScalarBaseMult sets e to g*k where g is the generator of the group and then
// and imaginary parts of the curve point. // returns out.
func (e *G2) CurvePoints() (*gfP2, *gfP2, *gfP2, *gfP2) {
return e.p.x, e.p.y, e.p.z, e.p.t
}
// ScalarBaseMult sets e to g*k where g is the generator of the group and
// then returns out.
func (e *G2) ScalarBaseMult(k *big.Int) *G2 { func (e *G2) ScalarBaseMult(k *big.Int) *G2 {
if e.p == nil { if e.p == nil {
e.p = newTwistPoint(nil) e.p = &twistPoint{}
} }
e.p.Mul(twistGen, k, new(bnPool)) e.p.Mul(twistGen, k)
return e return e
} }
// ScalarMult sets e to a*k and then returns e. // ScalarMult sets e to a*k and then returns e.
func (e *G2) ScalarMult(a *G2, k *big.Int) *G2 { func (e *G2) ScalarMult(a *G2, k *big.Int) *G2 {
if e.p == nil { if e.p == nil {
e.p = newTwistPoint(nil) e.p = &twistPoint{}
} }
e.p.Mul(a.p, k, new(bnPool)) e.p.Mul(a.p, k)
return e return e
} }
// Add sets e to a+b and then returns e. // Add sets e to a+b and then returns e.
// BUG(agl): this function is not complete: a==b fails.
func (e *G2) Add(a, b *G2) *G2 { func (e *G2) Add(a, b *G2) *G2 {
if e.p == nil { if e.p == nil {
e.p = newTwistPoint(nil) e.p = &twistPoint{}
} }
e.p.Add(a.p, b.p, new(bnPool)) e.p.Add(a.p, b.p)
return e return e
} }
// Marshal converts n into a byte slice. // Neg sets e to -a and then returns e.
func (n *G2) Marshal() []byte { func (e *G2) Neg(a *G2) *G2 {
n.p.MakeAffine(nil) if e.p == nil {
e.p = &twistPoint{}
}
e.p.Neg(a.p)
return e
}
xxBytes := new(big.Int).Mod(n.p.x.x, P).Bytes() // Set sets e to a and then returns e.
xyBytes := new(big.Int).Mod(n.p.x.y, P).Bytes() func (e *G2) Set(a *G2) *G2 {
yxBytes := new(big.Int).Mod(n.p.y.x, P).Bytes() if e.p == nil {
yyBytes := new(big.Int).Mod(n.p.y.y, P).Bytes() e.p = &twistPoint{}
}
e.p.Set(a.p)
return e
}
// Marshal converts e into a byte slice.
func (e *G2) Marshal() []byte {
// Each value is a 256-bit number. // Each value is a 256-bit number.
const numBytes = 256 / 8 const numBytes = 256 / 8
if e.p == nil {
e.p = &twistPoint{}
}
e.p.MakeAffine()
ret := make([]byte, numBytes*4) ret := make([]byte, numBytes*4)
copy(ret[1*numBytes-len(xxBytes):], xxBytes) if e.p.IsInfinity() {
copy(ret[2*numBytes-len(xyBytes):], xyBytes) return ret
copy(ret[3*numBytes-len(yxBytes):], yxBytes) }
copy(ret[4*numBytes-len(yyBytes):], yyBytes) temp := &gfP{}
montDecode(temp, &e.p.x.x)
temp.Marshal(ret)
montDecode(temp, &e.p.x.y)
temp.Marshal(ret[numBytes:])
montDecode(temp, &e.p.y.x)
temp.Marshal(ret[2*numBytes:])
montDecode(temp, &e.p.y.y)
temp.Marshal(ret[3*numBytes:])
return ret return ret
} }
// Unmarshal sets e to the result of converting the output of Marshal back into // Unmarshal sets e to the result of converting the output of Marshal back into
// a group element and then returns e. // a group element and then returns e.
func (e *G2) Unmarshal(m []byte) (*G2, bool) { 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, false return nil, errors.New("bn256: not enough data")
} }
if e.p == nil { if e.p == nil {
e.p = newTwistPoint(nil) e.p = &twistPoint{}
} }
e.p.x.x.SetBytes(m[0*numBytes : 1*numBytes]) e.p.x.x.Unmarshal(m)
e.p.x.y.SetBytes(m[1*numBytes : 2*numBytes]) e.p.x.y.Unmarshal(m[numBytes:])
e.p.y.x.SetBytes(m[2*numBytes : 3*numBytes]) e.p.y.x.Unmarshal(m[2*numBytes:])
e.p.y.y.SetBytes(m[3*numBytes : 4*numBytes]) e.p.y.y.Unmarshal(m[3*numBytes:])
montEncode(&e.p.x.x, &e.p.x.x)
montEncode(&e.p.x.y, &e.p.x.y)
montEncode(&e.p.y.x, &e.p.y.x)
montEncode(&e.p.y.y, &e.p.y.y)
if e.p.x.x.Sign() == 0 && if e.p.x.IsZero() && e.p.y.IsZero() {
e.p.x.y.Sign() == 0 &&
e.p.y.x.Sign() == 0 &&
e.p.y.y.Sign() == 0 {
// This is the point at infinity. // This is the point at infinity.
e.p.y.SetOne() e.p.y.SetOne()
e.p.z.SetZero() e.p.z.SetZero()
@ -263,11 +280,11 @@ func (e *G2) Unmarshal(m []byte) (*G2, bool) {
e.p.t.SetOne() e.p.t.SetOne()
if !e.p.IsOnCurve() { if !e.p.IsOnCurve() {
return nil, false return nil, errors.New("bn256: malformed point")
} }
} }
return e, true return m[4*numBytes:], nil
} }
// GT is an abstract cyclic group. The zero value is suitable for use as the // GT is an abstract cyclic group. The zero value is suitable for use as the
@ -276,6 +293,32 @@ type GT struct {
p *gfP12 p *gfP12
} }
// Pair calculates an Optimal Ate pairing.
func Pair(g1 *G1, g2 *G2) *GT {
return &GT{optimalAte(g2.p, g1.p)}
}
// PairingCheck calculates the Optimal Ate pairing for a set of points.
func PairingCheck(a []*G1, b []*G2) bool {
acc := new(gfP12)
acc.SetOne()
for i := 0; i < len(a); i++ {
if a[i].p.IsInfinity() || b[i].p.IsInfinity() {
continue
}
acc.Mul(acc, miller(b[i].p, a[i].p))
}
return finalExponentiation(acc).IsOne()
}
// Miller applies Miller's algorithm, which is a bilinear function from the
// source groups to F_p^12. Miller(g1, g2).Finalize() is equivalent to Pair(g1,
// g2).
func Miller(g1 *G1, g2 *G2) *GT {
return &GT{miller(g2.p, g1.p)}
}
func (g *GT) String() string { func (g *GT) String() string {
return "bn256.GT" + g.p.String() return "bn256.GT" + g.p.String()
} }
@ -283,152 +326,120 @@ func (g *GT) String() string {
// ScalarMult sets e to a*k and then returns e. // ScalarMult sets e to a*k and then returns e.
func (e *GT) ScalarMult(a *GT, k *big.Int) *GT { func (e *GT) ScalarMult(a *GT, k *big.Int) *GT {
if e.p == nil { if e.p == nil {
e.p = newGFp12(nil) e.p = &gfP12{}
} }
e.p.Exp(a.p, k, new(bnPool)) e.p.Exp(a.p, k)
return e return e
} }
// Add sets e to a+b and then returns e. // Add sets e to a+b and then returns e.
func (e *GT) Add(a, b *GT) *GT { func (e *GT) Add(a, b *GT) *GT {
if e.p == nil { if e.p == nil {
e.p = newGFp12(nil) e.p = &gfP12{}
} }
e.p.Mul(a.p, b.p, new(bnPool)) e.p.Mul(a.p, b.p)
return e return e
} }
// Neg sets e to -a and then returns e. // Neg sets e to -a and then returns e.
func (e *GT) Neg(a *GT) *GT { func (e *GT) Neg(a *GT) *GT {
if e.p == nil { if e.p == nil {
e.p = newGFp12(nil) e.p = &gfP12{}
} }
e.p.Invert(a.p, new(bnPool)) e.p.Conjugate(a.p)
return e return e
} }
// Marshal converts n into a byte slice. // Set sets e to a and then returns e.
func (n *GT) Marshal() []byte { func (e *GT) Set(a *GT) *GT {
n.p.Minimal() if e.p == nil {
e.p = &gfP12{}
}
e.p.Set(a.p)
return e
}
xxxBytes := n.p.x.x.x.Bytes() // Finalize is a linear function from F_p^12 to GT.
xxyBytes := n.p.x.x.y.Bytes() func (e *GT) Finalize() *GT {
xyxBytes := n.p.x.y.x.Bytes() ret := finalExponentiation(e.p)
xyyBytes := n.p.x.y.y.Bytes() e.p.Set(ret)
xzxBytes := n.p.x.z.x.Bytes() return e
xzyBytes := n.p.x.z.y.Bytes() }
yxxBytes := n.p.y.x.x.Bytes()
yxyBytes := n.p.y.x.y.Bytes()
yyxBytes := n.p.y.y.x.Bytes()
yyyBytes := n.p.y.y.y.Bytes()
yzxBytes := n.p.y.z.x.Bytes()
yzyBytes := n.p.y.z.y.Bytes()
// Marshal converts e into a byte slice.
func (e *GT) Marshal() []byte {
// Each value is a 256-bit number. // Each value is a 256-bit number.
const numBytes = 256 / 8 const numBytes = 256 / 8
ret := make([]byte, numBytes*12) ret := make([]byte, numBytes*12)
copy(ret[1*numBytes-len(xxxBytes):], xxxBytes) temp := &gfP{}
copy(ret[2*numBytes-len(xxyBytes):], xxyBytes)
copy(ret[3*numBytes-len(xyxBytes):], xyxBytes) montDecode(temp, &e.p.x.x.x)
copy(ret[4*numBytes-len(xyyBytes):], xyyBytes) temp.Marshal(ret)
copy(ret[5*numBytes-len(xzxBytes):], xzxBytes) montDecode(temp, &e.p.x.x.y)
copy(ret[6*numBytes-len(xzyBytes):], xzyBytes) temp.Marshal(ret[numBytes:])
copy(ret[7*numBytes-len(yxxBytes):], yxxBytes) montDecode(temp, &e.p.x.y.x)
copy(ret[8*numBytes-len(yxyBytes):], yxyBytes) temp.Marshal(ret[2*numBytes:])
copy(ret[9*numBytes-len(yyxBytes):], yyxBytes) montDecode(temp, &e.p.x.y.y)
copy(ret[10*numBytes-len(yyyBytes):], yyyBytes) temp.Marshal(ret[3*numBytes:])
copy(ret[11*numBytes-len(yzxBytes):], yzxBytes) montDecode(temp, &e.p.x.z.x)
copy(ret[12*numBytes-len(yzyBytes):], yzyBytes) temp.Marshal(ret[4*numBytes:])
montDecode(temp, &e.p.x.z.y)
temp.Marshal(ret[5*numBytes:])
montDecode(temp, &e.p.y.x.x)
temp.Marshal(ret[6*numBytes:])
montDecode(temp, &e.p.y.x.y)
temp.Marshal(ret[7*numBytes:])
montDecode(temp, &e.p.y.y.x)
temp.Marshal(ret[8*numBytes:])
montDecode(temp, &e.p.y.y.y)
temp.Marshal(ret[9*numBytes:])
montDecode(temp, &e.p.y.z.x)
temp.Marshal(ret[10*numBytes:])
montDecode(temp, &e.p.y.z.y)
temp.Marshal(ret[11*numBytes:])
return ret return ret
} }
// Unmarshal sets e to the result of converting the output of Marshal back into // Unmarshal sets e to the result of converting the output of Marshal back into
// a group element and then returns e. // a group element and then returns e.
func (e *GT) Unmarshal(m []byte) (*GT, bool) { func (e *GT) 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) != 12*numBytes { if len(m) < 12*numBytes {
return nil, false return nil, errors.New("bn256: not enough data")
} }
if e.p == nil { if e.p == nil {
e.p = newGFp12(nil) e.p = &gfP12{}
} }
e.p.x.x.x.SetBytes(m[0*numBytes : 1*numBytes]) e.p.x.x.x.Unmarshal(m)
e.p.x.x.y.SetBytes(m[1*numBytes : 2*numBytes]) e.p.x.x.y.Unmarshal(m[numBytes:])
e.p.x.y.x.SetBytes(m[2*numBytes : 3*numBytes]) e.p.x.y.x.Unmarshal(m[2*numBytes:])
e.p.x.y.y.SetBytes(m[3*numBytes : 4*numBytes]) e.p.x.y.y.Unmarshal(m[3*numBytes:])
e.p.x.z.x.SetBytes(m[4*numBytes : 5*numBytes]) e.p.x.z.x.Unmarshal(m[4*numBytes:])
e.p.x.z.y.SetBytes(m[5*numBytes : 6*numBytes]) e.p.x.z.y.Unmarshal(m[5*numBytes:])
e.p.y.x.x.SetBytes(m[6*numBytes : 7*numBytes]) e.p.y.x.x.Unmarshal(m[6*numBytes:])
e.p.y.x.y.SetBytes(m[7*numBytes : 8*numBytes]) e.p.y.x.y.Unmarshal(m[7*numBytes:])
e.p.y.y.x.SetBytes(m[8*numBytes : 9*numBytes]) e.p.y.y.x.Unmarshal(m[8*numBytes:])
e.p.y.y.y.SetBytes(m[9*numBytes : 10*numBytes]) e.p.y.y.y.Unmarshal(m[9*numBytes:])
e.p.y.z.x.SetBytes(m[10*numBytes : 11*numBytes]) e.p.y.z.x.Unmarshal(m[10*numBytes:])
e.p.y.z.y.SetBytes(m[11*numBytes : 12*numBytes]) e.p.y.z.y.Unmarshal(m[11*numBytes:])
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.y.x, &e.p.x.y.x)
montEncode(&e.p.x.y.y, &e.p.x.y.y)
montEncode(&e.p.x.z.x, &e.p.x.z.x)
montEncode(&e.p.x.z.y, &e.p.x.z.y)
montEncode(&e.p.y.x.x, &e.p.y.x.x)
montEncode(&e.p.y.x.y, &e.p.y.x.y)
montEncode(&e.p.y.y.x, &e.p.y.y.x)
montEncode(&e.p.y.y.y, &e.p.y.y.y)
montEncode(&e.p.y.z.x, &e.p.y.z.x)
montEncode(&e.p.y.z.y, &e.p.y.z.y)
return e, true return m[12*numBytes:], nil
}
// Pair calculates an Optimal Ate pairing.
func Pair(g1 *G1, g2 *G2) *GT {
return &GT{optimalAte(g2.p, g1.p, new(bnPool))}
}
// PairingCheck calculates the Optimal Ate pairing for a set of points.
func PairingCheck(a []*G1, b []*G2) bool {
pool := new(bnPool)
acc := newGFp12(pool)
acc.SetOne()
for i := 0; i < len(a); i++ {
if a[i].p.IsInfinity() || b[i].p.IsInfinity() {
continue
}
acc.Mul(acc, miller(b[i].p, a[i].p, pool), pool)
}
ret := finalExponentiation(acc, pool)
acc.Put(pool)
return ret.IsOne()
}
// bnPool implements a tiny cache of *big.Int objects that's used to reduce the
// number of allocations made during processing.
type bnPool struct {
bns []*big.Int
count int
}
func (pool *bnPool) Get() *big.Int {
if pool == nil {
return new(big.Int)
}
pool.count++
l := len(pool.bns)
if l == 0 {
return new(big.Int)
}
bn := pool.bns[l-1]
pool.bns = pool.bns[:l-1]
return bn
}
func (pool *bnPool) Put(bn *big.Int) {
if pool == nil {
return
}
pool.bns = append(pool.bns, bn)
pool.count--
}
func (pool *bnPool) Count() int {
return pool.count
} }

View file

@ -1,199 +1,46 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package bn256 package bn256
import ( import (
"bytes" "bytes"
"crypto/rand" "crypto/rand"
"math/big"
"testing" "testing"
) )
func TestGFp2Invert(t *testing.T) { func TestG1Marshal(t *testing.T) {
pool := new(bnPool) _, Ga, err := RandomG1(rand.Reader)
if err != nil {
a := newGFp2(pool) t.Fatal(err)
a.x.SetString("23423492374", 10)
a.y.SetString("12934872398472394827398470", 10)
inv := newGFp2(pool)
inv.Invert(a, pool)
b := newGFp2(pool).Mul(inv, a, pool)
if b.x.Int64() != 0 || b.y.Int64() != 1 {
t.Fatalf("bad result for a^-1*a: %s %s", b.x, b.y)
} }
ma := Ga.Marshal()
a.Put(pool) Gb := new(G1)
b.Put(pool) _, err = Gb.Unmarshal(ma)
inv.Put(pool) if err != nil {
t.Fatal(err)
}
mb := Gb.Marshal()
if c := pool.Count(); c > 0 { if !bytes.Equal(ma, mb) {
t.Errorf("Pool count non-zero: %d\n", c) t.Fatal("bytes are different")
} }
} }
func isZero(n *big.Int) bool { func TestG2Marshal(t *testing.T) {
return new(big.Int).Mod(n, P).Int64() == 0 _, Ga, err := RandomG2(rand.Reader)
} if err != nil {
t.Fatal(err)
func isOne(n *big.Int) bool {
return new(big.Int).Mod(n, P).Int64() == 1
}
func TestGFp6Invert(t *testing.T) {
pool := new(bnPool)
a := newGFp6(pool)
a.x.x.SetString("239487238491", 10)
a.x.y.SetString("2356249827341", 10)
a.y.x.SetString("082659782", 10)
a.y.y.SetString("182703523765", 10)
a.z.x.SetString("978236549263", 10)
a.z.y.SetString("64893242", 10)
inv := newGFp6(pool)
inv.Invert(a, pool)
b := newGFp6(pool).Mul(inv, a, pool)
if !isZero(b.x.x) ||
!isZero(b.x.y) ||
!isZero(b.y.x) ||
!isZero(b.y.y) ||
!isZero(b.z.x) ||
!isOne(b.z.y) {
t.Fatalf("bad result for a^-1*a: %s", b)
} }
ma := Ga.Marshal()
a.Put(pool) Gb := new(G2)
b.Put(pool) _, err = Gb.Unmarshal(ma)
inv.Put(pool) if err != nil {
t.Fatal(err)
if c := pool.Count(); c > 0 {
t.Errorf("Pool count non-zero: %d\n", c)
} }
} mb := Gb.Marshal()
func TestGFp12Invert(t *testing.T) { if !bytes.Equal(ma, mb) {
pool := new(bnPool) t.Fatal("bytes are different")
a := newGFp12(pool)
a.x.x.x.SetString("239846234862342323958623", 10)
a.x.x.y.SetString("2359862352529835623", 10)
a.x.y.x.SetString("928836523", 10)
a.x.y.y.SetString("9856234", 10)
a.x.z.x.SetString("235635286", 10)
a.x.z.y.SetString("5628392833", 10)
a.y.x.x.SetString("252936598265329856238956532167968", 10)
a.y.x.y.SetString("23596239865236954178968", 10)
a.y.y.x.SetString("95421692834", 10)
a.y.y.y.SetString("236548", 10)
a.y.z.x.SetString("924523", 10)
a.y.z.y.SetString("12954623", 10)
inv := newGFp12(pool)
inv.Invert(a, pool)
b := newGFp12(pool).Mul(inv, a, pool)
if !isZero(b.x.x.x) ||
!isZero(b.x.x.y) ||
!isZero(b.x.y.x) ||
!isZero(b.x.y.y) ||
!isZero(b.x.z.x) ||
!isZero(b.x.z.y) ||
!isZero(b.y.x.x) ||
!isZero(b.y.x.y) ||
!isZero(b.y.y.x) ||
!isZero(b.y.y.y) ||
!isZero(b.y.z.x) ||
!isOne(b.y.z.y) {
t.Fatalf("bad result for a^-1*a: %s", b)
}
a.Put(pool)
b.Put(pool)
inv.Put(pool)
if c := pool.Count(); c > 0 {
t.Errorf("Pool count non-zero: %d\n", c)
}
}
func TestCurveImpl(t *testing.T) {
pool := new(bnPool)
g := &curvePoint{
pool.Get().SetInt64(1),
pool.Get().SetInt64(-2),
pool.Get().SetInt64(1),
pool.Get().SetInt64(0),
}
x := pool.Get().SetInt64(32498273234)
X := newCurvePoint(pool).Mul(g, x, pool)
y := pool.Get().SetInt64(98732423523)
Y := newCurvePoint(pool).Mul(g, y, pool)
s1 := newCurvePoint(pool).Mul(X, y, pool).MakeAffine(pool)
s2 := newCurvePoint(pool).Mul(Y, x, pool).MakeAffine(pool)
if s1.x.Cmp(s2.x) != 0 ||
s2.x.Cmp(s1.x) != 0 {
t.Errorf("DH points don't match: (%s, %s) (%s, %s)", s1.x, s1.y, s2.x, s2.y)
}
pool.Put(x)
X.Put(pool)
pool.Put(y)
Y.Put(pool)
s1.Put(pool)
s2.Put(pool)
g.Put(pool)
if c := pool.Count(); c > 0 {
t.Errorf("Pool count non-zero: %d\n", c)
}
}
func TestOrderG1(t *testing.T) {
g := new(G1).ScalarBaseMult(Order)
if !g.p.IsInfinity() {
t.Error("G1 has incorrect order")
}
one := new(G1).ScalarBaseMult(new(big.Int).SetInt64(1))
g.Add(g, one)
g.p.MakeAffine(nil)
if g.p.x.Cmp(one.p.x) != 0 || g.p.y.Cmp(one.p.y) != 0 {
t.Errorf("1+0 != 1 in G1")
}
}
func TestOrderG2(t *testing.T) {
g := new(G2).ScalarBaseMult(Order)
if !g.p.IsInfinity() {
t.Error("G2 has incorrect order")
}
one := new(G2).ScalarBaseMult(new(big.Int).SetInt64(1))
g.Add(g, one)
g.p.MakeAffine(nil)
if g.p.x.x.Cmp(one.p.x.x) != 0 ||
g.p.x.y.Cmp(one.p.x.y) != 0 ||
g.p.y.x.Cmp(one.p.y.x) != 0 ||
g.p.y.y.Cmp(one.p.y.y) != 0 {
t.Errorf("1+0 != 1 in G2")
}
}
func TestOrderGT(t *testing.T) {
gt := Pair(&G1{curveGen}, &G2{twistGen})
g := new(GT).ScalarMult(gt, Order)
if !g.p.IsOne() {
t.Error("GT has incorrect order")
} }
} }
@ -207,78 +54,26 @@ func TestBilinearity(t *testing.T) {
e2.ScalarMult(e2, a) e2.ScalarMult(e2, a)
e2.ScalarMult(e2, b) e2.ScalarMult(e2, b)
minusE2 := new(GT).Neg(e2) if *e1.p != *e2.p {
e1.Add(e1, minusE2)
if !e1.p.IsOne() {
t.Fatalf("bad pairing result: %s", e1) t.Fatalf("bad pairing result: %s", e1)
} }
} }
} }
func TestG1Marshal(t *testing.T) {
g := new(G1).ScalarBaseMult(new(big.Int).SetInt64(1))
form := g.Marshal()
_, ok := new(G1).Unmarshal(form)
if !ok {
t.Fatalf("failed to unmarshal")
}
g.ScalarBaseMult(Order)
form = g.Marshal()
g2, ok := new(G1).Unmarshal(form)
if !ok {
t.Fatalf("failed to unmarshal ∞")
}
if !g2.p.IsInfinity() {
t.Fatalf("∞ unmarshaled incorrectly")
}
}
func TestG2Marshal(t *testing.T) {
g := new(G2).ScalarBaseMult(new(big.Int).SetInt64(1))
form := g.Marshal()
_, ok := new(G2).Unmarshal(form)
if !ok {
t.Fatalf("failed to unmarshal")
}
g.ScalarBaseMult(Order)
form = g.Marshal()
g2, ok := new(G2).Unmarshal(form)
if !ok {
t.Fatalf("failed to unmarshal ∞")
}
if !g2.p.IsInfinity() {
t.Fatalf("∞ unmarshaled incorrectly")
}
}
func TestG1Identity(t *testing.T) {
g := new(G1).ScalarBaseMult(new(big.Int).SetInt64(0))
if !g.p.IsInfinity() {
t.Error("failure")
}
}
func TestG2Identity(t *testing.T) {
g := new(G2).ScalarBaseMult(new(big.Int).SetInt64(0))
if !g.p.IsInfinity() {
t.Error("failure")
}
}
func TestTripartiteDiffieHellman(t *testing.T) { func TestTripartiteDiffieHellman(t *testing.T) {
a, _ := rand.Int(rand.Reader, Order) a, _ := rand.Int(rand.Reader, Order)
b, _ := rand.Int(rand.Reader, Order) b, _ := rand.Int(rand.Reader, Order)
c, _ := rand.Int(rand.Reader, Order) c, _ := rand.Int(rand.Reader, Order)
pa, _ := new(G1).Unmarshal(new(G1).ScalarBaseMult(a).Marshal()) pa, pb, pc := new(G1), new(G1), new(G1)
qa, _ := new(G2).Unmarshal(new(G2).ScalarBaseMult(a).Marshal()) qa, qb, qc := new(G2), new(G2), new(G2)
pb, _ := new(G1).Unmarshal(new(G1).ScalarBaseMult(b).Marshal())
qb, _ := new(G2).Unmarshal(new(G2).ScalarBaseMult(b).Marshal()) pa.Unmarshal(new(G1).ScalarBaseMult(a).Marshal())
pc, _ := new(G1).Unmarshal(new(G1).ScalarBaseMult(c).Marshal()) qa.Unmarshal(new(G2).ScalarBaseMult(a).Marshal())
qc, _ := new(G2).Unmarshal(new(G2).ScalarBaseMult(c).Marshal()) pb.Unmarshal(new(G1).ScalarBaseMult(b).Marshal())
qb.Unmarshal(new(G2).ScalarBaseMult(b).Marshal())
pc.Unmarshal(new(G1).ScalarBaseMult(c).Marshal())
qc.Unmarshal(new(G2).ScalarBaseMult(c).Marshal())
k1 := Pair(pb, qc) k1 := Pair(pb, qc)
k1.ScalarMult(k1, a) k1.ScalarMult(k1, a)
@ -297,6 +92,23 @@ func TestTripartiteDiffieHellman(t *testing.T) {
} }
} }
func BenchmarkG1(b *testing.B) {
x, _ := rand.Int(rand.Reader, Order)
b.ResetTimer()
for i := 0; i < b.N; i++ {
new(G1).ScalarBaseMult(x)
}
}
func BenchmarkG2(b *testing.B) {
x, _ := rand.Int(rand.Reader, Order)
b.ResetTimer()
for i := 0; i < b.N; i++ {
new(G2).ScalarBaseMult(x)
}
}
func BenchmarkPairing(b *testing.B) { func BenchmarkPairing(b *testing.B) {
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
Pair(&G1{curveGen}, &G2{twistGen}) Pair(&G1{curveGen}, &G2{twistGen})

View file

@ -16,29 +16,44 @@ func bigFromBase10(s string) *big.Int {
// u is the BN parameter that determines the prime: 1868033³. // u is the BN parameter that determines the prime: 1868033³.
var u = bigFromBase10("4965661367192848881") var u = bigFromBase10("4965661367192848881")
// p is a prime over which we form a basic field: 36u⁴+36u³+24u²+6u+1.
var P = bigFromBase10("21888242871839275222246405745257275088696311157297823662689037894645226208583")
// Order is the number of elements in both G₁ and G₂: 36u⁴+36u³+18u²+6u+1. // Order is the number of elements in both G₁ and G₂: 36u⁴+36u³+18u²+6u+1.
var Order = bigFromBase10("21888242871839275222246405745257275088548364400416034343698204186575808495617") var Order = bigFromBase10("21888242871839275222246405745257275088548364400416034343698204186575808495617")
// P is a prime over which we form a basic field: 36u⁴+36u³+24u²+6u+1.
var P = bigFromBase10("21888242871839275222246405745257275088696311157297823662689037894645226208583")
// p2 is p, represented as little-endian 64-bit words.
var p2 = [4]uint64{0x3c208c16d87cfd47, 0x97816a916871ca8d, 0xb85045b68181585d, 0x30644e72e131a029}
// np is the negative inverse of p, mod 2^256.
var np = [4]uint64{0x87d20782e4866389, 0x9ede7d651eca6ac9, 0xd8afcbd01833da80, 0xf57a22b791888c6b}
// rN1 is R^-1 where R = 2^256 mod p.
var rN1 = &gfP{0xed84884a014afa37, 0xeb2022850278edf8, 0xcf63e9cfb74492d9, 0x2e67157159e5c639}
// r2 is R^2 where R = 2^256 mod p.
var r2 = &gfP{0xf32cfc5b538afa89, 0xb5e71911d44501fb, 0x47ab1eff0a417ff6, 0x06d89f71cab8351f}
// r3 is R^3 where R = 2^256 mod p.
var r3 = &gfP{0xb1cd6dafda1530df, 0x62f210e6a7283db6, 0xef7f0b0c0ada0afb, 0x20fd6e902d592544}
// xiToPMinus1Over6 is ξ^((p-1)/6) where ξ = i+9. // xiToPMinus1Over6 is ξ^((p-1)/6) where ξ = i+9.
var xiToPMinus1Over6 = &gfP2{bigFromBase10("16469823323077808223889137241176536799009286646108169935659301613961712198316"), bigFromBase10("8376118865763821496583973867626364092589906065868298776909617916018768340080")} var xiToPMinus1Over6 = &gfP2{gfP{0xa222ae234c492d72, 0xd00f02a4565de15b, 0xdc2ff3a253dfc926, 0x10a75716b3899551}, gfP{0xaf9ba69633144907, 0xca6b1d7387afb78a, 0x11bded5ef08a2087, 0x02f34d751a1f3a7c}}
// xiToPMinus1Over3 is ξ^((p-1)/3) where ξ = i+9. // xiToPMinus1Over3 is ξ^((p-1)/3) where ξ = i+9.
var xiToPMinus1Over3 = &gfP2{bigFromBase10("10307601595873709700152284273816112264069230130616436755625194854815875713954"), bigFromBase10("21575463638280843010398324269430826099269044274347216827212613867836435027261")} var xiToPMinus1Over3 = &gfP2{gfP{0x6e849f1ea0aa4757, 0xaa1c7b6d89f89141, 0xb6e713cdfae0ca3a, 0x26694fbb4e82ebc3}, gfP{0xb5773b104563ab30, 0x347f91c8a9aa6454, 0x7a007127242e0991, 0x1956bcd8118214ec}}
// xiToPMinus1Over2 is ξ^((p-1)/2) where ξ = i+9. // xiToPMinus1Over2 is ξ^((p-1)/2) where ξ = i+9.
var xiToPMinus1Over2 = &gfP2{bigFromBase10("3505843767911556378687030309984248845540243509899259641013678093033130930403"), bigFromBase10("2821565182194536844548159561693502659359617185244120367078079554186484126554")} var xiToPMinus1Over2 = &gfP2{gfP{0xa1d77ce45ffe77c7, 0x07affd117826d1db, 0x6d16bd27bb7edc6b, 0x2c87200285defecc}, gfP{0xe4bbdd0c2936b629, 0xbb30f162e133bacb, 0x31a9d1b6f9645366, 0x253570bea500f8dd}}
// xiToPSquaredMinus1Over3 is ξ^((p²-1)/3) where ξ = i+9. // xiToPSquaredMinus1Over3 is ξ^((p²-1)/3) where ξ = i+9.
var xiToPSquaredMinus1Over3 = bigFromBase10("21888242871839275220042445260109153167277707414472061641714758635765020556616") var xiToPSquaredMinus1Over3 = &gfP{0x3350c88e13e80b9c, 0x7dce557cdb5e56b9, 0x6001b4b8b615564a, 0x2682e617020217e0}
// xiTo2PSquaredMinus2Over3 is ξ^((2p²-2)/3) where ξ = i+9 (a cubic root of unity, mod p). // xiTo2PSquaredMinus2Over3 is ξ^((2p²-2)/3) where ξ = i+9 (a cubic root of unity, mod p).
var xiTo2PSquaredMinus2Over3 = bigFromBase10("2203960485148121921418603742825762020974279258880205651966") var xiTo2PSquaredMinus2Over3 = &gfP{0x71930c11d782e155, 0xa6bb947cffbe3323, 0xaa303344d4741444, 0x2c3b3f0d26594943}
// xiToPSquaredMinus1Over6 is ξ^((1p²-1)/6) where ξ = i+9 (a cubic root of -1, mod p). // xiToPSquaredMinus1Over6 is ξ^((1p²-1)/6) where ξ = i+9 (a cubic root of -1, mod p).
var xiToPSquaredMinus1Over6 = bigFromBase10("21888242871839275220042445260109153167277707414472061641714758635765020556617") var xiToPSquaredMinus1Over6 = &gfP{0xca8d800500fa1bf2, 0xf0c5d61468b39769, 0x0e201271ad0d4418, 0x04290f65bad856e6}
// xiTo2PMinus2Over3 is ξ^((2p-2)/3) where ξ = i+9. // xiTo2PMinus2Over3 is ξ^((2p-2)/3) where ξ = i+9.
var xiTo2PMinus2Over3 = &gfP2{bigFromBase10("19937756971775647987995932169929341994314640652964949448313374472400716661030"), bigFromBase10("2581911344467009335267311115468803099551665605076196740867805258568234346338")} var xiTo2PMinus2Over3 = &gfP2{gfP{0x5dddfd154bd8c949, 0x62cb29a5a4445b60, 0x37bc870a0c7dd2b9, 0x24830a9d3171f0fd}, gfP{0x7361d77f843abe92, 0xa5bb2bd3273411fb, 0x9c941f314b3e2399, 0x15df9cddbb9fd3ec}}

View file

@ -1,80 +1,68 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package bn256 package bn256
import ( import (
"math/big" "math/big"
) )
// curvePoint implements the elliptic curve y²=x³+3. Points are kept in // curvePoint implements the elliptic curve y²=x³+3. Points are kept in Jacobian
// Jacobian form and t=z² when valid. G₁ is the set of points of this curve on // form and t=z² when valid. G₁ is the set of points of this curve on GF(p).
// GF(p).
type curvePoint struct { type curvePoint struct {
x, y, z, t *big.Int x, y, z, t gfP
} }
var curveB = new(big.Int).SetInt64(3) var curveB = newGFp(3)
// curveGen is the generator of G₁. // curveGen is the generator of G₁.
var curveGen = &curvePoint{ var curveGen = &curvePoint{
new(big.Int).SetInt64(1), x: *newGFp(1),
new(big.Int).SetInt64(2), y: *newGFp(2),
new(big.Int).SetInt64(1), z: *newGFp(1),
new(big.Int).SetInt64(1), t: *newGFp(1),
}
func newCurvePoint(pool *bnPool) *curvePoint {
return &curvePoint{
pool.Get(),
pool.Get(),
pool.Get(),
pool.Get(),
}
} }
func (c *curvePoint) String() string { func (c *curvePoint) String() string {
c.MakeAffine(new(bnPool)) c.MakeAffine()
return "(" + c.x.String() + ", " + c.y.String() + ")" x, y := &gfP{}, &gfP{}
} montDecode(x, &c.x)
montDecode(y, &c.y)
func (c *curvePoint) Put(pool *bnPool) { return "(" + x.String() + ", " + y.String() + ")"
pool.Put(c.x)
pool.Put(c.y)
pool.Put(c.z)
pool.Put(c.t)
} }
func (c *curvePoint) Set(a *curvePoint) { func (c *curvePoint) Set(a *curvePoint) {
c.x.Set(a.x) c.x.Set(&a.x)
c.y.Set(a.y) c.y.Set(&a.y)
c.z.Set(a.z) c.z.Set(&a.z)
c.t.Set(a.t) c.t.Set(&a.t)
} }
// IsOnCurve returns true iff c is on the curve where c must be in affine form. // IsOnCurve returns true iff c is on the curve.
func (c *curvePoint) IsOnCurve() bool { func (c *curvePoint) IsOnCurve() bool {
yy := new(big.Int).Mul(c.y, c.y) c.MakeAffine()
xxx := new(big.Int).Mul(c.x, c.x) if c.IsInfinity() {
xxx.Mul(xxx, c.x) return true
yy.Sub(yy, xxx)
yy.Sub(yy, curveB)
if yy.Sign() < 0 || yy.Cmp(P) >= 0 {
yy.Mod(yy, P)
} }
return yy.Sign() == 0
y2, x3 := &gfP{}, &gfP{}
gfpMul(y2, &c.y, &c.y)
gfpMul(x3, &c.x, &c.x)
gfpMul(x3, x3, &c.x)
gfpAdd(x3, x3, curveB)
return *y2 == *x3
} }
func (c *curvePoint) SetInfinity() { func (c *curvePoint) SetInfinity() {
c.z.SetInt64(0) c.x = gfP{0}
c.y = *newGFp(1)
c.z = gfP{0}
c.t = gfP{0}
} }
func (c *curvePoint) IsInfinity() bool { func (c *curvePoint) IsInfinity() bool {
return c.z.Sign() == 0 return c.z == gfP{0}
} }
func (c *curvePoint) Add(a, b *curvePoint, pool *bnPool) { func (c *curvePoint) Add(a, b *curvePoint) {
if a.IsInfinity() { if a.IsInfinity() {
c.Set(b) c.Set(b)
return return
@ -89,24 +77,21 @@ func (c *curvePoint) Add(a, b *curvePoint, pool *bnPool) {
// Normalize the points by replacing a = [x1:y1:z1] and b = [x2:y2:z2] // Normalize the points by replacing a = [x1:y1:z1] and b = [x2:y2:z2]
// by [u1:s1:z1·z2] and [u2:s2:z1·z2] // by [u1:s1:z1·z2] and [u2:s2:z1·z2]
// where u1 = x1·z2², s1 = y1·z2³ and u1 = x2·z1², s2 = y2·z1³ // where u1 = x1·z2², s1 = y1·z2³ and u1 = x2·z1², s2 = y2·z1³
z1z1 := pool.Get().Mul(a.z, a.z) z12, z22 := &gfP{}, &gfP{}
z1z1.Mod(z1z1, P) gfpMul(z12, &a.z, &a.z)
z2z2 := pool.Get().Mul(b.z, b.z) gfpMul(z22, &b.z, &b.z)
z2z2.Mod(z2z2, P)
u1 := pool.Get().Mul(a.x, z2z2)
u1.Mod(u1, P)
u2 := pool.Get().Mul(b.x, z1z1)
u2.Mod(u2, P)
t := pool.Get().Mul(b.z, z2z2) u1, u2 := &gfP{}, &gfP{}
t.Mod(t, P) gfpMul(u1, &a.x, z22)
s1 := pool.Get().Mul(a.y, t) gfpMul(u2, &b.x, z12)
s1.Mod(s1, P)
t.Mul(a.z, z1z1) t, s1 := &gfP{}, &gfP{}
t.Mod(t, P) gfpMul(t, &b.z, z22)
s2 := pool.Get().Mul(b.y, t) gfpMul(s1, &a.y, t)
s2.Mod(s2, P)
s2 := &gfP{}
gfpMul(t, &a.z, z12)
gfpMul(s2, &b.y, t)
// Compute x = (2h)²(s²-u1-u2) // Compute x = (2h)²(s²-u1-u2)
// where s = (s2-s1)/(u2-u1) is the slope of the line through // where s = (s2-s1)/(u2-u1) is the slope of the line through
@ -115,164 +100,130 @@ func (c *curvePoint) Add(a, b *curvePoint, pool *bnPool) {
// 4(s2-s1)² - 4h²(u1+u2) = 4(s2-s1)² - 4h³ - 4h²(2u1) // 4(s2-s1)² - 4h²(u1+u2) = 4(s2-s1)² - 4h³ - 4h²(2u1)
// = r² - j - 2v // = r² - j - 2v
// with the notations below. // with the notations below.
h := pool.Get().Sub(u2, u1) h := &gfP{}
xEqual := h.Sign() == 0 gfpSub(h, u2, u1)
xEqual := *h == gfP{0}
t.Add(h, h) gfpAdd(t, h, h)
// i = 4h² // i = 4h²
i := pool.Get().Mul(t, t) i := &gfP{}
i.Mod(i, P) gfpMul(i, t, t)
// j = 4h³ // j = 4h³
j := pool.Get().Mul(h, i) j := &gfP{}
j.Mod(j, P) gfpMul(j, h, i)
t.Sub(s2, s1) gfpSub(t, s2, s1)
yEqual := t.Sign() == 0 yEqual := *t == gfP{0}
if xEqual && yEqual { if xEqual && yEqual {
c.Double(a, pool) c.Double(a)
return return
} }
r := pool.Get().Add(t, t) r := &gfP{}
gfpAdd(r, t, t)
v := pool.Get().Mul(u1, i) v := &gfP{}
v.Mod(v, P) gfpMul(v, u1, i)
// t4 = 4(s2-s1)² // t4 = 4(s2-s1)²
t4 := pool.Get().Mul(r, r) t4, t6 := &gfP{}, &gfP{}
t4.Mod(t4, P) gfpMul(t4, r, r)
t.Add(v, v) gfpAdd(t, v, v)
t6 := pool.Get().Sub(t4, j) gfpSub(t6, t4, j)
c.x.Sub(t6, t)
gfpSub(&c.x, t6, t)
// Set y = -(2h)³(s1 + s*(x/4h²-u1)) // Set y = -(2h)³(s1 + s*(x/4h²-u1))
// This is also // This is also
// y = - 2·s1·j - (s2-s1)(2x - 2i·u1) = r(v-x) - 2·s1·j // y = - 2·s1·j - (s2-s1)(2x - 2i·u1) = r(v-x) - 2·s1·j
t.Sub(v, c.x) // t7 gfpSub(t, v, &c.x) // t7
t4.Mul(s1, j) // t8 gfpMul(t4, s1, j) // t8
t4.Mod(t4, P) gfpAdd(t6, t4, t4) // t9
t6.Add(t4, t4) // t9 gfpMul(t4, r, t) // t10
t4.Mul(r, t) // t10 gfpSub(&c.y, t4, t6)
t4.Mod(t4, P)
c.y.Sub(t4, t6)
// Set z = 2(u2-u1)·z1·z2 = 2h·z1·z2 // Set z = 2(u2-u1)·z1·z2 = 2h·z1·z2
t.Add(a.z, b.z) // t11 gfpAdd(t, &a.z, &b.z) // t11
t4.Mul(t, t) // t12 gfpMul(t4, t, t) // t12
t4.Mod(t4, P) gfpSub(t, t4, z12) // t13
t.Sub(t4, z1z1) // t13 gfpSub(t4, t, z22) // t14
t4.Sub(t, z2z2) // t14 gfpMul(&c.z, t4, h)
c.z.Mul(t4, h)
c.z.Mod(c.z, P)
pool.Put(z1z1)
pool.Put(z2z2)
pool.Put(u1)
pool.Put(u2)
pool.Put(t)
pool.Put(s1)
pool.Put(s2)
pool.Put(h)
pool.Put(i)
pool.Put(j)
pool.Put(r)
pool.Put(v)
pool.Put(t4)
pool.Put(t6)
} }
func (c *curvePoint) Double(a *curvePoint, pool *bnPool) { func (c *curvePoint) Double(a *curvePoint) {
// See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/doubling/dbl-2009-l.op3 // See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/doubling/dbl-2009-l.op3
A := pool.Get().Mul(a.x, a.x) A, B, C := &gfP{}, &gfP{}, &gfP{}
A.Mod(A, P) gfpMul(A, &a.x, &a.x)
B := pool.Get().Mul(a.y, a.y) gfpMul(B, &a.y, &a.y)
B.Mod(B, P) gfpMul(C, B, B)
C_ := pool.Get().Mul(B, B)
C_.Mod(C_, P)
t := pool.Get().Add(a.x, B) t, t2 := &gfP{}, &gfP{}
t2 := pool.Get().Mul(t, t) gfpAdd(t, &a.x, B)
t2.Mod(t2, P) gfpMul(t2, t, t)
t.Sub(t2, A) gfpSub(t, t2, A)
t2.Sub(t, C_) gfpSub(t2, t, C)
d := pool.Get().Add(t2, t2)
t.Add(A, A)
e := pool.Get().Add(t, A)
f := pool.Get().Mul(e, e)
f.Mod(f, P)
t.Add(d, d) d, e, f := &gfP{}, &gfP{}, &gfP{}
c.x.Sub(f, t) gfpAdd(d, t2, t2)
gfpAdd(t, A, A)
gfpAdd(e, t, A)
gfpMul(f, e, e)
t.Add(C_, C_) gfpAdd(t, d, d)
t2.Add(t, t) gfpSub(&c.x, f, t)
t.Add(t2, t2)
c.y.Sub(d, c.x)
t2.Mul(e, c.y)
t2.Mod(t2, P)
c.y.Sub(t2, t)
t.Mul(a.y, a.z) gfpAdd(t, C, C)
t.Mod(t, P) gfpAdd(t2, t, t)
c.z.Add(t, t) gfpAdd(t, t2, t2)
gfpSub(&c.y, d, &c.x)
gfpMul(t2, e, &c.y)
gfpSub(&c.y, t2, t)
pool.Put(A) gfpMul(t, &a.y, &a.z)
pool.Put(B) gfpAdd(&c.z, t, t)
pool.Put(C_)
pool.Put(t)
pool.Put(t2)
pool.Put(d)
pool.Put(e)
pool.Put(f)
} }
func (c *curvePoint) Mul(a *curvePoint, scalar *big.Int, pool *bnPool) *curvePoint { func (c *curvePoint) Mul(a *curvePoint, scalar *big.Int) {
sum := newCurvePoint(pool) sum, t := &curvePoint{}, &curvePoint{}
sum.SetInfinity() sum.SetInfinity()
t := newCurvePoint(pool)
for i := scalar.BitLen(); i >= 0; i-- { for i := scalar.BitLen(); i >= 0; i-- {
t.Double(sum, pool) t.Double(sum)
if scalar.Bit(i) != 0 { if scalar.Bit(i) != 0 {
sum.Add(t, a, pool) sum.Add(t, a)
} else { } else {
sum.Set(t) sum.Set(t)
} }
} }
c.Set(sum) c.Set(sum)
sum.Put(pool)
t.Put(pool)
return c
} }
func (c *curvePoint) MakeAffine(pool *bnPool) *curvePoint { func (c *curvePoint) MakeAffine() {
if words := c.z.Bits(); len(words) == 1 && words[0] == 1 { if c.z == *newGFp(1) {
return c return
} else if c.z == *newGFp(0) {
c.x = gfP{0}
c.y = *newGFp(1)
c.t = gfP{0}
return
} }
zInv := pool.Get().ModInverse(c.z, P) zInv := &gfP{}
t := pool.Get().Mul(c.y, zInv) zInv.Invert(&c.z)
t.Mod(t, P)
zInv2 := pool.Get().Mul(zInv, zInv)
zInv2.Mod(zInv2, P)
c.y.Mul(t, zInv2)
c.y.Mod(c.y, P)
t.Mul(c.x, zInv2)
t.Mod(t, P)
c.x.Set(t)
c.z.SetInt64(1)
c.t.SetInt64(1)
pool.Put(zInv) t, zInv2 := &gfP{}, &gfP{}
pool.Put(t) gfpMul(t, &c.y, zInv)
pool.Put(zInv2) gfpMul(zInv2, zInv, zInv)
return c gfpMul(&c.x, &c.x, zInv2)
gfpMul(&c.y, t, zInv2)
c.z = *newGFp(1)
c.t = *newGFp(1)
} }
func (c *curvePoint) Negative(a *curvePoint) { func (c *curvePoint) Neg(a *curvePoint) {
c.x.Set(a.x) c.x.Set(&a.x)
c.y.Neg(a.y) gfpNeg(&c.y, &a.y)
c.z.Set(a.z) c.z.Set(&a.z)
c.t.SetInt64(0) c.t = gfP{0}
} }

79
crypto/bn256/gfp.go Normal file
View file

@ -0,0 +1,79 @@
package bn256
import "fmt"
type gfP [4]uint64
func newGFp(x int64) (out *gfP) {
if x >= 0 {
out = &gfP{uint64(x)}
} else {
out = &gfP{uint64(-x)}
gfpNeg(out, out)
}
montEncode(out, out)
return out
}
func (e *gfP) String() string {
return fmt.Sprintf("%16.16x%16.16x%16.16x%16.16x", e[3], e[2], e[1], e[0])
}
func (e *gfP) Set(f *gfP) {
e[0] = f[0]
e[1] = f[1]
e[2] = f[2]
e[3] = f[3]
}
func (e *gfP) Invert(f *gfP) {
bits := [4]uint64{0x3c208c16d87cfd45, 0x97816a916871ca8d, 0xb85045b68181585d, 0x30644e72e131a029}
sum, power := &gfP{}, &gfP{}
sum.Set(rN1)
power.Set(f)
for word := 0; word < 4; word++ {
for bit := uint(0); bit < 64; bit++ {
if (bits[word]>>bit)&1 == 1 {
gfpMul(sum, sum, power)
}
gfpMul(power, power, power)
}
}
gfpMul(sum, sum, r3)
e.Set(sum)
}
func (e *gfP) Marshal(out []byte) {
for w := uint(0); w < 4; w++ {
for b := uint(0); b < 8; b++ {
out[8*w+b] = byte(e[3-w] >> (56 - 8*b))
}
}
}
func (e *gfP) Unmarshal(in []byte) {
for w := uint(0); w < 4; w++ {
for b := uint(0); b < 8; b++ {
e[3-w] += uint64(in[8*w+b]) << (56 - 8*b)
}
}
}
func montEncode(c, a *gfP) { gfpMul(c, a, r2) }
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)

32
crypto/bn256/gfp.h Normal file
View file

@ -0,0 +1,32 @@
#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

95
crypto/bn256/gfp.s Normal file
View file

@ -0,0 +1,95 @@
#include "gfp.h"
#include "mul.h"
#include "mul_bmi2.h"
TEXT ·gfpNeg(SB),0,$0-16
MOVQ ·p2+0(SB), R8
MOVQ ·p2+8(SB), R9
MOVQ ·p2+16(SB), R10
MOVQ ·p2+24(SB), R11
MOVQ a+8(FP), DI
SUBQ 0(DI), R8
SBBQ 8(DI), R9
SBBQ 16(DI), R10
SBBQ 24(DI), R11
MOVQ $0, AX
gfpCarry(R8,R9,R10,R11,AX, R12,R13,R14,R15,BX)
MOVQ c+0(FP), DI
storeBlock(R8,R9,R10,R11, 0(DI))
RET
TEXT ·gfpAdd(SB),0,$0-24
MOVQ a+8(FP), DI
MOVQ b+16(FP), SI
loadBlock(0(DI), R8,R9,R10,R11)
MOVQ $0, R12
ADDQ 0(SI), R8
ADCQ 8(SI), R9
ADCQ 16(SI), R10
ADCQ 24(SI), R11
ADCQ $0, R12
gfpCarry(R8,R9,R10,R11,R12, R13,R14,R15,AX,BX)
MOVQ c+0(FP), DI
storeBlock(R8,R9,R10,R11, 0(DI))
RET
TEXT ·gfpSub(SB),0,$0-24
MOVQ a+8(FP), DI
MOVQ b+16(FP), SI
loadBlock(0(DI), R8,R9,R10,R11)
MOVQ ·p2+0(SB), R12
MOVQ ·p2+8(SB), R13
MOVQ ·p2+16(SB), R14
MOVQ ·p2+24(SB), R15
MOVQ $0, AX
SUBQ 0(SI), R8
SBBQ 8(SI), R9
SBBQ 16(SI), R10
SBBQ 24(SI), R11
CMOVQCC AX, R12
CMOVQCC AX, R13
CMOVQCC AX, R14
CMOVQCC AX, R15
ADDQ R12, R8
ADCQ R13, R9
ADCQ R14, R10
ADCQ R15, R11
MOVQ c+0(FP), DI
storeBlock(R8,R9,R10,R11, 0(DI))
RET
TEXT ·gfpMul(SB),0,$160-24
MOVQ a+8(FP), DI
MOVQ b+16(FP), SI
// Jump to a slightly different implementation if MULX isn't supported.
CMPB runtime·support_bmi2(SB), $0
JE nobmi2Mul
mulBMI2(0(DI),8(DI),16(DI),24(DI), 0(SI))
storeBlock( R8, R9,R10,R11, 0(SP))
storeBlock(R12,R13,R14,R15, 32(SP))
gfpReduceBMI2()
JMP end
nobmi2Mul:
mul(0(DI),8(DI),16(DI),24(DI), 0(SI), 0(SP))
gfpReduce(0(SP))
end:
MOVQ c+0(FP), DI
storeBlock(R12,R13,R14,R15, 0(DI))
RET

View file

@ -1,7 +1,3 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package bn256 package bn256
// For details of the algorithms used, see "Multiplication and Squaring on // For details of the algorithms used, see "Multiplication and Squaring on
@ -15,25 +11,16 @@ import (
// gfP12 implements the field of size p¹² as a quadratic extension of gfP6 // gfP12 implements the field of size p¹² as a quadratic extension of gfP6
// where ω²=τ. // where ω²=τ.
type gfP12 struct { type gfP12 struct {
x, y *gfP6 // value is xω + y x, y gfP6 // value is xω + y
}
func newGFp12(pool *bnPool) *gfP12 {
return &gfP12{newGFp6(pool), newGFp6(pool)}
} }
func (e *gfP12) String() string { func (e *gfP12) String() string {
return "(" + e.x.String() + "," + e.y.String() + ")" return "(" + e.x.String() + "," + e.y.String() + ")"
} }
func (e *gfP12) Put(pool *bnPool) {
e.x.Put(pool)
e.y.Put(pool)
}
func (e *gfP12) Set(a *gfP12) *gfP12 { func (e *gfP12) Set(a *gfP12) *gfP12 {
e.x.Set(a.x) e.x.Set(&a.x)
e.y.Set(a.y) e.y.Set(&a.y)
return e return e
} }
@ -49,152 +36,125 @@ func (e *gfP12) SetOne() *gfP12 {
return e return e
} }
func (e *gfP12) Minimal() {
e.x.Minimal()
e.y.Minimal()
}
func (e *gfP12) IsZero() bool { func (e *gfP12) IsZero() bool {
e.Minimal()
return e.x.IsZero() && e.y.IsZero() return e.x.IsZero() && e.y.IsZero()
} }
func (e *gfP12) IsOne() bool { func (e *gfP12) IsOne() bool {
e.Minimal()
return e.x.IsZero() && e.y.IsOne() return e.x.IsZero() && e.y.IsOne()
} }
func (e *gfP12) Conjugate(a *gfP12) *gfP12 { func (e *gfP12) Conjugate(a *gfP12) *gfP12 {
e.x.Negative(a.x) e.x.Neg(&a.x)
e.y.Set(a.y) e.y.Set(&a.y)
return a return e
} }
func (e *gfP12) Negative(a *gfP12) *gfP12 { func (e *gfP12) Neg(a *gfP12) *gfP12 {
e.x.Negative(a.x) e.x.Neg(&a.x)
e.y.Negative(a.y) e.y.Neg(&a.y)
return e return e
} }
// Frobenius computes (xω+y)^p = x^p ω·ξ^((p-1)/6) + y^p // Frobenius computes (xω+y)^p = x^p ω·ξ^((p-1)/6) + y^p
func (e *gfP12) Frobenius(a *gfP12, pool *bnPool) *gfP12 { func (e *gfP12) Frobenius(a *gfP12) *gfP12 {
e.x.Frobenius(a.x, pool) e.x.Frobenius(&a.x)
e.y.Frobenius(a.y, pool) e.y.Frobenius(&a.y)
e.x.MulScalar(e.x, xiToPMinus1Over6, pool) e.x.MulScalar(&e.x, xiToPMinus1Over6)
return e return e
} }
// FrobeniusP2 computes (xω+y)^p² = x^p² ω·ξ^((p²-1)/6) + y^p² // FrobeniusP2 computes (xω+y)^p² = x^p² ω·ξ^((p²-1)/6) + y^p²
func (e *gfP12) FrobeniusP2(a *gfP12, pool *bnPool) *gfP12 { func (e *gfP12) FrobeniusP2(a *gfP12) *gfP12 {
e.x.FrobeniusP2(a.x) e.x.FrobeniusP2(&a.x)
e.x.MulGFP(e.x, xiToPSquaredMinus1Over6) e.x.MulGFP(&e.x, xiToPSquaredMinus1Over6)
e.y.FrobeniusP2(a.y) e.y.FrobeniusP2(&a.y)
return e
}
func (e *gfP12) FrobeniusP4(a *gfP12) *gfP12 {
e.x.FrobeniusP4(&a.x)
e.x.MulGFP(&e.x, xiToPSquaredMinus1Over3)
e.y.FrobeniusP4(&a.y)
return e return e
} }
func (e *gfP12) Add(a, b *gfP12) *gfP12 { func (e *gfP12) Add(a, b *gfP12) *gfP12 {
e.x.Add(a.x, b.x) e.x.Add(&a.x, &b.x)
e.y.Add(a.y, b.y) e.y.Add(&a.y, &b.y)
return e return e
} }
func (e *gfP12) Sub(a, b *gfP12) *gfP12 { func (e *gfP12) Sub(a, b *gfP12) *gfP12 {
e.x.Sub(a.x, b.x) e.x.Sub(&a.x, &b.x)
e.y.Sub(a.y, b.y) e.y.Sub(&a.y, &b.y)
return e return e
} }
func (e *gfP12) Mul(a, b *gfP12, pool *bnPool) *gfP12 { func (e *gfP12) Mul(a, b *gfP12) *gfP12 {
tx := newGFp6(pool) tx := (&gfP6{}).Mul(&a.x, &b.y)
tx.Mul(a.x, b.y, pool) t := (&gfP6{}).Mul(&b.x, &a.y)
t := newGFp6(pool)
t.Mul(b.x, a.y, pool)
tx.Add(tx, t) tx.Add(tx, t)
ty := newGFp6(pool) ty := (&gfP6{}).Mul(&a.y, &b.y)
ty.Mul(a.y, b.y, pool) t.Mul(&a.x, &b.x).MulTau(t)
t.Mul(a.x, b.x, pool)
t.MulTau(t, pool)
e.y.Add(ty, t)
e.x.Set(tx) e.x.Set(tx)
e.y.Add(ty, t)
tx.Put(pool)
ty.Put(pool)
t.Put(pool)
return e return e
} }
func (e *gfP12) MulScalar(a *gfP12, b *gfP6, pool *bnPool) *gfP12 { func (e *gfP12) MulScalar(a *gfP12, b *gfP6) *gfP12 {
e.x.Mul(e.x, b, pool) e.x.Mul(&e.x, b)
e.y.Mul(e.y, b, pool) e.y.Mul(&e.y, b)
return e return e
} }
func (c *gfP12) Exp(a *gfP12, power *big.Int, pool *bnPool) *gfP12 { func (c *gfP12) Exp(a *gfP12, power *big.Int) *gfP12 {
sum := newGFp12(pool) sum := (&gfP12{}).SetOne()
sum.SetOne() t := &gfP12{}
t := newGFp12(pool)
for i := power.BitLen() - 1; i >= 0; i-- { for i := power.BitLen() - 1; i >= 0; i-- {
t.Square(sum, pool) t.Square(sum)
if power.Bit(i) != 0 { if power.Bit(i) != 0 {
sum.Mul(t, a, pool) sum.Mul(t, a)
} else { } else {
sum.Set(t) sum.Set(t)
} }
} }
c.Set(sum) c.Set(sum)
sum.Put(pool)
t.Put(pool)
return c return c
} }
func (e *gfP12) Square(a *gfP12, pool *bnPool) *gfP12 { func (e *gfP12) Square(a *gfP12) *gfP12 {
// Complex squaring algorithm // Complex squaring algorithm
v0 := newGFp6(pool) v0 := (&gfP6{}).Mul(&a.x, &a.y)
v0.Mul(a.x, a.y, pool)
t := newGFp6(pool) t := (&gfP6{}).MulTau(&a.x)
t.MulTau(a.x, pool) t.Add(&a.y, t)
t.Add(a.y, t) ty := (&gfP6{}).Add(&a.x, &a.y)
ty := newGFp6(pool) ty.Mul(ty, t).Sub(ty, v0)
ty.Add(a.x, a.y) t.MulTau(v0)
ty.Mul(ty, t, pool)
ty.Sub(ty, v0)
t.MulTau(v0, pool)
ty.Sub(ty, t) ty.Sub(ty, t)
e.x.Add(v0, v0)
e.y.Set(ty) e.y.Set(ty)
e.x.Double(v0)
v0.Put(pool)
t.Put(pool)
ty.Put(pool)
return e return e
} }
func (e *gfP12) Invert(a *gfP12, pool *bnPool) *gfP12 { func (e *gfP12) Invert(a *gfP12) *gfP12 {
// See "Implementing cryptographic pairings", M. Scott, section 3.2. // See "Implementing cryptographic pairings", M. Scott, section 3.2.
// ftp://136.206.11.249/pub/crypto/pairings.pdf // ftp://136.206.11.249/pub/crypto/pairings.pdf
t1 := newGFp6(pool) t1, t2 := &gfP6{}, &gfP6{}
t2 := newGFp6(pool)
t1.Square(a.x, pool) t1.Square(&a.x)
t2.Square(a.y, pool) t2.Square(&a.y)
t1.MulTau(t1, pool) t1.MulTau(t1).Sub(t2, t1)
t1.Sub(t2, t1) t2.Invert(t1)
t2.Invert(t1, pool)
e.x.Negative(a.x)
e.y.Set(a.y)
e.MulScalar(e, t2, pool)
t1.Put(pool)
t2.Put(pool)
e.x.Neg(&a.x)
e.y.Set(&a.y)
e.MulScalar(e, t2)
return e return e
} }

View file

@ -1,227 +1,156 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package bn256 package bn256
// For details of the algorithms used, see "Multiplication and Squaring on // For details of the algorithms used, see "Multiplication and Squaring on
// Pairing-Friendly Fields, Devegili et al. // Pairing-Friendly Fields, Devegili et al.
// http://eprint.iacr.org/2006/471.pdf. // http://eprint.iacr.org/2006/471.pdf.
import ( // gfP2 implements a field of size p² as a quadratic extension of the base field
"math/big" // where i²=-1.
)
// gfP2 implements a field of size p² as a quadratic extension of the base
// field where i²=-1.
type gfP2 struct { type gfP2 struct {
x, y *big.Int // value is xi+y. x, y gfP // value is xi+y.
} }
func newGFp2(pool *bnPool) *gfP2 { func gfP2Decode(in *gfP2) *gfP2 {
return &gfP2{pool.Get(), pool.Get()} out := &gfP2{}
montDecode(&out.x, &in.x)
montDecode(&out.y, &in.y)
return out
} }
func (e *gfP2) String() string { func (e *gfP2) String() string {
x := new(big.Int).Mod(e.x, P) return "(" + e.x.String() + ", " + e.y.String() + ")"
y := new(big.Int).Mod(e.y, P)
return "(" + x.String() + "," + y.String() + ")"
}
func (e *gfP2) Put(pool *bnPool) {
pool.Put(e.x)
pool.Put(e.y)
} }
func (e *gfP2) Set(a *gfP2) *gfP2 { func (e *gfP2) Set(a *gfP2) *gfP2 {
e.x.Set(a.x) e.x.Set(&a.x)
e.y.Set(a.y) e.y.Set(&a.y)
return e return e
} }
func (e *gfP2) SetZero() *gfP2 { func (e *gfP2) SetZero() *gfP2 {
e.x.SetInt64(0) e.x = gfP{0}
e.y.SetInt64(0) e.y = gfP{0}
return e return e
} }
func (e *gfP2) SetOne() *gfP2 { func (e *gfP2) SetOne() *gfP2 {
e.x.SetInt64(0) e.x = gfP{0}
e.y.SetInt64(1) e.y = *newGFp(1)
return e return e
} }
func (e *gfP2) Minimal() {
if e.x.Sign() < 0 || e.x.Cmp(P) >= 0 {
e.x.Mod(e.x, P)
}
if e.y.Sign() < 0 || e.y.Cmp(P) >= 0 {
e.y.Mod(e.y, P)
}
}
func (e *gfP2) IsZero() bool { func (e *gfP2) IsZero() bool {
return e.x.Sign() == 0 && e.y.Sign() == 0 zero := gfP{0}
return e.x == zero && e.y == zero
} }
func (e *gfP2) IsOne() bool { func (e *gfP2) IsOne() bool {
if e.x.Sign() != 0 { zero, one := gfP{0}, *newGFp(1)
return false return e.x == zero && e.y == one
}
words := e.y.Bits()
return len(words) == 1 && words[0] == 1
} }
func (e *gfP2) Conjugate(a *gfP2) *gfP2 { func (e *gfP2) Conjugate(a *gfP2) *gfP2 {
e.y.Set(a.y) e.y.Set(&a.y)
e.x.Neg(a.x) gfpNeg(&e.x, &a.x)
return e return e
} }
func (e *gfP2) Negative(a *gfP2) *gfP2 { func (e *gfP2) Neg(a *gfP2) *gfP2 {
e.x.Neg(a.x) gfpNeg(&e.x, &a.x)
e.y.Neg(a.y) gfpNeg(&e.y, &a.y)
return e return e
} }
func (e *gfP2) Add(a, b *gfP2) *gfP2 { func (e *gfP2) Add(a, b *gfP2) *gfP2 {
e.x.Add(a.x, b.x) gfpAdd(&e.x, &a.x, &b.x)
e.y.Add(a.y, b.y) gfpAdd(&e.y, &a.y, &b.y)
return e return e
} }
func (e *gfP2) Sub(a, b *gfP2) *gfP2 { func (e *gfP2) Sub(a, b *gfP2) *gfP2 {
e.x.Sub(a.x, b.x) gfpSub(&e.x, &a.x, &b.x)
e.y.Sub(a.y, b.y) gfpSub(&e.y, &a.y, &b.y)
return e return e
} }
func (e *gfP2) Double(a *gfP2) *gfP2 {
e.x.Lsh(a.x, 1)
e.y.Lsh(a.y, 1)
return e
}
func (c *gfP2) Exp(a *gfP2, power *big.Int, pool *bnPool) *gfP2 {
sum := newGFp2(pool)
sum.SetOne()
t := newGFp2(pool)
for i := power.BitLen() - 1; i >= 0; i-- {
t.Square(sum, pool)
if power.Bit(i) != 0 {
sum.Mul(t, a, pool)
} else {
sum.Set(t)
}
}
c.Set(sum)
sum.Put(pool)
t.Put(pool)
return c
}
// See "Multiplication and Squaring in Pairing-Friendly Fields", // See "Multiplication and Squaring in Pairing-Friendly Fields",
// http://eprint.iacr.org/2006/471.pdf // http://eprint.iacr.org/2006/471.pdf
func (e *gfP2) Mul(a, b *gfP2, pool *bnPool) *gfP2 { func (e *gfP2) Mul(a, b *gfP2) *gfP2 {
tx := pool.Get().Mul(a.x, b.y) tx, t := &gfP{}, &gfP{}
t := pool.Get().Mul(b.x, a.y) gfpMul(tx, &a.x, &b.y)
tx.Add(tx, t) gfpMul(t, &b.x, &a.y)
tx.Mod(tx, P) gfpAdd(tx, tx, t)
ty := &gfP{}
gfpMul(ty, &a.y, &b.y)
gfpMul(t, &a.x, &b.x)
gfpSub(ty, ty, t)
ty := pool.Get().Mul(a.y, b.y)
t.Mul(a.x, b.x)
ty.Sub(ty, t)
e.y.Mod(ty, P)
e.x.Set(tx) e.x.Set(tx)
e.y.Set(ty)
pool.Put(tx)
pool.Put(ty)
pool.Put(t)
return e return e
} }
func (e *gfP2) MulScalar(a *gfP2, b *big.Int) *gfP2 { func (e *gfP2) MulScalar(a *gfP2, b *gfP) *gfP2 {
e.x.Mul(a.x, b) gfpMul(&e.x, &a.x, b)
e.y.Mul(a.y, b) gfpMul(&e.y, &a.y, b)
return e return e
} }
// MulXi sets e=ξa where ξ=i+9 and then returns e. // MulXi sets e=ξa where ξ=i+9 and then returns e.
func (e *gfP2) MulXi(a *gfP2, pool *bnPool) *gfP2 { func (e *gfP2) MulXi(a *gfP2) *gfP2 {
// (xi+y)(i+3) = (9x+y)i+(9y-x) // (xi+y)(i+9) = (9x+y)i+(9y-x)
tx := pool.Get().Lsh(a.x, 3) tx := &gfP{}
tx.Add(tx, a.x) gfpAdd(tx, &a.x, &a.x)
tx.Add(tx, a.y) gfpAdd(tx, tx, tx)
gfpAdd(tx, tx, tx)
gfpAdd(tx, tx, &a.x)
ty := pool.Get().Lsh(a.y, 3) gfpAdd(tx, tx, &a.y)
ty.Add(ty, a.y)
ty.Sub(ty, a.x) ty := &gfP{}
gfpAdd(ty, &a.y, &a.y)
gfpAdd(ty, ty, ty)
gfpAdd(ty, ty, ty)
gfpAdd(ty, ty, &a.y)
gfpSub(ty, ty, &a.x)
e.x.Set(tx) e.x.Set(tx)
e.y.Set(ty) e.y.Set(ty)
pool.Put(tx)
pool.Put(ty)
return e return e
} }
func (e *gfP2) Square(a *gfP2, pool *bnPool) *gfP2 { func (e *gfP2) Square(a *gfP2) *gfP2 {
// Complex squaring algorithm: // Complex squaring algorithm:
// (xi+b)² = (x+y)(y-x) + 2*i*x*y // (xi+y)² = (x+y)(y-x) + 2*i*x*y
t1 := pool.Get().Sub(a.y, a.x) tx, ty := &gfP{}, &gfP{}
t2 := pool.Get().Add(a.x, a.y) gfpSub(tx, &a.y, &a.x)
ty := pool.Get().Mul(t1, t2) gfpAdd(ty, &a.x, &a.y)
ty.Mod(ty, P) gfpMul(ty, tx, ty)
t1.Mul(a.x, a.y) gfpMul(tx, &a.x, &a.y)
t1.Lsh(t1, 1) gfpAdd(tx, tx, tx)
e.x.Mod(t1, P) e.x.Set(tx)
e.y.Set(ty) e.y.Set(ty)
pool.Put(t1)
pool.Put(t2)
pool.Put(ty)
return e return e
} }
func (e *gfP2) Invert(a *gfP2, pool *bnPool) *gfP2 { func (e *gfP2) Invert(a *gfP2) *gfP2 {
// See "Implementing cryptographic pairings", M. Scott, section 3.2. // See "Implementing cryptographic pairings", M. Scott, section 3.2.
// ftp://136.206.11.249/pub/crypto/pairings.pdf // ftp://136.206.11.249/pub/crypto/pairings.pdf
t := pool.Get() t1, t2 := &gfP{}, &gfP{}
t.Mul(a.y, a.y) gfpMul(t1, &a.x, &a.x)
t2 := pool.Get() gfpMul(t2, &a.y, &a.y)
t2.Mul(a.x, a.x) gfpAdd(t1, t1, t2)
t.Add(t, t2)
inv := pool.Get() inv := &gfP{}
inv.ModInverse(t, P) inv.Invert(t1)
e.x.Neg(a.x) gfpNeg(t1, &a.x)
e.x.Mul(e.x, inv)
e.x.Mod(e.x, P)
e.y.Mul(a.y, inv)
e.y.Mod(e.y, P)
pool.Put(t)
pool.Put(t2)
pool.Put(inv)
gfpMul(&e.x, t1, inv)
gfpMul(&e.y, &a.y, inv)
return e return e
} }
func (e *gfP2) Real() *big.Int {
return e.x
}
func (e *gfP2) Imag() *big.Int {
return e.y
}

View file

@ -1,41 +1,23 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package bn256 package bn256
// For details of the algorithms used, see "Multiplication and Squaring on // For details of the algorithms used, see "Multiplication and Squaring on
// Pairing-Friendly Fields, Devegili et al. // Pairing-Friendly Fields, Devegili et al.
// http://eprint.iacr.org/2006/471.pdf. // http://eprint.iacr.org/2006/471.pdf.
import (
"math/big"
)
// gfP6 implements the field of size p⁶ as a cubic extension of gfP2 where τ³=ξ // gfP6 implements the field of size p⁶ as a cubic extension of gfP2 where τ³=ξ
// and ξ=i+9. // and ξ=i+3.
type gfP6 struct { type gfP6 struct {
x, y, z *gfP2 // value is xτ² + yτ + z x, y, z gfP2 // value is xτ² + yτ + z
}
func newGFp6(pool *bnPool) *gfP6 {
return &gfP6{newGFp2(pool), newGFp2(pool), newGFp2(pool)}
} }
func (e *gfP6) String() string { func (e *gfP6) String() string {
return "(" + e.x.String() + "," + e.y.String() + "," + e.z.String() + ")" return "(" + e.x.String() + ", " + e.y.String() + ", " + e.z.String() + ")"
}
func (e *gfP6) Put(pool *bnPool) {
e.x.Put(pool)
e.y.Put(pool)
e.z.Put(pool)
} }
func (e *gfP6) Set(a *gfP6) *gfP6 { func (e *gfP6) Set(a *gfP6) *gfP6 {
e.x.Set(a.x) e.x.Set(&a.x)
e.y.Set(a.y) e.y.Set(&a.y)
e.z.Set(a.z) e.z.Set(&a.z)
return e return e
} }
@ -53,12 +35,6 @@ func (e *gfP6) SetOne() *gfP6 {
return e return e
} }
func (e *gfP6) Minimal() {
e.x.Minimal()
e.y.Minimal()
e.z.Minimal()
}
func (e *gfP6) IsZero() bool { func (e *gfP6) IsZero() bool {
return e.x.IsZero() && e.y.IsZero() && e.z.IsZero() return e.x.IsZero() && e.y.IsZero() && e.z.IsZero()
} }
@ -67,178 +43,132 @@ func (e *gfP6) IsOne() bool {
return e.x.IsZero() && e.y.IsZero() && e.z.IsOne() return e.x.IsZero() && e.y.IsZero() && e.z.IsOne()
} }
func (e *gfP6) Negative(a *gfP6) *gfP6 { func (e *gfP6) Neg(a *gfP6) *gfP6 {
e.x.Negative(a.x) e.x.Neg(&a.x)
e.y.Negative(a.y) e.y.Neg(&a.y)
e.z.Negative(a.z) e.z.Neg(&a.z)
return e return e
} }
func (e *gfP6) Frobenius(a *gfP6, pool *bnPool) *gfP6 { func (e *gfP6) Frobenius(a *gfP6) *gfP6 {
e.x.Conjugate(a.x) e.x.Conjugate(&a.x)
e.y.Conjugate(a.y) e.y.Conjugate(&a.y)
e.z.Conjugate(a.z) e.z.Conjugate(&a.z)
e.x.Mul(e.x, xiTo2PMinus2Over3, pool) e.x.Mul(&e.x, xiTo2PMinus2Over3)
e.y.Mul(e.y, xiToPMinus1Over3, pool) e.y.Mul(&e.y, xiToPMinus1Over3)
return e return e
} }
// FrobeniusP2 computes (xτ²+yτ+z)^(p²) = xτ^(2p²) + yτ^(p²) + z // FrobeniusP2 computes (xτ²+yτ+z)^(p²) = xτ^(2p²) + yτ^(p²) + z
func (e *gfP6) FrobeniusP2(a *gfP6) *gfP6 { func (e *gfP6) FrobeniusP2(a *gfP6) *gfP6 {
// τ^(2p²) = τ²τ^(2p²-2) = τ²ξ^((2p²-2)/3) // τ^(2p²) = τ²τ^(2p²-2) = τ²ξ^((2p²-2)/3)
e.x.MulScalar(a.x, xiTo2PSquaredMinus2Over3) e.x.MulScalar(&a.x, xiTo2PSquaredMinus2Over3)
// τ^(p²) = ττ^(p²-1) = τξ^((p²-1)/3) // τ^(p²) = ττ^(p²-1) = τξ^((p²-1)/3)
e.y.MulScalar(a.y, xiToPSquaredMinus1Over3) e.y.MulScalar(&a.y, xiToPSquaredMinus1Over3)
e.z.Set(a.z) e.z.Set(&a.z)
return e
}
func (e *gfP6) FrobeniusP4(a *gfP6) *gfP6 {
e.x.MulScalar(&a.x, xiToPSquaredMinus1Over3)
e.y.MulScalar(&a.y, xiTo2PSquaredMinus2Over3)
e.z.Set(&a.z)
return e return e
} }
func (e *gfP6) Add(a, b *gfP6) *gfP6 { func (e *gfP6) Add(a, b *gfP6) *gfP6 {
e.x.Add(a.x, b.x) e.x.Add(&a.x, &b.x)
e.y.Add(a.y, b.y) e.y.Add(&a.y, &b.y)
e.z.Add(a.z, b.z) e.z.Add(&a.z, &b.z)
return e return e
} }
func (e *gfP6) Sub(a, b *gfP6) *gfP6 { func (e *gfP6) Sub(a, b *gfP6) *gfP6 {
e.x.Sub(a.x, b.x) e.x.Sub(&a.x, &b.x)
e.y.Sub(a.y, b.y) e.y.Sub(&a.y, &b.y)
e.z.Sub(a.z, b.z) e.z.Sub(&a.z, &b.z)
return e return e
} }
func (e *gfP6) Double(a *gfP6) *gfP6 { func (e *gfP6) Mul(a, b *gfP6) *gfP6 {
e.x.Double(a.x)
e.y.Double(a.y)
e.z.Double(a.z)
return e
}
func (e *gfP6) Mul(a, b *gfP6, pool *bnPool) *gfP6 {
// "Multiplication and Squaring on Pairing-Friendly Fields" // "Multiplication and Squaring on Pairing-Friendly Fields"
// Section 4, Karatsuba method. // Section 4, Karatsuba method.
// http://eprint.iacr.org/2006/471.pdf // http://eprint.iacr.org/2006/471.pdf
v0 := (&gfP2{}).Mul(&a.z, &b.z)
v1 := (&gfP2{}).Mul(&a.y, &b.y)
v2 := (&gfP2{}).Mul(&a.x, &b.x)
v0 := newGFp2(pool) t0 := (&gfP2{}).Add(&a.x, &a.y)
v0.Mul(a.z, b.z, pool) t1 := (&gfP2{}).Add(&b.x, &b.y)
v1 := newGFp2(pool) tz := (&gfP2{}).Mul(t0, t1)
v1.Mul(a.y, b.y, pool) tz.Sub(tz, v1).Sub(tz, v2).MulXi(tz).Add(tz, v0)
v2 := newGFp2(pool)
v2.Mul(a.x, b.x, pool)
t0 := newGFp2(pool) t0.Add(&a.y, &a.z)
t0.Add(a.x, a.y) t1.Add(&b.y, &b.z)
t1 := newGFp2(pool) ty := (&gfP2{}).Mul(t0, t1)
t1.Add(b.x, b.y) t0.MulXi(v2)
tz := newGFp2(pool) ty.Sub(ty, v0).Sub(ty, v1).Add(ty, t0)
tz.Mul(t0, t1, pool)
tz.Sub(tz, v1) t0.Add(&a.x, &a.z)
tz.Sub(tz, v2) t1.Add(&b.x, &b.z)
tz.MulXi(tz, pool) tx := (&gfP2{}).Mul(t0, t1)
tz.Add(tz, v0) tx.Sub(tx, v0).Add(tx, v1).Sub(tx, v2)
t0.Add(a.y, a.z)
t1.Add(b.y, b.z)
ty := newGFp2(pool)
ty.Mul(t0, t1, pool)
ty.Sub(ty, v0)
ty.Sub(ty, v1)
t0.MulXi(v2, pool)
ty.Add(ty, t0)
t0.Add(a.x, a.z)
t1.Add(b.x, b.z)
tx := newGFp2(pool)
tx.Mul(t0, t1, pool)
tx.Sub(tx, v0)
tx.Add(tx, v1)
tx.Sub(tx, v2)
e.x.Set(tx) e.x.Set(tx)
e.y.Set(ty) e.y.Set(ty)
e.z.Set(tz) e.z.Set(tz)
t0.Put(pool)
t1.Put(pool)
tx.Put(pool)
ty.Put(pool)
tz.Put(pool)
v0.Put(pool)
v1.Put(pool)
v2.Put(pool)
return e return e
} }
func (e *gfP6) MulScalar(a *gfP6, b *gfP2, pool *bnPool) *gfP6 { func (e *gfP6) MulScalar(a *gfP6, b *gfP2) *gfP6 {
e.x.Mul(a.x, b, pool) e.x.Mul(&a.x, b)
e.y.Mul(a.y, b, pool) e.y.Mul(&a.y, b)
e.z.Mul(a.z, b, pool) e.z.Mul(&a.z, b)
return e return e
} }
func (e *gfP6) MulGFP(a *gfP6, b *big.Int) *gfP6 { func (e *gfP6) MulGFP(a *gfP6, b *gfP) *gfP6 {
e.x.MulScalar(a.x, b) e.x.MulScalar(&a.x, b)
e.y.MulScalar(a.y, b) e.y.MulScalar(&a.y, b)
e.z.MulScalar(a.z, b) e.z.MulScalar(&a.z, b)
return e return e
} }
// MulTau computes τ·(aτ²+bτ+c) = bτ²+cτ+aξ // MulTau computes τ·(aτ²+bτ+c) = bτ²+cτ+aξ
func (e *gfP6) MulTau(a *gfP6, pool *bnPool) { func (e *gfP6) MulTau(a *gfP6) *gfP6 {
tz := newGFp2(pool) tz := (&gfP2{}).MulXi(&a.x)
tz.MulXi(a.x, pool) ty := (&gfP2{}).Set(&a.y)
ty := newGFp2(pool)
ty.Set(a.y) e.y.Set(&a.z)
e.y.Set(a.z)
e.x.Set(ty) e.x.Set(ty)
e.z.Set(tz) e.z.Set(tz)
tz.Put(pool) return e
ty.Put(pool)
} }
func (e *gfP6) Square(a *gfP6, pool *bnPool) *gfP6 { func (e *gfP6) Square(a *gfP6) *gfP6 {
v0 := newGFp2(pool).Square(a.z, pool) v0 := (&gfP2{}).Square(&a.z)
v1 := newGFp2(pool).Square(a.y, pool) v1 := (&gfP2{}).Square(&a.y)
v2 := newGFp2(pool).Square(a.x, pool) v2 := (&gfP2{}).Square(&a.x)
c0 := newGFp2(pool).Add(a.x, a.y) c0 := (&gfP2{}).Add(&a.x, &a.y)
c0.Square(c0, pool) c0.Square(c0).Sub(c0, v1).Sub(c0, v2).MulXi(c0).Add(c0, v0)
c0.Sub(c0, v1)
c0.Sub(c0, v2)
c0.MulXi(c0, pool)
c0.Add(c0, v0)
c1 := newGFp2(pool).Add(a.y, a.z) c1 := (&gfP2{}).Add(&a.y, &a.z)
c1.Square(c1, pool) c1.Square(c1).Sub(c1, v0).Sub(c1, v1)
c1.Sub(c1, v0) xiV2 := (&gfP2{}).MulXi(v2)
c1.Sub(c1, v1)
xiV2 := newGFp2(pool).MulXi(v2, pool)
c1.Add(c1, xiV2) c1.Add(c1, xiV2)
c2 := newGFp2(pool).Add(a.x, a.z) c2 := (&gfP2{}).Add(&a.x, &a.z)
c2.Square(c2, pool) c2.Square(c2).Sub(c2, v0).Add(c2, v1).Sub(c2, v2)
c2.Sub(c2, v0)
c2.Add(c2, v1)
c2.Sub(c2, v2)
e.x.Set(c2) e.x.Set(c2)
e.y.Set(c1) e.y.Set(c1)
e.z.Set(c0) e.z.Set(c0)
v0.Put(pool)
v1.Put(pool)
v2.Put(pool)
c0.Put(pool)
c1.Put(pool)
c2.Put(pool)
xiV2.Put(pool)
return e return e
} }
func (e *gfP6) Invert(a *gfP6, pool *bnPool) *gfP6 { func (e *gfP6) Invert(a *gfP6) *gfP6 {
// See "Implementing cryptographic pairings", M. Scott, section 3.2. // See "Implementing cryptographic pairings", M. Scott, section 3.2.
// ftp://136.206.11.249/pub/crypto/pairings.pdf // ftp://136.206.11.249/pub/crypto/pairings.pdf
@ -252,45 +182,32 @@ func (e *gfP6) Invert(a *gfP6, pool *bnPool) *gfP6 {
// = τ²(y²-ξxz) + τ(ξx²-yz) + (z²-ξxy) // = τ²(y²-ξxz) + τ(ξx²-yz) + (z²-ξxy)
// //
// So that's why A = (z²-ξxy), B = (ξx²-yz), C = (y²-ξxz) // So that's why A = (z²-ξxy), B = (ξx²-yz), C = (y²-ξxz)
t1 := newGFp2(pool) t1 := (&gfP2{}).Mul(&a.x, &a.y)
t1.MulXi(t1)
A := newGFp2(pool) A := (&gfP2{}).Square(&a.z)
A.Square(a.z, pool)
t1.Mul(a.x, a.y, pool)
t1.MulXi(t1, pool)
A.Sub(A, t1) A.Sub(A, t1)
B := newGFp2(pool) B := (&gfP2{}).Square(&a.x)
B.Square(a.x, pool) B.MulXi(B)
B.MulXi(B, pool) t1.Mul(&a.y, &a.z)
t1.Mul(a.y, a.z, pool)
B.Sub(B, t1) B.Sub(B, t1)
C_ := newGFp2(pool) C := (&gfP2{}).Square(&a.y)
C_.Square(a.y, pool) t1.Mul(&a.x, &a.z)
t1.Mul(a.x, a.z, pool) C.Sub(C, t1)
C_.Sub(C_, t1)
F := newGFp2(pool) F := (&gfP2{}).Mul(C, &a.y)
F.Mul(C_, a.y, pool) F.MulXi(F)
F.MulXi(F, pool) t1.Mul(A, &a.z)
t1.Mul(A, a.z, pool)
F.Add(F, t1) F.Add(F, t1)
t1.Mul(B, a.x, pool) t1.Mul(B, &a.x).MulXi(t1)
t1.MulXi(t1, pool)
F.Add(F, t1) F.Add(F, t1)
F.Invert(F, pool) F.Invert(F)
e.x.Mul(C_, F, pool)
e.y.Mul(B, F, pool)
e.z.Mul(A, F, pool)
t1.Put(pool)
A.Put(pool)
B.Put(pool)
C_.Put(pool)
F.Put(pool)
e.x.Mul(C, F)
e.y.Mul(B, F)
e.z.Mul(A, F)
return e return e
} }

181
crypto/bn256/mul.h Normal file
View file

@ -0,0 +1,181 @@
#define mul(a0,a1,a2,a3, rb, stack) \
MOVQ a0, AX \
MULQ 0+rb \
MOVQ AX, R8 \
MOVQ DX, R9 \
MOVQ a0, AX \
MULQ 8+rb \
ADDQ AX, R9 \
ADCQ $0, DX \
MOVQ DX, R10 \
MOVQ a0, AX \
MULQ 16+rb \
ADDQ AX, R10 \
ADCQ $0, DX \
MOVQ DX, R11 \
MOVQ a0, AX \
MULQ 24+rb \
ADDQ AX, R11 \
ADCQ $0, DX \
MOVQ DX, R12 \
\
storeBlock(R8,R9,R10,R11, 0+stack) \
MOVQ R12, 32+stack \
\
MOVQ a1, AX \
MULQ 0+rb \
MOVQ AX, R8 \
MOVQ DX, R9 \
MOVQ a1, AX \
MULQ 8+rb \
ADDQ AX, R9 \
ADCQ $0, DX \
MOVQ DX, R10 \
MOVQ a1, AX \
MULQ 16+rb \
ADDQ AX, R10 \
ADCQ $0, DX \
MOVQ DX, R11 \
MOVQ a1, AX \
MULQ 24+rb \
ADDQ AX, R11 \
ADCQ $0, DX \
MOVQ DX, R12 \
\
ADDQ 8+stack, R8 \
ADCQ 16+stack, R9 \
ADCQ 24+stack, R10 \
ADCQ 32+stack, R11 \
ADCQ $0, R12 \
storeBlock(R8,R9,R10,R11, 8+stack) \
MOVQ R12, 40+stack \
\
MOVQ a2, AX \
MULQ 0+rb \
MOVQ AX, R8 \
MOVQ DX, R9 \
MOVQ a2, AX \
MULQ 8+rb \
ADDQ AX, R9 \
ADCQ $0, DX \
MOVQ DX, R10 \
MOVQ a2, AX \
MULQ 16+rb \
ADDQ AX, R10 \
ADCQ $0, DX \
MOVQ DX, R11 \
MOVQ a2, AX \
MULQ 24+rb \
ADDQ AX, R11 \
ADCQ $0, DX \
MOVQ DX, R12 \
\
ADDQ 16+stack, R8 \
ADCQ 24+stack, R9 \
ADCQ 32+stack, R10 \
ADCQ 40+stack, R11 \
ADCQ $0, R12 \
storeBlock(R8,R9,R10,R11, 16+stack) \
MOVQ R12, 48+stack \
\
MOVQ a3, AX \
MULQ 0+rb \
MOVQ AX, R8 \
MOVQ DX, R9 \
MOVQ a3, AX \
MULQ 8+rb \
ADDQ AX, R9 \
ADCQ $0, DX \
MOVQ DX, R10 \
MOVQ a3, AX \
MULQ 16+rb \
ADDQ AX, R10 \
ADCQ $0, DX \
MOVQ DX, R11 \
MOVQ a3, AX \
MULQ 24+rb \
ADDQ AX, R11 \
ADCQ $0, DX \
MOVQ DX, R12 \
\
ADDQ 24+stack, R8 \
ADCQ 32+stack, R9 \
ADCQ 40+stack, R10 \
ADCQ 48+stack, R11 \
ADCQ $0, R12 \
storeBlock(R8,R9,R10,R11, 24+stack) \
MOVQ R12, 56+stack
#define gfpReduce(stack) \
\ // m = (T * N') mod R, store m in R8:R9:R10:R11
MOVQ ·np+0(SB), AX \
MULQ 0+stack \
MOVQ AX, R8 \
MOVQ DX, R9 \
MOVQ ·np+0(SB), AX \
MULQ 8+stack \
ADDQ AX, R9 \
ADCQ $0, DX \
MOVQ DX, R10 \
MOVQ ·np+0(SB), AX \
MULQ 16+stack \
ADDQ AX, R10 \
ADCQ $0, DX \
MOVQ DX, R11 \
MOVQ ·np+0(SB), AX \
MULQ 24+stack \
ADDQ AX, R11 \
\
MOVQ ·np+8(SB), AX \
MULQ 0+stack \
MOVQ AX, R12 \
MOVQ DX, R13 \
MOVQ ·np+8(SB), AX \
MULQ 8+stack \
ADDQ AX, R13 \
ADCQ $0, DX \
MOVQ DX, R14 \
MOVQ ·np+8(SB), AX \
MULQ 16+stack \
ADDQ AX, R14 \
\
ADDQ R12, R9 \
ADCQ R13, R10 \
ADCQ R14, R11 \
\
MOVQ ·np+16(SB), AX \
MULQ 0+stack \
MOVQ AX, R12 \
MOVQ DX, R13 \
MOVQ ·np+16(SB), AX \
MULQ 8+stack \
ADDQ AX, R13 \
\
ADDQ R12, R10 \
ADCQ R13, R11 \
\
MOVQ ·np+24(SB), AX \
MULQ 0+stack \
ADDQ AX, R11 \
\
storeBlock(R8,R9,R10,R11, 64+stack) \
\
\ // m * N
mul(·p2+0(SB),·p2+8(SB),·p2+16(SB),·p2+24(SB), 64+stack, 96+stack) \
\
\ // Add the 512-bit intermediate to m*N
loadBlock(96+stack, R8,R9,R10,R11) \
loadBlock(128+stack, R12,R13,R14,R15) \
\
MOVQ $0, AX \
ADDQ 0+stack, R8 \
ADCQ 8+stack, R9 \
ADCQ 16+stack, R10 \
ADCQ 24+stack, R11 \
ADCQ 32+stack, R12 \
ADCQ 40+stack, R13 \
ADCQ 48+stack, R14 \
ADCQ 56+stack, R15 \
ADCQ $0, AX \
\
gfpCarry(R12,R13,R14,R15,AX, R8,R9,R10,R11,BX)

112
crypto/bn256/mul_bmi2.h Normal file
View file

@ -0,0 +1,112 @@
#define mulBMI2(a0,a1,a2,a3, rb) \
MOVQ a0, DX \
MOVQ $0, R13 \
MULXQ 0+rb, R8, R9 \
MULXQ 8+rb, AX, R10 \
ADDQ AX, R9 \
MULXQ 16+rb, AX, R11 \
ADCQ AX, R10 \
MULXQ 24+rb, AX, R12 \
ADCQ AX, R11 \
ADCQ $0, R12 \
ADCQ $0, R13 \
\
MOVQ a1, DX \
MOVQ $0, R14 \
MULXQ 0+rb, AX, BX \
ADDQ AX, R9 \
ADCQ BX, R10 \
MULXQ 16+rb, AX, BX \
ADCQ AX, R11 \
ADCQ BX, R12 \
ADCQ $0, R13 \
MULXQ 8+rb, AX, BX \
ADDQ AX, R10 \
ADCQ BX, R11 \
MULXQ 24+rb, AX, BX \
ADCQ AX, R12 \
ADCQ BX, R13 \
ADCQ $0, R14 \
\
MOVQ a2, DX \
MOVQ $0, R15 \
MULXQ 0+rb, AX, BX \
ADDQ AX, R10 \
ADCQ BX, R11 \
MULXQ 16+rb, AX, BX \
ADCQ AX, R12 \
ADCQ BX, R13 \
ADCQ $0, R14 \
MULXQ 8+rb, AX, BX \
ADDQ AX, R11 \
ADCQ BX, R12 \
MULXQ 24+rb, AX, BX \
ADCQ AX, R13 \
ADCQ BX, R14 \
ADCQ $0, R15 \
\
MOVQ a3, DX \
MULXQ 0+rb, AX, BX \
ADDQ AX, R11 \
ADCQ BX, R12 \
MULXQ 16+rb, AX, BX \
ADCQ AX, R13 \
ADCQ BX, R14 \
ADCQ $0, R15 \
MULXQ 8+rb, AX, BX \
ADDQ AX, R12 \
ADCQ BX, R13 \
MULXQ 24+rb, AX, BX \
ADCQ AX, R14 \
ADCQ BX, R15
#define gfpReduceBMI2() \
\ // m = (T * N') mod R, store m in R8:R9:R10:R11
MOVQ ·np+0(SB), DX \
MULXQ 0(SP), R8, R9 \
MULXQ 8(SP), AX, R10 \
ADDQ AX, R9 \
MULXQ 16(SP), AX, R11 \
ADCQ AX, R10 \
MULXQ 24(SP), AX, BX \
ADCQ AX, R11 \
\
MOVQ ·np+8(SB), DX \
MULXQ 0(SP), AX, BX \
ADDQ AX, R9 \
ADCQ BX, R10 \
MULXQ 16(SP), AX, BX \
ADCQ AX, R11 \
MULXQ 8(SP), AX, BX \
ADDQ AX, R10 \
ADCQ BX, R11 \
\
MOVQ ·np+16(SB), DX \
MULXQ 0(SP), AX, BX \
ADDQ AX, R10 \
ADCQ BX, R11 \
MULXQ 8(SP), AX, BX \
ADDQ AX, R11 \
\
MOVQ ·np+24(SB), DX \
MULXQ 0(SP), AX, BX \
ADDQ AX, R11 \
\
storeBlock(R8,R9,R10,R11, 64(SP)) \
\
\ // m * N
mulBMI2(·p2+0(SB),·p2+8(SB),·p2+16(SB),·p2+24(SB), 64(SP)) \
\
\ // Add the 512-bit intermediate to m*N
MOVQ $0, AX \
ADDQ 0(SP), R8 \
ADCQ 8(SP), R9 \
ADCQ 16(SP), R10 \
ADCQ 24(SP), R11 \
ADCQ 32(SP), R12 \
ADCQ 40(SP), R13 \
ADCQ 48(SP), R14 \
ADCQ 56(SP), R15 \
ADCQ $0, AX \
\
gfpCarry(R12,R13,R14,R15,AX, R8,R9,R10,R11,BX)

View file

@ -1,184 +1,114 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package bn256 package bn256
func lineFunctionAdd(r, p *twistPoint, q *curvePoint, r2 *gfP2, pool *bnPool) (a, b, c *gfP2, rOut *twistPoint) { func lineFunctionAdd(r, p *twistPoint, q *curvePoint, r2 *gfP2) (a, b, c *gfP2, rOut *twistPoint) {
// See the mixed addition algorithm from "Faster Computation of the // See the mixed addition algorithm from "Faster Computation of the
// Tate Pairing", http://arxiv.org/pdf/0904.0854v3.pdf // Tate Pairing", http://arxiv.org/pdf/0904.0854v3.pdf
B := (&gfP2{}).Mul(&p.x, &r.t)
B := newGFp2(pool).Mul(p.x, r.t, pool) D := (&gfP2{}).Add(&p.y, &r.z)
D.Square(D).Sub(D, r2).Sub(D, &r.t).Mul(D, &r.t)
D := newGFp2(pool).Add(p.y, r.z) H := (&gfP2{}).Sub(B, &r.x)
D.Square(D, pool) I := (&gfP2{}).Square(H)
D.Sub(D, r2)
D.Sub(D, r.t)
D.Mul(D, r.t, pool)
H := newGFp2(pool).Sub(B, r.x) E := (&gfP2{}).Add(I, I)
I := newGFp2(pool).Square(H, pool)
E := newGFp2(pool).Add(I, I)
E.Add(E, E) E.Add(E, E)
J := newGFp2(pool).Mul(H, E, pool) J := (&gfP2{}).Mul(H, E)
L1 := newGFp2(pool).Sub(D, r.y) L1 := (&gfP2{}).Sub(D, &r.y)
L1.Sub(L1, r.y) L1.Sub(L1, &r.y)
V := newGFp2(pool).Mul(r.x, E, pool) V := (&gfP2{}).Mul(&r.x, E)
rOut = newTwistPoint(pool) rOut = &twistPoint{}
rOut.x.Square(L1, pool) rOut.x.Square(L1).Sub(&rOut.x, J).Sub(&rOut.x, V).Sub(&rOut.x, V)
rOut.x.Sub(rOut.x, J)
rOut.x.Sub(rOut.x, V)
rOut.x.Sub(rOut.x, V)
rOut.z.Add(r.z, H) rOut.z.Add(&r.z, H).Square(&rOut.z).Sub(&rOut.z, &r.t).Sub(&rOut.z, I)
rOut.z.Square(rOut.z, pool)
rOut.z.Sub(rOut.z, r.t)
rOut.z.Sub(rOut.z, I)
t := newGFp2(pool).Sub(V, rOut.x) t := (&gfP2{}).Sub(V, &rOut.x)
t.Mul(t, L1, pool) t.Mul(t, L1)
t2 := newGFp2(pool).Mul(r.y, J, pool) t2 := (&gfP2{}).Mul(&r.y, J)
t2.Add(t2, t2) t2.Add(t2, t2)
rOut.y.Sub(t, t2) rOut.y.Sub(t, t2)
rOut.t.Square(rOut.z, pool) rOut.t.Square(&rOut.z)
t.Add(p.y, rOut.z) t.Add(&p.y, &rOut.z).Square(t).Sub(t, r2).Sub(t, &rOut.t)
t.Square(t, pool)
t.Sub(t, r2)
t.Sub(t, rOut.t)
t2.Mul(L1, p.x, pool) t2.Mul(L1, &p.x)
t2.Add(t2, t2) t2.Add(t2, t2)
a = newGFp2(pool) a = (&gfP2{}).Sub(t2, t)
a.Sub(t2, t)
c = newGFp2(pool) c = (&gfP2{}).MulScalar(&rOut.z, &q.y)
c.MulScalar(rOut.z, q.y)
c.Add(c, c) c.Add(c, c)
b = newGFp2(pool) b = (&gfP2{}).Neg(L1)
b.SetZero() b.MulScalar(b, &q.x).Add(b, b)
b.Sub(b, L1)
b.MulScalar(b, q.x)
b.Add(b, b)
B.Put(pool)
D.Put(pool)
H.Put(pool)
I.Put(pool)
E.Put(pool)
J.Put(pool)
L1.Put(pool)
V.Put(pool)
t.Put(pool)
t2.Put(pool)
return return
} }
func lineFunctionDouble(r *twistPoint, q *curvePoint, pool *bnPool) (a, b, c *gfP2, rOut *twistPoint) { func lineFunctionDouble(r *twistPoint, q *curvePoint) (a, b, c *gfP2, rOut *twistPoint) {
// See the doubling algorithm for a=0 from "Faster Computation of the // See the doubling algorithm for a=0 from "Faster Computation of the
// Tate Pairing", http://arxiv.org/pdf/0904.0854v3.pdf // Tate Pairing", http://arxiv.org/pdf/0904.0854v3.pdf
A := (&gfP2{}).Square(&r.x)
B := (&gfP2{}).Square(&r.y)
C := (&gfP2{}).Square(B)
A := newGFp2(pool).Square(r.x, pool) D := (&gfP2{}).Add(&r.x, B)
B := newGFp2(pool).Square(r.y, pool) D.Square(D).Sub(D, A).Sub(D, C).Add(D, D)
C_ := newGFp2(pool).Square(B, pool)
D := newGFp2(pool).Add(r.x, B) E := (&gfP2{}).Add(A, A)
D.Square(D, pool)
D.Sub(D, A)
D.Sub(D, C_)
D.Add(D, D)
E := newGFp2(pool).Add(A, A)
E.Add(E, A) E.Add(E, A)
G := newGFp2(pool).Square(E, pool) G := (&gfP2{}).Square(E)
rOut = newTwistPoint(pool) rOut = &twistPoint{}
rOut.x.Sub(G, D) rOut.x.Sub(G, D).Sub(&rOut.x, D)
rOut.x.Sub(rOut.x, D)
rOut.z.Add(r.y, r.z) rOut.z.Add(&r.y, &r.z).Square(&rOut.z).Sub(&rOut.z, B).Sub(&rOut.z, &r.t)
rOut.z.Square(rOut.z, pool)
rOut.z.Sub(rOut.z, B)
rOut.z.Sub(rOut.z, r.t)
rOut.y.Sub(D, rOut.x) rOut.y.Sub(D, &rOut.x).Mul(&rOut.y, E)
rOut.y.Mul(rOut.y, E, pool) t := (&gfP2{}).Add(C, C)
t := newGFp2(pool).Add(C_, C_) t.Add(t, t).Add(t, t)
t.Add(t, t) rOut.y.Sub(&rOut.y, t)
t.Add(t, t)
rOut.y.Sub(rOut.y, t)
rOut.t.Square(rOut.z, pool) rOut.t.Square(&rOut.z)
t.Mul(E, r.t, pool) t.Mul(E, &r.t).Add(t, t)
t.Add(t, t) b = (&gfP2{}).Neg(t)
b = newGFp2(pool) b.MulScalar(b, &q.x)
b.SetZero()
b.Sub(b, t)
b.MulScalar(b, q.x)
a = newGFp2(pool) a = (&gfP2{}).Add(&r.x, E)
a.Add(r.x, E) a.Square(a).Sub(a, A).Sub(a, G)
a.Square(a, pool) t.Add(B, B).Add(t, t)
a.Sub(a, A)
a.Sub(a, G)
t.Add(B, B)
t.Add(t, t)
a.Sub(a, t) a.Sub(a, t)
c = newGFp2(pool) c = (&gfP2{}).Mul(&rOut.z, &r.t)
c.Mul(rOut.z, r.t, pool) c.Add(c, c).MulScalar(c, &q.y)
c.Add(c, c)
c.MulScalar(c, q.y)
A.Put(pool)
B.Put(pool)
C_.Put(pool)
D.Put(pool)
E.Put(pool)
G.Put(pool)
t.Put(pool)
return return
} }
func mulLine(ret *gfP12, a, b, c *gfP2, pool *bnPool) { func mulLine(ret *gfP12, a, b, c *gfP2) {
a2 := newGFp6(pool) a2 := &gfP6{}
a2.x.SetZero()
a2.y.Set(a) a2.y.Set(a)
a2.z.Set(b) a2.z.Set(b)
a2.Mul(a2, ret.x, pool) a2.Mul(a2, &ret.x)
t3 := newGFp6(pool).MulScalar(ret.y, c, pool) t3 := (&gfP6{}).MulScalar(&ret.y, c)
t := newGFp2(pool) t := (&gfP2{}).Add(b, c)
t.Add(b, c) t2 := &gfP6{}
t2 := newGFp6(pool)
t2.x.SetZero()
t2.y.Set(a) t2.y.Set(a)
t2.z.Set(t) t2.z.Set(t)
ret.x.Add(ret.x, ret.y) ret.x.Add(&ret.x, &ret.y)
ret.y.Set(t3) ret.y.Set(t3)
ret.x.Mul(ret.x, t2, pool) ret.x.Mul(&ret.x, t2).Sub(&ret.x, a2).Sub(&ret.x, &ret.y)
ret.x.Sub(ret.x, a2) a2.MulTau(a2)
ret.x.Sub(ret.x, ret.y) ret.y.Add(&ret.y, a2)
a2.MulTau(a2, pool)
ret.y.Add(ret.y, a2)
a2.Put(pool)
t3.Put(pool)
t2.Put(pool)
t.Put(pool)
} }
// sixuPlus2NAF is 6u+2 in non-adjacent form. // sixuPlus2NAF is 6u+2 in non-adjacent form.
@ -189,54 +119,44 @@ var sixuPlus2NAF = []int8{0, 0, 0, 1, 0, 1, 0, -1, 0, 0, 1, -1, 0, 0, 1, 0,
// miller implements the Miller loop for calculating the Optimal Ate pairing. // miller implements the Miller loop for calculating the Optimal Ate pairing.
// See algorithm 1 from http://cryptojedi.org/papers/dclxvi-20100714.pdf // See algorithm 1 from http://cryptojedi.org/papers/dclxvi-20100714.pdf
func miller(q *twistPoint, p *curvePoint, pool *bnPool) *gfP12 { func miller(q *twistPoint, p *curvePoint) *gfP12 {
ret := newGFp12(pool) ret := (&gfP12{}).SetOne()
ret.SetOne()
aAffine := newTwistPoint(pool) aAffine := &twistPoint{}
aAffine.Set(q) aAffine.Set(q)
aAffine.MakeAffine(pool) aAffine.MakeAffine()
bAffine := newCurvePoint(pool) bAffine := &curvePoint{}
bAffine.Set(p) bAffine.Set(p)
bAffine.MakeAffine(pool) bAffine.MakeAffine()
minusA := newTwistPoint(pool) minusA := &twistPoint{}
minusA.Negative(aAffine, pool) minusA.Neg(aAffine)
r := newTwistPoint(pool) r := &twistPoint{}
r.Set(aAffine) r.Set(aAffine)
r2 := newGFp2(pool) r2 := (&gfP2{}).Square(&aAffine.y)
r2.Square(aAffine.y, pool)
for i := len(sixuPlus2NAF) - 1; i > 0; i-- { for i := len(sixuPlus2NAF) - 1; i > 0; i-- {
a, b, c, newR := lineFunctionDouble(r, bAffine, pool) a, b, c, newR := lineFunctionDouble(r, bAffine)
if i != len(sixuPlus2NAF)-1 { if i != len(sixuPlus2NAF)-1 {
ret.Square(ret, pool) ret.Square(ret)
} }
mulLine(ret, a, b, c, pool) mulLine(ret, a, b, c)
a.Put(pool)
b.Put(pool)
c.Put(pool)
r.Put(pool)
r = newR r = newR
switch sixuPlus2NAF[i-1] { switch sixuPlus2NAF[i-1] {
case 1: case 1:
a, b, c, newR = lineFunctionAdd(r, aAffine, bAffine, r2, pool) a, b, c, newR = lineFunctionAdd(r, aAffine, bAffine, r2)
case -1: case -1:
a, b, c, newR = lineFunctionAdd(r, minusA, bAffine, r2, pool) a, b, c, newR = lineFunctionAdd(r, minusA, bAffine, r2)
default: default:
continue continue
} }
mulLine(ret, a, b, c, pool) mulLine(ret, a, b, c)
a.Put(pool)
b.Put(pool)
c.Put(pool)
r.Put(pool)
r = newR r = newR
} }
@ -255,11 +175,9 @@ func miller(q *twistPoint, p *curvePoint, pool *bnPool) *gfP12 {
// //
// A similar argument can be made for the y value. // A similar argument can be made for the y value.
q1 := newTwistPoint(pool) q1 := &twistPoint{}
q1.x.Conjugate(aAffine.x) q1.x.Conjugate(&aAffine.x).Mul(&q1.x, xiToPMinus1Over3)
q1.x.Mul(q1.x, xiToPMinus1Over3, pool) q1.y.Conjugate(&aAffine.y).Mul(&q1.y, xiToPMinus1Over2)
q1.y.Conjugate(aAffine.y)
q1.y.Mul(q1.y, xiToPMinus1Over2, pool)
q1.z.SetOne() q1.z.SetOne()
q1.t.SetOne() q1.t.SetOne()
@ -269,126 +187,82 @@ func miller(q *twistPoint, p *curvePoint, pool *bnPool) *gfP12 {
// xiToPSquaredMinus1Over3 is ∈ GF(p). With y we get a factor of -1. We // xiToPSquaredMinus1Over3 is ∈ GF(p). With y we get a factor of -1. We
// ignore this to end up with -Q2. // ignore this to end up with -Q2.
minusQ2 := newTwistPoint(pool) minusQ2 := &twistPoint{}
minusQ2.x.MulScalar(aAffine.x, xiToPSquaredMinus1Over3) minusQ2.x.MulScalar(&aAffine.x, xiToPSquaredMinus1Over3)
minusQ2.y.Set(aAffine.y) minusQ2.y.Set(&aAffine.y)
minusQ2.z.SetOne() minusQ2.z.SetOne()
minusQ2.t.SetOne() minusQ2.t.SetOne()
r2.Square(q1.y, pool) r2.Square(&q1.y)
a, b, c, newR := lineFunctionAdd(r, q1, bAffine, r2, pool) a, b, c, newR := lineFunctionAdd(r, q1, bAffine, r2)
mulLine(ret, a, b, c, pool) mulLine(ret, a, b, c)
a.Put(pool)
b.Put(pool)
c.Put(pool)
r.Put(pool)
r = newR r = newR
r2.Square(minusQ2.y, pool) r2.Square(&minusQ2.y)
a, b, c, newR = lineFunctionAdd(r, minusQ2, bAffine, r2, pool) a, b, c, newR = lineFunctionAdd(r, minusQ2, bAffine, r2)
mulLine(ret, a, b, c, pool) mulLine(ret, a, b, c)
a.Put(pool)
b.Put(pool)
c.Put(pool)
r.Put(pool)
r = newR r = newR
aAffine.Put(pool)
bAffine.Put(pool)
minusA.Put(pool)
r.Put(pool)
r2.Put(pool)
return ret return ret
} }
// finalExponentiation computes the (p¹²-1)/Order-th power of an element of // finalExponentiation computes the (p¹²-1)/Order-th power of an element of
// GF(p¹²) to obtain an element of GT (steps 13-15 of algorithm 1 from // GF(p¹²) to obtain an element of GT (steps 13-15 of algorithm 1 from
// http://cryptojedi.org/papers/dclxvi-20100714.pdf) // http://cryptojedi.org/papers/dclxvi-20100714.pdf)
func finalExponentiation(in *gfP12, pool *bnPool) *gfP12 { func finalExponentiation(in *gfP12) *gfP12 {
t1 := newGFp12(pool) t1 := &gfP12{}
// This is the p^6-Frobenius // This is the p^6-Frobenius
t1.x.Negative(in.x) t1.x.Neg(&in.x)
t1.y.Set(in.y) t1.y.Set(&in.y)
inv := newGFp12(pool) inv := &gfP12{}
inv.Invert(in, pool) inv.Invert(in)
t1.Mul(t1, inv, pool) t1.Mul(t1, inv)
t2 := newGFp12(pool).FrobeniusP2(t1, pool) t2 := (&gfP12{}).FrobeniusP2(t1)
t1.Mul(t1, t2, pool) t1.Mul(t1, t2)
fp := newGFp12(pool).Frobenius(t1, pool) fp := (&gfP12{}).Frobenius(t1)
fp2 := newGFp12(pool).FrobeniusP2(t1, pool) fp2 := (&gfP12{}).FrobeniusP2(t1)
fp3 := newGFp12(pool).Frobenius(fp2, pool) fp3 := (&gfP12{}).Frobenius(fp2)
fu, fu2, fu3 := newGFp12(pool), newGFp12(pool), newGFp12(pool) fu := (&gfP12{}).Exp(t1, u)
fu.Exp(t1, u, pool) fu2 := (&gfP12{}).Exp(fu, u)
fu2.Exp(fu, u, pool) fu3 := (&gfP12{}).Exp(fu2, u)
fu3.Exp(fu2, u, pool)
y3 := newGFp12(pool).Frobenius(fu, pool) y3 := (&gfP12{}).Frobenius(fu)
fu2p := newGFp12(pool).Frobenius(fu2, pool) fu2p := (&gfP12{}).Frobenius(fu2)
fu3p := newGFp12(pool).Frobenius(fu3, pool) fu3p := (&gfP12{}).Frobenius(fu3)
y2 := newGFp12(pool).FrobeniusP2(fu2, pool) y2 := (&gfP12{}).FrobeniusP2(fu2)
y0 := newGFp12(pool) y0 := &gfP12{}
y0.Mul(fp, fp2, pool) y0.Mul(fp, fp2).Mul(y0, fp3)
y0.Mul(y0, fp3, pool)
y1, y4, y5 := newGFp12(pool), newGFp12(pool), newGFp12(pool) y1 := (&gfP12{}).Conjugate(t1)
y1.Conjugate(t1) y5 := (&gfP12{}).Conjugate(fu2)
y5.Conjugate(fu2)
y3.Conjugate(y3) y3.Conjugate(y3)
y4.Mul(fu, fu2p, pool) y4 := (&gfP12{}).Mul(fu, fu2p)
y4.Conjugate(y4) y4.Conjugate(y4)
y6 := newGFp12(pool) y6 := (&gfP12{}).Mul(fu3, fu3p)
y6.Mul(fu3, fu3p, pool)
y6.Conjugate(y6) y6.Conjugate(y6)
t0 := newGFp12(pool) t0 := (&gfP12{}).Square(y6)
t0.Square(y6, pool) t0.Mul(t0, y4).Mul(t0, y5)
t0.Mul(t0, y4, pool) t1.Mul(y3, y5).Mul(t1, t0)
t0.Mul(t0, y5, pool) t0.Mul(t0, y2)
t1.Mul(y3, y5, pool) t1.Square(t1).Mul(t1, t0).Square(t1)
t1.Mul(t1, t0, pool) t0.Mul(t1, y1)
t0.Mul(t0, y2, pool) t1.Mul(t1, y0)
t1.Square(t1, pool) t0.Square(t0).Mul(t0, t1)
t1.Mul(t1, t0, pool)
t1.Square(t1, pool)
t0.Mul(t1, y1, pool)
t1.Mul(t1, y0, pool)
t0.Square(t0, pool)
t0.Mul(t0, t1, pool)
inv.Put(pool)
t1.Put(pool)
t2.Put(pool)
fp.Put(pool)
fp2.Put(pool)
fp3.Put(pool)
fu.Put(pool)
fu2.Put(pool)
fu3.Put(pool)
fu2p.Put(pool)
fu3p.Put(pool)
y0.Put(pool)
y1.Put(pool)
y2.Put(pool)
y3.Put(pool)
y4.Put(pool)
y5.Put(pool)
y6.Put(pool)
return t0 return t0
} }
func optimalAte(a *twistPoint, b *curvePoint, pool *bnPool) *gfP12 { func optimalAte(a *twistPoint, b *curvePoint) *gfP12 {
e := miller(a, b, pool) e := miller(a, b)
ret := finalExponentiation(e, pool) ret := finalExponentiation(e)
e.Put(pool)
if a.IsInfinity() || b.IsInfinity() { if a.IsInfinity() || b.IsInfinity() {
ret.SetOne() ret.SetOne()

View file

@ -1,7 +1,3 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package bn256 package bn256
import ( import (
@ -12,82 +8,72 @@ import (
// kept in Jacobian form and t=z² when valid. The group G₂ is the set of // kept in Jacobian form and t=z² when valid. The group G₂ is the set of
// n-torsion points of this curve over GF(p²) (where n = Order) // n-torsion points of this curve over GF(p²) (where n = Order)
type twistPoint struct { type twistPoint struct {
x, y, z, t *gfP2 x, y, z, t gfP2
} }
var twistB = &gfP2{ var twistB = &gfP2{
bigFromBase10("266929791119991161246907387137283842545076965332900288569378510910307636690"), gfP{0x38e7ecccd1dcff67, 0x65f0b37d93ce0d3e, 0xd749d0dd22ac00aa, 0x0141b9ce4a688d4d},
bigFromBase10("19485874751759354771024239261021720505790618469301721065564631296452457478373"), gfP{0x3bf938e377b802a8, 0x020b1b273633535d, 0x26b7edf049755260, 0x2514c6324384a86d},
} }
// twistGen is the generator of group G₂. // twistGen is the generator of group G₂.
var twistGen = &twistPoint{ var twistGen = &twistPoint{
&gfP2{ gfP2{
bigFromBase10("11559732032986387107991004021392285783925812861821192530917403151452391805634"), gfP{0xafb4737da84c6140, 0x6043dd5a5802d8c4, 0x09e950fc52a02f86, 0x14fef0833aea7b6b},
bigFromBase10("10857046999023057135944570762232829481370756359578518086990519993285655852781"), gfP{0x8e83b5d102bc2026, 0xdceb1935497b0172, 0xfbb8264797811adf, 0x19573841af96503b},
}, },
&gfP2{ gfP2{
bigFromBase10("4082367875863433681332203403145435568316851327593401208105741076214120093531"), gfP{0x64095b56c71856ee, 0xdc57f922327d3cbb, 0x55f935be33351076, 0x0da4a0e693fd6482},
bigFromBase10("8495653923123431417604973247489272438418190587263600148770280649306958101930"), gfP{0x619dfa9d886be9f6, 0xfe7fd297f59e9b78, 0xff9e1a62231b7dfe, 0x28fd7eebae9e4206},
}, },
&gfP2{ gfP2{*newGFp(0), *newGFp(1)},
bigFromBase10("0"), gfP2{*newGFp(0), *newGFp(1)},
bigFromBase10("1"),
},
&gfP2{
bigFromBase10("0"),
bigFromBase10("1"),
},
}
func newTwistPoint(pool *bnPool) *twistPoint {
return &twistPoint{
newGFp2(pool),
newGFp2(pool),
newGFp2(pool),
newGFp2(pool),
}
} }
func (c *twistPoint) String() string { func (c *twistPoint) String() string {
return "(" + c.x.String() + ", " + c.y.String() + ", " + c.z.String() + ")" c.MakeAffine()
} x, y := gfP2Decode(&c.x), gfP2Decode(&c.y)
return "(" + x.String() + ", " + y.String() + ")"
func (c *twistPoint) Put(pool *bnPool) {
c.x.Put(pool)
c.y.Put(pool)
c.z.Put(pool)
c.t.Put(pool)
} }
func (c *twistPoint) Set(a *twistPoint) { func (c *twistPoint) Set(a *twistPoint) {
c.x.Set(a.x) c.x.Set(&a.x)
c.y.Set(a.y) c.y.Set(&a.y)
c.z.Set(a.z) c.z.Set(&a.z)
c.t.Set(a.t) c.t.Set(&a.t)
} }
// IsOnCurve returns true iff c is on the curve where c must be in affine form. // IsOnCurve returns true iff c is on the curve.
func (c *twistPoint) IsOnCurve() bool { func (c *twistPoint) IsOnCurve() bool {
pool := new(bnPool) c.MakeAffine()
yy := newGFp2(pool).Square(c.y, pool) if c.IsInfinity() {
xxx := newGFp2(pool).Square(c.x, pool) return true
xxx.Mul(xxx, c.x, pool) }
yy.Sub(yy, xxx)
yy.Sub(yy, twistB) y2, x3 := &gfP2{}, &gfP2{}
yy.Minimal() y2.Square(&c.y)
return yy.x.Sign() == 0 && yy.y.Sign() == 0 x3.Square(&c.x).Mul(x3, &c.x).Add(x3, twistB)
if *y2 != *x3 {
return false
}
cneg := &twistPoint{}
cneg.Mul(c, Order)
return cneg.z.IsZero()
} }
func (c *twistPoint) SetInfinity() { func (c *twistPoint) SetInfinity() {
c.x.SetZero()
c.y.SetOne()
c.z.SetZero() c.z.SetZero()
c.t.SetZero()
} }
func (c *twistPoint) IsInfinity() bool { func (c *twistPoint) IsInfinity() bool {
return c.z.IsZero() return c.z.IsZero()
} }
func (c *twistPoint) Add(a, b *twistPoint, pool *bnPool) { func (c *twistPoint) Add(a, b *twistPoint) {
// For additional comments, see the same function in curve.go. // For additional comments, see the same function in curve.go.
if a.IsInfinity() { if a.IsInfinity() {
@ -100,150 +86,119 @@ func (c *twistPoint) Add(a, b *twistPoint, pool *bnPool) {
} }
// See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/addition/add-2007-bl.op3 // See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/addition/add-2007-bl.op3
z1z1 := newGFp2(pool).Square(a.z, pool) z12 := (&gfP2{}).Square(&a.z)
z2z2 := newGFp2(pool).Square(b.z, pool) z22 := (&gfP2{}).Square(&b.z)
u1 := newGFp2(pool).Mul(a.x, z2z2, pool) u1 := (&gfP2{}).Mul(&a.x, z22)
u2 := newGFp2(pool).Mul(b.x, z1z1, pool) u2 := (&gfP2{}).Mul(&b.x, z12)
t := newGFp2(pool).Mul(b.z, z2z2, pool) t := (&gfP2{}).Mul(&b.z, z22)
s1 := newGFp2(pool).Mul(a.y, t, pool) s1 := (&gfP2{}).Mul(&a.y, t)
t.Mul(a.z, z1z1, pool) t.Mul(&a.z, z12)
s2 := newGFp2(pool).Mul(b.y, t, pool) s2 := (&gfP2{}).Mul(&b.y, t)
h := newGFp2(pool).Sub(u2, u1) h := (&gfP2{}).Sub(u2, u1)
xEqual := h.IsZero() xEqual := h.IsZero()
t.Add(h, h) t.Add(h, h)
i := newGFp2(pool).Square(t, pool) i := (&gfP2{}).Square(t)
j := newGFp2(pool).Mul(h, i, pool) j := (&gfP2{}).Mul(h, i)
t.Sub(s2, s1) t.Sub(s2, s1)
yEqual := t.IsZero() yEqual := t.IsZero()
if xEqual && yEqual { if xEqual && yEqual {
c.Double(a, pool) c.Double(a)
return return
} }
r := newGFp2(pool).Add(t, t) r := (&gfP2{}).Add(t, t)
v := newGFp2(pool).Mul(u1, i, pool) v := (&gfP2{}).Mul(u1, i)
t4 := newGFp2(pool).Square(r, pool) t4 := (&gfP2{}).Square(r)
t.Add(v, v) t.Add(v, v)
t6 := newGFp2(pool).Sub(t4, j) t6 := (&gfP2{}).Sub(t4, j)
c.x.Sub(t6, t) c.x.Sub(t6, t)
t.Sub(v, c.x) // t7 t.Sub(v, &c.x) // t7
t4.Mul(s1, j, pool) // t8 t4.Mul(s1, j) // t8
t6.Add(t4, t4) // t9 t6.Add(t4, t4) // t9
t4.Mul(r, t, pool) // t10 t4.Mul(r, t) // t10
c.y.Sub(t4, t6) c.y.Sub(t4, t6)
t.Add(a.z, b.z) // t11 t.Add(&a.z, &b.z) // t11
t4.Square(t, pool) // t12 t4.Square(t) // t12
t.Sub(t4, z1z1) // t13 t.Sub(t4, z12) // t13
t4.Sub(t, z2z2) // t14 t4.Sub(t, z22) // t14
c.z.Mul(t4, h, pool) c.z.Mul(t4, h)
z1z1.Put(pool)
z2z2.Put(pool)
u1.Put(pool)
u2.Put(pool)
t.Put(pool)
s1.Put(pool)
s2.Put(pool)
h.Put(pool)
i.Put(pool)
j.Put(pool)
r.Put(pool)
v.Put(pool)
t4.Put(pool)
t6.Put(pool)
} }
func (c *twistPoint) Double(a *twistPoint, pool *bnPool) { func (c *twistPoint) Double(a *twistPoint) {
// See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/doubling/dbl-2009-l.op3 // See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/doubling/dbl-2009-l.op3
A := newGFp2(pool).Square(a.x, pool) A := (&gfP2{}).Square(&a.x)
B := newGFp2(pool).Square(a.y, pool) B := (&gfP2{}).Square(&a.y)
C_ := newGFp2(pool).Square(B, pool) C := (&gfP2{}).Square(B)
t := newGFp2(pool).Add(a.x, B) t := (&gfP2{}).Add(&a.x, B)
t2 := newGFp2(pool).Square(t, pool) t2 := (&gfP2{}).Square(t)
t.Sub(t2, A) t.Sub(t2, A)
t2.Sub(t, C_) t2.Sub(t, C)
d := newGFp2(pool).Add(t2, t2) d := (&gfP2{}).Add(t2, t2)
t.Add(A, A) t.Add(A, A)
e := newGFp2(pool).Add(t, A) e := (&gfP2{}).Add(t, A)
f := newGFp2(pool).Square(e, pool) f := (&gfP2{}).Square(e)
t.Add(d, d) t.Add(d, d)
c.x.Sub(f, t) c.x.Sub(f, t)
t.Add(C_, C_) t.Add(C, C)
t2.Add(t, t) t2.Add(t, t)
t.Add(t2, t2) t.Add(t2, t2)
c.y.Sub(d, c.x) c.y.Sub(d, &c.x)
t2.Mul(e, c.y, pool) t2.Mul(e, &c.y)
c.y.Sub(t2, t) c.y.Sub(t2, t)
t.Mul(a.y, a.z, pool) t.Mul(&a.y, &a.z)
c.z.Add(t, t) c.z.Add(t, t)
A.Put(pool)
B.Put(pool)
C_.Put(pool)
t.Put(pool)
t2.Put(pool)
d.Put(pool)
e.Put(pool)
f.Put(pool)
} }
func (c *twistPoint) Mul(a *twistPoint, scalar *big.Int, pool *bnPool) *twistPoint { func (c *twistPoint) Mul(a *twistPoint, scalar *big.Int) {
sum := newTwistPoint(pool) sum, t := &twistPoint{}, &twistPoint{}
sum.SetInfinity()
t := newTwistPoint(pool)
for i := scalar.BitLen(); i >= 0; i-- { for i := scalar.BitLen(); i >= 0; i-- {
t.Double(sum, pool) t.Double(sum)
if scalar.Bit(i) != 0 { if scalar.Bit(i) != 0 {
sum.Add(t, a, pool) sum.Add(t, a)
} else { } else {
sum.Set(t) sum.Set(t)
} }
} }
c.Set(sum) c.Set(sum)
sum.Put(pool)
t.Put(pool)
return c
} }
func (c *twistPoint) MakeAffine(pool *bnPool) *twistPoint { func (c *twistPoint) MakeAffine() {
if c.z.IsOne() { if c.z.IsOne() {
return c return
} else if c.z.IsZero() {
c.x.SetZero()
c.y.SetOne()
c.t.SetZero()
return
} }
zInv := newGFp2(pool).Invert(c.z, pool) zInv := (&gfP2{}).Invert(&c.z)
t := newGFp2(pool).Mul(c.y, zInv, pool) t := (&gfP2{}).Mul(&c.y, zInv)
zInv2 := newGFp2(pool).Square(zInv, pool) zInv2 := (&gfP2{}).Square(zInv)
c.y.Mul(t, zInv2, pool) c.y.Mul(t, zInv2)
t.Mul(c.x, zInv2, pool) t.Mul(&c.x, zInv2)
c.x.Set(t) c.x.Set(t)
c.z.SetOne() c.z.SetOne()
c.t.SetOne() c.t.SetOne()
zInv.Put(pool)
t.Put(pool)
zInv2.Put(pool)
return c
} }
func (c *twistPoint) Negative(a *twistPoint, pool *bnPool) { func (c *twistPoint) Neg(a *twistPoint) {
c.x.Set(a.x) c.x.Set(&a.x)
c.y.SetZero() c.y.Neg(&a.y)
c.y.Sub(c.y, a.y) c.z.Set(&a.z)
c.z.Set(a.z)
c.t.SetZero() c.t.SetZero()
} }