init: v1.0.0

This commit is contained in:
yaole
2026-05-27 23:03:00 +08:00
commit 8d97f750eb
466 changed files with 80067 additions and 0 deletions
+44
View File
@@ -0,0 +1,44 @@
bn256
-----
Package bn256 implements a particular bilinear group.
Bilinear groups are the basis of many of the new cryptographic protocols that
have been proposed over the past decade. They consist of a triplet of groups
(G₁, G₂ and GT) such that there exists a function e(g₁ˣ,g₂ʸ)=gTˣʸ (where gₓ is a
generator of the respective group). That function is called a pairing function.
This package specifically implements the Optimal Ate pairing over a 256-bit
Barreto-Naehrig curve as described in
http://cryptojedi.org/papers/dclxvi-20100714.pdf. Its output is compatible with
the implementation described in that paper.
This package previously claimed to operate at a 128-bit security level. However,
recent improvements in attacks mean that is no longer true. See
https://moderncrypto.org/mail-archive/curves/2016/000740.html.
### Benchmarks
branch `master`:
```
BenchmarkG1-4 10000 154995 ns/op
BenchmarkG2-4 3000 541503 ns/op
BenchmarkGT-4 1000 1267811 ns/op
BenchmarkPairing-4 1000 1630584 ns/op
```
branch `lattices`:
```
BenchmarkG1-4 20000 92198 ns/op
BenchmarkG2-4 5000 340622 ns/op
BenchmarkGT-4 2000 635061 ns/op
BenchmarkPairing-4 1000 1629943 ns/op
```
official version:
```
BenchmarkG1-4 1000 2268491 ns/op
BenchmarkG2-4 300 7227637 ns/op
BenchmarkGT-4 100 15121359 ns/op
BenchmarkPairing-4 50 20296164 ns/op
```
+162
View File
@@ -0,0 +1,162 @@
package bn256
import (
"encoding/asn1"
"golang.org/x/crypto/cryptobyte"
"xdx.jelly/xgcl/gerrors"
"xdx.jelly/xgcl/sm/sm9/errors"
)
// return the bytes 04||x||y or 02(03)||x
func MarshalG1(p *G1, compressed bool) []byte {
data := make([]byte, 2*numBytes+1)
// infinity point is encoded as '00'
if p.IsInfinity() {
return []byte{0}
}
data[0] = 4
copy(data[1:], p.Marshal())
if compressed {
data[0] = 2 + data[2*numBytes]&1
data = data[:1+numBytes]
}
return data
}
func UnmarshalG1(p *G1, b []byte) (rest []byte, err error) {
// infinity case
if b[0] == 0 {
p.SetInfinity()
return b[1:], nil
}
if ((b[0] == 2 || b[0] == 3) && (len(b) < 1+numBytes)) ||
((b[0] == 4 || b[0] == 6 || b[0] == 7) && (len(b) < 1+2*numBytes)) {
return b, gerrors.WithAnnotating(errors.ErrDecodeASN1Failed, "parse G1 ASN.1 data failed")
}
switch b[0] {
case 2:
_, _ = p.UnmarshalCompressed(b[1:1+numBytes], 0)
b = b[1+numBytes:]
case 3:
_, _ = p.UnmarshalCompressed(b[1:1+numBytes], 1)
b = b[1+numBytes:]
case 6, 7:
if (b[0] & 1) != b[len(b)-1]&1 {
return b, gerrors.WithAnnotating(errors.ErrDecodeASN1Failed, "parse G1 ASN.1 data failed")
}
fallthrough
case 4:
_, err := p.Unmarshal(b[1:])
if err != nil {
return b, gerrors.WithAnnotating(errors.ErrDecodeASN1Failed, "parse G1 ASN.1 data failed")
}
b = b[1+2*numBytes:]
default:
return b, gerrors.WithAnnotating(errors.ErrDecodeASN1Failed, "parse G1 ASN.1 data failed, the leading byte of a EC point must be 2,3,4,6 or 7")
}
return b, nil
}
func MarshalG2(p *G2, compressed bool) []byte {
data := make([]byte, 4*numBytes+1)
// infinity case, the point is encoded as '00'
if p.IsInfinity() {
return []byte{0}
}
data[0] = 4
copy(data[1:], p.Marshal())
if compressed {
data[0] = 2 + data[4*numBytes]&1
data = data[:1+2*numBytes]
}
return data
}
func UnmarshalG2(p *G2, b []byte) (rest []byte, err error) {
// infinity case
if b[0] == 0 {
p.SetInfinity()
return b[1:], nil
}
if ((b[0] == 2 || b[0] == 3) && (len(b) < 1+2*numBytes)) ||
((b[0] == 4 || b[0] == 6 || b[0] == 7) && (len(b) < 1+4*numBytes)) {
return b, gerrors.WithAnnotating(errors.ErrDecodeASN1Failed, "parse G2 ASN.1 data failed")
}
switch b[0] {
case 2:
_, _ = p.UnmarshalCompressed(b[1:1+numBytes], b[1+numBytes:1+2*numBytes], 0)
b = b[1+2*numBytes:]
case 3:
_, _ = p.UnmarshalCompressed(b[1:1+numBytes], b[1+numBytes:1+2*numBytes], 1)
b = b[1+2*numBytes:]
case 6, 7:
if (b[0] & 1) != b[len(b)-1]&1 {
return b, gerrors.WithAnnotating(errors.ErrDecodeASN1Failed, "parse G2 ASN.1 data failed, the leading byte of a EC point must be 2,3,4,6 or 7")
}
fallthrough
case 4:
_, err := p.Unmarshal(b[1:])
if err != nil {
return b, gerrors.WithAnnotating(errors.ErrDecodeASN1Failed, "parse G2 ASN.1 data failed")
}
b = b[1+4*numBytes:]
default:
return b, gerrors.WithAnnotating(errors.ErrDecodeASN1Failed, "parse G2 ASN.1 data failed, the leading byte of a EC point must be 2,3,4,6 or 7")
}
return b, nil
}
// //////////////////////////////////////////////////////////////
//
// ASN.1 编解码G1,G2,
//
// //////////////////////////////////////////////////////////////
func (g *G1) MarshalASN1(compressed bool) ([]byte, error) {
var b cryptobyte.Builder
b.AddASN1BitString(MarshalG1(g, compressed))
return b.Bytes()
}
// UnmarshalASN1 ASN.1解码MastSignPublicKey
//
// 注:支持tag为0,2,3,4,6,7即无穷远点(0),非压缩形式(4),压缩形式(2,3),混合形式(6,7)
func (g *G1) UnmarshalASN1(data []byte) (rest []byte, err error) {
input := cryptobyte.String(data)
var b asn1.BitString
if ok := input.ReadASN1BitString(&b); !ok {
return data, gerrors.WithAnnotating(errors.ErrDecodeASN1Failed, "parse G1 ASN.1 data failed")
}
_, err = UnmarshalG1(g, b.RightAlign())
if err != nil {
return data, err
}
return []byte(input), nil
}
func (g *G2) MarshalASN1(compressed bool) ([]byte, error) {
var b cryptobyte.Builder
b.AddASN1BitString(MarshalG2(g, compressed))
return b.Bytes()
}
// UnmarshalASN1 ASN.1解码MastSignPublicKey
//
// 注:支持tag为0,2,3,4,6,7即无穷远点(0),非压缩形式(4),压缩形式(2,3),混合形式(6,7)
func (g *G2) UnmarshalASN1(data []byte) (rest []byte, err error) {
input := cryptobyte.String(data)
var b asn1.BitString
if ok := input.ReadASN1BitString(&b); !ok {
return data, gerrors.WithAnnotating(errors.ErrDecodeASN1Failed, "parse G2 ASN.1 data failed")
}
_, err = UnmarshalG2(g, b.RightAlign())
if err != nil {
return data, err
}
return []byte(input), nil
}
+179
View File
@@ -0,0 +1,179 @@
package bn256
/*
Benchmark Result:
goos: darwin
goarch: arm64
pkg: xdx.jelly/xgcl/sm/sm9/internal/bn256
BenchmarkGFpAdd
BenchmarkGFpAdd-10 469129488 2.532 ns/op 0 B/op 0 allocs/op
BenchmarkGFpMul
BenchmarkGFpMul-10 71532715 16.08 ns/op 0 B/op 0 allocs/op
BenchmarkGFp2Add
BenchmarkGFp2Add-10 201261476 5.944 ns/op 0 B/op 0 allocs/op
BenchmarkGFp2Mul
BenchmarkGFp2Mul-10 15537591 74.29 ns/op 0 B/op 0 allocs/op
BenchmarkGFp6Add
BenchmarkGFp6Add-10 61707891 19.06 ns/op 0 B/op 0 allocs/op
BenchmarkGFp6Mul
BenchmarkGFp6Mul-10 2176302 551.0 ns/op 0 B/op 0 allocs/op
BenchmarkGFp12Add
BenchmarkGFp12Add-10 29860556 39.36 ns/op 0 B/op 0 allocs/op
BenchmarkGFp12Mul
BenchmarkGFp12Mul-10 517333 2276 ns/op 0 B/op 0 allocs/op
BenchmarkPairing
BenchmarkPairing-10 1660 712120 ns/op 0 B/op 0 allocs/op
BenchmarkG1BaseMul
BenchmarkG1BaseMul-10 78440 15443 ns/op 0 B/op 0 allocs/op
BenchmarkG2BaseMul
BenchmarkG2BaseMul-10 22156 53968 ns/op 0 B/op 0 allocs/op
BenchmarkGTBaseMul
BenchmarkGTBaseMul-10 22365 53395 ns/op 0 B/op 0 allocs/op
PASS
ok xdx.jelly/xgcl/sm/sm9/internal/bn256 17.212s
*/
import (
"crypto/rand"
"testing"
"xdx.jelly/xgcl/grand"
)
func BenchmarkGFpAdd(b *testing.B) {
x := &gfP{}
y := &gfP{}
z := &gfP{}
x.random(grand.Reader)
y.random(grand.Reader)
b.ResetTimer()
for n := 0; n < b.N; n++ {
gfpAdd(z, x, y)
}
}
func BenchmarkGFpMul(b *testing.B) {
x := gfPFromBigInt(randomInt(rand.Reader, P))
y := gfPFromBigInt(randomInt(rand.Reader, P))
z := &gfP{}
b.ResetTimer()
for n := 0; n < b.N; n++ {
gfpMul(z, x, y)
}
}
func BenchmarkGFp2Add(b *testing.B) {
x := &gfP2{}
y := &gfP2{}
z := &gfP2{}
x.random(grand.Reader)
y.random(grand.Reader)
b.ResetTimer()
for n := 0; n < b.N; n++ {
z.Add(x, y)
}
}
func BenchmarkGFp2Mul(b *testing.B) {
x := &gfP2{}
y := &gfP2{}
z := &gfP2{}
x.random(grand.Reader)
y.random(grand.Reader)
b.ResetTimer()
for n := 0; n < b.N; n++ {
z.Mul(x, y)
}
}
func BenchmarkGFp6Add(b *testing.B) {
x := &gfP6{}
y := &gfP6{}
z := &gfP6{}
x.random(grand.Reader)
y.random(grand.Reader)
b.ResetTimer()
for n := 0; n < b.N; n++ {
z.Add(x, y)
}
}
func BenchmarkGFp6Mul(b *testing.B) {
x := &gfP6{}
y := &gfP6{}
z := &gfP6{}
x.random(grand.Reader)
y.random(grand.Reader)
b.ResetTimer()
for n := 0; n < b.N; n++ {
z.Mul(x, y)
}
}
func BenchmarkGFp12Add(b *testing.B) {
x := &gfP12{}
y := &gfP12{}
z := &gfP12{}
x.random(grand.Reader)
y.random(grand.Reader)
b.ResetTimer()
for n := 0; n < b.N; n++ {
z.Add(x, y)
}
}
func BenchmarkGFp12Mul(b *testing.B) {
x := &gfP12{}
y := &gfP12{}
z := &gfP12{}
x.random(grand.Reader)
y.random(grand.Reader)
b.ResetTimer()
for n := 0; n < b.N; n++ {
z.Mul(x, y)
}
}
func BenchmarkPairing(b *testing.B) {
e := &GT{}
b.ResetTimer()
for n := 0; n < b.N; n++ {
PairLol(e, &G1{*curveGen}, &G2{*twistGen})
}
}
func BenchmarkG1BaseMul(b *testing.B) {
x, _ := rand.Int(rand.Reader, N)
g := new(G1)
b.ResetTimer()
for i := 0; i < b.N; i++ {
g.ScalarBaseMult(x)
}
}
func BenchmarkG2BaseMul(b *testing.B) {
x, _ := rand.Int(rand.Reader, N)
g := new(G2)
b.ResetTimer()
for i := 0; i < b.N; i++ {
g.ScalarBaseMult(x)
}
}
func BenchmarkGTBaseMul(b *testing.B) {
x, _ := rand.Int(rand.Reader, N)
g := new(G2)
b.ResetTimer()
for i := 0; i < b.N; i++ {
g.ScalarBaseMult(x)
}
}
+618
View File
@@ -0,0 +1,618 @@
// Package bn256 implements a particular bilinear group.
//
// Bilinear groups are the basis of many of the new cryptographic protocols that
// have been proposed over the past decade. They consist of a triplet of groups
// (G₁, G₂ and GT) such that there exists a function e(g₁ˣ,g₂ʸ)=gTˣʸ (where gₓ
// is a generator of the respective group). That function is called a pairing
// function.
//
// This package specifically implements the Optimal Ate pairing over a 256-bit
// Barreto-Naehrig curve as described in
// http://cryptojedi.org/papers/dclxvi-20100714.pdf. Its output is compatible
// with the implementation described in that paper.
//
// This package previously claimed to operate at a 128-bit security level.
// However, recent improvements in attacks mean that is no longer true. See
// https://moderncrypto.org/mail-archive/curves/2016/000740.html.
package bn256
import (
"io"
"math/big"
"xdx.jelly/xgcl/gerrors"
"xdx.jelly/xgcl/sm/sm9/errors"
)
var one = big.NewInt(1)
// randomK returns a random integer in [1, N-1].
func randomK(r io.Reader) (k *big.Int, err error) {
b := make([]byte, numBytes)
n, err := r.Read(b)
if err != nil {
return nil, errors.ErrGenerateRandomFailed
}
// it is possible that err != nil but n > 0.
// In this case, we also consider it succeed.
if n == 0 {
return nil, errors.ErrGenerateRandomFailed
}
// 0 <= k <= N-2
k = new(big.Int).SetBytes(b)
if k.Cmp(nMinusOne) >= 0 {
k.Sub(k, nMinusOne)
}
// 1 <= k <= N-1
k.Add(k, one)
return k, nil
}
// G1 is an abstract cyclic group. The zero value is suitable for use as the
// output of an operation, but cannot be used as an input.
type G1 struct {
p curvePoint
}
// UnmarshalCompressed restore e from x and the LSB of y.
func (e *G1) UnmarshalCompressed(x []byte, yBit0 byte) (*G1, error) {
ex := &gfP{}
ey := &gfP{}
ex.Unmarshal(x)
montEncode(ex, ex)
// y^2 = x^3 + B
gfpMul(ey, ex, ex)
gfpMul(ey, ey, ex)
gfpAdd(ey, ey, curveB)
if legendre(ey) != 1 {
return e, gerrors.WithAnnotating(errors.ErrInvalidInput, "sqrt failed, input bytes are not a valid compressed point")
}
ey.Sqrt(ey)
var temp gfP
montDecode(&temp, ey)
if yBit0 != byte(temp[0]&1) {
gfpNeg(ey, ey)
}
e.p.x = *ex
e.p.y = *ey
e.p.z = r
e.p.t = r
return e, nil
}
// 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) {
k, err := randomK(r)
if err != nil {
return nil, nil, gerrors.WithMessage(err, "RandomG1 failed")
}
return k, new(G1).ScalarBaseMult(k), nil
}
// returns the montgemery domain of x
func (e *G1) X() *big.Int {
e.p.MakeAffine()
return e.p.x.toBigInt()
}
// returns the montgemery domain of x
func (e *G1) Y() *big.Int {
e.p.MakeAffine()
return e.p.y.toBigInt()
}
// returns the montgemery domain of x
func (e *G1) AffineX() *big.Int {
e.p.MakeAffine()
var x gfP
montDecode(&x, &e.p.x)
return x.toBigInt()
}
// returns the montgemery domain of x
func (e *G1) AffineY() *big.Int {
e.p.MakeAffine()
var y gfP
montDecode(&y, &e.p.y)
return y.toBigInt()
}
// String returns a readable string representation of e
func (e *G1) String() string {
return "G1" + e.p.String()
}
// IsInfinity returns if G1 is the infinity point
func (e *G1) IsInfinity() bool {
return e.p.IsInfinity()
}
// SetInfinity sets e to the infinity point
func (e *G1) SetInfinity() {
e.p.SetInfinity()
}
// Equal returns if e equals the other point
func (e *G1) Equal(other *G1) bool {
return e.p.Equal(&other.p)
}
// IsZero return true if e is infinity
func (e *G1) IsZero() bool {
return e.p.IsInfinity()
}
// IsValid return if e is a valid point of G1
func (e *G1) IsValid() bool {
return e.p.IsOnCurve()
}
// ScalarBaseMult sets e to [k]g1 where g1 is the generator of the group and returns e.
func (e *G1) ScalarBaseMult(k *big.Int) *G1 {
e.p.MulBase(k, curverBasePrecompted8)
return e
}
// ScalarMult sets e to [k]a and then returns e.
func (e *G1) ScalarMult(a *G1, k *big.Int) *G1 {
e.p.Mul(&a.p, k)
return e
}
// Add sets e to a+b and then returns e.
func (e *G1) Add(a, b *G1) *G1 {
e.p.Add(&a.p, &b.p)
return e
}
// Neg sets e to -a and then returns e.
func (e *G1) Neg(a *G1) *G1 {
e.p.Neg(&a.p)
return e
}
// Set sets e to a and then returns e.
func (e *G1) Set(a *G1) *G1 {
e.p.Set(&a.p)
return e
}
// FillBytes fills a point in G1 to a byte slice.
//
// The Input slice must be of exactly 64 bytes, i.e., len(b) == 64.
// Also assume the point is not infinity. But if so, then set b to 0s and return.
func (e *G1) FillBytes(b []byte) {
if e.IsInfinity() {
for i := 0; i < len(b); i++ {
b[i] = 0
}
return
}
e.p.MakeAffine()
temp := &gfP{}
montDecode(temp, &e.p.x)
temp.Marshal(b)
montDecode(temp, &e.p.y)
temp.Marshal(b[numBytes:])
}
// Marshal converts a point in G1 to a byte slice of length 64.
// The slice is filled with x || y.
func (e *G1) Marshal() []byte {
ret := make([]byte, numBytes*2)
if e.p.IsInfinity() {
return ret
}
e.FillBytes(ret)
return ret
}
// Unmarshal sets e to the result of converting the output of Marshal back into
// a group element and then returns e.
// The input byte slice m must at least 64 bytes long.
func (e *G1) Unmarshal(m []byte) ([]byte, error) {
if len(m) < 2*numBytes {
return m, gerrors.WithAnnotating(errors.ErrInvalidInput, "not enough data to unmarshal to G1")
}
e.p.x, e.p.y = gfP{0}, gfP{0}
e.p.x.Unmarshal(m)
e.p.y.Unmarshal(m[numBytes:])
montEncode(&e.p.x, &e.p.x)
montEncode(&e.p.y, &e.p.y)
zero := gfP{0}
if e.p.x == zero && e.p.y == zero {
// The point at infinity.
e.p.y = gfPOne
e.p.z = gfP{0}
e.p.t = gfP{0}
} else {
e.p.z = gfPOne
e.p.t = gfPOne
if !e.p.IsOnCurve() {
return nil, gerrors.WithAnnotating(errors.ErrInvalidPoint, "point is not a valid point on curve")
}
}
return m[2*numBytes:], nil
}
// G2 is an abstract cyclic group. The zero value is suitable for use as the
// output of an operation, but cannot be used as an input.
type G2 struct {
p twistPoint
}
// 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) {
k, err := randomK(r)
if err != nil {
return nil, nil, gerrors.WithMessage(err, "RandomG2 failed")
}
return k, new(G2).ScalarBaseMult(k), nil
}
func (e *G2) X() (*big.Int, *big.Int) {
e.p.MakeAffine()
return e.p.x.x.toBigInt(), e.p.x.y.toBigInt()
}
func (e *G2) Y() (*big.Int, *big.Int) {
e.p.MakeAffine()
return e.p.y.x.toBigInt(), e.p.y.y.toBigInt()
}
func (e *G2) IsInfinity() bool {
return e.p.IsInfinity()
}
func (e *G2) SetInfinity() {
e.p.SetInfinity()
}
func (e *G2) Equal(other *G2) bool {
return e.p.Equal(&other.p)
}
// FromX restore e from x and the LSB of y. yBit0 can only be 0 or 1.
func (e *G2) UnmarshalCompressed(x0, x1 []byte, yBit0 byte) (*G2, error) {
if len(x0) < numBytes || len(x1) < numBytes {
return nil, gerrors.WithAnnotating(errors.ErrInvalidInput, "point is not a valid point on curve")
}
if yBit0&byte(0xfe) != 0 {
return nil, gerrors.WithAnnotatingf(errors.ErrInvalidInput, "yBit0 can only be 0 or 1, but it's %d", yBit0)
}
ex := &gfP2{}
ey := &gfP2{}
ex0 := &ex.x
ex1 := &ex.y
ex0.Unmarshal(x0)
montEncode(ex0, ex0)
ex1.Unmarshal(x1)
montEncode(ex1, ex1)
ey.Mul(ex, ex)
ey.Mul(ey, ex)
ey.Add(ey, twistB) // ey = x^3 + B
if !ey.Sqrt(ey) {
return e, gerrors.WithAnnotatingf(errors.ErrInvalidPoint, "sqrt failed, input bytes are not a valid compressed point")
}
tmp := &gfP{}
montDecode(tmp, &ey.y)
if yBit0 != byte(tmp[0]&1) {
ey.Neg(ey)
}
e.p.x = *ex
e.p.y = *ey
e.p.t = gfP2{y: r}
e.p.z = gfP2{y: r}
return e, nil
}
func (e *G2) String() string {
return "G2" + e.p.String()
}
// ScalarBaseMult sets e to [k]g where g is the generator of the group and then
// returns out.
func (e *G2) ScalarBaseMult(k *big.Int) *G2 {
e.p.MulBase(k, twistBasePrecomputed8)
return e
}
// ScalarMult sets e to [k]a and then returns e.
func (e *G2) ScalarMult(a *G2, k *big.Int) *G2 {
e.p.Mul(&a.p, k)
return e
}
// Add sets e to a+b and then returns e.
func (e *G2) Add(a, b *G2) *G2 {
e.p.Add(&a.p, &b.p)
return e
}
// Neg sets e to -a and then returns e.
func (e *G2) Neg(a *G2) *G2 {
e.p.Neg(&a.p)
return e
}
// Set sets e to a and then returns e.
func (e *G2) Set(a *G2) *G2 {
e.p.Set(&a.p)
return e
}
// FillBytes fills a point in G2 to a byte slice.
//
// The Input slice must be of exactly 128 bytes, i.e., len(b) == 128.
// Also assume the point is not infinity. But if so, then set b to 0s and return.
func (e *G2) FillBytes(b []byte) {
if e.IsInfinity() {
for i := 0; i < len(b); i++ {
b[i] = 0
}
return
}
e.p.MakeAffine()
temp := &gfP{}
montDecode(temp, &e.p.x.x)
temp.Marshal(b)
montDecode(temp, &e.p.x.y)
temp.Marshal(b[numBytes:])
montDecode(temp, &e.p.y.x)
temp.Marshal(b[2*numBytes:])
montDecode(temp, &e.p.y.y)
temp.Marshal(b[3*numBytes:])
}
// Marshal converts e into a byte slice.
func (e *G2) Marshal() []byte {
ret := make([]byte, numBytes*4)
if e.p.IsInfinity() {
return ret
}
e.FillBytes(ret)
return ret
}
// Unmarshal sets e to the result of converting the output of Marshal back into
// a group element and then returns e.
func (e *G2) Unmarshal(m []byte) ([]byte, error) {
if len(m) < 4*numBytes {
return m, gerrors.WithAnnotatingf(errors.ErrInvalidInput, "not enough data to unmarshal to G1")
}
e.p.x.x.Unmarshal(m)
e.p.x.y.Unmarshal(m[numBytes:])
e.p.y.x.Unmarshal(m[2*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.IsZero() && e.p.y.IsZero() {
// This is the point at infinity.
e.p.y.SetOne()
e.p.z.SetZero()
e.p.t.SetZero()
} else {
e.p.z.SetOne()
e.p.t.SetOne()
if !e.p.IsOnCurve() {
return m, gerrors.WithAnnotatingf(errors.ErrInvalidPoint, "unmarshaled point is not a valid point on curve")
}
}
return m[4*numBytes:], nil
}
// GT is an abstract cyclic group. The zero value is suitable for use as the
// output of an operation, but cannot be used as an input.
type GT struct {
p gfP12
}
func (e *GT) Equal(other *GT) bool {
return e.p.Equal(&other.p)
}
// Order12412 change e to 1-2-4-12 field extension represent
func (e *GT) Order12412() {
e.p.x.y.x, e.p.x.y.y, e.p.y.y.x, e.p.y.y.y, e.p.x.z.x, e.p.x.z.y, e.p.y.x.x, e.p.y.x.y =
e.p.y.y.x, e.p.y.y.y, e.p.x.y.x, e.p.x.y.y, e.p.y.x.x, e.p.y.x.y, e.p.x.z.x, e.p.x.z.y
}
// RandomGT returns x and e(g₁, g₂)ˣ where x is a random, non-zero number read
// from r.
func RandomGT(r io.Reader) (*big.Int, *GT, error) {
k, err := randomK(r)
if err != nil {
return nil, nil, gerrors.WithMessage(err, "RandomGT failed")
}
return k, new(GT).ScalarBaseMult(k), nil
}
// Pair calculates an Optimal Ate pairing.
func Pair(g1 *G1, g2 *G2) *GT {
var e GT
optimalAte(&e.p, &g2.p, &g1.p)
return &e
}
// Pair calculates an Optimal Ate pairing.
func PairLol(e *GT, g1 *G1, g2 *G2) {
optimalAte(&e.p, &g2.p, &g1.p)
}
// 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 {
var e GT
miller(&e.p, &g2.p, &g1.p)
return &e
}
func (e *GT) String() string {
p := *e
p.Order12412()
return "GT" + gfP12Decode(&p.p).String()
}
// ScalarBaseMult sets e to g*k where g is the generator of the group and then
// returns out.
func (e *GT) ScalarBaseMult(k *big.Int) *GT {
if useLattice {
e.p.latticeExp(gfP12Gen, k)
return e
} else {
return e.ScalarMultSimple(&GT{*gfP12Gen}, k)
}
}
// ScalarMult sets e to a*k and then returns e. (If e is not guaranteed to be an element of the group because it is the
// output of Miller(), use ScalarMultSimple.)
func (e *GT) ScalarMult(a *GT, k *big.Int) *GT {
if useLattice {
e.p.latticeExp(&a.p, k)
return e
} else {
return e.ScalarMultSimple(a, k)
}
}
// ScalarMultSimple sets e to a*k and then returns e.
func (e *GT) ScalarMultSimple(a *GT, k *big.Int) *GT {
e.p.Exp(&a.p, k)
return e
}
func (e *GT) Mul(a, b *GT) *GT {
e.p.Mul(&a.p, &b.p)
return e
}
// Add sets e to a+b and then returns e.
func (e *GT) Add(a, b *GT) *GT {
e.p.Mul(&a.p, &b.p)
return e
}
// Neg sets e to -a and then returns e.
func (e *GT) Neg(a *GT) *GT {
e.p.Conjugate(&a.p)
return e
}
// Set sets e to a and then returns e.
func (e *GT) Set(a *GT) *GT {
e.p.Set(&a.p)
return e
}
// Set sets e to a and then returns e.
func (e *GT) SetOne() *GT {
e.p.SetOne()
return e
}
// Set sets e to a and then returns e.
func (e *GT) Invert(a *GT) *GT {
e.p.Invert(&a.p)
return e
}
// Finalize is a linear function from F_p^12 to GT.
// func (e *GT) Finalize() *GT {
// finalExponentiation(&e.p, &e.p)
// return e
// }
// Marshal converts e into a byte slice.
func (e *GT) Marshal() []byte {
p := *e
p.Order12412()
ret := make([]byte, numBytes*12)
temp := &gfP{}
montDecode(temp, &p.p.x.x.x)
temp.Marshal(ret)
montDecode(temp, &p.p.x.x.y)
temp.Marshal(ret[numBytes:])
montDecode(temp, &p.p.x.y.x)
temp.Marshal(ret[2*numBytes:])
montDecode(temp, &p.p.x.y.y)
temp.Marshal(ret[3*numBytes:])
montDecode(temp, &p.p.x.z.x)
temp.Marshal(ret[4*numBytes:])
montDecode(temp, &p.p.x.z.y)
temp.Marshal(ret[5*numBytes:])
montDecode(temp, &p.p.y.x.x)
temp.Marshal(ret[6*numBytes:])
montDecode(temp, &p.p.y.x.y)
temp.Marshal(ret[7*numBytes:])
montDecode(temp, &p.p.y.y.x)
temp.Marshal(ret[8*numBytes:])
montDecode(temp, &p.p.y.y.y)
temp.Marshal(ret[9*numBytes:])
montDecode(temp, &p.p.y.z.x)
temp.Marshal(ret[10*numBytes:])
montDecode(temp, &p.p.y.z.y)
temp.Marshal(ret[11*numBytes:])
return ret
}
// Unmarshal sets e to the result of converting the output of Marshal back into
// a group element and then returns e.
func (e *GT) Unmarshal(m []byte) ([]byte, error) {
if len(m) < 12*numBytes {
return m, gerrors.WithAnnotating(errors.ErrInvalidInput, "not enough data to unmarshal to GT")
}
e.p.x.x.x.Unmarshal(m)
e.p.x.x.y.Unmarshal(m[numBytes:])
e.p.x.y.x.Unmarshal(m[2*numBytes:])
e.p.x.y.y.Unmarshal(m[3*numBytes:])
e.p.x.z.x.Unmarshal(m[4*numBytes:])
e.p.x.z.y.Unmarshal(m[5*numBytes:])
e.p.y.x.x.Unmarshal(m[6*numBytes:])
e.p.y.x.y.Unmarshal(m[7*numBytes:])
e.p.y.y.x.Unmarshal(m[8*numBytes:])
e.p.y.y.y.Unmarshal(m[9*numBytes:])
e.p.y.z.x.Unmarshal(m[10*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)
e.Order12412()
return m[12*numBytes:], nil
}
+279
View File
@@ -0,0 +1,279 @@
package bn256
import (
"fmt"
"testing"
"time"
"bytes"
"crypto/rand"
)
// // return x,y
// func coordinates(e *G1) (*big.Int, *big.Int) {
// e.p.MakeAffine()
// temp := &gfP{}
// b := make([]byte, 32)
// montDecode(temp, &e.p.x)
// temp.Marshal(b)
// x := new(big.Int).SetBytes(b)
// montDecode(temp, &e.p.y)
// temp.Marshal(b)
// y := new(big.Int).SetBytes(b)
// return x, y
// }
func TestG1(t *testing.T) {
k, Ga, err := RandomG1(rand.Reader)
if err != nil {
t.Fatal(err)
}
ma := Ga.Marshal()
Gb := new(G1).ScalarBaseMult(k)
mb := Gb.Marshal()
if !bytes.Equal(ma, mb) {
t.Fatal("bytes are different")
}
}
func TestG1UnmarshalCompressed(t *testing.T) {
for i := 0; i < 10000; i++ {
_, e1, err := RandomG1(rand.Reader)
if err != nil {
t.Fatal(err)
}
b := e1.Marshal()
e2, err := (&G1{}).UnmarshalCompressed(b[:32], b[len(b)-1]&1)
if err != nil {
t.Fatal(err)
}
if !e1.p.Equal(&e2.p) {
t.Fatal()
}
}
}
func TestG2UnmarshalCompressed(t *testing.T) {
for i := 0; i < 10000; i++ {
_, e1, err := RandomG2(rand.Reader)
if err != nil {
t.Fatal(err)
}
b := e1.Marshal()
e2, err := (&G2{}).UnmarshalCompressed(b[:32], b[32:64], b[len(b)-1]&1)
if err != nil {
t.Fatal(err)
}
if !e1.p.Equal(&e2.p) {
t.Fatal()
}
}
}
func TestG2FromX(t *testing.T) {
n := newGFp(2)
gfpNeg(n, n)
for i := 0; i < 4; i++ {
fmt.Printf("%x\n", n[i])
}
}
func TestG1Marshal(t *testing.T) {
_, Ga, err := RandomG1(rand.Reader)
if err != nil {
t.Fatal(err)
}
ma := Ga.Marshal()
Gb := new(G1)
_, err = Gb.Unmarshal(ma)
if err != nil {
t.Fatal(err)
}
mb := Gb.Marshal()
if !bytes.Equal(ma, mb) {
t.Fatal("bytes are different")
}
}
func TestG2(t *testing.T) {
k, Ga, err := RandomG2(rand.Reader)
if err != nil {
t.Fatal(err)
}
ma := Ga.Marshal()
Gb := new(G2).ScalarBaseMult(k)
mb := Gb.Marshal()
if !bytes.Equal(ma, mb) {
t.Fatal()
}
}
func TestG2Marshal(t *testing.T) {
_, Ga, err := RandomG2(rand.Reader)
if err != nil {
t.Fatal(err)
}
ma := Ga.Marshal()
Gb := new(G2)
_, err = Gb.Unmarshal(ma)
if err != nil {
t.Fatal(err)
}
mb := Gb.Marshal()
if !bytes.Equal(ma, mb) {
t.Fatal("bytes are different")
}
}
func TestGT(t *testing.T) {
k, Ga, err := RandomGT(rand.Reader)
if err != nil {
t.Fatal(err)
}
ma := Ga.Marshal()
Gb := new(GT).ScalarBaseMult(k)
mb := Gb.Marshal()
if !bytes.Equal(ma, mb) {
t.Fatal()
}
}
func TestGTMarshal(t *testing.T) {
_, Ga, err := RandomGT(rand.Reader)
if err != nil {
t.Fatal(err)
}
ma := Ga.Marshal()
Gb := new(GT)
_, err = Gb.Unmarshal(ma)
if err != nil {
t.Fatal(err)
}
mb := Gb.Marshal()
if !bytes.Equal(ma, mb) {
t.Fatal("bytes are different")
}
}
func TestBilinearity(t *testing.T) {
for i := 0; i < 2; i++ {
a, p1, _ := RandomG1(rand.Reader)
b, p2, _ := RandomG2(rand.Reader)
e1 := Pair(p1, p2)
e2 := Pair(&G1{*curveGen}, &G2{*twistGen})
e2.ScalarMult(e2, a)
e2.ScalarMult(e2, b)
if e1.p != e2.p {
t.Log(e1)
t.Log(e2)
t.Fatalf("bad pairing result: %s", e1)
}
}
}
func TestTripartiteDiffieHellman(t *testing.T) {
a, _ := rand.Int(rand.Reader, N)
b, _ := rand.Int(rand.Reader, N)
c, _ := rand.Int(rand.Reader, N)
pa, pb, pc := new(G1), new(G1), new(G1)
qa, qb, qc := new(G2), new(G2), new(G2)
_, _ = pa.Unmarshal(new(G1).ScalarBaseMult(a).Marshal())
_, _ = qa.Unmarshal(new(G2).ScalarBaseMult(a).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.ScalarMult(k1, a)
k1Bytes := k1.Marshal()
k2 := Pair(pc, qa)
k2.ScalarMult(k2, b)
k2Bytes := k2.Marshal()
k3 := Pair(pa, qb)
k3.ScalarMult(k3, c)
k3Bytes := k3.Marshal()
if !bytes.Equal(k1Bytes, k2Bytes) || !bytes.Equal(k2Bytes, k3Bytes) {
t.Errorf("keys didn't agree")
}
}
func TestSelfAddG1(t *testing.T) {
_, Ga, err := RandomG1(rand.Reader)
if err != nil {
t.Fatal(err)
}
Gb := &G1{*curveGen}
Gb.p.Double(&Ga.p)
mb := Gb.Marshal()
Ga.Add(Ga, Ga)
ma := Ga.Marshal()
if !bytes.Equal(ma, mb) {
t.Fatal("bytes are different")
}
}
func TestSelfAddG2(t *testing.T) {
_, Ga, err := RandomG2(rand.Reader)
if err != nil {
t.Fatal(err)
}
Gb := &G2{*twistGen}
Gb.p.Double(&Ga.p)
mb := Gb.Marshal()
Ga.Add(Ga, Ga)
ma := Ga.Marshal()
if !bytes.Equal(ma, mb) {
t.Fatal("bytes are different")
}
}
func TestDirtyUnmarshal(t *testing.T) {
_, Ga, err := RandomG2(rand.Reader)
if err != nil {
t.Fatal(err)
}
ma := Ga.Marshal()
if _, err := Ga.Unmarshal(ma); err != nil {
t.Fatal(err)
}
}
func TestPairing(T *testing.T) {
begin := time.Now()
total := 1
for i := 0; i < total; i++ {
e := Pair(&G1{*curveGen}, &G2{*twistGen})
// fmt.Println("e:", gfP12Decode(e.p))
_ = e
}
elaspe := time.Since(begin)
fmt.Println("time: ", elaspe.Milliseconds(), "ms")
fmt.Println(float64(total) / float64(elaspe.Milliseconds()) * 1000)
}
+136
View File
@@ -0,0 +1,136 @@
package bn256
import (
"math/big"
)
const numBytes = 256 / 8
func bigFromBase10(s string) *big.Int {
n, _ := new(big.Int).SetString(s, 10)
return n
}
func bigFromBase16(s string) *big.Int {
n, _ := new(big.Int).SetString(s, 16)
return n
}
// u is the BN parameter that determines the prime: 1868033³.
var u = bigFromBase16("600000000058F98A")
// P is a prime over which we form a basic field: 36u⁴+36u³+24u²+6u+1.
var P = bigFromBase16("B640000002A3A6F1D603AB4FF58EC74521F2934B1A7AEEDBE56F9B27E351457D")
// N is the number of elements in both G₁ and G₂: 36u⁴+36u³+18u²+6u+1.
var N = bigFromBase16("B640000002A3A6F1D603AB4FF58EC74449F2934B18EA8BEEE56EE19CD69ECF25")
// nMinusOne equals N-1.
// Note that N-1 = (2**5) * 3 * 5743 * 280941149 * 130979359433191 * 491513138693455212421542731357 * 6518589491078791937
var nMinusOne = bigFromBase16("B640000002A3A6F1D603AB4FF58EC74449F2934B18EA8BEEE56EE19CD69ECF24")
// pPlus1Over4 little-endian representation of (p-1) / 4
// var pPlus1Over4 = [4]uint64{0xf95be6c9f8d4515f, 0x487ca4d2c69ebbb6, 0x7580ead3fd63b1d1, 0x2d90000000a8e9bc}
var pMinus1Over2 = [4]uint64{0xf2b7cd93f1a8a2be, 0x90f949a58d3d776d, 0xeb01d5a7fac763a2, 0x5b2000000151d378}
var pMinus1 = [4]uint64{0xe56f9b27e351457c, 0x21f2934b1a7aeedb, 0xd603ab4ff58ec745, 0xb640000002a3a6f1}
var pMinus2 = [4]uint64{0xe56f9b27e351457b, 0x21f2934b1a7aeedb, 0xd603ab4ff58ec745, 0xb640000002a3a6f1}
var pPlus3Over8 = [4]uint64{0x7cadf364fc6a28b0, 0xa43e5269634f5ddb, 0x3ac07569feb1d8e8, 0x16c80000005474de}
var pMinus5Over8 = [4]uint64{0x7cadf364fc6a28af, 0xa43e5269634f5ddb, 0x3ac07569feb1d8e8, 0x16c80000005474de}
var sqrtRootOfMinus1ModP = &gfP{0xabbaac18a46a2054, 0x46ee57561222c759, 0x1dae609fa0e23561, 0x1df7113dae0adc3c}
// p2 is P
var p2 = [4]uint64{0xe56f9b27e351457d, 0x21f2934b1a7aeedb, 0xd603ab4ff58ec745, 0xb640000002a3a6f1} // nolint
// // np = -P^{-1} mod 2^256 is the negative inverse of P, mod 2^256.
var np = [4]uint64{0x892bc42c2f2ee42b, 0x181ae39613c8dbaf, 0x966a4b291522b137, 0xafd2bac5558a13b3} // nolint
// r is the Montgemory reprents of 1, r = R % p where R = 2^256
var r = [4]uint64{0x1a9064d81caeba83, 0xde0d6cb4e5851124, 0x29fc54b00a7138ba, 0x49bffffffd5c590e}
// gfPOne is the same as r
var gfPOne = gfP{0x1a9064d81caeba83, 0xde0d6cb4e5851124, 0x29fc54b00a7138ba, 0x49bffffffd5c590e}
// gfPZero is the 0
var gfPZero = gfP{0}
// nr is the Montgemory reprents of -1, r = -R % p where R = 2^256
var nr = [4]uint64{0xcadf364fc6a28afa, 0x43e5269634f5ddb7, 0xac07569feb1d8e8a, 0x6c80000005474de3}
// r2 is the Montgemory reprents of R, i.e., r2 = R^2%p.
var r2 = &gfP{0x27dea312b417e2d2, 0x88f8105fae1a5d3f, 0xe479b522d6706e7b, 0x2ea795a656f62fbd}
// r3 is the Montgemory reprents of R^2, i.e., r3 = R^3%p.
var r3 = &gfP{0x130257769df5827e, 0x36920fc0837ec76e, 0xcbec24519c22a142, 0x219be84a7c687090}
var rN1 = &gfP{0x0a1c7970e5df544d, 0xe74504e9a96b56cc, 0xcda02d92d4d62924, 0x7d2bc576fdf597d1} // nolint
var p = &gfP{0xe56f9b27e351457d, 0x21f2934b1a7aeedb, 0xd603ab4ff58ec745, 0xb640000002a3a6f1} // nolint
// montgomery encode of u^{p-1}, xiToPMinus1 = u^{p-1} * R % p = 2^{(p-1)/2} * R % p.
// used for Frob. map: frob(xu+y) = x*xiToPMinus1 * u + y
var xiToPMinus1 = &gfP{0xcadf364fc6a28afa, 0x43e5269634f5ddb7, 0xac07569feb1d8e8a, 0x6c80000005474de3} // nolint
var xiToPMinus1Over2 = &gfP{0xf5b21fd3da24d011, 0x9f9d411806dc5177, 0xf55acc93ee0baf15, 0x6c648de5dc0a3f2c} // nolint
var xiTo2PSquaredMinus2Over3 = &gfP{0x2f4981aa150a0eb3, 0x19c92815c28ded55, 0x39934d9cf7fd761b, 0x99cac18b7ca1dd5f}
var xiToPSquaredMinus1Over3 = &gfP{0x81054fcd94e9c1c4, 0x4c0e91cb8ce2df3e, 0x4877b452e8aedfb4, 0x88f53e748b491776}
var xiToPSquaredMinus1Over6 = &gfP{0xb626197dce4736ca, 0x08296b3557ed0186, 0x9c705db2fd91512a, 0x1c753e748601c992}
var xiTo2PMinus2Over3 = &gfP{0x81054fcd94e9c1c4, 0x4c0e91cb8ce2df3e, 0x4877b452e8aedfb4, 0x88f53e748b491776}
var xiToPMinus1Over3 = &gfP{0xb626197dce4736ca, 0x08296b3557ed0186, 0x9c705db2fd91512a, 0x1c753e748601c992}
var xiToPMinus1Over6 = &gfP{0x1a98dfbd4575299f, 0x9ec8547b245c54fd, 0xf51f5eac13df846c, 0x9ef74015d5a16393}
var xiTo2Minus2POver3 = &gfP{0x2f4981aa150a0eb3, 0x19c92815c28ded55, 0x39934d9cf7fd761b, 0x99cac18b7ca1dd5f}
var xiTo1MinusPOver3 = &gfP{0x646a4b5a4e6783b9, 0xd5e4017f8d980f9d, 0x8d8bf6fd0cdfe790, 0x2d4ac18b775a8f7b}
var xiTo1MinusPOver2 = &gfP{0xabbaac18a46a2054, 0x46ee57561222c759, 0x1dae609fa0e23561, 0x1df7113dae0adc3c}
//// xiToPMinus1Over6 is ξ^((P-1)/6) where ξ = i+3.
//var xiToPMinus1Over6 = &gfP2{gfP{0x25af52988477cdb7, 0x3d81a455ddced86a, 0x227d012e872c2431, 0x179198d3ea65d05}, gfP{0x7407634dd9cca958, 0x36d5bd6c7afb8f26, 0xf4b1c32cebd880fa, 0x6aa7869306f455f}}
//
//// xiToPMinus1Over3 is ξ^((P-1)/3) where ξ = i+3.
//var xiToPMinus1Over3 = &gfP2{gfP{0x4f59e37c01832e57, 0xae6be39ac2bbbfe4, 0xe04ea1bb697512f8, 0x3097caa8fc40e10e}, gfP{0xf8606916d3816f2c, 0x1e5c0d7926de927e, 0xbc45f3946d81185e, 0x80752a25aa738091}}
//
//// xiToPMinus1Over2 is ξ^((P-1)/2) where ξ = i+3.
//var xiToPMinus1Over2 = &gfP2{gfP{0x19da71333653ee20, 0x7eaaf34fc6ed6019, 0xc4ba3a29a60cdd1d, 0x75281311bcc9df79}, gfP{0x18dbee03fb7708fa, 0x1e7601a602c843c7, 0x5dde0688cdb231cb, 0x86db5cf2c605a524}}
//
//// xiToPSquaredMinus1Over3 is ξ^((P²-1)/3) where ξ = i+3.
//var xiToPSquaredMinus1Over3 = &gfP{0x12d3cef5e1ada57d, 0xe2eca1463753babb, 0xca41e40ddccf750, 0x551337060397e04c}
//
//// xiTo2PSquaredMinus2Over3 is ξ^((2p²-2)/3) where ξ = i+3 (a cubic root of unity, mod P).
//var xiTo2PSquaredMinus2Over3 = &gfP{0x3642364f386c1db8, 0xe825f92d2acd661f, 0xf2aba7e846c19d14, 0x5a0bcea3dc52b7a0}
//
//// xiToPSquaredMinus1Over6 is ξ^((1p²-1)/6) where ξ = i+3 (a cubic root of -1, mod P).
//var xiToPSquaredMinus1Over6 = &gfP{0xe21a761d259c78af, 0x6358fa3f5e84f7e, 0xb7c444d01ac33f0d, 0x35a9333f6e50d058}
//
//// xiTo2PMinus2Over3 is ξ^((2p-2)/3) where ξ = i+3.
//var xiTo2PMinus2Over3 = &gfP2{gfP{0x51678e7469b3c52a, 0x4fb98f8b13319fc9, 0x29b2254db3f1df75, 0x1c044935a3d22fb2}, gfP{0x4d2ea218872f3d2c, 0x2fcb27fc4abe7b69, 0xd31d972f0e88ced9, 0x53adc04a00a73b15}}
//
//// p2 is P, represented as little-endian 64-bit words.
//var p2 = [4]uint64{0x185cac6c5e089667, 0xee5b88d120b5b59e, 0xaa6fecb86184dc21, 0x8fb501e34aa387f9}
//
//// np is the negative inverse of P, mod 2^256.
//var np = [4]uint64{0x2387f9007f17daa9, 0x734b3343ab8513c8, 0x2524282f48054c12, 0x38997ae661c3ef3c}
//
//// rN1 is R^-1 where R = 2^256 mod P.
//var rN1 = &gfP{0xcbb781e36236117d, 0xcc65f3bcec8c91b, 0x2eab68888ea1f515, 0x1fc5c0956f92f825}
//
//// r2 is R^2 where R = 2^256 mod P.
//var r2 = &gfP{0x9c21c3ff7e444f56, 0x409ed151b2efb0c2, 0xc6dc37b80fb1651, 0x7c36e0e62c2380b7}
//
//// r3 is R^3 where R = 2^256 mod P.
//var r3 = &gfP{0x2af2dfb9324a5bb8, 0x388f899054f538a4, 0xdf2ff66396b107a7, 0x24ebbbb3a2529292}
//
//// pPlus1Over4 is (P+1)/4.
//var pPlus1Over4 = [4]uint64{0x86172b1b1782259a, 0x7b96e234482d6d67, 0x6a9bfb2e18613708, 0x23ed4078d2a8e1fe}
//
//// pMinus2 is P-2.
//var pMinus2 = [4]uint64{0x185cac6c5e089665, 0xee5b88d120b5b59e, 0xaa6fecb86184dc21, 0x8fb501e34aa387f9}
//
//// pMinus1Over2 is (P-1)/2.
//var pMinus1Over2 = [4]uint64{0x0c2e56362f044b33, 0xf72dc468905adacf, 0xd537f65c30c26e10, 0x47da80f1a551c3fc}
// s is the Montgomery encoding of the square root of -3. Then, s = sqrt(-3) * 2^256 mod P.
var s = &gfP{0x236e675956be783b, 0x053957e6f379ab64, 0xe60789a768f4a5c4, 0x04f8979dd8bad754} // nolint
// sMinus1Over2 is the Montgomery encoding of (s-1)/2. Then, sMinus1Over2 = ( (s-1) / 2) * 2^256 mod P.
var sMinus1Over2 = &gfP{0x3642364f386c1db8, 0xe825f92d2acd661f, 0xf2aba7e846c19d14, 0x5a0bcea3dc52b7a0} // nolint
+114
View File
@@ -0,0 +1,114 @@
package bn256
import (
"fmt"
"testing"
"xdx.jelly/xgcl/gmath"
)
// Generate the gfP present from big.Int
func gfPFromBase16(s string) (r [4]uint64) {
t := bigFromBase16(s)
r[0] = t.Uint64()
t.Rsh(t, 64)
r[1] = t.Uint64()
t.Rsh(t, 64)
r[2] = t.Uint64()
t.Rsh(t, 64)
r[3] = t.Uint64()
t.Rsh(t, 64)
return
}
func TestConstGFP(t *testing.T) {
// output var pPlus1Over4 = [4]uint64{0x86172b1b1782259a, 0x7b96e234482d6d67, 0x6a9bfb2e18613708, 0x23ed4078d2a8e1fe}
var p = bigFromBase10("65000549695646603732796438742359905742825358107623003571877145026864184071783")
p.Add(p, gmath.BigInt1)
p.Rsh(p, 2)
x := gfPFromBase16(p.Text(16))
for _, i := range x {
fmt.Printf("%x ", i)
}
}
func TestConst(t *testing.T) {
m := make(map[string][]string, 0)
m["xiToPMinus1Over6"] = []string{"3f23ea58e5720bdb843c6cfa9c08674947c5c86e0ddd04eda91d8354377b698b"}
m["xiToPMinus1Over3"] = []string{"f300000002a3a6f2780272354f8b78f4d5fc11967be65334"}
m["xiToPMinus1Over2"] = []string{"6c648de5dc0a3f2cf55acc93ee0baf159f9d411806dc5177f5b21fd3da24d011"}
m["xiToPSquaredMinus1Over3"] = []string{"f300000002a3a6f2780272354f8b78f4d5fc11967be65333"}
m["xiTo2PSquaredMinus2Over3"] = []string{"b640000002a3a6f0e303ab4ff2eb2052a9f02115caef75e70f738991676af249"}
m["xiToPSquaredMinus1Over6"] = []string{"f300000002a3a6f2780272354f8b78f4d5fc11967be65334"}
m["xiTo2PMinus2Over3"] = []string{"f300000002a3a6f2780272354f8b78f4d5fc11967be65333"}
m["p2"] = []string{"B640000002A3A6F1D603AB4FF58EC74521F2934B1A7AEEDBE56F9B27E351457D"}
m["np"] = []string{"afd2bac5558a13b3966a4b291522b137181ae39613c8dbaf892bc42c2f2ee42b"}
m["rN1"] = []string{"7d2bc576fdf597d1cda02d92d4d62924e74504e9a96b56cc0a1c7970e5df544d"}
m["r2"] = []string{"49bffffffd5c590e29fc54b00a7138bade0d6cb4e58511241a9064d81caeba83"}
//m["r2"] = []string{"2ea795a656f62fbde479b522d6706e7b88f8105fae1a5d3f27dea312b417e2d2"}
m["r3"] = []string{"219be84a7c687090cbec24519c22a14236920fc0837ec76e130257769df5827e"}
//m["pPlus1Over4"] = []string{"2d90000000a8e9bc7580ead3fd63b1d1487ca4d2c69ebbb6f95be6c9f8d4515f"}
//m["pMinus2"] = []string{"b640000002a3a6f1d603ab4ff58ec74521f2934b1a7aeedbe56f9b27e351457b"}
//m["pMinus1Over2"] = []string{"5b2000000151d378eb01d5a7fac763a290f949a58d3d776df2b7cd93f1a8a2be"}
m["xiToPMinus1"] = []string{"b640000002a3a6f1d603ab4ff58ec74521f2934b1a7aeedbe56f9b27e351457c"}
//// s is the Montgomery encoding of the square root of -3. Then, s = sqrt(-3) * 2^256 mod P.
//var s = &gfP{0x236e675956be783b, 0x053957e6f379ab64, 0xe60789a768f4a5c4, 0x04f8979dd8bad754}
//
//// sMinus1Over2 is the Montgomery encoding of (s-1)/2. Then, sMinus1Over2 = ( (s-1) / 2) * 2^256 mod P.
//var sMinus1Over2 = &gfP{0x3642364f386c1db8, 0xe825f92d2acd661f, 0xf2aba7e846c19d14, 0x5a0bcea3dc52b7a0}
for k, v := range m {
if len(v) == 1 {
f := gfPFromBase16(v[0])
fmt.Print("var ", k, " = &gfP{")
for i := range f {
fmt.Printf("0x%x", f[i])
if i < 3 {
fmt.Print(", ")
} else {
fmt.Println("}")
}
}
} else if len(v) == 2 {
t.Fatal()
}
}
}
func TestMontEncode(t *testing.T) {
m := make(map[string][]string, 0)
m["5*R"] = []string{"5"}
m["twistx0"] = []string{"85AEF3D078640C98597B6027B441A01FF1DD2C190F5E93C454806C11D8806141"}
m["twistx1"] = []string{"3722755292130B08D2AAB97FD34EC120EE265948D19C17ABF9B7213BAF82D65B"}
m["twisty0"] = []string{"17509B092E845C1266BA0D262CBEE6ED0736A96FA347C8BD856DC76B84EBEB96"}
m["twisty1"] = []string{"A7CF28D519BE3DA65F3170153D278FF247EFBA98A71A08116215BBA5C999A7C7"}
m["curvex"] = []string{"93DE051D62BF718FF5ED0704487D01D6E1E4086909DC3280E8C4E4817C66DDDD"}
m["curvey"] = []string{"21FE8DDA4F21E607631065125C395BBC1C1C00CBFA6024350C464CD70A3EA616"}
m["alpha"] = []string{"b640000002a3a6f0e303ab4ff2eb2052a9f02115caef75e70f738991676af249"}
m["xiTo2Minus2POver3"] = []string{"b640000002a3a6f0e303ab4ff2eb2052a9f02115caef75e70f738991676af249"}
m["xiTo1MinusPOver3"] = []string{"b640000002a3a6f0e303ab4ff2eb2052a9f02115caef75e70f738991676af24a"}
m["xiTo1MinusPOver2"] = []string{"49db721a269967c4e0a8debc0783182f82555233139e9d63efbd7b54092c756c"}
for k, v := range m {
if len(v) == 1 {
f := bigFromBase16(v[0])
f.Lsh(f, 256)
f.Mod(f, P)
fp := gfPFromBase16(f.Text(16))
fmt.Print("var ", k, " = &gfP{")
for i := range fp {
fmt.Printf("0x%x", fp[i])
if i < 3 {
fmt.Print(", ")
} else {
fmt.Println("}")
}
}
} else if len(v) == 2 {
t.Fatal()
}
}
}
+284
View File
@@ -0,0 +1,284 @@
package bn256
import (
"math/big"
)
// curvePoint implements the elliptic curve y²=x³+3. Points are kept in Jacobian
// form and t=z² when valid. G₁ is the set of points of this curve on GF(P).
type curvePoint struct {
x, y, z, t gfP
}
var curveB = newGFp(5)
// curveGen is the generator of G₁.
var curveGen = &curvePoint{
gfP{0x22e935e29860501b, 0xa946fd5e0073282c, 0xefd0cec817a649be, 0x5129787c869140b5},
gfP{0xee779649eb87f7c7, 0x15563cbdec30a576, 0x326353912824efbf, 0x7215717763c39828},
gfPOne,
gfPOne,
}
func (c *curvePoint) String() string {
c.MakeAffine()
var x gfP
var y gfP
montDecode(&x, &c.x)
montDecode(&y, &c.y)
return "[" + x.String() + ", " + y.String() + "]"
}
func (c *curvePoint) AffineCoordinates() (*big.Int, *big.Int) {
c.MakeAffine()
var x gfP
var y gfP
montDecode(&x, &c.x)
montDecode(&y, &c.y)
return x.toBigInt(), y.toBigInt()
}
func (c *curvePoint) Equal(a *curvePoint) bool {
if c == a {
return true
}
c.MakeAffine()
a.MakeAffine()
return *a == *c
}
func (c *curvePoint) Set(a *curvePoint) {
c.x.Set(&a.x)
c.y.Set(&a.y)
c.z.Set(&a.z)
c.t.Set(&a.t)
}
// IsOnCurve returns true iff c is on the curve.
func (c *curvePoint) IsOnCurve() bool {
c.MakeAffine()
if c.IsInfinity() {
return true
}
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() {
c.x = gfP{0}
c.y = gfPOne
c.z = gfP{0}
c.t = gfP{0}
}
func (c *curvePoint) IsInfinity() bool {
return c.z == gfP{0}
}
func (c *curvePoint) Add(a, b *curvePoint) {
if a.IsInfinity() {
c.Set(b)
return
}
if b.IsInfinity() {
c.Set(a)
return
}
// See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/addition/add-2007-bl.op3
// Normalize the points by replacing a = [x1:y1:z1] and b = [x2:y2: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³
z12, z22 := &gfP{}, &gfP{}
gfpMul(z12, &a.z, &a.z)
gfpMul(z22, &b.z, &b.z)
u1, u2 := &gfP{}, &gfP{}
gfpMul(u1, &a.x, z22)
gfpMul(u2, &b.x, z12)
t, s1 := &gfP{}, &gfP{}
gfpMul(t, &b.z, z22)
gfpMul(s1, &a.y, t)
s2 := &gfP{}
gfpMul(t, &a.z, z12)
gfpMul(s2, &b.y, t)
// Compute x = (2h)²(s²-u1-u2)
// where s = (s2-s1)/(u2-u1) is the slope of the line through
// (u1,s1) and (u2,s2). The extra factor 2h = 2(u2-u1) comes from the value of z below.
// This is also:
// 4(s2-s1)² - 4h²(u1+u2) = 4(s2-s1)² - 4h³ - 4h²(2u1)
// = r² - j - 2v
// with the notations below.
h := &gfP{}
gfpSub(h, u2, u1)
xEqual := *h == gfP{0}
gfpAdd(t, h, h)
// i = 4h²
i := &gfP{}
gfpMul(i, t, t)
// j = 4h³
j := &gfP{}
gfpMul(j, h, i)
gfpSub(t, s2, s1)
yEqual := *t == gfP{0}
if xEqual && yEqual {
c.Double(a)
return
}
r := &gfP{}
gfpAdd(r, t, t)
v := &gfP{}
gfpMul(v, u1, i)
// t4 = 4(s2-s1)²
t4, t6 := &gfP{}, &gfP{}
gfpMul(t4, r, r)
gfpAdd(t, v, v)
gfpSub(t6, t4, j)
gfpSub(&c.x, t6, t)
// Set y = -(2h)³(s1 + s*(x/4h²-u1))
// This is also
// y = - 2·s1·j - (s2-s1)(2x - 2i·u1) = r(v-x) - 2·s1·j
gfpSub(t, v, &c.x) // t7
gfpMul(t4, s1, j) // t8
gfpAdd(t6, t4, t4) // t9
gfpMul(t4, r, t) // t10
gfpSub(&c.y, t4, t6)
// Set z = 2(u2-u1)·z1·z2 = 2h·z1·z2
gfpAdd(t, &a.z, &b.z) // t11
gfpMul(t4, t, t) // t12
gfpSub(t, t4, z12) // t13
gfpSub(t4, t, z22) // t14
gfpMul(&c.z, t4, h)
}
func (c *curvePoint) Double(a *curvePoint) {
// See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/doubling/dbl-2009-l.op3
A, B, C := &gfP{}, &gfP{}, &gfP{}
gfpMul(A, &a.x, &a.x)
gfpMul(B, &a.y, &a.y)
gfpMul(C, B, B)
t, t2 := &gfP{}, &gfP{}
gfpAdd(t, &a.x, B)
gfpMul(t2, t, t)
gfpSub(t, t2, A)
gfpSub(t2, t, C)
d, e, f := &gfP{}, &gfP{}, &gfP{}
gfpAdd(d, t2, t2)
gfpAdd(t, A, A)
gfpAdd(e, t, A)
gfpMul(f, e, e)
gfpAdd(t, d, d)
gfpSub(&c.x, f, t)
gfpMul(&c.z, &a.y, &a.z)
gfpAdd(&c.z, &c.z, &c.z)
gfpAdd(t, C, C)
gfpAdd(t2, t, t)
gfpAdd(t, t2, t2)
gfpSub(&c.y, d, &c.x)
gfpMul(t2, e, &c.y)
gfpSub(&c.y, t2, t)
}
func (c *curvePoint) Mul(a *curvePoint, scalar *big.Int) {
if useLattice {
precomp := [1 << 2]*curvePoint{nil, {}, {}, {}}
precomp[1].Set(a)
precomp[2].Set(a)
gfpMul(&precomp[2].x, &precomp[2].x, xiTo2PMinus2Over3)
//precomp[3].Add(precomp[1], precomp[2])
//TODO Fix decompose
decomp := curveLattice.decompose(scalar)
if decomp[0].Sign() < 0 {
precomp[1].Neg(precomp[1])
}
if decomp[1].Sign() < 0 {
precomp[2].Neg(precomp[2])
}
precomp[3].Add(precomp[1], precomp[2])
multiScalar := curveLattice.Multi(scalar)
sum := &curvePoint{}
sum.SetInfinity()
t := &curvePoint{}
for i := len(multiScalar) - 1; i >= 0; i-- {
t.Double(sum)
if multiScalar[i] == 0 {
sum.Set(t)
} else {
sum.Add(t, precomp[multiScalar[i]])
}
}
c.Set(sum)
} else {
sum, t := &curvePoint{}, &curvePoint{}
sum.SetInfinity()
for i := scalar.BitLen(); i >= 0; i-- {
t.Double(sum)
if scalar.Bit(i) != 0 {
sum.Add(t, a)
} else {
sum.Set(t)
}
}
c.Set(sum)
}
}
// MakeAffine set x = x*z^2, y = y*z^3, z = t = 1 for a finite point.
func (c *curvePoint) MakeAffine() {
if c.z == gfPOne {
return
} else if c.z == gfPZero {
c.x = gfP{0}
c.y = gfPOne
c.t = gfP{0}
return
}
zInv := &gfP{}
zInv.Invert(&c.z)
t, zInv2 := &gfP{}, &gfP{}
gfpMul(t, &c.y, zInv)
gfpMul(zInv2, zInv, zInv)
gfpMul(&c.x, &c.x, zInv2)
gfpMul(&c.y, t, zInv2)
c.z = gfPOne
c.t = gfPOne
}
func (c *curvePoint) Neg(a *curvePoint) {
c.x.Set(&a.x)
gfpNeg(&c.y, &a.y)
c.z.Set(&a.z)
c.t = gfP{0}
}
+345
View File
@@ -0,0 +1,345 @@
// Package bn256 ..
package bn256
import "math/big"
// 256*4*4*4 = 16K
var curverBasePrecompted8 = []*curvePoint{ // nolint
{gfP{0}, gfP{0x1a9064d81caeba83, 0xde0d6cb4e5851124, 0x29fc54b00a7138ba, 0x49bffffffd5c590e}, gfP{0}, gfP{0}},
{gfP{0x22e935e29860501b, 0xa946fd5e0073282c, 0xefd0cec817a649be, 0x5129787c869140b5}, gfP{0xee779649eb87f7c7, 0x15563cbdec30a576, 0x326353912824efbf, 0x7215717763c39828}, gfPOne, gfPOne},
{gfP{0x95ca1bb919a322eb, 0xc4d13c49d672e273, 0x4797255d41bb8c0f, 0x1ebf8f510af182d0}, gfP{0x1d74935661933d97, 0x10deb64252136a02, 0xee16c808be654172, 0x28187964a641c5d3}, gfPOne, gfPOne},
{gfP{0x22b50a53643b5e18, 0x9925f2f496c29484, 0x63e092df2137c75a, 0x44f8b7668f3dfe88}, gfP{0x7c4714cfb557d50, 0x682c1e8f295b6779, 0x8e87d2562714a0be, 0xa4b7662d47a1fb97}, gfPOne, gfPOne},
{gfP{0xba28d1e3d5048a4a, 0x304272c35402c713, 0x69e99637e85352dc, 0x8700ed2483b0b77b}, gfP{0x969534adc499393c, 0x5e8df13a66ad38f0, 0x8f0df437dbc29dcb, 0xa08db36b5f08d049}, gfPOne, gfPOne},
{gfP{0xa343996a7367c29d, 0xe96e87ea23df0d62, 0xddf5f38d18e96a63, 0x5098ee53e76f8e35}, gfP{0x97c267182697b1ee, 0xe867e6ea877b42e0, 0x320ca334328006be, 0xa8739bc600caf504}, gfPOne, gfPOne},
{gfP{0x112fb240f96cb07c, 0x318df722aa440595, 0x1ab5ec6703a61625, 0x878907dfc54b5ca9}, gfP{0x183a961c7faaacf4, 0xd5007f6ccaaa2917, 0x9575750bcb725b69, 0x9403e61886d2bac2}, gfPOne, gfPOne},
{gfP{0xecdde15b0285058f, 0xcc0e59ba3c87dcaf, 0x619836fa9bc27c3f, 0x36d9c0af2af6f957}, gfP{0x5dce98f96958261, 0x80a52fb92984a952, 0xef7f3ff1ef4938d8, 0x3a2823202a28283b}, gfPOne, gfPOne},
{gfP{0x4e0b75ceaf4a2887, 0xc3841acb67fb189a, 0x18c9578469741c9a, 0x692fab8164cee33f}, gfP{0xfaf6b1c1b91ffbb, 0x2161e01d6794e678, 0x757e6f30473f2d5f, 0x269bd35f64914a96}, gfPOne, gfPOne},
{gfP{0x213c9bd8e08c3c3f, 0x63a16fce2a85abe, 0x3f42d40a72cd11f0, 0x8f1fc73f06dd64d}, gfP{0x9453e2983440bb1b, 0x2f2407c95345ca17, 0x681a6b7635efdb6b, 0xa884f4aa644e5fc4}, gfPOne, gfPOne},
{gfP{0x8c421ac5ecba0343, 0x101d2e9b67b0f4ee, 0x3fafcfad92789f5a, 0x64642f323001a421}, gfP{0xa781b10be5989c03, 0xe9996e4b3cd51cb7, 0x8a35b2c52f42274d, 0xacc965059aa5cd5b}, gfPOne, gfPOne},
{gfP{0xc0d9fc893046aba7, 0x1362b9f9a10d4b07, 0xa50705ad82675e37, 0x5fd6ab1801c54945}, gfP{0xa079a2a53e55cd40, 0xf6cb313d402e5eb0, 0x98a6fdf0253fe446, 0x5d25905331b5b3f3}, gfPOne, gfPOne},
{gfP{0x4e0c47ce11cc2bea, 0xde09108ddb55ad9d, 0x8504aa303c428c24, 0x907addcb5c32e071}, gfP{0xffa66d4b19f624a4, 0x52dc7449d50bad3, 0x4b083d71488917b, 0x3865bfdad0f204db}, gfPOne, gfPOne},
{gfP{0x497fb9cad2bc9918, 0x74ab6701d62a870d, 0x89e7a0f78a5b300f, 0x7efa2b1d3899556b}, gfP{0xc3455af447763054, 0x952ddb2149fe6482, 0x17e3e7cc10b1028a, 0x2376b0d03a4d0a19}, gfPOne, gfPOne},
{gfP{0xf88bf6055451bbc2, 0x8d565d103a596a91, 0x89658fa5f00563f3, 0x4f086a996709429f}, gfP{0x66d510275e67c25d, 0x93e1627f86978a5e, 0x9ea7f8c713662129, 0x9d201c6a4266a161}, gfPOne, gfPOne},
{gfP{0xbeb026037146dbb8, 0x1444acca1e6ec560, 0x7f28198c42c9040e, 0x889fc8063c4bc1bd}, gfP{0xa9b908acc0ae21e8, 0x116775ec23c04db9, 0x185774aab2ba5c8f, 0x2b6c5c862e0df140}, gfPOne, gfPOne},
{gfP{0x46b8b8692a8eda6b, 0xe98400d89a9938b2, 0x2f6f8c3aa958752e, 0x87928e7b21296dff}, gfP{0xc578f06244de1eb7, 0xf67910a8d1befa71, 0x313c89849f89483b, 0x285df6a6b5c9f283}, gfPOne, gfPOne},
{gfP{0x99f991c62f896dc2, 0xca48dec99b12a0ca, 0x47979262c298eaff, 0x4e7325f6fee9c93a}, gfP{0x4a621d37ab703864, 0x22ea8d68bccdc8e7, 0x1872c133d0d4ed44, 0x8f83b2400eea2c5e}, gfPOne, gfPOne},
{gfP{0xc19b639f19c89b81, 0xbe23b5be678be2f6, 0xb3aaabb6975aab05, 0x2cec49b56009d525}, gfP{0x36a8845062c2be08, 0x9c230ea63ae3ecca, 0xee334b537db2c198, 0x63d9bc37e670df81}, gfPOne, gfPOne},
{gfP{0x2d567d811d344cda, 0xdb950f96df6a67d5, 0x6aa7a52e38415b5d, 0xa3bbbbea127c8d19}, gfP{0x250c55b431c9ff5, 0x788b71cfa722d91d, 0x1b7ff8f263f7e058, 0x19e07e2e11d3c799}, gfPOne, gfPOne},
{gfP{0xa48c4767ad45f7fa, 0xe4e180d4073c21b5, 0x606a49caaf4e22e0, 0x824b6a4d362cb4ab}, gfP{0x123813621182b89e, 0xf02b168a564ca3f7, 0x5946559985a31a8a, 0x83898fb99a58ae51}, gfPOne, gfPOne},
{gfP{0xd8ce0f64e4ff7789, 0x56a63f768bf4dfd6, 0x70c98904775436b2, 0x53cac0d685e11505}, gfP{0xfad84ab4c6cd3523, 0xa3a9aa3de679b3b6, 0x62dc68e29df06692, 0x165cb89486b919bd}, gfPOne, gfPOne},
{gfP{0xbc063c49d27436f4, 0x119334185d04c00a, 0x5c594c453bf29d17, 0x7be93482f4d6bad9}, gfP{0xf1388389af5af70b, 0x6ef88fafc3dbd925, 0xd0dab7df96b102ae, 0x7729f40268a44371}, gfPOne, gfPOne},
{gfP{0x48366c8fef21e70a, 0xb6bdc599cad5b296, 0xc266da496d7a1404, 0x8c25ba2ebadcfd39}, gfP{0x5c4ef2925ff4e88c, 0xf2b74b199450ac63, 0x4051bd06b5872f70, 0xaecc1319fcd16799}, gfPOne, gfPOne},
{gfP{0xf60e5b5fe3819130, 0x4830068ec8b0e199, 0x24b318b6ff94d5fc, 0x80c741851155f73}, gfP{0x54e7078f8bac638c, 0xa5c3470027b932ba, 0xc2e539fc817c91b5, 0xaa43e8d515eb4a7c}, gfPOne, gfPOne},
{gfP{0x7b506fc61ddfd6ec, 0x4e632e9298b40b2d, 0xa43f822c58d2a7ed, 0x1bbc9e5ce1eb4ee0}, gfP{0x8edff18d25e883a3, 0xc72fb0fbc31bb149, 0x753ef7688bd5023b, 0x3c67b97fc7ed8488}, gfPOne, gfPOne},
{gfP{0x30fc6ad3ebd49d9f, 0x1d686366dc98bd38, 0xab8db50a5aee31a7, 0x586bd3c5b99f378}, gfP{0x54ce3fdbe76e1035, 0x12fc82b1c534bcfd, 0x4fd44f4d8bd614ef, 0x3ad2b84e895120cd}, gfPOne, gfPOne},
{gfP{0x4e2752dfcef9a7b1, 0x29ee26be7d1dc039, 0x498723beacca21cb, 0x4dd1216cd612d819}, gfP{0xecf91550e64f05db, 0xbfd127755f5584df, 0xda25e36c32b07282, 0x80c4bd0f27d04818}, gfPOne, gfPOne},
{gfP{0xeaaffb627720c7e0, 0x406b37eae3fc85ef, 0x73f3ae81e3e1bb9a, 0x515131669b5f34d3}, gfP{0x851172e39f098ea1, 0xeb700aae74e621b6, 0x1250f804737e2ffc, 0x3f64202e3c2471f9}, gfPOne, gfPOne},
{gfP{0xebca04ef2e690c80, 0x1743bb12cc939039, 0x1bd9c7045064ea4a, 0x57cf7f70c75d7c43}, gfP{0x28d1a0e85f17ca2d, 0x6f5488b94b7cf41a, 0x46c513898c82c77c, 0x108b7158e1af75b}, gfPOne, gfPOne},
{gfP{0xe47e9bf0ef164509, 0xb7f3c26d59054e84, 0xc3aa94875c7f8b15, 0x8021e363d66a23ac}, gfP{0xe0a58a2ef919b471, 0x136500be029f8032, 0x1d00062ef3b0927f, 0x2139140a5be88669}, gfPOne, gfPOne},
{gfP{0x6967658082b3212c, 0xa53c40b72cd997c9, 0x6820179490ffb5aa, 0x97cb3e002e6c383e}, gfP{0x8ecc4a2ccbe4be7b, 0x2733aac0fa4d64d3, 0x82771ac33f03c391, 0x658a1cfd726cd85b}, gfPOne, gfPOne},
{gfP{0x881f1dfd166cd3c1, 0xd308eac84be917c8, 0xf5b6207a3992b980, 0x261ae33ba5f17e39}, gfP{0xbe638db9fd976a70, 0xb7619dd3949f24e9, 0x56518e2b24e07ede, 0xa77bfab0e221f51d}, gfPOne, gfPOne},
{gfP{0x9320230398a59e3e, 0xe4653faed943ea9a, 0xa67cc03ee268cddb, 0xaca53dab149ca84c}, gfP{0x8805fdee234fba5d, 0xa6c57d16a76e7bd, 0x93f72c93b7b50870, 0x61f4ff4d499f2224}, gfPOne, gfPOne},
{gfP{0x5aa749b0a053d5ec, 0xe989c59830162157, 0xa58c960ce6cdfd15, 0x74868ad561f95d32}, gfP{0x8d5aa4b4640a5307, 0xda75bcdfac06e18c, 0xcc0467e2cfdaba6c, 0x673644fdbb0cb089}, gfPOne, gfPOne},
{gfP{0xca842194aff45433, 0xea3cc076db5cdf3c, 0x668d48a59ea1b825, 0x78ed978fa0134cee}, gfP{0x186a0d74dcc6c73c, 0x39fc9c4ec0d2384a, 0xa9e4feb0678e0da1, 0x7a75fa1ee6018144}, gfPOne, gfPOne},
{gfP{0xd78a3c59ef7f1986, 0x6659ccc0c16abffb, 0x2e9ed6a476a57e8e, 0x2c252b5c0a72cb2f}, gfP{0xa5c4bbb1b6af7b10, 0xb06c5b6e7324f7bf, 0x1a0a1f6714b34074, 0xb22cad4f3a54689f}, gfPOne, gfPOne},
{gfP{0x8a324f2f8bfffa23, 0xb4d694d0f269607e, 0xa50ce3e9170bc6f8, 0x29b9224c74185802}, gfP{0x77ed167bc69d4cb9, 0x86089a8cc90f62b8, 0x43a327a1eb0fbcb2, 0x60f5dff2805841be}, gfPOne, gfPOne},
{gfP{0x3a2270d001db2320, 0xa8bab01612daa280, 0xf5aebe1efa734eab, 0xcf7d26649b8e098}, gfP{0xe413aa47f5db8e9b, 0xb92c3b03dc76820f, 0xed606d81174d73fb, 0x74e637c051d960bc}, gfPOne, gfPOne},
{gfP{0x94a203140becf139, 0x615d0c1a9209fd80, 0xd15401f67b8766ce, 0xa81adfc4d904de0b}, gfP{0xe636bec345e6f9b3, 0xb01cc79c5ca91750, 0xae8334a81ac560cf, 0x76f212cbdb2f69d4}, gfPOne, gfPOne},
{gfP{0xc88d68fd9db1c411, 0x113922e3aebfcb57, 0x56104db14f59b8b3, 0x1a978fb2fdd65680}, gfP{0x2232a99fcf41f354, 0xccfd83f1670ab665, 0x999957f9258485fd, 0x59f80b1e0eb01af6}, gfPOne, gfPOne},
{gfP{0x8badc0707b3e0f03, 0x45281f18b7f2e0f7, 0x60fd788812a2882a, 0xd41befcc5d24be3}, gfP{0x522cef4a0397fdf1, 0xd3cfaa924a7af62b, 0x53939b3f87762ba9, 0x6b6e72b8e9c9cb59}, gfPOne, gfPOne},
{gfP{0x13ea6f5d2bdd3a39, 0x92af44598a10365a, 0x22fc94fe947ac0fe, 0xb5714e95e84acf99}, gfP{0xb647673d1ee38529, 0x7e183dcd41859746, 0x776698b19f585432, 0x4cc5626601296793}, gfPOne, gfPOne},
{gfP{0xe078f6b73682aac5, 0xa0d16d7aee10e620, 0x75c4963e4ee2f8d1, 0x70d50c991fb423e8}, gfP{0x413bd39ebf905c02, 0xa624e1a1c323d263, 0x3d6db3cd89f8260a, 0x8d5f5fc35a3096fe}, gfPOne, gfPOne},
{gfP{0x906ff875b036c48c, 0xa61b4272083f58e5, 0x426c509d0f1f14cc, 0x125c5c1b652f56f9}, gfP{0x61662d9facf98736, 0x13b8cf4fda8f0ab2, 0xa04392a5ed43919a, 0x7138c6281dc8a358}, gfPOne, gfPOne},
{gfP{0xc1f5a1ec1d4a931f, 0xb55f483542b73d0b, 0x34c38a1bf02c78a0, 0x2e00f1cc14f4f38b}, gfP{0xc1a65107d4b21963, 0x4d1db32627ba25cf, 0x5c9082c451fc4977, 0x963d57c398a03486}, gfPOne, gfPOne},
{gfP{0x1e8eda93473168b3, 0x6630e072cda89c59, 0xceba69050e0855e9, 0x68c4432ffe681d8a}, gfP{0x953d607e1f132456, 0xaa5e328f36c3a309, 0x86c4e579a9803d1b, 0xb62fd3beaaf64aeb}, gfPOne, gfPOne},
{gfP{0xdbed084684a66484, 0x3b0a02f572b175ab, 0xab13dc306c2675f, 0x9d55879efe55c5e5}, gfP{0xf285db494a98699c, 0xafda167292cf1207, 0x919de983868de3d0, 0x93fa7e6e88295714}, gfPOne, gfPOne},
{gfP{0x1134adde63f354d2, 0x55b6d0b3f39881fa, 0x6de4786017d9c995, 0x510df70152e82884}, gfP{0xd916ade24b2b030f, 0x9f45606cf95f4f7d, 0x4d62435110d74125, 0x78104e21338f37a9}, gfPOne, gfPOne},
{gfP{0xfef164af9aa2d8f4, 0xf5e6ea027ac1a9d2, 0x74755029091bdd71, 0x3c8dc342834b6518}, gfP{0x70edfa49ae738118, 0x713ad62ae7ed4ef, 0xd40b554945e4f69f, 0x2a6082a27fc5b177}, gfPOne, gfPOne},
{gfP{0x71d58474b98c32cd, 0x318253354b0aea62, 0x6d650c5da40ab7b0, 0x21b309b555fcd0e2}, gfP{0x6b9d317bce5eed71, 0x76d6e0faa15c7ff7, 0x26e540e1b80321a5, 0x730fd3e881c02854}, gfPOne, gfPOne},
{gfP{0xbd86c27cf80f6eb8, 0x9d7a96ab828f4085, 0xc8787877318d7942, 0x7890355636f2b16a}, gfP{0x262dc2e60119c80, 0x52e671c9018dcacd, 0xb31f80b5a48723b4, 0x2a4d24a583ae6a05}, gfPOne, gfPOne},
{gfP{0xbf1ef20fb065e1e9, 0xf24cc32a1fa5e9b1, 0x6dd3a83d684e952e, 0x3c6a7c37bb5ff605}, gfP{0xdf3213c7541c232a, 0x7d6c66f945245fb, 0x3a235d3ec742e8b7, 0xac6d5793c8ca9309}, gfPOne, gfPOne},
{gfP{0x188eae4d41449632, 0xc7e0beee046c3874, 0xf8a54dad78a545fa, 0x8bfdeac61a6199e}, gfP{0xc0d0cb8b06894629, 0xbc6371c53bb38c52, 0x5c2dc825dbbef484, 0x171a1406bad6cde8}, gfPOne, gfPOne},
{gfP{0xeb8fec3a236d5d0, 0x36827277856bec43, 0xf7946475abbf523a, 0x6ecd8484079ea6fe}, gfP{0xe37e11c6b099e7b2, 0x36e39126b3c91f05, 0xda27ae3216198eb5, 0xf843d69554f0559}, gfPOne, gfPOne},
{gfP{0xf4cee0c56e48fc36, 0x538a9996f233a292, 0x9ac7d480d869f7b5, 0x75dfff19190fad6f}, gfP{0x5917496cf5ad5f3b, 0x45376fb74448fb0a, 0xcdb41afc9ae5cb6e, 0x1bae67a5941c2095}, gfPOne, gfPOne},
{gfP{0x76b60749b85fc866, 0x79ccfff2d4eea1d1, 0x35e3ae6013927f78, 0xc48a87b01fd6f2c}, gfP{0xcc231463ece30029, 0x7c545f1b1c2bdceb, 0xf837b31e6da665e9, 0xad58175b15733602}, gfPOne, gfPOne},
{gfP{0xba8a7e6fbcd62b67, 0x9b1a134874e29946, 0xd63ac7be2a3fa56c, 0xaa2c408f5ac16bf8}, gfP{0x8f585d07996aedbe, 0xa279a032be82e745, 0x1c52f3871cf97906, 0x39d17f442217e279}, gfPOne, gfPOne},
{gfP{0x6955894d84099066, 0x42d0f9e10488ba6d, 0xb46b30e20f26f99, 0xb45f8609005157bd}, gfP{0x89bb9a935bdb5c74, 0xc7b27d8f84a99805, 0x72866e902086870d, 0xaa35bb629ab9119a}, gfPOne, gfPOne},
{gfP{0x2a9d9b9bd12856d9, 0x41a946cb01b6d9a, 0x2ed589fc20dbbcad, 0x6f2ae74751fd2c9e}, gfP{0x615908a21e1e53d6, 0x473adae775bdffbe, 0x6555651372b5442, 0xabb8e40e997d67d4}, gfPOne, gfPOne},
{gfP{0x8c3f63b337e5be4, 0x873a15f866bf6bce, 0xf0198996be94868d, 0x6a9a959f5d34d589}, gfP{0x6bf12f1bac06db7b, 0xdbb09135c792cb18, 0xd52e25881fe26650, 0xaa18ba300c3c5542}, gfPOne, gfPOne},
{gfP{0xe3322b14d0058fea, 0xa7054b5109a0867e, 0xfb8d5625590e4902, 0x592621d50063de5d}, gfP{0x1c9a300af8eadcf6, 0xc6a7aa9c4ba3a3b3, 0x54cc20635591df9c, 0x767d1146776466be}, gfPOne, gfPOne},
{gfP{0x3d9a1c43be69f030, 0xb67483134ae956b0, 0x66ea89010fcad992, 0x58299a0d83ef5ea5}, gfP{0x583aaeeb4e36d413, 0xf1f6082008de3ab3, 0xc7c79916abd241cf, 0x28725f8bd264ded4}, gfPOne, gfPOne},
{gfP{0x824a9615a5c52a31, 0x86a6a26d4949830e, 0x9724559ffa6798f7, 0x39688b7ac902aa85}, gfP{0xc1aeffd9743f0831, 0xffa8acede8593906, 0xd3d547f7d9832de7, 0x66de1b690170f36a}, gfPOne, gfPOne},
{gfP{0x40e1c1513da71eaa, 0x71ed359497847585, 0xa45a19d19b1e6f33, 0x84b7412821186f41}, gfP{0x8bd69894806e3a1d, 0xb0ee7ab013af20f, 0x7cd371ed4e97c36b, 0x68563ee8764f345a}, gfPOne, gfPOne},
{gfP{0x46f64915f6a708ef, 0x5e96a75c790f9c42, 0xadc963e8f8f272c1, 0x7a7e2536a99d3a36}, gfP{0xf9472e631d52bc0f, 0x8b04b9c53b647691, 0xb4ac69af1e267c98, 0x3ace4cdc41d24d6}, gfPOne, gfPOne},
{gfP{0xe8db4e2de49ae8b3, 0x42f3d07ec34d1f36, 0xd1e144ae4217df3f, 0x6a31f7844f7a6ec3}, gfP{0x5b74d5405e12a0c, 0x11a34480ec157596, 0x88aff221e21b3b53, 0x4823e1ce261b62a3}, gfPOne, gfPOne},
{gfP{0x106501bc52813160, 0x7eca738835aecbab, 0x69ad166336bc8b18, 0xadc193c5cb6211a1}, gfP{0xbfc0cea2ab70ca95, 0x794e0b3ab6e44fe6, 0x1c63615f31403519, 0x34da51fb8da862eb}, gfPOne, gfPOne},
{gfP{0x211ace47487ca54b, 0x167124cfa02d4a6f, 0xf67d81ac451be038, 0x49953a9fa0ed3631}, gfP{0x9c39db45d05c392, 0x21e8ea068ae98cfc, 0x931dc970da019c09, 0x2d9f574d46176925}, gfPOne, gfPOne},
{gfP{0xb5e93687bbeeccd8, 0x89f331916207b439, 0xe39647be10152e3b, 0xaa3873ed3faec88d}, gfP{0xb60c53a84c62ede4, 0x720778e426caa01a, 0xef774fe256a101c2, 0xa9405ea40628fdb9}, gfPOne, gfPOne},
{gfP{0x720b1aa1c1f72b88, 0x1d17136beb55b204, 0x256b886c4a2e84e8, 0x6010d87d30fe6779}, gfP{0x55dc0fd43b406662, 0xb5297061fb1e8990, 0xfb9002c8c34e83ea, 0x9a585bc21f182b35}, gfPOne, gfPOne},
{gfP{0x9d0cd4f8f7365600, 0x79a6f9869f42404c, 0x5d59fedd5b44fe73, 0x230f85ea4e077d28}, gfP{0xe2117fe09cacef2c, 0xbf570a97d8002736, 0xa732826e07e8c0d7, 0x35d882316dcb13d9}, gfPOne, gfPOne},
{gfP{0xa0a20775433dc077, 0xfeec84dd9b74a8de, 0xdb92499dcf7b9305, 0x3a16a7d64723ee9}, gfP{0x42d4e4bf0db521d, 0xf2a95eeb05ff11d6, 0xa11b603e163ecf94, 0x755c77d0767a4af8}, gfPOne, gfPOne},
{gfP{0x16353d84f6b7c958, 0x20953794c350d6b1, 0xd41587927f756b92, 0x9c9f6628a9d20fb9}, gfP{0x394dedea148ea0d9, 0xc3a325bab2250eaf, 0x73d3a7d00a1eb6b5, 0x50e1c63aab01e3c}, gfPOne, gfPOne},
{gfP{0xb44f4dc309e3b248, 0xef16eae6fc37e3c0, 0x3c408755b8609a7, 0x5ac9ed976894121c}, gfP{0x76cf6ec6ab5e043f, 0x68ea8fa7a4f9dd2c, 0xfb53d5a4b12402f5, 0x28647c009605d19}, gfPOne, gfPOne},
{gfP{0x8ba0c929c48b282e, 0xfcd9bc530f539185, 0xdc4c61b874f7448e, 0x413b5593a64ac7b0}, gfP{0xaad3a8dbf48c8863, 0xeb3625429c74b3ae, 0x10be2b63783bb964, 0x818b7476bed411c1}, gfPOne, gfPOne},
{gfP{0x6538ecbec9d27d2c, 0xa067a5ce60111309, 0x90ea4626dfd54ad7, 0x12c941678809cdd6}, gfP{0x354ea78dd40c9dc5, 0xa2aa9237199996a7, 0x860d7aec99168a92, 0x7305f13a1000cdd}, gfPOne, gfPOne},
{gfP{0xa608825ce5cc4abc, 0xcdb2928403f1a6bd, 0xfaf9d390fa39de80, 0x941ad9ce5d7c3f93}, gfP{0x39ca679b55ae25a1, 0xde6f2e45fdb27ddf, 0x2fa0c83f1d152bd2, 0x8e82604227634371}, gfPOne, gfPOne},
{gfP{0x5d58a10749ed05e6, 0x2ac99fcaa38efbd9, 0x12506cb29c16a00d, 0xadecd8a116835070}, gfP{0xeefea708f32793e1, 0xfca12e87d789154b, 0xed8dc1b47ba29ffa, 0x7eb0b91868f5bebf}, gfPOne, gfPOne},
{gfP{0x40f11e071b72225e, 0x1e2004629f2c761c, 0xbf0f478b1ba6d5b4, 0x8925918dee747767}, gfP{0xb576bf68bf067cc6, 0x9892cc697e2b7b11, 0xa27752a4e1d172d6, 0xac071a201a4042d5}, gfPOne, gfPOne},
{gfP{0x414ab8de0e998a9, 0xe6b76b533b13a8ff, 0x3c14e5384013b578, 0x716b8aefb78f23bd}, gfP{0x9e9ee97502cbb199, 0xb55144227a8ab0e3, 0xbc498660e38964de, 0x34601293617f87a7}, gfPOne, gfPOne},
{gfP{0xbe97fd85d257b670, 0x3cce7057d39d7947, 0x1cc124d0f0ed37d2, 0x9f8ac5ffa5e75faa}, gfP{0x633c732a8de82bd8, 0x221bc8c2dd8b46c5, 0x76ecc18258be2e38, 0xb16f0f8b0d2dd9a4}, gfPOne, gfPOne},
{gfP{0xb9eb4029312873cb, 0x3d0080eae0e403f, 0xa7485785e65efc76, 0x26ffe8df4aa1ef59}, gfP{0x492bb2820005bea3, 0x5ca793172a005105, 0x20fd999474b767b0, 0x52ed49358aed4b7c}, gfPOne, gfPOne},
{gfP{0xe3d84dcbdfa12a76, 0x8864adf5b5a9175b, 0x94bec16389888233, 0x2032edcb36bb0d72}, gfP{0x8082463af9e87516, 0xee12522b927d2ae8, 0xfbb4d5c51fa33c7e, 0x25588c80a3f90ea3}, gfPOne, gfPOne},
{gfP{0x983ed8aaf1166b70, 0x37664d28789570bc, 0xbdb0ef89bbd065dd, 0x988c762b5abd2c16}, gfP{0xba1b835fb556181c, 0x2c4e63c063ed161e, 0xcb2ab2a379ed6179, 0x64abe36bf1d027b3}, gfPOne, gfPOne},
{gfP{0x79b6eb3c2e2a57ff, 0xede997305ad1e6ce, 0x395b0f074e9adca4, 0x36763c5d6c7dc962}, gfP{0x2611a3268fb513a5, 0x5b1100f2e584ebf9, 0xe163637e560f1e0a, 0x68d51102d894b745}, gfPOne, gfPOne},
{gfP{0x3575419ba14db070, 0x8e4017ed6c48d863, 0xf511e5df8ba366e2, 0x92ccc874e705776e}, gfP{0xb660ef2719055025, 0x332704c4b5481f31, 0x10dff3b0aabf8519, 0x5f3ff6b24f31556d}, gfPOne, gfPOne},
{gfP{0x4334a50f1b32d674, 0x5c43ea02f0790984, 0xc91608a20f077098, 0x62136c46945f0c3a}, gfP{0xdfcebedbc69b0009, 0xd593c6a81d7104cb, 0xbd2462ce99955377, 0xa18058b5b7d9be5d}, gfPOne, gfPOne},
{gfP{0x115a73ef193685f9, 0xc157bc6218e65afc, 0x2eabbff541d10279, 0x5ce6f554f711b006}, gfP{0x4ac7dcb9978048d1, 0x3e574909358823af, 0x27f47eb83c200955, 0x4d73e7fcd690e7f2}, gfPOne, gfPOne},
{gfP{0xc0cd07cbd8212ad5, 0x7f1e46cae3dff575, 0x44a15c55be60b28f, 0x85f19ec8f6842569}, gfP{0x2a6677c5a6ef37a5, 0xc51fa1b63ca929ed, 0xb7b8fd7f7bc4c6f1, 0x6ebcdaa64e2122ce}, gfPOne, gfPOne},
{gfP{0x6502ac10b38633b5, 0xa927a3afdc54b416, 0x90b4af2a84170172, 0x3d57c9d28093c883}, gfP{0x5db19094e754fd5a, 0xff1b1443a50dee7d, 0xcfd245e95ce3b460, 0x968f7d0683fdb25e}, gfPOne, gfPOne},
{gfP{0x5c3da2cdbbedd5e, 0xaad0342187a951f0, 0x5b4b619221c478e, 0x37d3c2d67289704f}, gfP{0xccaeb4862e2061d9, 0xad32a200cf7d0b45, 0x9c22a26e2e3c2127, 0x76b083f8341d20ad}, gfPOne, gfPOne},
{gfP{0x263ee9d812c7419f, 0x7f93786a02b2f619, 0xf1c1953a3f5c9c0d, 0x58dc489898ca7e97}, gfP{0xd26352014539922, 0x8a12bf5417e9b2b7, 0x868353ccb9ea5eb4, 0x984d742d3194f68c}, gfPOne, gfPOne},
{gfP{0x6f11c1ff9e677a52, 0x3549cce061a37899, 0x73429a05e6b79e4a, 0x8f0116f4df9a9c02}, gfP{0x8dd62ca763689eb, 0xed93cdf26eeb2584, 0x1a426b677a27fb98, 0x11b62f7981759c9e}, gfPOne, gfPOne},
{gfP{0x9840a8afd68eca0c, 0x4954f87e287141b0, 0xf7678f62a428bf98, 0x6fe0e8de9fc08c29}, gfP{0x7a9f5c062f94d115, 0xd4aff7fd35534cf4, 0xef64f859ae181e1c, 0x44c07654b965d38b}, gfPOne, gfPOne},
{gfP{0xfcaf82553564df72, 0x9d325288a9d4939e, 0x6b36f46d600aa367, 0x7105b89b3434b1a3}, gfP{0x5df1f095a95f929b, 0x9ce70fd0310648d2, 0x89fd03aec77964d8, 0x4fed56ceff545a4a}, gfPOne, gfPOne},
{gfP{0x64764b7bb6239729, 0x181105ca735abe1d, 0x5b9da89f56e6c2e0, 0x1eea2a4e1aa2de7a}, gfP{0x3cb21bb630510440, 0x97e187eb9932a11d, 0x931c8398bff1e20d, 0x258dc6674bed422f}, gfPOne, gfPOne},
{gfP{0x370fddbb6b7f604c, 0x1be3bbd9762378af, 0x7b61365888a632e3, 0x10ae8c0dcabdfee7}, gfP{0x3c77a13df0464cc, 0x17cef87f89935d61, 0x2cd1a2ca7c6f7376, 0x263ff055296e52cf}, gfPOne, gfPOne},
{gfP{0x6612342391b24bba, 0x5d205cfed1b91a17, 0xeae23b4f4b83bc4b, 0x5c05cca6e01c121c}, gfP{0x4eac0851dbe45205, 0xb2570a90aea38fbd, 0x439512c3379768a9, 0xa924db69e7777acb}, gfPOne, gfPOne},
{gfP{0x4d17705bf10975aa, 0x8e00333978d9279a, 0xe22134361c0badd4, 0xd5cd7185c4869fc}, gfP{0x2d0052af0ab8d419, 0x6c85de0a8c8d5982, 0xf15eb75495a95d69, 0x4bba811f1bc58f4e}, gfPOne, gfPOne},
{gfP{0x91f87ac5eb523164, 0x48bebd7ae3dddb69, 0x60f0bbea0e3bd9b3, 0x98e6c9e521602c7c}, gfP{0x8c4f4faa028625d6, 0xf4b022ef5dc884b0, 0x71086741ae76ed4c, 0x1518f40f0f43a727}, gfPOne, gfPOne},
{gfP{0x3c481b1d915add48, 0xed714c4083003f0b, 0x89033c4b020afcd5, 0x95889d020391b7cb}, gfP{0x4e19f9c2fa47aef6, 0xd5e2e0fc4e124b11, 0xbd32b8e03a2845d1, 0x9b6e0dd3e488fb16}, gfPOne, gfPOne},
{gfP{0x5ed358e5bc0b2935, 0x168977c14dcff470, 0x8e660847f4de3a7a, 0x8e8cb75733112c06}, gfP{0xe803a1a340d787f7, 0x335503fdf35031ec, 0x521fedc50b919f58, 0x89850caee4b9262b}, gfPOne, gfPOne},
{gfP{0xd05420aa538c7a87, 0x8fb50556c67b4366, 0x1be6bd5c21bd4725, 0x300e146021f3137b}, gfP{0x64620bdf2ebaa06d, 0x64e350730197e640, 0x7bd723439598fb71, 0x59860c474dfad3ec}, gfPOne, gfPOne},
{gfP{0x4de646a757c13340, 0xba917e80e41c16ae, 0x8a7f12cea8f5c746, 0xd9c8daab2139fc0}, gfP{0xac592e328c605933, 0x2346651fdf95705b, 0x9a34d38a4dc68ae9, 0x9f85891cbd0c8aed}, gfPOne, gfPOne},
{gfP{0xfae4ca646fc5e5e1, 0x297908c8f667134c, 0x57fd620042ca1d36, 0x97c814a8de79280d}, gfP{0x269a0154be7b3934, 0xdd3e349c02876986, 0xa7d6382637f5c8d5, 0x1738b7c8a88ad062}, gfPOne, gfPOne},
{gfP{0xe586d93cdd516a61, 0xdcee53ecc80b9e63, 0xc33205c1b2eb74c0, 0x3a483b0701b78440}, gfP{0xc352ff312a68345b, 0xfcb4ee5df2ea078b, 0x198f90e045a69df0, 0x3544e4f73c391865}, gfPOne, gfPOne},
{gfP{0x590563a9cbbcfff0, 0xa4e7edda60a932a6, 0xd76f2880de2317a4, 0x7768254330f06fb3}, gfP{0xea957024d3788ddb, 0xbdfd626b0a1afea7, 0x2a907531357c9abd, 0x6f51715ec7044d0f}, gfPOne, gfPOne},
{gfP{0x97282e41d4351fba, 0xa36e9c64623ace19, 0x483d42491d286524, 0x18f1ca9aeea3ddc8}, gfP{0xdc3b902fe58f5857, 0x7613c42f6066428c, 0xc13e80d3fea09ad5, 0x90509dd1a70b6110}, gfPOne, gfPOne},
{gfP{0xfb3fc4a81f3dc686, 0x4093d890a612d364, 0x3837e94d3170975d, 0x6e36e4af6cc3419b}, gfP{0x9e2cd9ce06880db7, 0x4f3110b8cf5ce617, 0x79e94314145907d8, 0x399307d090ee9ba5}, gfPOne, gfPOne},
{gfP{0xc210799781fc48b0, 0x22ceae2aa9891ecf, 0xe2b84d14801f3245, 0xa8ccd51d64e40fb2}, gfP{0x9079f62930998b90, 0x504c392882e40772, 0x7085121e6dcd2b15, 0x57b8c8505bfcceab}, gfPOne, gfPOne},
{gfP{0x64a4993852f5b9c7, 0x5f45d5e94791ae58, 0x836bbecd8b89d040, 0x98474b3b897d388e}, gfP{0xcdab423f599772af, 0x4582ca250b16ace3, 0x171d5a4d142873b4, 0x54400a3e41cef07b}, gfPOne, gfPOne},
{gfP{0x1bab86205cda1c29, 0x9ee3b9f2e162e496, 0xfd6331f5c24ccbb3, 0x6a9ef83bcb5d566f}, gfP{0x67efe9609c0083c8, 0x452af9402e003787, 0xdda89e8ae101f62a, 0xa85b84dd78d841c2}, gfPOne, gfPOne},
{gfP{0xb31fc5aa600a20d, 0xfba6a045b23e13ae, 0x44823e6bd3563b13, 0x829db68b576f0982}, gfP{0x1eb562cc9d735919, 0x40e5a20e0ead0ae9, 0x8c124acb751d628a, 0x2c8c21742d9b9f43}, gfPOne, gfPOne},
{gfP{0x46f0d0f5d6d129c2, 0xb494c2fd498f937b, 0x1fbd7e630176cfdf, 0xa1c5ce6c1d33ef59}, gfP{0x87fa70a2c0ff259d, 0x3531a52e69ec3cad, 0xb377cdc73f6f6462, 0x7cb05f0a8978a10e}, gfPOne, gfPOne},
{gfP{0xf607af06c06c53d9, 0x7356d578b859e65e, 0xe254a578d5f4c8d8, 0x2c57ef07b5536e09}, gfP{0xa6ddce3c2d4f5821, 0x68ae883a81cd347e, 0xa5a44d5c4bc80505, 0xb1cb133e22d36bd}, gfPOne, gfPOne},
{gfP{0x5c0f67375ae7f2fa, 0xe5b92c43299e230e, 0x4279aa232ed229b0, 0x3b5198d7a8ac905b}, gfP{0x925893fef10b0f8d, 0x312451d87d8c32a, 0x5261c9793d01ed0, 0x7ffd6adb069555c5}, gfPOne, gfPOne},
{gfP{0x7e9819f25b6f49f0, 0xa165ed57e7ecffc0, 0xffd727389210a4de, 0x7d7ee9847d136be7}, gfP{0xe86afc5004e46574, 0xa4576da0eaea465a, 0x8295fbfd4db53be5, 0x96f139175b902637}, gfPOne, gfPOne},
{gfP{0xa8161de0137459e7, 0xed26d9be56eb74d4, 0xd7f783d44ab10cbf, 0xb067c357190a2519}, gfP{0xb55fe28dea58fc1f, 0x6d5995642816e6fe, 0x4973d80131f5b0d8, 0xa0c3654d2dd48af0}, gfPOne, gfPOne},
{gfP{0xd090af1856767757, 0xb85d008482f8e88, 0xf2aa4e278808cf9e, 0x151773a86176fb2d}, gfP{0xce967c4eb17c7f07, 0x540773713ab54f34, 0x50e0255d724bbf59, 0x6085efa7eeb4ac82}, gfPOne, gfPOne},
{gfP{0x7266214ee25d755b, 0x3f1bac093a4cd13c, 0x7c2b3c0e21135190, 0x1135a481d684fd59}, gfP{0x975dfe6d2dc27fe6, 0xfce89892ee71e065, 0xf89ec547a405a924, 0x3fe3f7e718943ad4}, gfPOne, gfPOne},
{gfP{0xef033d82311eebb, 0x89d2c041580f57ac, 0xdcae878d619d1824, 0x206a5912a841e9fc}, gfP{0xd55f2153368e3694, 0x664cb4ca9aec59fa, 0x1772a69057f13d21, 0x4f7b6c2bff08deff}, gfPOne, gfPOne},
{gfP{0x84f3c2f8e86f77d5, 0x9dbb1eea12d3b1ec, 0xaa58bf0262b96d4, 0x9f01d5234957aba5}, gfP{0xdc2f604a19db7ccc, 0xbbbbd07772f1b86c, 0x95b77c12c0d01f89, 0xaf1f3b3c10fa6be4}, gfPOne, gfPOne},
{gfP{0xbf0973de7c146bc9, 0x2d21a9370bad7997, 0x147a456b4c17cc4b, 0x30a65d0cde47b1f4}, gfP{0x2ed45ffa76e6f648, 0xd623f83741797c6, 0xaf352b1eb978d59d, 0xe3089c3a6ba80f6}, gfPOne, gfPOne},
{gfP{0xacc6c81ced10afbf, 0xc42e4c69094d434d, 0x7c66c9ae0439f9fe, 0x6a8a275ed9beaa17}, gfP{0xe3ea5e9dac373a0d, 0xea88f5b85cfa1342, 0x43399541fb6a7339, 0x5a8887323d54b831}, gfPOne, gfPOne},
{gfP{0x7410f5647175c5df, 0xf0736a67a17d946f, 0x156232f9e14d9553, 0xa20c9db536605ba3}, gfP{0xc4295cdbd2d895d, 0x8beb1cbb7ae81a6, 0xcd4416021e48dee5, 0x2588391574b38a8a}, gfPOne, gfPOne},
{gfP{0xb4bce7fe8afdfeb0, 0xb3f209b20eb7fca4, 0x611508b9e42669e6, 0x554fdbefa12f9eb7}, gfP{0x21092a8398ee490b, 0xb80354e1900e18fc, 0xd4f406837573ee26, 0x9b67f2af1991d160}, gfPOne, gfPOne},
{gfP{0x5727cbf036bea734, 0x65e09bd30080f047, 0x3980938524d98d30, 0x3c8dcf7bd09649dd}, gfP{0x2dd764f80da0310a, 0x495533cc6ad98171, 0x6b9157c6468745ad, 0xa245beeb2b14f3f2}, gfPOne, gfPOne},
{gfP{0x8bd9077793384ac2, 0x562cfab6f939044c, 0xe48a7412cbeee7a4, 0x7018feb31e1b2c27}, gfP{0x93a427c3005e372e, 0xd75aa13fd23f9921, 0x118cdda96b6e31a6, 0x7cca0c12e96bd486}, gfPOne, gfPOne},
{gfP{0xa8c4c68b780611a5, 0x18078ce27c324720, 0x76b7c26b4deebc2d, 0xab4d5378198164cc}, gfP{0xeae5015c1ef6c357, 0xc3dd2cecffa75882, 0xed6084959e038501, 0x9584d10b8e7a70b7}, gfPOne, gfPOne},
{gfP{0x2b81209d5addcdfe, 0xad2f5ae187091159, 0xfb5c3cdd44b8721c, 0x3d8429baf0dfd4f2}, gfP{0x7d3c7781fba9cc68, 0xab7c17165597393, 0xefe1a4e041e5a378, 0x8dd8e1085a5f3b5d}, gfPOne, gfPOne},
{gfP{0x693fdfb2d1b5ce76, 0x9b99131b233bf443, 0x748c70c0fea0db39, 0x4d96b164e94d991f}, gfP{0xf86d964810036e6a, 0x6b35736acaed7e5b, 0x6dad59ea9ea74eb5, 0x33d6b63c63c2c4e2}, gfPOne, gfPOne},
{gfP{0x58b7fa4310554a0c, 0xfc546ad4307e6d7d, 0xc36f12a82829504e, 0x3aad0c349b2ae784}, gfP{0x84f88d045a8d2896, 0x9ae85ad2a08b5a2e, 0x74fa88f884f3427e, 0x6d3f6a6e9a5e17b}, gfPOne, gfPOne},
{gfP{0xda8a7eb57a0909f, 0x861c3852ed669eb6, 0x904a8fd7d78c0477, 0x2bf38c5266ff7f13}, gfP{0xaca83398fc6f56fa, 0x53e74f563e1ba586, 0xd1099266e1a51e15, 0x218b81f78644e34e}, gfPOne, gfPOne},
{gfP{0xc1f0d533401f7e5c, 0x7071b18ef39296e5, 0x3df64d9d47daf2e5, 0x27ac74a2ebbccec6}, gfP{0x38c334a351e3394, 0xc1df38aea7cb54e0, 0x8b34c70bf0635f43, 0x75ced38cf5ea0e90}, gfPOne, gfPOne},
{gfP{0x495cb8edaca5f1cb, 0x6790e23fad2bdd1a, 0x4e9b791f706f35ac, 0x7aaee43677884ca3}, gfP{0xe0fad25bee9933ac, 0xddc7440fa876af76, 0x1016bc57bebf7cb0, 0xa171746e9b34a9fb}, gfPOne, gfPOne},
{gfP{0x16c26ecd4c10404c, 0x9bcf7433ed81d6ff, 0x95431cf91ecb16db, 0x560cd980c9f85c6f}, gfP{0x4fa4d2e4971158d2, 0x89447d61e3417269, 0xbc57d40f7ea3ac43, 0x4907f1cc668f1080}, gfPOne, gfPOne},
{gfP{0xae40cef9890c2f02, 0xcc6e4e4e309f2173, 0x3da5978cc247d6f5, 0x56b82603f89ceaea}, gfP{0x11f239b35b671aeb, 0x41c7aa14f49215e6, 0xb20112224d1c876, 0x331369956009453e}, gfPOne, gfPOne},
{gfP{0x88d7d2f612801225, 0x22fe9f1c57b1ada8, 0x81f6a9e346eeb999, 0x591b5c2d5d8411bd}, gfP{0x8fe5439fc644d114, 0xae100ef4db65e95c, 0xc7830879884a755d, 0x7cc9eb1659f3e68e}, gfPOne, gfPOne},
{gfP{0x531cae056f917bd9, 0x1031c6ecbc0925dd, 0xc9eeb79546a3920d, 0xa7673bf56caaed08}, gfP{0xcb7ca60bf3a90fde, 0x41313bf7ab77fca1, 0xbde1a5d29233e31f, 0x9584faeffc17cd8b}, gfPOne, gfPOne},
{gfP{0xa1bec79c983b6b23, 0x5bd2d8991ada359f, 0x5ad719fc273ab4e6, 0x92a45491401d54f4}, gfP{0x5e24b2d2ac336def, 0xa47afc7646525839, 0x84296cbeed6a9cdc, 0x8b4f5db85a27ed70}, gfPOne, gfPOne},
{gfP{0xa57e0209d24a6517, 0xb6d8a27b9bc2163d, 0xa9837bba7d329e18, 0x82801c146c755c60}, gfP{0xf81732ded37d1732, 0x194bfbc5fce4f0a1, 0x61e9b825dbf0f99b, 0x2c14730ad77d2d7d}, gfPOne, gfPOne},
{gfP{0x855ba2bd144e3fb3, 0x8484d35ca073dd10, 0xbd4449d6a277438b, 0xb41d92303af0b532}, gfP{0x54ce1e06bbf16448, 0xdd831e3a4332cd8a, 0xa86ea22ea244e613, 0x351d2c9dc12a51c4}, gfPOne, gfPOne},
{gfP{0x78bb49dde8c72f59, 0xd2576f7c13b496fd, 0xe0cd6dac3ea9de84, 0x3b86958395001cc8}, gfP{0xe393fdf6a13ffc53, 0xff588cc84c484b2a, 0xc4a3db34ccce4ba, 0x51d6510759e79b8a}, gfPOne, gfPOne},
{gfP{0xc54930bffe6f3c1c, 0x7aaf283db2c27c2c, 0x5a495b239be06d78, 0x5d86eff04938e6c9}, gfP{0x536622c54a3acaba, 0xf4bd2ed5715304a3, 0xc357a5620f690e4f, 0x1e470c3649959eeb}, gfPOne, gfPOne},
{gfP{0x94c8aa5d8e8cb86d, 0x1810d7746bd50fa3, 0xf591515545e91450, 0xffb805168acab6c}, gfP{0xf1a30005396c0143, 0xbecb90a78505b50, 0xe1d60fd1df1164aa, 0x247827be79d3f16a}, gfPOne, gfPOne},
{gfP{0x2b96239bb020fe26, 0xa345605d1e913d0b, 0xaa579f96dbda344, 0x4439cfbf4fb4ce8e}, gfP{0xaff007acc470b03d, 0x273c490c3c2b49d6, 0xdb160421b2ff32c8, 0x2524a4c122d8d817}, gfPOne, gfPOne},
{gfP{0x840e6b0927854059, 0xb813836e02195dbf, 0x9bfb1c74e912a1a2, 0x75975bb88136242e}, gfP{0xd7305cdc108f28af, 0x14df24d4c4e3c493, 0x35e0b29fde00db2, 0xbc52fc8e8d7a18}, gfPOne, gfPOne},
{gfP{0x90af748b44e06b09, 0x17f78f6d76d56350, 0x3b288db795065a99, 0x9235e40c56fdbbfa}, gfP{0xf4a50c1323862b6c, 0x54a141c60c4b2509, 0x21db8173a6bfcfdb, 0x2d2ae4eb455c5789}, gfPOne, gfPOne},
{gfP{0x80fa2eaa6bf2de22, 0xbbf3cdf4b8911fc1, 0x4ff56a56f44b5a38, 0x356b5c75fa47c9b0}, gfP{0x82ab0a802caee0dd, 0x2c61d31ffdca5981, 0x53f50af8945376e8, 0x38c18506b05d6ce6}, gfPOne, gfPOne},
{gfP{0x4cd992e27f5ba049, 0x14b95d0849435c9c, 0x3e92608d9b2d1fd6, 0x5eb556c8c2f3a9ef}, gfP{0x39bcbedd735e7d40, 0x121350b38b9c06e4, 0x7bfb8be1d88a6e06, 0x9f97b1af6989fb85}, gfPOne, gfPOne},
{gfP{0xafd9494f5dd29233, 0x24e6ec2c9047a1c5, 0x7f7fa5eab7ad0c11, 0x71e02f268acdfeb1}, gfP{0x4b5ccd267d2181e7, 0x6d6d7ff8559f169a, 0x3fc9ab99be59ce31, 0x553dd187b585eb69}, gfPOne, gfPOne},
{gfP{0x5ab4f194edec95f5, 0xde815a4ab781a05c, 0x14bffb81514a3fdf, 0xa5df5b0083e855c0}, gfP{0x2389e7ee6a398341, 0x54ccb6ea9fa8fc86, 0xeb6c517ab7a1ea3d, 0x2482a369c18484fe}, gfPOne, gfPOne},
{gfP{0xc2ab1702a0b79a87, 0xb1398d93934e26b8, 0xf52ddf6b9e0d1037, 0xf80f9ccadd9b11}, gfP{0x8f68119840617081, 0xb9ab2db102d4b781, 0xc8edd54cce29b0ff, 0x861bb7f2f528610a}, gfPOne, gfPOne},
{gfP{0x6996c0154c4f8312, 0x2d7b575d26862c2b, 0xed3931824e52903, 0x2807dafacae27f8b}, gfP{0x75bcc4d4a63ffbcd, 0x83192f9ccb705a26, 0x2b72cec2ba4c5d95, 0x36d213696fcb0845}, gfPOne, gfPOne},
{gfP{0x898d44a0ed8805d2, 0x181854ec8b470212, 0x2761242c6a924ec6, 0x54e30da7f5d6e097}, gfP{0xc569547415a57dba, 0x9594e1884b526bf0, 0x1b25c50d453f6ca9, 0x2591e39f42352f84}, gfPOne, gfPOne},
{gfP{0x105193dfa25d0144, 0xc85327ab4117e152, 0xa6b5fac3c968464b, 0x10e4d08a58efc4b7}, gfP{0x95a75b01e1ffc188, 0x2f1f4d9e4e4260b3, 0x857aa04242084dd5, 0x37f2deb806d9467f}, gfPOne, gfPOne},
{gfP{0x6c5e1932effd7cf2, 0xbcff8e6c943f673e, 0x31edf8010e2fb52e, 0xb437bdd946d406f8}, gfP{0x11912eb78a956937, 0x4b796def4c4a5ca7, 0xdad5c0c7e7fbd4e6, 0x55a6dfb61426c4e5}, gfPOne, gfPOne},
{gfP{0xb4fd05309f2f581f, 0xd3ef84c53799fdad, 0xd62fb03f17afe305, 0x4a97389d72ab5a56}, gfP{0x320ffec6f7370fb0, 0xc2f3ffd39cab32df, 0x8af02a7c2739e3dd, 0xf5b216bddb19451}, gfPOne, gfPOne},
{gfP{0x80f8be0bdc0d19ae, 0xf7a4bcc7570d65df, 0xcb6af35b26b6750a, 0x5dca5489c3c2939e}, gfP{0x14447c669891c3d7, 0x513e9b5278639290, 0xe57d787471feed7e, 0xc5944daeb234df}, gfPOne, gfPOne},
{gfP{0xd58f103faba0ac53, 0x71d1f187f22b9524, 0x6401e34eb430bcae, 0x9abfb1f7072947b7}, gfP{0x509bd01835b40fb7, 0xa3eccd73fb7aef58, 0x177365855294585d, 0x9cef811802bd32f9}, gfPOne, gfPOne},
{gfP{0xa78c63617b75adc9, 0x44bd1d8209a56327, 0xd88150065e283bfb, 0x7bf029bdbb754785}, gfP{0x9bccb04c8e25e24d, 0x82248997537cfebb, 0x4cbe840b8e1fad36, 0x7ab6b5c0c32ae32e}, gfPOne, gfPOne},
{gfP{0xd36e81958b531b62, 0xcbceefbaab691fb2, 0x22358d9f10bd2e21, 0x645c4952a4317076}, gfP{0xa8a627af86f3cb82, 0xc2a341ba92202dc4, 0xb10a0e58dfc9f32d, 0x8350461932238401}, gfPOne, gfPOne},
{gfP{0xd3fcc89cac551412, 0xbd2067156c44015f, 0x89330e81cd247b3c, 0xa83ec0f5e410e0cf}, gfP{0x55e0b1212fc1b1ef, 0xa322d8ef94a49648, 0xc143a50dc1e645ac, 0x8b735f3fe79013ae}, gfPOne, gfPOne},
{gfP{0x7fb26ccb1301e9b4, 0x324cde2d74c9f08a, 0xb87fa108174bbdd2, 0x12ca37dd0ddf005d}, gfP{0x342957fa2ffae4c5, 0x19d5dfcfdc8667b, 0x2e38c0caa2d39c88, 0x94c91a4c0906d5b3}, gfPOne, gfPOne},
{gfP{0x958d3a0712f3d33d, 0xd411034ca87dfc0, 0xfa902c8a688ce8ff, 0x938ef64d891e8743}, gfP{0xea976ceacccd2292, 0x46ab736e33af026c, 0x28a1dd2f69d8cf43, 0x9027c9302ae61b8}, gfPOne, gfPOne},
{gfP{0x26972d395bf47b0f, 0xf530019faedaeb82, 0x1034f0fd61746b6b, 0xaf9d6076e2a18d4}, gfP{0x94392022b386df88, 0x1b92a10306b78fc6, 0xf932b7cca9f6c894, 0x6bc7762dd5fc88f9}, gfPOne, gfPOne},
{gfP{0x56406c075a3fc67f, 0x7cc1c7f1464fa936, 0xca39a5d5a332095e, 0x96d1793defe51974}, gfP{0x9af0fa8ac71b0926, 0xd8a293125f0fbbf6, 0xd4b45e28b1f19170, 0x9397dcd44d612ed0}, gfPOne, gfPOne},
{gfP{0x20c7d06e2b4ea3ba, 0x4206b7291f401d6a, 0x7c788a3324638462, 0x3bd9b441b713f93}, gfP{0x33b74f18051318c, 0x681c4ee3bac4038e, 0xfa63b1c04d4feade, 0x6b6024c1f398ab06}, gfPOne, gfPOne},
{gfP{0x7b337bcbbd4f9f48, 0xb61b9cc98b054189, 0x31f2d272f087484, 0x4dd0d9306734de55}, gfP{0xa26e5a707412cbc8, 0xf22c8f73bcad45e0, 0xdef7d16c6ef8c336, 0x3fac4f30d55ee94}, gfPOne, gfPOne},
{gfP{0xdd2c191ebbc21073, 0x81de1d7ef35317f2, 0x58485d136712131, 0x530fdeb2cc474f4f}, gfP{0x69011c8b81da7079, 0x569b09f818f83323, 0x134bee7a04f369de, 0x1f47848d0d485a42}, gfPOne, gfPOne},
{gfP{0xd1e2a52f58764f6a, 0xe9fe4e76ababfb04, 0x343bbcb847de1533, 0x802973ff9f94d324}, gfP{0xf127ca531e250100, 0x14e3cab2d415bfdd, 0x370ea05e4c98e7ca, 0x10fcbd8846c2e73a}, gfPOne, gfPOne},
{gfP{0x19811f13b5622561, 0x359e4fec5a652f5e, 0x50d49e11a56cc619, 0x1d6fdeaef5ed9f0f}, gfP{0x5307772834da5588, 0x88dbc66d909e47c8, 0x7b63c779663426eb, 0xa68eec9b0823734b}, gfPOne, gfPOne},
{gfP{0xc64fb41906d8ec86, 0xe3028189bb877cd9, 0xb3eb20698e302c68, 0x32824a7b9c1d9487}, gfP{0xba99c36d9007e2b0, 0x3f04e9e638c0204c, 0xe7e9fdaa705525d, 0x7ae86b2ea982324d}, gfPOne, gfPOne},
{gfP{0x599debddb7b9babe, 0xf16b5689bd581223, 0x16545b0f4ace2795, 0x9dd9a61aaac54d17}, gfP{0x927c243eb7c79436, 0x3765d87125f348a8, 0xaa7a7910208a2a9e, 0x3c12e5bcc426a267}, gfPOne, gfPOne},
{gfP{0x75ea6bdaec259c14, 0x865e0751de6f2fc, 0x1e2337dfe960b2a9, 0x466522c5369ecfec}, gfP{0x7928feb106291da4, 0x25c4ff3ec0e1c921, 0xf5a647d4d6761d1f, 0xa22b9be7e15ee958}, gfPOne, gfPOne},
{gfP{0x25dd13f8fa3b0439, 0x31f081d1c21eb9c6, 0x1bc2156256d5b30a, 0x16d061c021f08b69}, gfP{0x5a680895859b1181, 0x6f3a86b2d327f01b, 0xa60e2a4e35f8a495, 0x71d60f30156e2ac9}, gfPOne, gfPOne},
{gfP{0x6e39c495bab52743, 0xd7eb70769377f418, 0xd84dd79804a939ce, 0x4dfece78cbd2c365}, gfP{0x46bd389c56e2503d, 0xde79d40dbc3c3454, 0xb4edc877d5efbe72, 0x9b142059fbe68c52}, gfPOne, gfPOne},
{gfP{0x588b4095ecb1a68d, 0x3e985dcd6b576ff3, 0xd7f1d4922ea6202, 0x53686d2c4ce60479}, gfP{0xa7e945656138359, 0x7d8e4f32fb7cd714, 0xcdb7c5660cea0e9f, 0x1834514ad4b02aec}, gfPOne, gfPOne},
{gfP{0x8f885b64a5052c59, 0xa6f6fe720dd6d1da, 0xe8430c469c9626fc, 0xac7a920b114dd947}, gfP{0x8f71ae48a9dbf4df, 0x689c1581c4d93c8e, 0xa15ae20b0bd37b81, 0x70a5d2c700c213c4}, gfPOne, gfPOne},
{gfP{0x5afaace024be3754, 0xe93546b16863f50a, 0xbae2c61df55309e5, 0x8c43dd565b7dd326}, gfP{0x5e388eb21b86603, 0xbcb5add199d30208, 0x156c3526a77bdb36, 0x4e56c99d0f99377}, gfPOne, gfPOne},
{gfP{0xc5f0e7f1d960b545, 0xb74ff83effd3cbc0, 0xbccf08748f206533, 0xbc20d1c74260064}, gfP{0x480d64f58758ef53, 0x908247dadf0b8244, 0xce170f2e56f67818, 0x8100963c8309c87e}, gfPOne, gfPOne},
{gfP{0x351282911dd673e8, 0xb9e1a2dfa749f8d7, 0x8fb37ea9b267467f, 0x18c0a3a3ec358046}, gfP{0x3d8146063a4b7fa8, 0xbf94cc0ef25074d5, 0xd6a589e8e6e214f7, 0x5c911c83682dc36e}, gfPOne, gfPOne},
{gfP{0x7b31e6ab1e0c8008, 0xfec5725486be003a, 0x32551c9d02303e0c, 0xa82694e309dbd868}, gfP{0xfdab56b2905a19a5, 0xe5a9079db04d2083, 0xaa7d38be296d320d, 0x172ea60c2ce11501}, gfPOne, gfPOne},
{gfP{0x2f47e466f517150b, 0x6748544c3a4307de, 0xb71c8d542ae1497c, 0x693865b7785de51}, gfP{0xd8bb8c2fb8a2237d, 0x487ff51d4aae1f02, 0xfa381e7b4e44d600, 0x56a0814ae9959071}, gfPOne, gfPOne},
{gfP{0xd8b8faabdec90d0d, 0x6821e24546e8852e, 0x6e3631b9faf97f3f, 0x4794825b98975f7c}, gfP{0x1b0f86c0d8a35bd4, 0x910a8ea72b59019b, 0x4bbb6a05230e33e0, 0x2e9871a46f7592a3}, gfPOne, gfPOne},
{gfP{0x9a5ea97524a41040, 0x6117917805742161, 0xc03adf72717acb72, 0xa9979b70e843371c}, gfP{0xb01c923c63a38a8e, 0xdf198f1261806a27, 0x6f20e24907c7568b, 0x40d7b1bdd6284105}, gfPOne, gfPOne},
{gfP{0x6348990efb0a497a, 0xe47f91382ec5fcd5, 0x78772ff3c93a9cf9, 0x7c1224463c780cb4}, gfP{0x8d746a78a105319c, 0x9ba8fa470606c53a, 0xdee148f0c8d8d907, 0x5ae0db70eda78d52}, gfPOne, gfPOne},
{gfP{0x6f2fe454498bc688, 0x1aab2d7da6c60647, 0x4c95123ba1e557fe, 0xa3616ca7efcb050e}, gfP{0xf2d4b1dfd0eaf791, 0x48c1210916b4ee98, 0x40834c21cff0ac0e, 0x1a6f0fa6ab684aaf}, gfPOne, gfPOne},
{gfP{0x83b6fa3ee5f5cf23, 0xfe574d58745d55d7, 0xff69e155d3c1c06a, 0x64bb6fa30d6aadc9}, gfP{0xf8d0b81b75e8356c, 0x568175bd4ccc22b2, 0x8926e214eaee036d, 0xd4b22eef2a5ce3e}, gfPOne, gfPOne},
{gfP{0xef32bcbafd7ebafd, 0xc167f4b665104256, 0x6846a66725ba001b, 0xe1c5126b4e18859}, gfP{0x845eadfb9e56ac12, 0x7d602ecc4164a3d6, 0xe0fbf52c76355bc0, 0xb46b82950476bd0}, gfPOne, gfPOne},
{gfP{0x5679851c653afcde, 0x914b028276ea6e73, 0x380c9d69150c6487, 0xad632d38be456ec5}, gfP{0x257fba330f3ff5ba, 0x4be8c99d16fba1ed, 0x343dfe670f1a830e, 0x19148fa0f75743a6}, gfPOne, gfPOne},
{gfP{0x1c4d3b159b9045d6, 0x89eda0279b9a91d0, 0x1d8b68819c90e774, 0x24c69f4fc8e472fb}, gfP{0x9ccebc712878e5df, 0xcfed7b0174286a71, 0x741bd7401afc1a2e, 0x198d0cce761d9621}, gfPOne, gfPOne},
{gfP{0x1c489dc1be406d52, 0x36a06a42b08bd997, 0xb080ca6c856c77d9, 0x16b62732769f6932}, gfP{0xecd8e40e93a8e4d6, 0xa45e3377fc264ea8, 0xb13d9469e902fd69, 0x486469d09e003e8e}, gfPOne, gfPOne},
{gfP{0x8c72e7672c1e6489, 0xae56cf93511df546, 0x75bb93da4a97e7b3, 0x2dd963201e0fc3d1}, gfP{0x89f12b9a4f35d23f, 0x833a267b75bb6d7a, 0x9a9f6aef40793033, 0x332c83fd6006a5c}, gfPOne, gfPOne},
{gfP{0xdf5a10a34d750f1b, 0x85ef446c3d637695, 0xa72acf5037ee75d6, 0x970618359541a5fe}, gfP{0xdd694f01b96b3da0, 0x103c9e394b665421, 0x1abc79bd25940023, 0x5f09980cfaff9ffd}, gfPOne, gfPOne},
{gfP{0xa76d2d8bfcad33f0, 0xab1e383c67e82229, 0x83476fd9ad4f1895, 0x42a278beb7b63ae0}, gfP{0x4c0ebdedc94078d7, 0x8b60b773258eb6d4, 0x77a4830c1c994962, 0x62532936ef3bb576}, gfPOne, gfPOne},
{gfP{0x84344001a1074906, 0x92914ce5353f53ec, 0xd23d2919d297faf2, 0xa8352ed905aaabc3}, gfP{0xf358d9a1fc38fb56, 0x7afe9d157091df9f, 0x37e913f760121b73, 0xac9958cd2cffb4f8}, gfPOne, gfPOne},
{gfP{0x42ca7b8f508c253d, 0x3c5df570d94b9238, 0x8345330412774517, 0x56d0e4ee06baad9b}, gfP{0x4287a4f0100dce98, 0x6784fcac31d1011d, 0x78daff508b9b92f8, 0x94f9901aaedb86ad}, gfPOne, gfPOne},
{gfP{0x2b56acd6ca80ebc4, 0xe90764117037a7c8, 0x27ca9a814f8d0932, 0xb0f896604939ee1a}, gfP{0x48b1588178b8c9de, 0xe4cd5798e32ee5ff, 0x2cde366b352af54b, 0x29942306b31d4314}, gfPOne, gfPOne},
{gfP{0x4f57f4934fa7873f, 0x4d85d2980052b693, 0x77325bab4f52f763, 0x16b1826537f3c3f1}, gfP{0xeab2e4d187fc4cd3, 0x84585838e7d526b5, 0xd33074be511eeb22, 0x3864b72ff53e4bd0}, gfPOne, gfPOne},
{gfP{0x4c827bd650be7f03, 0x6c8199f3ac4542c2, 0xf4a774fbe4dd11a2, 0x6448070645311ad6}, gfP{0x249310f40f7d70ae, 0x20cfaedf5f43d805, 0x458b8ea19df1fab3, 0x9fe83c6e0ac4c085}, gfPOne, gfPOne},
{gfP{0x5fc706e6ce8d94fe, 0xda48a8b5356a4b08, 0xd9c132ca0dae251b, 0x2cb11e54d16dab7f}, gfP{0xc13ce46d0b2f2a96, 0x50604765f264d7ba, 0xcee2adab5d226bda, 0x9cedfbf0eac28975}, gfPOne, gfPOne},
{gfP{0xd2ea9bf56a9ab09c, 0x7c3cd7ad227258ad, 0xd716e2d429ceb6e6, 0x3cb1f2631d9048ef}, gfP{0x71ec6d02577a32eb, 0x1f4efd128c3f2c8a, 0x1bdc00709e71a89f, 0x6d5e92d48959bf3c}, gfPOne, gfPOne},
{gfP{0xedbb4f20430ad43, 0x22984301f5ef177f, 0xce3b6636bfdffbe5, 0x583149b96949790b}, gfP{0x28bfcdd7a10033a8, 0xc389ff1d955585aa, 0xe293f9f87cd46fd4, 0x9926a3b3497fa8fc}, gfPOne, gfPOne},
{gfP{0x45ddcf105a7c4b50, 0xe6274432aa862eb6, 0xadb2affdb729f561, 0x832f131ff191ab9}, gfP{0xc891c36521b5a97b, 0x6eae74603eedbd28, 0x127dd01e3b850399, 0x9662b385de5377c8}, gfPOne, gfPOne},
{gfP{0xdd95f169e8bc1032, 0x8f0ffe132d605734, 0xc4d28a341249ab48, 0x5b68d02ba9947d58}, gfP{0xf00aa14e5f6ab4a2, 0x38c5bae244b8492d, 0x3c6ac80b4e6cbe1a, 0x3ff167cb22a13a8e}, gfPOne, gfPOne},
{gfP{0xccb902325d7b1129, 0x6129780a3b4aeb7d, 0x50e3408d463aff4, 0x30e4eebc728e4552}, gfP{0x2d393391b67712a8, 0xdb28bc0bcd6c96ab, 0x2c281bd783fecfa4, 0x1e4bb2dac4b1b998}, gfPOne, gfPOne},
{gfP{0xf3406d0bf8b374ab, 0x93b5d0a215f71156, 0x22443871744998f4, 0x36fd2678438d2364}, gfP{0x53385f8981382927, 0xdfb9a98a79c17e45, 0x8b6fd73dc19b8483, 0xa045a1cd61238810}, gfPOne, gfPOne},
{gfP{0x50e31d9e3757a86f, 0xb52681ba3a181e00, 0xa49390c3e43b07b1, 0x696237a267e9d22f}, gfP{0x838a70d2f0d396c2, 0xe373e94d8b360097, 0xfbdf37ff6e0d496d, 0x26da6fcd4690b2f6}, gfPOne, gfPOne},
{gfP{0x57176ba3037e3960, 0xebb1aca271f58de, 0xd788b8567b980c60, 0x870c1625c6cf8459}, gfP{0x7d852d05ebb95bd, 0x111d9700cc5f02b1, 0x59b41c0afc96fb1f, 0x1f80bd77dccb1cf0}, gfPOne, gfPOne},
{gfP{0x271526613e895997, 0xb699808385c3d444, 0xc0a0c3ffaf415ee3, 0x91cfdb521fbd10e4}, gfP{0xaf7492f19b2bd2a, 0xe5fa4e9ea02fce7b, 0x2466002cc40a5d0f, 0x14f6bf99e82519d3}, gfPOne, gfPOne},
{gfP{0x955cf354af5f207c, 0xfb6474fcf6bf74f8, 0x4a6941d582440ad0, 0x20e36936c5251cd9}, gfP{0xd12792fd2f7a77dc, 0xc2eb3e1527a0a9d3, 0x2213ad94621327e3, 0x632a48d765f6e755}, gfPOne, gfPOne},
{gfP{0x5dda3402b2a703fb, 0xf7883426e0f7df2d, 0x3a8e7b0348009280, 0x5d48ea3fd8ab0996}, gfP{0x3487125291302257, 0x7d401cf915559e4d, 0x3035b07df4782f64, 0x95dd6e3bfed1cec9}, gfPOne, gfPOne},
{gfP{0xa81d8101a44dc764, 0x9a5d336ecc4326eb, 0x6540f1a6797cca44, 0x1c6269793a0f0249}, gfP{0xc0391a5b4f2f86b4, 0x5c465c05f9dfece, 0x2dc115341ae299d3, 0x6dbcae566af4c08d}, gfPOne, gfPOne},
{gfP{0x5b172f74de39081b, 0x6237d27638c9de8b, 0x83fd1d19c59648ca, 0x53fc998810f77e0c}, gfP{0x33f285985ff3fde7, 0x13b00104f67cafff, 0xc276ceb414a09545, 0x7bfa015acc283aee}, gfPOne, gfPOne},
{gfP{0xbb5915888601ddb4, 0x7b53c015f9bc1492, 0xbe2552a5a47f843e, 0x88300787ee71f11f}, gfP{0xc33f030285c14a92, 0xcb10af54f14198e, 0xf64a621fab3ea887, 0xa0b2aa2038e54eb1}, gfPOne, gfPOne},
{gfP{0x8220fcccb0b485bf, 0xe4fada5d324d9d6e, 0x725605635589b58c, 0x103e33231da915f}, gfP{0xba9e51e89eaa7722, 0x2eb461e4675cb426, 0xcf68f2049c071f69, 0x655b8a5cbe8b5a79}, gfPOne, gfPOne},
{gfP{0xa367f1cee945eaa6, 0xf3b7b346b337351b, 0x6640d7bb75788636, 0x70168124ab98bc55}, gfP{0xab2688a126a57749, 0xb49da8caed1aba3f, 0x6375de275a32bb3e, 0xf70da08afa5759a}, gfPOne, gfPOne},
{gfP{0xde77935240e4c5b2, 0x26781e7771ac2cc0, 0x39a4c867f34186bd, 0x24d793ef02a9088}, gfP{0x5c5c67fb43ea8146, 0xaf94d02a1237bf3b, 0x17fc6f18cff02a05, 0x8f8fa51d0c7b45a9}, gfPOne, gfPOne},
{gfP{0x1eb10cb7138d11f8, 0x37c21628bd2976f0, 0x2a1b539391c3c122, 0x57e8f2a32f951030}, gfP{0x8c17706d7ca3e6eb, 0x62f9f1d722053ec1, 0x2bb7a9d286372780, 0x39d36fa6f4568912}, gfPOne, gfPOne},
{gfP{0x4ae3c3269e627dfb, 0x5a587ecb9b5cb410, 0x3e4168f27f1c5afa, 0x8a9e67e5f80fd9}, gfP{0xa6cd8669cb4d5416, 0xdc61b52d99bcb419, 0x88710f486cecec3e, 0x331005bb9104d453}, gfPOne, gfPOne},
{gfP{0x4cffcd1f0a5417e4, 0xcedfebf4dd10eb50, 0x7199305ae4f5d6c0, 0x85ffc4aba0a7c6fe}, gfP{0x14fc12ae26245915, 0x60632cb8add1b0d2, 0x52b5f05423fcdc7a, 0xabac00cd94bb724e}, gfPOne, gfPOne},
{gfP{0x590fe48280a46054, 0x2996c1a5df1275b0, 0xf40dacc7ed47872d, 0x4f6c452330453366}, gfP{0xabf944a36fe8e67a, 0x62d2ca2afb555546, 0x3264694a2a1c09da, 0x75ab8d47d53c632d}, gfPOne, gfPOne},
{gfP{0x7fefd4ed5ac7282c, 0x41b1a1622fd4738e, 0x7e1fc0a15e869e, 0x18fcf6f97adfb7c7}, gfP{0x6014db0b38b3e196, 0x4361d962c964777d, 0x12364d819feaeeb7, 0x32f83ba466e858e1}, gfPOne, gfPOne},
{gfP{0xc3be93c740293517, 0x62f8ba7705b3e77d, 0x545ea87a3b486c6f, 0x3f63a5e6c13a2bae}, gfP{0xca6692f81bdb638d, 0x259948a034f84850, 0xeb77953a658fdf8, 0xa1c3a1a8fa2fd206}, gfPOne, gfPOne},
{gfP{0x2dbc0a109c92014a, 0xac2b00cb58eb6bd1, 0x13a8f3ae10bfa548, 0x5a365caf3f23858}, gfP{0x4344189d982e3724, 0x5f5878055a75befa, 0x55150105a405d6ad, 0x890b283f5f9b1ea}, gfPOne, gfPOne},
{gfP{0xade8848d7154f1ca, 0x6f03291746c34d2c, 0x2eb6887ee8a65d36, 0x5bfb84958e7aec0b}, gfP{0x865d068655041db4, 0xbb2ce42c3336bb70, 0x5bf3f2631d02002e, 0x6b6c332e71f5cc02}, gfPOne, gfPOne},
{gfP{0x89edc8810edaf6ce, 0xeb0538c5de469428, 0xbe12a7d7bfc798ef, 0x5b06212a92096373}, gfP{0xe3fd08f7683ab120, 0x47320935545c1dfd, 0xd95f058ab8139976, 0xa83500d0e0db4b59}, gfPOne, gfPOne},
{gfP{0x534cf1ebeecafd1, 0x5064f74be40e509e, 0xff44764f7da0b941, 0xace00af12ccf48dc}, gfP{0x894e2fd8107a2d43, 0x273be2c5dfae422a, 0xa1aafb55113a2174, 0x4cfb849394b3be06}, gfPOne, gfPOne},
{gfP{0xc49994c7faab274d, 0x41ff9dd8a85129c7, 0x52b1088f1d4242f2, 0x7db1e4d360032ea2}, gfP{0xf5c6b0dafe6527fc, 0x1d970a083bbd5266, 0x38ba89efdafddd56, 0x68c77897337efea4}, gfPOne, gfPOne},
{gfP{0x4b5303ad036255bb, 0xd67f6582da500a9c, 0xf4bbe23b298c31f2, 0x2e007604c640ca10}, gfP{0xd2e91aeeb40acb7, 0xec0f24d3618434b3, 0x76fdf6770c4921f0, 0xa7103eae7f93d219}, gfPOne, gfPOne},
{gfP{0x7a4d64de8859c126, 0x6263bc0f1a5c17f9, 0x74e00a2133a6c016, 0x3963f36605ba8b36}, gfP{0x9c52ca1d17f48028, 0x8104ef2f9764e8e7, 0x2b8e0237f7533e0c, 0x519b24e4c97bae12}, gfPOne, gfPOne},
{gfP{0x613e0c9e7e4da1c0, 0x8f172375727fd6e2, 0xe81ff51982a6c41c, 0x4eed4e26ea668083}, gfP{0xdb7b398fdebc586a, 0x69d8ea6246faf392, 0x2d3bc523e6c8258d, 0x558bb8f3231caa04}, gfPOne, gfPOne},
{gfP{0xcbb7c66f5cb74161, 0x626e935fa10bd251, 0x3d2f610e0613d51, 0x801657bc335df137}, gfP{0xb8ccb862d7a8eb11, 0x66148fee4787b7cd, 0x91d3258ce654d1c9, 0x7bde5ff69c33fdd1}, gfPOne, gfPOne},
{gfP{0x2448daff554c6b43, 0x9c7a0f594520d528, 0xa75145fcbe4e16ad, 0xafb19cb3ea16f941}, gfP{0xf084b43289761071, 0x7f0b6c9ee0a094ab, 0xada80c607d423d43, 0x96b9b3e9c68ad8db}, gfPOne, gfPOne},
{gfP{0x5fc7b9945b3d71e5, 0x3a29106d5fb61068, 0xdc97f98313de4e66, 0x1957a43c916e732f}, gfP{0xab35cda5dab8ed48, 0x5d3e549342ef94c1, 0x461b373d895d974f, 0x5fb50b1344ff1cf1}, gfPOne, gfPOne},
{gfP{0x95da5ed748c60678, 0x4e3a30e970902de7, 0xb42ab5c0f6fb1497, 0x2da1984ece49a3a1}, gfP{0x8053022c7ef95301, 0x91ecbdcf31475603, 0xa6be61f47070280a, 0x51eef68b2da0991d}, gfPOne, gfPOne},
{gfP{0x52b2332357053035, 0xe298b291cbd2ab72, 0x47741ab8aee0d9f, 0x680f9a2a17ba7efa}, gfP{0xc2cab72dac3a107c, 0xdcea96b2208bd7e7, 0x5f78963f7d538a94, 0x10a1839f5aa99b1d}, gfPOne, gfPOne},
{gfP{0xd2813441856ab167, 0x9373767664eee31b, 0xc49325639d571c57, 0x7b41b7cb342bc4c7}, gfP{0xbdd3e44bf07b972c, 0xd64052aa5dac1bd0, 0xe11ace28beb79ee9, 0x37a2121f6d4bf624}, gfPOne, gfPOne},
{gfP{0x58548a06f1ea9d78, 0xb9b99cc0f55a8afc, 0xe51413a4b19979a, 0x406a3ac41e79f7b4}, gfP{0x780ff05333617202, 0x7fe20d43eb745163, 0xe3e7b7475027cb6a, 0x13dd1aca24b7af6f}, gfPOne, gfPOne},
{gfP{0xa43d604e74d69332, 0x42c06a3235a47a59, 0x941801eaebd923cd, 0xaf5c699b8a8c96a5}, gfP{0xa5973af352b3d784, 0x43864487580fde98, 0x10abe5251462cfe8, 0x78b5c82c6cf1f70d}, gfPOne, gfPOne},
{gfP{0xce47d5702154990f, 0x607ee781820195ab, 0x70c0b489b0afccf1, 0x8588651b58c7be0e}, gfP{0xde3c44b3c3eb8034, 0x4082e336f9680ce8, 0x5ba1275f2c2d0e82, 0x49e025974813bf57}, gfPOne, gfPOne},
{gfP{0x1ceaecbd1bd7fdbe, 0x527cb80ccb7568c7, 0x199710b3f259b03f, 0x8f879dbb9b3dc3ca}, gfP{0xe809213a2fcc6d8b, 0x734e2bbaec309388, 0x99386377e05a18f5, 0x6d72d96d03e2c95d}, gfPOne, gfPOne},
{gfP{0xacca7849ca39fec7, 0xb460de754a80e824, 0x995e3b2ea7ffcdf3, 0xad5b4846180d95b}, gfP{0xb823d9dbc98bf826, 0x5abf5b87b0fef244, 0x59e8d188fe07d6c1, 0x949c56ce93966ef9}, gfPOne, gfPOne},
{gfP{0xf34282e7ecd21dc7, 0x8679d81e3d0e8bf8, 0xce46c9ef80d03b6e, 0xaa301832aa7a5a1e}, gfP{0x454746f43a8202a3, 0x6bc7278ac271030b, 0xc022d661edceec7f, 0x9ffe9483326e4a4c}, gfPOne, gfPOne},
{gfP{0x7eee34f6cd4e319e, 0x36fa41911e2b5231, 0x991bc6831a3c637a, 0x42d10739c8992a96}, gfP{0xb08a53378d0195c0, 0xfbc9554b9ec970a8, 0x403b806f55a71e61, 0x2c03082211fee7a}, gfPOne, gfPOne},
{gfP{0x8e4fed59eab327b2, 0x6bf815e591b6bf4, 0x189a6bedbd6871f6, 0x5e517c852f951d3f}, gfP{0xbf3169adc081e845, 0x18fe345d0f208c2e, 0x40ede4f50a95bd7d, 0x58f6bddd5f62163d}, gfPOne, gfPOne},
{gfP{0xd4c658ee782f66ef, 0xc48b53fdbb11f779, 0x8959c8eae84942a1, 0x458a59299e6bf76d}, gfP{0xd90c557f56c6631e, 0x43511713cd9d06fe, 0xbdd59b20817beda3, 0x14b9f4ac6b9be7c4}, gfPOne, gfPOne},
{gfP{0xff4a2cdd53e44546, 0x8a108ea11bd63a46, 0xd5ba0072898100db, 0x169729ba87f7a6b9}, gfP{0x55042d6ea1a53bea, 0x39b530ce347810be, 0x5370095c8b3ac79e, 0x8dbda8940baa649f}, gfPOne, gfPOne},
{gfP{0xdd5f6b25243bb894, 0xe5b0bb1c9e835a3e, 0x3a1c1a615f055454, 0xa02102f811eae2c1}, gfP{0xdc0dc988a6435de8, 0x99a872d7d7123b0a, 0x215c6bf51660d83c, 0x487302618a002b8d}, gfPOne, gfPOne},
{gfP{0xee787bb4f2463b8c, 0x487feb782873d475, 0xfb6dd178a1d412fb, 0xa2cf5b23af2acd3b}, gfP{0xd77ca577924a1f21, 0x10b810c50f184465, 0x7f29d0e6bf3d4042, 0xa67b192d774f35f9}, gfPOne, gfPOne},
{gfP{0xba99ac53038e1e9, 0x80a3624af2adf6e8, 0xe737a73807ce79f6, 0x14afba07e55a6d50}, gfP{0x4e0b8d91da04f1f1, 0x79667e4e655e19ec, 0xaa1ab4bdc465c35f, 0x54a7d0336ae002c}, gfPOne, gfPOne},
{gfP{0xf3629579da04da05, 0x355627f9438c5527, 0x366b5a127cced7b, 0xa896eb4c13fd8087}, gfP{0x921f31efb2cf9e89, 0xf549080991e1dc03, 0xf1bebc6b4bdd4b3a, 0x33c9e63202bf4472}, gfPOne, gfPOne},
{gfP{0x8653581950b31142, 0x36cff22e4717bfef, 0x67cc456070963993, 0x4e0958b0d0770c4a}, gfP{0x8b5f5031af6f0057, 0x8efced1d8fe9c043, 0xcef02464bdc925dd, 0x6f86d163fb05ed5f}, gfPOne, gfPOne},
{gfP{0x126cd183331861ba, 0xa767c1d0b5df342, 0x9a00adadca46e3bc, 0x5bc67e273355743e}, gfP{0x46baecc5f15b50cc, 0xd5ee97907606d217, 0x4cb039f9762270f4, 0x519d365a0301298b}, gfPOne, gfPOne},
}
var curverBasePrecompted4 = []*curvePoint{ // nolint
{gfP{0}, gfPOne, gfP{0}, gfP{0}},
{gfP{0x22e935e29860501b, 0xa946fd5e0073282c, 0xefd0cec817a649be, 0x5129787c869140b5}, gfP{0xee779649eb87f7c7, 0x15563cbdec30a576, 0x326353912824efbf, 0x7215717763c39828}, gfPOne, gfPOne},
{gfP{0xba28d1e3d5048a4a, 0x304272c35402c713, 0x69e99637e85352dc, 0x8700ed2483b0b77b}, gfP{0x969534adc499393c, 0x5e8df13a66ad38f0, 0x8f0df437dbc29dcb, 0xa08db36b5f08d049}, gfPOne, gfPOne},
{gfP{0xa343996a7367c29d, 0xe96e87ea23df0d62, 0xddf5f38d18e96a63, 0x5098ee53e76f8e35}, gfP{0x97c267182697b1ee, 0xe867e6ea877b42e0, 0x320ca334328006be, 0xa8739bc600caf504}, gfPOne, gfPOne},
{gfP{0x46b8b8692a8eda6b, 0xe98400d89a9938b2, 0x2f6f8c3aa958752e, 0x87928e7b21296dff}, gfP{0xc578f06244de1eb7, 0xf67910a8d1befa71, 0x313c89849f89483b, 0x285df6a6b5c9f283}, gfPOne, gfPOne},
{gfP{0x99f991c62f896dc2, 0xca48dec99b12a0ca, 0x47979262c298eaff, 0x4e7325f6fee9c93a}, gfP{0x4a621d37ab703864, 0x22ea8d68bccdc8e7, 0x1872c133d0d4ed44, 0x8f83b2400eea2c5e}, gfPOne, gfPOne},
{gfP{0xa48c4767ad45f7fa, 0xe4e180d4073c21b5, 0x606a49caaf4e22e0, 0x824b6a4d362cb4ab}, gfP{0x123813621182b89e, 0xf02b168a564ca3f7, 0x5946559985a31a8a, 0x83898fb99a58ae51}, gfPOne, gfPOne},
{gfP{0xd8ce0f64e4ff7789, 0x56a63f768bf4dfd6, 0x70c98904775436b2, 0x53cac0d685e11505}, gfP{0xfad84ab4c6cd3523, 0xa3a9aa3de679b3b6, 0x62dc68e29df06692, 0x165cb89486b919bd}, gfPOne, gfPOne},
{gfP{0x40e1c1513da71eaa, 0x71ed359497847585, 0xa45a19d19b1e6f33, 0x84b7412821186f41}, gfP{0x8bd69894806e3a1d, 0xb0ee7ab013af20f, 0x7cd371ed4e97c36b, 0x68563ee8764f345a}, gfPOne, gfPOne},
{gfP{0x46f64915f6a708ef, 0x5e96a75c790f9c42, 0xadc963e8f8f272c1, 0x7a7e2536a99d3a36}, gfP{0xf9472e631d52bc0f, 0x8b04b9c53b647691, 0xb4ac69af1e267c98, 0x3ace4cdc41d24d6}, gfPOne, gfPOne},
{gfP{0x211ace47487ca54b, 0x167124cfa02d4a6f, 0xf67d81ac451be038, 0x49953a9fa0ed3631}, gfP{0x9c39db45d05c392, 0x21e8ea068ae98cfc, 0x931dc970da019c09, 0x2d9f574d46176925}, gfPOne, gfPOne},
{gfP{0xb5e93687bbeeccd8, 0x89f331916207b439, 0xe39647be10152e3b, 0xaa3873ed3faec88d}, gfP{0xb60c53a84c62ede4, 0x720778e426caa01a, 0xef774fe256a101c2, 0xa9405ea40628fdb9}, gfPOne, gfPOne},
{gfP{0x414ab8de0e998a9, 0xe6b76b533b13a8ff, 0x3c14e5384013b578, 0x716b8aefb78f23bd}, gfP{0x9e9ee97502cbb199, 0xb55144227a8ab0e3, 0xbc498660e38964de, 0x34601293617f87a7}, gfPOne, gfPOne},
{gfP{0xbe97fd85d257b670, 0x3cce7057d39d7947, 0x1cc124d0f0ed37d2, 0x9f8ac5ffa5e75faa}, gfP{0x633c732a8de82bd8, 0x221bc8c2dd8b46c5, 0x76ecc18258be2e38, 0xb16f0f8b0d2dd9a4}, gfPOne, gfPOne},
{gfP{0x983ed8aaf1166b70, 0x37664d28789570bc, 0xbdb0ef89bbd065dd, 0x988c762b5abd2c16}, gfP{0xba1b835fb556181c, 0x2c4e63c063ed161e, 0xcb2ab2a379ed6179, 0x64abe36bf1d027b3}, gfPOne, gfPOne},
{gfP{0x79b6eb3c2e2a57ff, 0xede997305ad1e6ce, 0x395b0f074e9adca4, 0x36763c5d6c7dc962}, gfP{0x2611a3268fb513a5, 0x5b1100f2e584ebf9, 0xe163637e560f1e0a, 0x68d51102d894b745}, gfPOne, gfPOne},
{gfP{0}, gfPOne, gfP{0}, gfP{0}},
{gfP{0x95ca1bb919a322eb, 0xc4d13c49d672e273, 0x4797255d41bb8c0f, 0x1ebf8f510af182d0}, gfP{0x1d74935661933d97, 0x10deb64252136a02, 0xee16c808be654172, 0x28187964a641c5d3}, gfPOne, gfPOne},
{gfP{0x4e0b75ceaf4a2887, 0xc3841acb67fb189a, 0x18c9578469741c9a, 0x692fab8164cee33f}, gfP{0xfaf6b1c1b91ffbb, 0x2161e01d6794e678, 0x757e6f30473f2d5f, 0x269bd35f64914a96}, gfPOne, gfPOne},
{gfP{0x8c421ac5ecba0343, 0x101d2e9b67b0f4ee, 0x3fafcfad92789f5a, 0x64642f323001a421}, gfP{0xa781b10be5989c03, 0xe9996e4b3cd51cb7, 0x8a35b2c52f42274d, 0xacc965059aa5cd5b}, gfPOne, gfPOne},
{gfP{0x881f1dfd166cd3c1, 0xd308eac84be917c8, 0xf5b6207a3992b980, 0x261ae33ba5f17e39}, gfP{0xbe638db9fd976a70, 0xb7619dd3949f24e9, 0x56518e2b24e07ede, 0xa77bfab0e221f51d}, gfPOne, gfPOne},
{gfP{0x5aa749b0a053d5ec, 0xe989c59830162157, 0xa58c960ce6cdfd15, 0x74868ad561f95d32}, gfP{0x8d5aa4b4640a5307, 0xda75bcdfac06e18c, 0xcc0467e2cfdaba6c, 0x673644fdbb0cb089}, gfPOne, gfPOne},
{gfP{0xc88d68fd9db1c411, 0x113922e3aebfcb57, 0x56104db14f59b8b3, 0x1a978fb2fdd65680}, gfP{0x2232a99fcf41f354, 0xccfd83f1670ab665, 0x999957f9258485fd, 0x59f80b1e0eb01af6}, gfPOne, gfPOne},
{gfP{0x13ea6f5d2bdd3a39, 0x92af44598a10365a, 0x22fc94fe947ac0fe, 0xb5714e95e84acf99}, gfP{0xb647673d1ee38529, 0x7e183dcd41859746, 0x776698b19f585432, 0x4cc5626601296793}, gfPOne, gfPOne},
{gfP{0x8bd9077793384ac2, 0x562cfab6f939044c, 0xe48a7412cbeee7a4, 0x7018feb31e1b2c27}, gfP{0x93a427c3005e372e, 0xd75aa13fd23f9921, 0x118cdda96b6e31a6, 0x7cca0c12e96bd486}, gfPOne, gfPOne},
{gfP{0x2b81209d5addcdfe, 0xad2f5ae187091159, 0xfb5c3cdd44b8721c, 0x3d8429baf0dfd4f2}, gfP{0x7d3c7781fba9cc68, 0xab7c17165597393, 0xefe1a4e041e5a378, 0x8dd8e1085a5f3b5d}, gfPOne, gfPOne},
{gfP{0x16c26ecd4c10404c, 0x9bcf7433ed81d6ff, 0x95431cf91ecb16db, 0x560cd980c9f85c6f}, gfP{0x4fa4d2e4971158d2, 0x89447d61e3417269, 0xbc57d40f7ea3ac43, 0x4907f1cc668f1080}, gfPOne, gfPOne},
{gfP{0x88d7d2f612801225, 0x22fe9f1c57b1ada8, 0x81f6a9e346eeb999, 0x591b5c2d5d8411bd}, gfP{0x8fe5439fc644d114, 0xae100ef4db65e95c, 0xc7830879884a755d, 0x7cc9eb1659f3e68e}, gfPOne, gfPOne},
{gfP{0xd58f103faba0ac53, 0x71d1f187f22b9524, 0x6401e34eb430bcae, 0x9abfb1f7072947b7}, gfP{0x509bd01835b40fb7, 0xa3eccd73fb7aef58, 0x177365855294585d, 0x9cef811802bd32f9}, gfPOne, gfPOne},
{gfP{0xd36e81958b531b62, 0xcbceefbaab691fb2, 0x22358d9f10bd2e21, 0x645c4952a4317076}, gfP{0xa8a627af86f3cb82, 0xc2a341ba92202dc4, 0xb10a0e58dfc9f32d, 0x8350461932238401}, gfPOne, gfPOne},
{gfP{0x20c7d06e2b4ea3ba, 0x4206b7291f401d6a, 0x7c788a3324638462, 0x3bd9b441b713f93}, gfP{0x33b74f18051318c, 0x681c4ee3bac4038e, 0xfa63b1c04d4feade, 0x6b6024c1f398ab06}, gfPOne, gfPOne},
{gfP{0xdd2c191ebbc21073, 0x81de1d7ef35317f2, 0x58485d136712131, 0x530fdeb2cc474f4f}, gfP{0x69011c8b81da7079, 0x569b09f818f83323, 0x134bee7a04f369de, 0x1f47848d0d485a42}, gfPOne, gfPOne},
}
// if free - constant time.
func (c *curvePoint) MulBase(scalar *big.Int, table []*curvePoint) {
// montEncode of point inf: (0,1,0,0)
t := &curvePoint{gfP{0}, gfP{0x1a9064d81caeba83, 0xde0d6cb4e5851124, 0x29fc54b00a7138ba, 0x49bffffffd5c590e}, gfP{0}, gfP{0}}
if len(table) == 32 {
//nIsInfinityMask := ^uint32(0)
var tableOffset uint
// The loop adds bits at positions 0, 64, 128 and 192, followed by
// positions 32,96,160 and 224 and does this 32 times.
for i := uint(0); i < 32; i++ {
//if (i != 0) {
// t.Double(t)
//}
t.Double(t)
tableOffset = 0
for j := uint(0); j <= 32; j += 32 {
bit0 := scalar.Bit(int(31 - i + j))
bit1 := scalar.Bit(int(95 - i + j))
bit2 := scalar.Bit(int(159 - i + j))
bit3 := scalar.Bit(int(223 - i + j))
index := bit0 | (bit1 << 1) | (bit2 << 2) | (bit3 << 3)
t.Add(t, table[tableOffset+index])
tableOffset += 16
}
}
c.Set(t)
} else if len(table) == 256 {
for i := uint(0); i < 32; i++ {
t.Double(t)
bit0 := scalar.Bit(int(31 - i))
bit1 := scalar.Bit(int(63 - i))
bit2 := scalar.Bit(int(95 - i))
bit3 := scalar.Bit(int(127 - i))
bit4 := scalar.Bit(int(159 - i))
bit5 := scalar.Bit(int(191 - i))
bit6 := scalar.Bit(int(223 - i))
bit7 := scalar.Bit(int(255 - i))
index := bit0 | (bit1 << 1) | (bit2 << 2) | (bit3 << 3) | (bit4 << 4) | (bit5 << 5) | (bit6 << 6) | (bit7 << 7)
t.Add(t, table[index])
}
c.Set(t)
}
}
+251
View File
@@ -0,0 +1,251 @@
package bn256
import (
"crypto/rand"
"fmt"
"math/big"
"testing"
"time"
"xdx.jelly/xgcl/gmath"
)
func TestCurve(t *testing.T) {
pt := &curvePoint{}
pt.Set(curveGen)
if !pt.IsOnCurve() {
t.Fail()
t.Log("IsOnCurve failed!")
return
}
pt.Double(curveGen)
pt.MakeAffine()
fmt.Println("Double of gen:", pt)
if !pt.IsOnCurve() {
t.Fail()
t.Log("Double failed!")
return
}
pt.Add(pt, curveGen)
fmt.Println("Triple of gen:", pt)
if !pt.IsOnCurve() {
t.Fail()
t.Log("Add failed!")
return
}
OrderMinus1 := new(big.Int)
OrderMinus1.Sub(N, gmath.BigInt1)
pt.Mul(curveGen, OrderMinus1)
pt.Neg(pt)
pt.MakeAffine()
if *pt != *curveGen {
t.Fail()
t.Log("Mul failed!")
t.Log(pt)
t.Log(curveGen)
return
}
pt.Mul(curveGen, N)
if !pt.IsOnCurve() {
t.Fail()
t.Log("Mul N failed!")
return
}
if !pt.IsInfinity() {
t.Fail()
t.Log("IsInfinity failed!")
return
}
}
func TestCurveBaseMul(t *testing.T) {
pt0 := &curvePoint{}
pt1 := &curvePoint{}
for i := 0; ; i++ {
k, _ := rand.Int(rand.Reader, N)
pt0.Mul(curveGen, k)
pt1.MulBase(k, curverBasePrecompted8)
if !pt0.Equal(pt1) {
t.Log(pt0)
t.Log(pt1)
t.Fail()
return
}
if i%10000 == 0 {
t.Log(i, "passed")
}
}
}
func BenchmarkCurveMul(b *testing.B) {
//BenchmarkCurveMul-8 13298 85947 ns/op
pt := &curvePoint{}
k, _ := rand.Int(rand.Reader, N)
for i := 0; i < b.N; i++ {
pt.Mul(curveGen, k)
}
}
func BenchmarkCurveBaseMul(b *testing.B) {
//BenchmarkCurveBaseMul-8 28418 40692 ns/op
//BenchmarkCurveBaseMul-8 41059 25595 ns/op
pt := &curvePoint{}
k, _ := rand.Int(rand.Reader, N)
for i := 0; i < b.N; i++ {
pt.MulBase(k, curverBasePrecompted8)
}
}
func TestCurveSpeed(T *testing.T) {
{
// 11000 次/秒
useLattice = true
pt := &curvePoint{}
k, _ := rand.Int(rand.Reader, N)
begin := time.Now()
total := 10000
for i := 0; i < total; i++ {
pt.Mul(curveGen, k)
}
elaspe := time.Since(begin)
fmt.Println("time: ", elaspe.Milliseconds(), "ms")
fmt.Println(float64(total) / float64(elaspe.Milliseconds()) * 1000)
}
{
// 7300 次/秒
useLattice = false
pt := &curvePoint{}
k, _ := rand.Int(rand.Reader, N)
begin := time.Now()
total := 10000
for i := 0; i < total; i++ {
pt.Mul(curveGen, k)
}
elaspe := time.Since(begin)
fmt.Println("time: ", elaspe.Milliseconds(), "ms")
fmt.Println(float64(total) / float64(elaspe.Milliseconds()) * 1000)
}
}
func TestTwistCurve(t *testing.T) {
pt := &twistPoint{}
pt.Set(twistGen)
if !pt.IsOnCurve() {
t.Fail()
t.Log("IsOnCurve failed!")
return
}
pt.Double(twistGen)
if !pt.IsOnCurve() {
t.Fail()
t.Log("Double failed!")
return
}
pt.Add(pt, twistGen)
if !pt.IsOnCurve() {
t.Fail()
t.Log("Add failed!")
return
}
OrderMinus1 := new(big.Int)
OrderMinus1.Sub(N, gmath.BigInt1)
pt.Mul(twistGen, OrderMinus1)
pt.Neg(pt)
pt.MakeAffine()
if *pt != *twistGen {
t.Fail()
t.Log("Mul failed!")
fmt.Println(pt)
fmt.Println(twistGen)
return
}
pt.Mul(twistGen, N)
if !pt.IsOnCurve() {
t.Fail()
t.Log("Mul N failed!")
return
}
if !pt.IsInfinity() {
t.Fail()
t.Log("IsInfinity failed!")
return
}
}
func TestTwistBaseMul(t *testing.T) {
pt0 := &twistPoint{}
pt1 := &twistPoint{}
for i := 0; i < 1000000; i++ {
k, _ := rand.Int(rand.Reader, N)
pt0.Mul(twistGen, k)
pt1.MulBase(k, twistBasePrecomputed8)
if !pt0.Equal(pt1) {
t.Log(pt0)
t.Log(pt1)
t.Fail()
return
}
if i%10000 == 0 {
t.Log(i, "passed")
}
}
}
func BenchmarkTwistBaseMul(b *testing.B) {
//BenchmarkTwistBaseMul-8 11694 101403 ns/op
pt := &twistPoint{}
k, _ := rand.Int(rand.Reader, N)
for i := 0; i < b.N; i++ {
pt.MulBase(k, twistBasePrecomputed8)
}
}
func BenchmarkTwistCurve(b *testing.B) {
//BenchmarkTwistCurve-8 3090 350948 ns/op
pt := &twistPoint{}
k, _ := rand.Int(rand.Reader, N)
for i := 0; i < b.N; i++ {
pt.Mul(twistGen, k)
}
}
func TestTwistCurveSpeed(T *testing.T) {
{
// 2800 次/秒
useLattice = true
pt := &twistPoint{}
k, _ := rand.Int(rand.Reader, N)
begin := time.Now()
total := 10000
for i := 0; i < total; i++ {
pt.Mul(twistGen, k)
}
elaspe := time.Since(begin)
fmt.Println("time: ", elaspe.Milliseconds(), "ms")
fmt.Println(float64(total) / float64(elaspe.Milliseconds()) * 1000)
}
{
// 1900 次/秒
useLattice = false
pt := &twistPoint{}
k, _ := rand.Int(rand.Reader, N)
begin := time.Now()
total := 10000
for i := 0; i < total; i++ {
pt.Mul(twistGen, k)
}
elaspe := time.Since(begin)
fmt.Println("time: ", elaspe.Milliseconds(), "ms")
fmt.Println(float64(total) / float64(elaspe.Milliseconds()) * 1000)
}
}
+39
View File
@@ -0,0 +1,39 @@
package bn256
import (
"crypto/rand"
)
func ExamplePair() {
// This implements the tripartite Diffie-Hellman algorithm from "A One
// Round Protocol for Tripartite Diffie-Hellman", A. Joux.
// http://www.springerlink.com/content/cddc57yyva0hburb/fulltext.pdf
// Each of three parties, a, b and c, generate a private value.
a, _ := rand.Int(rand.Reader, N)
b, _ := rand.Int(rand.Reader, N)
c, _ := rand.Int(rand.Reader, N)
// Then each party calculates g₁ and g₂ times their private value.
pa := new(G1).ScalarBaseMult(a)
qa := new(G2).ScalarBaseMult(a)
pb := new(G1).ScalarBaseMult(b)
qb := new(G2).ScalarBaseMult(b)
pc := new(G1).ScalarBaseMult(c)
qc := new(G2).ScalarBaseMult(c)
// Now each party exchanges its public values with the other two and
// all parties can calculate the shared key.
k1 := Pair(pb, qc)
k1.ScalarMult(k1, a)
k2 := Pair(pc, qa)
k2.ScalarMult(k2, b)
k3 := Pair(pa, qb)
k3.ScalarMult(k3, c)
// k1, k2 and k3 will all be equal.
}
@@ -0,0 +1,99 @@
package bn256
import (
"fmt"
"math/big"
"testing"
"xdx.jelly/xgcl/gmath"
)
func TestGenCurvePrecompute4(t *testing.T) {
table := make([]*curvePoint, 0, 32)
for i := 0; i < 16; i++ {
c := &curvePoint{}
c.SetInfinity()
for j := 0; j < 4; j++ {
t := &curvePoint{}
k := new(big.Int)
if (i>>j)&1 != 0 {
k.Lsh(gmath.BigInt1, 64*uint(j))
t.Mul(curveGen, k)
c.Add(c, t)
}
}
table = append(table, c)
}
for i := 0; i < 16; i++ {
c := &curvePoint{}
c.SetInfinity()
for j := 0; j < 4; j++ {
t := &curvePoint{}
k := new(big.Int)
if (i>>j)&1 != 0 {
k.Lsh(gmath.BigInt1, 31+64*uint(j))
t.Mul(curveGen, k)
c.Add(c, t)
}
}
table = append(table, c)
}
for _, x := range table {
x.MakeAffine()
fmt.Printf("&curvePoint{gfP{0x%x,0x%x,0x%x,0x%x},gfP{0x%x,0x%x,0x%x,0x%x},*newGFp(1),*newGFp(1)},\n", x.x[0], x.x[1], x.x[2], x.x[3], x.y[0], x.y[1], x.y[2], x.y[3])
}
}
func TestGenCurvePrecompute8(t *testing.T) {
table := make([]*curvePoint, 0, 256)
for i := 0; i < 256; i++ {
c := &curvePoint{}
c.SetInfinity()
for j := 0; j < 8; j++ {
t := &curvePoint{}
k := new(big.Int)
if (i>>j)&1 != 0 {
k.Lsh(gmath.BigInt1, 32*uint(j))
t.Mul(curveGen, k)
c.Add(c, t)
}
}
table = append(table, c)
}
for _, x := range table {
x.MakeAffine()
//fmt.Println(x)
fmt.Printf("&curvePoint{gfP{0x%x,0x%x,0x%x,0x%x},gfP{0x%x,0x%x,0x%x,0x%x},*newGFp(1),*newGFp(1)},\n",
x.x[0], x.x[1], x.x[2], x.x[3],
x.y[0], x.y[1], x.y[2], x.y[3])
}
}
func TestGenTwistCurvePrecompute8(t *testing.T) {
table := make([]*twistPoint, 0, 256)
for i := 0; i < 256; i++ {
c := &twistPoint{}
c.SetInfinity()
for j := 0; j < 8; j++ {
t := &twistPoint{}
k := new(big.Int)
if (i>>j)&1 != 0 {
k.Lsh(gmath.BigInt1, 32*uint(j))
t.Mul(twistGen, k)
c.Add(c, t)
}
}
table = append(table, c)
}
for _, x := range table {
x.MakeAffine()
fmt.Println(x)
//fmt.Printf("&twistPoint{gfP2{gfP{0x%x,0x%x,0x%x,0x%x},gfP{0x%x,0x%x,0x%x,0x%x}},gfP2{gfP{0x%x,0x%x,0x%x,0x%x},gfP{0x%x,0x%x,0x%x,0x%x}},gfP2{gfP{0},*newGFP(1)},gfP2{gfP{0},*newGFP(1)}},\n",
// x.x.x[0],x.x.x[1],x.x.x[2],x.x.x[3],
// x.x.y[0],x.x.y[1],x.x.y[2],x.x.y[3],
// x.y.x[0],x.y.x[1],x.y.x[2],x.y.x[3],
// x.y.y[0],x.y.y[1],x.y.y[2],x.y.y[3])
}
}
+245
View File
@@ -0,0 +1,245 @@
package bn256
import (
"encoding/binary"
"fmt"
"math/big"
"golang.org/x/crypto/hkdf"
"xdx.jelly/xgcl/sm/sm3"
)
// gfP is the finite fileds GF(p), little-endian and Montgomery reprent.
type gfP [4]uint64
// newGFp return the Montgomery encoded of x, i.e., out = x * R mod p
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
}
// bug: the output order
func (e *gfP) toBigInt() *big.Int {
// r := new(big.Int).SetUint64(e[0])
// r.Lsh(r, 64).Add(r, new(big.Int).SetUint64(e[1]))
// r.Lsh(r, 64).Add(r, new(big.Int).SetUint64(e[2]))
// r.Lsh(r, 64).Add(r, new(big.Int).SetUint64(e[3]))
// should be:
r := new(big.Int).SetUint64(e[3])
r.Lsh(r, 64).Add(r, new(big.Int).SetUint64(e[2]))
r.Lsh(r, 64).Add(r, new(big.Int).SetUint64(e[1]))
r.Lsh(r, 64).Add(r, new(big.Int).SetUint64(e[0]))
return r
}
// hashToBase implements hashing a message to an element of the field.
//
// L = ceil((256+128)/8)=48, ctr = 0, i = 1
//
// Although we do not need it in SM9.
func hashToBase(msg, dst []byte) *gfP { // nolint
var t [48]byte
info := []byte{'H', '2', 'C', byte(0), byte(1)}
// sha256 or sm3? its a question.
// r := hkdf.New(sha256.New, msg, dst, info)
r := hkdf.New(sm3.New, msg, dst, info)
if _, err := r.Read(t[:]); err != nil {
panic(err)
}
var x big.Int
v := x.SetBytes(t[:]).Mod(&x, P).Bytes()
v32 := [32]byte{}
for i := len(v) - 1; i >= 0; i-- {
v32[len(v)-1-i] = v[i]
}
u := &gfP{
binary.LittleEndian.Uint64(v32[0*8 : 1*8]),
binary.LittleEndian.Uint64(v32[1*8 : 2*8]),
binary.LittleEndian.Uint64(v32[2*8 : 3*8]),
binary.LittleEndian.Uint64(v32[3*8 : 4*8]),
}
montEncode(u, u)
return u
}
// String return the hex of e.
//
// Note e is Montgomery encoded, decode it befor printing if you want print the origin value.
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) Equal(other *gfP) bool {
return *e == *other
}
// Set sets e to f.
func (e *gfP) Set(f *gfP) {
e[0] = f[0]
e[1] = f[1]
e[2] = f[2]
e[3] = f[3]
}
// exp compute e = f^bits with naive square-mul method.
// Input bits is reprents as little-endian.
func (e *gfP) exp(f *gfP, bits [4]uint64) {
sum, power := &gfP{}, &gfP{}
sum[0], sum[1], sum[2], sum[3] = r[0], r[1], r[2], r[3] // sum = 1
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)
}
}
e.Set(sum)
}
// Invert set e to f^{-1}, by Farmat's little theorem: a^{-1} = a^{p-2} mod p
//
// If input f is 0, then e is 0 after return.
func (e *gfP) Invert(f *gfP) {
e.exp(f, pMinus2)
}
// half set e to f/2. Use shift to void mul 1/2 mod p
func (e *gfP) half(f *gfP) {
sign := f[0] & 1
if sign == 1 {
gfpNeg(e, f)
} else {
if e != f {
*e = *f
}
}
// e = e >> 1
e[0] = (e[0] >> 1) | (e[1] << 63)
e[1] = (e[1] >> 1) | (e[2] << 63)
e[2] = (e[2] >> 1) | (e[3] << 63)
e[3] >>= 1
if sign == 1 {
gfpNeg(e, e)
}
}
// Sqrt set e to be the square root of f if f is a square.
// If f is not a square, the result is undefined.
func (e *gfP) Sqrt(f *gfP) {
// Since P = 8u+5, then:
// if f^{2u+1} = 1, e = f^(u+1)
// or
// f^{2u+1} = -1, e = f^(u+1) * sqrt(-1).
if false {
// If we do not care side channel attack, we just square f^(u+1) and compare with f.
// if f is not a square, then f is undefined
root := &gfP{}
ff := &gfP{}
root.exp(f, pPlus3Over8) // sum = f^{u+1}
gfpMul(ff, root, root) // power = f^{2u+2}
if *ff == *f {
e.Set(root)
} else {
gfpMul(e, root, sqrtRootOfMinus1ModP)
}
} else {
// constant time, but extra 2 mul.
f2u1 := &gfP{}
fu1 := &gfP{}
fu1s1 := &gfP{}
fu1s1.exp(f, pMinus5Over8) // fu = f^u
gfpMul(fu1, fu1s1, f) // fu1 = f^{u+1}
gfpMul(f2u1, fu1s1, fu1) // g=f^{2u+1}
gfpMul(fu1s1, fu1, sqrtRootOfMinus1ModP) // fu = f^{u+1} * sqrt(-1)
// g must be -1, 0 or 1 if f is a square.
switch {
case *f2u1 == gfP(r):
e.Set(fu1)
case *f2u1 == gfP(nr):
e.Set(fu1s1)
case *f2u1 == gfP{}:
e[0] = 0
e[1] = 0
e[2] = 0
e[3] = 0
default:
// f is not a square, e unchange
}
}
}
// Marshal marshal e to bytes
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))
}
}
}
// Unmarshal restore e from bytes
func (e *gfP) Unmarshal(in []byte) {
for w := uint(0); w < 4; w++ {
e[3-w] = 0
for b := uint(0); b < 8; b++ {
e[3-w] += uint64(in[8*w+b]) << (56 - 8*b)
}
}
}
// montEncode set c to a's Montgomery reprent, c = a*R mod p
func montEncode(c, a *gfP) {
gfpMul(c, a, r2)
}
// montDecode a Montgomery reprent a, c = a*R^-1 mod p
func montDecode(c, a *gfP) {
gfpMul(c, a, &gfP{1})
}
// sign0 returns the sign of e - (p-1)/2
func sign0(e *gfP) int { // nolint
x := &gfP{}
montDecode(x, e)
for w := 3; w >= 0; w-- {
if x[w] > pMinus1Over2[w] {
return 1
} else if x[w] < pMinus1Over2[w] {
return -1
}
}
return 1
}
// legendre return the legendre symbol of e
func legendre(e *gfP) int {
f := &gfP{}
// Since P = 4k+3, then e^(2k+1) is the Legendre symbol of e.
f.exp(e, pMinus1Over2)
montDecode(f, f)
if *f != [4]uint64{} {
return 2*int(f[0]&1) - 1
}
return 0
}
+249
View File
@@ -0,0 +1,249 @@
package bn256
// For details of the algorithms used, see "Multiplication and Squaring on
// Pairing-Friendly Fields, Devegili et al.
// http://eprint.iacr.org/2006/471.pdf.
import (
"math/big"
)
// gfP12 implements the field of size P¹² as a quadratic extension of gfP6
// where ω²=τ.
type gfP12 struct {
x, y gfP6 // value is xω + y
}
// gfP12Gen = e(g1, g2)
var gfP12Gen = &gfP12{
x: gfP6{
x: gfP2{
x: gfP{0xeb2aeaa2823d010c, 0xe192c39d7c3e6440, 0x68411e843fea2a9b, 0x5f23b1ce3ac438e7},
y: gfP{0x65c1ad6d376db4f, 0xe2447d6d5edfdda6, 0xd4eba5c8c017781, 0x61ebca2110d736bf},
},
y: gfP2{
x: gfP{0xc219536a54552cae, 0xc4e4ad66027f8f55, 0xff31b23d5bc78184, 0x3b0fc03d5711c93d},
y: gfP{0x290e1c8bdb9441aa, 0x74e1694c800c130, 0xfa196a2583564700, 0x254eb32dea84e64d},
},
z: gfP2{
x: gfP{0x24fb5abe38626c9c, 0xd32d71f71d7bd3de, 0x671d686fd9c9271d, 0xa3eec3cd6a795be8},
y: gfP{0x7b9c733c1f964b52, 0x9b988c0c238fb05e, 0xe546ccb8d6e1f9b8, 0xb101d668bfbf8ac8},
},
},
y: gfP6{
x: gfP2{
x: gfP{0x487ab1a6229d91f3, 0x7e2a3e36c6c822c7, 0x282c24f00c10930f, 0x2efe33f18332bb77},
y: gfP{0x346965f4dc5b5813, 0xed43ed38c0ce33e6, 0x9ba7630e295a5ce7, 0xa6db7142e0ca24ae},
},
y: gfP2{
x: gfP{0xfea0bce10965b32b, 0x441e074b4573390c, 0xe9d6067a4cf3c571, 0x9ee43c7e3740bcd8},
y: gfP{0xe06727b47ee6118, 0xb01ab631f2f10a18, 0xb0ebd9852fc780ef, 0xaa07010f9d42787c},
},
z: gfP2{
x: gfP{0xbe7381e2bce90a00, 0x2a72158dbf514e31, 0x44e199bee3498d4d, 0x6a5fed210720de58},
y: gfP{0xb55d63ee8d7a8468, 0x9ef5d413e3176666, 0x796c802ec3f1370b, 0xa0f422c35d7b6262},
},
},
}
func gfP12Decode(in *gfP12) *gfP12 { // nolint
return &gfP12{
*gfP6Decode(&in.x),
*gfP6Decode(&in.y),
}
}
func (e *gfP12) Equal(other *gfP12) bool {
return e.x.Equal(&other.x) && e.y.Equal(&other.y)
}
func (e *gfP12) String() string {
return "(" + e.x.String() + "," + e.y.String() + ")"
}
func (e *gfP12) Set(a *gfP12) *gfP12 {
e.x.Set(&a.x)
e.y.Set(&a.y)
return e
}
func (e *gfP12) SetZero() *gfP12 {
e.x.SetZero()
e.y.SetZero()
return e
}
func (e *gfP12) SetOne() *gfP12 {
e.x.SetZero()
e.y.SetOne()
return e
}
func (e *gfP12) IsZero() bool {
return e.x.IsZero() && e.y.IsZero()
}
func (e *gfP12) IsOne() bool {
return e.x.IsZero() && e.y.IsOne()
}
func (e *gfP12) Conjugate(a *gfP12) *gfP12 {
e.x.Neg(&a.x)
e.y.Set(&a.y)
return e
}
func (e *gfP12) Neg(a *gfP12) *gfP12 {
e.x.Neg(&a.x)
e.y.Neg(&a.y)
return e
}
// Frobenius computes (xω+y)^P = x^P ω·ξ^((P-1)/6) + y^P
func (e *gfP12) Frobenius(a *gfP12) *gfP12 {
e.x.Frobenius(&a.x)
e.y.Frobenius(&a.y)
e.x.MulGFP(&e.x, xiToPMinus1Over6)
return e
}
// FrobeniusP2 computes (xω+y)^P² = x^P² ω·ξ^((P²-1)/6) + y^P²
func (e *gfP12) FrobeniusP2(a *gfP12) *gfP12 {
e.x.FrobeniusP2(&a.x)
e.x.MulGFP(&e.x, xiToPSquaredMinus1Over6)
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
}
func (e *gfP12) Add(a, b *gfP12) *gfP12 {
e.x.Add(&a.x, &b.x)
e.y.Add(&a.y, &b.y)
return e
}
func (e *gfP12) Sub(a, b *gfP12) *gfP12 {
e.x.Sub(&a.x, &b.x)
e.y.Sub(&a.y, &b.y)
return e
}
func (e *gfP12) Mul(a, b *gfP12) *gfP12 {
tx := (&gfP6{}).Mul(&a.x, &b.y)
t := (&gfP6{}).Mul(&b.x, &a.y)
tx.Add(tx, t)
ty := (&gfP6{}).Mul(&a.y, &b.y)
t.Mul(&a.x, &b.x).MulTau(t)
e.x.Set(tx)
e.y.Add(ty, t)
return e
}
func (e *gfP12) MulScalar(a *gfP12, b *gfP6) *gfP12 {
e.x.Mul(&e.x, b)
e.y.Mul(&e.y, b)
return e
}
// Exp compute c = a^power, and return c. Exp is the common square-mul, for all
// Elements in gfp12
func (e *gfP12) Exp(a *gfP12, power *big.Int) *gfP12 {
sum := (&gfP12{}).SetOne()
t := &gfP12{}
for i := power.BitLen() - 1; i >= 0; i-- {
t.Square(sum)
if power.Bit(i) != 0 {
sum.Mul(t, a)
} else {
sum.Set(t)
}
}
return e.Set(sum)
}
// for element in GT
func (e *gfP12) latticeExp(a *gfP12, power *big.Int) *gfP12 {
base := [1 << 2]*gfP12{{}, {}, {}, {}}
base[0].Set(a)
base[1].Frobenius(base[0])
base[2].FrobeniusP2(base[0])
base[3].Frobenius(base[2])
decomp := targetLattice.decompose(power)
//fmt.Println(decomp)
for i := 0; i < len(decomp); i++ {
if decomp[i].Sign() < 0 {
base[i].Conjugate(base[i])
}
}
precomp := [1 << 4]*gfP12{}
targetLattice.Precompute(func(i, j uint) {
if precomp[j] == nil {
precomp[j] = &gfP12{}
precomp[j].SetOne()
}
precomp[j].Mul(precomp[j], base[i])
})
multiPower := targetLattice.Multi(power)
sum := &gfP12{}
sum.SetOne()
t := &gfP12{}
for i := len(multiPower) - 1; i >= 0; i-- {
t.Square(sum)
if multiPower[i] == 0 {
sum.Set(t)
} else {
sum.Mul(t, precomp[multiPower[i]])
}
}
e.Set(sum)
return e
}
func (e *gfP12) Square(a *gfP12) *gfP12 {
// Complex squaring algorithm
v0 := (&gfP6{}).Mul(&a.x, &a.y)
t := (&gfP6{}).MulTau(&a.x)
t.Add(&a.y, t)
ty := (&gfP6{}).Add(&a.x, &a.y)
ty.Mul(ty, t).Sub(ty, v0)
t.MulTau(v0)
ty.Sub(ty, t)
e.x.Add(v0, v0)
e.y.Set(ty)
return e
}
func (e *gfP12) Invert(a *gfP12) *gfP12 {
// See "Implementing cryptographic pairings", M. Scott, section 3.2.
// ftp://136.206.11.249/pub/crypto/pairings.pdf
t1, t2 := &gfP6{}, &gfP6{}
t1.Square(&a.x)
t2.Square(&a.y)
t1.MulTau(t1).Sub(t2, t1)
t2.Invert(t1)
e.x.Neg(&a.x)
e.y.Set(&a.y)
e.MulScalar(e, t2)
return e
}
+199
View File
@@ -0,0 +1,199 @@
package bn256
// For details of the algorithms used, see "Multiplication and Squaring on
// Pairing-Friendly Fields, Devegili et al.
// http://eprint.iacr.org/2006/471.pdf.
// gfP2 implements a field of size P² as a quadratic extension of the base field
// where i²=-1.
// For SM9, gfP2 = gfP[x]/(x²+2) = gfP(u) where u²=-2.
type gfP2 struct {
// sm9: xu+y
x, y gfP
}
func gfP2Decode(in *gfP2) *gfP2 {
out := &gfP2{}
montDecode(&out.x, &in.x)
montDecode(&out.y, &in.y)
return out
}
func (e *gfP2) String() string {
return "(" + e.x.String() + ", " + e.y.String() + ")"
}
func (e *gfP2) Equal(other *gfP2) bool {
return e.x.Equal(&other.x) && e.y.Equal(&other.y)
}
func (e *gfP2) Set(a *gfP2) *gfP2 {
e.x.Set(&a.x)
e.y.Set(&a.y)
return e
}
func (e *gfP2) SetZero() *gfP2 {
e.x = gfP{0}
e.y = gfP{0}
return e
}
func (e *gfP2) SetOne() *gfP2 {
e.x = gfP{0}
e.y = gfPOne
return e
}
func (e *gfP2) IsZero() bool {
return e.x == gfPZero && e.y == gfPZero
}
func (e *gfP2) IsOne() bool {
return e.x == gfPZero && e.y == gfPOne
}
// Conjugate sets e = -xu+y if a = xu+y. Also note that conjugate equivalents to e = Frobenius(a) = a^p
func (e *gfP2) Conjugate(a *gfP2) *gfP2 {
e.y.Set(&a.y)
gfpNeg(&e.x, &a.x)
return e
}
func (e *gfP2) Neg(a *gfP2) *gfP2 {
gfpNeg(&e.x, &a.x)
gfpNeg(&e.y, &a.y)
return e
}
func (e *gfP2) Add(a, b *gfP2) *gfP2 {
gfpAdd(&e.x, &a.x, &b.x)
gfpAdd(&e.y, &a.y, &b.y)
return e
}
func (e *gfP2) Sub(a, b *gfP2) *gfP2 {
gfpSub(&e.x, &a.x, &b.x)
gfpSub(&e.y, &a.y, &b.y)
return e
}
// See "Multiplication and Squaring in Pairing-Friendly Fields",
// http://eprint.iacr.org/2006/471.pdf
// (ax*u + ay) (bx*u + by) = (ay*by - 2ax*bx) + (ay*bx+ax*by)u
func (e *gfP2) Mul(a, b *gfP2) *gfP2 {
tx, t := &gfP{}, &gfP{}
gfpMul(tx, &a.x, &b.y)
gfpMul(t, &b.x, &a.y)
gfpAdd(tx, tx, t)
ty := &gfP{}
gfpMul(ty, &a.y, &b.y)
gfpMul(t, &a.x, &b.x)
gfpAdd(t, t, t)
gfpSub(ty, ty, t)
e.x.Set(tx)
e.y.Set(ty)
return e
}
func (e *gfP2) MulScalar(a *gfP2, b *gfP) *gfP2 {
gfpMul(&e.x, &a.x, b)
gfpMul(&e.y, &a.y, b)
return e
}
//MulXi sets e=ξa where ξ=i+3 and then returns e.
//e = u*a = -2x + yu
// sm9: e = a*u = yu - 2x
func (e *gfP2) MulXi(a *gfP2) *gfP2 {
// (xi+y)(i+3) = (3x+y)i+(3y-x)
//e = u*a = -2x + yu
ty := &gfP{}
gfpAdd(ty, &a.x, &a.x)
gfpNeg(ty, ty)
tx := &gfP{}
tx.Set(&a.y)
e.x.Set(tx)
e.y.Set(ty)
return e
}
func (e *gfP2) Square(a *gfP2) *gfP2 {
// Complex squaring algorithm:
// (xi+y)² = (x+y)(y-x) + 2*i*x*y
// sm9: (xu+y)² = y²-2x² + 2uxy
tx, ty := &gfP{}, &gfP{}
gfpMul(ty, &a.y, &a.y)
gfpMul(tx, &a.x, &a.x)
gfpAdd(tx, tx, tx)
gfpSub(ty, ty, tx)
gfpMul(tx, &a.x, &a.y)
gfpAdd(tx, tx, tx)
e.x.Set(tx)
e.y.Set(ty)
return e
}
func (e *gfP2) Invert(a *gfP2) *gfP2 {
// See "Implementing cryptographic pairings", M. Scott, section 3.2.
// ftp://136.206.11.249/pub/crypto/pairings.pdf
t1, t2 := &gfP{}, &gfP{}
gfpMul(t1, &a.x, &a.x)
gfpAdd(t1, t1, t1)
gfpMul(t2, &a.y, &a.y)
gfpAdd(t1, t1, t2)
inv := &gfP{}
inv.Invert(t1)
gfpNeg(t1, &a.x)
gfpMul(&e.x, t1, inv)
gfpMul(&e.y, &a.y, inv)
return e
}
// Sqrt sets e = sqrt(e) and return true if e is a square. Otherwise returns false and e remain unchanged.
// The algorithm is based on the beautiful identity:
// $$
// \sqrt{a+bx} = \pm\left(\sqrt{ \frac{a \pm \sqrt{a^2 + nb^2}}{2} } + \frac{xb}{2\sqrt{ \frac{a \pm \sqrt{a^2 + nb^2}}{2} }}\right)
// $$
func (e *gfP2) Sqrt(f *gfP2) bool {
a := &gfP{}
b := &gfP{}
tmp := &gfP{}
// e = a + bu
gfpMul(a, &f.y, &f.y)
gfpMul(b, &f.x, &f.x)
gfpAdd(tmp, a, b)
gfpAdd(tmp, tmp, b)
//a = a^2 + nb^2
if legendre(tmp) != 1 {
return false
}
tmp.Sqrt(tmp)
gfpAdd(a, &f.y, tmp)
a.half(a)
if legendre(a) != 1 {
gfpSub(a, &f.y, tmp)
a.half(a)
if legendre(a) != 1 {
return false
}
}
e.y.Sqrt(a)
gfpAdd(a, &e.y, &e.y)
a.Invert(a)
gfpMul(&e.x, a, &f.x)
return true
}
+243
View File
@@ -0,0 +1,243 @@
package bn256
// For details of the algorithms used, see "Multiplication and Squaring on
// Pairing-Friendly Fields, Devegili et al.
// http://eprint.iacr.org/2006/471.pdf.
// gfP6 implements the field of size P⁶ as a cubic extension of gfP2 where τ³=ξ
// and ξ=i+3.
//
// SM9: The sm9 extension is 1-2-4-12, but we use 1-2-6-12. Also τ³=ξ and ξ=u where
// u²=-2
type gfP6 struct {
x, y, z gfP2 // value is xτ² + yτ + z
}
func gfP6Decode(in *gfP6) *gfP6 { // nolint
return &gfP6{
*gfP2Decode(&in.x),
*gfP2Decode(&in.y),
*gfP2Decode(&in.z),
}
}
func (e *gfP6) Equal(other *gfP6) bool {
return e.x.Equal(&other.x) && e.y.Equal(&other.y) && e.z.Equal(&other.z)
}
// String returns a readable string.
func (e *gfP6) String() string {
return "(" + e.x.String() + ", " + e.y.String() + ", " + e.z.String() + ")"
}
// Set sets e to a.
func (e *gfP6) Set(a *gfP6) *gfP6 {
e.x.Set(&a.x)
e.y.Set(&a.y)
e.z.Set(&a.z)
return e
}
// SetZero sets e to 0.
func (e *gfP6) SetZero() *gfP6 {
e.x.SetZero()
e.y.SetZero()
e.z.SetZero()
return e
}
// SetOne sets e to 1.
func (e *gfP6) SetOne() *gfP6 {
e.x.SetZero()
e.y.SetZero()
e.z.SetOne()
return e
}
// IsZero returns trun if e is 0.
func (e *gfP6) IsZero() bool {
return e.x.IsZero() && e.y.IsZero() && e.z.IsZero()
}
// IsOne returns trun if e is 1.
func (e *gfP6) IsOne() bool {
return e.x.IsZero() && e.y.IsZero() && e.z.IsOne()
}
// Neg sets e to the negative of a.
func (e *gfP6) Neg(a *gfP6) *gfP6 {
e.x.Neg(&a.x)
e.y.Neg(&a.y)
e.z.Neg(&a.z)
return e
}
// Frobenius sets e = frob(a) = a^{p}
//
// If a = xτ² + yτ + z, then
// x^p = frob(x) =
// τ^p = (τ^3)^{(p-1)/3} * τ = ξ^{(p-1)/3} * τ
// τ^2p = (τ^3)^{2(p-1)/3} * τ² = ξ^{(p-1)/3} * τ²
func (e *gfP6) Frobenius(a *gfP6) *gfP6 {
// Conjugate equals to Frobenius over gfP2
e.x.Conjugate(&a.x)
e.y.Conjugate(&a.y)
e.z.Conjugate(&a.z)
e.x.MulScalar(&e.x, xiTo2PMinus2Over3)
e.y.MulScalar(&e.y, xiToPMinus1Over3)
return e
}
// FrobeniusP2 computes (xτ²+yτ+z)^(P²) = xτ^(2p²) + yτ^(P²) + z
func (e *gfP6) FrobeniusP2(a *gfP6) *gfP6 {
// τ^(2p²) = τ²τ^(2p²-2) = τ²ξ^((2p²-2)/3)
e.x.MulScalar(&a.x, xiTo2PSquaredMinus2Over3)
// τ^(P²) = ττ^(P²-1) = τξ^((P²-1)/3)
e.y.MulScalar(&a.y, xiToPSquaredMinus1Over3)
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
}
func (e *gfP6) Add(a, b *gfP6) *gfP6 {
e.x.Add(&a.x, &b.x)
e.y.Add(&a.y, &b.y)
e.z.Add(&a.z, &b.z)
return e
}
func (e *gfP6) Sub(a, b *gfP6) *gfP6 {
e.x.Sub(&a.x, &b.x)
e.y.Sub(&a.y, &b.y)
e.z.Sub(&a.z, &b.z)
return e
}
func (e *gfP6) Mul(a, b *gfP6) *gfP6 {
// "Multiplication and Squaring on Pairing-Friendly Fields"
// Section 4, Karatsuba method.
// 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)
t0 := (&gfP2{}).Add(&a.x, &a.y)
t1 := (&gfP2{}).Add(&b.x, &b.y)
tz := (&gfP2{}).Mul(t0, t1)
tz.Sub(tz, v1).Sub(tz, v2).MulXi(tz).Add(tz, v0)
t0.Add(&a.y, &a.z)
t1.Add(&b.y, &b.z)
ty := (&gfP2{}).Mul(t0, t1)
t0.MulXi(v2)
ty.Sub(ty, v0).Sub(ty, v1).Add(ty, t0)
t0.Add(&a.x, &a.z)
t1.Add(&b.x, &b.z)
tx := (&gfP2{}).Mul(t0, t1)
tx.Sub(tx, v0).Add(tx, v1).Sub(tx, v2)
e.x.Set(tx)
e.y.Set(ty)
e.z.Set(tz)
return e
}
func (e *gfP6) MulScalar(a *gfP6, b *gfP2) *gfP6 {
e.x.Mul(&a.x, b)
e.y.Mul(&a.y, b)
e.z.Mul(&a.z, b)
return e
}
func (e *gfP6) MulGFP(a *gfP6, b *gfP) *gfP6 {
e.x.MulScalar(&a.x, b)
e.y.MulScalar(&a.y, b)
e.z.MulScalar(&a.z, b)
return e
}
// MulTau computes τ·(aτ²+bτ+c) = bτ²+cτ+aξ
func (e *gfP6) MulTau(a *gfP6) *gfP6 {
tz := (&gfP2{}).MulXi(&a.x)
ty := (&gfP2{}).Set(&a.y)
e.y.Set(&a.z)
e.x.Set(ty)
e.z.Set(tz)
return e
}
func (e *gfP6) Square(a *gfP6) *gfP6 {
v0 := (&gfP2{}).Square(&a.z)
v1 := (&gfP2{}).Square(&a.y)
v2 := (&gfP2{}).Square(&a.x)
c0 := (&gfP2{}).Add(&a.x, &a.y)
c0.Square(c0).Sub(c0, v1).Sub(c0, v2).MulXi(c0).Add(c0, v0)
c1 := (&gfP2{}).Add(&a.y, &a.z)
c1.Square(c1).Sub(c1, v0).Sub(c1, v1)
xiV2 := (&gfP2{}).MulXi(v2)
c1.Add(c1, xiV2)
c2 := (&gfP2{}).Add(&a.x, &a.z)
c2.Square(c2).Sub(c2, v0).Add(c2, v1).Sub(c2, v2)
e.x.Set(c2)
e.y.Set(c1)
e.z.Set(c0)
return e
}
func (e *gfP6) Invert(a *gfP6) *gfP6 {
// See "Implementing cryptographic pairings", M. Scott, section 3.2.
// ftp://136.206.11.249/pub/crypto/pairings.pdf
// Here we can give a short explanation of how it works: let j be a cubic root of
// unity in GF(P²) so that 1+j+j²=0.
// Then (xτ² + yτ + z)(xj²τ² + yjτ + z)(xjτ² + yj²τ + z)
// = (xτ² + yτ + z)(Cτ²+Bτ+A)
// = (x³ξ²+y³ξ+z³-3ξxyz) = F is an element of the base field (the norm).
//
// On the other hand (xj²τ² + yjτ + z)(xjτ² + yj²τ + z)
// = τ²(y²-ξxz) + τ(ξx²-yz) + (z²-ξxy)
//
// So that's why A = (z²-ξxy), B = (ξx²-yz), C = (y²-ξxz)
t1 := (&gfP2{}).Mul(&a.x, &a.y)
t1.MulXi(t1)
A := (&gfP2{}).Square(&a.z)
A.Sub(A, t1)
B := (&gfP2{}).Square(&a.x)
B.MulXi(B)
t1.Mul(&a.y, &a.z)
B.Sub(B, t1)
C := (&gfP2{}).Square(&a.y)
t1.Mul(&a.x, &a.z)
C.Sub(C, t1)
F := (&gfP2{}).Mul(C, &a.y)
F.MulXi(F)
t1.Mul(A, &a.z)
F.Add(F, t1)
t1.Mul(B, &a.x).MulXi(t1)
F.Add(F, t1)
F.Invert(F)
e.x.Mul(C, F)
e.y.Mul(B, F)
e.z.Mul(A, F)
return e
}
+187
View File
@@ -0,0 +1,187 @@
// +build amd64,!generic
#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 loadModulus(p0,p1,p2,p3) \
MOVD ·p2+0(SB), p0 \
MOVD ·p2+8(SB), p1 \
MOVD ·p2+16(SB), p2 \
MOVD ·p2+24(SB), p3
#define loadR(p0,p1,p2,p3) \
MOVD ·r+0(SB), p0 \
MOVD ·r+8(SB), p1 \
MOVD ·r+16(SB), p2 \
MOVD ·r+24(SB), p3
#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 = CMOVAEQ (AT&T), i.e., a >= p then move a-p to a.
CMOVQCC b0, a0 \
CMOVQCC b1, a1 \
CMOVQCC b2, a2 \
CMOVQCC b3, a3
#include "mul_amd64.h"
#include "mul_bmi2_amd64.h"
// a > p
TEXT ·gfpNeg(SB),0,$0-16
loadModulus(R8,R9,R10,R11)
loadR(R12,R13,R14,R15)
// Let R = 2^{256} and r = R % p
// /- p - a if p >= a
// R11:R8 = -|
// \- R + p - a if p < a
MOVQ a+8(FP), DI
SUBQ 0(DI), R8
SBBQ 8(DI), R9
SBBQ 16(DI), R10
SBBQ 24(DI), R11
// /- 0 if p >= a
// R15:R12 = -|
// \- r if p < a
MOVQ $0, AX
CMOVQCC AX, R12
CMOVQCC AX, R13
CMOVQCC AX, R14
CMOVQCC AX, R15
// /- p - a if p >= a
// R11:R8 = -|
// \- R + p - a - r if p < a
// Note R + p - a - r = p - a mod p and
// 0 < R + p - a - r < R
SUBQ R12, R8
SBBQ R13, R9
SBBQ R14, R10
SBBQ R15, R11
MOVQ c+0(FP), DI
storeBlock(R8,R9,R10,R11, 0(DI))
RET
// cloudflare
// a > p mod r
// 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 // p - a
// 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
// a - b or R + a - b
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
// sub 0 or sub r=R%p = R-p.
// sub r equals add p.
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 ·hasBMI2(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
+140
View File
@@ -0,0 +1,140 @@
// +build arm64,!generic
#define storeBlock(a0,a1,a2,a3, r) \
MOVD a0, 0+r \
MOVD a1, 8+r \
MOVD a2, 16+r \
MOVD a3, 24+r
#define loadBlock(r, a0,a1,a2,a3) \
MOVD 0+r, a0 \
MOVD 8+r, a1 \
MOVD 16+r, a2 \
MOVD 24+r, a3
#define loadModulus(p0,p1,p2,p3) \
MOVD ·p2+0(SB), p0 \
MOVD ·p2+8(SB), p1 \
MOVD ·p2+16(SB), p2 \
MOVD ·p2+24(SB), p3
#define loadR(p0,p1,p2,p3) \
MOVD ·r+0(SB), p0 \
MOVD ·r+8(SB), p1 \
MOVD ·r+16(SB), p2 \
MOVD ·r+24(SB), p3
#include "mul_arm64.h"
TEXT ·gfpNeg(SB),0,$0-16
MOVD a+8(FP), R0
loadBlock(0(R0), R1,R2,R3,R4)
loadModulus(R5,R6,R7,R8)
// (CS, R8:R5) = p-a
SUBS R1,R5, R5
SBCS R2,R6, R6
SBCS R3,R7, R7
SBCS R4,R8, R8
// if CS = 0, then p >= a, R8:R5 = p-a
// if CS = 1, then p < a, R8:R5 = R+p-a mod p
// Thus we need sub R if CS = 1.
// If CS = 1, R4:R1 = R, otherwise 0
loadR(R1,R2,R3,R4)
MOVD $0, R0
CSEL CS, R0, R1, R1
CSEL CS, R0, R2, R2
CSEL CS, R0, R3, R3
CSEL CS, R0, R4, R4
// R5:R8 = p-a
SUBS R1, R5, R5
SBCS R2, R6, R6
SBCS R3, R7, R7
SBCS R4, R8, R8
MOVD c+0(FP), R0
storeBlock(R5,R6,R7,R8, 0(R0))
RET
TEXT ·gfpAdd(SB),0,$0-24
MOVD a+8(FP), R0
loadBlock(0(R0), R1,R2,R3,R4)
MOVD b+16(FP), R0
loadBlock(0(R0), R5,R6,R7,R8)
loadModulus(R9,R10,R11,R12)
MOVD ZR, R0
// (R0,R4,R3,R2,R1) = a + b
ADDS R5, R1
ADCS R6, R2
ADCS R7, R3
ADCS R8, R4
ADCS ZR, R0
// (R0,R8,R7,R6,R5) = a + b - p
SUBS R9, R1, R5
SBCS R10, R2, R6
SBCS R11, R3, R7
SBCS R12, R4, R8
SBCS ZR, R0, R0
// if CS = 1, then a + b < p
CSEL CS, R5, R1, R1
CSEL CS, R6, R2, R2
CSEL CS, R7, R3, R3
CSEL CS, R8, R4, R4
MOVD c+0(FP), R0
storeBlock(R1,R2,R3,R4, 0(R0))
RET
TEXT ·gfpSub(SB),0,$0-24
MOVD a+8(FP), R0
loadBlock(0(R0), R1,R2,R3,R4)
MOVD b+16(FP), R0
loadBlock(0(R0), R5,R6,R7,R8)
loadModulus(R9,R10,R11,R12)
// R4:R1 = a - b or R + a - b
SUBS R5, R1
SBCS R6, R2
SBCS R7, R3
SBCS R8, R4
// R12:R9= 0 or p
CSEL CS, ZR, R9, R9
CSEL CS, ZR, R10, R10
CSEL CS, ZR, R11, R11
CSEL CS, ZR, R12, R12
// actually, we should sub r if R4:R1 = R + a - b.
// but R4:R1 - r = R-r + a-b = p + a-b.
// Therefore, sub r equals add p.
// Also, for a < b, the addtion carrys 0.
ADDS R9, R1
ADCS R10, R2
ADCS R11, R3
ADCS R12, R4
MOVD c+0(FP), R0
storeBlock(R1,R2,R3,R4, 0(R0))
RET
TEXT ·gfpMul(SB),0,$0-24
MOVD a+8(FP), R0
loadBlock(0(R0), R1,R2,R3,R4)
MOVD b+16(FP), R0
loadBlock(0(R0), R5,R6,R7,R8)
// R16:R9 = R4:R1 * R8:R5 = a * b
mul(R9,R10,R11,R12,R13,R14,R15,R16)
gfpReduce()
MOVD c+0(FP), R0
storeBlock(R1,R2,R3,R4, 0(R0))
RET
+24
View File
@@ -0,0 +1,24 @@
//go:build (amd64 && !generic) || (arm64 && !generic)
// +build amd64,!generic arm64,!generic
package bn256
// This file contains forward declarations for the architecture-specific
// assembly implementations of these functions, provided that they exist.
import "golang.org/x/sys/cpu"
var hasBMI2 = cpu.X86.HasBMI2
var _ = hasBMI2
//go:noescape
func gfpNeg(c, a *gfP) // for all a < R, return c = -a mod p, a could be > p
//go:noescape
func gfpAdd(c, a, b *gfP) // for a,b <p
//go:noescape
func gfpSub(c, a, b *gfP) // for a, b < p
//go:noescape
func gfpMul(c, a, b *gfP) // for a*b < pR
+245
View File
@@ -0,0 +1,245 @@
//go:build (!amd64 && !arm64) || generic
// +build !amd64,!arm64 generic
package bn256
/*
判断进位的规则
设B=2^w, w = 64 or 32.
假设a op b = c + carry·B.
注:若carry =0 or 1, 则a + b + carry是否产生进位和carry无关。
因为若a+b+carry当carry=0不产生进位,当carry=1产生进位,当且仅当
a+b = B-1, 则a,b中必然有一个数(不妨设为a)的某个非最高比特为0,则
a'=a+carry, a'与a的最高比特相同。因此a'+b 与a+b的进位相同。因此
我们只需要考虑carry为0的情况。
# Add
carry如下:
a[w-1] 0 0 0 1 1 1
b[w-1] 0 1 1 0 0 1
c[w-1] x 0 1 0 1 x
carry 0 1 0 1 0 1
carry>0 <=> a或b都为1(第w-1bit) 或 ab其中一个为1,但c为0.
# Sub
carry如下:
a[w-1] 0 0 0 1 1 1
b[w-1] 0 0 1 0 1 1
c[w-1] 1 0 x x 0 1
carry 1 0 1 0 0 1
carry = (b&^a | (b|^a)&c) >> 63
carry>0 <=> a为0b为1 或 (a,b)!=(1,0)并且c=1.
*/
// gfpCarry compute (a, head) mod p, input (a,head) < 2p
//
// 先计算 (b,carry) = a - p
//
// carry head ret
// 0(a>p) 0 b
// 0 1 b(此情形下,(a,head) > 2p, 不应出现。此时,应再调用一次gfpCarry)
// 1(a<p) 0 a
// 1 1 b
//
// so, carry &^ head = 1, return a, otherwise return b
func gfpCarry(a *gfP, head uint64) {
b := &gfP{}
var carry uint64
for i, pi := range p2 {
ai := a[i]
bi := ai - pi - carry
b[i] = bi
carry = (pi&^ai | (pi|^ai)&bi) >> 63
}
carry = carry &^ head
// If b is negative, then return a.
// Else return b.
carry = -carry
ncarry := ^carry
for i := 0; i < 4; i++ {
a[i] = (a[i] & carry) | (b[i] & ncarry)
}
}
// gfpNeg set c = -a, input a < p
func gfpNeg(c, a *gfP) {
var carry uint64
for i, pi := range p2 {
ai := a[i]
ci := pi - ai - carry
c[i] = ci
carry = (ai&^pi | (ai|^pi)&ci) >> 63
}
// FIXME: carry?
gfpCarry(c, 0)
}
// gfpAdd set c = a+b
func gfpAdd(c, a, b *gfP) {
var carry uint64
for i, ai := range a {
bi := b[i]
ci := ai + bi + carry
c[i] = ci
carry = (ai&bi | (ai|bi)&^ci) >> 63
}
gfpCarry(c, carry)
}
func gfpSub(c, a, b *gfP) {
t := &gfP{}
// t = p-b
var carry uint64
for i, pi := range p2 {
bi := b[i]
ti := pi - bi - carry
t[i] = ti
carry = (bi&^pi | (bi|^pi)&ti) >> 63
}
// c = a+t
carry = 0
for i, ai := range a {
ti := t[i]
ci := ai + ti + carry
c[i] = ci
carry = (ai&ti | (ai|ti)&^ci) >> 63
}
gfpCarry(c, carry)
}
// mul returns the multiplication of a*b. a,b are no restrictions.
func mul(a, b [4]uint64) [8]uint64 {
const (
mask16 uint64 = 0x0000ffff
mask32 uint64 = 0xffffffff
)
// Let B = 2^16, then
// buff = buff[0] + buff[1]*B + ... + buff[31]*B^31
var buff [32]uint64
for i, ai := range a {
a0, a1, a2, a3 := ai&mask16, (ai>>16)&mask16, (ai>>32)&mask16, ai>>48
for j, bj := range b {
// compute ai * bj and save to buff[4*(i+j):]
// (a0 + a1*B + a2*B^2 + a3*B^3) * (b0 + b2*B^2)
// = a0*b0 + a1*b0*B + (a2*b0 + a0*b2)*B^2 + (a1*b2 + a3*b0)*B^3 + a2*b2*B^4 + a3*b2*B^5
b0, b2 := bj&mask32, bj>>32
off := 4 * (i + j)
buff[off+0] += a0 * b0
buff[off+1] += a1 * b0
buff[off+2] += a2*b0 + a0*b2
buff[off+3] += a3*b0 + a1*b2
buff[off+4] += a2 * b2
buff[off+5] += a3 * b2
}
}
// buff:
// 0 1 2 3 | 4 5 6 7 | 8 9 10 11 | 12 13 14 15
// 外循环对将1,2,3加到0上
// 内循环处理0,4,8,12...
for i := uint(1); i < 4; i++ {
shift := 16 * i
var head, carry uint64
for j := uint(0); j < 8; j++ {
block := 4 * j
xi := buff[block]
yi := (buff[block+i] << shift) + head
zi := xi + yi + carry
buff[block] = zi
carry = (xi&yi | (xi|yi)&^zi) >> 63
head = buff[block+i] >> (64 - shift)
}
}
return [8]uint64{buff[0], buff[4], buff[8], buff[12], buff[16], buff[20], buff[24], buff[28]}
}
// halfMul returns a*b mod R, where R = 2^256.
func halfMul(a, b [4]uint64) [4]uint64 {
const (
mask16 uint64 = 0x0000ffff
mask32 uint64 = 0xffffffff
)
var buff [18]uint64
for i, ai := range a {
a0, a1, a2, a3 := ai&mask16, (ai>>16)&mask16, (ai>>32)&mask16, ai>>48
for j, bj := range b {
if i+j > 3 {
break
}
b0, b2 := bj&mask32, bj>>32
off := 4 * (i + j)
buff[off+0] += a0 * b0
buff[off+1] += a1 * b0
buff[off+2] += a2*b0 + a0*b2
buff[off+3] += a3*b0 + a1*b2
buff[off+4] += a2 * b2
buff[off+5] += a3 * b2
}
}
for i := uint(1); i < 4; i++ {
shift := 16 * i
var head, carry uint64
for j := uint(0); j < 4; j++ {
block := 4 * j
xi := buff[block]
yi := (buff[block+i] << shift) + head
zi := xi + yi + carry
buff[block] = zi
carry = (xi&yi | (xi|yi)&^zi) >> 63
head = buff[block+i] >> (64 - shift)
}
}
return [4]uint64{buff[0], buff[4], buff[8], buff[12]}
}
// gfpMul implements the Montgomery multiplication of a*b, i.e.,
// c = a*b*R^{-1} mod p
//
// Let T = a*b = T_h*R + T_l, then
//
// a*b = T_h*R + T_l
// = T_h*R + T_l + (T_l*np mod R)*P mod P
// (For np*P = -1 mod R, so T_l + (T_l*np mod R)*P = 0 mod R.)
// = higher parts of T + (T_l*np mod R)*P
func gfpMul(c, a, b *gfP) {
T := mul(*a, *b)
m := halfMul([4]uint64{T[0], T[1], T[2], T[3]}, np) // m = T_l *np mod R
t := mul([4]uint64{m[0], m[1], m[2], m[3]}, p2) // t = (T_l*np mod R)*P
// (T, carry) = a*b and (c, carry) = a*b/R
// T[0:4] must be 0.
var carry uint64
for i, Ti := range T {
ti := t[i]
zi := Ti + ti + carry
T[i] = zi
carry = (Ti&ti | (Ti|ti)&^zi) >> 63
}
*c = gfP{T[4], T[5], T[6], T[7]}
// TODO: can c >= p?
gfpCarry(c, carry)
}
+618
View File
@@ -0,0 +1,618 @@
package bn256
import (
"crypto/rand"
"fmt"
"io"
"math/big"
"testing"
"time"
"xdx.jelly/xgcl/gmath"
)
var twoTo256 = new(big.Int).Lsh(big.NewInt(1), 256)
func gfPFromBigInt(A *big.Int) *gfP {
a := &gfP{}
buf := make([]byte, 32)
A.FillBytes(buf)
a.Unmarshal(buf)
montEncode(a, a)
return a
}
func randomInt(r io.Reader, max *big.Int) *big.Int {
a, _ := rand.Int(r, max)
return a
}
func (e *gfP) random(r io.Reader) *gfP {
e.Set(gfPFromBigInt(randomInt(r, P)))
return e
}
func (e *gfP2) random(r io.Reader) *gfP2 {
e.x.random(r)
e.y.random(r)
return e
}
func (f *gfP6) random(r io.Reader) *gfP6 {
f.x.random(r)
f.z.random(r)
f.y.random(r)
return f
}
func (f *gfP12) random(r io.Reader) *gfP12 {
f.x.random(r)
f.y.random(r)
return f
}
func testOp(t *testing.T, arg1, arg2 *big.Int, op1 func(*big.Int, *big.Int, *big.Int), op2 func(*gfP, *gfP, *gfP), equal func(*gfP, *gfP) bool) {
var a, b *gfP
a = gfPFromBigInt(arg1)
if arg2 != nil {
b = gfPFromBigInt(arg2)
}
C := new(big.Int)
op1(C, arg1, arg2)
c1 := gfPFromBigInt(C)
c2 := &gfP{}
op2(c2, a, b)
if !equal(c1, c2) {
fmt.Println("failed:")
fmt.Println("\ta =", a)
fmt.Println("\tb =", b)
fmt.Println("\tc1 =", c1)
fmt.Println("\tc2 =", c2)
t.Fatal()
}
}
func TestGFpSqrt(t *testing.T) {
for i := 0; i < 100000; i++ {
a := randomInt(rand.Reader, twoTo256)
a.Mul(a, a).Mod(a, N)
testOp(t,
big.NewInt(1),
nil,
func(c *big.Int, a *big.Int, b *big.Int) {
c.ModSqrt(a, P)
},
func(c *gfP, a *gfP, b *gfP) {
c.Sqrt(a)
},
func(a *gfP, b *gfP) bool {
c := &gfP{}
gfpAdd(c, a, b)
return *a == *b || *c == gfP{}
},
)
}
}
func TestGFpNeg(t *testing.T) {
a := &gfP{0xe56f9b27e351457c, 0x21f2934b1a7aeedb, 0xd603ab4ff58ec745, 0xb640000002a3a6f1}
gfpNeg(a, a)
if *a != (gfP{1, 0, 0, 0}) {
t.Fatal()
}
for i := 0; i < 1000000; i++ {
a := randomInt(rand.Reader, P)
a.Mul(a, a).Mod(a, N)
testOp(t,
randomInt(rand.Reader, P),
nil,
func(c *big.Int, a *big.Int, b *big.Int) {
c.Neg(a).Mod(c, P)
},
func(c *gfP, a *gfP, b *gfP) {
gfpNeg(c, a)
},
func(a *gfP, b *gfP) bool {
return *a == *b
},
)
}
}
func TestGFpAdd(t *testing.T) {
for i := 0; i < 1000000; i++ {
testOp(t,
randomInt(rand.Reader, twoTo256),
randomInt(rand.Reader, twoTo256),
func(c *big.Int, a *big.Int, b *big.Int) {
c.Add(a, b).Mod(c, P)
},
func(c *gfP, a *gfP, b *gfP) {
gfpAdd(c, a, b)
},
func(a *gfP, b *gfP) bool {
return *a == *b
},
)
}
}
func TestGFpSub(t *testing.T) {
for i := 0; i < 1000000; i++ {
a := randomInt(rand.Reader, twoTo256)
b := randomInt(rand.Reader, twoTo256)
testOp(t,
a,
b.Sub(a, big.NewInt(1)),
func(c *big.Int, a *big.Int, b *big.Int) {
c.Sub(a, b).Mod(c, P)
},
func(c *gfP, a *gfP, b *gfP) {
gfpSub(c, a, b)
},
func(a *gfP, b *gfP) bool {
return *a == *b
},
)
}
}
func TestGFpHalf(t *testing.T) {
for i := 0; i < 100000; i++ {
testOp(t,
randomInt(rand.Reader, P),
nil,
func(c *big.Int, a *big.Int, b *big.Int) {
c.Set(a)
if c.Bit(0) == 1 {
c.Add(a, P)
}
c.Rsh(c, 1)
},
func(c *gfP, a *gfP, b *gfP) {
c.half(a)
},
func(a *gfP, b *gfP) bool {
return *a == *b
},
)
}
}
// FIXME: amd64平台不支持 a and b > p
func TestGFpMul(t *testing.T) {
for i := 0; i < 100000; i++ {
testOp(t,
randomInt(rand.Reader, P),
randomInt(rand.Reader, P),
func(c *big.Int, a *big.Int, b *big.Int) {
c.Mul(a, b).Mod(c, P)
},
func(c *gfP, a *gfP, b *gfP) {
gfpMul(c, a, b)
},
func(a *gfP, b *gfP) bool {
return *a == *b
},
)
testOp(t,
randomInt(rand.Reader, twoTo256),
randomInt(rand.Reader, twoTo256),
func(c *big.Int, a *big.Int, b *big.Int) {
c.Mul(a, b).Mod(c, P)
},
func(c *gfP, a *gfP, b *gfP) {
gfpMul(c, a, b)
},
func(a *gfP, b *gfP) bool {
return *a == *b
},
)
testOp(t,
new(big.Int).Sub(twoTo256, big.NewInt(int64(i+1))),
new(big.Int).Sub(twoTo256, big.NewInt(int64(i+2))),
func(c *big.Int, a *big.Int, b *big.Int) {
c.Mul(a, b).Mod(c, P)
},
func(c *gfP, a *gfP, b *gfP) {
gfpMul(c, a, b)
},
func(a *gfP, b *gfP) bool {
return *a == *b
},
)
}
}
func TestSpeedGFp(t *testing.T) {
a := newGFp(123)
b := newGFp(123)
c := newGFp(1)
buf := make([]byte, 32)
a.Marshal(buf)
A := new(big.Int).SetBytes(buf)
b.Marshal(buf)
B := new(big.Int).SetBytes(buf)
c.Marshal(buf)
C := new(big.Int).SetBytes(buf)
// fmt.Println(a, b, c)
begin := time.Now()
total := 10000000
for i := 0; i < total; i++ {
gfpMul(c, a, b)
}
elaspe := time.Since(begin)
fmt.Println("time: ", elaspe.Milliseconds(), "ms")
fmt.Println(int(float64(total) / float64(elaspe.Milliseconds()) * 1000))
begin = time.Now()
for i := 0; i < total; i++ {
C.Mul(A, B)
}
elaspe = time.Since(begin)
fmt.Println("time: ", elaspe.Milliseconds(), "ms")
fmt.Println(int(float64(total) / float64(elaspe.Milliseconds()) * 1000))
}
func (e *gfP2) Exp(a *gfP2, power *big.Int) *gfP2 {
sum := (&gfP2{}).SetOne()
t := &gfP2{}
for i := power.BitLen() - 1; i >= 0; i-- {
t.Square(sum)
if power.Bit(i) != 0 {
sum.Mul(t, a)
} else {
sum.Set(t)
}
}
e.Set(sum)
return e
}
// Exp set c = a^power and return c
func (f *gfP6) Exp(a *gfP6, power *big.Int) *gfP6 {
sum := (&gfP6{}).SetOne()
t := &gfP6{}
for i := power.BitLen() - 1; i >= 0; i-- {
t.Square(sum)
if power.Bit(i) != 0 {
sum.Mul(t, a)
} else {
sum.Set(t)
}
}
f.Set(sum)
return f
}
func TestGFp(t *testing.T) {
one := newGFp(1)
//one := &gfP{1}
//two := &gfP{2}
gfpMul(one, r2, one)
gfpMul(one, &gfP{1}, one)
montDecode(one, one)
if *one != (gfP{1}) {
t.Fail()
fmt.Println(one)
return
}
// a := (&gfP{}).random(rand.Reader)
a := &gfP{0x0a1c7970e5df544d, 0xe74504e9a96b56cc, 0xcda02d92d4d62924, 0x7d2bc576fdf597d1}
b := &gfP{}
c := &gfP{}
fmt.Println("Test Exponent")
b.exp(a, pMinus1)
//b.exp(a,[4]uint64{2,0,0,0})
//fmt.Println("a:", b)
//gfpMul(c,a,a)
//fmt.Println("c:",c)
//gfpSub(b,c,b)
// montDecode(b, b)
if *b != *newGFp(1) {
t.Fail()
fmt.Println(b)
return
}
fmt.Println("pass")
var rN1 = &gfP{0x0a1c7970e5df544d, 0xe74504e9a96b56cc, 0xcda02d92d4d62924, 0x7d2bc576fdf597d1}
fmt.Println("Test Rn")
gfpMul(b, rN1, r3)
montDecode(b, b)
if *b != (gfP{1}) {
t.Fail()
fmt.Println(b)
return
}
fmt.Println("pass")
fmt.Println("Test Invert")
a = newGFp(1)
c.Invert(a)
fmt.Println(a, c)
gfpMul(c, c, a)
montDecode(c, c)
if *c != (gfP{1}) {
t.Fail()
fmt.Println(c)
return
}
fmt.Println("pass")
}
func TestGfP2(t *testing.T) {
p2Minus1 := new(big.Int)
p2Minus1.Mul(P, P)
p2Minus1.Sub(p2Minus1, gmath.BigInt1)
a := (&gfP2{}).random(rand.Reader)
b := &gfP2{}
c := &gfP2{}
fmt.Println("Test gfP2 mul and square")
fmt.Println("a: ", a)
b.Mul(a, a)
fmt.Println("a^2:", b)
c.Square(a)
fmt.Println("a*a:", c)
if !c.Sub(c, b).IsZero() {
t.Fail()
fmt.Println(c)
return
}
fmt.Println("pass")
fmt.Println("Test exponential")
c.Exp(a, p2Minus1)
if !c.IsOne() {
t.Fail()
fmt.Println(c)
return
}
fmt.Println("pass")
fmt.Println("Test Invert")
c.Invert(a)
c.Mul(c, a)
if !c.IsOne() {
t.Fail()
fmt.Println(c)
return
}
fmt.Println("pass")
}
func TestGFp2Sqrt(t *testing.T) {
for i := 0; i < 100000; i++ {
a := (&gfP2{}).random(rand.Reader)
a.Mul(a, a)
b := *a
if !a.Sqrt(a) {
t.Fatal()
}
a.Square(a)
if *a != b {
t.Fatal()
}
c := &gfP2{}
if !c.Sqrt(a) {
t.Fatal()
}
a.Square(c)
if *a != b {
t.Fatal()
}
}
}
func TestGfP6(t *testing.T) {
p6Minus1 := new(big.Int)
p6Minus1.Exp(P, gmath.BigInt6, nil)
p6Minus1.Sub(p6Minus1, gmath.BigInt1)
a := (&gfP6{}).random(rand.Reader)
b := &gfP6{}
c := &gfP6{}
fmt.Println(a)
fmt.Println("Test gfP6 mul and square")
fmt.Println("a: ", a)
b.Mul(a, a)
fmt.Println("a^2:", b)
c.Square(a)
fmt.Println("a*a:", c)
if !c.Sub(c, b).IsZero() {
t.Fail()
fmt.Println(c)
return
}
fmt.Println("Test exponential")
c.Exp(a, p6Minus1)
//c.Exp(a,gmath.BigInt1)
if !c.IsOne() {
t.Fail()
fmt.Println(c)
return
}
fmt.Println("pass")
fmt.Println("Test Invert")
c.Invert(a)
c.Mul(c, a)
if !c.IsOne() {
t.Fail()
fmt.Println(c)
return
}
fmt.Println("pass")
}
func TestGfP12(t *testing.T) {
p12Minus1 := new(big.Int)
p12Minus1.Exp(P, gmath.BigInt12, nil)
p12Minus1.Sub(p12Minus1, gmath.BigInt1)
a := (&gfP12{}).random(rand.Reader)
b := &gfP12{}
c := &gfP12{}
fmt.Println(a)
fmt.Println("Test gfP12 mul and square")
fmt.Println("a: ", a)
b.Mul(a, a)
fmt.Println("a^2:", b)
c.Square(a)
fmt.Println("a*a:", c)
if !c.Sub(c, b).IsZero() {
t.Fail()
fmt.Println(c)
return
}
fmt.Println("Test exponential")
c.Exp(a, p12Minus1)
//c.Exp(a,gmath.BigInt1)
if !c.IsOne() {
t.Fail()
fmt.Println(c)
return
}
fmt.Println("pass")
fmt.Println("Test Invert")
c.Invert(a)
c.Mul(c, a)
if !c.IsOne() {
t.Fail()
fmt.Println(c)
return
}
fmt.Println("pass")
}
func TestFrobenius6(t *testing.T) {
p2 := new(big.Int).Mul(P, P)
a := (&gfP6{}).random(rand.Reader)
b := &gfP6{}
c := &gfP6{}
b.Frobenius(a)
c.Exp(a, P)
if *b != *c {
fmt.Println("a:", a)
fmt.Println("b:", b)
fmt.Println("c:", c)
t.Fatal()
}
b.FrobeniusP2(a)
c.Exp(a, p2)
if *b != *c {
t.Fatal()
}
}
func TestFrobenius12(t *testing.T) {
p2 := new(big.Int).Mul(P, P)
a := (&gfP12{}).random(rand.Reader)
b := &gfP12{}
c := &gfP12{}
fmt.Println("Test Frobenius on GFP12")
b.Frobenius(a)
c.Exp(a, P)
if *b != *c {
fmt.Println("a:", a)
fmt.Println("b:", b)
fmt.Println("c:", c)
t.Fail()
return
}
fmt.Println("pass")
fmt.Println("Test Frobenius2 on GFP12")
b.FrobeniusP2(a)
c.Exp(a, p2)
if *b != *c {
t.Fail()
return
}
fmt.Println("pass")
}
func present(p *gfP) string {
return fmt.Sprintf("gfP{0x%x,0x%x,0x%x,0x%x}", p[0], p[1], p[2], p[3])
}
// ExampleGFP12Gen generate gfP12Gen
func TestGFP12Gen(t *testing.T) {
e := Pair(&G1{*curveGen}, &G2{*twistGen}).p
fmt.Printf(`
var gfP12Gen *gfP12 = &gfP12{
x: gfP6{
x: gfP2{
x: %s,
y: %s,
},
y: gfP2{
x: %s,
y: %s,
},
z: gfP2{
x: %s,
y: %s,
},
},
y: gfP6{
x: gfP2{
x: %s,
y: %s,
},
y: gfP2{
x: %s,
y: %s,
},
z: gfP2{
x: %s,
y: %s,
},
},
}
`, present(&e.x.x.x),
present(&e.x.x.y),
present(&e.x.y.x),
present(&e.x.y.y),
present(&e.x.z.x),
present(&e.x.z.y),
present(&e.y.x.x),
present(&e.y.x.y),
present(&e.y.y.x),
present(&e.y.y.y),
present(&e.y.z.x),
present(&e.y.z.y))
}
+128
View File
@@ -0,0 +1,128 @@
package bn256
import (
"math/big"
)
// useLattice switch if we use lattice and GLV to accelerate computing.
// In product version, it could be a const.
// const useLattice = true
var useLattice = true
var half = new(big.Int).Rsh(N, 1)
var curveLattice = &lattice{
vectors: [][]*big.Int{
{bigFromBase10("287113247090025866066532163502283840641"), bigFromBase10("13835058055293825813")},
{bigFromBase10("13835058055293825813"), bigFromBase10("-287113247090025866052697105446990014828")},
},
inverse: []*big.Int{
bigFromBase10("287113247090025866052697105446990014828"),
bigFromBase10("13835058055293825813"),
},
det: bigFromBase16("B640000002A3A6F1D603AB4FF58EC74449F2934B18EA8BEEE56EE19CD69ECF25"),
}
var targetLattice = &lattice{
vectors: [][]*big.Int{
{bigFromBase10("6917529027646912907"), bigFromBase10("6917529027646912906"), bigFromBase10("6917529027646912906"), bigFromBase10("-13835058055293825812")},
{bigFromBase10("13835058055293825813"), bigFromBase10("-6917529027646912906"), bigFromBase10("-6917529027646912907"), bigFromBase10("-6917529027646912906")},
{bigFromBase10("13835058055293825812"), bigFromBase10("13835058055293825813"), bigFromBase10("13835058055293825813"), bigFromBase10("13835058055293825813")},
{bigFromBase10("6917529027646912905"), bigFromBase10("27670116110587651626"), bigFromBase10("-13835058055293825811"), bigFromBase10("6917529027646912905")},
},
inverse: []*big.Int{
bigFromBase10("95704415696675288700373269546839468391"),
bigFromBase10("3972228441934428951444310461776851119314861197558173512586"),
bigFromBase10("1986114220967214475722155230888425559660889363292910212746"),
bigFromBase10("-95704415696675288686538211491545642578"),
},
det: new(big.Int).Set(N),
}
type lattice struct {
vectors [][]*big.Int
inverse []*big.Int
det *big.Int
}
// decompose takes a scalar mod Order as input and finds a short, positive decomposition of it wrt to the lattice basis.
// output: out[0] + lambda*out[1] = 0 mod n
// [lambda](x,y) = (eta*x, y), eta^3 = 1
// TODO out[0] and out[1] should > 0 or ?
func (l *lattice) decompose(k *big.Int) []*big.Int {
n := len(l.inverse)
// Calculate closest vector in lattice to <k,0,0,...> with Babai's rounding.
c := make([]*big.Int, n)
for i := 0; i < n; i++ {
c[i] = new(big.Int).Mul(k, l.inverse[i])
round(c[i], l.det)
}
// Transform vectors according to c and subtract <k,0,0,...>.
out := make([]*big.Int, n)
temp := new(big.Int)
for i := 0; i < n; i++ {
out[i] = new(big.Int)
for j := 0; j < n; j++ {
temp.Mul(c[j], l.vectors[j][i])
out[i].Add(out[i], temp)
}
out[i].Neg(out[i])
//TODO why add
out[i].Add(out[i], l.vectors[0][i]).Add(out[i], l.vectors[0][i])
}
out[0].Add(out[0], k)
return out
}
func (l *lattice) Precompute(add func(i, j uint)) {
n := uint(len(l.vectors))
total := uint(1) << uint(n)
for i := uint(0); i < n; i++ {
for j := uint(0); j < total; j++ {
if (j>>i)&1 == 1 {
add(i, j)
}
}
}
}
func (l *lattice) Multi(scalar *big.Int) []uint8 {
decomp := l.decompose(scalar)
maxLen := 0
for _, x := range decomp {
if x.BitLen() > maxLen {
maxLen = x.BitLen()
}
}
out := make([]uint8, maxLen)
for j, x := range decomp {
for i := 0; i < maxLen; i++ {
//out[i] += uint8(x.Bit(i)) << uint(j)
out[i] += uint8(x.Abs(x).Bit(i)) << uint(j)
}
}
return out
}
// round sets num to num/denom rounded to the nearest integer.
func round(num, denom *big.Int) {
r := new(big.Int)
num.DivMod(num, denom, r)
if r.Cmp(half) == 1 {
num.Add(num, big.NewInt(1))
}
}
+215
View File
@@ -0,0 +1,215 @@
package bn256
import (
"crypto/rand"
"fmt"
"testing"
"time"
)
func TestLatticeReduceCurve(t *testing.T) {
for {
k, _ := rand.Int(rand.Reader, N)
//for i:=255;i>100;i-- {
// k.SetBit(k, i, 0)
//}
ks := curveLattice.decompose(k)
fmt.Println("============================================")
fmt.Println("k = ", k.Text(16), k.BitLen(), k.Sign())
fmt.Println("k1 = ", ks[0].Text(16), ks[0].BitLen(), ks[0].Sign())
fmt.Println("k2 = ", ks[1].Text(16), ks[1].BitLen(), ks[1].Sign())
if ks[0].BitLen() > 130 || ks[1].BitLen() > 130 {
t.Fatal("reduction too large")
} else if ks[0].Sign() < 0 || ks[1].Sign() < 0 {
t.Fatal("reduction must be positive")
}
}
}
func TestLatticeReduceTarget(t *testing.T) {
k, _ := rand.Int(rand.Reader, N)
ks := targetLattice.decompose(k)
if ks[0].BitLen() > 66 || ks[1].BitLen() > 66 || ks[2].BitLen() > 66 || ks[3].BitLen() > 66 {
t.Fatal("reduction too large")
} else if ks[0].Sign() < 0 || ks[1].Sign() < 0 || ks[2].Sign() < 0 || ks[3].Sign() < 0 {
t.Fatal("reduction must be positive")
}
}
func TestLatticeCurveMul(t *testing.T) {
useLattice = false
pt := &curvePoint{}
t.Log("G =", curveGen)
l2 := bigFromBase10("82434016654578246432914077779442682275270229881604616279947255993657999048255")
l := bigFromBase10("11916685325803286854045818138240527491926474132365765087461")
pt.Mul(curveGen, l)
t.Log("[l]G=", pt)
pt.Add(curveGen, pt)
t.Log("[l+1]G=", pt)
pt.Neg(pt)
t.Log("-[l+1]G=", pt)
pt.Mul(curveGen, l2)
t.Log("[l2]G=", pt)
pt.Set(curveGen)
gfpMul(&pt.x, &curveGen.x, xiTo2PMinus2Over3)
t.Log("phiG=", pt)
t.Log("phi(G) is on curve:", pt.IsOnCurve())
}
func TestLatticeTwistCurveMul(t *testing.T) {
useLattice = false
pt := &twistPoint{}
t.Log("G =", twistGen)
l2 := bigFromBase10("82434016654578246432914077779442682275270229881604616279947255993657999048255")
l := bigFromBase10("11916685325803286854045818138240527491926474132365765087461")
pt.Mul(twistGen, l)
t.Log("[l]G=", pt)
pt.Add(twistGen, pt)
t.Log("[l+1]G=", pt)
pt.Neg(pt)
t.Log("-[l+1]G=", pt)
pt.Mul(twistGen, l2)
t.Log("[l2]G=", pt)
pt.Set(twistGen)
//gfpMul(&pt.x, &twistGen.x, xiTo2PMinus2Over3)
pt.x.MulScalar(&pt.x, xiTo2PSquaredMinus2Over3)
t.Log("phiG=", pt)
t.Log("phi(G) is on curve:", pt.IsOnCurve())
}
func TestTemp(t *testing.T) {
useLattice = true
l := bigFromBase10("11916685325803286854045818138240527491926474132365765087461")
// a := bigFromBase10("18601171214415468628822298024872005604767796808132779597987639723831549415194")
a := bigFromBase10("186011712144154686288222980248720056047677968081327795979876397238315495")
//a = new(big.Int).Sub(Order,gmath.BigInt2)
//multiScalar := curveLattice.Multi(a)
decomp := curveLattice.decompose(a)
fmt.Println(decomp)
s := decomp[1]
s.Mul(s, l)
s.Add(s, decomp[0])
s.Mod(s, N)
fmt.Println(s)
fmt.Println(a)
pt1 := &curvePoint{}
pt1.Mul(curveGen, a)
fmt.Println(pt1)
useLattice = false
pt2 := &curvePoint{}
pt2.Mul(curveGen, a)
fmt.Println(pt2)
}
func TestTemp1(t *testing.T) {
count := 0
for {
a, _ := rand.Int(rand.Reader, N)
useLattice = true
pt1 := &curvePoint{}
pt1.Mul(curveGen, a)
useLattice = false
pt2 := &curvePoint{}
pt2.Mul(curveGen, a)
pt1.MakeAffine()
pt2.MakeAffine()
if *pt1 != *pt2 {
fmt.Println(pt1)
fmt.Println(pt2)
t.Fail()
return
}
count++
if count%10000 == 0 {
fmt.Println(count, "pass")
}
}
}
func TestGfP12Lattice(t *testing.T) {
k, _ := rand.Int(rand.Reader, N)
e := &gfP12{}
f := &gfP12{}
e.Exp(gfP12Gen, k)
f.latticeExp(gfP12Gen, k)
if *e != *f {
t.Log(e)
t.Log(f)
t.Fatalf("bad lattice exponitial:")
}
}
func TestGfP12LatticePairint(t *testing.T) {
useLattice = true
fmt.Println("Test bilinear")
k1, p1, _ := RandomG1(rand.Reader)
k2, p2, _ := RandomG2(rand.Reader)
e1 := Pair(p1, p2)
e2 := &GT{*gfP12Gen}
e2.ScalarBaseMult(k1)
e2.ScalarMult(e2, k2)
if e1.p != e2.p {
t.Log(e1)
t.Log(e2)
t.Fatalf("bad pairing result:")
}
}
func BenchmarkLatticeGFP12(b *testing.B) {
k, _ := rand.Int(rand.Reader, N)
e := &gfP12{}
b.ResetTimer()
for i := 0; i < b.N; i++ {
e.latticeExp(gfP12Gen, k)
}
}
func BenchmarkNormalLatticeGFP12(b *testing.B) {
k, _ := rand.Int(rand.Reader, N)
e := &gfP12{}
b.ResetTimer()
for i := 0; i < b.N; i++ {
e.Exp(gfP12Gen, k)
}
}
func TestGfP12LatticeSpeed(t *testing.T) {
k, _ := rand.Int(rand.Reader, N)
e := &gfP12{}
f := &gfP12{}
total := 1000
{
//800
begin := time.Now()
for i := 0; i < total; i++ {
e.Exp(gfP12Gen, k)
}
elaspe := time.Since(begin)
fmt.Println("time: ", elaspe.Milliseconds(), "ms")
fmt.Println(float64(total) / float64(elaspe.Milliseconds()) * 1000)
}
{
// 1600 次/秒
begin := time.Now()
for i := 0; i < total; i++ {
f.latticeExp(gfP12Gen, k)
}
elaspe := time.Since(begin)
fmt.Println("time: ", elaspe.Milliseconds(), "ms")
fmt.Println(float64(total) / float64(elaspe.Milliseconds()) * 1000)
}
}
+181
View File
@@ -0,0 +1,181 @@
#define mul(a0,a1,a2,a3, rb, stack) \
/* a0*rb -> stack[0:64] */\
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)
+202
View File
@@ -0,0 +1,202 @@
/*
mul computes [R4*R1] * [R8:R5] = [c7:c0]
use registers R0, R26, R27, R29.
when return, R1 is changed.
(*R1)
R8 R7 R6 R5
x R1
----------------------------
c1 c0
+ c2 R0
----------------------------
c2 c1 c0
+ c3 R0
----------------------------
c3 c2 c1 c0
+ c4 R0
----------------------------
c4 c3 c2 c1 c0
(*R2)
R8 R7 R6 R5
x R2
----------------------------
R26 R1
R27 R0
R29 R0
c5 R0
+ c4 c3 c2 c1 c0
----------------------------
c5 c4 c3 c2 c1 c0
(*R3)
R8 R7 R6 R5
x R3
----------------------------
R26 R1
R27 R0
R29 R0
c6 R0
c5 c4 c3 c2 c1 c0
----------------------------
c6 c5 c4 c3 c2 c1 c0
(*R4)
R8 R7 R6 R5
x R4
----------------------------
R26 R1
R27 R0
R29 R0
c7 R0
c6 c5 c4 c3 c2 c1 c0
----------------------------
c7 c6 c5 c4 c3 c2 c1 c0
*/
#define mul(c0,c1,c2,c3,c4,c5,c6,c7) \
MUL R1, R5, c0 /* save the 0-63 bits of R1*R5 to c0 */\
UMULH R1, R5, c1 /* save the 64-129 bits of R1*R5 to c1 */\
MUL R1, R6, R0 \
ADDS R0, c1 \
UMULH R1, R6, c2 \
MUL R1, R7, R0 \
ADCS R0, c2 /* also add the carry of R0+c1 */\
UMULH R1, R7, c3 \
MUL R1, R8, R0 \
ADCS R0, c3 \
UMULH R1, R8, c4 \
ADCS ZR, c4 \
/* [c4:c0] = R1 * [R8:R5] */\
MUL R2, R5, R1 \
UMULH R2, R5, R26 \
MUL R2, R6, R0 \
ADDS R0, R26 \
UMULH R2, R6, R27 \
MUL R2, R7, R0 \
ADCS R0, R27 \
UMULH R2, R7, R29 \
MUL R2, R8, R0 \
ADCS R0, R29 \
UMULH R2, R8, c5 \
ADCS ZR, c5 \
ADDS R1, c1 \
ADCS R26, c2 \
ADCS R27, c3 \
ADCS R29, c4 \
ADCS ZR, c5 \
\
MUL R3, R5, R1 \
UMULH R3, R5, R26 \
MUL R3, R6, R0 \
ADDS R0, R26 \
UMULH R3, R6, R27 \
MUL R3, R7, R0 \
ADCS R0, R27 \
UMULH R3, R7, R29 \
MUL R3, R8, R0 \
ADCS R0, R29 \
UMULH R3, R8, c6 \
ADCS ZR, c6 \
ADDS R1, c2 \
ADCS R26, c3 \
ADCS R27, c4 \
ADCS R29, c5 \
ADCS ZR, c6 \
\
MUL R4, R5, R1 \
UMULH R4, R5, R26 \
MUL R4, R6, R0 \
ADDS R0, R26 \
UMULH R4, R6, R27 \
MUL R4, R7, R0 \
ADCS R0, R27 \
UMULH R4, R7, R29 \
MUL R4, R8, R0 \
ADCS R0, R29 \
UMULH R4, R8, c7 \
ADCS ZR, c7 \
ADDS R1, c3 \
ADCS R26, c4 \
ADCS R27, c5 \
ADCS R29, c6 \
ADCS ZR, c7
// gfpReduce computes
// [R4:R1] = [R16:R9] * R^{-1} mod p
// = [R16:R13] + [The higher half of ([R12:R9] * np mod R) * P]
#define gfpReduce() \
/* m = (T * N') mod R, store m in R1:R2:R3:R4, np * [R1:R4] mod R => [R1:R4] */ \
MOVD ·np+0(SB), R17 \
MOVD ·np+8(SB), R25 \
MOVD ·np+16(SB), R19 \
MOVD ·np+24(SB), R20 \
\
/*[R4:R1] <- [R20,R19,R24,R17] * R9 mod R */\
MUL R9, R17, R1 \
UMULH R9, R17, R2 \
MUL R9, R25, R0 \
ADDS R0, R2 \
UMULH R9, R25, R3 \
MUL R9, R19, R0 \
ADCS R0, R3 \
UMULH R9, R19, R4 \
MUL R9, R20, R0 \
ADCS R0, R4 \
\
/*[R23,R22,R21,0] <- [R20,R19,R24,R17] * R10 mod R */\
/* [R4:R1] <- [R4:R1] + [R23,R22,R21,0] mod R */\
MUL R10, R17, R21 \
UMULH R10, R17, R22 \
MUL R10, R25, R0 \
ADDS R0, R22 \
UMULH R10, R25, R23 \
MUL R10, R19, R0 \
ADCS R0, R23 \
ADDS R21, R2 \
ADCS R22, R3 \
ADCS R23, R4 \
\
/*[R22,R21,0,0] <- [R20,R19,R24,R17] * R11 mod R */\
/* [R4:R1] <- [R4:R1] + [R22,R21,0,0] mod R */\
MUL R11, R17, R21 \
UMULH R11, R17, R22 \
MUL R11, R25, R0 \
ADDS R0, R22 \
ADDS R21, R3 \
ADCS R22, R4 \
\
MUL R12, R17, R21 \
ADDS R21, R4 \
\
/* now [R4:R1] = [R12:R9] * np mod R*/ \
loadModulus(R5, R6, R7, R8) \
/* multiply with P */\
mul(R17, R25, R19, R20, R21, R22, R23, R24) \
\
/* Add the 512-bit intermediate to m*N */ \
/* Although R17,R25,R19,R20 must be 0 after the addtion, */\
/* But we can't omit the lower have addtion. For we not sure if there have a carry. */\
MOVD ZR , R0 \
ADDS R9 , R17 /* R17=0 */\
ADCS R10, R25 /* R25=0 */\
ADCS R11, R19 /* R19=0 */\
ADCS R12, R20 /* R20=0 */\
ADCS R13, R21 /* If one of R9,... R20 are non-zero, then there have a carry. */\
ADCS R14, R22 \
ADCS R15, R23 \
ADCS R16, R24 \
ADCS ZR , R0 \
\
/* Our output is [R0,R24,R23,R22,R21]. Reduce mod p if necessary.*/ \
SUBS R5, R21, R10 \
SBCS R6, R22, R11 \
SBCS R7, R23, R12 \
SBCS R8, R24, R13 \
SBCS $0, R0, R0\
\
CSEL CS, R10, R21, R1 \
CSEL CS, R11, R22, R2 \
CSEL CS, R12, R23, R3 \
CSEL CS, R13, R24, R4
+111
View File
@@ -0,0 +1,111 @@
#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() \
\
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)) \
\
\
mulBMI2(·p2+0(SB),·p2+8(SB),·p2+16(SB),·p2+24(SB), 64(SP)) \
\
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)
+289
View File
@@ -0,0 +1,289 @@
package bn256
func lineFunctionAdd(a, b, c *gfP2, rOut *twistPoint, r, p *twistPoint, q *curvePoint, r2 *gfP2) {
// See the mixed addition algorithm from "Faster Computation of the
// Tate Pairing", http://arxiv.org/pdf/0904.0854v3.pdf
B := (&gfP2{}).Mul(&p.x, &r.t)
D := (&gfP2{}).Add(&p.y, &r.z)
D.Square(D).Sub(D, r2).Sub(D, &r.t).Mul(D, &r.t)
H := (&gfP2{}).Sub(B, &r.x)
I := (&gfP2{}).Square(H)
E := (&gfP2{}).Add(I, I)
E.Add(E, E)
J := (&gfP2{}).Mul(H, E)
L1 := (&gfP2{}).Sub(D, &r.y)
L1.Sub(L1, &r.y)
V := (&gfP2{}).Mul(&r.x, E)
// rOut = &twistPoint{}
t, t2 := &gfP2{}, &gfP2{}
rOut.x.Square(L1).Sub(&rOut.x, J).Sub(&rOut.x, V).Sub(&rOut.x, V)
rOut.z.Add(&r.z, H).Square(&rOut.z).Sub(&rOut.z, &r.t).Sub(&rOut.z, I)
t.Sub(V, &rOut.x).Mul(t, L1)
t2.Mul(&r.y, J).Add(t2, t2)
rOut.y.Sub(t, t2)
rOut.t.Square(&rOut.z)
t.Add(&p.y, &rOut.z).Square(t).Sub(t, r2).Sub(t, &rOut.t)
t2.Mul(L1, &p.x).Add(t2, t2)
a.Sub(t2, t)
c.MulScalar(&rOut.z, &q.y)
c.Add(c, c)
b.Neg(L1)
b.MulScalar(b, &q.x).Add(b, b)
}
func lineFunctionDouble(a, b, c *gfP2, rOut *twistPoint, r *twistPoint, q *curvePoint) {
// See the doubling algorithm for a=0 from "Faster Computation of the
// Tate Pairing", http://arxiv.org/pdf/0904.0854v3.pdf
A := (&gfP2{}).Square(&r.x)
B := (&gfP2{}).Square(&r.y)
C := (&gfP2{}).Square(B)
D := (&gfP2{}).Add(&r.x, B)
D.Square(D).Sub(D, A).Sub(D, C).Add(D, D)
E := (&gfP2{}).Add(A, A)
E.Add(E, A)
G := (&gfP2{}).Square(E)
// rOut = &twistPoint{}
rOut.x.Sub(G, D).Sub(&rOut.x, D)
rOut.z.Add(&r.y, &r.z).Square(&rOut.z).Sub(&rOut.z, B).Sub(&rOut.z, &r.t)
rOut.y.Sub(D, &rOut.x).Mul(&rOut.y, E)
t := (&gfP2{}).Add(C, C)
t.Add(t, t).Add(t, t)
rOut.y.Sub(&rOut.y, t)
rOut.t.Square(&rOut.z)
t.Mul(E, &r.t).Add(t, t)
b.Neg(t)
b.MulScalar(b, &q.x)
a.Add(&r.x, E)
a.Square(a).Sub(a, A).Sub(a, G)
t.Add(B, B).Add(t, t)
a.Sub(a, t)
c.Mul(&rOut.z, &r.t)
c.Add(c, c).MulScalar(c, &q.y)
}
func mulLine(ret *gfP12, a, b, c *gfP2) {
if false {
a2 := &gfP6{}
a2.y.Set(a)
a2.z.Set(b)
a2.Mul(a2, &ret.x)
t3 := (&gfP6{}).MulScalar(&ret.y, c)
t := (&gfP2{}).Add(b, c)
t2 := &gfP6{}
t2.y.Set(a)
t2.z.Set(t)
ret.x.Add(&ret.x, &ret.y)
ret.y.Set(t3)
ret.x.Mul(&ret.x, t2).Sub(&ret.x, a2).Sub(&ret.x, &ret.y)
a2.MulTau(a2)
ret.y.Add(&ret.y, a2)
} else {
// ret = ret * [ cτ*w + (bτ+a) ]
a2 := &gfP12{}
a2.x.x.SetZero()
a2.x.y.Set(c)
a2.x.z.SetZero()
a2.y.x.SetZero()
a2.y.y.Set(b)
a2.y.z.Set(a)
ret.Mul(ret, a2)
}
}
// sixuPlus2NAF is 6u+2 in non-adjacent form.
// var sixuPlus2NAF = []int8{0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, -1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, -1, 0, 1, 0, 0, 0, 1, 0, -1, 0, 0, 0, -1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, -1, 0, -1, 0, 0, 0, 0, 1, 0, 0, 0, 1}
var sixuPlus2NAF = []int8{0, -1, 0, 0, 0, 0, 1, 0, 1, 0, 0, -1, 0, -1, 0, 0, 0, -1, 0, -1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1}
// miller implements the Miller loop for calculating the Optimal Ate pairing.
// See algorithm 1 from http://cryptojedi.org/papers/dclxvi-20100714.pdf
func miller(ret *gfP12, q *twistPoint, p *curvePoint) {
ret.SetOne()
aAffine := &twistPoint{}
aAffine.Set(q)
aAffine.MakeAffine()
bAffine := &curvePoint{}
bAffine.Set(p)
bAffine.MakeAffine()
minusA := &twistPoint{}
minusA.Neg(aAffine)
r := &twistPoint{}
r.Set(aAffine)
r2 := (&gfP2{}).Square(&aAffine.y)
a := &gfP2{}
b := &gfP2{}
c := &gfP2{}
newR := &twistPoint{}
for i := len(sixuPlus2NAF) - 1; i > 0; i-- {
lineFunctionDouble(a, b, c, newR, r, bAffine)
if i != len(sixuPlus2NAF)-1 {
ret.Square(ret)
}
mulLine(ret, a, b, c)
r.Set(newR)
switch sixuPlus2NAF[i-1] {
case 1:
lineFunctionAdd(a, b, c, newR, r, aAffine, bAffine, r2)
case -1:
lineFunctionAdd(a, b, c, newR, r, minusA, bAffine, r2)
default:
continue
}
mulLine(ret, a, b, c)
r.Set(newR)
}
// In order to calculate Q1 we have to convert q from the sextic twist
// to the full GF(P^12) group, apply the Frobenius there, and convert
// back.
//
// The twist isomorphism is (x', y') -> (xω², yω³). If we consider just
// x for a moment, then after applying the Frobenius, we have x̄ω^(2p)
// where x̄ is the conjugate of x. If we are going to apply the inverse
// isomorphism we need a value with a single coefficient of ω² so we
// rewrite this as x̄ω^(2p-2)ω². ξ⁶ = ω and, due to the construction of
// P, 2p-2 is a multiple of six. Therefore we can rewrite as
// x̄ξ^((P-1)/3)ω² and applying the inverse isomorphism eliminates the
// ω².
//
// A similar argument can be made for the y value.
q1 := &twistPoint{}
q1.x.Conjugate(&aAffine.x).MulScalar(&q1.x, xiTo1MinusPOver3)
q1.y.Conjugate(&aAffine.y).MulScalar(&q1.y, xiTo1MinusPOver2)
q1.z.SetOne()
q1.t.SetOne()
// For Q2 we are applying the P² Frobenius. The two conjugations cancel
// out and we are left only with the factors from the isomorphism. In
// the case of x, we end up with a pure number which is why
// xiToPSquaredMinus1Over3 is ∈ GF(P). With y we get a factor of -1. We
// ignore this to end up with -Q2.
minusQ2 := &twistPoint{}
minusQ2.x.MulScalar(&aAffine.x, xiTo2Minus2POver3)
minusQ2.y.Set(&aAffine.y)
minusQ2.z.SetOne()
minusQ2.t.SetOne()
r2.Square(&q1.y)
lineFunctionAdd(a, b, c, newR, r, q1, bAffine, r2)
mulLine(ret, a, b, c)
r = newR
r2.Square(&minusQ2.y)
lineFunctionAdd(a, b, c, newR, r, minusQ2, bAffine, r2) // nolint
mulLine(ret, a, b, c)
r = newR // nolint
}
// 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
// http://cryptojedi.org/papers/dclxvi-20100714.pdf)
func finalExponentiation(out *gfP12, in *gfP12) {
if false {
// The naive algorithm. For rightness test.
e := bigFromBase16("61835e8b12594991a09a6ae43ade454acef6f4e86411255c16be7fbaca54d38dd9d1d3019dba1539bf41bcb4067aa64be8cb0476c5042cb93b5122d974b7ba196f691269ceb7907239e0cb2a13873665ed57cd410455806b97559b180ee9629f1c8d7d0598eee9b93dc562fa23afa5a3bed65f00632c9cc80357732739295edcb5a6b4b9ec19ba7a4defa394c04689ab78bd480ff56fa0696fd3135583d5aa1335d59c358aac66ee2c3601d19f32c692fb14fc5412315ec5a54d51e82f7dd634550e98dca2042c36b948ebd4aa170bae804f361d729e88dc3e3945f87bf22030f4c6983d64089bdf703b00c9e53535a5bbd6c4aa78c62f31d16182c1d978ad0efe915cab1b62d11b760558913d719f2bb6793f9fe39f2568478b1a3e843d1fa0b48ee8fd4c31b8f6fe5e935a4b5f799cbd806a8225955b05b83e3d7e2d0b9698e4890ab7e824dc7c6135fec864e1676b19fe1764ac0b7482facdd0f0d042330")
out.Exp(in, e)
return
}
t1 := &gfP12{}
// This is the P^6-Frobenius
t1.x.Neg(&in.x)
t1.y.Set(&in.y)
inv := &gfP12{}
inv.Invert(in)
t1.Mul(t1, inv)
t2 := (&gfP12{}).FrobeniusP2(t1)
t1.Mul(t1, t2)
fp := (&gfP12{}).Frobenius(t1)
fp2 := (&gfP12{}).FrobeniusP2(t1)
fp3 := (&gfP12{}).Frobenius(fp2)
fu := (&gfP12{}).Exp(t1, u)
fu2 := (&gfP12{}).Exp(fu, u)
fu3 := (&gfP12{}).Exp(fu2, u)
y3 := (&gfP12{}).Frobenius(fu)
fu2p := (&gfP12{}).Frobenius(fu2)
fu3p := (&gfP12{}).Frobenius(fu3)
y2 := (&gfP12{}).FrobeniusP2(fu2)
y0 := &gfP12{}
y0.Mul(fp, fp2).Mul(y0, fp3)
y1 := (&gfP12{}).Conjugate(t1)
y5 := (&gfP12{}).Conjugate(fu2)
y3.Conjugate(y3)
y4 := (&gfP12{}).Mul(fu, fu2p)
y4.Conjugate(y4)
y6 := (&gfP12{}).Mul(fu3, fu3p)
y6.Conjugate(y6)
if false {
t0 := (&gfP12{}).Square(y6)
t0.Mul(t0, y4).Mul(t0, y5)
t1.Mul(y3, y5).Mul(t1, t0)
t0.Mul(t0, y2)
t1.Square(t1).Mul(t1, t0).Square(t1)
t0.Mul(t1, y1)
t1.Mul(t1, y0)
t0.Square(t0).Mul(t0, t1)
// return t0
} else {
out.Square(y6)
out.Mul(out, y4).Mul(out, y5)
t1.Mul(y3, y5).Mul(t1, out)
out.Mul(out, y2)
t1.Square(t1).Mul(t1, out).Square(t1)
out.Mul(t1, y1)
t1.Mul(t1, y0)
out.Square(out).Mul(out, t1)
}
}
func optimalAte(e *gfP12, a *twistPoint, b *curvePoint) *gfP12 {
if a.IsInfinity() || b.IsInfinity() {
e.SetOne()
return e
}
miller(e, a, b)
finalExponentiation(e, e)
return e
}
@@ -0,0 +1,30 @@
import math
n = 0xB640000002A3A6F1D603AB4FF58EC74449F2934B18EA8BEEE56EE19CD69ECF25
p = 0xB640000002A3A6F1D603AB4FF58EC74521F2934B1A7AEEDBE56F9B27E351457D
p0=p%n
n2 = int(math.sqrt(n))
# n = 65000549695646603732796438742359905742570406053903786389881062969044166799969
# p = 65000549695646603732796438742359905742825358107623003571877145026864184071783
b = [13037178982157583874, 13037178982157583875, 13037178982157583875, 13037178982157583875]
a = [v*(p**i) % n for i,v in enumerate(b)]
print(a)
print(sum(a)%n)
# x = sum(out[i]*(p**i))
def padic(x):
m = p % n
print(m)
b=[]
while x > 0:
b.append(x%m)
x = x // m
return b
print(padic(n))
print("----------")
for m in [n*(n//4+n2+i) for i in range(1,10)]:
print(padic(m))
print("")
+61
View File
@@ -0,0 +1,61 @@
#!/usr/bin/python3
import math
n = 0xB640000002A3A6F1D603AB4FF58EC74449F2934B18EA8BEEE56EE19CD69ECF25
p = 0xB640000002A3A6F1D603AB4FF58EC74521F2934B1A7AEEDBE56F9B27E351457D
# n = 65000549695646603732796438742359905742570406053903786389881062969044166799969
# p = 65000549695646603732796438742359905742825358107623003571877145026864184071783
sqrt_n = int( math.sqrt(n))
def lamb(n):
l = pow(2,(n-1)//3, n)
l2 = l**2%n
return min(l,l2)
# return max(l,l2)
def norm(a,b):
return int(math.sqrt(a**2 + b**2))
l = lamb(n)
print("lambda=",l)
print("lambda^2=",l**2%n)
print("")
# eta = pow(p-2, 2*(p-1)//3,p)
# print("eta = ", hex(eta))
# print("eta^2 = ", hex(eta**2%p))
s = [1,0]
t = [0,1]
r = [n,l]
while r[-1] > 1:
d = r[-2] // r[-1]
r.append(r[-2] - r[-1]*d)
s.append(s[-2] - s[-1]*d)
t.append(t[-2] - t[-1]*d)
d = r[-2] // r[-1]
r.append(r[-2] - r[-1]*d)
s.append(s[-2] - s[-1]*d)
t.append(t[-2] - t[-1]*d)
# r[-1] < sqrt_n
print("s * n + t * l = r")
for i in range(len(s)):
print("{} * n + {} * lambda = {}".format( s[i], t[i], r[i]))
print("")
print("sqrt(n)=",sqrt_n,"\n")
print("norm:")
print(norm(r[-1], t[-1]))
print(norm(r[-2], t[-2]))
print(norm(r[-3], t[-3]))
print("")
print("v1,v2:")
for i in range(len(s)):
print(r[i], -t[i], "\n==>", norm(r[i], t[i]), r[i] < sqrt_n)
print("")
# print(r[-1], -t[-1])
# print(r[-2], -t[-2])
# print(r[-3], -t[-3])
# print(r[-2]*t[-3]-r[-3]*t[-2]),
+33
View File
@@ -0,0 +1,33 @@
#!/usr/bin/env sage
from sage.all import *
n = 0xB640000002A3A6F1D603AB4FF58EC74449F2934B18EA8BEEE56EE19CD69ECF25
p = 0xB640000002A3A6F1D603AB4FF58EC74521F2934B1A7AEEDBE56F9B27E351457D
# n = 65000549695646603732796438742359905742570406053903786389881062969044166799969
# p = 65000549695646603732796438742359905742825358107623003571877145026864184071783
# p_inv = pow(p, n - 2, n)
# a = matrix(ZZ, 4, 4, [
# [n, 0, 0, 0],
# [0, p, -1, 0],
# [0, 0, p, -1],
# [0, 0, 0, n],
# [n - 1, p_inv, 0, 0],
# [n - 2, p_inv, p_inv ** 2 % n, 0],
# [n - 3, p_inv, p_inv ** 2 % n, p_inv ** 3 % n]
# ])
# print(a.BKZ())
x = 0x600000000058F98A
t = 6*x*x+1
r = p+1-t
# x = 6518589491078791937
v = [[x + 1, x, x, -2 * x],[2 * x + 1, -x, -(x + 1), -x],[2 * x, 2 * x + 1, 2 * x + 1, 2 * x + 1],[x - 1, 4 * x + 2, -(2 * x - 1), x - 1]]
mv = matrix(ZZ, 4,4,v)
print(mv.det())
print()
print(-3*r)
for l in v:
print("bigFromBase10(\"{}\"),bigFromBase10(\"{}\"),bigFromBase10(\"{}\"),bigFromBase10(\"{}\")".format(l[0],l[1],l[2],l[3]))
# a = [v * (p ** i) % n for i, v in enumerate(l)]
# print(sum(a) % n)
print(2*x*x+3*x+1, 12*x*x*x+8*x*x+x, 6*x*x*x+4*x*x+x, -2*x*x-x)
+256
View File
@@ -0,0 +1,256 @@
package bn256
import (
"math/big"
)
// twistPoint implements the elliptic curve y²=x³+3/ξ over GF(P²). Points are
// 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)
type twistPoint struct {
x, y, z, t gfP2
}
var twistB = &gfP2{
gfP{0xb9f2c1e8c8c71995, 0x125df8f246a377fc, 0x25e650d049188d1c, 0x43fffffed866f63},
gfP{0},
}
// twistGen is the generator of group G₂.
var twistGen = &twistPoint{
gfP2{
gfP{0xdb6db4822750a8a6, 0x84c6135a5121f134, 0x1874032f88791d41, 0x905112f2b85f3a37},
gfP{0x260226a68ce2da8f, 0x7ee5645edbf6c06b, 0xf8f57c82b1495444, 0x61fcf018bc47c4d1},
},
gfP2{
gfP{0xf7b82dac4c89bfbb, 0x3706f3f6a49dc12f, 0x1e29de93d3eef769, 0x81e448c3c76a5d53},
gfP{0xc03f138f9171c24a, 0x92fbab45a15a3ca7, 0x2445561e2ff77cdb, 0x108495e0c0f62ece},
},
gfP2{gfP{0}, gfPOne},
gfP2{gfP{0}, gfPOne},
}
// AffineCoordinates returns x1, x2, y1, y2
func (c *twistPoint) AffineCoordinates() (*big.Int, *big.Int, *big.Int, *big.Int) {
c.MakeAffine()
var x1, x2, y1, y2 gfP
montDecode(&x1, &c.x.x)
montDecode(&x2, &c.x.y)
montDecode(&y1, &c.y.x)
montDecode(&y2, &c.y.y)
return x1.toBigInt(), x2.toBigInt(), y1.toBigInt(), y2.toBigInt()
}
func (c *twistPoint) String() string {
c.MakeAffine()
x, y := gfP2Decode(&c.x), gfP2Decode(&c.y)
return "(" + x.String() + ", " + y.String() + ")"
}
func (c *twistPoint) Equal(a *twistPoint) bool {
if c == a {
return true
}
c.MakeAffine()
a.MakeAffine()
return *a == *c
}
func (c *twistPoint) Set(a *twistPoint) {
if true {
*c = *a
} else {
c.x.Set(&a.x)
c.y.Set(&a.y)
c.z.Set(&a.z)
c.t.Set(&a.t)
}
}
// IsOnCurve returns true iff c is on the curve.
func (c *twistPoint) IsOnCurve() bool {
c.MakeAffine()
if c.IsInfinity() {
return true
}
y2, x3 := &gfP2{}, &gfP2{}
y2.Square(&c.y)
x3.Square(&c.x).Mul(x3, &c.x).Add(x3, twistB)
return *y2 == *x3
}
func (c *twistPoint) SetInfinity() {
c.x.SetZero()
c.y.SetOne()
c.z.SetZero()
c.t.SetZero()
}
func (c *twistPoint) IsInfinity() bool {
return c.z.IsZero()
}
func (c *twistPoint) Add(a, b *twistPoint) {
// For additional comments, see the same function in curve.go.
if a.IsInfinity() {
c.Set(b)
return
}
if b.IsInfinity() {
c.Set(a)
return
}
// See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/addition/add-2007-bl.op3
z12 := (&gfP2{}).Square(&a.z)
z22 := (&gfP2{}).Square(&b.z)
u1 := (&gfP2{}).Mul(&a.x, z22)
u2 := (&gfP2{}).Mul(&b.x, z12)
t := (&gfP2{}).Mul(&b.z, z22)
s1 := (&gfP2{}).Mul(&a.y, t)
t.Mul(&a.z, z12)
s2 := (&gfP2{}).Mul(&b.y, t)
h := (&gfP2{}).Sub(u2, u1)
xEqual := h.IsZero()
t.Add(h, h)
i := (&gfP2{}).Square(t)
j := (&gfP2{}).Mul(h, i)
t.Sub(s2, s1)
yEqual := t.IsZero()
if xEqual && yEqual {
c.Double(a)
return
}
r := (&gfP2{}).Add(t, t)
v := (&gfP2{}).Mul(u1, i)
t4 := (&gfP2{}).Square(r)
t.Add(v, v)
t6 := (&gfP2{}).Sub(t4, j)
c.x.Sub(t6, t)
t.Sub(v, &c.x) // t7
t4.Mul(s1, j) // t8
t6.Add(t4, t4) // t9
t4.Mul(r, t) // t10
c.y.Sub(t4, t6)
t.Add(&a.z, &b.z) // t11
t4.Square(t) // t12
t.Sub(t4, z12) // t13
t4.Sub(t, z22) // t14
c.z.Mul(t4, h)
}
func (c *twistPoint) Double(a *twistPoint) {
// See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/doubling/dbl-2009-l.op3
A := (&gfP2{}).Square(&a.x)
B := (&gfP2{}).Square(&a.y)
C := (&gfP2{}).Square(B)
t := (&gfP2{}).Add(&a.x, B)
t2 := (&gfP2{}).Square(t)
t.Sub(t2, A)
t2.Sub(t, C)
d := (&gfP2{}).Add(t2, t2)
t.Add(A, A)
e := (&gfP2{}).Add(t, A)
f := (&gfP2{}).Square(e)
t.Add(d, d)
c.x.Sub(f, t)
c.z.Mul(&a.y, &a.z)
c.z.Add(&c.z, &c.z)
t.Add(C, C)
t2.Add(t, t)
t.Add(t2, t2)
c.y.Sub(d, &c.x)
t2.Mul(e, &c.y)
c.y.Sub(t2, t)
}
func (c *twistPoint) Mul(a *twistPoint, scalar *big.Int) {
if useLattice {
precomp := [1 << 2]*twistPoint{nil, {}, {}, {}}
precomp[1].Set(a)
precomp[2].Set(a)
precomp[2].x.MulScalar(&precomp[2].x, xiTo2PSquaredMinus2Over3)
//precomp[3].Add(precomp[1], precomp[2])
//TODO Fix decompose
decomp := curveLattice.decompose(scalar)
if decomp[0].Sign() < 0 {
precomp[1].Neg(precomp[1])
}
if decomp[1].Sign() < 0 {
precomp[2].Neg(precomp[2])
}
precomp[3].Add(precomp[1], precomp[2])
multiScalar := curveLattice.Multi(scalar)
sum := &twistPoint{}
sum.SetInfinity()
t := &twistPoint{}
for i := len(multiScalar) - 1; i >= 0; i-- {
t.Double(sum)
if multiScalar[i] == 0 {
sum.Set(t)
} else {
sum.Add(t, precomp[multiScalar[i]])
}
}
c.Set(sum)
} else {
sum, t := &twistPoint{}, &twistPoint{}
sum.SetInfinity()
for i := scalar.BitLen(); i >= 0; i-- {
t.Double(sum)
if scalar.Bit(i) != 0 {
sum.Add(t, a)
} else {
sum.Set(t)
}
}
c.Set(sum)
}
}
func (c *twistPoint) MakeAffine() {
if c.z.IsOne() {
return
} else if c.z.IsZero() {
c.x.SetZero()
c.y.SetOne()
c.t.SetZero()
return
}
zInv := (&gfP2{}).Invert(&c.z)
t := (&gfP2{}).Mul(&c.y, zInv)
zInv2 := (&gfP2{}).Square(zInv)
c.y.Mul(t, zInv2)
t.Mul(&c.x, zInv2)
c.x.Set(t)
c.z.SetOne()
c.t.SetOne()
}
func (c *twistPoint) Neg(a *twistPoint) {
c.x.Set(&a.x)
c.y.Neg(&a.y)
c.z.Set(&a.z)
c.t.SetZero()
}
+317
View File
@@ -0,0 +1,317 @@
package bn256
import "math/big"
// 256*4*4*4*2 = 32K Bytes.
var twistBasePrecomputed8 = []*twistPoint{
{gfP2{gfP{0x0, 0x0, 0x0, 0x0}, gfP{0x0, 0x0, 0x0, 0x0}}, gfP2{gfP{0x0, 0x0, 0x0, 0x0}, gfP{0x1a9064d81caeba83, 0xde0d6cb4e5851124, 0x29fc54b00a7138ba, 0x49bffffffd5c590e}}, gfP2{gfP{0}, gfP{0}}, gfP2{gfP{0}, gfP{0}}},
{gfP2{gfP{0xdb6db4822750a8a6, 0x84c6135a5121f134, 0x1874032f88791d41, 0x905112f2b85f3a37}, gfP{0x260226a68ce2da8f, 0x7ee5645edbf6c06b, 0xf8f57c82b1495444, 0x61fcf018bc47c4d1}}, gfP2{gfP{0xf7b82dac4c89bfbb, 0x3706f3f6a49dc12f, 0x1e29de93d3eef769, 0x81e448c3c76a5d53}, gfP{0xc03f138f9171c24a, 0x92fbab45a15a3ca7, 0x2445561e2ff77cdb, 0x108495e0c0f62ece}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xc5fb644bdf2354c6, 0xcdfd499ef173fbbc, 0xbcfe70472ea2973d, 0x6ac85071a7badcbc}, gfP{0x4ec5ae6de6e7e3f5, 0x579d6192cb5f4010, 0x762f8798b8c86c1e, 0x43f0d2bfdd7632d0}}, gfP2{gfP{0xaf675938a99f7c75, 0x7691c8ef47d6d36e, 0xd3ae60adc7fda33, 0x606bd3d09c3cdd6a}, gfP{0xe8e4bd6709e420f8, 0x27683ca35be109ad, 0x3441f6ec4dd878d5, 0x4e9fdca6652eef04}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x263044fc17436912, 0x6b2f604a9356ec7a, 0x58a4df9eb3d1819f, 0x53ffa324ee578cb7}, gfP{0x640afc60e3d55b7b, 0xfa4d405cf6f1e4f0, 0xb42011e3aa8eec65, 0x1b6275e50bf11ae3}}, gfP2{gfP{0x97603278bcd1390d, 0x222a6c462a95d9a2, 0xd1b761ee09f950e6, 0x7d7da8bfdd029a52}, gfP{0x5a723ba4161731ad, 0x92fa97b24f21d069, 0xe47d8a2a4d03899b, 0xb135913fdfa7a543}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x6463feec3c8bdbab, 0x64dc842b9bcee33b, 0xa3e6c43761abbfe7, 0x85559a3d0b1f130e}, gfP{0x60f8bd0c3ad98738, 0xc6f9453399138d5d, 0xd9f8f4158eac1ae3, 0x382cec3b0d7f2db2}}, gfP2{gfP{0x2c731b1525ad3c11, 0xb670090152839463, 0x9501f0a64010993c, 0xad858308fdc04a95}, gfP{0xca527cf183587ced, 0xf89c3824adc81a59, 0x9bd5d8fb8c02195c, 0xa19141e277c74cbc}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x40b8aa8aa6f998a9, 0xd4842c88ee557b7b, 0x985b72df85b1ef71, 0x3d9568b5b197ea6}, gfP{0xbf594ead2be677da, 0xda9cdc98c1f802ad, 0xfecfa1bac30cc360, 0x5f146bd65376a354}}, gfP2{gfP{0x9707f0e6a313ce90, 0x590dd3722201ef90, 0x3ca97f81c5d672cd, 0x2df3849c7ae46eb8}, gfP{0xd35f101ca9d8771, 0xa5aa643d984a83f7, 0x2fed160520acc6ac, 0x43daa6376a145336}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xe5faa6a3a4048fe7, 0xc9b0d641fdea4317, 0x8410409f8b7b41d2, 0x23b0d237044641d9}, gfP{0xe117e885774f23d2, 0xf97bee1af801f3b1, 0x11eca3aa4dccaa64, 0x1465111fedf0910f}}, gfP2{gfP{0x228b21f99f0eb2c, 0xe1acc89ad71503d6, 0x10a1b3e94a233d50, 0xa85178637c3e455b}, gfP{0x6f5b3ac648ea5e9f, 0xdec6667fd35f5115, 0x6c7755f0d71a18ca, 0x83596255cfa7eb98}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x94d5a76870db62e2, 0xef362edfc1275649, 0xf200c5c5b04c02e8, 0x3455ab4597fe4369}, gfP{0xd7fdb42c25355826, 0x8c6f0165c6cb172f, 0xcede559c76b4681e, 0xb14aa1470067d03b}}, gfP2{gfP{0xbeb575ba829f90bb, 0xe13cad971efb0dd8, 0xd42365512c7a8f0b, 0x4caf1b6d82e95470}, gfP{0x8b05da7a76eb9173, 0xf14c9c313e0532ed, 0xe097fae68508c038, 0x9fafd15d39d4b5dd}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xb1d8787cff1ff15a, 0xab372943f1dd9659, 0x8924974de51e1bd5, 0x13e108d59ca4be79}, gfP{0xa9eaa942ca07e120, 0x238466744a039acb, 0x7e1a54a959fe2480, 0x42faaa621feaffaa}}, gfP2{gfP{0x9c489b48243a905, 0xae21f53c7565707c, 0x9b13e607f3563db7, 0x98332cd7199136e6}, gfP{0xb24a710a83bc0e5c, 0x767d1ac0855f566a, 0xdab7822548ccedaa, 0x5ae1ec760a576f2c}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xafb97fec7174a810, 0xacc0ac8c4e3f8a71, 0xb87bdb9097a99b9b, 0x5f92cf6d30f13ff8}, gfP{0xc3323d5cadcb8720, 0x379b0427aa2ff5f9, 0x13ad906a601ea662, 0x450fecae6b885a5a}}, gfP2{gfP{0x8fe5b12dc3a8f229, 0x4755060242691742, 0xce5344bc160b2601, 0x8cea7a07235fac92}, gfP{0x7bac6571b3e21d8e, 0x91b20ed5bb372845, 0x444051f0db7cbd17, 0x5d837cc558c62c52}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x558edbf385a8c79f, 0x4940110333c45113, 0xc7f0b1d7f1f0939a, 0xa6d88d81af50bf98}, gfP{0xe7b2d279c3a89f47, 0x7537abbfbfee62fa, 0x5591e28294e663c6, 0x46cf94a4f89293b9}}, gfP2{gfP{0x3e5fee9dbebe3f89, 0xfd9a6495c4b923eb, 0x9df1b45429ac0f3, 0x13bfb67e2f1b4b16}, gfP{0xfc5eb5d3862e7986, 0xfad0d5408e9535c1, 0x4736ca3d22c55ad3, 0x4e30ebf7b5bffda9}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x5dc360a842a549a3, 0x833ba195a439988, 0xca66a503d7de8d02, 0x4cf6339b1415808b}, gfP{0xbea6d9ed9e8f8e82, 0xd59f97e8a6f84872, 0x79a99739e000ee49, 0x11f7ece09b14aac2}}, gfP2{gfP{0xb80268b3d1d80bca, 0xaf787a7e25f63521, 0xb5e539485105fe67, 0xb2b9a401a0be4397}, gfP{0x9b2584f94dcfbf47, 0x490dc6a6242603a5, 0xeda4039633ee2d3a, 0x8b77f0ca1a18fa69}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xe803c8781bfa1668, 0x45ff86a72b5dd51, 0x3e292cd306f1f5b7, 0x6cdb67105bfa392a}, gfP{0x875be4e255ad9c9c, 0x15b8207c65289fd5, 0xcbf29b6f30f8d238, 0x9588cf1da2976fa2}}, gfP2{gfP{0x251a0752329685c1, 0xef2317996fbbb6ae, 0xb61e983430ff554e, 0x63351124b162b900}, gfP{0xade41f819d37e7f7, 0x5a5ec5f493f9ca1c, 0x8faeda3c27db812a, 0x23a1db71b0b5e22e}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xabeecbef757bbac3, 0xf8d1722d2d69c910, 0x1a617fd5bafe4e83, 0x16030fbb09888f76}, gfP{0x6f48682d1de89676, 0x158b842a4a53ba6f, 0xf9119f53cbe7bcaa, 0x22f428fba81e6a23}}, gfP2{gfP{0x2994e639b5a12c4f, 0x61da9ec9684ab41e, 0x271f80a5ddb5351f, 0x13b019467cf6370d}, gfP{0x46ddb28c8921cf5d, 0xd345bea3a666b409, 0xaba1a43c5b8240ed, 0x726a60be4c063617}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xcc073781f564ddc9, 0x9d2289c4359a22fc, 0x274bb085d4ace1ac, 0x22065fc1091bcf3e}, gfP{0xf8c1c58c6f82709b, 0xdd182c87cd9969d4, 0x45dcaa3dbe075268, 0xb057448230813056}}, gfP2{gfP{0xcf8b0d37d540b53d, 0x5215255a73ba5048, 0xed01aee04aa8a346, 0x720ab627c84acc54}, gfP{0x31d3e81c439960a1, 0xa1d15d86c571cb79, 0xec36bae98f8be710, 0x8e1ea4678f6ce680}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xc70050c52c18072d, 0x1e73f4c9e519245f, 0xfae3f6c8d52072be, 0x2c9b128e27782e33}, gfP{0x9e9a420e75b152c3, 0xeba4bedd2243fb36, 0x71ce55f412c64f71, 0x4eb305d340f78c0b}}, gfP2{gfP{0xb2db0667426a68ee, 0x1cc8c23b55032120, 0x876eaf8943c63d3a, 0x3a5bf1d8d606d299}, gfP{0x318b7464cc1eb43b, 0x7a9a92a29477c7a1, 0xf1ec4acf9978054b, 0x715e7f954995a615}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x6f3387a1b02c9c9e, 0x9b887642c32a8d9e, 0x1c7dbd380fbdc42d, 0x6609e885885cd975}, gfP{0x1956294fa662b946, 0x4f4af30451e2a2e1, 0xe9137b8d29d20583, 0xac2e15d5b60b8b78}}, gfP2{gfP{0x1142bf699628bd2e, 0x7d2bd765f8bc697f, 0x1bbdc3e3c85c1cf4, 0xa80f50787c1e928}, gfP{0xa83292b4fb9dc8d5, 0x70c17c8f0718d49e, 0x8412a5365903a75b, 0x33fce3ec94c31e25}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xbda65045e559c4dc, 0xcf48515cb80cba89, 0x3499669089b907f1, 0x3e8612e84f096b66}, gfP{0x3f7b717b8759ca4, 0xb4bbe0225a8990af, 0x995d81523691b9b, 0x31fec0dae03b4333}}, gfP2{gfP{0xc5d7b3f000a91f04, 0x514e39a9f8ac0815, 0xf4c1f67ff5fdc077, 0x4dcd2422693fa2bd}, gfP{0x292d7188203b020a, 0x7cd38a0708afe117, 0x5ef9c8aad40b5f78, 0x82d3051d99011bce}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x674ca246228a2f9d, 0x74c3b1f97ada56ea, 0xc9c355ebeb477786, 0x21c511f541563e03}, gfP{0x4f3a5cd015b953fe, 0x9da3a9ca485d95b9, 0x34c002b2dc02e71f, 0x6702fa7b0c47a322}}, gfP2{gfP{0xc3b3a31fef80bd0, 0xae17c14c14dadbdb, 0xbddf06b74c53c85f, 0x738c28d6f653c0e4}, gfP{0xbd37a4a67dd17609, 0x31af23ec108a31f, 0x5a65a8c151f72d6a, 0x23a05e3be2a02022}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x29f730758cee4074, 0xf4ed85584a95220f, 0x5ad61404b60b2153, 0x2b2638c4b3b3a550}, gfP{0xf2fef9fd1f78554c, 0xb7460203cda93583, 0xbac0db31f0fe9db0, 0x9719195140384d9e}}, gfP2{gfP{0x9a21c5696dd40d34, 0xa2091bc9451af667, 0x6d213cb9fa293234, 0x7b489034735f5a68}, gfP{0x396fa4b9ed167b00, 0x9bce5cbe56117724, 0xe7210384535584a2, 0x9b75efe876b1a1f7}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x885aacda25419b8f, 0x74c622c06a6f19b9, 0xf08da461c8f7bb33, 0x41189fbea0e83239}, gfP{0x4bcd5c7123819f89, 0x2286d9caf1e191fa, 0xbfc41325655679ff, 0x7bfd2403f1e90113}}, gfP2{gfP{0x587a80aa292eb058, 0x46e45860a6d20a3b, 0xffe34159f73f52df, 0xa47ed9ab1ef56ada}, gfP{0x789671435c8d1d7f, 0xf1892cd9f2ffdcc9, 0xc92762dadcc775ac, 0xc51be00f703b68a}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x50507052e1da80a5, 0x72c1cd1b15a6bd13, 0xf7813dceeac8ae7f, 0x3b16aa48179f7db1}, gfP{0x61f029ee22588e2a, 0xf783cb2856271825, 0x78e68edb70f8714f, 0x6fc0969d164b8a60}}, gfP2{gfP{0xc24449273b370370, 0x19d62426be785ce1, 0xec6cb217a26d4865, 0x6cd54836873c3abc}, gfP{0x686c5fa32723194f, 0xd7465a7b4ebbfef8, 0x22d64f3b5c2dcd98, 0x928c4f9ccb271b45}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xd0bd3c796c693fc3, 0xa5cf80144f4b9873, 0xdcffea4f0ce0b33c, 0xb40921dded649369}, gfP{0x4edb2925841d2f0e, 0x17e563e68a9e4558, 0xfe202520729ca5d, 0x998c4dba938455a3}}, gfP2{gfP{0x32b38ead2a0612d8, 0x39629fb1b8ff7f72, 0x9577e5970e381725, 0x141f21ab2bcef4d2}, gfP{0xf0ae3868afcb7ef5, 0xd771c503b9e947f6, 0xb0111776086910b0, 0x863672ac76e08e14}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x8784cbfdcbb24c00, 0x79e88534d42d03b9, 0x85075e6029feec43, 0x21b33e27ae68a1cb}, gfP{0x91791a0d83faff6a, 0x4e7f76cc43e01692, 0x4558f13f3c2edb5d, 0xae0e54170eb1218f}}, gfP2{gfP{0xf56a098143fa9b34, 0x232372adbf37d428, 0x786cf2fab865a22e, 0x880b78a6f4ab178b}, gfP{0x775cbde560ba5eab, 0xbd75fe927a3fc155, 0x2c99cd4d41ba7bbc, 0x970eb97eed696349}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xc5c6d245010fa807, 0xd4a14b66fc0d7b07, 0x3005390a58e126d8, 0x51bb937a23c8fc8f}, gfP{0xf6f5d3824980fe92, 0xaa03005ef21ca4dc, 0x46f3137a19f7dc11, 0x6ac3a59155fe0b24}}, gfP2{gfP{0xaf187829810e76c1, 0x85ecf75f2fd1c33f, 0xabac86136fb8e767, 0x1b31a21399daf198}, gfP{0x2cbdfa4057a21ae7, 0xef044f121c29ee98, 0x5a586fc32b10d703, 0x707cd5ca03872dd0}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xbc89c21668e0e17a, 0x34b28cfb35ca6c47, 0x6c8d08d2fa6fc879, 0x877495a1367e4c67}, gfP{0x35500e4187c089c5, 0x1266a0074641a02f, 0x71a73752a7c3b80c, 0x1a8c6ae8d80ecbb5}}, gfP2{gfP{0x9f760b8e96f04663, 0x63aa99ca027e03db, 0x38e0c1eecc609e04, 0x6bdf5a0609636a7b}, gfP{0xe7e956f2dade66fb, 0x9640f09a4c229922, 0x4dda9d778ac745c5, 0x167eae450d1e781b}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x1b6be5b8a1069728, 0xeac07d1155061ef6, 0x8b0b4cc033ca0aa6, 0x765817c7ccc500b4}, gfP{0xb6eae75049264819, 0x2fa119a5b77b0eb1, 0x5c3b88fb70e2929e, 0x6d1dfa37fe3cbe7f}}, gfP2{gfP{0x15dca3aead9d7cbf, 0x9e26f0803c4fc5fb, 0x7ebb0deffa399407, 0x8e1da4378dc6b2f8}, gfP{0x1b22bea165a722a2, 0x61fb37c52bf61964, 0x12fddda13e6eb980, 0x2dc3ec23cb2d0b5d}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x119562d891af3033, 0xf8463170449dc57d, 0x4862d36571a09ae8, 0x5e7331c956236dd3}, gfP{0x728df11d3740c396, 0xa1a38c05293afe9, 0x3bf74736e8bb4225, 0x2dee9b392dbd73d7}}, gfP2{gfP{0x3789525394d21beb, 0x33c1d82dbcc80f5, 0xf6f8cc3afa687d9b, 0x125f9bd0b86f0fa5}, gfP{0xaecc6852b87c6546, 0xbd18d9c7cc95a955, 0x6f9d2a2a616a9ce1, 0x1518e1dc42123fdf}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x92cc85c959a1fb92, 0x61ac0af6596517d, 0xf1c896101a89c7ff, 0x1681f1e2d18c0de6}, gfP{0x160bd9df5a815846, 0x3c50a95e2a58ee04, 0xe99b6d969b32fc18, 0x7c3ab4872d05c6f9}}, gfP2{gfP{0x9e76bb8b1f0abf08, 0x9dffe8294176ee08, 0xd3ca505067acc56a, 0x68cca21150ab004}, gfP{0x3ac5d79d2211a8e2, 0x336bb56de3ef6790, 0xb84d115d7eee14c9, 0x5e3fa1b5c5e5520f}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xe0cfb5a848a2685b, 0xbc886c549ab06037, 0xdb216e3b7df3b4d5, 0x5d43acc6fc84bc23}, gfP{0xd92363ec9837593e, 0x20cc418c9d3dd42c, 0xcb29b865730ac210, 0xa86f82d2aee2900e}}, gfP2{gfP{0xd96b9854360badcb, 0xfbe92d68badf330e, 0x9e4792645fd4a261, 0x1f7e55b00ff197e7}, gfP{0x820125ac96555f30, 0x8bf140b585f5e8c1, 0x11bbd297de591f73, 0x5dc8061f7006adfa}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x1717aeb2d3551d52, 0x2d2008ea62e17b3e, 0x7286b86b60e238d2, 0x39645621935103f6}, gfP{0xb559fd711786b800, 0x672e9ec1c72b3fb4, 0x21458a0ee578f1c6, 0x9ae16d2a25a889dd}}, gfP2{gfP{0xf6734d344ea939d, 0xf4320cf0949f3a2b, 0x8b233e71c9790803, 0x15a1bdb19de02ecd}, gfP{0x2f50d98c4d384311, 0x77023c166278e872, 0xe10e2243797efe0, 0x6e8d16fcee357364}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x39e1225a07562a52, 0x6611e5906c88dbdc, 0xdc8eb9486c4a25d9, 0x89ccacfe54085146}, gfP{0xa8bc6e2fadcc9c7e, 0xf7f3e08c0ede9fe8, 0x5ec9ea05306eef0c, 0x2d9f4ade4a29d3bc}}, gfP2{gfP{0x14737be71f13b5a, 0xbf997ccfe2be786, 0xa2dfd4e13df922e4, 0x326fecfecbe4d9b1}, gfP{0xdc0f0ad8ceee469d, 0x154453cf95a68efb, 0x8d0af4a032c72da9, 0x6a5fca147450d51b}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xc97be8ec3efef610, 0x740ce6b3927df809, 0x28b4073215b10cd9, 0x11360af700244976}, gfP{0x8ce5b5f9dac20217, 0x5c9a863ace158b45, 0x291552f57f053a3a, 0x9a710e9c09065ff8}}, gfP2{gfP{0x53c45a118b282b7e, 0x27467c4558e973c0, 0xae19cea60d7c9115, 0x6a6740e0fb12f11}, gfP{0x8f59deab98b7e244, 0x6d000b9abb7cce2a, 0xd8c01d62545a2176, 0x4775afbcba4fdac9}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xf251dbe8ac379887, 0xf9a8850432120061, 0x4f7a697fecdd8a82, 0x3fff3358047304cf}, gfP{0xee03127269f42ae2, 0x10dee107bf46568d, 0xe14b69ddbb3470da, 0x946ec75ecf032d8c}}, gfP2{gfP{0x512f7076c37e8f3f, 0x1c81b5497428ce67, 0xd21aa281ac6db505, 0x71578fd1a70b33be}, gfP{0x16f96a9b4be3659e, 0x79c4b4470f294272, 0xbcdf6c9baa704fab, 0x14e0c1b4399f8be9}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xde687f3c9e1f93fd, 0xb6b3fd1365f56bf2, 0x6524f6256de0b879, 0x228a37ac0a3ba324}, gfP{0x862bf8da76c0daef, 0x64de2def92c1f11e, 0xdf7895456bfe714c, 0xb156c31d9fb85ae5}}, gfP2{gfP{0x7be0c82b803052e2, 0xc9ac23a47cb2a1a4, 0xf1f43e5f1da4f6e0, 0x1147764d09e81803}, gfP{0x1c20fda427f7bad, 0x7be0825940560, 0x37abe86eb464cce9, 0xac959084dbaa2088}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xa8240a8f74c96459, 0xd2ee9e89c2a3192d, 0x672fc1e0f4b5683e, 0x303d2ed2f2fc7d94}, gfP{0xf55ba0abdfab8e0d, 0x9affcda3bfe4ffaf, 0x56cb8e30b730d6c8, 0x12199811a543b1b}}, gfP2{gfP{0x1cc58e2ed34e65e2, 0x5102693b73c27797, 0xad469ffc80963642, 0x44d478cf29c545a1}, gfP{0x85b7d13d35be564e, 0x50731a53c4bec647, 0xb337bb55f5a2ceb5, 0x4e182afe08e2fcf0}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x13dbedaae67a8ee3, 0xf4d64243ea2083d2, 0x56447cd9e4e40871, 0x88c59e16122821de}, gfP{0x4cc933f49e16a978, 0x89a859d4754be4ec, 0x5d414dc74b660fcd, 0xabcae8fa08deb6b9}}, gfP2{gfP{0x9bfe189a1372426e, 0x17726d69a04da12f, 0xe9762ec24ccdb3dc, 0x10eb1854cce6b1b9}, gfP{0x1d510aaa12c84c0e, 0x4b27121b506a4071, 0xd8928f653e66541, 0x38c0717f94e70408}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xd2c66495975e5333, 0x27e409cfa294cea6, 0x72888b27c9401d2d, 0x59fe56e71153e225}, gfP{0x38ace41b12c4e5aa, 0xfd5057e4f8e8ef35, 0x74dcedb33248a657, 0x60554e19a0e9c273}}, gfP2{gfP{0x8db5666c0264e000, 0x416df65748f187b6, 0x8555e6599f80ed66, 0x76681224d343665f}, gfP{0x3435e60aa19ff39c, 0xdcbca4118e7cf6c1, 0xef154d17a99f61e4, 0xdd7b7c4e01ef89}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x5d0690858df460ea, 0x1d441ca6561477cf, 0x246edb99f50b736b, 0x5ab0e8762c1b0057}, gfP{0x115df77b0b297372, 0xe65ee66f94b76039, 0xf874e10e49a54108, 0x4ea97df42534bb7f}}, gfP2{gfP{0x9fd0f90fd584d3c5, 0x43144bfdbe62d46, 0xb2383db901ebca5, 0x4b95d919edb7f8ac}, gfP{0xbf7155925e1b3323, 0x29835de86982b0f4, 0x5c117128eec85ac, 0x53740a641648a4c3}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x123e560fd8d5e39f, 0x291de0ce23ddd459, 0xb43c117773a2d642, 0x52b72b39e9331a00}, gfP{0xa6711ae946bfaf50, 0x8803d10ddeebd5e2, 0x2f812cfb1f4a3d2c, 0x25917b69127f1938}}, gfP2{gfP{0x223ca9df00bb16d1, 0xfd35c449b9c77a10, 0x191d9cb5449ed8d3, 0x635716f13d513721}, gfP{0xce12aa1b0f8b7277, 0xd2a18650089173d4, 0x64edcee6c4e25689, 0x5ec01f2ddf9ca3b6}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xe390e7aefe0944ae, 0x243a165b6fa4ff57, 0x8af8da9bc1fd4509, 0x4d03b60e29c56416}, gfP{0x523f80e18c2496b7, 0xecd0f2dbc9bbeb3f, 0x97fecdbc8fd8b235, 0x5cc459c37415b102}}, gfP2{gfP{0xc4678240aefa5e08, 0x727a12de25674751, 0xc2f9e0e91a83af43, 0x5bc8d4dd022a11d3}, gfP{0x2f415ac25d496804, 0xfb53f5d4d679f942, 0xad6df00a73290183, 0x4f1affeba3ea1e6}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x232625275044588, 0xf1ff9c231fef78b0, 0xcf2e75fb88ce219, 0x68591a264892804a}, gfP{0x1a68312e942ee2d7, 0xa2d073e54716aa89, 0xb61d8358f7d6650a, 0xb23ec29cda640021}}, gfP2{gfP{0xaa6328df90de0731, 0xbeaac644bcf2844, 0x1f301cef155cc3c3, 0x8836faa74f7bec3}, gfP{0xb644d6ea1f609f3a, 0xd1b44b7a7c9a6747, 0xe4e0c38f61fe31f1, 0x4adfde6d0918c04e}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x18e9b738de2740c4, 0xb328d7f890f87b32, 0xe1bd983264853f01, 0x23601bccb5e061b5}, gfP{0x9abde2f4a02a3208, 0xb2fe185c5885f77, 0xefb0693a52c842f1, 0xac84762a2fb17a53}}, gfP2{gfP{0xbcaa66016d3c582b, 0x9d9f3b568d2d2b08, 0x3f4ce79e0d261977, 0x852bdb71e6da018c}, gfP{0x9786d26da3c5c08d, 0xd089ccf58409237d, 0xdcbbf2611ffc7acf, 0x706ab7b44cf3b293}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xa72c14994e49a6c6, 0xb67131b5bfc6686f, 0xb6210c429837daaf, 0x71b6d9884b09270}, gfP{0x6cbd601fd947bad5, 0xcad1a1640288aa4b, 0xbbb02204ebb09eb1, 0x3aacff9d6c36890f}}, gfP2{gfP{0x78a7103e573f2d74, 0x3f2662ef34b28e80, 0xd3c524028bfd3be8, 0xb426ddd53b737758}, gfP{0xe9b91c50d083a0b1, 0x4aeee7d8e30cf0bb, 0xc433bee2b110b671, 0x97eac5dfedeccb7e}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xf7e86e315c05700e, 0xdaa0339a5caaf31c, 0xfe5e2612e995141a, 0x1368c6f1b79952ae}, gfP{0xf0489e8f2f194533, 0xd2ad05fa0bf12c78, 0x42668b0b890c6343, 0x430a53f3cf7fc777}}, gfP2{gfP{0xdf4fce367387ee56, 0x231e5aaef321ad29, 0x857d697746da836b, 0x2382ef531c14c61a}, gfP{0x1a6db1e0ebbd0564, 0x2e1c43dcfb00bdf8, 0x4f9e373b53ee38e3, 0x137cdf89c564b870}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xe1e1492cb51b16c6, 0x47c0b79dd0fa6bfa, 0xf47aa627459b089, 0x53ed68d2d8c654f5}, gfP{0x4e8beff927dc56b3, 0x65db35ff6aff1f02, 0xb744ead53a061c39, 0xaa1bfb5f8c43575d}}, gfP2{gfP{0x975b9a912a2d6b9e, 0x447f79ba52ce5610, 0x67aba33d5acfbd9a, 0xa4ef1b626f7337ff}, gfP{0xf0c16298231d54d7, 0x8262feb56a59f237, 0x4add60fc7d7d7e11, 0x709d48c8af71ab40}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x8e2e7ad645a357a6, 0x620290b19c22aad0, 0xd7ef64309c1af4dc, 0x40e371b1a0cab35f}, gfP{0x1d567257c641eb84, 0x3d819bba220fe3b1, 0xc0f915e61881c572, 0x5a30b372c86c8b28}}, gfP2{gfP{0x2f9aa1b6cef0ffad, 0x36f56bc182b7c7ca, 0x2c12d0a45386b439, 0x5ea1e889ceeccc01}, gfP{0x13d2adde68b85107, 0x12aa0b44b9d84d0e, 0xcafc8cc0fd4b0545, 0x45f062e29bc86754}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x40b8193c2d38b132, 0xcbd3514d7a316475, 0x11435d2085913662, 0x5671cf2dc15e45f2}, gfP{0x84d7284eed3cec24, 0xdec5c242af1c29a7, 0xdb7a4d81c6cd3da3, 0x8a793be4d0fff58f}}, gfP2{gfP{0x1ba560b6d5479f26, 0x4a162813e07b7d35, 0x2fbd4943fccc1547, 0x6daeb823ebe96dbd}, gfP{0x6792f122f68bd973, 0x6f8e0069c921aee, 0x65d1ed22e39154df, 0x17ec224654f6fef8}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x5b19d3b4cd812a48, 0x8971c06aed096c5f, 0xec21a35417710d5a, 0x235661f390e294a6}, gfP{0x5381a19b7941ee08, 0xccd86ce1ba89fe28, 0x5718eaf4ae03b1a6, 0xeab3ac445c3c44f}}, gfP2{gfP{0x1c90b851e24cd4bc, 0x7c87a1bd6e929218, 0x866ef5bf44f72f69, 0x7af781fd0eaf232d}, gfP{0x6a96030de179eb51, 0xa3eb9e843cfdef57, 0xb1fbf53c1fbf8f98, 0x127ef0fe428493cb}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xf63406c7ca9175b2, 0x12bc9b312aca52a2, 0xf1679860e9c802db, 0xa84d200959c3aefc}, gfP{0xb771ee04a410c3f6, 0x568d2a0fd6690991, 0x9e2753a24e92ed79, 0x2e07ffdc5d3366d6}}, gfP2{gfP{0x7e7fbb4fbfdbcb8, 0xa9845d2649c8a27e, 0xc1d444e99bfa5878, 0x3cdaf59991ce2c0a}, gfP{0xb725357e476b8732, 0x3ccd1a8bad0c170e, 0xa34a361b34664265, 0xb55f4eab7f15281}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x75271b1493ae69d0, 0x58db3f689dbaa61a, 0x2d264c18ce90eb68, 0xae5989226aea0236}, gfP{0x47b9e0067240666f, 0x5f2c29f86bc4b625, 0xff4a686b2543957a, 0xade9da6e491e72b}}, gfP2{gfP{0x910fb2dbe89821f8, 0xb00f465adf5bea7, 0x43073428e4921893, 0xb5ceb7c6676bb1de}, gfP{0xc3beb17f3a173f59, 0x145e1afb761110e4, 0xdef2f0b862c73fe7, 0x6110d10dadeb2760}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x1abefe3e260d335d, 0xb9b7c6f967c2d5c8, 0x194c91742acdf53, 0xa1e49ab9c76d2126}, gfP{0xed9246ad1374248f, 0x4a04ec6f37f2c274, 0x688ffdfa84291bb7, 0x131740ca840fa4a1}}, gfP2{gfP{0xc2c85f76338ee15a, 0x5139cae5053904f5, 0x7cfbabec1fea5a72, 0x1e41644beee333f}, gfP{0xe280258d862fb63e, 0x470c49e8ce0652e5, 0xb0281ceb75bafbe4, 0x9367049b95cebea7}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xc3af742e659ef096, 0xe27e00d8078f30d4, 0x37e088d61bdb2a81, 0x94f0e89db27b9a7c}, gfP{0x168f275e10029774, 0x437df8119e2684cf, 0xd8768f537e538ee0, 0x4f5dc3a952ebdf2}}, gfP2{gfP{0x5560478d349d5fe1, 0xd95cc87b139fc57a, 0x3442e19e76593923, 0x310171a6869c5a48}, gfP{0x7c37fcc5af05c672, 0x2e39885feced3345, 0xc05071198e338121, 0xeea3c5bb2fcce9b}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x10e45b6386506403, 0xa35f59b8745aa2f0, 0x4739096a9278281b, 0xab7bf3ec7388164}, gfP{0x18367963d002cf94, 0x248a53078bbebe83, 0x802e52dc645f1219, 0x5284c99c4c3218b7}}, gfP2{gfP{0x4fffbeacf4899e20, 0xa7db6835dd92ac84, 0xda0fd5b3d6fd5241, 0x1cd1c2f801d2025e}, gfP{0x45ae5289cae9c623, 0x860b09a41c22e5b4, 0x6e1b4985e8089bd0, 0xadde967ef95569bb}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x1208b38a24b328b0, 0x85628b3fefd9a7cd, 0x6b6744e65a31fab5, 0x46561ee28c039789}, gfP{0xbf4d2b1a4a8657be, 0xd600b05fdc929639, 0x83abcb2e9c97f1f0, 0x6cbd3243c9108222}}, gfP2{gfP{0xc8c597018182336c, 0x59d7961e12c04fcf, 0x67513979f9e09bd, 0x9198166e7e3494cc}, gfP{0x86e47fd886409ab1, 0xd088a26f41e07257, 0xf5fff071f8786048, 0x9e600d2696716ddf}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x72adc8170995ff95, 0x8a38a5187293819e, 0xe7b5ea445563d9f9, 0x71f4ad5781fe31d1}, gfP{0x43aba0b6688686ef, 0xefcb93e78344c172, 0x914b85c02a9e6a22, 0x8f588eaa9ddcc7f7}}, gfP2{gfP{0xe776482216545ea4, 0x634a0ea61d4f0e27, 0x6cadd71a1d72873b, 0xa158e3421a69e9d8}, gfP{0xf0b8f458d7cfa3af, 0x5604fe26856dfbf1, 0x43a5597c2b9c87e0, 0x5e996370bd614989}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xf79beada1117386f, 0x852b0b5606924120, 0x2b1297b8489c20f7, 0x5b031d32abe8d527}, gfP{0x60cd5a978b2f389, 0xc4c8dbb5b10e2116, 0x9344c76f17c64459, 0x903d5f7afb3e6741}}, gfP2{gfP{0xb3332a851af918fd, 0xf659f912b1d8a1ba, 0x2df7d98514affcfa, 0x633d7faafa207cfd}, gfP{0x26e17845739907f6, 0x2d405347c7c137fc, 0x6f0499d525f28980, 0x7615c9939f2bcdbb}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x78cdc00b3d171f58, 0x303917b7173f5134, 0x662462a29690724e, 0x90376960a96d38ce}, gfP{0x4f549a3839ba64ac, 0x69434c409fe89b96, 0x1fa1f062ac0b6c74, 0x364f391a7a74a5d7}}, gfP2{gfP{0xe49c7e445e1fe07f, 0x8c5675a69616b5d8, 0xffda67ead7cdbdd1, 0x4b4dd1dfcc644cd3}, gfP{0x9ddf81d78365993b, 0x3d15b5976e477986, 0xe4f276ee51526433, 0x274aeec28f258bd3}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xb1b3fcf5b806fc85, 0x70c2cded0caf3f86, 0x181a71768791c401, 0x6f05ca7f1d1c78a4}, gfP{0x91450a37c4e33466, 0x15af74220c15f281, 0xd4385f1a8ee00686, 0x41a79848ad0b6008}}, gfP2{gfP{0x60560131845419d2, 0x9642ff063bc2ca1d, 0xb0fb3fcee16b8136, 0x403e322463a381e4}, gfP{0x65fbb73e79d9944b, 0x393ce1011d79bf64, 0xce08104883111bb3, 0x43b17b70ea1bb11f}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x8cd43ce0d26a6e5f, 0xe38f496bc08ed3a1, 0xcf566fb204315c68, 0x842b5c5c2446f796}, gfP{0xb36d8bdd7c2eca8d, 0xd38854df75b023e6, 0xc4cce4a580b87fa6, 0x57df60d29b6dd58d}}, gfP2{gfP{0x81592478760dd45e, 0xf76c6157ae4bde56, 0x41dd093e288909f2, 0x6b54b373d875403b}, gfP{0x13d6e6b9435fea41, 0x6db36301081b6c5c, 0x6b69de1cfab3cef4, 0x579910da9249afd6}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xbf9f7124ed650f38, 0x59bd22509929b105, 0x6f368729077c56df, 0x230575d367faa2da}, gfP{0x6487e34d966b2f28, 0xc12b1d83f394d6c8, 0x133fa6ebcf57b85c, 0x6d7e14bad12b0bfe}}, gfP2{gfP{0xccbd38fb03652434, 0xde5be2a010944b95, 0x7dda4aa61091ff60, 0x893e982eab3c4aca}, gfP{0x6c2b3a516c43ae9d, 0x417190536e2ad81e, 0x938c2694ebfa3a51, 0x43f2a0831f5ab063}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x707e38255cba3320, 0x3c56d0d77205aaeb, 0xac0e78a6eeda4a92, 0x1282b007e7fd3d96}, gfP{0xccf1615a620924fc, 0x2c57634b61b52923, 0x291098ffe602df32, 0x748cdb2f55802070}}, gfP2{gfP{0x8b5bd0df9304bff9, 0x20fc9d21feba1e37, 0xa88b5960034ad1c6, 0xb0200aabafe7d779}, gfP{0x496e9a151103318f, 0xb1ccb572d2801ba5, 0x8b4221386108a523, 0x753f8dd4ccb1c552}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xec2a24073c08c034, 0xa6f14b6c3c7b2f65, 0x36c8b74f0423c0ee, 0x137f9832a7f53364}, gfP{0x76426dc12505e470, 0x4e7483d46fa1670c, 0x59c6ea7cb43bb5e4, 0xc5abcd3d966c087}}, gfP2{gfP{0x21e817e02f3f0474, 0xbebb3f8f0899627e, 0xa8390521471d4043, 0x6606bead6b84bbdd}, gfP{0xa1c7db59497551df, 0x129f8a118cbb37dd, 0x8f521ed8a76ee64, 0x7e809b108fee3793}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x50ba66e9338b6cac, 0x1e684372164fc05b, 0xa67be202d4823c4b, 0x24a3d4f4895537ac}, gfP{0xcb46a5f5831f5289, 0xc086dd486745fc22, 0x61a8a0cd3863c443, 0x238817954155f852}}, gfP2{gfP{0x5eff5d784bb147b5, 0x76d5d0c3eb5d138a, 0xeaaf833172f55a6b, 0x56313bb333867462}, gfP{0x8ebc2da8b2d096f4, 0xbc676c804a12a429, 0x133d8f032eb47849, 0xc13d6684baeb412}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x7fa8011696f7f0b4, 0x9ab20b69c34b2a9d, 0x2b5f9b23bb582c3, 0x7bb303fda9f61120}, gfP{0x5fc6ebe71fc205c1, 0xeaa5ca080d434639, 0xeb314389b2087b65, 0x1c02f2e1a591aaf4}}, gfP2{gfP{0xa4f20b9696b9c1b5, 0x7f71b802072d59, 0x3153c69b8bb57944, 0x59cac863445048b7}, gfP{0x943225b9fc565a7b, 0x15e2316f561ce8b1, 0x967f6264da8436cb, 0x50cc52fcccdb456c}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x597fec5cf2e6803e, 0x59fe2057de205af6, 0x4b74e37a2c8f5256, 0x6e3572ab379cc09a}, gfP{0xda0971adea469bd4, 0x2f766d28f78538e9, 0xe1eebe800c188bb2, 0x45a010b257ab1d53}}, gfP2{gfP{0xa97f5419c24c18b0, 0x41be5bade8ef9fbf, 0xcadc6cf953c315ec, 0xa3c70767b4686fde}, gfP{0x8f5f871b6db06afa, 0x2b2ec2b9cec4d043, 0x81fd2d40c8b114b6, 0x20ef2cfd591395b5}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xd40776498ddcda7, 0x57068b66930374bb, 0xd7fdc21fbb270b42, 0xcc80c6a95e54c5a}, gfP{0xb3292e7b2f59101c, 0xc86a6890e2916ca3, 0x502f6653495cb530, 0x21571b45b127bba6}}, gfP2{gfP{0xdeab89d6e35136dd, 0x76b8014643b0b86f, 0x3ad2e768ae55c226, 0x7748147566286e28}, gfP{0xe57d973323b8b, 0x3e0eab7bcbbdff63, 0x84bc8f74d53b81eb, 0x9ae8cb1d13d7aca2}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x20f12f9ed2d753b4, 0xa0f0085072abc32c, 0x709db8fcb4dbb565, 0x335ab5c5d3278972}, gfP{0xc4ee69e47f4e09f0, 0x364038b84ad8345f, 0x2161d9d12eda2779, 0x6b3a595aafa68280}}, gfP2{gfP{0x9f808978abd129e5, 0xc514d80df814407c, 0x9a4ea35bd5d100a, 0x1aa5c4ed2ccc2d29}, gfP{0x74905fc168821d05, 0xedf8fc65fb42c235, 0xf1c85e0ff7b08420, 0x9291099d44eae3ad}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x67d5bc69bfe5aeef, 0xecbe858830b0ccaf, 0x8a678185bfeba120, 0x2dd0964dcfe737ef}, gfP{0x236917992629a215, 0x5c2aaa392776e016, 0xc253969c6ae88cc5, 0x88220cdfb83885a3}}, gfP2{gfP{0xd173c55d49786e28, 0xd84dad65d7699594, 0xba520de6c27e676d, 0x34d5bea5d8d76ab7}, gfP{0x652266ba5c526150, 0xf2cb90f8f72a40e5, 0x6f7c1e4e7026ffcd, 0x72bd64cddd129d5e}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xef34aae55751b860, 0x922b9066ab8279b3, 0x98fff7d447bf8887, 0x65fe2941039ba7aa}, gfP{0xba211ec76aa9535a, 0x52acae80a85939f0, 0x4ad2a15574f4da44, 0x18d8c815833addbb}}, gfP2{gfP{0x309e2f53bdf39fff, 0xe67f79bb9dcdfab6, 0xdd80e9d898dc0003, 0x907b8ccc8f575736}, gfP{0x4f49edbdac75bdf1, 0x59b2fece02751dee, 0x3104a5d7a28c281a, 0x5930aa4fad08da13}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x42947d3fd1ac9fa9, 0x918bdb884dbc16b, 0x5b71a60c4d8a7805, 0x584d3d7d2932de4b}, gfP{0x59c77893efeb999d, 0xd6667483834a1883, 0x404a24abc33c7bfe, 0x631b1de520e30681}}, gfP2{gfP{0xf2b10991e6f54155, 0xb71c0c132cb6fd79, 0xfa3b7c165c62120e, 0x1843061392780b89}, gfP{0x52ee4897ba28f804, 0x2a1a3a5fbda33046, 0x82ff4ba924da3853, 0x49df277828687e88}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xaf8f6a89b3e3630, 0x5764d4f0c87bae5a, 0xc08ce968d2288419, 0x3a041ef93fa4a206}, gfP{0x24a59cc1e2cb6154, 0xbfbd16a6c3a5dcbd, 0xd87d94f47e808bac, 0x13c4a9800a4932d7}}, gfP2{gfP{0xa106b7b8853c7f68, 0x75582b2c8734d61c, 0x242fb193a07a267b, 0x890aefc8fb016ce4}, gfP{0x856f2daa103d11d1, 0xd527c42686324aee, 0x8e73b2b70cce4eaa, 0x7870298af9351c21}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xbe671c77131f0877, 0xc6d9ac261ece3891, 0x80e48176a86e8fe, 0x9dee5c29fe8412e7}, gfP{0x54f04d7d5c6184c, 0x124e086dbf138645, 0xca30ae129022bf00, 0x22a070cc8b5770a0}}, gfP2{gfP{0x1650ed9e3e7620b5, 0x41464d813df837a5, 0x3f0b9eeff8f38411, 0x310de7f2826365f3}, gfP{0xd0fccd0ceaa7835d, 0x39a9a33316f3800f, 0x129eafdffea0af1a, 0x1a69e4c79c9bac4f}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x541a975c5b9f8898, 0x8ea59a18595a32f2, 0xc01db9116e58c271, 0x800bc9ca814e011c}, gfP{0xddaa5c5f5ba99b73, 0x31dcc2c07c27e984, 0xe0b3e498f4eab2ef, 0xa083ef0e976ed888}}, gfP2{gfP{0x4e4f81af53e78661, 0xbe51a318f2291906, 0xc8debbd36132a009, 0x59bf083d2faf3f64}, gfP{0xf24508616b5a16b2, 0x661e16957bbfbee8, 0xb0255053557e383e, 0x5cd1618558fa246b}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x1a309f75508249b5, 0xd8f3a2a253b6b935, 0x13a217d2559a3b7b, 0x2a8e56430fe70e8f}, gfP{0x63a1b4bc56205731, 0xb80460ccbf77750a, 0x16c74b9890374c7b, 0x395b064d07b43a49}}, gfP2{gfP{0xa33aca2e633ce11, 0xe70a3bf19f5e6742, 0xba837a648142ce94, 0x27992eb25249cb2e}, gfP{0x32d5d107ab10a8, 0x3e19533651f81f96, 0x3979e64b863103db, 0x14a2b6936ad67b3}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xf1708b5aa33a5c1d, 0xb2f5314bbd56f2d3, 0x7110bf0a202ec002, 0x9d239b69b2473e8a}, gfP{0x50c5c3fc8f619048, 0xc56e8d3b3ad5ce62, 0x2cc8bd0a15e514ea, 0x1cca67e8293caee4}}, gfP2{gfP{0xd05caaf126f16b12, 0x7f36622bf6c10c5c, 0xad197d69ec1e0670, 0x2fd416f6886ca33b}, gfP{0xa7ccb12cde7aacbf, 0x31fe6f21591cca59, 0xac8e91e0d6208681, 0xb1055c3c955dbcd2}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xa65aff77f1ff8c9f, 0x495130690193a0c1, 0x326f7c2df24f0724, 0x137700ee10d7be23}, gfP{0xdaa5540966911a61, 0x3b894d273c55e, 0x7cd976b4a0033907, 0x1d89e7d00268f848}}, gfP2{gfP{0x727a5358c1fc6b88, 0xf8bfcfe280c8b3b6, 0xa8754d9e25632336, 0x5dc590318ad9912a}, gfP{0xb15b685670edd26d, 0x270d731c52a9b347, 0xad19fb265e7afb4e, 0x20478a6d43dc002c}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xac0d9304c1f3d5dc, 0x82c9f3d54f8008f6, 0xf53200ee1f039df5, 0x4da2d91803133b6a}, gfP{0xfa831a041695ccda, 0xd50a85b15d2e264b, 0xa2ba2c762b310c40, 0x2a156c760da50aba}}, gfP2{gfP{0xf4459d7a671bc203, 0xafca57db14b384b1, 0x5b4ee2042d02c1a, 0x5b780bc0b81fa003}, gfP{0x764821bcd6fa26fc, 0xcb9bae0ca28b73cb, 0x182068b402fdfc29, 0x1fe105de16f3c1d4}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x9c1245c26c25789e, 0x600b12f323bc3bb0, 0x10956f5915bfd35d, 0x22d53178ce07dd81}, gfP{0x8fe6c5635ed48e53, 0x824ab875388d2816, 0xee4ccf7777dd1ade, 0xab64550f62894cf5}}, gfP2{gfP{0x5076de93e13c371e, 0x634a0c04db8107e4, 0x8fbbbbe5d6a689b6, 0x75598547d4dd99f9}, gfP{0xb2dd7c8f857d43fb, 0x60d93dd08ee15284, 0xbd05f14ffa2aea63, 0xa6c9910bff378302}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x96ec07a9bf1ba04b, 0xbdbfb902bda2fd58, 0x9a8cda2cb31baf5d, 0x78260ad6061355b1}, gfP{0x80d712003624f6bd, 0x905157d26d089b8f, 0x4633c00632b9155e, 0x60c9a765acfde594}}, gfP2{gfP{0x401c5e36729d4414, 0x414ffb940c605833, 0x751bc03b71902771, 0x8576124b96cb02ce}, gfP{0xbf8eed9d5f2c4702, 0xb484cd78537eeb17, 0xf3a55d21f52d1ac9, 0x233b3a92c20a0267}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x728ab53f1dcb938e, 0xdbb3c634535c2fe0, 0x72afc1cb0bb5cc1b, 0x9f505831f43d6760}, gfP{0x7d884f11cb0c1f3, 0x8e62b43cfe04e4ba, 0x895e1c04f92b8685, 0xa43fbe61b8083e8f}}, gfP2{gfP{0xff1200e287e7e39a, 0xc7a3da4e9ed99ea4, 0x936970a82654cb46, 0x38a7b0cbea7a3aa}, gfP{0x804e85ee10239a9b, 0xb39dbd1cc0d262a4, 0x8b4bfdb80cc3ff68, 0x4915be45666ec995}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xa1aacef81f378b21, 0xdb6184b42338b70f, 0x3a8d3b7285660863, 0x26cc0fb97cea1bcf}, gfP{0xc7adce687dd9b344, 0xa7c9a76e1fb7b8d2, 0xbb00fe5d30d8f129, 0x4497935e85b03721}}, gfP2{gfP{0x6b5baeb56b0f8457, 0x1ad9e98122988caa, 0xd16cbd87465991db, 0x8fe182705fe062f8}, gfP{0x9d6272b12362dcfd, 0x68fb817a6348433b, 0x959793ac65c768cc, 0xd02c1f0783fcc24}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xae57a0253babf011, 0x991ae6cf7409b5e7, 0xf4c2223d60b883d, 0x37c8c83d050455d8}, gfP{0x6518920da637d92d, 0xb36bf65c933ec0e5, 0xcf59be258159783d, 0x98f4e7bad889a5f8}}, gfP2{gfP{0x902f3e4c98158319, 0x628bd83861cc3149, 0x87a8fc0cb1c366d4, 0xe9cacdbefb29985}, gfP{0x7821076cf3b50a32, 0xcc17932f310fdc94, 0xb64f442b2228ecdf, 0x35472caf57ce6c4b}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x8db842972d1ccdb9, 0xc6ba83adec7931a6, 0xa21064042c30cf2d, 0x55b390968ca152b8}, gfP{0xb483fa629688c3c5, 0x2edd28714f7fa43d, 0x18fb2e7b54f473c7, 0x6db08f5ba5d10430}}, gfP2{gfP{0x8832d06530b2ff66, 0x72255fc4367680ec, 0xfb0a32952d9995ee, 0x5146c437a55edf08}, gfP{0xf18665b51b803016, 0xe4a8614befe178cc, 0x815c4392dd6448f3, 0xe390756aa7100a6}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xdb53a4da52c95cb9, 0x4a4c7c827a12e73, 0x4d0cb0c4a4ed2773, 0xa2c2a05b688308a3}, gfP{0xa6dd23ac42085915, 0x61ed3343e63bccdc, 0x2f27ff2a1a725bfa, 0x731338736bcd7615}}, gfP2{gfP{0xd113110c6405564d, 0xf60b0cafdb29c116, 0xda0291300b82d6a0, 0x575d02a61dc8e224}, gfP{0xddfe4b80796d88c7, 0x91523c14bbd367c5, 0xb05582e7eea51623, 0x833ed2a59652578c}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x1c61850159ab98b5, 0x62caeaf0261648ce, 0x78fde1a7bb29ce5b, 0xa2d8bf6b31d57696}, gfP{0xd273474631ddb25e, 0x21ef770c9c8f8898, 0x993367085d7a26f3, 0x732cdca3f845de6b}}, gfP2{gfP{0x672b0a716d8f506a, 0x5bd12bc0dff6d5e6, 0xfda373f4d874fb3b, 0x79602bd9c04952ef}, gfP{0x53e9a1fdbacab34e, 0x2172015aba33b0b3, 0xb8d4ae896925d47a, 0x4b7acd646315cbaf}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x48e482d12f83c159, 0xd8ce949ddb246770, 0x4c59557a13e8f6ac, 0x9a6d78e645664489}, gfP{0x7a14cf6e2f2a8071, 0x89657f35262aba7e, 0x7c5b8802e23cf076, 0x69b725f1554858cc}}, gfP2{gfP{0xf4b7a9c64f2e6aab, 0xb9abb8c208699437, 0x3c171bab18cc448b, 0x4df67584af8346b2}, gfP{0xc5effa88c947b9be, 0x7c91d91f05ac235b, 0xef97aa8e14e1e463, 0xa2739ecdf571d01c}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x5410847ac1273d75, 0xf181b7e6a595b374, 0xbe08ab7c97d191f1, 0x51e8175e005b4118}, gfP{0xc2c110eec398c5e3, 0xdf65ad36f29dfd9f, 0x6ad32f7552221efa, 0x510b3115c6b66700}}, gfP2{gfP{0x424e10a69c45cbf7, 0x303a60a0c40989bc, 0x8d029e3dc697cdbd, 0x51ee947cb5dc240c}, gfP{0x92e7234cb1281843, 0x904d376b49d53e28, 0x1107c524a206dbe3, 0x9e2cfd2d98d0e6de}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x5285c3af096dce84, 0xbdddac64f2d39c5c, 0xb7aa8a6448048778, 0x4078c13ec8bd331b}, gfP{0x48632900686f252a, 0x8ae8010c0500db67, 0xc93763d851e2de99, 0xad042148fbfa8767}}, gfP2{gfP{0xcf8cf6498948e18f, 0xe05fd5659a63c06d, 0xf865810d2f16768, 0x24d7c543601204d0}, gfP{0xcee8ffa251567ef7, 0xca78d3598757de4f, 0x29765c361819c6f6, 0x85e3b1fa96109d46}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xc27e49820fc1a341, 0xbcb8de9b19471752, 0xfd703f5f14ee4e9, 0xa9d8e27cfaf92a3}, gfP{0x6722a9aad5197722, 0x371ec3d1e7dff390, 0xcbfed36d612921a, 0x43d6ec7a072e8a85}}, gfP2{gfP{0xf4e018a860ee0c33, 0x1993089f6899f873, 0x356b782d234ff8cf, 0x368d555aa5db9eea}, gfP{0x6625a381a34e15cd, 0x1186e12a31454a66, 0xa55d4b64a2de400f, 0x77ac06a1e4de6e3d}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x1880516c57de71b1, 0xfe8975b5754df372, 0x88729f8e99e3dd6, 0x3012d778ce150355}, gfP{0xc91139d874831a8a, 0xb006dc978160ca60, 0xb87eb59187fb9289, 0x992da913fc94696f}}, gfP2{gfP{0x173a79909d886bc0, 0x28f43c88b388237c, 0x45b33281a575b871, 0x79cc709028004e46}, gfP{0x553dfc0caf295f6b, 0x73817ae65fd2329b, 0xe360853e9f7555dc, 0x73a4d932875fff29}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x9d9790c829c61874, 0x7981abcb8b70ccd6, 0xfc82ea5cf7563a1a, 0xa9e8af2135dcb276}, gfP{0xc7111d1814e6fcbf, 0x4ba20facf411f760, 0x2197ec49545813e6, 0x7440b5560cf00e44}}, gfP2{gfP{0x77ef5c491256d946, 0x231f209a5a0d29cf, 0x823fefc011d38ab4, 0x29ef148701fb0783}, gfP{0xac67a576447df05d, 0xafcc866c51137de, 0xba44a5e4c5972a36, 0x692404b1b5de8692}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x3e87b14ec6c74c9f, 0x43a54299d32f991, 0x7ff93d0da3f39240, 0x459d62a32b210fda}, gfP{0xb2bec758eee3230e, 0x3a603b3c27a1880, 0x334faa1926c23c39, 0x9d99d26434df8bb9}}, gfP2{gfP{0x762d136aab1cf276, 0x4ec0edc0e4341ec, 0xab0a9471c092f4cd, 0x34a20a8607c6c83d}, gfP{0x7721af4b9c91dbc1, 0x9508c5dadbbc3009, 0xb9c60929e81d08e7, 0x48720a4fcd7d6f25}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x8256216bc1ec7816, 0xa0497d1ca439626, 0x2f59cdf4d4cecf20, 0x8388a4968ade98d7}, gfP{0x8764047c2af7bf99, 0x21a0007b96c9f342, 0xc1846ab04d0dd726, 0x9bec1075f5d8b03}}, gfP2{gfP{0x90e2ce0dc8ad27f7, 0x63f4c6624cc25cc5, 0x25269b96c8a862f3, 0x9cf64b981f603d04}, gfP{0xc932207b4dab6173, 0x3cfcc758ade3ac78, 0x59714e9c8950b844, 0x4c3102ee262f7e4d}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x45833d035e5fb6f8, 0x34ec5ae85e232648, 0x848a048c223fe34c, 0x8edd03f41d33d857}, gfP{0x2c4f1f25c73460d5, 0x5c4a9120679a3b9, 0xd04dd7af73dcab91, 0xa1aad08b520820ce}}, gfP2{gfP{0xc7f01041168d582e, 0xb085470becd0f19f, 0x43dfb07975f358fe, 0x4d9a078b1de88578}, gfP{0x6ef02dd335e501f5, 0x77d3db5e6ec6a059, 0xfce6d50ab5fadf44, 0x2e7eccb26bccf85e}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x75a7e31ab4a9c18f, 0x375910c636af669b, 0x87db9eee79d0f12b, 0x9414f6cf63bb3036}, gfP{0xa12989f771c22474, 0x954ae31d6350d51a, 0xe49ff2d0299e1ab, 0x45f02935f1f792cb}}, gfP2{gfP{0x57e7c41a5467a90a, 0xf2a454fa7835d8a5, 0xc4d66bb126016e9e, 0x6ff70311a7706335}, gfP{0xa9a4e53ce25428ea, 0xd92dfa5d77608562, 0xfce9e40e29b4bb77, 0xa36876a2463a46f1}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x677990b76f62f36f, 0x7a1d8ebc5f77d885, 0xfe4c076ecd878af5, 0xf7aa28eda4a961}, gfP{0xc589e30def6e8ec7, 0xea9b6eea1765b8ac, 0x7ffc64f9bdd7ccb7, 0x34dc4d92cf0a0b47}}, gfP2{gfP{0x36808d9be2d9fbeb, 0x290e0a853091b107, 0x2fa95a3f4a69df1a, 0x31b5cc13362ec07b}, gfP{0x39c7534ad7020453, 0x6c1cb71fe9704403, 0x9c0a603fc8c71219, 0x5f51d9e29d4dca94}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x6212a533f82ff7b9, 0xbe6c682bd5fe5ec4, 0x54f0f31a0fd6e803, 0x51f950a0675388c3}, gfP{0xdee09665d0588f3c, 0x76c24819676029e6, 0xe446d67e7507fd3c, 0x8c07afb957308b4b}}, gfP2{gfP{0x1bddc64735fb83bd, 0x7553c61c1c67f234, 0xe9cd8bda808133d, 0x2cdfbc06d0d98023}, gfP{0x9001cde2d800b8cc, 0xc556714a102a5565, 0xd1985402b6b3ada7, 0x50beda9025239c40}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x17841ace8eeab62d, 0xe200c4860f599021, 0x7bc6eaf5d038f1bf, 0x7933b6575c7282e3}, gfP{0xb7fead8861688b5a, 0x54de48532e4e7eaa, 0x99aa35caa1b6cdf9, 0x4a0a16ecea623172}}, gfP2{gfP{0x16a6ca64cf12ecff, 0x93827f74277e716e, 0x542a28f0810cf195, 0x8910664561d2f25d}, gfP{0x6ff298617738193f, 0x76075bb976b83162, 0x7ef8e014a2a44597, 0x22b75d6b1f39d2ba}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x22c263bad913bf4, 0x4945379bcd62e6f9, 0x735e0c06bc744d1a, 0x66c22761377f2859}, gfP{0x720b7e9c4f267994, 0x1f6406ea11340fad, 0x7bbfcacacdd4aaa5, 0x1cdcfa2f7a452df4}}, gfP2{gfP{0x1955b570e5818777, 0x3f7c8647e1c8297e, 0x17acebff04681e0c, 0x65e5ec7626b5aa2f}, gfP{0xb72d65e2f1e27d7f, 0x2bab5045f4d6c986, 0x762be006fe43b135, 0x7dbb559675fab839}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xffc97c19ba32b669, 0x5386e458f2612f25, 0xed7322998a97e160, 0x9daa4c7f08d8ce84}, gfP{0x7c095f326dd9ae95, 0x423ba701e9469fd5, 0x75c8782986d2d604, 0x8aec96ce9dd51da1}}, gfP2{gfP{0x90de8f478ed70b56, 0x81b8d0b84946f262, 0x951ff1b265272acf, 0x4314941fdf52fa04}, gfP{0xf251fb574473f81, 0xbe5abad146e34763, 0xe20678443fcf808a, 0x917d8e0fd48b528c}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xa3059b9d6bb7a34, 0xfc2ea6660a13f2b, 0x3b6ef06c13801a57, 0x9e5eec8e172f0db7}, gfP{0xf19a18bc7db8cfaf, 0xdbe9a7158b714a60, 0xc8b442fab5b95aa6, 0xa66a6ab302883e31}}, gfP2{gfP{0xed6657fc8bd85687, 0xdef82c5fe73182fb, 0x83b3a60f189dfe0a, 0x76cb3997c41ac1f6}, gfP{0x6c72bd850e4411b2, 0xe5d47d39466eb2b0, 0x4c54c84340a63d04, 0x6b078bdb033d25c5}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x44dfd304ea97bd61, 0x5831cc9716df0a1, 0xdea2c245e733abcf, 0xa5745309a9fe46a9}, gfP{0x70444b63a7638996, 0x10ba02e382ab976a, 0x809d6acce3f667ce, 0x47568bbbfbcaa273}}, gfP2{gfP{0xf143043310ac05a1, 0x6f5460b373e4c75c, 0x67765d23017d1b97, 0x7fc9822017ae7398}, gfP{0x1c52e6d83d908c9b, 0xd5d5c1a94df649d9, 0xf794197e0a3775e8, 0x194d4f02ec2c5277}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xb5cf27969bd5a88, 0xe80d618e0a9e5e81, 0xa59c8db8b60b12a6, 0x597c7eda201ac227}, gfP{0xf773bb4aad7de75c, 0x1091e7205acb5248, 0xdedf8fe8bbee2652, 0x183575193f0d3117}}, gfP2{gfP{0x9a5ddf4de59c1142, 0xc72de06d256c8968, 0xf11f23b627d519bf, 0x6d34e888aac65b71}, gfP{0xc5c8a0493ac9c8a8, 0x59a5ddce3f8a9f47, 0x5909de679958f7c7, 0x67cdca2ab88c0dc2}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x1cfa44fdf3f1d004, 0xe741fc6a85a72d51, 0xe9f9174332d45bcd, 0x2f05bf984000a8fe}, gfP{0x594f196575ee5e32, 0xeb24af8042453799, 0xf28562273b511501, 0x846836578cae80dc}}, gfP2{gfP{0xe83bd59624fc015, 0xcf569688a03610ad, 0xbdbb40ab24fedf65, 0x6bf1b20ebc9dcb30}, gfP{0x308819a492facb8e, 0x69d4d1901e6a73fd, 0x61907a88c8ab2674, 0x34f35c8275ce5463}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x2040415ac79b4696, 0x13c5cc4503295e6e, 0x3c9f4eaacf3b7bf1, 0x54461412a5e0bf11}, gfP{0x5e97375daf390a69, 0x31807cc5b42eb8f0, 0x9c23d5bfc3afa75d, 0xb2074333837b4e54}}, gfP2{gfP{0x32ed06efe84b5326, 0xee921aa72faba8d9, 0xb8dfcf740b59f80a, 0x1577de1cd77e0601}, gfP{0xd68ce53fcc557d10, 0xeda56beac8114b5e, 0x686cd858abe756b1, 0xb5fe5421e284f83}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x69f92dc147f15dd4, 0xee56428414fd8fb5, 0x191caa62f0d01d98, 0x2a7160ecd1676506}, gfP{0x9f2340123ce05602, 0x4e43b3fb02550e, 0xb434400991c9a7bf, 0x25cc746cd6ca287a}}, gfP2{gfP{0x4620403d17a57cef, 0xf79d80031254b874, 0x1a23402d591d3c33, 0xa60ba69aba42e8c4}, gfP{0xdd3e089ee82149bf, 0x1b65530108682343, 0x6d8080d85b195a02, 0x6e0050b894cdf1c3}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xc444accb55c5d0c4, 0x264ef4f84255478a, 0x9b011660b3c28074, 0x6a96f887aea15ec5}, gfP{0x9dd9ec8629b77b47, 0xecb45b7d0cdc3c85, 0x61eaf78d6ab8427f, 0x798a8faabeebb699}}, gfP2{gfP{0x46bb31209d58f92b, 0x8c8dfa6c3c2285f, 0x9bbcd183a7cff503, 0xab9d7258d3a22d5f}, gfP{0xc44a915c364dde5d, 0xfa20d0e54cdd8d5b, 0x8409fa06693f77a2, 0xa46bb8777cce3c57}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x36bb81b7db4dc3c3, 0x7c182dfc8ebe9a02, 0x6d13121ad8e53e51, 0x3efd537d8a8fb660}, gfP{0x4d6012a5ffa66efc, 0x3624431d841357d3, 0x739a72393defd397, 0x26de02513b629595}}, gfP2{gfP{0xdad7e54bafad46, 0x3ba20967387d93cc, 0x8b893b4c5fc65cf1, 0x3e91d51418b87c30}, gfP{0xdce417d55b6d261d, 0x25a246402988caca, 0xeb304ede58904b9c, 0x817455f200b81ee7}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x56cbc76d9a2f2c41, 0x8d4b102ba42e74bd, 0x92a6da6b788f1193, 0x153886ac7f7c4b2e}, gfP{0xb4087999ee58eafd, 0x123a100313d5933, 0x30d93b3562c15846, 0x3f745c2a34bfa424}}, gfP2{gfP{0x320e0456f4a337a, 0xa627727499ca5836, 0xd730c4403d804b33, 0x56fd3993039a3535}, gfP{0x32450966cdd53c59, 0xe4f04f5d86f797a0, 0x626cd21426823ec8, 0xa7d96abef6a74894}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x8152e3a4be2da97d, 0x26fd598be809e1, 0x205c89d30fbe32fd, 0x92db6bee14192c77}, gfP{0xe439cd5a16c45b97, 0x7ed068a2ac084c14, 0xa48565f261f222e4, 0x77f185c3598ce818}}, gfP2{gfP{0x8bdba865fbf2de2e, 0xcaf7ea2d639807f6, 0x4a5646f92d68cf19, 0x25bc1db5d4a57f04}, gfP{0x5b04213e838f5899, 0x36c35b4e8a68a2a1, 0xdfc0dcc3985b6fa0, 0x44c258eebd37d343}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x931cd6852a80dee4, 0xf135724687e401aa, 0xce56c3cdc2c87e74, 0x1d8d9f30175dd951}, gfP{0xdcbf8bd11725990, 0xc74afcb51ea7e377, 0x8b2df89ca0178d5d, 0x7d50cc9b42072bca}}, gfP2{gfP{0xbc8ab75a712a6c57, 0xc1357fc30076508f, 0xe698c36d77de35b, 0x5f63872d07e73db9}, gfP{0x3b3252c9ec335d13, 0xbe3d1563b3d89bca, 0xe2a0f5c8170d8781, 0x36677d17c90be7fa}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xa142e768d4521c9, 0x4dc31ad88e48ba7c, 0xfcd9be9ed7963186, 0xae2ca3a95233da92}, gfP{0x9e36f51c12496802, 0xb925c65452c100c2, 0x6a644be75729133a, 0x68bacd41b702cb6b}}, gfP2{gfP{0x92356c8c7ddb0cdc, 0x6fea6600890fcb29, 0x117282f05bbba2b3, 0xae98bd358f73daf1}, gfP{0x5f20911ac389feb1, 0x648682b4ea0d6124, 0xb0a1d03a2f4dc1d5, 0x9dda6fced9202106}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x7842a0d4989ec21, 0xf9a57fe6b23368ce, 0x5301c1ab153dc17d, 0x19fd6924b76146a9}, gfP{0x477e584715d748d2, 0x39442b4c138b067e, 0x32231fc446524017, 0x93fc582f98f36749}}, gfP2{gfP{0xbf86a0f0089d546d, 0xfb10fecbf1f64c4d, 0xc17049a35b8fad12, 0x6090742f2a15dfed}, gfP{0x3a41ed271e4ab4c3, 0xd80586ce37ac9398, 0xf1ad27b155812774, 0x2b75573daf5fb0b7}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xcd510da18ae19620, 0xef705159095bf140, 0xd7c9a3723baed5a3, 0x1691488893c3eddc}, gfP{0xb2d8674182108f0d, 0x735657f5d703712, 0x39f0e9f6fa17235b, 0x7a4ce7bd47277906}}, gfP2{gfP{0xec8637d2bbfeab47, 0xd21b3ee3f32b47af, 0x53f4be87dc80c4f8, 0x1dcac0dcb6433425}, gfP{0x8c710b0a9ee5e972, 0x605ab63faff4c855, 0x301406c9be4b59eb, 0x573e6d90373c1618}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xb403650ef36547f, 0xc3b7c6a89b814a50, 0x940af5758047a619, 0x4ee3c1e82181387}, gfP{0x9a7f3ca337c3a37f, 0x5ef3eaab997befb2, 0x50bc2901f424d345, 0xad48d4594df21115}}, gfP2{gfP{0x85f3db0035f23261, 0x4c513528194c06f5, 0x4b5838e2cb10f6ac, 0x275055fade061c86}, gfP{0xff578b6d20e0ce5b, 0x6d0682af3d7be44f, 0x6a36bc6e71889d29, 0xb228c4e33aa4a4cc}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x19520f5c22318d8f, 0x9c9e82c3955d30b, 0x9b430fecb5c37685, 0x7be1f9100fde3b8a}, gfP{0x3050a976d7a6ebd4, 0xb4cb5c561a36a317, 0xec7176aa9511e7d, 0x1e8b40ad65bb88b1}}, gfP2{gfP{0x8ac564a01c10a84c, 0x543b966d1d78268, 0x36fcbb6e56d7ee12, 0x1b60f800ff429f27}, gfP{0x481d9a6178b1a157, 0x24d4b27ca2c314f5, 0x37b5760e753dc4b1, 0x139bf2b58e96a43f}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x7068ac849e81adad, 0x6ff03ccfed4221f4, 0x48f973f0e2a7a33b, 0xb2cba9f5d0d0d2f7}, gfP{0x7a6854f53c0fc811, 0x4633b895c432a320, 0x673030503bcb4f28, 0x5d81755fc315b59}}, gfP2{gfP{0x3127044d3d8ddd83, 0x703c0b31794928c0, 0x62608d9713cd810, 0xa45e27ce09c16657}, gfP{0x4d1b94309b41f068, 0x1fbc93a1f9eb3d2d, 0xb03d80d2161d9383, 0x1774797553d3b2c3}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x38899ab996fae560, 0xdc55b413e8d38a, 0xd8a7aa86953b93d, 0x80ad297e02a5d226}, gfP{0xc4da812542a7ba9d, 0xfc1478da57f3ae7c, 0x28d0a1cfdb531da9, 0x82378b5fde094553}}, gfP2{gfP{0xc5c3b0b986e0824d, 0x78ceeba8bcf05bff, 0x21222706d06c617e, 0x7fc1452f405f92ca}, gfP{0x41d46527c3c44ce3, 0x4eb39ccfd4cd4ce2, 0x76437ae9ed32a9c4, 0x11a08b0c19d1f07f}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x8b21941e9560d0c7, 0x118ba6ec7c855595, 0x56c1ade4aa239f, 0x330b7d4642f5b355}, gfP{0xbcff72540948fb0c, 0x543894937f0d8fdf, 0xc63f09f7257ed300, 0x2449e02787d9664b}}, gfP2{gfP{0x4f87cd5969c4eb86, 0x3ceaf3b9830b2be9, 0x890f070e6d9621b0, 0x9bea8dbefd04e76c}, gfP{0xc32bb705e82180ab, 0x82af753d24aa49ad, 0x31774bb847e5639, 0x2f620bd26f362762}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x323460ea43018341, 0xffaeeb1c749d61ba, 0xf57b0fdb8f8dae1, 0x5fe4c33e1ead7beb}, gfP{0xc767a4c79b08a3eb, 0x5bc826963960f639, 0xfab7623540ba624a, 0x35d7b173fc7a12}}, gfP2{gfP{0x92a93d8ee1586fca, 0x482b622341d0262d, 0xecc2cd54a8add772, 0x3b566ca290fa0cb9}, gfP{0xa66dca65d590257f, 0xe5f09a55fdb6eecd, 0xfee9b53a3f3b9846, 0xc65c0bdf7cd671b}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xc05aeba7e8dfe24e, 0x3655c3d14522c421, 0xdf39e52068d194d3, 0x2b4010254aa92425}, gfP{0x5f6d6b8bfc1a1324, 0x2291de492e42240d, 0xee44c133f861b7c0, 0x50418f821d2cc905}}, gfP2{gfP{0x2f825d6203dd2e0f, 0x43a13473e1af05b3, 0x9e88254d05b9a067, 0x15fc44cff855a7cd}, gfP{0xb811f09afd594c6, 0x434b140da46b92de, 0xa3b8120abbdc402d, 0x53424ecb6cd1956d}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x24daab9e8e84b9d6, 0xae79d00f98462b38, 0xbadf358e7b5bdd4b, 0x2383246b7aafced9}, gfP{0x183aa836060e5096, 0x815e5b762055e777, 0x3a00d6f11be4160a, 0x5f9bc8038af48471}}, gfP2{gfP{0x13d9c102d66331f0, 0x490408e3288dfafa, 0x3194d9be3d59afb5, 0x2106fb446b25a66d}, gfP{0xb1a2da582252a637, 0x45867ecf0e1e2639, 0x618baf853ed08ff3, 0x69f9b2cf24fe28e5}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x2e6381b1291dd7ff, 0xa6c8ceaa9ee839, 0x98f4a6ce90dab40, 0x7666f680a640edf0}, gfP{0x23975e236b410a1d, 0xd26afc813fc106bb, 0x59ff023bf7e92031, 0xb5f8ff20db816132}}, gfP2{gfP{0xdc702caa0234f0dc, 0x79cb7e1c86f13bab, 0xe7d2f5313917671a, 0x102c6359d30b8a64}, gfP{0x1e1283ed011d857d, 0x5ab6fa2d914b24ff, 0xe8137b5bc66a0cb1, 0x7d5714bc5bbbf7ff}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x7d92b81b5ea291da, 0xa09e3503d9882b34, 0x87bd7c9fa44e5ebb, 0x9caaa44cde3e9595}, gfP{0xed0d1978c38a38d4, 0xea69ae232ba21bf1, 0x8cb2e194e6cd870a, 0x5e81806fb3720fc1}}, gfP2{gfP{0x56c3d16e5bcc7953, 0xc075b61781ffc335, 0x9ef55df1c6eb5a9d, 0x7d905ca659541243}, gfP{0x1c8d7ad7c3acdea9, 0xc0357e9029770297, 0x19d07f2f30002dd4, 0xa0a780289fcf7d7}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x257ac1fe7e26a438, 0xce6b694e9d461d87, 0xd33806db97bd0931, 0x2c7da2b2149a857}, gfP{0x4ff0c799eea10d4d, 0x29bf1fc3a78bbe3, 0x77d613fb3a4f6ce2, 0x62722d7988de4a6}}, gfP2{gfP{0x65dcf4f32cda6d19, 0x7ef70ca143bf3ad, 0xb767c9cd8f42c3b5, 0x8e43deaea0d72a0a}, gfP{0xd98ddb2e692043be, 0x93c850e69e4320c1, 0xc79c06775938630, 0x4f327c9b3c6f4220}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xbe85b567927bc0bc, 0xa95ac10beff17cda, 0xf0b4a0ba83f2dbf8, 0x12f398bc57b5a4ed}, gfP{0xa20178c1df550889, 0x77150f1fe6ac31d2, 0x53872be99b352146, 0x46c8a8f1e76d6f7c}}, gfP2{gfP{0x2e9ff0ff921dff65, 0x9d1aaaf715068f3e, 0xc3da92045af8f3a, 0x9021e6337674511d}, gfP{0x37deafc2c3f5843a, 0x89b008168b682a3b, 0x914702ce21f28960, 0x8d47250f376522fb}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x4a5d0993d800bf7e, 0x4e682e95dcc7288, 0x20a494b62266102a, 0x1c5819649a4e237f}, gfP{0xd254d8e198d9ad93, 0x14f2bedb240177eb, 0x3c211cd565e3de1a, 0xac8b3e775f29b493}}, gfP2{gfP{0x6166c1103e29f317, 0x89f63d7c47ca1f20, 0xcf586fc8bae6db84, 0x60be1b8bb2081253}, gfP{0x3fc3e508a4d15c5d, 0xc7a6ddf2b16ddc8f, 0x1bd6ce83bc6d2870, 0x4cab73ca97118369}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x448d539a8866255e, 0x346e895f2a231dbb, 0xd61017bc1ed31538, 0x81370b94acfd3f7c}, gfP{0x5f443f5a149f94aa, 0xeb6b6e9b7613e317, 0xf4cd6d87cc4635c5, 0x4f3e13ee17dc0716}}, gfP2{gfP{0x40c6605f9862216, 0x4f759ed88cac1e4b, 0xe81fdfcae672fbd2, 0x7be7ab962a10ed69}, gfP{0xaba1d83900311e15, 0xdbacceb9890d48ad, 0x7b6e8b7e75bf818b, 0xb5ce5139478238f7}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x3ff47462c2e5cd02, 0xcb9399a724dcb3e3, 0xee1977cd1c3c3417, 0xb30e0057bd6965e2}, gfP{0xf4008c2e409fde09, 0x4bb3f44db7acdc4, 0x615995b3fcfb9e76, 0xaf456125f71e93a5}}, gfP2{gfP{0x49e4cc9738682367, 0x559b34ce40fe153c, 0x35b756afddfa3b91, 0x9ce2a2e55446193b}, gfP{0x22f0eaec4b7d4184, 0xc599bd45b6ffe4f5, 0x244ec74ea4eb72b6, 0x8f8b71748d26f55c}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x67d5bba3dee85e51, 0x10622393257cbd18, 0x7ec6db61a2024b58, 0xa6e9ef102a40f000}, gfP{0xd80746920d3c1be5, 0xe5bf9830b79cea5a, 0x8a6bb2b3eb0dbbb4, 0xb171dd2f1c746224}}, gfP2{gfP{0x4923e208785210ab, 0xfb44cec3c6e856a1, 0xea3dd5926dfd2759, 0x426c89fa13a02f41}, gfP{0x32366087ebba74da, 0x3065dec7493edffd, 0xa1d400a4bbc4eed6, 0xa664227d396292f2}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x4311beb741c619a5, 0x70ccf554da42f4ed, 0xe8cd572ce795a141, 0x6ff97faaf0f734f1}, gfP{0x4a0b7414aea72d5a, 0x3296f60569ff13e, 0xbed5c93f8b18a6da, 0x5040a8a2d4517408}}, gfP2{gfP{0x2e922e806fa53d0a, 0xdd9bfcab0a95c61f, 0x4ed7f2f02a06419d, 0x46086f0f2553f0ef}, gfP{0xe86332f4fa028e3f, 0x93f2e1523e4008fd, 0x81cf5b92b1995a2d, 0x4d95061f1addb445}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x99d4366cab1869ac, 0xd220e2eb2c50b7bd, 0x8dc7f9f7a8431bdc, 0x7eb6a128996971fb}, gfP{0xf8f044693ef26004, 0xa39bbf278f9331bd, 0xd63d5bbe1d2345a, 0x30132f43f676cb47}}, gfP2{gfP{0xa83682746050b254, 0x2c0516fac7e0503a, 0xd879c7b65b1d8c6b, 0x1c49259c23def54f}, gfP{0xefcad5af480b8fa9, 0x70485f2dc4a3f917, 0xa208ae07933328fe, 0xc1f3122745e7144}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xa34a638afc5717f7, 0x76e2f20657d033b6, 0xead30d559c68d5b4, 0x2367663a37815e8d}, gfP{0x5853e29ec6eef0dc, 0xb040abb67547a1b1, 0x85085b8a61b40680, 0x3672cdd7ce4ac07d}}, gfP2{gfP{0xcd5b1b6ab89a6054, 0x2f6dae52fe4691b1, 0x39fd65bd990085e5, 0x290686cc7dffd40d}, gfP{0xdaddcb7b1b7058c4, 0x20ed682658aefd16, 0x5898a1aa177488a7, 0x7518b630dd4f3e1d}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xc4f0f2a47f3a0aa1, 0x222361be9d1f9364, 0xf10ca8b295bb61f7, 0x1cd92b55cd98771b}, gfP{0x303c2a28c5b63559, 0x666e5fd4b005a039, 0xc07521c56c508336, 0xb4dc507d6dba929b}}, gfP2{gfP{0x8cd6390d705a248c, 0xb27193803d077145, 0x6b2179be8026f41b, 0x8902b12726b45016}, gfP{0x2d36169eb0698dff, 0xadd5a681668142ac, 0x2e7a2be2eb6d78d5, 0x8dc3e806a2b54618}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x262d7329b460cfa0, 0x2fbbfae94916ee14, 0xcaf1e93b4f07b248, 0xb495767b8b5e641d}, gfP{0x29f54d5d1660cc5, 0x792e18092038320c, 0x8e7a1acf39071e44, 0x1814e438f4c60623}}, gfP2{gfP{0x786d79919fe1aeda, 0xa4a066b73b7e230a, 0xaa309e34a0fac575, 0x28cb625949be596b}, gfP{0x1eb38b6d7e54480f, 0xe087dea4900e03e7, 0x99dc873cd91f636b, 0x184f75c47154fa4f}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x1948c545e9d88316, 0x420809880422c72a, 0x7d54843a847b39d7, 0x817fd25a98f3ef11}, gfP{0x11a74d5da8b27ff1, 0xdc14201e79d7469c, 0x29c7c8275b95b9aa, 0xf168f0ae75557e4}}, gfP2{gfP{0xae4e96cd7c4ee4e8, 0x5dc900074399b625, 0x6cc5ec2d53e80c4b, 0x27a334ddaac5d081}, gfP{0x825895eb16db8956, 0x655ccfae5133fe56, 0x5ef39b16cb6586d2, 0x36c25f211f52b3ea}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xf0043ec40f2c6f55, 0x5b8378a8d732af8a, 0xf373de2c659f3f86, 0x4569521055433f10}, gfP{0x54160e106c5dd113, 0x8d4225667560261c, 0xb8346690fa82a92d, 0x5b11400430cf7c12}}, gfP2{gfP{0x428936cdbf4fb800, 0xd749f40b8dcf7c8b, 0x7464dcc3464ea658, 0x22daf49a945fcfd}, gfP{0xb0ccb9ff4a96b2df, 0x75164b56deaef4f2, 0x8b906ee82ba75c31, 0x4eab7cd0e0794e37}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xc8c3e8a862340a6f, 0xa8cde5feb0e40182, 0x83b15bcbd4b38684, 0x6c62df133cd1d826}, gfP{0x7ece9de724a8fcd9, 0xda6890a5d31a04fe, 0x94f1dbcf2913f922, 0x54c476d50e7d0642}}, gfP2{gfP{0xbe95c6e8b742f227, 0x8db2bc53750947ee, 0x51f491b047dd34c5, 0xa0e9d479b5083209}, gfP{0x15b2ef368f79b91e, 0xa5d32db8f4f700ec, 0x8ab60910251b4032, 0x97783c8aa1ceee34}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x18a4c63ebe1bcbe0, 0xfedf5770d32599a8, 0xa88480301650d181, 0xaa1b03fa531686a0}, gfP{0x96a2be44d4ec0402, 0xa256c635db001b1, 0xa94cbcb887036b4a, 0x4acfb72e2584992a}}, gfP2{gfP{0xad210b3d2edaea50, 0x318ddfe0077a5cfd, 0xed69520887814a52, 0x27b21c2e486dfe93}, gfP{0x8400ad8458a25fc1, 0x62d4e9739ac5fa4b, 0x4011e9f75d6b1f6, 0x1d84caf3c4d0aeb4}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xa5c9a3a8e85b791f, 0x58115ee50f1ae018, 0xd7592487c44e7103, 0x24c902daaac47406}, gfP{0x711df57c7f3b1f96, 0x2fb5fcfaacf5dfba, 0xd46432b31cdf2bf4, 0x59e06c37f204a63f}}, gfP2{gfP{0x3d830a4ca8cef138, 0xc19bc51f7a4911e0, 0xe8767668147762a0, 0x16d05f9d05f29d76}, gfP{0x999fe1d78cb8d2a3, 0x71fa9139e78c79de, 0xfb71bc6922097636, 0x33dd14554b11ef76}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x314d8c94136014fe, 0xa97ed3b779ed6792, 0x96eae768fb35e919, 0x44c010013b261ac6}, gfP{0x150d1d13ee28ec2d, 0xf0175000558acd81, 0xc91f440ae2c5a409, 0x5ded3f7c087fc5b0}}, gfP2{gfP{0x2f4a2f0ee56c3994, 0x4212c42db1b8620c, 0x69ba4450e5129ea4, 0x127e610317274329}, gfP{0xe43bf55eb9e4bf48, 0x679ed1f6fa525c00, 0x3c858f1ef556d666, 0x146e20e735a49f8e}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xe48bb519cd57e5a0, 0x49826093df9c847b, 0x67af98e3924a2f9a, 0x7729017e06d6c771}, gfP{0xf858abe4788b4d3c, 0x76e69b71eb3ee1ef, 0x157b80ba1a6e5afe, 0xa00d900707c50e91}}, gfP2{gfP{0x3c716bb52487b76b, 0x20cf1f831f1b1fc4, 0x6d5ede31442a09da, 0x1f423ccf9a3edc0e}, gfP{0x705e51cb8776e68, 0x5486d60ed846a0fb, 0x37884f93c0ac7918, 0xa8b35c1c84e38c20}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xa1aaabc5efc85af1, 0x8c671e8c559a94f, 0x436966d1a7782a26, 0x7076f6662a3233e}, gfP{0x71df8314db5f53f2, 0x44315a0e7aa57ae6, 0xa8c763063d702c77, 0x4c98f2d8bf10a737}}, gfP2{gfP{0xbb62661a7e2986ea, 0xb6f0f37087de7664, 0xf2db5a97ada82080, 0x14ab3fb3413ef09e}, gfP{0x71c36f94caebda8d, 0xeb3fef54d5e20c21, 0xe9cd2283c98cac95, 0x8d6d46aae5c974b0}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x92db40e63f0ddc30, 0x6e0a719a57b1f69b, 0xac4e41f164bddf3e, 0x5792256585351713}, gfP{0xe33b0ba281d7c81e, 0x95e484d2004c9847, 0x2af5aa5dc369ebdb, 0xabed1857f891cea}}, gfP2{gfP{0x6ffc007965a84637, 0xc2fe8d601cfa8a4f, 0xc398b0a9198a8e1d, 0x59ba961a59d12664}, gfP{0xb1e96a780ba391bf, 0x3aa1e312792175a, 0x288a52dcff9d392f, 0x75d66ef91f215dea}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x7a4734ece5e1e82b, 0xcb7e97841836754d, 0x578aaa2de9d9751d, 0xa517125838dc2c72}, gfP{0x3c9adacf3330ed16, 0xda3ae719c1fe689e, 0xad4855ccc7a961d0, 0x840d4490555a7433}}, gfP2{gfP{0x294fffa472a161ba, 0xaba4c43cc852a6df, 0xcc106ecc75b97d64, 0x2b08e866d7d5be21}, gfP{0x1c468ce11dd0dc1a, 0xe230bef57612c2bf, 0xa9c0e2e4d3234b0, 0x84e7c52fc810705e}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x7023365a1c39bdf2, 0x99f57afd2da25a66, 0x669dad07f12227f2, 0x802faf4cd85b85bf}, gfP{0x23a3e89a5727d44, 0x4dea1c2058e19571, 0xd28d7ffa1fa5becf, 0x974393a8ece9ead4}}, gfP2{gfP{0x702c7d515a0beb65, 0x36d91b3f2291644, 0xcc3749b94ee4c5a4, 0x430237873c6a3001}, gfP{0xd063593f3f62263, 0x49a685cd9879a2a3, 0x9091848a39dc22bc, 0x9ed55d1d94f7a78b}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x84f9b323efd6d667, 0xbebdc0c79effba4, 0xf97b37cbab4dffd9, 0x410da3c866878cdf}, gfP{0x2ed269de72417776, 0x7d584a00348ac364, 0x522d7c42a83945e0, 0x86261eaf5c3a6c30}}, gfP2{gfP{0x51736e8d34b38ec3, 0xd7ee8856be88965c, 0xe73b28281ece8dba, 0xa2ba90574e85f78b}, gfP{0x7c8e9a3d9f0f7e68, 0xc4bf2700f1fc49bb, 0xaa4e98c4ba653455, 0x366b56254a5f7a0d}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x1736c8b9965a5309, 0x1b7d5afc23952734, 0x8fa431ae6cc6c6be, 0x88472aa177b26197}, gfP{0x3f84b10ba1380a20, 0xe11a3a5044332f17, 0x5633ada5579ad8a6, 0x8a62db45fd7f5710}}, gfP2{gfP{0xff557527689eed9d, 0x79783361cea6f582, 0x110f8403cc5cfd7, 0xb555eb6601756ab}, gfP{0x7a9e703c5928715e, 0x2193cebf121b0819, 0x69488c9509598c12, 0x21ef6189696eb25b}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x17345fb65fbae508, 0x7381875643bd4515, 0x82c39d1b0712299c, 0x816cc51dc62331}, gfP{0x5cbe72de83d0ea32, 0x3b9b71ebdd80090e, 0xe88db9ed237c194d, 0x7ea60d3cce392312}}, gfP2{gfP{0xa9d9cfbc473276c8, 0x107de88bf62eef99, 0x376823481cdc253, 0x1beed08fd3870bd6}, gfP{0x492ba47b766eb45c, 0x2563751605fc6ed3, 0xb77825a9583968c6, 0x1aef932f1a7e9e87}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x32e6aad492fc9774, 0xbcf47c6f266fc783, 0xa5099725cb4832ad, 0x27956749ac772620}, gfP{0xadf8c8e67f5e6b2d, 0x16af3c3fc73635d5, 0x6ead9230133d88f9, 0x516376630d9644c4}}, gfP2{gfP{0x60bda22f141d1ae, 0x5b8b74ae00a08c6e, 0xf04c7cb560f58f9d, 0x656df006f45fa3de}, gfP{0x26ced9c82722375e, 0xe614f094a76ab16, 0x45fb878ce3c37511, 0x826533d4c4f0ff0b}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x58f7a235ba7bdaba, 0x38ffef8b04e6aeb2, 0x1fdaf95a091d9cf8, 0x53bb298a84b99029}, gfP{0x1990b336ee7d1f6a, 0xc0207dc99f292c8b, 0x24851686443225b1, 0x1eeb1797a167764d}}, gfP2{gfP{0x6a4c1a34010a17d8, 0x212a36d786697716, 0x6e242865a7769b7e, 0x197e7a2bc6b059ab}, gfP{0xdd97c149cf48c13f, 0x74dfad8a54c0a903, 0x93228f559887fda7, 0x9f844c9f3c5303e3}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xc448bd47e473280b, 0x5270dfb670004475, 0x4d232c4e0c442c59, 0x35c9a372211ade45}, gfP{0xddb8c442f366ef5, 0x7b8bd86dac4ade2c, 0x7137700e6718b5ad, 0x2dd66fd21cc72565}}, gfP2{gfP{0x9dd143b56a879a0e, 0xc39f9bf780f75600, 0xf9cafa9ab4df8257, 0xa84ea95e0d135c1f}, gfP{0x991e0a604792b394, 0x4f233bd860a31768, 0x3af37680b87d6b40, 0x182062fdb7666f2f}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xbfcfc19145f86935, 0x770c1139788df83b, 0x5996442700320a89, 0x2fb3b0df0608ff7c}, gfP{0x2c534265ed1773c5, 0x3c5772761af99548, 0x728f930e5f405f81, 0x548160a3e01d5de5}}, gfP2{gfP{0x763f6503a5d35e0e, 0xe64dc57744ae1730, 0x65117b637f916d7c, 0xa83bdb397701e2aa}, gfP{0x28330a1097a28fa8, 0x103784b29cdbc40a, 0xfbe39525275db32d, 0x79445be190b7a922}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xf11252e1a90692f9, 0x90b37d58b807a4c3, 0x45fc89ba0abd5bdb, 0xafce769cea42141a}, gfP{0xf2ed5012887ac0c0, 0x17248814f5eabcb9, 0x4e07a57fbc24da71, 0x35933b23ee7b137e}}, gfP2{gfP{0xfbf9a5ca2da60831, 0x32093de7831533f7, 0x3c01ae7224e783ff, 0x767b0926b01b3ab}, gfP{0x6d1165406d8201b8, 0x5eddfc361195e811, 0x857f553a4ad72193, 0x2d6711fb4da1f327}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xbe9a59dd33110130, 0x36d7a875c6e7da65, 0xbe9456c3c3b110c, 0x6ea6a242b6263b22}, gfP{0x75eeb3acff7bbe77, 0x42cf188ef64f745, 0x318248c972336817, 0x26147d33e40faa1b}}, gfP2{gfP{0xd0ad3aa89f43c5c7, 0xbf6ffd7ede09477a, 0x5a62b2831890a815, 0x2700851a12979454}, gfP{0x26dff77849618b8b, 0x932e54e361549f71, 0x8a9ac4aba07a3a93, 0x37f04cce1246c72f}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xa4dfc64a4f039f4d, 0xf1c256860e43b646, 0xb04fb3a75135460d, 0x408170c030e38328}, gfP{0xb7b8949bd5e8db0e, 0x4c09da459b3c2549, 0x951789bc2edbfa, 0x1ef3be7a13577dd6}}, gfP2{gfP{0xa18a267a195358da, 0x67d44dbfad5c4f97, 0x1210d7ce62f5d073, 0x3abe551f82d32bbd}, gfP{0xec1c208d4cdfdf51, 0xf32e8db60328c0d1, 0x5982703fa2248b37, 0x728323859596341e}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xa1a9e42604ed17a3, 0x467207d54fb42c5e, 0x5757453cbc456201, 0x12e19fa939fee671}, gfP{0x3b5cfcf358adcae6, 0x84742c089a17aef9, 0x687b3195097f920f, 0x3516b55cbe55c801}}, gfP2{gfP{0x78974aa9d8540f94, 0xc054f16d76464613, 0xb80a2566d491f4d5, 0x3098b408301959b8}, gfP{0x2f5127ecd541ebc2, 0x8163e41f997fc0e6, 0x9c9ba6d2d3c00092, 0x7184ce48e00b3867}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xc433cf917841f877, 0x8493fe040db849d1, 0x9d979e705adaacc6, 0x342aed43605ab2c0}, gfP{0xa85a666bcb073a3b, 0xf0ee091e7761ecc1, 0x36252037adeee7a, 0x71b04d5ac7d1989a}}, gfP2{gfP{0x5aacfc207a746cdd, 0x23defd380d9bcc91, 0x4b4165efb91e08dc, 0x5f4bcdc40db38261}, gfP{0xe32c14967f23ba95, 0x2c0f922df3ab1eeb, 0x2cdbe3c8777ea83e, 0x7053453275ad6cad}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x1e2acb4215dff306, 0xf98245ce856f0ae1, 0x69c0101aea65e505, 0x9e10ab7ff9a11e5a}, gfP{0xe8746d0117058c29, 0x9d16fb40d4d4b601, 0xbe79746031a2f28c, 0x3b49b38f0ec3840f}}, gfP2{gfP{0xb25600db66829d9e, 0xb243a0771c9d5803, 0xc1d7c18e26863016, 0x3f5e12350a9f7619}, gfP{0x686e96e6909726a7, 0x3c80865942adbe1a, 0x443182485dc96a85, 0x6412baf4a6eb4a0}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xcea66fa3dbd1c5c2, 0x15ccf0a9f7c27ff5, 0x51e373ad63107bda, 0x6db2c4ec93d9fd82}, gfP{0x84122c07a30d9c46, 0x88274d16ab75e481, 0x800559b425cca1f0, 0x7487170b502d90a6}}, gfP2{gfP{0x225a63a4cc31b624, 0x387c4f60146e80a4, 0x42436fb5d4dbf6bb, 0x196da63995f4d82a}, gfP{0xe0c8e5be346c4e52, 0x74f9ad9e5c088d91, 0x5c8144c4dda2c144, 0xab98a7ebbf14145d}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x29739ce34b97e8bc, 0x9c4e6b9c42168bd5, 0x73305d8b75b64bc5, 0x5d0f21c091e94761}, gfP{0x1f56695e5ff6626d, 0x7a3a166cadaf81e4, 0x903fbce5dc94ecb1, 0x571b873552a49d71}}, gfP2{gfP{0x7a1fd4c89aba0770, 0xe3d5331d148b51e1, 0x8238170333696824, 0x8b481c4bcc5b1d21}, gfP{0xa28d12e1cec5ac81, 0x614d157c788c6e38, 0x84c6285bbdbdf65d, 0x6c9cf839f0c0037f}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x418c6c4342832eb8, 0x22d736f4ec2fdd9d, 0x32a0715b2b0fc930, 0x820a6525fb9ea3ca}, gfP{0x90d8b6188e482d1c, 0x7f71a940b0d2ff74, 0x1f9aa0f532a1772d, 0x3627562597036ab6}}, gfP2{gfP{0x949de7e85aff068f, 0x971ceb951ce2b73f, 0x4b1df7651abd5646, 0x889a80d178dde626}, gfP{0x4799c07524274ba9, 0xd2aaa21ac2c451bf, 0x31b6f423da561d6b, 0x56d4368f98d4f459}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xbf4f3dca1b9855d7, 0xb9f329cc198f0e71, 0x118da553349390cc, 0x1cea5ba0dd7f9ddb}, gfP{0x2d9d53d000caee3a, 0x6f7a9ed45c63aed1, 0x7b63b0c1ce41eca5, 0x44db1be2de9bb946}}, gfP2{gfP{0x5b1422b09bb57d83, 0x5cf3bea09a22b669, 0x521f46a22583e2f5, 0x89f0016c3d291cb7}, gfP{0x30adc0b9db89e30f, 0x2e85e384adf8afe4, 0x56c3546e32b9f76f, 0x9478fe1846d50fc3}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xea56190bfad36f51, 0x911135d40416882a, 0x6afb1264bb8047, 0x4cd80c9ad76155ad}, gfP{0xb50134944f0bce58, 0x400c76887428fdb1, 0xd5cb089090fc5059, 0x69720d75ed854a0b}}, gfP2{gfP{0x5404a817e903cd4a, 0xb2aa9b541308101a, 0xc241018b911349fb, 0x3ea5f8bf73f5e83c}, gfP{0xcb057de70a962f2a, 0xca83ee4e2a1e011a, 0x567f194f5a2f8c24, 0x26f8d49dec04427d}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x60408e6a21f69725, 0x4715e99182b2ae2a, 0xd9f4cf04568789e3, 0x98d38cda902945}, gfP{0x9c054361b8c3b403, 0x704921c2d10a5f90, 0x92ac1fc72306835c, 0x3897e7f247c43f21}}, gfP2{gfP{0x86babffdc65b1fa2, 0xae04c0e5d8a7c399, 0x637b0b6b1f923848, 0x8f77967237ebb2f4}, gfP{0xb41068f401d6171c, 0xf25824ffbb9a897a, 0xd21c6cac0f58cab8, 0x7f5d9b4ace559d35}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x14739f2a33deb3b8, 0x5db32c101c79e53a, 0x9b79131d1f0c2c6a, 0x499cdc8b554e5776}, gfP{0xf9a52be847d29721, 0xe09b844213e8e30f, 0x97ca49ac9a331a2e, 0x9da5b21fa73bef19}}, gfP2{gfP{0xd596108b12511499, 0xc85dffc4302a6702, 0x56861626a58411f4, 0xa7f175f98dc51c5b}, gfP{0x3e2426aea4a54cf0, 0xbfc9e71913170fba, 0x1224541a36a342f4, 0xa76741b728f4fc57}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x17f7fc7db492a919, 0x6933658658823934, 0x3c6ef9843852eef1, 0x9bd4043c7d0bdfc0}, gfP{0x19f5900018405335, 0x6ccd822f32012fae, 0x1c649715b3850852, 0x9de7965e6f840906}}, gfP2{gfP{0x97c0914004dcee90, 0xe3427533bb33504b, 0x204e1177cb8a0854, 0xb5b79eb453031225}, gfP{0x8b8cc887dac10845, 0xd90a93e48593903, 0xb453bbc7e1f7b8f8, 0x874ff9e39a67457f}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xc45c841792f05eac, 0x5a3383aae2eefb8d, 0xe2212350f5e151af, 0x4f36fbfe5651f857}, gfP{0xd972acc35efcca74, 0xeb5481a8e256bfa8, 0x2443fdf3b87f1e82, 0x3d3e6c4b068042ae}}, gfP2{gfP{0x67be5f8924b01ec3, 0xc80a9546cb7f5096, 0x6ecd66e4b15a378e, 0x4cd2d1f81593b82}, gfP{0x683bef34cdb7a2a4, 0x650b61b72dd80f28, 0xcd8edd6f9ed0e7f8, 0xaa6055ada3d5aae8}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x40b17388b89659e4, 0x8ae372ee9774ee8c, 0x553df6f6607e373b, 0x8a9f070a00fb9da6}, gfP{0x1b4f8d07941dac32, 0x77be9040aef87348, 0x402f46d66c34a0a2, 0x7b2d1d1ffcb6fd63}}, gfP2{gfP{0x6fdea0e05d308608, 0x6c57459f715e1c25, 0x41a34cfaa2db0db6, 0x6d67b1c81917ec}, gfP{0xeae4ec5194e0b37a, 0xc04256aa60d92768, 0xe5562dfdca5166b2, 0x2e30ad309fc742d5}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x78de3e4718b13252, 0x7ca10a857c7f9e6d, 0x3ca66370632b624c, 0x79d30b961901cff7}, gfP{0x99334d7094669035, 0x7671ab877e125b8c, 0xc7d75230278ab10a, 0x285aabf94b9dcef7}}, gfP2{gfP{0xfffd3fa418cbdc79, 0x51a2722474118ac8, 0xd4dda2f303c30cfb, 0x6b962a29354f3487}, gfP{0xb5423ff6cd287b59, 0x59fd58a27bc4146d, 0x2495055966f11512, 0x47452f600b30a466}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x29fc92fa838aaffd, 0x9670ab7b2cf47a41, 0x6e1ac471ba8cb182, 0x4709b1a03fa830cc}, gfP{0xcf6f527c740e75ec, 0x7f7a54e644b96bb4, 0x8d3ac99ca1211631, 0x87ecdd28dcd41eac}}, gfP2{gfP{0x9f762b7d51a50ce2, 0x43a4a7e5c9296f3f, 0xe56e34089a41128b, 0x3e62f026063a8cf7}, gfP{0x2b32e1be35476fff, 0xa7b874aaef966c3e, 0x54dea21db3dbda5b, 0x6ebbce0890cfe62d}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x5836fa9877c6025b, 0xc64c9fd97f3812b5, 0x7237ec69e809f446, 0x329bcf85a5c43ad1}, gfP{0x2db03ac00271a1f4, 0x6cc8b135e3aa170b, 0x60da93fbedb3a184, 0x63b562a596185a9c}}, gfP2{gfP{0x84c41a244e0b992e, 0x110367fab2966dd9, 0x1712652501838da, 0x3f6e06916077d74b}, gfP{0xc59eee24a13717bb, 0xe394e8f65dd0bd5b, 0x9371e68a5395c8b4, 0x7c10b20f53fa44af}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x3251255ad156bcbc, 0xd0f320476d784332, 0xdcb5cf4eaaab9a3f, 0x6abfa360cbaf603d}, gfP{0x4050ad67578c1604, 0x7f86dd6d81be970b, 0x4caa405023451216, 0x8f4e6dfb661fd9c}}, gfP2{gfP{0x22bcf75407f462a6, 0xb463d2f0ae553646, 0xb0764346cfa0c7af, 0xb4fef26b8a67da69}, gfP{0xba4be4184cd53f4c, 0x5f0c1e566a3be65c, 0xd26d5e4667b7dc90, 0x4190cb1591677088}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x90356db80a0d3f96, 0xfd0bbf53dd2a98c4, 0x4e1f09e72c98b731, 0x43686e78d22c496a}, gfP{0x3498efe1310f37fe, 0x924b7354289ac835, 0x394402dae3a7357b, 0x536d8f0268720e39}}, gfP2{gfP{0x7bd49c6b1810dae7, 0x427398fc9896b3ea, 0xb47ce9f01c692dab, 0xb06c46f8d0da2453}, gfP{0xa181a74ad77f4950, 0x6665677f538e0ac7, 0xac9b9e7296d8f482, 0x5850f3ff02423e85}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xb145696ac103d2c0, 0x2e48b7d6a8abba9f, 0x3c3cfb664ada8541, 0x638366f6233e7ca3}, gfP{0xc5baadda357dce8c, 0x9504de6e9d908eff, 0x2ba51662bd5b844a, 0x9cb3d861c7922022}}, gfP2{gfP{0x82e26647d57bb8f7, 0x5458aeea4b1f3c17, 0xa8905655b6220abe, 0x76bbc16972b77f0c}, gfP{0xe5bd4fbc580bd341, 0x53f8a1d997013c21, 0xbe3c9a4d1ece6375, 0xc68e433e7bab90b}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xdc323cac8d447bc, 0xeb072eb99fb11f16, 0x268085789b036eda, 0xf6681447051d4e7}, gfP{0x6d0a1798ff480ca6, 0x51daba4f2897015d, 0xd7ca303d744d6174, 0x5638de8d31004986}}, gfP2{gfP{0x818cf25474b3727b, 0xf7554da767490b01, 0x868b69ee811a5237, 0x7f7f59512cf00981}, gfP{0xe7c1c1328fa1558d, 0xb0245314ca337154, 0xb4cbdf9fdb24ad2e, 0x7ca422f1125029a8}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x42d8cb72076dc3a, 0xc00c949c545cd872, 0xfefe1cf31a6101bc, 0x657aa9785e6af893}, gfP{0xc74b134a5253d0f3, 0xd35d1bb13a3ec028, 0xb2b0cf9261135eb3, 0x440def06b3740721}}, gfP2{gfP{0x519765baeb8a5948, 0x21229775e200e427, 0x81465100cbceefe8, 0x1b603450b0751bd8}, gfP{0x16cb9782dafebc07, 0x57ab9522f2e12aa, 0x588bf466a64526ae, 0xa8669d933c85b413}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xe5d035492fcc02f7, 0x38d7d84ac476c025, 0xc668f1d2812dcc54, 0x4525423b402e217f}, gfP{0xb4ccadd19819d4c5, 0xbde1a741309035a4, 0xb3eda7c62e6eb51f, 0x3546aa44f6bbd668}}, gfP2{gfP{0xbc9dea2264e213a5, 0xb6d27e8718a8ce67, 0x962e0290c51756a8, 0x7ae11695b114d514}, gfP{0x8592c02677d2b866, 0x2e5bd625df08ffd, 0x3ba6f022eb9fd516, 0x9537fbd53a8d79fb}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xbdb9d4a4dcc053b7, 0x4f1c9a8c66af1376, 0x38621ca17e034a20, 0xa603bd05f0dbe592}, gfP{0x92be2f0f36899ecc, 0xa52045339e6c6889, 0xeb17996693712ac0, 0x806b276dcddee9dd}}, gfP2{gfP{0xed164de9e6855a7e, 0x6b1f7f21d2a50e5e, 0x852ad30906fdc515, 0x3ed1322ea3375e6d}, gfP{0x9f8edfa961013195, 0x37f65bef1e106bc8, 0xdb03765a3c93471f, 0x377414d2fecfd443}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xafa454aefbc080e9, 0x76031768948d5a61, 0xf744796c446fe650, 0x9da3ccd055f8bb24}, gfP{0x159625a280773f94, 0xc7e58bd0583df577, 0x78b92da24e986e96, 0x474ef04890f41eb2}}, gfP2{gfP{0x3444d5ebab7c475d, 0x66c7bd3e035ffce7, 0x7cde77b57b586f, 0x8761526d86293dfc}, gfP{0x538eab672a0e5934, 0xeae93b50338a8a5e, 0x56594268e81614b6, 0x43320569f49c5eb}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xf5e9a6b60056753, 0x48a1f3afeed1d463, 0x44f877c39a4e3669, 0x56ea385b4ce25bd6}, gfP{0x7cb37430dcdcf861, 0x22302c21399c13f9, 0xcff48457be9a174e, 0x57d6de8c6ae1ef2e}}, gfP2{gfP{0x7ede2156a21217f6, 0x38692e5d56c02d8e, 0x58ebbf6ac21c8ec0, 0x23ad0e61b34d49dc}, gfP{0x20089560e0018009, 0x4ca8a0a72f158188, 0x982270c72a0a8333, 0xac06e71d402c3583}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xbde73f6273477904, 0x5466a03fba5cbec4, 0x5a952697b56a36fc, 0x51b549c28d26996f}, gfP{0xf9ce4e58705b1709, 0xb032bd66697ce5a9, 0xea13a3d00f9ce33e, 0x69df8bb1301ad4db}}, gfP2{gfP{0x3a923c475065b138, 0xc9bfb0734b070d4e, 0x965aeed6143df39, 0x445981721df2d54c}, gfP{0x4e37cd2f53809a25, 0x707dc5e6b729ada9, 0xf6c396ac9a3300db, 0x1b2e0388fd0ccb7c}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xe43faf30c698e4bd, 0x2b6203b6c661b1e1, 0x296d84fbc6c668b7, 0x9218303f875e73fd}, gfP{0x7a126e9fd0c3c57d, 0xec0c0b54ff8005b2, 0xa1a29528b1a3f9b7, 0x892789b75220c4bf}}, gfP2{gfP{0xf0e4aba4f38a5597, 0x829421b67c24292b, 0x2a8c2c7774e3733f, 0x7a11ee6fd79fd22a}, gfP{0x9eb5fe73dcfd4f86, 0x24c65f3cc844ea2f, 0xc17d357f4da94904, 0x613f12828bde7c51}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x7c17ffbbdb492662, 0x403a2fce239e0638, 0xd105cec5bd55e698, 0x3868e9addbf33c55}, gfP{0x1d1c3cf306734ca2, 0x49f4c862cec093ad, 0xf37aa97ff420b88b, 0x8e4d9401965c7a65}}, gfP2{gfP{0xfcee9a65c5cd0946, 0xe6c3eceab0871e49, 0x9e69055b128ead38, 0x9e60eacdd690e5ed}, gfP{0x8fc3db991e30eef9, 0xf955e1ab29c773a1, 0xd4336eb0a4e5a326, 0x9f6700f4161f9997}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xcba4ac6d6798a11c, 0x512895c27568008e, 0x22bb28325df22b0a, 0x7d7e7f136d5e6677}, gfP{0x6cb24d507f7f5110, 0xc7b5a78d264673d2, 0x2047f25d6f35704a, 0x4a16f9c6e75ba073}}, gfP2{gfP{0xd2009930a703f311, 0x9f5b7ae6c5dc9b0e, 0x9a4df94510b7ad79, 0x46e1f0deeb370daa}, gfP{0x5f3db5be1666bad5, 0x2642c96732764458, 0x63d51bded4bf2f06, 0x17470bca02022bb9}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x4ef322ef3dbcf692, 0xd662827e77a77216, 0xc1b1d5da4ad52e66, 0x54a9f8087caa7d56}, gfP{0x3b9394a508cbd889, 0x4bc466ac5128d42b, 0x80ec107ed09611ce, 0xec9c983dcc55944}}, gfP2{gfP{0x5c90d19e857abbc0, 0x5f07159b539a290f, 0x16e96a3bdc937673, 0x11f3fbfff79c8ef9}, gfP{0x8165e99ffe0537f3, 0x5e8b8db57abf7d8b, 0x33e82131578a1993, 0xa07b2a98dab1d014}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x7bc07eab24a7d7bb, 0x38c68346976aeb53, 0x503b0eeca01dd552, 0x20c088b0fb9f993e}, gfP{0xa815b5febed84bef, 0x53ad038c1695e143, 0xecce7cd0a3c5fdca, 0x1957c1641ff6ce46}}, gfP2{gfP{0x44ec56a1c7cede13, 0x831a0cf57b575846, 0x3a5e1337f277e914, 0xb330c621e7fe8129}, gfP{0x5198e921b5a2d86b, 0xda543523c7388d70, 0x3f253b9473b5cae4, 0x403fc0b963578655}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x7476ccb2bd2a4622, 0x18554d6a8dac7c63, 0xb563d0af47c161df, 0x88504db960da8ab6}, gfP{0x3059b2858e911cf6, 0x3d9fcc8cb1e40b2d, 0x1ed5d9097b6b9787, 0x6f111c874f2f5917}}, gfP2{gfP{0xd30a724136fe2ffb, 0x14a8b85e0ff7921f, 0xfc393e1c5dcae018, 0x277f3db12d03dd0a}, gfP{0x167cb102fe182d9e, 0xdee466c319087458, 0x4091b0a158ebce70, 0x100d3c5bd73aa7fb}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xf6f55f4b2c2e2da5, 0x6a81477c139eb34d, 0xf87a4d33b2a8882d, 0x8edcbd6cae64604f}, gfP{0x46e83dcff670e8fe, 0xed4e2beea1f3247c, 0xc67f90be3a72c49b, 0x1b4dbf9b58cdab5a}}, gfP2{gfP{0x49ca5a0b9f3581fe, 0x6d9ea61dd3d34021, 0xb4c216c0f039d8da, 0x10272e6325d51536}, gfP{0x6e1fd94bd0846b4f, 0xadbbc3c3dbee624d, 0x6929f92aa871fec0, 0x4f1c66118d91fa02}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xf4cd395f8564ad91, 0x1df075b9bc6665ec, 0x6a03a36f250d321, 0x7be30a51747eee15}, gfP{0x68c86d594c5d9c72, 0xb4126dfd53c9dd5c, 0x16ec79e88886d86f, 0x67ac8ac9037f739d}}, gfP2{gfP{0xf7dcfe198adfafdf, 0x7c20b16a4aeac258, 0x4293866ab30854cf, 0x3a051978400b5830}, gfP{0x32e82194b0f9f9a9, 0x15666e51f8f6133c, 0x467e9a123c7628b5, 0x178a35004b0769e8}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x4d9cf60b25e24948, 0x8007534f2b5a7e83, 0x8f6708721f2b8c04, 0x9e86a45e746383e4}, gfP{0xda1e43a944ae2d2d, 0x8acd9708fbf9bf6e, 0x4e6019a64664151d, 0xa404e2fbdc21608a}}, gfP2{gfP{0x5375264de0853f5c, 0xd6b6b88200d34770, 0xb937079d29c0e44a, 0x3c6075f20713c093}, gfP{0x1a4726ff7add0eb0, 0x3434d71074a46108, 0x8e86b6ae0ae97121, 0x6eda46e6e4f7994a}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x9d3cb60049b06ea6, 0x6b9612c1be663deb, 0x597824591ad4181b, 0x441da2c20c8b8b8e}, gfP{0x5e561b01d562a002, 0x6d38d7283f911cb0, 0x2511763cf824824e, 0x4cc68e831c735550}}, gfP2{gfP{0x2614f7e6548481de, 0x1ffa731803894c2b, 0x79653072e86535d6, 0xa820fd4c82252af3}, gfP{0xb90224c22390d1de, 0xfa49498228e3cf64, 0x473e9c0c9c6495da, 0x405016bc56bff86e}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x6c53d090a650242d, 0x70f19ac847a1193d, 0x88f60c7aaad8d76d, 0x5dcb438b1d17d5b1}, gfP{0x1231756c16cdd73c, 0xe0b755f249e5e117, 0xbbdc78c1a42b55b8, 0x19bbb0c04a756e24}}, gfP2{gfP{0xfcad345a96369ead, 0x4386e8c5015e96a4, 0xc7ba34089bc78ca2, 0x97a1d49e1ecf9fd9}, gfP{0xaf5efea8678c0689, 0x8ac2a214f230bc2f, 0xc47ced4e006c2a2, 0x44d36b574a47b8f2}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x14e349fe8ed25986, 0x66cd413155db390f, 0xec170595f3e582c2, 0x2d6d7d68e9a44cbf}, gfP{0x703652c199ff5827, 0xa9265cc4593008d3, 0x32e61e48a7133c3c, 0x8deac1f37c94b667}}, gfP2{gfP{0x936a86c34690cf73, 0x5c31ca406cec33f, 0xf54196c3e467fb1b, 0x5cc114b1300e7016}, gfP{0xdf8dfc85ecd41ed8, 0x6797faf4133e2221, 0x45ef64ef4c37f6d4, 0x9c3cecdb24e916ac}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x7b467ecc860dab84, 0xcbfef938a7818615, 0xa817123beb8c579a, 0xc2137003f853a5}, gfP{0xea9dce1d7a6403bc, 0xc94f1212e69ab353, 0x710766c35c953bb3, 0x36501a035f372c82}}, gfP2{gfP{0x911f312550f011a7, 0x4630861c43dba4f6, 0xfe2340f4440b7e9b, 0xa7eafbca54a4a209}, gfP{0x4f36df2ae71aa81a, 0xd2e1061ea272778f, 0x1a9688f176f1e8e2, 0x7d704ddf205d0861}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x70a5440478a9f621, 0x8610b617041fac9d, 0xa0a48a93001b6ff6, 0x71cd12a72f89346c}, gfP{0x3930b87d7b0a668b, 0x3e0f6835cf9f86fd, 0xfd92fef8929ea00b, 0x9105c43261cbd575}}, gfP2{gfP{0x84bda7524c0a2010, 0x4180a7df27bdb8d2, 0x51d6b68f185d4c77, 0x249cfc9ba3a284cd}, gfP{0x42b69bdb49208de1, 0x7580281485f71407, 0x3ab12bd8353a8289, 0x87f76e6b4e609dae}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x7801c401d6585bd5, 0x737b2ed26cfe5cac, 0x68c3c574e1ed712f, 0x9094b684b8a959bb}, gfP{0x808c44f317f71d78, 0x5fc5ee0520379e9c, 0xe23051b23b5c79d7, 0xc318be16bac5df3}}, gfP2{gfP{0xcd60494dfe120c6e, 0x6af7663675ef650d, 0xaddfcfdb8e406b1b, 0x5222749781a1617d}, gfP{0x9fcbc3fadf687d93, 0x7c56585974cf8455, 0xe0cd5bd243d63c0e, 0x59f6794a91ebb16d}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x3d6a84964b985fd1, 0x38da74791a7c0536, 0x71ab1bda7894c2b3, 0x7285c96bfce1f9dc}, gfP{0xfff7ec88a498cd30, 0x52e90edd07cda69c, 0x4d304f502fbc3375, 0x6e261480120eb179}}, gfP2{gfP{0x6e3d7c209676fbb8, 0x47b2148ab104dcb5, 0x949b75e95d62f22d, 0x82362b3acef3b8d1}, gfP{0xd15768f335c4e949, 0x9a7c6f43d6c3cdfc, 0x855b6fdf70540513, 0x27433cc9f6c6ae44}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xaf4119a6e6302474, 0xe17d78c9bd4fb19d, 0xb7827b3e3de98342, 0x8701dffb879ec773}, gfP{0xe88a3a2fce3329e, 0xdd736ea3e5f6edb5, 0x4920ba36277de8d1, 0x9ced5f4d7d0e8652}}, gfP2{gfP{0xd0e72dd831363c7a, 0x63fb2421a8bec606, 0x4c90c3128a49b262, 0xaeffd6a918f5c153}, gfP{0x768e511df0ed4492, 0x197f828b90ffe6f6, 0xb42969c563b08660, 0x5ef26847c4f5d967}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x5cacb7997f2b0338, 0x5beda7459747b986, 0x2efd681258e74c13, 0x65c4b588cdedd4f6}, gfP{0xc53280f5fa003280, 0x5540ab73a1539ff0, 0xf2be4b83ad86c2a4, 0x1f58b5713eb73671}}, gfP2{gfP{0x6a608daad267b784, 0x7f34de664d668ba4, 0x46f5f9392e6aea77, 0x48c50f9141965792}, gfP{0x4c17a88bbc538254, 0xff07740372dc82ce, 0xe378197ae5384a8d, 0x6230cc5bc465a930}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xea8d1f04ea23313c, 0xd28b487d55a25983, 0xc2a537470fdd424d, 0x6f60c2039a5ab946}, gfP{0x1f83520c8de73666, 0x6f68936cdffeb8c0, 0x9d3ce5cc72584ee5, 0x6147da61dda8e7aa}}, gfP2{gfP{0x9e52fe365bf47a9, 0x9dd7f1c470e4557d, 0x9687f7c34014bff3, 0x1658200647bf6c21}, gfP{0x9a1018f45d8aa6cd, 0x39c14924768e62fc, 0x540aa85f4dbf8f57, 0x7735b373d84f1342}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x10c37c801a865342, 0xa9d8dfc8f83d2265, 0xf715232cb2e12af9, 0x56dbf8c0e68bfa34}, gfP{0x89c1b7329cd0624, 0x478291224d9d4a03, 0xf9e3dc2af952574e, 0x5ea2b7b02d871391}}, gfP2{gfP{0x7b20f464cd0dca39, 0xe16fa010f55d727f, 0x819b98012dfe15bb, 0x652db5e8367645b5}, gfP{0xab7abf8648291331, 0x221b17d95850c8a9, 0x4f1a086085913ea8, 0x7dd959de6803cf0e}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x8e43ac456d086c50, 0x35314b6beb20e701, 0x31704efaa55abd59, 0x5938dbc1568382ff}, gfP{0xc6a32304564b05fd, 0x78ef3d40fbde2c3d, 0x761ff3fe1f2363ce, 0x6b52a6fc1ac69b4e}}, gfP2{gfP{0x3e50490e5898c9f9, 0xe7b3aa414be5706b, 0xc91816aaaeae0574, 0x8f7d8effb86d08c7}, gfP{0x9fe536d831a10616, 0xc24d3a4e86f823bc, 0xcfa6236d4988f031, 0x97c6b06455092143}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xf25e21de44a2e2e6, 0x716e1ebdec9f087a, 0x3e95bddad9a63bf3, 0x7c99214f19bdb26c}, gfP{0xde033d4fc357bd3c, 0xa456e635b8141f52, 0xa36ea39aab3bca62, 0x18d66b82220e061a}}, gfP2{gfP{0x77c6aa868490d2c3, 0x6da13bdaa510638b, 0x1cf0dc54916ef50e, 0x97f268cf0543f162}, gfP{0x5720cf8009b23d64, 0xf3323b2db7009db7, 0x5d4f81666addef09, 0x9917c6e558596274}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x687c81db268335f, 0x480271ffc359011e, 0x3ede14ca1ecc615, 0x47ebe6e1531ebde2}, gfP{0x140c71eccb4a2d6a, 0x7cf565f8b2ca52b4, 0xa1b5360ff6e75361, 0x37dab403c185f3fd}}, gfP2{gfP{0xe6cfdda29443c582, 0x9e1e8aab1e3156c9, 0xc4b101257f8508df, 0x78d90268d7a0ed82}, gfP{0xbab4cd5eb1a5a6a0, 0x527da6467c9d66d9, 0x6064dd7b10b5004, 0x1773d0e31bb0c82b}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xfbbf91387156e7ba, 0x84d8735ebd20e061, 0xb26c6ec0d3e14e44, 0xb591cdd70808d156}, gfP{0x37c37bf3e7811f90, 0x9da2ec9d2e93f442, 0x985645548f8acbf7, 0xa214d41d887b268e}}, gfP2{gfP{0xbb22f800de641282, 0x13cb56f9330de8c2, 0x34f3746f7829ba99, 0x7269bdbe1348b698}, gfP{0x74c9fdd9cd233479, 0x5a31b64f37105347, 0x2e06c271c9eee214, 0x643bd0b99ed892eb}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x11a57d2382c768fa, 0x63166854e15d3676, 0x6bd4eb9fce713f88, 0x472c3e3e828629a3}, gfP{0xb2a61aa83bdf0508, 0x625fdf781038ef9b, 0xbb1cac2f604edabb, 0x7830b9d31bafaf95}}, gfP2{gfP{0xd8285ce532d50d81, 0xb61c37b8b2e54eaa, 0x78d5231fda4631bc, 0x6ea0fe05ef96d6d}, gfP{0xcbae66412a1d6915, 0xeea0e02f18c4de99, 0xc82ab9d576e1ec48, 0x51ed2b5521bb7129}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xb8e3f284c4ef4bbd, 0xc38e56fb005a88c6, 0xbd37cdea6692f9dc, 0x1a21722cb9632ff6}, gfP{0xb855c3da9c20de05, 0xdca6877dcdc91b26, 0x3212ccf90abcc7e4, 0x17c5ec68f2ef2073}}, gfP2{gfP{0x3a0c4e2237f98209, 0x747cc518eedda907, 0xa055b3d1df975a72, 0xa169b958f80ee6e2}, gfP{0x6179a69f54d262e2, 0xc43b472f51d55af7, 0x454cf64e230f8859, 0x942cce634d5d1c9}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xb9c0376b956a0e2f, 0xb1de85b0f8645bc2, 0xa6e4e28b093cbdf8, 0x24dfb572be2ffeec}, gfP{0xa410a864cdf21c0, 0xf844aa61838390e2, 0x39624c1630e9f1d7, 0xf222666dd4bdf9f}}, gfP2{gfP{0xc0eaa545ae1bcc0d, 0xfef00eca2ab36cc0, 0x802d4e4a3dd3fa8e, 0x647c30bde0d62d3b}, gfP{0xc7741b9a43def0d4, 0x5cbebaf606e70f1, 0xc0d5874f7bd32e32, 0x92db0b9cc7f0331}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x456a1c2f93ada0d5, 0x8ae8e67f0fccba02, 0x9997f93a26425fc9, 0x4c50f3264bc9177f}, gfP{0x3e90789609b21b7d, 0xf1a7da6be8b2771e, 0xe10fe4e1efbe8866, 0x2a6e8b0160afd8fa}}, gfP2{gfP{0x5b91e045d66d1337, 0x4dee04f450a66144, 0xc99d440fe04364c3, 0x1c17089031ab3ad6}, gfP{0x72ed6f9b2d0437d7, 0xd6e66892739083e3, 0xc4afc4b8b9cbaf39, 0x7dd97bb58489db16}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x3fb2479a79db54e9, 0xa02e487f1b291cf6, 0x6a5d559ba5962290, 0x1d56c998605e239a}, gfP{0xdf3232ccbbdf64cf, 0x1a7a97bfcef976d6, 0x67af4bb2cfb9a29e, 0x8974b8c157d3238f}}, gfP2{gfP{0x2896cb0daa7e6d9c, 0xc67de92b51883dc5, 0xf8b4aafd9519d973, 0xcead5133219967e}, gfP{0x6aade65293d50c5, 0x99f4024155b909ad, 0x83e72bce58685770, 0x1ee03f857803a83}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xbc5a91e059b5613f, 0xeebe905490685c02, 0x840cada4b417f770, 0x7554235820b33a41}, gfP{0x53c8110f54471eaf, 0xfd91905de5371124, 0x6e3fbd754646c191, 0x8eaff79755d1513b}}, gfP2{gfP{0x5b1fbd2cc506692e, 0xf103d59e64f10bff, 0xc92cb39ad41a2ffc, 0x884a6a4ffa514264}, gfP{0xd98b7798ee9006b7, 0x9777049734dfc9b9, 0x201a406d7443de94, 0x9bda6d3129c62a73}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x10b957e1ec5ef01, 0x1178523b8b480e4, 0x5b39ab70e30c34eb, 0x871496276c8354a3}, gfP{0x8821dcac32141bd, 0xafd7dc9f8eb2f4f3, 0xcf6db740c4194c27, 0x4e0d75d122f64c89}}, gfP2{gfP{0x71a1e126a633f746, 0x40b1260ea82b58fa, 0xf348f9feecba90, 0x6f52c9df6296a0ca}, gfP{0x7643b8a7228e9351, 0x4560427189aff5ba, 0x3e4b44b3545b5f, 0x3dd11bd7ba4a5825}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x6cb97891d5588aa7, 0x852619669f639965, 0x8dc528e15368e6d5, 0x961ff67cbbad711}, gfP{0x8786e12d1a1f19f8, 0x998a6cf1c03535d8, 0x258dc9939be3a6ab, 0xb48affa681a5d78c}}, gfP2{gfP{0xf6cc6d59cfd8d539, 0xaf5819f468d3fe5f, 0xcaa328bd2ddb3f0, 0x527c920b9ec65f0f}, gfP{0x998ba7745e29648, 0x670bc5f7a5448389, 0xd1be67326a8711dd, 0x6e0d3eaabff5f15f}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x943d5b627b906a54, 0x7460561138192267, 0x3cb8337f29263072, 0x7f7114d8cecfc57b}, gfP{0xe10d95479e794bc8, 0xa624f8f9d142ef24, 0x2dd7540b8bc449b4, 0xd8f46e12f73ac5f}}, gfP2{gfP{0x9b45a54fae9e9a46, 0x1a5d223f1b73fca5, 0xf1406ad7859d5ba, 0x1a26eb34a08d1ec6}, gfP{0x24c61d91ca380568, 0xf0626bae511cab1a, 0x9dd66980de4f38ad, 0x92b3c95897fd113c}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xda483ff0bb62df1a, 0xeb134b39c74a37c5, 0x2ae5068eb79c96fc, 0xf7642885b050b8a}, gfP{0xf20e4e5448636a6b, 0xa9a0ff9540548478, 0xfb27088932a8c3e6, 0x5c1b230723613f0c}}, gfP2{gfP{0xcf929f7f0f738704, 0xc01b4b18e10ad0a, 0xeda7ec18c9ef386, 0xaa8f937035782b5c}, gfP{0x5b42df856430d3cb, 0x5bb8e4e396b88441, 0xf63c7bc122317adf, 0x39f9b502199067d5}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x566568ebfa697d53, 0x6d1a1680431fa741, 0x2f08363a753a4497, 0x5ff3d3c66af11719}, gfP{0xf907539b93a85ba0, 0x9ad1b83749a47934, 0x14f85fa0e9843659, 0x621f5ae4b30ecaa}}, gfP2{gfP{0x5915c0bb067ed480, 0x61bb2660d1cab0f2, 0xd1569f278e3d3015, 0x3b2eedff6e88373d}, gfP{0xa6551ca81a79e87f, 0x7f7b7738dc4459c7, 0xf9007221473dcdd8, 0x13825865a16f639b}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x46cbebb557a5d1e8, 0x9f8dceefb49f391c, 0xc7641edf86a5eb8a, 0xb453a4abd25be7ba}, gfP{0x1f467111449e2174, 0x82a758ed1fc562d9, 0x53961553dfb00c87, 0x6a8f84cb8dad88d7}}, gfP2{gfP{0xcb8de7d6be772f36, 0xc3ab2d81490dbe7c, 0x3766281bd2364ae, 0x923512c5acbda894}, gfP{0x39478b2b95a3226a, 0xe0ee21805ccb3d41, 0x686650632b28fa30, 0x5eeea238d6907c85}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xb9f971efcfaa8c3, 0x8b8c2418e55a8bce, 0x2013828b04d9f5ef, 0x8cb2353da772f50c}, gfP{0x4c1cd61f6f586878, 0x259f211be3b5e7e5, 0x424d9999ce56492d, 0x85414bb86bc9851a}}, gfP2{gfP{0x55959697220198d7, 0x8a7746d37ea27a5f, 0xcc79c587d1ddb883, 0x248d3b949fc2fe93}, gfP{0x62609a5af25d336e, 0xd0fe6ebe9e52b6f8, 0x911c3d8b7f0bcb9e, 0x7cf7b4e7af3614c8}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x76795977b9a656b8, 0x1b2f90113d2a35dd, 0xa4ad495020f7096f, 0x38d04e3173069a08}, gfP{0xc9d7c5cdafa416a2, 0x297d5d0f31ee459, 0x90d4186dc7f7556, 0x5241bbedab29b965}}, gfP2{gfP{0x5da5128d1f28e82f, 0xa27c0e593b4926e2, 0xbf9dd0c6f60257f7, 0x563109a6668ddaa2}, gfP{0x41c0ed07a2426b8, 0x63433cae0b0aeadc, 0xcb2f4dea9de65eb3, 0x731f1fc1f3f56b63}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xf320b3e2b86539d1, 0x3a7807d130f81297, 0xd219a0e595b27508, 0x3c3d8d73f2090056}, gfP{0xa311109abbac91c3, 0x624d7560c3e69947, 0x3d8361a527bb771f, 0x4fcda018d5123ac5}}, gfP2{gfP{0x642068e33c2dfd82, 0x5b20cdcdc3d19e2c, 0xe118e76e057aa8d9, 0x1e0b2dca3da3092b}, gfP{0xab6cbe14ab45670b, 0x680d8b417958423d, 0x86e0480829944c67, 0x74dbb33433703cb2}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x37b5309b690fa7bc, 0x163d49295452f0d4, 0xa33a47c0cf3216ee, 0x148715bc07eae3d4}, gfP{0xb80f9eae18ce302, 0xcdfa67ed32440f81, 0x916518d79bb4e4b3, 0x23a672689c9498b2}}, gfP2{gfP{0xdaf6928f75ebc573, 0x5d449b0a6ee31a5a, 0xfb73dbeb8f870641, 0xd11a62e0d766353}, gfP{0xb8d0a80bd626e7f9, 0x49108e6efb8b3384, 0x82b33c0e82d0f6fc, 0x6bcf7d6e6300c0fd}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x6a1dc63ce26b0a4b, 0x719e3191fa73f9ed, 0xaf4e07f65eac1ca3, 0x2a852a43ef63d46e}, gfP{0x7f056bb26b2c1530, 0x8ca3f115045bbc19, 0x19defbed6cd69bf3, 0x256cabc2330b171c}}, gfP2{gfP{0xdec0cb66357de555, 0x4acaca80c80a2cf0, 0x74476cbfcc927e5a, 0x6fa8e07d79c60845}, gfP{0x745faeba8044b9b1, 0xacf370b2edf73f56, 0xeeee51e69022f2f0, 0xe2a77b7ce8a853}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x8f5cdf4fecb88902, 0x5ae0e1b219f03f42, 0xe31a03c93435fc88, 0x608d74cd614f5067}, gfP{0x1d62162cd5de00c3, 0xe16a645f01a2db09, 0x47987d297541aeec, 0xb006fad8dfd60492}}, gfP2{gfP{0xd927d6279b2c27a4, 0x1be594831c3b406e, 0x15929a45f2c1fd2a, 0x241eb333d157b598}, gfP{0x589c51d064d938dd, 0xebd3a23426f8c8ce, 0xb66d83f6af2de0c8, 0x6b4dd64e51efb83b}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x2694b9652aeaa46d, 0xb87391e4c46dbcb6, 0x6d5f115aa51cd3ce, 0x910fcb1286bfa6d9}, gfP{0x3b7ed8eb3f1b52f3, 0xa708ab6f44e3fd9a, 0xb843a75597b3f20a, 0x540a11e53dc9e345}}, gfP2{gfP{0xa036089b77cc5808, 0x58f54763521bf251, 0xdb1a413a5369c82b, 0x6e28cece5ee15273}, gfP{0x965e8557508c8720, 0xd389101868c5de2c, 0x12ec8ce0323b378c, 0x3ba7f4118a6f39ad}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x2fb1f61599e8aade, 0xc0269c85654ceaca, 0x9295fb4fa03a9865, 0xe187d689b2e6ce0}, gfP{0x2d1174cd36b1cbaa, 0x37cbe64987683afd, 0x793b6afc43556e65, 0x90f7cf44c68904b0}}, gfP2{gfP{0x3c68fe8a35d0a4f0, 0x3390063e3b99b8b1, 0xb2ce3245ac560deb, 0x3debec0acbb93743}, gfP{0xeeea64976ea9cffd, 0x86258dc2b93e6ab0, 0xef1a840fe0286c, 0xb24488485c63cffa}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x8d3199ac9ca44c43, 0x6c4da3476e87678b, 0x76c4634eae10a911, 0x6659c5ff910d2707}, gfP{0xeb2e2989c5743de7, 0xb88f04b73fd222cc, 0x5895c37b3665c4b8, 0x949689ffdd9a0c6e}}, gfP2{gfP{0x299c510b3bb74be1, 0xec2c8dcafd89ed71, 0x95e7bd2a01e59ce3, 0x591f8e9a6bace5b6}, gfP{0x424101afe282abf2, 0xb2180c00db764a20, 0x94645da2bed8a824, 0x2b469b3c87f28654}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x28db26d94e1c60f6, 0x43a5e5d9d4aea227, 0x4ec41aab0cc11e5c, 0x8c97ee4fb225852b}, gfP{0xa729d37daed69cd2, 0x9e231e4743428538, 0x7c85266ce7986afd, 0xb2e255dac59e92bc}}, gfP2{gfP{0x6e5549840a76cb33, 0xfe0e233e0eb0cc80, 0xf0c7d6a78e542f00, 0x6c3b946833908a7a}, gfP{0xa2d0ddf75f67312a, 0xf71d542ea4328152, 0xeeeffff14544b1a0, 0x3608a8aeb73333d}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x963f257f8e6b4fc5, 0x4867384a09de98a3, 0xc16f3e318c00c338, 0x2339427fd57b33be}, gfP{0x1e2efc99cf724e1d, 0x1c548432a5e2e9ef, 0x591a62a380c35daf, 0x3af7e6505b1de516}}, gfP2{gfP{0x4878019f27433599, 0x199bd0922eced22e, 0x2fbef54a0a621905, 0x9175413e481e2126}, gfP{0xd1c0a8957a5425fb, 0xdee1debd78d6d06b, 0xcbc6ef82ff98b836, 0x5044039304e8f798}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xddd114ae522f4fee, 0x84caf13ed0c06a2f, 0x40f0d173048bdffe, 0x393a4c9f4f68f644}, gfP{0xaa05a786584a0fec, 0x1b4a0f359e9e9548, 0x6b24a330193b80f2, 0x294da919a125f80c}}, gfP2{gfP{0x6fefacffbff7845b, 0xfdcf5cd7ce7787ec, 0x73659c0646f595d3, 0xa73d83af5c89237a}, gfP{0x250792b3f1b68de6, 0xc4aa6114500a6980, 0x2e4da2fe70bc5d88, 0x57ba7cb42e16c489}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x8ea643ac5e0f264f, 0x8aa23538140b2f00, 0x29f8675ca0bd4174, 0xa3f334d059636900}, gfP{0x720c56cc0abd3309, 0xc7248cd070b16a5c, 0xe8b54023ae24c05a, 0x7ae8333488731358}}, gfP2{gfP{0xdc74f13673695ec3, 0x88c59184e3cac3f4, 0xccaa3523e0a4c27a, 0x69dbe0f1f20d2180}, gfP{0x17f32ec1fdeda8fa, 0x28225a420ec88806, 0xc0abceb6ee15a59f, 0x418a7c899ee87166}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xaa49c6a00aaa592b, 0xa71e1382223a6d09, 0x16f504c134454dc0, 0xa2c92e45918930f2}, gfP{0x2a407d979e216335, 0x98a6c4c8321bb7d2, 0x95796881a5499600, 0x287dd8b583a64cd}}, gfP2{gfP{0xdcb17a0d3d772e1f, 0xd938ce4bab3cac00, 0xe47c52e83f23409, 0x7b620cd5a0d00e08}, gfP{0xc6544872877d253c, 0x2b04c26aa7dc3129, 0x9f13e69953a90d01, 0xac86800f85ffce26}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x167084748e3fa899, 0x9e9423144cca5e0d, 0x182de5c99d92471e, 0x720a3dd2ccbafa98}, gfP{0xdbb99e1b1d6aa5cd, 0x399fe8547cb3640d, 0xca47581b69e5b887, 0x7f464d8ece7415e5}}, gfP2{gfP{0x96ba738dbff41553, 0xa87fe18689961d36, 0xc54424903c779398, 0x7ffb2484d964e35f}, gfP{0xc59a7ddf1cdb6121, 0x888c4bb9837949cf, 0xc9c3fb4a0605ba08, 0x3cb3c55f92ba8b99}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xcce559d695e39fd, 0xd40ad0113f4497e5, 0x1cfe28114ef5eff8, 0x49afdbe4cd94cb03}, gfP{0xd1a7e1506d7e4f91, 0x458f107051eb1e9b, 0x3c4bc777c6a56c73, 0x2724c4f4206f1f89}}, gfP2{gfP{0x31622954ba0b0218, 0xef5a869a74d7671d, 0x5fce0e64462d2620, 0x4b448344fbe3ea22}, gfP{0x7b94725d9ee9aa50, 0x4acab3bac255ff9d, 0xf96737aa68acbb83, 0x7be5b0a9cc964f8d}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x8c1aa1a07455c9ce, 0xb643274e61e74c3d, 0x57998d3df575e533, 0x3db948259c83556d}, gfP{0xbf77e8cf47be3e08, 0x4739f6154df2c982, 0x44d933111bd280d8, 0x4622132b6661450}}, gfP2{gfP{0x840af77af437ee38, 0x5bb42dab93445c9f, 0x4ae310a801ead073, 0x3925acb2d7f37018}, gfP{0xe774ce3ad4dd0178, 0xb693efeb505561de, 0x58f2ff25b3b0cd70, 0x54c58e77f6f0ca7f}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x1c242a395ae919a5, 0xb81d8d523fe32b4, 0xb30636ef3903018, 0x31c5ca9ce6e8a5a1}, gfP{0x3d5e17802eefb10d, 0x25f8b2157b3cbae1, 0x6627f86712164532, 0x48e9f2171b782ade}}, gfP2{gfP{0x8a3a9846b83b332d, 0xed443b289f8dba64, 0x60d605456c79d010, 0x7473dd12542840d6}, gfP{0x19d211add8c857d, 0x5d6ecb13c6c3f4d4, 0xf24a4c008893b566, 0x43fb42d714232ed9}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x76b2c6bdc2222290, 0x7db1f5730d81f879, 0x8b4113c56bc07e35, 0xaa9d9e5da05e8ebe}, gfP{0xa6985272f1c0688e, 0xe3635eeaf743d25f, 0xf62fa77af3344cf9, 0x47c35cda4a1661ce}}, gfP2{gfP{0xe99ec119a8c80491, 0xb68b6c6f7eaee42f, 0xd45b7cf3debda5f6, 0x1604e2b075ad0c2f}, gfP{0x7ac0f4523bfd292a, 0x71e60dc95ef3278e, 0xb110e93679a41d95, 0x47d4a54f9e03ed5f}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xb378749c79c2ec96, 0x2743944cad248a73, 0x39740bf8208eaf5d, 0x7ca097be86a32e94}, gfP{0xe854a7a5c5fed964, 0xdb2295c1dfb5f5f2, 0x6906f255e15dccbb, 0x68fd0e8954702e28}}, gfP2{gfP{0x76358a35550053d6, 0x85972a6e4f80ae21, 0x400b4fd86ac2ebf7, 0x75a777fc3d290c13}, gfP{0x18e0e53defe16766, 0x61f3d119903e1c3c, 0x880c21dddc5423c2, 0x9fd5d19af1cc24fa}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x59166f63d8d2ceed, 0xfc20fb66d306437f, 0xc49d5e37c7818242, 0x297d4bce22d0c089}, gfP{0x357bf61d958eb05b, 0xf696c91bbbd36, 0x306ba7427774560c, 0x6ed2732e78588ad4}}, gfP2{gfP{0x12d622277c8d2496, 0x9bec23169bc5b9e, 0xf32812d5f9a7bd27, 0x9cbc28f250a3f697}, gfP{0x749b37e3cd9d5332, 0xb7213cf2bd799520, 0xe7e1687d88551914, 0x27f399b2b41bf310}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x52e3e0172a0340f, 0xf8252b4ace03374c, 0x6519f575e0be126, 0x20e87526bbca5668}, gfP{0xc963b3a32511bd3c, 0x90a7571d8bfa6cdc, 0x7f682e43a250b247, 0x7e6272ab5f8f912}}, gfP2{gfP{0x1634fac79f6e60cd, 0xcd760856111e3e44, 0xcc46acd8693e4b42, 0x9fb6d40736837e43}, gfP{0x796fe72212d0b16f, 0xc60b4cb89b762bcf, 0x7e9b7f5303c3af9b, 0x6df81fe46daeb29a}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x934f8d54894b67c8, 0x93ddf59b3b869d43, 0x7812309c06ea510f, 0x43bc2368093b2480}, gfP{0xe373a77ca2115129, 0x28f66874800be61a, 0x4eb3d9bba20b8e29, 0x2ab88d941075207b}}, gfP2{gfP{0x6cfa3a92a57c8f8a, 0xcda1c7c66457982b, 0x56b2aac15926f809, 0x860f2605fd8aaf56}, gfP{0xafed39037374594e, 0x28b8c15540d84a19, 0x3d79f15e2cf93153, 0x5617262402af8dbb}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x8e19c8c540d2ef63, 0x563f49737c1ed88e, 0xaa9351ccd5cc839b, 0x16cbab0d34390ea0}, gfP{0xca591df84ba68420, 0xd55762ef652cd2b6, 0x1623f26e3f2e3fb2, 0x36cd5a785a1863e5}}, gfP2{gfP{0x4b99415a2590e904, 0x4722d1b5c59c6859, 0xf6de2386d4288f17, 0x62c03159c3e9fb90}, gfP{0xa3f85900f0282524, 0x2ee893a11301ddf6, 0x2aab77c9ce08ba9d, 0xa01d76bdbbc1a412}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xc2ef9bf5d10a028a, 0xc941e6581bdae63b, 0x3295ede22e0e23d7, 0xb3bcba084eaece3b}, gfP{0x2ba14ed29d7d2a5b, 0xc4f05067ae6224ac, 0xbe7d80b02bf45779, 0x93f8b84b8c73e01a}}, gfP2{gfP{0x16af3e1b298a0ce, 0xd9298d346c0907b9, 0x65d91df36d336f7f, 0x51782c994e7996e7}, gfP{0xfdf3daddbf7e0193, 0xbbf0a876d5f9ccb0, 0xbebca0d062684f64, 0x3c3939fd1f4516c0}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x868aea26c10f33f3, 0x7b4bae0211f86bc, 0x9196f953248cd79e, 0xa6495863ce4e79c0}, gfP{0x1afbbb091e8a3468, 0x735291ecd62dfd3c, 0x99427000902c7824, 0x4946e69aab98f1db}}, gfP2{gfP{0xb9e962841de799a7, 0xb560c36b6d9b6845, 0xf7ad5d4873750fc5, 0xb53f8916035af35}, gfP{0x7fea322f9bc0a7b3, 0x4e242f65cae5657b, 0xa9ea3206bb92935a, 0x6cbd3981233a60b6}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xff03e6a3ef9de694, 0x6b03bcd0eded567f, 0x5f85220ba4a64e92, 0xbdbb57b5de7793d}, gfP{0x86e3b27a5faa79e0, 0x97405c569f222095, 0x8e8743ace267fab6, 0x2c631f9035be5a10}}, gfP2{gfP{0x61c7df933f79479d, 0xdf3ee52aea517eb6, 0x603b5997b20dca1e, 0x87ad73153d0d8910}, gfP{0x6ed21fce122a9927, 0x5aac7617229b4ceb, 0xacb9fb2265362a6d, 0x2b75e8526d6301c5}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x9fac86d3b4aacfe0, 0xc3240bde93d6a1e7, 0x956bb6488fe51799, 0x13421a11d832df81}, gfP{0xb9999bcf8eb3e821, 0x2425d2e4ddc859e0, 0xa885947346aca395, 0x4fc4aba02c9b5636}}, gfP2{gfP{0x10c8ba0019182a8e, 0xc848d79f007f2a72, 0x323ec61c1c0a41b6, 0x21336b43df4a7781}, gfP{0x8863e0ce5d1fd255, 0x8db79b635a21b59f, 0x1f305718567c0ede, 0x93cd082985847592}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xb62ad0c32d33817c, 0xc825f1f1e27d1f93, 0xd8c8659951ba04ae, 0x37f37f29c772f8b3}, gfP{0x2ad007b2cbbc2430, 0x82f468ab6685c44e, 0xccb7b32d135656fd, 0x4df23f5f93da1795}}, gfP2{gfP{0x77187c06841fb630, 0xc3c1f4d948dfcecf, 0xd17c08ae46a0027f, 0x4570e32218bc414f}, gfP{0x657a7c36d6f8f376, 0xed3c6e16a31245fd, 0xf64c16c0a423b3d8, 0x816aa7c4dabde484}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x91748233aff19906, 0x4a7d58e04a3155aa, 0xf86789852ea0ad93, 0x796fb024793a51e5}, gfP{0x656ad389db60618f, 0x33d0f67f712642b6, 0x85f07a3ab214cfd9, 0x853a20b61d3ae4a2}}, gfP2{gfP{0xc7e07f74fbea5780, 0xd73bdbcfa36a5d4e, 0xe671b35a0331a08c, 0xa53d81a4a58f5049}, gfP{0x55d8ea360b015223, 0x74171d1cfb7f5352, 0x8bb7a3e8a750735d, 0x625668a2a9360ad4}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xf885da0302250c7e, 0x89468e3a9ad1ceb2, 0xd0d72037b723df04, 0x151c6445950e663a}, gfP{0x9958b5040697f591, 0xe7116ac85a0e9e2, 0xdb49c775d1cb47cf, 0x37ce02e2c70643a5}}, gfP2{gfP{0x74448de55660ba95, 0x7fac68c318b395af, 0xcddb7d2fce635b08, 0x12aa110eb6e3e84}, gfP{0x124de5ff21d94d86, 0x56673158bce64560, 0x33f67fc6f7e41e43, 0x97ef147920d0916e}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x3ac82d8bc7e0aa9, 0x1acbc14eb65147bc, 0x95cd23511cb7b7d0, 0x760195ff517947cf}, gfP{0x8543c20ba5e2c51b, 0x5bda803851c0145b, 0xf2ce4f9b2be070be, 0x544ccc199ae918bb}}, gfP2{gfP{0x405955d173fb0559, 0x9e6d4d4359390bc0, 0x8b1371ab74b405ab, 0x6bd74edee7824664}, gfP{0xa338cdd01bf11950, 0xcd986180fa89fb94, 0x6e79624b495549aa, 0x8a07716292614fec}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0x3001b17bfd493ae9, 0xf80fb74594947696, 0x38c99c9e7674408e, 0xa7c5f26fac9f49cd}, gfP{0x7a2f926ddbaf0168, 0x24d415ae119b1e9a, 0x25725129258655e4, 0x176f10ce6bb6fadb}}, gfP2{gfP{0x9d4cc814762b09fa, 0x8f0550a1e8ddf280, 0xb344ceb4a377ef2c, 0x2b291be9f626f572}, gfP{0xe3a083c8bb3d0053, 0xa27abee309291d, 0x85e8f50519c869c9, 0xaa12a1ee47e7a666}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xce404b616823f83b, 0x1b12a98a5bd1fd4d, 0x74add5c446081091, 0x93f4422f9d33581e}, gfP{0xb5de0937accc3d21, 0xa75e18e026c6baca, 0x61da105e71efd3a2, 0x9cffa5bb6c7495c1}}, gfP2{gfP{0x6ceb7066525d503d, 0xa9675abc4adcb356, 0xa346c7d1d4aca78d, 0x54b372122c47c90c}, gfP{0x313e099da7236225, 0xae23901482a2e645, 0x16eca9c09e1d0fc2, 0x84cb968808ada134}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xd759ab805b65b719, 0x91597a0f027971e, 0x5c185855c7114447, 0x8103c403d1a122aa}, gfP{0x546ac1e2579d12f3, 0xf0c9b194f301522a, 0x4929ba6fd446dc34, 0x3c58d52e253a1f17}}, gfP2{gfP{0x1b30ee109f4e5a81, 0x8844fd1a108d2f44, 0x193ff743efcef2a5, 0x4af9a10a5b40108a}, gfP{0x435c0b7e6883ded1, 0x57dd366b941197e, 0x70e23efe30b9b50b, 0x80cd44788a7d6503}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xc6d769af16dafe31, 0xc53c4e11eb8f27ca, 0xe6ad9cb891765c42, 0x6033c79a6d22e74c}, gfP{0x3de0cab7a6e3f773, 0xa366720ee4387515, 0x509c18a52af27606, 0x7c41f412bb713438}}, gfP2{gfP{0x4af7ea7a02b56135, 0x2031982fe97a2ef8, 0x59f73b7fd92ea114, 0x39d60af40e61d85c}, gfP{0x8d2d9a1fc0770fca, 0x2002049fd6c529fa, 0x27752e5ac94cee09, 0x97d30bb4a52001c8}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
{gfP2{gfP{0xc342e2a9d383550d, 0xe27b45952b32ccda, 0x9b3fb5a9ad72b5af, 0x4ae58491f709dbf2}, gfP{0xd47b1fa1e4d41b05, 0x5935421529f6f93b, 0x4c68f3a729563037, 0x9f00750f80dabb5b}}, gfP2{gfP{0x80d98739a9bea45a, 0x55a4356c31fd4871, 0xc972b7a5f496315b, 0x646bfe4add031052}, gfP{0x5980d97d6a05302b, 0xc2b4c5194859be3a, 0x3526f8fc934c8fef, 0x2d53e02d0e4b27bb}}, gfP2{gfP{0}, gfPOne}, gfP2{gfP{0}, gfPOne}},
}
// if free - constant time.
func (c *twistPoint) MulBase(scalar *big.Int, table []*twistPoint) {
// t = inf.
t := &twistPoint{
gfP2{gfP{0}, gfP{0}},
gfP2{gfP{0}, gfP{0x1a9064d81caeba83, 0xde0d6cb4e5851124, 0x29fc54b00a7138ba, 0x49bffffffd5c590e}},
gfP2{gfP{0}, gfP{0}},
gfP2{gfP{0}, gfP{0}},
}
switch len(table) {
case 32:
//nIsInfinityMask := ^uint32(0)
var tableOffset uint
// The loop adds bits at positions 0, 64, 128 and 192, followed by
// positions 32,96,160 and 224 and does this 32 times.
for i := uint(0); i < 32; i++ {
//if (i != 0) {
// t.Double(t)
//}
t.Double(t)
tableOffset = 0
for j := uint(0); j <= 32; j += 32 {
bit0 := scalar.Bit(int(31 - i + j))
bit1 := scalar.Bit(int(95 - i + j))
bit2 := scalar.Bit(int(159 - i + j))
bit3 := scalar.Bit(int(223 - i + j))
index := bit0 | (bit1 << 1) | (bit2 << 2) | (bit3 << 3)
t.Add(t, table[tableOffset+index])
tableOffset += 16
}
}
c.Set(t)
case 256:
for i := uint(0); i < 32; i++ {
t.Double(t)
bit0 := scalar.Bit(int(31 - i))
bit1 := scalar.Bit(int(63 - i))
bit2 := scalar.Bit(int(95 - i))
bit3 := scalar.Bit(int(127 - i))
bit4 := scalar.Bit(int(159 - i))
bit5 := scalar.Bit(int(191 - i))
bit6 := scalar.Bit(int(223 - i))
bit7 := scalar.Bit(int(255 - i))
index := bit0 | (bit1 << 1) | (bit2 << 2) | (bit3 << 3) | (bit4 << 4) | (bit5 << 5) | (bit6 << 6) | (bit7 << 7)
t.Add(t, table[index])
}
c.Set(t)
default:
panic("not precomputed")
}
}