init: v1.0.0
This commit is contained in:
+301
@@ -0,0 +1,301 @@
|
||||
package sm9
|
||||
|
||||
import (
|
||||
encoding_asn1 "encoding/asn1"
|
||||
"math/big"
|
||||
"time"
|
||||
|
||||
"golang.org/x/crypto/cryptobyte"
|
||||
cryptobyte_asn1 "golang.org/x/crypto/cryptobyte/asn1"
|
||||
"xdx.jelly/xgcl/gerrors"
|
||||
"xdx.jelly/xgcl/gmath"
|
||||
oid "xdx.jelly/xgcl/identifier"
|
||||
"xdx.jelly/xgcl/sm/sm9/errors"
|
||||
"xdx.jelly/xgcl/sm/sm9/internal/bn256"
|
||||
)
|
||||
|
||||
// GM/T 0080 SM9密码算法使用规范
|
||||
// ASN.1编解码
|
||||
|
||||
// GMT/T 0006 OID定义
|
||||
var (
|
||||
OidSm9 = oid.OIDSM9
|
||||
OidSm9Sign = oid.OIDSM9Signature
|
||||
OidSm9KeyExchange = oid.OIDSM9KeyExchange
|
||||
OidSm9Encryption = oid.OIDSM9Encryption
|
||||
OidSm9EncryptionEcb = oid.OIDSM9EncryptionECB
|
||||
OidSm9EncryptionCbc = oid.OIDSM9EncryptionCBC
|
||||
OidSm9EncryptionCfb = oid.OIDSM9EncryptionCFB
|
||||
OidSm9EncryptionOfb = oid.OIDSM9EncryptionOFB
|
||||
OidSM9KeyEncupsulate = oid.OIDSM9KeyEncupsulate
|
||||
)
|
||||
|
||||
const numBytes = 32
|
||||
|
||||
// Identifier GM/T 0090定义身份标识
|
||||
//
|
||||
// deprecated: Identifier moves to package xdx.jelly/xibc
|
||||
type Identifier struct {
|
||||
// 标准中多了一个explicit
|
||||
Version int `asn1:"default:0"`
|
||||
IdentityType encoding_asn1.ObjectIdentifier
|
||||
Alias string `asn1:"utf8"`
|
||||
IdentityData []byte
|
||||
Serial *big.Int `asn1:"optional,explicit,tag:0"`
|
||||
ValidStart time.Time `asn1:"generalized"`
|
||||
ValidEnd time.Time `asn1:"optional,explicit,generalized,tag:1"`
|
||||
IdExtentions []byte `asn1:"optional,explicit,tag:2"`
|
||||
}
|
||||
|
||||
func (id *Identifier) MarshalASN1() ([]byte, error) {
|
||||
return encoding_asn1.Marshal(*id)
|
||||
}
|
||||
|
||||
func (id *Identifier) UnmarshalASN1(b []byte) (rest []byte, err error) {
|
||||
return encoding_asn1.Unmarshal(b, id)
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 主签名密钥
|
||||
//
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
func (k *MastSignPrivateKey) MarshalASN1() ([]byte, error) {
|
||||
var b cryptobyte.Builder
|
||||
b.AddASN1BigInt(&k.Int)
|
||||
return b.Bytes()
|
||||
}
|
||||
|
||||
func (k *MastSignPrivateKey) UnmarshalASN1(data []byte) (rest []byte, err error) {
|
||||
input := cryptobyte.String(data)
|
||||
ok := input.ReadASN1Integer(&k.Int)
|
||||
if !ok {
|
||||
return data, gerrors.WithAnnotating(errors.ErrDecodeASN1Failed, "parse MastSignPrivateKey failed, read ASN.1 Integer error")
|
||||
}
|
||||
return []byte(input), nil
|
||||
}
|
||||
|
||||
// MarshalASN1 返回ASN.1编码,如果compressed为true,则返回的是压缩形式
|
||||
//
|
||||
// 注:不支持混合形式输出
|
||||
func (k *MastSignPublicKey) MarshalASN1(compressed bool) ([]byte, error) {
|
||||
return k.G2.MarshalASN1(compressed)
|
||||
}
|
||||
|
||||
// UnmarshalASN1 ASN.1解码MastSignPublicKey
|
||||
//
|
||||
// 注:支持tag为0,2,3,4,6,7即无穷远点(0),非压缩形式(4),压缩形式(2,3),混合形式(6,7)
|
||||
func (k *MastSignPublicKey) UnmarshalASN1(data []byte) (rest []byte, err error) {
|
||||
return k.G2.UnmarshalASN1(data)
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 主加密密钥
|
||||
//
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
func (k *MastEncPrivateKey) MarshalASN1() ([]byte, error) {
|
||||
var b cryptobyte.Builder
|
||||
b.AddASN1BigInt(&k.Int)
|
||||
return b.Bytes()
|
||||
}
|
||||
|
||||
func (k *MastEncPrivateKey) UnmarshalASN1(data []byte) (rest []byte, err error) {
|
||||
input := cryptobyte.String(data)
|
||||
ok := input.ReadASN1Integer(&k.Int)
|
||||
if !ok {
|
||||
return data, gerrors.WithAnnotating(errors.ErrDecodeASN1Failed, "parse MastEncPrivateKey failed, read ASN.1 Integer error")
|
||||
}
|
||||
return []byte(input), nil
|
||||
}
|
||||
|
||||
// MarshalASN1 返回ASN.1编码,如果compressed为true,则返回的是压缩形式
|
||||
//
|
||||
// 注:不支持混合形式
|
||||
func (k *MastEncPublicKey) MarshalASN1(compressed bool) ([]byte, error) {
|
||||
return k.G1.MarshalASN1(compressed)
|
||||
}
|
||||
|
||||
// UnmarshalASN1 ASN.1解码MastSignPublicKey
|
||||
//
|
||||
// 注:支持tag为0,2,3,4,6,7即无穷远点(0),非压缩形式(4),压缩形式(2,3),混合形式(6,7)
|
||||
func (k *MastEncPublicKey) UnmarshalASN1(data []byte) (rest []byte, err error) {
|
||||
return k.G1.UnmarshalASN1(data)
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 用户密钥
|
||||
//
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
func (u *UserSignKey) MarshalASN1(compressed bool) ([]byte, error) {
|
||||
return u.G1.MarshalASN1(compressed)
|
||||
}
|
||||
|
||||
func (u *UserSignKey) UnmarshalASN1(data []byte) (rest []byte, err error) {
|
||||
return u.G1.UnmarshalASN1(data)
|
||||
}
|
||||
|
||||
func (u *UserEncKey) MarshalASN1(compressed bool) ([]byte, error) {
|
||||
return u.G2.MarshalASN1(compressed)
|
||||
|
||||
}
|
||||
|
||||
func (u *UserEncKey) UnmarshalASN1(data []byte) (rest []byte, err error) {
|
||||
return u.G2.UnmarshalASN1(data)
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 签名结构
|
||||
//
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
// SM9Signature ::= SEQUENCE{
|
||||
// H OCTET STRING, ——杂凑分量,算法是H2(见GB/T 38635.2—2020)
|
||||
// S BIT STRING ——签名结果(见GB/T 38635.2—2020)
|
||||
// }
|
||||
|
||||
func (s *Signature) MarshalASN1(compressed bool) ([]byte, error) {
|
||||
var b cryptobyte.Builder
|
||||
h := make([]byte, numBytes)
|
||||
err := gmath.FillBytes(&s.H, h)
|
||||
if err != nil {
|
||||
return nil, gerrors.WithAnnotating(
|
||||
gerrors.ChainErrors(errors.ErrDecodeASN1Failed, err),
|
||||
"Signature.H is bigger than 256 bits",
|
||||
)
|
||||
}
|
||||
|
||||
b.AddASN1(cryptobyte_asn1.SEQUENCE, func(b *cryptobyte.Builder) {
|
||||
b.AddASN1OctetString(h)
|
||||
b.AddASN1BitString(bn256.MarshalG1(&s.S, compressed))
|
||||
})
|
||||
|
||||
return b.Bytes()
|
||||
}
|
||||
|
||||
func (s *Signature) UnmarshalASN1(data []byte) (rest []byte, err error) {
|
||||
input := cryptobyte.String(data)
|
||||
var inner, hBytes cryptobyte.String
|
||||
var sBitString encoding_asn1.BitString
|
||||
if !input.ReadASN1(&inner, cryptobyte_asn1.SEQUENCE) ||
|
||||
inner.Empty() ||
|
||||
!inner.ReadASN1(&hBytes, cryptobyte_asn1.OCTET_STRING) ||
|
||||
!inner.ReadASN1BitString(&sBitString) ||
|
||||
!inner.Empty() {
|
||||
return data, errors.ErrDecodeASN1Failed
|
||||
}
|
||||
s.H.SetBytes(hBytes)
|
||||
_, err = bn256.UnmarshalG1(&s.S, sBitString.RightAlign())
|
||||
if err != nil {
|
||||
return data, err
|
||||
}
|
||||
return []byte(input), err
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 密文结构
|
||||
//
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
// SM9Cipher ::= SEQUENCE{
|
||||
// EnType INTEGER, ——加密方式
|
||||
// C1 BIT STRING, ——密文第一部分C1(见GB/T 38635.2—2020)
|
||||
// C3 OCTET STRING, ——密文杂凑值
|
||||
// C2 OCTET STRING ——密文
|
||||
// }
|
||||
|
||||
func (c *Cipher) MarshalASN1(compressed bool) ([]byte, error) {
|
||||
var b cryptobyte.Builder
|
||||
c2Bytes := make([]byte, len(c.C)+len(c.IV))
|
||||
n := 0
|
||||
if c.EncType > 1 {
|
||||
n += copy(c2Bytes, c.IV[:])
|
||||
}
|
||||
n += copy(c2Bytes[n:], c.C)
|
||||
c2Bytes = c2Bytes[:n]
|
||||
|
||||
b.AddASN1(cryptobyte_asn1.SEQUENCE, func(b *cryptobyte.Builder) {
|
||||
b.AddASN1Int64(int64(c.EncType))
|
||||
b.AddASN1BitString(bn256.MarshalG1(&c.C1, compressed))
|
||||
b.AddASN1OctetString(c.H[:])
|
||||
b.AddASN1OctetString(c2Bytes)
|
||||
})
|
||||
return b.Bytes()
|
||||
}
|
||||
|
||||
func (c *Cipher) UnmarshalASN1(data []byte) (rest []byte, err error) {
|
||||
input := cryptobyte.String(data)
|
||||
var inner, c3Bytes, c2Bytes cryptobyte.String
|
||||
var c1BitString encoding_asn1.BitString
|
||||
var encType uint32
|
||||
if !input.ReadASN1(&inner, cryptobyte_asn1.SEQUENCE) ||
|
||||
!inner.ReadASN1Integer(&encType) ||
|
||||
!inner.ReadASN1BitString(&c1BitString) ||
|
||||
!inner.ReadASN1(&c3Bytes, cryptobyte_asn1.OCTET_STRING) ||
|
||||
!inner.ReadASN1(&c2Bytes, cryptobyte_asn1.OCTET_STRING) ||
|
||||
!inner.Empty() {
|
||||
return data, gerrors.WithAnnotating(errors.ErrDecodeASN1Failed, "parse Cipher ASN.1 data failed")
|
||||
}
|
||||
c.EncType = EncType(encType)
|
||||
_, err = bn256.UnmarshalG1(&c.C1, c1BitString.RightAlign())
|
||||
if err != nil {
|
||||
return data, gerrors.WithAnnotating(errors.ErrDecodeASN1Failed, "parse Cipher ASN.1 data failed")
|
||||
}
|
||||
if len(c3Bytes) != len(c.H) {
|
||||
return data, gerrors.WithAnnotating(errors.ErrDecodeASN1Failed, "parse Cipher ASN.1 data failed")
|
||||
}
|
||||
copy(c.H[:], c3Bytes)
|
||||
|
||||
if c.EncType > 1 {
|
||||
if len(c2Bytes) < len(c.IV) {
|
||||
return data, gerrors.WithAnnotating(errors.ErrDecodeASN1Failed, "parse Cipher ASN.1 data failed")
|
||||
}
|
||||
copy(c.IV[:], c2Bytes)
|
||||
c2Bytes = c2Bytes[len(c.IV):]
|
||||
}
|
||||
c.C = append(c.C[:0], c2Bytes...)
|
||||
return []byte(input), nil
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 密文封装结构
|
||||
//
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
// SM9KeyPackage ::= SEQUENCE{
|
||||
// K OCTET STRING, ——生成的密钥
|
||||
// C BIT STRING ——封装的交换密文
|
||||
// }
|
||||
// K作为用户A保留的密钥。C作为交换密文传递给B用户,B用户利用C可以生成K。
|
||||
|
||||
// 这里与标准不同,只是封装C. 密钥不进行封装。即
|
||||
//
|
||||
// SM9KeyPackage := OCTET STRING
|
||||
func (k *KeyPackage) MarshalASN1(compressed bool) ([]byte, error) {
|
||||
var b cryptobyte.Builder
|
||||
b.AddASN1BitString(bn256.MarshalG1(&k.G1, compressed))
|
||||
return b.Bytes()
|
||||
}
|
||||
|
||||
func (k *KeyPackage) UnmarshalASN1(data []byte) (rest []byte, err error) {
|
||||
input := cryptobyte.String(data)
|
||||
var b encoding_asn1.BitString
|
||||
if ok := input.ReadASN1BitString(&b); !ok {
|
||||
return data, gerrors.WithAnnotating(errors.ErrDecodeASN1Failed, "parse KeyPackage ASN.1 data failed")
|
||||
}
|
||||
_, err = bn256.UnmarshalG1(&k.G1, b.RightAlign())
|
||||
if err != nil {
|
||||
return data, gerrors.WithAnnotating(
|
||||
gerrors.ChainErrors(errors.ErrDecodeASN1Failed, err),
|
||||
"parse KeyPackage ASN.1 data failed",
|
||||
)
|
||||
}
|
||||
return []byte(input), nil
|
||||
}
|
||||
@@ -0,0 +1,277 @@
|
||||
package sm9_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"xdx.jelly/xgcl/sm/sm9"
|
||||
)
|
||||
|
||||
func decodeHex(h string) []byte {
|
||||
buf, err := hex.DecodeString(h)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return buf
|
||||
}
|
||||
|
||||
func TestIdentifier(t *testing.T) {
|
||||
id := sm9.Identifier{
|
||||
IdentityType: sm9.OidSm9,
|
||||
Alias: "SM9",
|
||||
IdentityData: []byte("alice@xdx.jelly"),
|
||||
Serial: big.NewInt(12345678),
|
||||
ValidStart: time.Now(),
|
||||
ValidEnd: time.Now().Add(time.Hour * 365 * 24),
|
||||
IdExtentions: nil,
|
||||
}
|
||||
|
||||
b, err := id.MarshalASN1()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
id2 := &sm9.Identifier{}
|
||||
_, err = id2.UnmarshalASN1(b)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !(id.Version == id2.Version) {
|
||||
t.Fatal()
|
||||
}
|
||||
if !(id.IdentityType.Equal(id2.IdentityType)) {
|
||||
t.Fatal()
|
||||
}
|
||||
if !(id.Alias == id2.Alias) {
|
||||
t.Fatal()
|
||||
}
|
||||
if !bytes.Equal(id.IdentityData, id2.IdentityData) {
|
||||
t.Fatal()
|
||||
}
|
||||
|
||||
// Can't comapre id.ValidStart == id2.ValidStart or
|
||||
// id.ValidStart.Equal(id2.ValidStart)
|
||||
if !(id.ValidStart.Unix() == id2.ValidStart.Unix()) {
|
||||
t.Fatal()
|
||||
}
|
||||
if !(id.ValidEnd.Unix() == id2.ValidEnd.Unix()) {
|
||||
t.Fatal()
|
||||
}
|
||||
if !bytes.Equal(id.IdExtentions, id2.IdExtentions) {
|
||||
t.Fatal()
|
||||
}
|
||||
}
|
||||
|
||||
type testKeyVector struct {
|
||||
pri []byte
|
||||
priAsn1 []byte
|
||||
pubAsn1 []byte
|
||||
pubAsn1Compressed []byte
|
||||
}
|
||||
|
||||
var testKeyVectors = map[string]*testKeyVector{
|
||||
"MastSignPrivateKey": {
|
||||
pri: decodeHex("000130E78459D78545CB54C587E02CF480CE0B66340F319F348A1D5B1F2DC5F4"),
|
||||
priAsn1: decodeHex("021f0130e78459d78545cb54c587e02cf480ce0b66340f319f348a1d5b1f2dc5f4"),
|
||||
pubAsn1: decodeHex("03818200049f64080b3084f733e48aff4b41b565011ce0711c5e392cfb0ab1b6791b94c40829dba116152d1f786ce843ed24a3b573414d2177386a92dd8f14d65696ea5e3269850938abea0112b57329f447e3a0cbad3e2fdb1a77f335e89e1408d0ef1c2541e00a53dda532da1a7ce027b7a46f741006e85f5cdff0730e75c05fb4e3216d"),
|
||||
pubAsn1Compressed: decodeHex("034200039f64080b3084f733e48aff4b41b565011ce0711c5e392cfb0ab1b6791b94c40829dba116152d1f786ce843ed24a3b573414d2177386a92dd8f14d65696ea5e32"),
|
||||
},
|
||||
"MastEncPrivateKey": {
|
||||
pri: decodeHex("0002E65B0762D042F51F0D23542B13ED8CFA2E9A0E7206361E013A283905E31F"),
|
||||
priAsn1: decodeHex("021f02E65B0762D042F51F0D23542B13ED8CFA2E9A0E7206361E013A283905E31F"),
|
||||
pubAsn1: decodeHex("034200049174542668E8F14AB273C0945C3690C66E5DD09678B86F734C4350567ED0628354E598C6BF749A3DACC9FFFEDD9DB6866C50457CFC7AA2A4AD65C3168FF74210"),
|
||||
pubAsn1Compressed: decodeHex("032200029174542668E8F14AB273C0945C3690C66E5DD09678B86F734C4350567ED06283"),
|
||||
},
|
||||
}
|
||||
|
||||
func TestASN1MastSignKey(t *testing.T) {
|
||||
testVector := testKeyVectors["MastSignPrivateKey"]
|
||||
ds := &sm9.MastSignPrivateKey{}
|
||||
_, _ = ds.SetBytes(testVector.pri)
|
||||
b, err := ds.MarshalASN1()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !bytes.Equal(b, testVector.priAsn1) {
|
||||
t.Fatal("MastSignPrivateKey marshal failed")
|
||||
}
|
||||
ds = &sm9.MastSignPrivateKey{}
|
||||
_, err = ds.UnmarshalASN1(b)
|
||||
if err != nil {
|
||||
t.Fatal("MastSignPrivateKey unmarshal error")
|
||||
}
|
||||
if !bytes.Equal(ds.Bytes(), testVector.pri) {
|
||||
fmt.Printf("%x\n", ds.Bytes())
|
||||
|
||||
t.Fatal()
|
||||
}
|
||||
|
||||
pubs := ds.Public()
|
||||
b, err = pubs.MarshalASN1(false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !bytes.Equal(b, testVector.pubAsn1) {
|
||||
t.Fatal("MastSignPublicKey marshal failed")
|
||||
}
|
||||
pubs = &sm9.MastSignPublicKey{}
|
||||
_, err = pubs.UnmarshalASN1(b)
|
||||
if err != nil {
|
||||
t.Fatal("MastSignPublicKey unmarshal error")
|
||||
}
|
||||
if !bytes.Equal(pubs.Bytes(), ds.Public().Bytes()) {
|
||||
t.Fatal()
|
||||
}
|
||||
|
||||
b, err = pubs.MarshalASN1(true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !bytes.Equal(b, testVector.pubAsn1Compressed) {
|
||||
t.Fatal("MastSignPublicKey marshal failed")
|
||||
}
|
||||
pubs = &sm9.MastSignPublicKey{}
|
||||
_, err = pubs.UnmarshalASN1(b)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !bytes.Equal(pubs.Bytes(), ds.Public().Bytes()) {
|
||||
t.Fatal("MastSignPublicKey unmarshal error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestASN1MastEncKey(t *testing.T) {
|
||||
testVector := testKeyVectors["MastEncPrivateKey"]
|
||||
de := &sm9.MastEncPrivateKey{}
|
||||
_, _ = de.SetBytes(testVector.pri)
|
||||
b, err := de.MarshalASN1()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !bytes.Equal(b, testVector.priAsn1) {
|
||||
t.Fatal("MastEncPrivateKey marshal failed")
|
||||
}
|
||||
de = &sm9.MastEncPrivateKey{}
|
||||
_, err = de.UnmarshalASN1(b)
|
||||
if err != nil {
|
||||
t.Fatal("MastEncPrivateKey unmarshal error")
|
||||
}
|
||||
if !bytes.Equal(de.Bytes(), testVector.pri) {
|
||||
t.Fatal()
|
||||
}
|
||||
|
||||
pube := de.Public()
|
||||
b, err = pube.MarshalASN1(true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !bytes.Equal(b, testVector.pubAsn1Compressed) {
|
||||
t.Fatal("MastEncPublicKey marshal failed")
|
||||
}
|
||||
pube = &sm9.MastEncPublicKey{}
|
||||
_, err = pube.UnmarshalASN1(b)
|
||||
if err != nil {
|
||||
t.Fatal("MastEncPublicKey unmarshal error")
|
||||
}
|
||||
if !bytes.Equal(pube.Bytes(), de.Public().Bytes()) {
|
||||
t.Fatal()
|
||||
}
|
||||
|
||||
pube = de.Public()
|
||||
b, err = pube.MarshalASN1(false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !bytes.Equal(b, testVector.pubAsn1) {
|
||||
t.Fatal("MastEncPublicKey marshal failed")
|
||||
}
|
||||
pube = &sm9.MastEncPublicKey{}
|
||||
_, err = pube.UnmarshalASN1(b)
|
||||
if err != nil {
|
||||
t.Fatal("MastEncPublicKey unmarshal error")
|
||||
}
|
||||
if !bytes.Equal(pube.Bytes(), de.Public().Bytes()) {
|
||||
t.Fatal()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestASN1Signature(t *testing.T) {
|
||||
signature := &sm9.Signature{
|
||||
H: *new(big.Int).SetBytes(decodeHex("823C4B21E4BD2DFE1ED92C606653E996668563152FC33F55D7BFBB9BD9705ADB")),
|
||||
}
|
||||
if _, err := signature.S.Unmarshal(decodeHex("73BF96923CE58B6AD0E13E9643A406D8EB98417C50EF1B29CEF9ADB48B6D598C856712F1C2E0968AB7769F42A99586AED139D5B8B3E15891827CC2ACED9BAA05")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// 压缩模式
|
||||
b, err := signature.MarshalASN1(true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
wantedASN1 := decodeHex("30460420823c4b21e4bd2dfe1ed92c606653e996668563152fc33f55d7bfbb9bd9705adb0322000373bf96923ce58b6ad0e13e9643a406d8eb98417c50ef1b29cef9adb48b6d598c")
|
||||
if !bytes.Equal(b, wantedASN1) {
|
||||
fmt.Printf("%x\n", b)
|
||||
t.Fatal()
|
||||
}
|
||||
|
||||
b, err = signature.MarshalASN1(false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
wantedASN1 = decodeHex("30660420823C4B21E4BD2DFE1ED92C606653E996668563152FC33F55D7BFBB9BD9705ADB0342000473BF96923CE58B6AD0E13E9643A406D8EB98417C50EF1B29CEF9ADB48B6D598C856712F1C2E0968AB7769F42A99586AED139D5B8B3E15891827CC2ACED9BAA05")
|
||||
if !bytes.Equal(b, wantedASN1) {
|
||||
fmt.Printf("%x\n", b)
|
||||
t.Fatal()
|
||||
}
|
||||
signature2 := &sm9.Signature{}
|
||||
_, err = signature2.UnmarshalASN1(b)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if signature.H.Cmp(&signature2.H) != 0 ||
|
||||
!signature.S.Equal(&signature2.S) {
|
||||
t.Fatal()
|
||||
}
|
||||
}
|
||||
|
||||
func TestASN1Cipher(t *testing.T) {
|
||||
id := []byte("Bob")
|
||||
rnd, _ := hex.DecodeString("0001EDEE3778F441F8DEA3D9FA0ACC4E07EE36C93F9A08618AF4AD85CEDE1C22")
|
||||
_, pube, _ := sm9.GenerateMastEncPrivateKey(bytes.NewReader(rnd))
|
||||
|
||||
msg := []byte("Chinese IBE standard")
|
||||
// _, _ := sm9.GenerateUserEncKey(id, ke)
|
||||
rnd, _ = hex.DecodeString("0000AAC0541779C8FC45E3E2CB25C12B5D2576B2129AE8BB5EE2CBE5EC9E785C")
|
||||
|
||||
c, _ := sm9.Encrypt(sm9.EncTypeKDF, pube, id, msg, bytes.NewReader(rnd), nil)
|
||||
var data []byte
|
||||
var err error
|
||||
if data, err = c.MarshalASN1(false); err != nil ||
|
||||
!bytes.Equal(data, decodeHex("307F020100034200042445471164490618E1EE20528FF1D545B0F14C8BCAA44544F03DAB5DAC07D8FF42FFCA97D57CDDC05EA405F2E586FEB3A6930715532B8000759F13059ED59AC00420BA672387BCD6DE5016A158A52BB2E7FC429197BCAB70B25AFEE37A2B9DB9F36704141B5F5B0E951489682F3E64E1378CDD5DA9513B1C")) {
|
||||
fmt.Printf("%x\n", data)
|
||||
t.Fatal()
|
||||
}
|
||||
|
||||
if data, err = c.MarshalASN1(true); err != nil ||
|
||||
!bytes.Equal(data, decodeHex("305f020100032200022445471164490618e1ee20528ff1d545b0f14c8bcaa44544f03dab5dac07d8ff0420ba672387bcd6de5016a158a52bb2e7fc429197bcab70b25afee37a2b9db9f36704141b5f5b0e951489682f3e64e1378cdd5da9513b1c")) {
|
||||
fmt.Printf("%x\n", data)
|
||||
t.Fatal()
|
||||
}
|
||||
|
||||
c2 := &sm9.Cipher{}
|
||||
rest, err := c2.UnmarshalASN1(data)
|
||||
if err != nil || len(rest) > 0 ||
|
||||
c.EncType != c2.EncType ||
|
||||
c.IV != c2.IV ||
|
||||
c.C1 != c2.C1 ||
|
||||
c.H != c2.H ||
|
||||
!bytes.Equal(c.C, c2.C) {
|
||||
t.Fatal()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
// package dkgc is the distributed KGC mechanism
|
||||
// CAUTION: this package is currently in an experimental state
|
||||
// DO NOT USE THIS UNLESS YOU KNOW WHAT YOU ARE DOING
|
||||
package dkgc
|
||||
@@ -0,0 +1,113 @@
|
||||
package dkgc
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"io"
|
||||
"math/big"
|
||||
|
||||
"xdx.jelly/xgcl/sm/sm9"
|
||||
)
|
||||
|
||||
type DoubleKGC struct {
|
||||
ks sm9.MastSignPrivateKey
|
||||
commonPubs sm9.MastSignPublicKey
|
||||
}
|
||||
|
||||
func (dk *DoubleKGC) GenerateMastKey() {
|
||||
|
||||
}
|
||||
|
||||
var alpha = big.NewInt(2)
|
||||
var alphaInv = new(big.Int).ModInverse(alpha, sm9.Order())
|
||||
|
||||
func ComputeHHat(id []byte) (*big.Int, *big.Int, bool) {
|
||||
h1 := sm9.H1(id, []byte{0x01})
|
||||
hh := new(big.Int).ModSqrt(h1, sm9.Order())
|
||||
if hh == nil {
|
||||
hh = new(big.Int).Lsh(h1, 1)
|
||||
hh.ModSqrt(hh, sm9.Order())
|
||||
return h1, hh, false
|
||||
}
|
||||
return h1, hh, true
|
||||
}
|
||||
|
||||
func UserRandom0(reader io.Reader, basePoint *sm9.G1) (*big.Int, *sm9.G1, error) {
|
||||
r, err := rand.Int(reader, sm9.Order())
|
||||
if err != nil || r.Sign() == 0 {
|
||||
return nil, nil, err
|
||||
}
|
||||
R := &sm9.G1{}
|
||||
R.ScalarMult(basePoint, r)
|
||||
return r, R, nil
|
||||
}
|
||||
|
||||
func KGC1ComputeData(reader io.Reader, R *sm9.G1, ks *sm9.MastSignPrivateKey, hh *big.Int) (*big.Int, *sm9.G1, error) {
|
||||
r, err := rand.Int(reader, sm9.Order())
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
t1 := new(big.Int).Add(hh, &ks.Int)
|
||||
t1.Mod(t1, sm9.Order())
|
||||
if t1.Sign() == 0 {
|
||||
panic("Got zero of t1")
|
||||
}
|
||||
t1.ModInverse(t1, sm9.Order())
|
||||
t1.Mul(t1, r)
|
||||
t1.Mod(t1, sm9.Order())
|
||||
|
||||
r.ModInverse(r, sm9.Order())
|
||||
T1 := new(sm9.G1).ScalarMult(R, r)
|
||||
return t1, T1, nil
|
||||
}
|
||||
|
||||
func KGC2ComputeData(T1 *sm9.G1, ks *sm9.MastSignPrivateKey, hh *big.Int) (*sm9.G1, error) {
|
||||
t2 := new(big.Int).Add(hh, &ks.Int)
|
||||
t2.ModInverse(t2, sm9.Order())
|
||||
T2 := new(sm9.G1).ScalarMult(T1, t2)
|
||||
return T2, nil
|
||||
}
|
||||
|
||||
func UserComputeSignKey(id []byte, t1 *big.Int, T2 *sm9.G1, r *big.Int, pubs1, pubs2, pubs *sm9.MastSignPublicKey, basePoint *sm9.G1) (*sm9.UserSignKey, *sm9.MastSignPublicKey, error) {
|
||||
h1, hh, isSquare := ComputeHHat(id)
|
||||
rInv := new(big.Int).ModInverse(r, sm9.Order())
|
||||
if isSquare {
|
||||
// h1 is square
|
||||
d := new(big.Int).Mul(h1, t1)
|
||||
d.Mul(d, rInv)
|
||||
d.Mod(d, sm9.Order())
|
||||
ds := new(sm9.G1).ScalarMult(T2, d)
|
||||
ds.Neg(ds)
|
||||
// ds.Add(ds, sm9.G1Generator())
|
||||
ds.Add(ds, basePoint)
|
||||
|
||||
g := new(sm9.G2).Add(&pubs1.G2, &pubs2.G2)
|
||||
g.ScalarMult(g, hh)
|
||||
g.Add(g, &pubs.G2)
|
||||
return &sm9.UserSignKey{
|
||||
G1: *ds,
|
||||
}, &sm9.MastSignPublicKey{
|
||||
G2: *g,
|
||||
}, nil
|
||||
} else {
|
||||
d := new(big.Int).Mul(h1, t1)
|
||||
d.Mul(d, rInv)
|
||||
d.Mul(d, alpha)
|
||||
d.Mod(d, sm9.Order())
|
||||
|
||||
ds := new(sm9.G1).ScalarMult(T2, d)
|
||||
ds.Neg(ds)
|
||||
// ds.Add(ds, sm9.G1Generator())
|
||||
ds.Add(ds, basePoint)
|
||||
|
||||
g := new(sm9.G2).Add(&pubs1.G2, &pubs2.G2)
|
||||
g.ScalarMult(g, hh)
|
||||
g.ScalarMult(g, alphaInv)
|
||||
g.Add(g, new(sm9.G2).ScalarMult(&pubs.G2, alphaInv))
|
||||
return &sm9.UserSignKey{
|
||||
G1: *ds,
|
||||
}, &sm9.MastSignPublicKey{
|
||||
G2: *g,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,272 @@
|
||||
package dkgc
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"xdx.jelly/xgcl/grand"
|
||||
"xdx.jelly/xgcl/internal"
|
||||
"xdx.jelly/xgcl/sm/sm9"
|
||||
)
|
||||
|
||||
func spiner() {
|
||||
start := time.Now()
|
||||
for {
|
||||
for _, c := range "|/-\\" {
|
||||
fmt.Printf("\r%c ", c)
|
||||
now := time.Since(start)
|
||||
s := int(now.Seconds())
|
||||
if s > 3600 {
|
||||
fmt.Printf("%dh%dm%ds ", s/3600, s%3600/60, s%60)
|
||||
} else if s > 60 {
|
||||
fmt.Printf("%dm%ds ", s/60, s%60)
|
||||
} else {
|
||||
fmt.Printf("%.1fs ", now.Seconds())
|
||||
}
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkReportSpeedDKGC(b *testing.B) {
|
||||
|
||||
ks1, pubs1, err := sm9.GenerateMastSignPrivateKey(rand.Reader)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
ks2, pubs2, err := sm9.GenerateMastSignPrivateKey(rand.Reader)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
ks := new(sm9.MastSignPrivateKey)
|
||||
ks.Int.Mul(&ks1.Int, &ks2.Int)
|
||||
ks.Int.Mod(&ks.Int, sm9.Order())
|
||||
ks.Public().G2.ScalarBaseMult(&ks.Int)
|
||||
pubs := ks.Public()
|
||||
|
||||
uid := grand.GetRandom(10)
|
||||
msg := grand.GetRandom(10)
|
||||
// uid := []byte("Alice")
|
||||
// msg := []byte("Chinese IBS standard")
|
||||
ra, R, err := UserRandom0(rand.Reader, sm9.G1Generator())
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
_, hh, _ := ComputeHHat(uid)
|
||||
|
||||
t1, T1, err := KGC1ComputeData(rand.Reader, R, ks1, hh)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
T2, err := KGC2ComputeData(T1, ks2, hh)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
ds, userPubs, err := UserComputeSignKey(uid, t1, T2, ra, pubs1, pubs2, pubs, sm9.G1Generator())
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
signature, _ := sm9.Sign(msg, ds, userPubs, grand.GetRandom(32))
|
||||
|
||||
//bn256.SetUseLattice(false)
|
||||
if !sm9.Verify(signature, uid, msg, userPubs) {
|
||||
b.Logf("\n%x\n%x\n", uid, msg)
|
||||
b.Fatal("verify failed")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestDKGC(t *testing.T) {
|
||||
go spiner()
|
||||
for {
|
||||
for i := 1; i < 1000; i++ {
|
||||
ks1, pubs1, err := sm9.GenerateMastSignPrivateKey(rand.Reader)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ks2, pubs2, err := sm9.GenerateMastSignPrivateKey(rand.Reader)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ks := new(sm9.MastSignPrivateKey)
|
||||
ks.Int.Mul(&ks1.Int, &ks2.Int)
|
||||
ks.Int.Mod(&ks.Int, sm9.Order())
|
||||
ks.Public().G2.ScalarBaseMult(&ks.Int)
|
||||
pubs := ks.Public()
|
||||
|
||||
uid := grand.GetRandom(i)
|
||||
msg := grand.GetRandom(i)
|
||||
// uid := []byte("Alice")
|
||||
// msg := []byte("Chinese IBS standard")
|
||||
ra, R, err := UserRandom0(rand.Reader, sm9.G1Generator())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, hh, _ := ComputeHHat(uid)
|
||||
|
||||
t1, T1, err := KGC1ComputeData(rand.Reader, R, ks1, hh)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
T2, err := KGC2ComputeData(T1, ks2, hh)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ds, userPubs, err := UserComputeSignKey(uid, t1, T2, ra, pubs1, pubs2, pubs, sm9.G1Generator())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
signature, _ := sm9.Sign(msg, ds, userPubs, grand.GetRandom(32))
|
||||
//bn256.SetUseLattice(false)
|
||||
if !sm9.Verify(signature, uid, msg, userPubs) {
|
||||
t.Logf("\n%x\n%x\n", uid, msg)
|
||||
t.Fatal("verify failed")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDKGCWithTPC(t *testing.T) {
|
||||
go spiner()
|
||||
for {
|
||||
for i := 1; i < 1000; i++ {
|
||||
ks1, pubs1, err := sm9.GenerateMastSignPrivateKey(rand.Reader)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ks2, pubs2, err := sm9.GenerateMastSignPrivateKey(rand.Reader)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ks := new(sm9.MastSignPrivateKey)
|
||||
ks.Int.Mul(&ks1.Int, &ks2.Int)
|
||||
ks.Int.Mod(&ks.Int, sm9.Order())
|
||||
ks.Public().G2.ScalarBaseMult(&ks.Int)
|
||||
pubs := ks.Public()
|
||||
|
||||
uid := grand.GetRandom(i)
|
||||
msg := grand.GetRandom(i)
|
||||
// uid := []byte("Alice")
|
||||
// msg := []byte("Chinese IBS standard")
|
||||
|
||||
serverKey, basePoint, err := ServerGenerateKey(rand.Reader)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ra, R, err := UserRandom0(rand.Reader, &basePoint.G1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, hh, _ := ComputeHHat(uid)
|
||||
|
||||
t1, T1, err := KGC1ComputeData(rand.Reader, R, ks1, hh)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
T2, err := KGC2ComputeData(T1, ks2, hh)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
clientKey, userPubs, err := UserComputeSignKey(uid, t1, T2, ra, pubs1, pubs2, pubs, &basePoint.G1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// signature := sm9.Sign(msg, ds, userPubs, grand.GetRandom(32))
|
||||
csc := &ClientSignContext{}
|
||||
u, err := csc.ComputeSignData(rand.Reader, userPubs)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
h, k1, k2, err := ServerComputeSignData(rand.Reader, u, msg, userPubs, serverKey)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
signature, err := csc.ComputeSignature(uid, h, k1, k2, clientKey)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !sm9.Verify(signature, uid, msg, userPubs) {
|
||||
t.Logf("\n%x\n%x\n", uid, msg)
|
||||
t.Fatal("verify failed")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDKGCReport(t *testing.T) {
|
||||
ks1, pubs1, err := sm9.GenerateMastSignPrivateKey(rand.Reader)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ks2, pubs2, err := sm9.GenerateMastSignPrivateKey(rand.Reader)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ks := new(sm9.MastSignPrivateKey)
|
||||
ks.Int.Mul(&ks1.Int, &ks2.Int)
|
||||
ks.Int.Mod(&ks.Int, sm9.Order())
|
||||
ks.Public().G2.ScalarBaseMult(&ks.Int)
|
||||
pubs := ks.Public()
|
||||
|
||||
uid := grand.GetRandom(10)
|
||||
msg := grand.GetRandom(10)
|
||||
|
||||
ra, R, err := UserRandom0(rand.Reader, sm9.G1Generator())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var t1 *big.Int
|
||||
var T1, T2 *sm9.G1
|
||||
count, duation := internal.SingleThreadTester(func() {
|
||||
_, hh, _ := ComputeHHat(uid)
|
||||
t1, T1, err = KGC1ComputeData(rand.Reader, R, ks1, hh)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
})
|
||||
fmt.Printf("KGC1 compute: %d, used time: %d ms, %d pcs/s\n", count, duation.Milliseconds(), int(internal.Rate(count, duation)))
|
||||
|
||||
count, duation = internal.SingleThreadTester(func() {
|
||||
_, hh, _ := ComputeHHat(uid)
|
||||
T2, err = KGC2ComputeData(T1, ks2, hh)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
})
|
||||
fmt.Printf("KGC2 compute: %d, used time: %d ms, %d pcs/s\n", count, duation.Milliseconds(), int(internal.Rate(count, duation)))
|
||||
|
||||
var ds *sm9.UserSignKey
|
||||
var userPubs *sm9.MastSignPublicKey
|
||||
count, duation = internal.SingleThreadTester(func() {
|
||||
ds, userPubs, err = UserComputeSignKey(uid, t1, T2, ra, pubs1, pubs2, pubs, sm9.G1Generator())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
})
|
||||
fmt.Printf("User compute: %d, used time: %d ms, %d pcs/s\n", count, duation.Milliseconds(), int(internal.Rate(count, duation)))
|
||||
|
||||
signature, _ := sm9.Sign(msg, ds, userPubs, grand.GetRandom(32))
|
||||
|
||||
if !sm9.Verify(signature, uid, msg, userPubs) {
|
||||
t.Logf("\n%x\n%x\n", uid, msg)
|
||||
t.Fatal("verify failed")
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
package dkgc
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"io"
|
||||
"math/big"
|
||||
|
||||
"xdx.jelly/xgcl/sm/sm9"
|
||||
)
|
||||
|
||||
type ServerKey struct {
|
||||
big.Int
|
||||
}
|
||||
|
||||
type ClientKey = sm9.UserSignKey
|
||||
|
||||
func ServerGenerateKey(r io.Reader) (sk *ServerKey, basePoint *ClientKey, err error) {
|
||||
for {
|
||||
x, err := rand.Int(r, sm9.Order())
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if x.Sign() == 0 {
|
||||
continue
|
||||
}
|
||||
sk = &ServerKey{
|
||||
Int: *x,
|
||||
}
|
||||
basePoint = &ClientKey{}
|
||||
y := new(big.Int).Set(x)
|
||||
y.ModInverse(y, sm9.Order())
|
||||
basePoint.G1.ScalarBaseMult(y)
|
||||
return sk, basePoint, nil
|
||||
}
|
||||
}
|
||||
|
||||
type ClientSignContext struct {
|
||||
r1 big.Int
|
||||
}
|
||||
|
||||
func (csc *ClientSignContext) ComputeSignData(r io.Reader, pubs *sm9.MastSignPublicKey) (u *sm9.GT, err error) {
|
||||
for {
|
||||
x, err := rand.Int(r, sm9.Order())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if x.Sign() == 0 {
|
||||
continue
|
||||
}
|
||||
csc.r1 = *x
|
||||
break
|
||||
}
|
||||
u = sm9.Pairing(sm9.G1Generator(), &pubs.G2)
|
||||
u.ScalarMult(u, &csc.r1)
|
||||
return u, nil
|
||||
}
|
||||
|
||||
func (csc *ClientSignContext) ComputeSignature(id []byte, h, k1, k2 *big.Int, kc *ClientKey) (*sm9.Signature, error) {
|
||||
sig := &sm9.Signature{}
|
||||
sig.H = *h
|
||||
x := new(big.Int)
|
||||
x.Mul(&csc.r1, k1)
|
||||
x.Add(x, k2)
|
||||
sig.S.ScalarMult(&kc.G1, x)
|
||||
return sig, nil
|
||||
}
|
||||
|
||||
func ServerComputeSignData(r io.Reader, u *sm9.GT, m []byte, pubs *sm9.MastSignPublicKey, ks *ServerKey) (h, k1, k2 *big.Int, err error) {
|
||||
r2 := new(big.Int)
|
||||
r3 := new(big.Int)
|
||||
for {
|
||||
r2, err = rand.Int(r, sm9.Order())
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
if r2.Sign() == 0 {
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
for {
|
||||
r3, err = rand.Int(r, sm9.Order())
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
if r3.Sign() == 0 {
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
g := sm9.Pairing(sm9.G1Generator(), &pubs.G2)
|
||||
g.ScalarMult(g, r3)
|
||||
w := new(sm9.GT)
|
||||
w.ScalarMult(u, r2)
|
||||
w.Add(w, g)
|
||||
h = sm9.H2(m, w.Marshal())
|
||||
|
||||
k1 = new(big.Int).Mul(r2, &ks.Int)
|
||||
k1.Mod(k1, sm9.Order())
|
||||
k2 = new(big.Int).Sub(r3, h)
|
||||
k2.Mul(k2, &ks.Int)
|
||||
k2.Mod(k2, sm9.Order())
|
||||
return h, k1, k2, nil
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package sm9
|
||||
|
||||
// Change log:
|
||||
// 1. Use io.Reader instead of random bytes input.
|
||||
// 2. 计算配对函数调用较多, go1.18(and go1.17 on amd64) 改了寄存器传参,因此有较大的速度提升。
|
||||
@@ -0,0 +1,27 @@
|
||||
# 判断标识,用户私钥和主公钥的一致性
|
||||
Let $h_1 = H_1(ID||hid, N)$, for the user sign key $ds$,
|
||||
$$
|
||||
ds = \left[ \frac{ks}{h_1+ks} \right]\cdot P_1,
|
||||
$$
|
||||
and $P_{pubs} = [ks]\cdot P_2$, we have
|
||||
$$
|
||||
\begin{array}{rcl}
|
||||
& & e(ds, P_{pubs} + [h_1]\cdot P2) \\
|
||||
&=& e(\left[ \frac{ks}{h_1+ks} \right]\cdot P_1, [ks+h_1]\cdot P_2)\\
|
||||
&=& e(P_1, P_{2})^{ks} \\
|
||||
&=& e(P_1, P_{pubs}).
|
||||
\end{array}
|
||||
$$
|
||||
|
||||
|
||||
Thus, we need to compute if the following equation holds:
|
||||
$$
|
||||
e(ds, P_{pubs} + [h_1]\cdot P_2) \overset{?}{=} e(P_1, P_{pubs}).
|
||||
$$
|
||||
|
||||
The same for encryption user key $de$:
|
||||
$$
|
||||
e(P_{pube} + [h_1]\cdot P_1, de) \overset{?}{=} e(P_{pube}, P_2).
|
||||
$$
|
||||
|
||||
|
||||
@@ -0,0 +1,181 @@
|
||||
///
|
||||
/// Copyright (c) 2018 xdx. All rights reserved.
|
||||
///
|
||||
/// \file: enc_impl.go
|
||||
///
|
||||
/// \brief: sm9加密辅助函数
|
||||
///
|
||||
/// \author: xdx
|
||||
///
|
||||
|
||||
package sm9
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"math/big"
|
||||
|
||||
"xdx.jelly/xgcl/gerrors"
|
||||
"xdx.jelly/xgcl/sm/sm4"
|
||||
"xdx.jelly/xgcl/sm/sm9/errors"
|
||||
)
|
||||
|
||||
type encReader struct {
|
||||
E encoder
|
||||
R io.Reader
|
||||
}
|
||||
|
||||
func (er *encReader) Read(dst []byte) (n int, err error) {
|
||||
n, err = er.R.Read(dst)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
dst, err = er.E.encode(dst, dst)
|
||||
return len(dst), nil
|
||||
}
|
||||
|
||||
type encoder interface {
|
||||
encode(dst, src []byte) ([]byte, error)
|
||||
}
|
||||
|
||||
type encFunc func(dst, iv, key, src []byte) ([]byte, error)
|
||||
type worker struct {
|
||||
key []byte
|
||||
iv []byte
|
||||
f encFunc
|
||||
}
|
||||
|
||||
func (o *worker) encode(dst, src []byte) ([]byte, error) {
|
||||
return o.f(dst, o.iv, o.key, src)
|
||||
}
|
||||
|
||||
func DecryptParams(c *Cipher) (int, func(dst, iv, key, src []byte) ([]byte, error), error) {
|
||||
switch c.EncType {
|
||||
case EncTypeKDF:
|
||||
return len(c.C) + macKeySize, xor, nil
|
||||
case EncTypeSM4ECB:
|
||||
return sm4.BlockSize + macKeySize, decEcb, nil
|
||||
case EncTypeSM4CBC:
|
||||
return sm4.BlockSize + macKeySize, decCbc, nil
|
||||
case EncTypeSM4CFB:
|
||||
return sm4.BlockSize + macKeySize, decCfb, nil
|
||||
case EncTypeSM4OFB:
|
||||
return sm4.BlockSize + macKeySize, decOfb, nil
|
||||
default:
|
||||
return 0, nil, errors.ErrEncUnsupportedMode
|
||||
}
|
||||
}
|
||||
|
||||
var DecryptFunc = map[EncType]func(dst, iv, key, src []byte) ([]byte, error){
|
||||
EncTypeKDF: xor,
|
||||
EncTypeSM4ECB: decEcb,
|
||||
EncTypeSM4CBC: decCbc,
|
||||
EncTypeSM4CFB: decCfb,
|
||||
EncTypeSM4OFB: decOfb,
|
||||
}
|
||||
|
||||
func xor(dst, iv, key, src []byte) ([]byte, error) {
|
||||
for i := range src {
|
||||
dst[i] = key[i] ^ src[i]
|
||||
}
|
||||
return dst, nil
|
||||
}
|
||||
|
||||
func encEcb(dst, iv, key, src []byte) ([]byte, error) {
|
||||
return sm4.ECBEncrypt(dst, key, src)
|
||||
}
|
||||
|
||||
func decEcb(dst, iv, key, src []byte) ([]byte, error) {
|
||||
return sm4.ECBDecrypt(dst, key, src)
|
||||
}
|
||||
|
||||
func encCbc(dst, iv, key, src []byte) ([]byte, error) {
|
||||
return sm4.CBCEncrypt(dst, iv, key, src)
|
||||
}
|
||||
func decCbc(dst, iv, key, src []byte) ([]byte, error) {
|
||||
return sm4.CBCDecrypt(dst, iv, key, src)
|
||||
}
|
||||
|
||||
func encCfb(dst, iv, key, src []byte) ([]byte, error) {
|
||||
return sm4.CFBEncrypt(dst, iv, key, src)
|
||||
}
|
||||
|
||||
func decCfb(dst, iv, key, src []byte) ([]byte, error) {
|
||||
return sm4.CFBDecrypt(dst, iv, key, src)
|
||||
}
|
||||
|
||||
func encOfb(dst, iv, key, src []byte) ([]byte, error) {
|
||||
return sm4.OFBEncrypt(dst, iv, key, src)
|
||||
}
|
||||
|
||||
func decOfb(dst, iv, key, src []byte) ([]byte, error) {
|
||||
return sm4.OFBDecrypt(dst, iv, key, src)
|
||||
}
|
||||
|
||||
// assume plain is padding and n blocks, iv is set of 16 bytes if cbc
|
||||
func encryption(id, plain []byte, pube *MastEncPublicKey, iv, rnd []byte, keylen int, f encFunc, encType EncType) *Cipher {
|
||||
c := new(Cipher)
|
||||
c.C = make([]byte, len(plain))
|
||||
r := new(big.Int).SetBytes(rnd)
|
||||
// c.X, c.Y = genKeyPackage(id, pube, rnd)
|
||||
c.C1.Set(hashToG1(id, &pube.G1, hidEncryption))
|
||||
c.C1.ScalarMult(&c.C1, r)
|
||||
c.EncType = encType
|
||||
copy(c.IV[:], iv)
|
||||
|
||||
key := make([]byte, keylen)
|
||||
|
||||
// genKey(key, id, &c.C1, &pube.G1, g2Gen, r)
|
||||
w := >{}
|
||||
if pube.e != nil {
|
||||
w.ScalarMult(pube.e, r)
|
||||
} else {
|
||||
pairing(w, &pube.G1, g2Gen)
|
||||
w.ScalarMult(w, r)
|
||||
}
|
||||
genKey(key, id, &c.C1, w)
|
||||
|
||||
reader := &encReader{
|
||||
E: &worker{key[:len(key)-macKeySize], iv, f},
|
||||
R: bytes.NewReader(plain),
|
||||
}
|
||||
_, _ = reader.Read(c.C)
|
||||
copy(c.H[:], mac(key[len(key)-macKeySize:], c.C))
|
||||
return c
|
||||
}
|
||||
|
||||
// decryptions, encType are not used
|
||||
func decryption(id []byte, c *Cipher, de *UserEncKey, keylen int, f encFunc) ([]byte, error) {
|
||||
if !c.C1.IsValid() {
|
||||
return nil, gerrors.WithAnnotating(errors.ErrDecFailed, "C1 is not a valid point on curve")
|
||||
}
|
||||
|
||||
w := >{}
|
||||
pairing(w, &c.C1, &de.G2)
|
||||
|
||||
key := make([]byte, keylen)
|
||||
genKey(key, id, &c.C1, w)
|
||||
return decodeCipher(c, key, f)
|
||||
}
|
||||
|
||||
// DecodeCipher export decodeCipher for tpc package.
|
||||
// Do not use this function unless you know what you are doing.
|
||||
var DecodeCipher = decodeCipher
|
||||
|
||||
func decodeCipher(c *Cipher, key []byte, f encFunc) ([]byte, error) {
|
||||
keylen := len(key)
|
||||
|
||||
m := mac(key[keylen-macKeySize:], c.C)
|
||||
if !bytes.Equal(c.H[:], m[:]) {
|
||||
return nil, gerrors.WithAnnotating(errors.ErrDecFailed, "check C3 failed")
|
||||
}
|
||||
|
||||
reader := &encReader{
|
||||
E: &worker{key[:keylen-macKeySize], c.IV[:], f},
|
||||
R: bytes.NewReader(c.C),
|
||||
}
|
||||
plain := make([]byte, len(c.C))
|
||||
_, _ = reader.Read(plain)
|
||||
|
||||
return plain, nil
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package sm9
|
||||
|
||||
import (
|
||||
"io"
|
||||
"math/big"
|
||||
|
||||
"xdx.jelly/xgcl/gerrors"
|
||||
"xdx.jelly/xgcl/grand"
|
||||
"xdx.jelly/xgcl/sm/sm9/errors"
|
||||
)
|
||||
|
||||
// KeyPackage 输出密钥封装结构
|
||||
type KeyPackage struct {
|
||||
G1
|
||||
}
|
||||
|
||||
// KeyEncapsule output KeyPackage and key with kenlen.
|
||||
//
|
||||
// rnd可以为:
|
||||
// - []byte, 并且len(rnd)= 32
|
||||
// - io.Reader, 随机数发生器, 如crypto/rand.Reader, 也可以是包装的硬件随机数发生器
|
||||
// - nil, 则会使用默认的软件随机数发生器
|
||||
func KeyEncapsulate(id []byte, keylen int, pube *MastEncPublicKey, rnd interface{}) (*KeyPackage, []byte, error) {
|
||||
if rnd == nil {
|
||||
rnd = grand.Reader
|
||||
}
|
||||
|
||||
if b, ok := rnd.([]byte); ok {
|
||||
return keyEncapsulate(id, keylen, pube, b)
|
||||
} else if reader, ok := rnd.(io.Reader); ok {
|
||||
b := make([]byte, numBytes)
|
||||
if _, err := reader.Read(b); err != nil {
|
||||
return nil, nil, gerrors.ChainErrors(errors.ErrKeyEncapsuleFailed, err)
|
||||
}
|
||||
return keyEncapsulate(id, keylen, pube, b)
|
||||
} else {
|
||||
panic("rnd can only be of nil, []byte or io.Reader")
|
||||
}
|
||||
}
|
||||
|
||||
func keyEncapsulate(id []byte, keylen int, pube *MastEncPublicKey, rnd []byte) (*KeyPackage, []byte, error) {
|
||||
if len(rnd) != numBytes {
|
||||
panic("input rnd invalid")
|
||||
}
|
||||
C := hashToG1(id, &pube.G1, hidKeyEncapsule)
|
||||
r := new(big.Int).SetBytes(rnd)
|
||||
C = C.ScalarMult(C, r)
|
||||
|
||||
key := make([]byte, keylen)
|
||||
// genKey(key, id, C, &pube.G1, g2Gen,r)
|
||||
w := >{}
|
||||
if pube.e != nil {
|
||||
w.ScalarMult(pube.e, r)
|
||||
} else {
|
||||
pairing(w, &pube.G1, g2Gen)
|
||||
w.ScalarMult(w, r)
|
||||
}
|
||||
genKey(key, id, C, w)
|
||||
return &KeyPackage{*C}, key, nil
|
||||
}
|
||||
|
||||
// KeyUnencapsule unencapsule keypackage
|
||||
func KeyDecapsulate(id []byte, pack *KeyPackage, keylen int, de *UserEncKey) ([]byte, error) {
|
||||
if !pack.G1.IsValid() {
|
||||
return nil, gerrors.WithAnnotating(errors.ErrKeyUnencapsuleFailed, "the KeyPackage's C1 is not a valid point on curve")
|
||||
}
|
||||
key := make([]byte, keylen)
|
||||
//genKey(key, id, pack.X, pack.Y, pack.X, pack.Y, de.X0, de.X1, de.Y0, de.Y1, nil)
|
||||
// genKey(key, id, &pack.G1, &pack.G1, &de.G2, nil)
|
||||
w := >{}
|
||||
pairing(w, &pack.G1, &de.G2)
|
||||
genKey(key, id, &pack.G1, w)
|
||||
return key, nil
|
||||
}
|
||||
@@ -0,0 +1,255 @@
|
||||
///
|
||||
/// Copyright (c) 2018 xdx. All rights reserved.
|
||||
///
|
||||
/// \file: encryption.go
|
||||
///
|
||||
/// \brief: SM9加解密
|
||||
///
|
||||
/// \author: xdx
|
||||
///
|
||||
|
||||
package sm9
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"xdx.jelly/xgcl/gerrors"
|
||||
"xdx.jelly/xgcl/grand"
|
||||
"xdx.jelly/xgcl/sm/sm4"
|
||||
"xdx.jelly/xgcl/sm/sm9/errors"
|
||||
)
|
||||
|
||||
type EncType uint32
|
||||
|
||||
// 加密类型
|
||||
const (
|
||||
EncTypeKDF EncType = 0
|
||||
EncTypeSM4ECB EncType = 1
|
||||
EncTypeSM4CBC EncType = 2
|
||||
EncTypeSM4CFB EncType = 4
|
||||
EncTypeSM4OFB EncType = 8
|
||||
encTypeDummy EncType = 0xffffffff //无效类型
|
||||
)
|
||||
|
||||
// defaultCipherLength 默认初始分配大小,并不是限定密文长度。
|
||||
// 一般加密16字节SM4密钥
|
||||
const defaultCipherLength = 32
|
||||
|
||||
// Cipher 密文结构
|
||||
type Cipher struct {
|
||||
EncType EncType // 加密类型
|
||||
IV [sm4.BlockSize]byte // iv, 当为SM4 CBC,OFB...时有效
|
||||
C1 G1
|
||||
H [macSize]byte // C3
|
||||
C []byte // C2
|
||||
|
||||
}
|
||||
|
||||
// NewCipher allocate memeory for a cipher
|
||||
// TODO: NewXXX should also works when replaced by &XXX{}
|
||||
func NewCipher() *Cipher {
|
||||
return &Cipher{
|
||||
EncType: encTypeDummy,
|
||||
C: make([]byte, 0, defaultCipherLength),
|
||||
}
|
||||
}
|
||||
|
||||
// MarshalBinary return type || X || Y || C3 || len(IV+C2) || IV || C2
|
||||
func (c *Cipher) MarshalBinary() ([]byte, error) {
|
||||
dataLen := 4 + 2*Sm9RefMaxLen + macSize + 4 + len(c.C)
|
||||
if (c.EncType == EncTypeSM4CBC || c.EncType == EncTypeSM4CFB || c.EncType == EncTypeSM4OFB) && len(c.IV) == sm4.BlockSize {
|
||||
dataLen += sm4.BlockSize
|
||||
}
|
||||
data := make([]byte, 4, dataLen)
|
||||
Endian.PutUint32(data, uint32(c.EncType))
|
||||
data = append(data, c.C1.Marshal()...)
|
||||
data = append(data, c.H[:]...)
|
||||
buf := make([]byte, 4)
|
||||
Endian.PutUint32(buf, uint32(len(c.C)))
|
||||
data = append(data, buf...)
|
||||
if c.EncType == EncTypeSM4CBC && len(c.IV) == sm4.BlockSize {
|
||||
data = append(data, c.IV[:]...)
|
||||
}
|
||||
data = append(data, c.C...)
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface
|
||||
func (c *Cipher) UnmarshalBinary(data []byte) error {
|
||||
if len(data) < 4+2*Sm9RefMaxLen+macSize+4 {
|
||||
return gerrors.WithAnnotating(errors.ErrUnmarshalFailed, "input unmarshal data too short")
|
||||
}
|
||||
encType := EncType(Endian.Uint32(data))
|
||||
data = data[4:]
|
||||
|
||||
var err error
|
||||
if data, err = c.C1.Unmarshal(data); err != nil {
|
||||
return gerrors.ChainErrors(errors.ErrUnmarshalFailed, err)
|
||||
}
|
||||
|
||||
c.EncType = EncType(encType)
|
||||
copy(c.H[:], data[:macSize])
|
||||
data = data[macSize:]
|
||||
|
||||
// if CBC, clen include the iv
|
||||
clen := Endian.Uint32(data)
|
||||
data = data[4:]
|
||||
// clen too short even for a iv
|
||||
if encType == EncTypeSM4CBC || encType == EncTypeSM4CFB || encType == EncTypeSM4OFB {
|
||||
if clen < sm4.BlockSize {
|
||||
return gerrors.WithAnnotating(errors.ErrUnmarshalFailed, "input unmarshal data of C2 less than a block")
|
||||
}
|
||||
copy(c.IV[:], data[:sm4.BlockSize])
|
||||
data = data[sm4.BlockSize:]
|
||||
}
|
||||
|
||||
if len(data) < int(clen) {
|
||||
return gerrors.WithAnnotating(errors.ErrUnmarshalFailed, "input unmarshal data too short")
|
||||
}
|
||||
c.C = append(c.C[:0], data...)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Encrypt SM9加密
|
||||
//
|
||||
// 输入:
|
||||
// - pube: 加密主公钥
|
||||
// - encType: 加密类型
|
||||
// - optionalIV: 当加密类型为EncTypeSM4CBC、EncTypeSM4CFB、EncTypeSM4OFB时, 输入16字节iv值。也可以输入nil, 则使用rand随机产生。
|
||||
// - plain: 加密原文,当为非KDF加密类型时,长度必须是16的倍数,内部不做padding
|
||||
func Encrypt(encType EncType, pube *MastEncPublicKey, id, plain []byte, rand io.Reader, optionalIV []byte) (*Cipher, error) {
|
||||
rnd := make([]byte, Sm9RefMaxLen)
|
||||
if rand == nil {
|
||||
rand = grand.Reader
|
||||
}
|
||||
if _, err := rand.Read(rnd); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if encType != EncTypeKDF && len(plain)%sm4.BlockSize != 0 {
|
||||
return nil, gerrors.WithAnnotating(errors.ErrEncFailed, "input plaintext is not multilple of block size, padding first")
|
||||
}
|
||||
|
||||
switch encType {
|
||||
case EncTypeKDF:
|
||||
return encryption(id, plain, pube, nil, rnd, len(plain)+macKeySize, xor, EncTypeKDF), nil
|
||||
case EncTypeSM4ECB:
|
||||
return encryption(id, plain, pube, nil, rnd, sm4.BlockSize+macKeySize, encEcb, EncTypeSM4ECB), nil
|
||||
case EncTypeSM4CBC:
|
||||
if len(optionalIV) < numBytes {
|
||||
optionalIV = make([]byte, sm4.BlockSize)
|
||||
if _, err := rand.Read(optionalIV); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return encryption(id, plain, pube, optionalIV, rnd, sm4.BlockSize+macKeySize, encCbc, EncTypeSM4CBC), nil
|
||||
case EncTypeSM4CFB:
|
||||
if len(optionalIV) == 0 {
|
||||
optionalIV = make([]byte, sm4.BlockSize)
|
||||
if _, err := rand.Read(optionalIV); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return encryption(id, plain, pube, optionalIV, rnd, sm4.BlockSize+macKeySize, encCfb, EncTypeSM4CFB), nil
|
||||
case EncTypeSM4OFB:
|
||||
if len(optionalIV) == 0 {
|
||||
optionalIV = make([]byte, sm4.BlockSize)
|
||||
if _, err := rand.Read(optionalIV); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return encryption(id, plain, pube, optionalIV, rnd, sm4.BlockSize+macKeySize, encOfb, EncTypeSM4OFB), nil
|
||||
default:
|
||||
return nil, errors.ErrEncUnsupportedMode
|
||||
}
|
||||
}
|
||||
|
||||
// Decrypt SM9解密。分组模式不对解密明文做unpadding
|
||||
func Decrypt(id []byte, c *Cipher, de *UserEncKey) ([]byte, error) {
|
||||
keylen, f, err := DecryptParams(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return decryption(id, c, de, keylen, f)
|
||||
}
|
||||
|
||||
// EncryptionKDF kdf模式加密
|
||||
//
|
||||
// Deprecated: use Encrypt/Decrypt instead.
|
||||
func EncryptionKDF(id, plain []byte, pube *MastEncPublicKey, rnd []byte) (*Cipher, error) {
|
||||
return encryption(id, plain, pube, nil, rnd, len(plain)+macKeySize, xor, EncTypeKDF), nil
|
||||
}
|
||||
|
||||
// DecryptionKDF kdf模式加密
|
||||
//
|
||||
// Deprecated: use Encrypt/Decrypt instead.
|
||||
func DecryptionKDF(id []byte, c *Cipher, de *UserEncKey) ([]byte, error) {
|
||||
return decryption(id, c, de, len(c.C)+macKeySize, xor)
|
||||
}
|
||||
|
||||
// EncryptionSm4ECB SM4_ECB模式, 不做padding和unpadding
|
||||
//
|
||||
// Deprecated: use Encrypt/Decrypt instead.
|
||||
func EncryptionSm4ECB(id, plain []byte, pube *MastEncPublicKey, rnd []byte) (*Cipher, error) {
|
||||
if len(plain)%sm4.BlockSize != 0 {
|
||||
return nil, gerrors.WithAnnotating(errors.ErrEncFailed, "input plaintext is not multilple of block size, padding first")
|
||||
}
|
||||
return encryption(id, plain, pube, nil, rnd, sm4.BlockSize+macKeySize, encEcb, EncTypeSM4ECB), nil
|
||||
}
|
||||
|
||||
// DecryptionSm4ECB SM4_ECB模式, 不做padding和unpadding
|
||||
//
|
||||
// Deprecated: use Encrypt/Decrypt instead.
|
||||
func DecryptionSm4ECB(id []byte, c *Cipher, de *UserEncKey) ([]byte, error) {
|
||||
return decryption(id, c, de, sm4.BlockSize+macKeySize, decEcb)
|
||||
}
|
||||
|
||||
// EncryptionSm4CBC SM4_CBC模式,不做padding和unpadding
|
||||
//
|
||||
// Deprecated: use Encrypt/Decrypt instead.
|
||||
func EncryptionSm4CBC(id, plain []byte, pube *MastEncPublicKey, iv, rnd []byte) (*Cipher, error) {
|
||||
if len(plain)%sm4.BlockSize != 0 {
|
||||
return nil, gerrors.WithAnnotating(errors.ErrEncFailed, "input plaintext is not multilple of block size, padding first")
|
||||
}
|
||||
return encryption(id, plain, pube, iv, rnd, sm4.BlockSize+macKeySize, encCbc, EncTypeSM4CBC), nil
|
||||
}
|
||||
|
||||
// DecryptionSm4CBC SM4_ECB模式, 不做padding和unpadding
|
||||
//
|
||||
// Deprecated: use Encrypt/Decrypt instead.
|
||||
func DecryptionSm4CBC(id []byte, c *Cipher, de *UserEncKey) ([]byte, error) {
|
||||
return decryption(id, c, de, sm4.BlockSize+macKeySize, decCbc)
|
||||
}
|
||||
|
||||
// EncryptionSm4CFB SM4_CFB模式,不做padding和unpadding
|
||||
//
|
||||
// Deprecated: use Encrypt/Decrypt instead.
|
||||
func EncryptionSm4CFB(id, plain []byte, pube *MastEncPublicKey, iv, rnd []byte) (*Cipher, error) {
|
||||
if len(plain)%sm4.BlockSize != 0 {
|
||||
return nil, gerrors.WithAnnotating(errors.ErrEncFailed, "input plaintext is not multilple of block size, padding first")
|
||||
}
|
||||
return encryption(id, plain, pube, iv, rnd, sm4.BlockSize+macKeySize, encCfb, EncTypeSM4CFB), nil
|
||||
}
|
||||
|
||||
// DecryptionSm4CFB SM4_CFB模式, 不做padding和unpadding
|
||||
//
|
||||
// Deprecated: use Encrypt/Decrypt instead.
|
||||
func DecryptionSm4CFB(id []byte, c *Cipher, de *UserEncKey) ([]byte, error) {
|
||||
return decryption(id, c, de, sm4.BlockSize+macKeySize, decCfb)
|
||||
}
|
||||
|
||||
// EncryptionSm4OFB SM4_OFB模式,不做padding和unpadding
|
||||
//
|
||||
// Deprecated: use Encrypt/Decrypt instead.
|
||||
func EncryptionSm4OFB(id, plain []byte, pube *MastEncPublicKey, iv, rnd []byte) (*Cipher, error) {
|
||||
if len(plain)%sm4.BlockSize != 0 {
|
||||
return nil, gerrors.WithAnnotating(errors.ErrEncFailed, "input plaintext is not multilple of block size, padding first")
|
||||
}
|
||||
return encryption(id, plain, pube, iv, rnd, sm4.BlockSize+macKeySize, encOfb, EncTypeSM4OFB), nil
|
||||
}
|
||||
|
||||
// DecryptionSm4OFB SM4_OFB模式, 不做padding和unpadding
|
||||
//
|
||||
// Deprecated: use Encrypt/Decrypt instead.
|
||||
func DecryptionSm4OFB(id []byte, c *Cipher, de *UserEncKey) ([]byte, error) {
|
||||
return decryption(id, c, de, sm4.BlockSize+macKeySize, decOfb)
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package sm9
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
|
||||
"xdx.jelly/xgcl/sm"
|
||||
)
|
||||
|
||||
type endian struct {
|
||||
isBigEndian bool
|
||||
}
|
||||
|
||||
func (e *endian) PutUint32(b []byte, v uint32) {
|
||||
if e.isBigEndian {
|
||||
binary.BigEndian.PutUint32(b, v)
|
||||
} else {
|
||||
binary.LittleEndian.PutUint32(b, v)
|
||||
}
|
||||
}
|
||||
|
||||
func (e *endian) Uint32(b []byte) uint32 {
|
||||
if e.isBigEndian {
|
||||
return binary.BigEndian.Uint32(b)
|
||||
}
|
||||
|
||||
return binary.LittleEndian.Uint32(b)
|
||||
}
|
||||
|
||||
var (
|
||||
// Endian is the endian when marshal a int, default is big endian
|
||||
Endian = endian{true}
|
||||
)
|
||||
|
||||
// SetToBigEndian 将端序设置为大端序
|
||||
func SetToBigEndian() {
|
||||
Endian.isBigEndian = true
|
||||
}
|
||||
|
||||
// SetToLittleEndian 设置为小端序
|
||||
func SetToLittleEndian() {
|
||||
Endian.isBigEndian = false
|
||||
}
|
||||
|
||||
// SetToDefaultEndian 恢复默认端序-大端
|
||||
func SetToDefaultEndian() {
|
||||
Endian.isBigEndian = true
|
||||
}
|
||||
|
||||
func init() {
|
||||
sm.RegisterCallBack(SetToBigEndian, SetToLittleEndian, SetToDefaultEndian)
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package errors
|
||||
|
||||
import "xdx.jelly/xgcl/gerrors"
|
||||
|
||||
//go:generate stringer -type=ErrorCode -linecomment -output=errors_string.go errors.go
|
||||
type ErrorCode gerrors.ErrorCode
|
||||
|
||||
func (e ErrorCode) Error() string {
|
||||
return gerrors.Format(uint32(e), e.String())
|
||||
}
|
||||
|
||||
// error codes
|
||||
const (
|
||||
ErrInvalidInput ErrorCode = 0x01009000 + iota //输入不合法
|
||||
ErrMarshalFailed //Marshal失败
|
||||
ErrUnmarshalFailed //Unmarshal失败
|
||||
ErrGenerateRandomFailed //生成随机数失败
|
||||
ErrEncodeASN1Failed //ASN.1编码失败
|
||||
ErrDecodeASN1Failed //ASN.1解码失败
|
||||
ErrInvalidPoint //不是SM9曲线上的点
|
||||
ErrInvalidMastPublicKey //SM9主公钥不合法
|
||||
ErrInvalidPublicKey //SM9公钥不合法
|
||||
ErrSignFailed //SM9签名失败
|
||||
ErrVerifyFailed //SM9签名验证失败
|
||||
ErrEncFailed //SM9加密失败
|
||||
ErrDecFailed //SM9解密失败
|
||||
ErrKeyExchangeFailed //SM9密钥交换失败
|
||||
ErrKeyEncapsuleFailed //SM9密钥封装失败
|
||||
ErrKeyUnencapsuleFailed //SM9密钥解封装失败
|
||||
ErrKGCRebuildKey //KGC主密钥需要重新
|
||||
ErrEncUnsupportedMode //SM9加密不支持的模式
|
||||
)
|
||||
|
||||
// ERR_SM9_INVALID_MLEN_OF_SM4 //明文长度不合法
|
||||
// ERR_SM9_INVALID_CLEN_OF_SM4 //密文长度不合法
|
||||
// ERR_SM9_DEC_INVALID_C1 //SM9密文C1不是一个有效点
|
||||
// ERR_SM9_DEC_KEY_IS_ZERO //SM9解密中得到K1全0
|
||||
// ERR_SM9_DEC_INVALID_MAC //SM
|
||||
// 解密MAC校验不通过
|
||||
// ERR_SM9_KEYUE_INVALID_C1 //SM9解封装密文C1不是一个有效点
|
||||
// ERR_SM9_KEYUE_KEY_IS_ZERO //SM9解封装密文K1全0
|
||||
// ERR_SM9_KEYEX_CHECK_HASH_FAIL //SM9密钥交换验证失败
|
||||
// ERR_SM9_KEYEX_INVALID_POINT //SM9密钥交换接收到的Ra、Rb不是一个有效的点
|
||||
// ERR_SM9_SIGN_VERIFY_FAIL //SM9签名验证失败
|
||||
// ERR_SM9_ENC_GET_LEN_INVALID_TYPE //SM9根据密文/明文长度、加密类型获取解密明文/加密密文,输入类型错误
|
||||
// ERR_SM9_ENC_GET_LEN_INVALID_LEN //输入长度不正确
|
||||
// ERR_SM9_INVALID_CLEN //密文长度不合法
|
||||
@@ -0,0 +1,41 @@
|
||||
// Code generated by "stringer -type=ErrorCode -linecomment -output=errors_string.go errors.go"; DO NOT EDIT.
|
||||
|
||||
package errors
|
||||
|
||||
import "strconv"
|
||||
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[ErrInvalidInput-16814080]
|
||||
_ = x[ErrMarshalFailed-16814081]
|
||||
_ = x[ErrUnmarshalFailed-16814082]
|
||||
_ = x[ErrGenerateRandomFailed-16814083]
|
||||
_ = x[ErrEncodeASN1Failed-16814084]
|
||||
_ = x[ErrDecodeASN1Failed-16814085]
|
||||
_ = x[ErrInvalidPoint-16814086]
|
||||
_ = x[ErrInvalidMastPublicKey-16814087]
|
||||
_ = x[ErrInvalidPublicKey-16814088]
|
||||
_ = x[ErrSignFailed-16814089]
|
||||
_ = x[ErrVerifyFailed-16814090]
|
||||
_ = x[ErrEncFailed-16814091]
|
||||
_ = x[ErrDecFailed-16814092]
|
||||
_ = x[ErrKeyExchangeFailed-16814093]
|
||||
_ = x[ErrKeyEncapsuleFailed-16814094]
|
||||
_ = x[ErrKeyUnencapsuleFailed-16814095]
|
||||
_ = x[ErrKGCRebuildKey-16814096]
|
||||
_ = x[ErrEncUnsupportedMode-16814097]
|
||||
}
|
||||
|
||||
const _ErrorCode_name = "输入不合法Marshal失败Unmarshal失败生成随机数失败ASN.1编码失败ASN.1解码失败不是SM9曲线上的点SM9主公钥不合法SM9公钥不合法SM9签名失败SM9签名验证失败SM9加密失败SM9解密失败SM9密钥交换失败SM9密钥封装失败SM9密钥解封装失败KGC主密钥需要重新SM9加密不支持的模式"
|
||||
|
||||
var _ErrorCode_index = [...]uint16{0, 15, 28, 43, 64, 81, 98, 122, 143, 161, 176, 197, 212, 227, 248, 269, 293, 317, 344}
|
||||
|
||||
func (i ErrorCode) String() string {
|
||||
i -= 16814080
|
||||
if i >= ErrorCode(len(_ErrorCode_index)-1) {
|
||||
return "ErrorCode(" + strconv.FormatInt(int64(i+16814080), 10) + ")"
|
||||
}
|
||||
return _ErrorCode_name[_ErrorCode_index[i]:_ErrorCode_index[i+1]]
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package sm9
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"xdx.jelly/xgcl/sm/sm3"
|
||||
)
|
||||
|
||||
// 生成GBT 38635附录签名示例数据
|
||||
func TestGBT38635Sign(t *testing.T) {
|
||||
|
||||
uid := []byte("Alice")
|
||||
msg := []byte("Chinese IBS standard")
|
||||
digest := sm3.Sum(msg)
|
||||
msg = digest[:]
|
||||
fmt.Printf("待签名消息的杂凑M: %s\n", strings.ToUpper(hex.EncodeToString(msg)))
|
||||
|
||||
rnd, _ := hex.DecodeString("000130E78459D78545CB54C587E02CF480CE0B66340F319F348A1D5B1F2DC5F4")
|
||||
ks, pubs, _ := GenerateMastSignPrivateKey(bytes.NewReader(rnd))
|
||||
ds, err := ks.GenerateUserSignKey(uid)
|
||||
assert.Nil(t, err)
|
||||
|
||||
// 打印
|
||||
fmt.Printf("签名主私钥ks:%s\n", strings.ToUpper(ks.String()))
|
||||
fmt.Printf("签名主公钥Pubs:%s\n", strings.ToUpper(pubs.G2.String()))
|
||||
|
||||
fmt.Printf("实体A的标识:%s\n", string(uid))
|
||||
fmt.Printf("实体A的签名私钥ds:%s\n", ds.G1.String())
|
||||
|
||||
if PrintIntermediaDataForSTD38635 {
|
||||
fmt.Printf("\n================= 签名步骤中的相关值 ===================\n")
|
||||
}
|
||||
rnd, _ = hex.DecodeString("00033C8616B06704813203DFD00965022ED15975C662337AED648835DC4B1CBE")
|
||||
signature, _ := Sign(msg, ds, pubs, rnd)
|
||||
|
||||
if PrintIntermediaDataForSTD38635 {
|
||||
fmt.Printf("\n================= 验证步骤中的相关值 ===================\n")
|
||||
}
|
||||
if !Verify(signature, uid, msg, pubs) {
|
||||
t.Fatal()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package sm9
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"xdx.jelly/xgcl/gmath"
|
||||
"xdx.jelly/xgcl/internal/kdf"
|
||||
"xdx.jelly/xgcl/sm/sm3"
|
||||
)
|
||||
|
||||
const (
|
||||
macSize = sm3.Size
|
||||
macKeySize = sm3.Size
|
||||
)
|
||||
|
||||
func mac(key, msg []byte) []byte {
|
||||
ret := sm3.Sum(msg, key)
|
||||
return ret[:]
|
||||
}
|
||||
|
||||
// const hlen = 320 / 8
|
||||
|
||||
var Kdf = kdf.StdKdf.Kdf
|
||||
|
||||
// h are fixed TODO: make it change with params
|
||||
func _h(out, n *big.Int, tag byte, z ...[]byte) {
|
||||
ha := make([]byte, 64)
|
||||
s0 := sm3.NewDigest()
|
||||
s1 := sm3.NewDigest()
|
||||
|
||||
_, _ = s0.Write([]byte{tag})
|
||||
for _, w := range z {
|
||||
_, _ = s0.Write(w)
|
||||
}
|
||||
buf := make([]byte, 4)
|
||||
buf[3] = 1
|
||||
|
||||
*s1 = *s0
|
||||
_, _ = s1.Write(buf)
|
||||
d := s1.Sum(nil)
|
||||
copy(ha, d)
|
||||
buf[3] = 2
|
||||
|
||||
_, _ = s0.Write(buf)
|
||||
d = s0.Sum(nil)
|
||||
copy(ha[32:], d)
|
||||
|
||||
out.SetBytes(ha[:40])
|
||||
out.Mod(out, n)
|
||||
out.Add(out, gmath.BigInt1)
|
||||
}
|
||||
|
||||
// H1 H1函数
|
||||
func H1(z ...[]byte) *big.Int {
|
||||
r := new(big.Int)
|
||||
_h(r, nMinusOne, 1, z...)
|
||||
return r
|
||||
}
|
||||
|
||||
// H2 H2函数
|
||||
func H2(z ...[]byte) *big.Int {
|
||||
r := new(big.Int)
|
||||
_h(r, nMinusOne, 2, z...)
|
||||
return r
|
||||
}
|
||||
|
||||
// ////////////////////////////////////////////// local functions
|
||||
// hashToG1 hash id to a point of G1, (px, py) are KGC's master key
|
||||
// return (x,y) = H1(id||hid)g1 + BasePoint, BasePoint相当于做一个平移。
|
||||
// 可以理解为id在某个KGC下的公钥
|
||||
func hashToG1(id []byte, base *G1, hid byte) *G1 {
|
||||
h := H1(id, []byte{hid})
|
||||
g := new(G1).ScalarBaseMult(h)
|
||||
g.Add(g, base)
|
||||
return g
|
||||
}
|
||||
|
||||
// genKey return a key of length keylen, key = kdf(cx||cy||e(p,q)^k||id)
|
||||
// k could be nil, then e(p,q)^k=e(p,q)
|
||||
// func genKey(key, id []byte, c, p *G1, q *G2, k *big.Int)[]byte{
|
||||
func genKey(key, id []byte, c *G1, w *GT) []byte {
|
||||
_ = Kdf(key,
|
||||
c.Marshal(),
|
||||
w.Marshal(),
|
||||
id)
|
||||
return key
|
||||
}
|
||||
@@ -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
|
||||
```
|
||||
@@ -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
|
||||
}
|
||||
@@ -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 := >{}
|
||||
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)
|
||||
}
|
||||
}
|
||||
@@ -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(>{*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
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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])
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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) 或 a,b其中一个为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为0,b为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)
|
||||
}
|
||||
@@ -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))
|
||||
}
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
@@ -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 := >{*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)
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
@@ -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("")
|
||||
@@ -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]),
|
||||
@@ -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)
|
||||
@@ -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()
|
||||
}
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
}
|
||||
+376
@@ -0,0 +1,376 @@
|
||||
package sm9
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"io"
|
||||
"math/big"
|
||||
|
||||
"xdx.jelly/xgcl/gerrors"
|
||||
"xdx.jelly/xgcl/gmath"
|
||||
"xdx.jelly/xgcl/sm/sm3"
|
||||
"xdx.jelly/xgcl/sm/sm9/errors"
|
||||
)
|
||||
|
||||
// MastSignPublicKey 签名主公钥
|
||||
type MastSignPublicKey struct {
|
||||
G2
|
||||
e *GT // Precomputed. If e != nil, then e = e(pubs, g2).
|
||||
}
|
||||
|
||||
// MastSignPrivateKey 签名主私钥。主公钥使用.Public()方法获得。
|
||||
type MastSignPrivateKey struct {
|
||||
public *MastSignPublicKey
|
||||
big.Int
|
||||
}
|
||||
|
||||
// MastEncPublicKey 加密主公钥
|
||||
type MastEncPublicKey struct {
|
||||
G1
|
||||
e *GT // if e != nil, then e = e(g1, pube)
|
||||
}
|
||||
|
||||
// MastEncPrivateKey 加密主私钥,主公钥使用.Public()方法获得
|
||||
type MastEncPrivateKey struct {
|
||||
public *MastEncPublicKey
|
||||
big.Int
|
||||
}
|
||||
|
||||
// UserSignKey 用户签名私钥
|
||||
type UserSignKey struct {
|
||||
G1
|
||||
}
|
||||
|
||||
// UserEncKey 用户加密私钥
|
||||
type UserEncKey struct {
|
||||
G2
|
||||
}
|
||||
|
||||
// BytesCount return how many bytes an UserSignKey need.
|
||||
func (k *UserSignKey) BytesCount() int {
|
||||
return 2 * 256 / 8
|
||||
}
|
||||
|
||||
// BytesCount return how many bytes an UserEncKey need.
|
||||
func (k *UserEncKey) BytesCount() int {
|
||||
return 4 * 256 / 8
|
||||
}
|
||||
|
||||
// Clear set the memory to zeros.
|
||||
func (k *MastSignPrivateKey) Clear() {
|
||||
gmath.ClearBigInt(&k.Int)
|
||||
k.public.G2.SetInfinity()
|
||||
}
|
||||
|
||||
// Clear set the memory to zeros.
|
||||
func (k *MastEncPrivateKey) Clear() {
|
||||
gmath.ClearBigInt(&k.Int)
|
||||
k.public.G1.SetInfinity()
|
||||
}
|
||||
|
||||
// Clear set the user's sign key to const g1.
|
||||
func (k *UserSignKey) Clear() {
|
||||
k.G1.SetInfinity()
|
||||
}
|
||||
|
||||
// Clear set the user's encryption key to const g2.
|
||||
func (k *UserEncKey) Clear() {
|
||||
k.G2.SetInfinity()
|
||||
}
|
||||
|
||||
// Bytes 主签名私钥转化为32字节串
|
||||
func (k *MastSignPrivateKey) Bytes() []byte {
|
||||
k.Int.Mod(&k.Int, Order())
|
||||
ret := make([]byte, byteSize)
|
||||
_ = gmath.FillBytes(&k.Int, ret)
|
||||
return ret
|
||||
}
|
||||
|
||||
// fillBytes 主签名私钥转化为32字节串, b 必须为32字节
|
||||
func (k *MastSignPrivateKey) fillBytes(b []byte) {
|
||||
k.Int.Mod(&k.Int, Order())
|
||||
_ = gmath.FillBytes(&k.Int, b)
|
||||
}
|
||||
|
||||
// Bytes 主签名公钥转化为128字节串 X0||X1||Y0||Y1
|
||||
func (k *MastSignPublicKey) Bytes() []byte {
|
||||
return k.G2.Marshal()
|
||||
}
|
||||
|
||||
// fillBytes 主签名公钥转化为128字节串 X0||X1||Y0||Y1, b必须为128字节
|
||||
func (k *MastSignPublicKey) fillBytes(b []byte) {
|
||||
k.G2.FillBytes(b)
|
||||
}
|
||||
|
||||
// Bytes 主加密私钥转化为32字节串
|
||||
func (k *MastEncPrivateKey) Bytes() []byte {
|
||||
k.Int.Mod(&k.Int, Order())
|
||||
return gmath.BigIntToNByte(&k.Int, byteSize)
|
||||
}
|
||||
|
||||
// fillBytes 主加密私钥转化为32字节串
|
||||
func (k *MastEncPrivateKey) fillBytes(b []byte) {
|
||||
k.Int.Mod(&k.Int, Order())
|
||||
gmath.FillBytes(&k.Int, b)
|
||||
}
|
||||
|
||||
// Bytes 主加密公钥转化为64字节串X||Y
|
||||
func (k *MastEncPublicKey) Bytes() []byte {
|
||||
return k.G1.Marshal()
|
||||
}
|
||||
|
||||
// fillBytes 主加密公钥转化为64字节串X||Y, len(b) must be 64
|
||||
func (k *MastEncPublicKey) fillBytes(b []byte) {
|
||||
k.G1.FillBytes(b)
|
||||
}
|
||||
|
||||
// Bytes 用户签名私钥转化为64字节串X||Y
|
||||
func (k *UserSignKey) Bytes() []byte {
|
||||
return k.G1.Marshal()
|
||||
}
|
||||
|
||||
// fillBytes 用户签名私钥转化为64字节串X||Y
|
||||
func (k *UserSignKey) fillBytes(b []byte) {
|
||||
k.G1.FillBytes(b)
|
||||
}
|
||||
|
||||
// Bytes 用户加密私钥转换为128字节串X0||X1||Y0||Y1
|
||||
func (k *UserEncKey) Bytes() []byte {
|
||||
return k.G2.Marshal()
|
||||
}
|
||||
|
||||
// fillBytes 用户加密私钥转换为128字节串X0||X1||Y0||Y1
|
||||
func (k *UserEncKey) fillBytes(b []byte) {
|
||||
k.G2.FillBytes(b)
|
||||
}
|
||||
|
||||
// SetBytes 从字节串转换为主签名私钥
|
||||
func (k *MastSignPrivateKey) SetBytes(buf []byte) (*MastSignPrivateKey, error) {
|
||||
k.Int.SetBytes(buf)
|
||||
k.Int.Mod(&k.Int, Order())
|
||||
k.computePublic()
|
||||
return k, nil
|
||||
}
|
||||
|
||||
// SetBytes 从字节串转换为主签名公钥
|
||||
func (k *MastSignPublicKey) SetBytes(buf []byte) (*MastSignPublicKey, error) {
|
||||
if len(buf) < 4*byteSize {
|
||||
return nil, gerrors.WithAnnotating(errors.ErrInvalidInput, "input data too short")
|
||||
}
|
||||
_, err := k.G2.Unmarshal(buf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
k.ComputePairing()
|
||||
return k, nil
|
||||
}
|
||||
|
||||
// SetBytes 从字节串转换为主加密私钥
|
||||
func (k *MastEncPrivateKey) SetBytes(buf []byte) (*MastEncPrivateKey, error) {
|
||||
k.Int.SetBytes(buf)
|
||||
k.Int.Mod(&k.Int, Order())
|
||||
k.computePublic()
|
||||
return k, nil
|
||||
}
|
||||
|
||||
// SetBytes 从字节串转换为主加密公钥
|
||||
func (k *MastEncPublicKey) SetBytes(buf []byte) (*MastEncPublicKey, error) {
|
||||
if len(buf) < 2*byteSize {
|
||||
return nil, gerrors.WithAnnotating(errors.ErrInvalidInput, "input data too short")
|
||||
}
|
||||
_, err := k.G1.Unmarshal(buf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
k.ComputePairing()
|
||||
return k, nil
|
||||
}
|
||||
|
||||
// SetBytes 从字节串转换为用户签名私钥
|
||||
func (k *UserSignKey) SetBytes(src []byte) (err error) {
|
||||
_, err = k.G1.Unmarshal(src)
|
||||
return
|
||||
}
|
||||
|
||||
// SetBytes 从字节串转换为用户加密私钥
|
||||
func (k *UserEncKey) SetBytes(src []byte) (err error) {
|
||||
_, err = k.G2.Unmarshal(src)
|
||||
return
|
||||
}
|
||||
|
||||
// String implements the Stringer interface.
|
||||
func (k *MastSignPrivateKey) String() string {
|
||||
return hex.EncodeToString(k.Bytes())
|
||||
}
|
||||
|
||||
// String implements the Stringer interface.
|
||||
func (k *MastSignPublicKey) String() string {
|
||||
return hex.EncodeToString(k.Bytes())
|
||||
}
|
||||
|
||||
// String implements the Stringer interface.
|
||||
func (k *MastEncPrivateKey) String() string {
|
||||
return hex.EncodeToString(k.Bytes())
|
||||
}
|
||||
|
||||
// String implements the Stringer interface.
|
||||
func (k *MastEncPublicKey) String() string {
|
||||
return hex.EncodeToString(k.Bytes())
|
||||
}
|
||||
|
||||
// ComputePairing computes k.e = (g1, Ppubs) if k.e == nil.
|
||||
// 注意,不要对k主密钥重新赋值,否则这里的预计算值不能更新。
|
||||
func (k *MastSignPublicKey) ComputePairing() {
|
||||
if k.e != nil {
|
||||
return
|
||||
}
|
||||
k.e = Pairing(g1Gen, &k.G2)
|
||||
}
|
||||
|
||||
// ComputePairing computes k.e = (Ppube, g2)
|
||||
// 注意,不要对k主密钥重新赋值,否则这里的预计算值不能更新。
|
||||
func (k *MastEncPublicKey) ComputePairing() {
|
||||
if k.e != nil {
|
||||
return
|
||||
}
|
||||
k.e = Pairing(&k.G1, g2Gen)
|
||||
}
|
||||
|
||||
// randOrder returns a number in [1, N-1].
|
||||
//
|
||||
// It returns an nil error unless the random number generator r reads 0 bytes and got an error.
|
||||
func randOrder(r io.Reader) (*big.Int, error) {
|
||||
b := make([]byte, numBytes)
|
||||
ret := new(big.Int)
|
||||
|
||||
_, err := r.Read(b)
|
||||
if err != nil {
|
||||
return nil, errors.ErrGenerateRandomFailed
|
||||
}
|
||||
for {
|
||||
ret.SetBytes(b)
|
||||
if ret.Sign() > 0 && ret.Cmp(Order()) < 0 {
|
||||
return ret, nil
|
||||
}
|
||||
d := sm3.Sum(b)
|
||||
b = d[:]
|
||||
}
|
||||
}
|
||||
|
||||
// GenerateMastSignPrivateKey 生成签名主私钥
|
||||
func GenerateMastSignPrivateKey(r io.Reader) (*MastSignPrivateKey, *MastSignPublicKey, error) {
|
||||
ks := &MastSignPrivateKey{}
|
||||
d, err := randOrder(r)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
ks.Int = *d
|
||||
ks.computePublic()
|
||||
return ks, ks.public, nil
|
||||
}
|
||||
|
||||
// GenerateMastEncPrivateKey 生成加密主私钥
|
||||
func GenerateMastEncPrivateKey(r io.Reader) (*MastEncPrivateKey, *MastEncPublicKey, error) {
|
||||
ke := &MastEncPrivateKey{}
|
||||
d, err := randOrder(r)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
ke.Int = *d
|
||||
ke.computePublic()
|
||||
return ke, ke.public, nil
|
||||
}
|
||||
|
||||
// GenerateUserSignKey 生成用户私钥。
|
||||
//
|
||||
// 注意: 有极小可能返回error。但一旦返回error,则需要更换主签名密钥以及重新生成所有用户密钥。
|
||||
// 一般来说,这个概率非常……非常低。但一旦返回error,如果KGC可以改变uid的值(比如uid内的时间等参数)
|
||||
// 则用新uid重新计算。否则若uid完全由用户提交上来,则必须更换主签名密钥以及重新生成所有用户密钥。
|
||||
// 因为此时该用户可以根据此uid计算出主私钥。
|
||||
func GenerateUserSignKey(uid []byte, ks *MastSignPrivateKey) (*UserSignKey, error) {
|
||||
return ks.GenerateUserSignKey(uid)
|
||||
}
|
||||
|
||||
// GenerateUserEncKey 生成用户加密私钥
|
||||
//
|
||||
// 注: 见GenerateUserSignKey说明
|
||||
func GenerateUserEncKey(uid []byte, ke *MastEncPrivateKey) (*UserEncKey, error) {
|
||||
return ke.GenerateUserEncKey(uid)
|
||||
}
|
||||
|
||||
func (k *MastSignPrivateKey) computePublic() {
|
||||
if k.public == nil {
|
||||
k.public = &MastSignPublicKey{}
|
||||
}
|
||||
k.public.G2.ScalarBaseMult(&k.Int)
|
||||
k.public.ComputePairing()
|
||||
}
|
||||
|
||||
func (k *MastEncPrivateKey) computePublic() {
|
||||
if k.public == nil {
|
||||
k.public = &MastEncPublicKey{}
|
||||
}
|
||||
k.public.G1.ScalarBaseMult(&k.Int)
|
||||
k.public.ComputePairing()
|
||||
}
|
||||
|
||||
// GenerateUserSignKey 生成用户私钥。注意如果返回错误ErrKGCRebuildKey,则需要重建主密钥。
|
||||
//
|
||||
// k,err:= k.GenerateUserSignKey(uid)
|
||||
// if err.Is(ErrKGCRebuildKey){...}
|
||||
//
|
||||
// - 也可以更改uid中某些项,比如uid如果是ASN.1编码的identity,则可以通过改变时间等参数来重新计算。
|
||||
// - 如果uid是用户提交的不能更改,则必须重建主密钥,否则用户可以推算出主密钥。
|
||||
// - 返回ErrKGCRebuildKey错误的几率非常低,以致可以忽略。
|
||||
func (k *MastSignPrivateKey) GenerateUserSignKey(uid []byte) (*UserSignKey, error) {
|
||||
t1 := H1(uid, []byte{hidSign})
|
||||
t1.Add(t1, &k.Int)
|
||||
t1.Mod(t1, Order())
|
||||
if gmath.IsBigInt0(t1) {
|
||||
return nil, errors.ErrKGCRebuildKey
|
||||
}
|
||||
|
||||
t1.ModInverse(t1, Order())
|
||||
t1.Mul(t1, &k.Int)
|
||||
t1.Mod(t1, Order())
|
||||
|
||||
return &UserSignKey{
|
||||
*new(G1).ScalarBaseMult(t1),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GenerateUserEncKey 生成用户加密私钥
|
||||
//
|
||||
// 注: 见GenerateUserSignKey说明
|
||||
func (k *MastEncPrivateKey) GenerateUserEncKey(uid []byte) (*UserEncKey, error) {
|
||||
t1 := H1(uid, []byte{hidEncryption})
|
||||
t1.Add(t1, &k.Int)
|
||||
t1.Mod(t1, Order())
|
||||
if gmath.IsBigInt0(t1) {
|
||||
return nil, errors.ErrKGCRebuildKey
|
||||
}
|
||||
|
||||
t1.ModInverse(t1, Order())
|
||||
t1.Mul(t1, &k.Int)
|
||||
t1.Mod(t1, Order())
|
||||
return &UserEncKey{
|
||||
*new(G2).ScalarBaseMult(t1),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Public 返回主签名公钥
|
||||
func (k *MastSignPrivateKey) Public() *MastSignPublicKey {
|
||||
if k.public == nil {
|
||||
k.computePublic()
|
||||
}
|
||||
k.public.ComputePairing()
|
||||
return k.public
|
||||
}
|
||||
|
||||
// Public 返回主加密公钥
|
||||
func (k *MastEncPrivateKey) Public() *MastEncPublicKey {
|
||||
if k.public == nil {
|
||||
k.computePublic()
|
||||
}
|
||||
k.public.ComputePairing()
|
||||
return k.public
|
||||
}
|
||||
@@ -0,0 +1,279 @@
|
||||
/// Copyright (c) 2018 xdx. All rights reserved.
|
||||
///
|
||||
/// \file: keyexchange.go
|
||||
///
|
||||
/// \brief: SM9密钥交换协议
|
||||
///
|
||||
/// \author: xdx
|
||||
///
|
||||
/// 注意:密钥交换协议中要求双方的主公钥一致。
|
||||
|
||||
package sm9
|
||||
|
||||
import (
|
||||
"io"
|
||||
"math/big"
|
||||
|
||||
"crypto/rand"
|
||||
|
||||
"xdx.jelly/xgcl/gerrors"
|
||||
"xdx.jelly/xgcl/grand"
|
||||
"xdx.jelly/xgcl/sm/sm9/errors"
|
||||
)
|
||||
|
||||
// Sponsor holds a sponsor's key pairs and temp key pairs, context data.
|
||||
// Sponsor对象可以重复使用
|
||||
type Sponsor struct {
|
||||
id []byte
|
||||
r big.Int // update: 20200624, change []byte to *big.Int
|
||||
de UserEncKey
|
||||
//
|
||||
idOfResponsor []byte
|
||||
tempKeyOfSponsor MastEncPublicKey
|
||||
pube MastEncPublicKey //responsor的主公钥
|
||||
state int // Sponsor的状态。
|
||||
}
|
||||
|
||||
// NewSponsor make a copy of privateKey, so Clear will not change the input privateKey
|
||||
// input:
|
||||
//
|
||||
// id sponsor's id
|
||||
// pube responsor's master encryption publick key
|
||||
// de sponsor's private key
|
||||
func NewSponsor(id []byte, de *UserEncKey) *Sponsor {
|
||||
ida := make([]byte, len(id))
|
||||
copy(ida, id)
|
||||
return &Sponsor{
|
||||
id: ida,
|
||||
de: *de,
|
||||
}
|
||||
}
|
||||
|
||||
// Clear 无论成功与否,最后调用Clear
|
||||
func (s *Sponsor) Clear() {
|
||||
// s.de.Clear()
|
||||
}
|
||||
|
||||
// Responsor hold a responsor's key pairs and id
|
||||
// Responsor对象可以重复使用
|
||||
type Responsor struct {
|
||||
id []byte
|
||||
de UserEncKey
|
||||
}
|
||||
|
||||
// NewResponsor return a responsor's instance
|
||||
func NewResponsor(id []byte, de *UserEncKey) *Responsor {
|
||||
return &Responsor{
|
||||
id: dup(id),
|
||||
de: *de,
|
||||
}
|
||||
}
|
||||
|
||||
// Clear 无论成功与否,最后调用Clear
|
||||
func (rs *Responsor) Clear() {
|
||||
// rs.de.Clear()
|
||||
}
|
||||
|
||||
// // A is sponsor and B is responsor
|
||||
|
||||
// //////////////////////
|
||||
// // 发起方函数
|
||||
|
||||
// GenerateAgreementData 发起方首先调用
|
||||
// 输出tempKeyOfSponsor发送给响应方。调用MashalBinary转换为字节
|
||||
func (s *Sponsor) GenerateAgreementData(
|
||||
idOfResponsor []byte,
|
||||
pube *MastEncPublicKey,
|
||||
rnd []byte) (tempKeyOfSponsor *MastEncPublicKey, err error) {
|
||||
|
||||
s.idOfResponsor = make([]byte, len(idOfResponsor))
|
||||
copy(s.idOfResponsor, idOfResponsor)
|
||||
|
||||
if len(rnd) < byteSize {
|
||||
rnd = make([]byte, byteSize)
|
||||
if _, err := grand.GenerateRandom(rnd); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// return nil, gerrors.ERR_SM_INVALID_INPUT
|
||||
}
|
||||
if !pube.G1.IsValid() {
|
||||
return nil, gerrors.WithAnnotating(errors.ErrKeyExchangeFailed, "input MastEncPublicKey is not a valid point on curve")
|
||||
}
|
||||
s.pube.G1.Set(&pube.G1)
|
||||
|
||||
s.r.SetBytes(rnd)
|
||||
tempKeyOfSponsor = &MastEncPublicKey{}
|
||||
tempKeyOfSponsor.G1.ScalarMult(hashToG1(idOfResponsor, &pube.G1, hidKeyExchange), &s.r)
|
||||
s.tempKeyOfSponsor.G1.Set(&tempKeyOfSponsor.G1)
|
||||
s.state = 1
|
||||
return tempKeyOfSponsor, nil
|
||||
}
|
||||
|
||||
// GenerateKey 发起方调用生成协商密钥。
|
||||
func (s *Sponsor) GenerateKey(tempKeyOfResponsor *MastEncPublicKey, keyLength int) (outKey []byte, err error) {
|
||||
// TODO: 改为状态模式?
|
||||
if s.state != 1 {
|
||||
return nil, gerrors.WithAnnotating(errors.ErrKeyExchangeFailed, "call GenerateAgreementData first")
|
||||
}
|
||||
|
||||
if !tempKeyOfResponsor.G1.IsValid() {
|
||||
return nil, gerrors.WithAnnotating(errors.ErrKeyExchangeFailed, "input MastEncPublicKey is not a valid point on curve")
|
||||
}
|
||||
g1 := >{}
|
||||
g2 := >{}
|
||||
pairing(g1, &s.pube.G1, g2Gen)
|
||||
g1.ScalarMult(g1, &s.r)
|
||||
pairing(g2, &tempKeyOfResponsor.G1, &s.de.G2)
|
||||
g3 := (>{}).ScalarMult(g2, &s.r)
|
||||
|
||||
buf := make([]byte, 0, byteSize*4+byteSize*12*3)
|
||||
buf = append(buf, s.tempKeyOfSponsor.G1.Marshal()...)
|
||||
buf = append(buf, tempKeyOfResponsor.G1.Marshal()...)
|
||||
buf = append(buf, g1.Marshal()...)
|
||||
buf = append(buf, g2.Marshal()...)
|
||||
buf = append(buf, g3.Marshal()...)
|
||||
|
||||
outKey = make([]byte, keyLength)
|
||||
_ = Kdf(outKey, s.id, s.idOfResponsor, buf)
|
||||
s.state = 0
|
||||
return outKey, nil
|
||||
}
|
||||
|
||||
// 响应方
|
||||
|
||||
// GenerateAgreementDataAndKey 响应方调用生成临时公钥及协商密钥
|
||||
// Za、Zb由PreComputeWithIdAndPubkey计算
|
||||
func (rs *Responsor) GenerateAgreementDataAndKey(
|
||||
idOfSponsor []byte,
|
||||
pubeOfSponsor, tempKeyOfSponsor *MastEncPublicKey,
|
||||
keyLength int,
|
||||
rnd []byte) (outKey []byte, tempKeyOfResponsor *MastEncPublicKey, err error) {
|
||||
|
||||
if len(rnd) < byteSize {
|
||||
rnd = make([]byte, byteSize)
|
||||
if _, err := grand.GenerateRandom(rnd); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
// return nil, nil, gerrors.ERR_SM_INVALID_INPUT
|
||||
}
|
||||
r := new(big.Int).SetBytes(rnd)
|
||||
tempKeyOfResponsor = &MastEncPublicKey{}
|
||||
tempKeyOfResponsor.G1.ScalarMult(hashToG1(idOfSponsor, &pubeOfSponsor.G1, hidKeyExchange), r)
|
||||
|
||||
if !pubeOfSponsor.G1.IsValid() {
|
||||
return nil, nil, errors.ErrInvalidMastPublicKey
|
||||
}
|
||||
|
||||
if !tempKeyOfSponsor.G1.IsValid() {
|
||||
return nil, nil, gerrors.WithAnnotating(errors.ErrInvalidPublicKey, "sponsor's temp param is not a valid curve point")
|
||||
}
|
||||
|
||||
g1 := >{}
|
||||
g2 := >{}
|
||||
pairing(g1, &tempKeyOfSponsor.G1, &rs.de.G2)
|
||||
pairing(g2, &pubeOfSponsor.G1, g2Gen)
|
||||
g2.ScalarMult(g2, r)
|
||||
g3 := (>{}).ScalarMult(g1, r)
|
||||
buf := make([]byte, 0, byteSize*4+byteSize*12*3)
|
||||
buf = append(buf, tempKeyOfSponsor.G1.Marshal()...)
|
||||
buf = append(buf, tempKeyOfResponsor.G1.Marshal()...)
|
||||
buf = append(buf, g1.Marshal()...)
|
||||
buf = append(buf, g2.Marshal()...)
|
||||
buf = append(buf, g3.Marshal()...)
|
||||
|
||||
outKey = make([]byte, keyLength)
|
||||
_ = Kdf(outKey, idOfSponsor, rs.id, buf)
|
||||
|
||||
return outKey, tempKeyOfResponsor, nil
|
||||
|
||||
}
|
||||
|
||||
// functional
|
||||
|
||||
func GenerateAgreementData(idb []byte, pube *MastEncPublicKey, rnd io.Reader) (ra *big.Int, Ra *G1, err error) {
|
||||
if !pube.G1.IsValid() {
|
||||
return nil, nil, errors.ErrInvalidMastPublicKey
|
||||
}
|
||||
ra, err = rand.Int(rnd, N)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
for ra.Sign() == 0 {
|
||||
ra, err = rand.Int(rnd, N)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
Ra = &G1{}
|
||||
Ra.ScalarMult(hashToG1(idb, &pube.G1, hidKeyExchange), ra)
|
||||
return
|
||||
}
|
||||
|
||||
// GenerateKey 发起方调用生成协商密钥。
|
||||
func GenerateKey(ida []byte, idb []byte, Ra, Rb *G1, ra *big.Int, de *UserEncKey, pube *MastEncPublicKey, keyLength int) (outKey []byte, err error) {
|
||||
if !Rb.IsValid() {
|
||||
return nil, gerrors.WithAnnotating(errors.ErrInvalidPublicKey, "responsor's temp param(Rb) is not a valid curve point")
|
||||
}
|
||||
g1 := >{}
|
||||
g2 := >{}
|
||||
pairing(g1, &pube.G1, g2Gen)
|
||||
g1.ScalarMult(g1, ra)
|
||||
pairing(g2, Rb, &de.G2)
|
||||
g3 := (>{}).ScalarMult(g2, ra)
|
||||
|
||||
buf := make([]byte, 0, byteSize*4+byteSize*12*3)
|
||||
buf = append(buf, Ra.Marshal()...)
|
||||
buf = append(buf, Rb.Marshal()...)
|
||||
buf = append(buf, g1.Marshal()...)
|
||||
buf = append(buf, g2.Marshal()...)
|
||||
buf = append(buf, g3.Marshal()...)
|
||||
|
||||
outKey = make([]byte, keyLength)
|
||||
_ = Kdf(outKey, ida, idb, buf)
|
||||
return outKey, nil
|
||||
}
|
||||
|
||||
// 响应方
|
||||
|
||||
// GenerateAgreementDataAndKey 响应方调用生成临时公钥及协商密钥
|
||||
// Za、Zb由PreComputeWithIdAndPubkey计算
|
||||
func GenerateAgreementDataAndKey(ida []byte, idb []byte, Ra *G1, de *UserEncKey, pube *MastEncPublicKey, keyLength int, rnd io.Reader) (outKey []byte, Rb *G1, err error) {
|
||||
|
||||
rb, err := rand.Int(rnd, N)
|
||||
if err != nil {
|
||||
return nil, nil, gerrors.WithAnnotating(errors.ErrKeyExchangeFailed, "generate random number failed")
|
||||
}
|
||||
for rb.Sign() == 0 {
|
||||
rb, err = rand.Int(rnd, N)
|
||||
if err != nil {
|
||||
return nil, nil, gerrors.WithAnnotating(errors.ErrKeyExchangeFailed, "generate random number failed")
|
||||
}
|
||||
}
|
||||
Rb = &G1{}
|
||||
Rb.ScalarMult(hashToG1(ida, &pube.G1, hidKeyExchange), rb)
|
||||
|
||||
if !pube.G1.IsValid() {
|
||||
return nil, nil, gerrors.WithAnnotating(errors.ErrInvalidPublicKey, "sponsor's temp param(Ra) is not a valid curve point")
|
||||
}
|
||||
if !Ra.IsValid() {
|
||||
return nil, nil, gerrors.WithAnnotating(errors.ErrInvalidPublicKey, "sponsor's temp param(Ra) is not a valid curve point")
|
||||
}
|
||||
|
||||
g1 := >{}
|
||||
g2 := >{}
|
||||
pairing(g1, Ra, &de.G2)
|
||||
pairing(g2, &pube.G1, g2Gen)
|
||||
g2.ScalarMult(g2, rb)
|
||||
g3 := (>{}).ScalarMult(g1, rb)
|
||||
buf := make([]byte, 0, byteSize*4+byteSize*12*3)
|
||||
buf = append(buf, Ra.Marshal()...)
|
||||
buf = append(buf, Rb.Marshal()...)
|
||||
buf = append(buf, g1.Marshal()...)
|
||||
buf = append(buf, g2.Marshal()...)
|
||||
buf = append(buf, g3.Marshal()...)
|
||||
|
||||
outKey = make([]byte, keyLength)
|
||||
_ = Kdf(outKey, ida, idb, buf)
|
||||
return outKey, Rb, nil
|
||||
}
|
||||
+200
@@ -0,0 +1,200 @@
|
||||
package sm9
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"math/big"
|
||||
"strings"
|
||||
|
||||
"xdx.jelly/xgcl/gerrors"
|
||||
"xdx.jelly/xgcl/gmath"
|
||||
"xdx.jelly/xgcl/grand"
|
||||
"xdx.jelly/xgcl/sm/sm3"
|
||||
"xdx.jelly/xgcl/sm/sm9/errors"
|
||||
)
|
||||
|
||||
// 38635打印数据
|
||||
const PrintIntermediaDataForSTD38635 = false
|
||||
|
||||
// Signature 签名数据结构
|
||||
type Signature struct {
|
||||
H big.Int
|
||||
S G1
|
||||
}
|
||||
|
||||
// NewSignature returns a new Signature.
|
||||
//
|
||||
// Deprecated, use `&Signature{}` or `new(Signature)`.
|
||||
func NewSignature() *Signature {
|
||||
return &Signature{}
|
||||
}
|
||||
|
||||
// MarshalBinary implements the encoding.BinaryMarshaler interface. It returns the byte slice of H || X || Y.
|
||||
func (s *Signature) MarshalBinary() ([]byte, error) {
|
||||
data := make([]byte, 3*Sm9RefMaxLen)
|
||||
if err := gmath.FillBytes(&s.H, data[:Sm9RefMaxLen]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.S.FillBytes(data[Sm9RefMaxLen:])
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface
|
||||
// if return error, s will remain
|
||||
func (s *Signature) UnmarshalBinary(data []byte) error {
|
||||
if len(data) != 3*Sm9RefMaxLen {
|
||||
return gerrors.WithAnnotating(errors.ErrInvalidInput, "input data too short")
|
||||
}
|
||||
s.H.SetBytes(data[:Sm9RefMaxLen])
|
||||
if s.H.Cmp(Order()) >= 0 || s.H.Sign() == 0 {
|
||||
return gerrors.WithAnnotating(errors.ErrInvalidInput, "Signature.H is zero or bigger than order N")
|
||||
}
|
||||
_, err := s.S.Unmarshal(data[Sm9RefMaxLen:])
|
||||
if err != nil {
|
||||
return gerrors.WithMessage(err, "Signature.S Unmarshal failed")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// String 实现Stringer接口
|
||||
func (s *Signature) String() string {
|
||||
return fmt.Sprintf("SM9 Signature{\n\tH: %s,\n\tS: %s\n}", s.H.Text(16), s.S.String())
|
||||
}
|
||||
|
||||
// Bytes output H || X || Y
|
||||
func (s *Signature) Bytes() []byte {
|
||||
buf := make([]byte, 3*byteSize)
|
||||
copy(buf[:byteSize], gmath.BigIntToNByte(&s.H, byteSize))
|
||||
copy(buf[byteSize:], s.S.Marshal())
|
||||
return buf
|
||||
}
|
||||
|
||||
func (s *Signature) Set(t *Signature) {
|
||||
s.H.Set(&t.H)
|
||||
s.S.Set(&t.S)
|
||||
}
|
||||
|
||||
// SetBytes set signature from a byte slice
|
||||
func (s *Signature) SetBytes(data []byte) error {
|
||||
if len(data) < 3*byteSize {
|
||||
return gerrors.WithAnnotating(errors.ErrInvalidInput, "input data too short")
|
||||
}
|
||||
data = data[:3*byteSize]
|
||||
s.H.SetBytes(data[:byteSize])
|
||||
s.S.Unmarshal(data[byteSize:])
|
||||
return nil
|
||||
}
|
||||
|
||||
// Sign 签名
|
||||
//
|
||||
// rnd输入随机字节串或随机数发生器,可以为:
|
||||
// - []byte, 并且len(rnd)= 32
|
||||
// - io.Reader, 随机数发生器, 如crypto/rand.Reader, 也可以是包装的硬件随机数发生器
|
||||
// - nil, 则会使用默认的软件随机数发生器
|
||||
func Sign(msg []byte, ds *UserSignKey, pubs *MastSignPublicKey, rnd interface{}) (*Signature, error) {
|
||||
if rnd == nil {
|
||||
rnd = grand.Reader
|
||||
}
|
||||
|
||||
if b, ok := rnd.([]byte); ok {
|
||||
return sign(msg, ds, pubs, b)
|
||||
} else if reader, ok := rnd.(io.Reader); ok {
|
||||
b := make([]byte, numBytes)
|
||||
if _, err := reader.Read(b); err != nil {
|
||||
return nil, gerrors.ChainErrors(errors.ErrSignFailed, err)
|
||||
}
|
||||
return sign(msg, ds, pubs, b)
|
||||
} else {
|
||||
return nil, gerrors.WithAnnotating(errors.ErrSignFailed, "input rnd can only be nil, []byte or io.Reader")
|
||||
}
|
||||
}
|
||||
|
||||
func sign(msg []byte, ds *UserSignKey, pubs *MastSignPublicKey, rnd []byte) (*Signature, error) {
|
||||
if len(rnd) != byteSize {
|
||||
return nil, gerrors.WithAnnotating(errors.ErrInvalidInput, "input rnd too short")
|
||||
}
|
||||
signature := &Signature{}
|
||||
r := new(big.Int)
|
||||
h := new(big.Int)
|
||||
g := >{}
|
||||
for {
|
||||
r.SetBytes(rnd[:byteSize])
|
||||
if pubs.e != nil {
|
||||
g.ScalarMult(pubs.e, r)
|
||||
} else {
|
||||
mulG1BaseThenPairing(g, &pubs.G2, r)
|
||||
}
|
||||
|
||||
h = H2(msg, g.Marshal())
|
||||
r.Sub(r, h)
|
||||
r.Mod(r, Order())
|
||||
|
||||
if PrintIntermediaDataForSTD38635 {
|
||||
fmt.Printf("计算群GT中的元素g = e (P1 , Ppub-s): %s\n", pubs.e.String())
|
||||
fmt.Printf("计算群GT中的元素w = g^r: %s\n", g.String())
|
||||
fmt.Printf("h: %s\n", strings.ToUpper(h.Text(16)))
|
||||
fmt.Printf("计算l = ( r - h ) mod N: %s\n", strings.ToUpper(r.Text(16)))
|
||||
}
|
||||
|
||||
if r.Sign() != 0 {
|
||||
break
|
||||
}
|
||||
|
||||
d := sm3.Sum(rnd)
|
||||
copy(rnd, d[:])
|
||||
}
|
||||
// Issues 5
|
||||
// s := ds.G1.ScalarMult(&ds.G1, r) //ds changed!
|
||||
s := (&G1{}).ScalarMult(&ds.G1, r)
|
||||
|
||||
if PrintIntermediaDataForSTD38635 {
|
||||
fmt.Printf("计算群G1中的元素S: %s\n", s.String())
|
||||
fmt.Printf("消息M的签名为(h, S):\n")
|
||||
fmt.Printf("h: %s\n", strings.ToUpper(h.Text(16)))
|
||||
fmt.Printf("S: %s\n", s.String())
|
||||
}
|
||||
|
||||
signature.H.Set(h)
|
||||
signature.S.Set(s)
|
||||
return signature, nil
|
||||
}
|
||||
|
||||
// Verify 签名验证
|
||||
func Verify(sig *Signature, uid, msg []byte, pubs *MastSignPublicKey) bool {
|
||||
h := new(big.Int).Set(&sig.H)
|
||||
if gmath.IsBigInt0(h) || h.Cmp(Order()) >= 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
if !sig.S.IsValid() || sig.S.IsZero() {
|
||||
return false
|
||||
}
|
||||
|
||||
t := >{}
|
||||
mulG1BaseThenPairing(t, &pubs.G2, h)
|
||||
|
||||
h1 := H1(uid, []byte{hidSign})
|
||||
p := new(G2).ScalarBaseMult(h1)
|
||||
p.Add(p, &pubs.G2)
|
||||
|
||||
u := >{}
|
||||
pairing(u, &sig.S, p)
|
||||
|
||||
if PrintIntermediaDataForSTD38635 {
|
||||
fmt.Printf("计算群GT中的元素g = e (P1 , Ppub-s): %s\n", pubs.e.String())
|
||||
fmt.Printf("计算群GT中的元素t = g^h: %s\n", t.String())
|
||||
fmt.Printf("计算h1 = H1(IDA||hid, N)\n")
|
||||
fmt.Printf("h1: %s\n", strings.ToUpper(h1.Text(16)))
|
||||
fmt.Printf("计算群G2中的元素P = [h1]P2 + Ppub-s = (xP , yP): %s\n", p.String())
|
||||
fmt.Printf("计算群GT中的元素u = e (S , P): %s\n", u.String())
|
||||
}
|
||||
|
||||
u.Add(u, t) // In GT, Add is the same with Mul
|
||||
h2 := H2(msg, u.Marshal())
|
||||
if PrintIntermediaDataForSTD38635 {
|
||||
fmt.Printf("计算群GT中的元素w' = u*t: %s\n", u.String())
|
||||
fmt.Printf("计算h2 = H2(M||w, N): %s\n", strings.ToUpper(h.Text(16)))
|
||||
|
||||
}
|
||||
return h2.Cmp(h) == 0
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package sm9
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"io"
|
||||
)
|
||||
|
||||
var _ crypto.Signer = &Signer{}
|
||||
var _ crypto.Decrypter = &Decrypter{}
|
||||
|
||||
type Signer struct {
|
||||
Id []byte
|
||||
Priv *UserSignKey
|
||||
MastSignPublicKey *MastSignPublicKey
|
||||
}
|
||||
|
||||
// Sign signs digest with priv, reading randomness from rand. The opts argument
|
||||
// is not currently used but, in keeping with the crypto.Signer interface,
|
||||
// should be the hash function used to digest the message.
|
||||
func (s *Signer) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) {
|
||||
signature, err := Sign(digest, s.Priv, s.MastSignPublicKey, rand)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return signature.MarshalASN1(false)
|
||||
}
|
||||
func VerifyASN1(id []byte, hash, sig []byte, pub *MastSignPublicKey) bool {
|
||||
var signature Signature
|
||||
_, err := signature.UnmarshalASN1(sig)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return Verify(&signature, id, hash, pub)
|
||||
}
|
||||
|
||||
type Decrypter struct {
|
||||
Id []byte
|
||||
Priv *UserEncKey
|
||||
MastEncPublicKey *MastEncPublicKey
|
||||
}
|
||||
|
||||
func (s *Signer) Public() crypto.PublicKey {
|
||||
return s.Id
|
||||
}
|
||||
|
||||
// Decrypt implements crypto.Decrypter.
|
||||
func (d *Decrypter) Decrypt(rand io.Reader, msg []byte, opts crypto.DecrypterOpts) (plaintext []byte, err error) {
|
||||
var cipher Cipher
|
||||
_, err = cipher.UnmarshalASN1(msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return Decrypt(d.Id, &cipher, d.Priv)
|
||||
}
|
||||
|
||||
func (d *Decrypter) Public() crypto.PublicKey {
|
||||
return d.Id
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package sm9
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"xdx.jelly/xgcl/sm/sm9/errors"
|
||||
"xdx.jelly/xgcl/sm/sm9/internal/bn256"
|
||||
)
|
||||
|
||||
const (
|
||||
// Sm9RefMaxBits defined in GMT 0018
|
||||
Sm9RefMaxBits = 256
|
||||
|
||||
// Sm9RefMaxLen defined in GMT 0018
|
||||
Sm9RefMaxLen = (Sm9RefMaxBits + 7) / 8
|
||||
|
||||
byteSize = Sm9RefMaxLen
|
||||
|
||||
// Sm9Strict UnmarshalBinary check data strict
|
||||
Sm9Strict = false
|
||||
|
||||
// hidSign 签名hid
|
||||
hidSign byte = 1
|
||||
|
||||
// hidKeyExchange 密钥交换hid
|
||||
hidKeyExchange byte = 3
|
||||
|
||||
// hidKeyEncapsule 密钥封装hid
|
||||
hidKeyEncapsule byte = 3
|
||||
|
||||
// hidEncryption 加解密hid
|
||||
hidEncryption byte = 3
|
||||
)
|
||||
|
||||
// G1 is the group G<sup>1</sup>
|
||||
type G1 = bn256.G1
|
||||
|
||||
// G2 is the group G2
|
||||
type G2 = bn256.G2
|
||||
|
||||
// GT is the group GT
|
||||
type GT = bn256.GT
|
||||
|
||||
type PublicKey = []byte
|
||||
|
||||
var (
|
||||
// Pairing is the pairing funcition e: G1 x G2 -> GT.
|
||||
Pairing func(g1 *G1, g2 *G2) *GT = bn256.Pair
|
||||
pairing func(e *GT, g1 *G1, g2 *G2) = bn256.PairLol
|
||||
|
||||
// N is the group order of G1, G2 and GT
|
||||
N = bn256.N
|
||||
|
||||
// P is the character of finite field where E lives.
|
||||
P = bn256.P
|
||||
|
||||
g1Gen *G1 = new(G1).ScalarBaseMult(new(big.Int).SetInt64(1))
|
||||
g2Gen *G2 = new(G2).ScalarBaseMult(new(big.Int).SetInt64(1))
|
||||
gtGen *GT = Pairing(g1Gen, g2Gen)
|
||||
nMinusOne = new(big.Int).Sub(N, new(big.Int).SetInt64(1))
|
||||
)
|
||||
|
||||
// ByteSize returns the size of the bytes number of order (which is 32).
|
||||
func ByteSize() int {
|
||||
return byteSize
|
||||
}
|
||||
|
||||
// OrderN return the order of group G1, G2 and GT
|
||||
// Deprecated: use Order instead.
|
||||
var OrderN = Order
|
||||
|
||||
// Order returns the order of group G1, G2 and GT.
|
||||
func Order() *big.Int {
|
||||
return N
|
||||
}
|
||||
|
||||
// Prime returns the character of finite field.
|
||||
func Prime() *big.Int {
|
||||
return P
|
||||
}
|
||||
|
||||
// G1Generator returns the generator of G1.
|
||||
func G1Generator() *G1 {
|
||||
return g1Gen
|
||||
}
|
||||
|
||||
// G2Generator returns the generator of G2.
|
||||
func G2Generator() *G2 {
|
||||
return g2Gen
|
||||
}
|
||||
|
||||
// GTGenerator returns the generator of GT.
|
||||
func GTGenerator() *GT {
|
||||
return gtGen
|
||||
}
|
||||
|
||||
var ErrKGCRebuildKey = errors.ErrKGCRebuildKey
|
||||
@@ -0,0 +1,33 @@
|
||||
package sm9
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func BenchmarkSign(b *testing.B) {
|
||||
uid := []byte("Alice")
|
||||
msg := []byte("Chinese IBS standard")
|
||||
|
||||
ks, pubs, _ := GenerateMastSignPrivateKey(rand.Reader)
|
||||
ds, _ := GenerateUserSignKey(uid, ks)
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = Sign(msg, ds, pubs, nil)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkVerify(b *testing.B) {
|
||||
uid := []byte("Alice")
|
||||
msg := []byte("Chinese IBS standard")
|
||||
ks, pubs, _ := GenerateMastSignPrivateKey(rand.Reader)
|
||||
|
||||
ds, _ := GenerateUserSignKey(uid, ks)
|
||||
sig, _ := Sign(msg, ds, pubs, nil)
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
Verify(sig, uid, msg, pubs)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
package sm9
|
||||
|
||||
// Fuzz Test use random data and run for a long time
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"testing"
|
||||
|
||||
"xdx.jelly/xgcl/sm/sm3"
|
||||
"xdx.jelly/xgcl/sm/sm4"
|
||||
"xdx.jelly/xgcl/utils/padding"
|
||||
)
|
||||
|
||||
func FuzzSign(f *testing.F) {
|
||||
ks, pubs, err := GenerateMastSignPrivateKey(rand.Reader)
|
||||
if err != nil {
|
||||
f.Fatal(err)
|
||||
}
|
||||
|
||||
f.Add([]byte{}, []byte{}, []byte{})
|
||||
f.Fuzz(func(t *testing.T, uid, msg, seed []byte) {
|
||||
ds, err := GenerateUserSignKey(uid, ks)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
dig := sm3.Sum(seed)
|
||||
signature, err := Sign(msg, ds, pubs, dig[:])
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !Verify(signature, uid, msg, pubs) {
|
||||
t.Fatal("verify failed")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func FuzzKeyExchange(f *testing.F) {
|
||||
ke, pube, err := GenerateMastEncPrivateKey(rand.Reader)
|
||||
if err != nil {
|
||||
f.Fatal(err)
|
||||
}
|
||||
|
||||
f.Add([]byte{}, []byte{}, []byte{}, uint(1))
|
||||
f.Fuzz(func(t *testing.T, idA, idB, seed []byte, kLen uint) {
|
||||
kLen += 1
|
||||
deA, _ := GenerateUserEncKey(idA, ke)
|
||||
deB, _ := GenerateUserEncKey(idB, ke)
|
||||
alice := NewSponsor(idA, deA)
|
||||
bob := NewResponsor(idB, deB)
|
||||
rnd := sm3.Sum(seed)
|
||||
tempKeyOfSponsor, _ := alice.GenerateAgreementData(idB, pube, rnd[:])
|
||||
rnd = sm3.Sum(seed)
|
||||
keyOfResponsor, tempKeyOfResponsor, _ := bob.GenerateAgreementDataAndKey(idA, pube, tempKeyOfSponsor, int(kLen), rnd[:])
|
||||
keyOfSponsor, _ := alice.GenerateKey(tempKeyOfResponsor, int(kLen))
|
||||
if !bytes.Equal(keyOfResponsor, keyOfSponsor) {
|
||||
t.Fatal()
|
||||
}
|
||||
alice.Clear()
|
||||
bob.Clear()
|
||||
})
|
||||
}
|
||||
|
||||
func FuzzEnc(f *testing.F) {
|
||||
ke, pube, err := GenerateMastEncPrivateKey(rand.Reader)
|
||||
if err != nil {
|
||||
f.Fatal(err)
|
||||
}
|
||||
|
||||
f.Add([]byte{}, []byte{}, []byte{})
|
||||
f.Fuzz(func(t *testing.T, id, msg, seed []byte) {
|
||||
de, err := GenerateUserEncKey(id, ke)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// msg,id可能共享内存,因此不能直接在msg上padding。先复制一份
|
||||
paddedMsg := append([]byte{}, msg...)
|
||||
paddedMsg = padding.P7.Pad(paddedMsg, sm4.BlockSize)
|
||||
|
||||
for _, encType := range []EncType{EncTypeKDF} {
|
||||
c, err := Encrypt(encType, pube, id, msg, rand.Reader, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
plain, err := Decrypt(id, c, de)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !bytes.Equal(plain, msg) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
for _, encType := range []EncType{EncTypeSM4ECB, EncTypeSM4CBC, EncTypeSM4CFB, EncTypeSM4OFB} {
|
||||
c, err := Encrypt(encType, pube, id, paddedMsg, rand.Reader, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
plain, err := Decrypt(id, c, de)
|
||||
if !bytes.Equal(plain, paddedMsg) || err != nil {
|
||||
t.Fatal()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package sm9
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"xdx.jelly/xgcl/internal"
|
||||
)
|
||||
|
||||
func TestReportSpeed(T *testing.T) {
|
||||
uid := []byte("Alice")
|
||||
msg := []byte("Chinese IBS standard")
|
||||
ks, pubs, _ := GenerateMastSignPrivateKey(rand.Reader)
|
||||
ds, _ := ks.GenerateUserSignKey(uid)
|
||||
|
||||
count, duation := internal.SingleThreadTester(func() {
|
||||
ds, _ = ks.GenerateUserSignKey(uid)
|
||||
})
|
||||
fmt.Printf("Generate User key: %d, used time: %d ms, %d pcs/s\n", count, duation.Milliseconds(), int(internal.Rate(count, duation)))
|
||||
|
||||
var sig *Signature
|
||||
count, duation = internal.SingleThreadTester(func() {
|
||||
sig, _ = Sign(msg, ds, pubs, nil)
|
||||
})
|
||||
fmt.Printf("Sign %d, used time: %d ms, %d pcs/s\n", count, duation.Milliseconds(), int(internal.Rate(count, duation)))
|
||||
|
||||
count, duation = internal.SingleThreadTester(func() {
|
||||
Verify(sig, uid, msg, pubs)
|
||||
})
|
||||
|
||||
fmt.Printf("Verify %d, used time: %d ms, %d pcs/s\n", count, duation.Milliseconds(), int(internal.Rate(count, duation)))
|
||||
|
||||
}
|
||||
@@ -0,0 +1,350 @@
|
||||
package sm9
|
||||
|
||||
// fixed data test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"xdx.jelly/xgcl/grand"
|
||||
)
|
||||
|
||||
func TestKey(t *testing.T) {
|
||||
uid := []byte("Alice")
|
||||
b, _ := hex.DecodeString("000130E78459D78545CB54C587E02CF480CE0B66340F319F348A1D5B1F2DC5F4")
|
||||
ks, pubs, _ := GenerateMastSignPrivateKey(bytes.NewReader(b))
|
||||
|
||||
if hex.EncodeToString(pubs.Bytes()) != "9f64080b3084f733e48aff4b41b565011ce0711c5e392cfb0ab1b6791b94c40829dba116152d1f786ce843ed24a3b573414d2177386a92dd8f14d65696ea5e3269850938abea0112b57329f447e3a0cbad3e2fdb1a77f335e89e1408d0ef1c2541e00a53dda532da1a7ce027b7a46f741006e85f5cdff0730e75c05fb4e3216d" {
|
||||
t.Fatal()
|
||||
return
|
||||
}
|
||||
|
||||
ds, err := ks.GenerateUserSignKey(uid)
|
||||
if err != nil {
|
||||
t.Log(err)
|
||||
t.Fatal()
|
||||
return
|
||||
}
|
||||
|
||||
if hex.EncodeToString(ds.Bytes()) != "a5702f05cf1315305e2d6eb64b0deb923db1a0bcf0caff90523ac8754aa6982078559a844411f9825c109f5ee3f52d720dd01785392a727bb1556952b2b013d3" {
|
||||
t.Fatal()
|
||||
return
|
||||
}
|
||||
|
||||
uid = []byte("Bob")
|
||||
b, _ = hex.DecodeString("0001EDEE3778F441F8DEA3D9FA0ACC4E07EE36C93F9A08618AF4AD85CEDE1C22")
|
||||
ke, pube, _ := GenerateMastEncPrivateKey(bytes.NewReader(b))
|
||||
|
||||
if hex.EncodeToString(pube.Bytes()) != "787ed7b8a51f3ab84e0a66003f32da5c720b17eca7137d39abc66e3c80a892ff769de61791e5adc4b9ff85a31354900b202871279a8c49dc3f220f644c57a7b1" {
|
||||
t.Fatal()
|
||||
return
|
||||
}
|
||||
de, _ := ke.GenerateUserEncKey(uid)
|
||||
buf := de.Bytes()
|
||||
if err := de.SetBytes(buf); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if hex.EncodeToString(de.Bytes()) != "94736acd2c8c8796cc4785e938301a139a059d3537b6414140b2d31eecf41683115bae85f5d8bc6c3dbd9e5342979acccf3c2f4f28420b1cb4f8c0b59a19b1587aa5e47570da7600cd760a0cf7beaf71c447f3844753fe74fa7ba92ca7d3b55f27538a62e7f7bfb51dce08704796d94c9d56734f119ea44732b50e31cdeb75c1" {
|
||||
t.Fatal()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestSign(t *testing.T) {
|
||||
uid := []byte("Alice")
|
||||
msg := []byte("Chinese IBS standard")
|
||||
rnd, _ := hex.DecodeString("000130E78459D78545CB54C587E02CF480CE0B66340F319F348A1D5B1F2DC5F4")
|
||||
ks, pubs, _ := GenerateMastSignPrivateKey(bytes.NewReader(rnd))
|
||||
|
||||
ds, _ := ks.GenerateUserSignKey(uid)
|
||||
rnd, _ = hex.DecodeString("00033C8616B06704813203DFD00965022ED15975C662337AED648835DC4B1CBE")
|
||||
_, _ = Sign(msg, ds, pubs, rnd)
|
||||
// Test Issue 5, Sign changed ds.
|
||||
signature, _ := Sign(msg, ds, pubs, rnd)
|
||||
|
||||
s, err := signature.MarshalBinary()
|
||||
if err != nil {
|
||||
t.Log("Signature.MarshalBinary failed: ", err)
|
||||
}
|
||||
if hex.EncodeToString(s) !=
|
||||
"823c4b21e4bd2dfe1ed92c606653e996668563152fc33f55d7bfbb9bd9705adb"+
|
||||
"73bf96923ce58b6ad0e13e9643a406d8eb98417c50ef1b29cef9adb48b6d598c"+
|
||||
"856712f1c2e0968ab7769f42a99586aed139d5b8b3e15891827cc2aced9baa05" {
|
||||
t.Fatal()
|
||||
}
|
||||
if !Verify(signature, uid, msg, pubs) {
|
||||
t.Fatal()
|
||||
}
|
||||
}
|
||||
|
||||
func TestKeyExchange(t *testing.T) {
|
||||
// FIXME test the fixed data
|
||||
idA := []byte("Sponsor")
|
||||
idB := []byte("Responsor")
|
||||
|
||||
keA, pubeA, _ := GenerateMastEncPrivateKey(rand.Reader)
|
||||
deA, _ := keA.GenerateUserEncKey(idA)
|
||||
// A and B must under a same KGC's master key
|
||||
keB := keA
|
||||
// keB := GenMastEncPrivateKey(nil)
|
||||
pubeB := pubeA
|
||||
// pubeB := GenMastEncPublicKey(keB)
|
||||
deB, _ := keB.GenerateUserEncKey(idB)
|
||||
|
||||
// 使用默认id传入nil或GetDefaultID
|
||||
alice := NewSponsor(idA, deA)
|
||||
bob := NewResponsor(idB, deB)
|
||||
|
||||
// NEVER FORGET CLEAR
|
||||
// defer keA.Clear()
|
||||
// defer keB.Clear()
|
||||
// defer deA.Clear()
|
||||
// defer deB.Clear()
|
||||
defer alice.Clear()
|
||||
defer bob.Clear()
|
||||
|
||||
// 多次密钥交换是可以重复使用Sponsor和Responsor的-只要其私钥和id不变
|
||||
for keylen := 1; keylen < 256; keylen++ {
|
||||
// t.Log("key exchange test for key length = ", keylen)
|
||||
|
||||
// key exchange
|
||||
tempKeyOfSponsor, _ := alice.GenerateAgreementData(idB, pubeB, nil)
|
||||
// t.Log("11", tempKeyOfSponsor, err)
|
||||
keyOfResponsor, tempKeyOfResponsor, _ := bob.GenerateAgreementDataAndKey(idA, pubeA, tempKeyOfSponsor, keylen, nil)
|
||||
// t.Log("tempKeyOfResponsor", tempKeyOfResponsor)
|
||||
// return
|
||||
|
||||
keyOfSponsor, _ := alice.GenerateKey(tempKeyOfResponsor, keylen)
|
||||
|
||||
// check if OK
|
||||
// printlen := 32
|
||||
// if keylen < printlen {
|
||||
// printlen = keylen
|
||||
// }
|
||||
//t.Log("responsor: ", hex.EncodeToString(keyOfResponsor[:printlen]), "...")
|
||||
//t.Log("sponsor : ", hex.EncodeToString(keyOfSponsor[:printlen]), "...")
|
||||
if !bytes.Equal(keyOfResponsor, keyOfSponsor) {
|
||||
t.Log()
|
||||
t.Fail()
|
||||
return
|
||||
}
|
||||
// t.Log("OK\n")
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func TestKeyExchange2(t *testing.T) {
|
||||
idA := []byte("Sponsor")
|
||||
idB := []byte("Responsor")
|
||||
|
||||
ke, pube, _ := GenerateMastEncPrivateKey(rand.Reader)
|
||||
deA, _ := ke.GenerateUserEncKey(idA)
|
||||
deB, _ := ke.GenerateUserEncKey(idB)
|
||||
|
||||
for keylen := 0; keylen < 256; keylen++ {
|
||||
ra, Ra, err := GenerateAgreementData(idB, pube, grand.Reader)
|
||||
if err != nil {
|
||||
t.Fatal()
|
||||
}
|
||||
key2, Rb, err := GenerateAgreementDataAndKey(idA, idB, Ra, deB, pube, keylen, grand.Reader)
|
||||
if err != nil {
|
||||
t.Fatal()
|
||||
}
|
||||
key1, err := GenerateKey(idA, idB, Ra, Rb, ra, deA, pube, keylen)
|
||||
if err != nil {
|
||||
t.Fatal()
|
||||
}
|
||||
|
||||
if !bytes.Equal(key1, key2) {
|
||||
t.Fatal()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func TestKeyEncap(t *testing.T) {
|
||||
r, _ := hex.DecodeString("0001EDEE3778F441F8DEA3D9FA0ACC4E07EE36C93F9A08618AF4AD85CEDE1C22")
|
||||
ke, pube, _ := GenerateMastEncPrivateKey(bytes.NewReader(r))
|
||||
id := []byte("Bob")
|
||||
|
||||
r, _ = hex.DecodeString("000074015F8489C01EF4270456F9E6475BFB602BDE7F33FD482AB4E3684A6722")
|
||||
|
||||
klen := 32
|
||||
keypackage, key, err := KeyEncapsulate(id, klen, pube, r)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if hex.EncodeToString(key) != "4ff5cf86d2ad40c8f4bac98d76abdbde0c0e2f0a829d3f911ef5b2bce0695480" {
|
||||
t.Fatal()
|
||||
}
|
||||
|
||||
target, _ := hex.DecodeString("1edee2c3f465914491de44cefb2cb434ab02c308d9dc5e2067b4fed5aaac8a0f1c9b4c435eca35ab83bb734174c0f78fde81a53374aff3b3602bbc5e37be9a4c")
|
||||
if !bytes.Equal(keypackage.G1.Marshal(), target) {
|
||||
t.Fatal()
|
||||
}
|
||||
|
||||
de, _ := ke.GenerateUserEncKey(id)
|
||||
uncapKey, _ := KeyDecapsulate(id, keypackage, klen, de)
|
||||
if hex.EncodeToString(uncapKey) != "4ff5cf86d2ad40c8f4bac98d76abdbde0c0e2f0a829d3f911ef5b2bce0695480" {
|
||||
t.Log(hex.EncodeToString(uncapKey))
|
||||
t.Log(hex.EncodeToString(key))
|
||||
t.Fatal()
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncryptionECB(t *testing.T) {
|
||||
id := []byte("Bob")
|
||||
rnd, _ := hex.DecodeString("0001EDEE3778F441F8DEA3D9FA0ACC4E07EE36C93F9A08618AF4AD85CEDE1C22")
|
||||
ke, pube, _ := GenerateMastEncPrivateKey(bytes.NewReader(rnd))
|
||||
|
||||
msg := []byte("Chinese IBE standard")
|
||||
msg = append(msg, []byte{0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c}...)
|
||||
de, _ := ke.GenerateUserEncKey(id)
|
||||
rnd, _ = hex.DecodeString("0000AAC0541779C8FC45E3E2CB25C12B5D2576B2129AE8BB5EE2CBE5EC9E785C")
|
||||
c, err := EncryptionSm4ECB(id, msg, pube, rnd)
|
||||
if err != nil {
|
||||
t.Fatal()
|
||||
}
|
||||
encType := make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(encType, uint32(EncTypeSM4ECB))
|
||||
if data, err := c.MarshalBinary(); err != nil || hex.EncodeToString(data) != hex.EncodeToString(encType)+"2445471164490618e1ee20528ff1d545b0f14c8bcaa44544f03dab5dac07d8ff42ffca97d57cddc05ea405f2e586feb3a6930715532b8000759f13059ed59ac0fd3c98dd92c44c68332675a370cceede31e0c5cd209c257601149d12b394a2be00000020e05b6fac6f11b965268c994f00dba7a8bb00fd60583546cbdf4649250863f10a" {
|
||||
t.Log("Got :", hex.EncodeToString(data))
|
||||
t.Log("Want:", "000000022445471164490618e1ee20528ff1d545b0f14c8bcaa44544f03dab5dac07d8ff42ffca97d57cddc05ea405f2e586feb3a6930715532b8000759f13059ed59ac0fd3c98dd92c44c68332675a370cceede31e0c5cd209c257601149d12b394a2be00000020e05b6fac6f11b965268c994f00dba7a8bb00fd60583546cbdf4649250863f10a")
|
||||
t.Fatal()
|
||||
}
|
||||
|
||||
plain, err := DecryptionSm4ECB(id, c, de)
|
||||
if !bytes.Equal(plain, msg) || err != nil {
|
||||
t.Fatal()
|
||||
}
|
||||
|
||||
data, _ := c.MarshalBinary()
|
||||
c1 := NewCipher()
|
||||
if err = c1.UnmarshalBinary(data); err != nil {
|
||||
t.Fatal()
|
||||
}
|
||||
data2, _ := c1.MarshalBinary()
|
||||
if !bytes.Equal(data, data2) {
|
||||
t.Fatal()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestEncryptionKDF(t *testing.T) {
|
||||
id := []byte("Bob")
|
||||
rnd, _ := hex.DecodeString("0001EDEE3778F441F8DEA3D9FA0ACC4E07EE36C93F9A08618AF4AD85CEDE1C22")
|
||||
ke, pube, _ := GenerateMastEncPrivateKey(bytes.NewReader(rnd))
|
||||
|
||||
msg := []byte("Chinese IBE standard")
|
||||
de, _ := GenerateUserEncKey(id, ke)
|
||||
rnd, _ = hex.DecodeString("0000AAC0541779C8FC45E3E2CB25C12B5D2576B2129AE8BB5EE2CBE5EC9E785C")
|
||||
|
||||
c, err := Encrypt(EncTypeKDF, pube, id, msg, bytes.NewReader(rnd), nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
encType := make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(encType, uint32(EncTypeKDF))
|
||||
if data, err := c.MarshalBinary(); err != nil || hex.EncodeToString(data) != hex.EncodeToString(encType)+"2445471164490618e1ee20528ff1d545b0f14c8bcaa44544f03dab5dac07d8ff42ffca97d57cddc05ea405f2e586feb3a6930715532b8000759f13059ed59ac0ba672387bcd6de5016a158a52bb2e7fc429197bcab70b25afee37a2b9db9f367000000141b5f5b0e951489682f3e64e1378cdd5da9513b1c" {
|
||||
t.Fatal()
|
||||
}
|
||||
|
||||
plain, err := Decrypt(id, c, de)
|
||||
if !bytes.Equal(plain, msg) || err != nil {
|
||||
t.Fatal()
|
||||
}
|
||||
|
||||
data, _ := c.MarshalBinary()
|
||||
c1 := &Cipher{}
|
||||
if err = c1.UnmarshalBinary(data); err != nil {
|
||||
t.Fatal()
|
||||
}
|
||||
data2, _ := c1.MarshalBinary()
|
||||
if !bytes.Equal(data, data2) {
|
||||
t.Fatal()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestGenMastKey(t *testing.T) {
|
||||
for i := 1; i < 1000; i++ {
|
||||
_, _, err := GenerateMastEncPrivateKey(bytes.NewReader(grand.GetRandom(i)))
|
||||
if err != nil {
|
||||
t.Fatal()
|
||||
}
|
||||
|
||||
_, _, err = GenerateMastSignPrivateKey(bytes.NewReader(grand.GetRandom(i)))
|
||||
if err != nil {
|
||||
t.Fatal()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSign1(t *testing.T) {
|
||||
uid, _ := hex.DecodeString("5573657231")
|
||||
msg, _ := hex.DecodeString("5152536162636471")
|
||||
|
||||
d, _ := hex.DecodeString("530569D472BD8A263AF99F6A3DE7FAA807E2B1094A6DCB98EAFE7E045B64F7EF" +
|
||||
"88201ADF41654F340A796F113D0E885BA70D088B076F14831B4553EB0105B2E3" +
|
||||
"0FFFDC648D8BD259F27BB90C9C09E6E8FAEDD46D1B017FF3CEFA6FC914EFE8D5" +
|
||||
"3137D9A8731FFDA255E519CE3340DC1D0ED5F0273258E441B994EC955B497961")
|
||||
pubs, _ := new(MastSignPublicKey).SetBytes(d)
|
||||
|
||||
d, _ = hex.DecodeString("1740268704F86C31B641287A1B296087DFDB43C5FB00AB687D03059E54334583" +
|
||||
"08B1B3DBD5447690DC8EC3967D804927AF5C6BD36ED058EB9728BDAF69B117C7" +
|
||||
"359DA014F0C619F9729AE1F2B62C567B1DCF5E1885DA322B019DF1F04F3CDFF8")
|
||||
signature := new(Signature)
|
||||
signature.SetBytes(d)
|
||||
|
||||
if !Verify(signature, uid, msg, pubs) {
|
||||
t.Fatal()
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncryption1(t *testing.T) {
|
||||
id, err := hex.DecodeString("5573657231")
|
||||
assert.Nil(t, err)
|
||||
de := new(UserEncKey)
|
||||
b, err := hex.DecodeString("5DB6FAEF0E0C010C20F35341C68DA9111BFB8582C60F9B07F08E3D9F7929D14F847DA2D9F02ACA4B324827A2B54601CE2C26D9693F6A3018984925557F11653451D82AE921FD2C9D64D8D3A824DF1B6753C71234A5420E1BAC456919B88E84EB8D7B9FA5788AEF0B9BAD1BECC5FAA9619BA58F2C97343235193A24857EF9F0A3")
|
||||
assert.Nil(t, err)
|
||||
de.Unmarshal(b)
|
||||
|
||||
b, err = hex.DecodeString("23E2C8C3C2267865198A6C1062D7703A0745D9AB86CCB3E0CB0E9B8D9D9D25C16AE46F6C174945020BDD8F679024B6179462BE4A9AE648999D909432AB7EEEFCCD34790782D43D80F0713C51F74C9B41E55F6F10496AD18D6EBC85626F5236961643E90D0C9DFB9AC80B7BA9B69F35D7")
|
||||
assert.Nil(t, err)
|
||||
c := &Cipher{EncType: 1}
|
||||
c.C1.Unmarshal(b[:64])
|
||||
copy(c.H[:], b[64:96])
|
||||
c.C = append([]byte{}, b[96:]...)
|
||||
|
||||
plain, err := Decrypt(id, c, de)
|
||||
assert.Nil(t, err)
|
||||
|
||||
fmt.Printf("%x", plain)
|
||||
}
|
||||
|
||||
func TestEncryption2(t *testing.T) {
|
||||
id, err := hex.DecodeString("426f62")
|
||||
assert.Nil(t, err)
|
||||
de := new(UserEncKey)
|
||||
b, err := hex.DecodeString("94736acd2c8c8796cc4785e938301a139a059d3537b6414140b2d31eecf41683115bae85f5d8bc6c3dbd9e5342979acccf3c2f4f28420b1cb4f8c0b59a19b1587aa5e47570da7600cd760a0cf7beaf71c447f3844753fe74fa7ba92ca7d3b55f27538a62e7f7bfb51dce08704796d94c9d56734f119ea44732b50e31cdeb75c1")
|
||||
assert.Nil(t, err)
|
||||
de.Unmarshal(b)
|
||||
|
||||
b, err = hex.DecodeString("2445471164490618e1ee20528ff1d545b0f14c8bcaa44544f03dab5dac07d8ff42ffca97d57cddc05ea405f2e586feb3a6930715532b8000759f13059ed59ac0ba672387bcd6de5016a158a52bb2e7fc429197bcab70b25afee37a2b9db9f3671b5f5b0e951489682f3e64e1378cdd5da9513b1c")
|
||||
assert.Nil(t, err)
|
||||
c := &Cipher{EncType: 0}
|
||||
c.C1.Unmarshal(b[:64])
|
||||
copy(c.H[:], b[64:96])
|
||||
c.C = append([]byte{}, b[96:]...)
|
||||
|
||||
plain, err := Decrypt(id, c, de)
|
||||
assert.Nil(t, err)
|
||||
|
||||
fmt.Printf("%x", plain)
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package sm9
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
)
|
||||
|
||||
// dup duplicates a byte slice b.
|
||||
func dup(b []byte) []byte {
|
||||
ret := make([]byte, len(b))
|
||||
copy(ret, b)
|
||||
return ret
|
||||
}
|
||||
|
||||
// pairingThenMul computes e = e(p,q)^k
|
||||
func pairingThenMul(p *G1, q *G2, k *big.Int) *GT {
|
||||
e := Pairing(p, q)
|
||||
return e.ScalarMult(e, k)
|
||||
}
|
||||
|
||||
// mulG1ThenPairing computes e = e(p,q)^k = e(kp,q)
|
||||
func mulG1ThenPairing(p *G1, q *G2, k *big.Int) *GT {
|
||||
p1 := (&G1{}).ScalarMult(p, k)
|
||||
return Pairing(p1, q)
|
||||
}
|
||||
|
||||
// mulG2ThenPairing computes e = e(p,q)^k = e(p,kq)
|
||||
func mulG2ThenPairing(p *G1, q *G2, k *big.Int) *GT {
|
||||
q2 := (&G2{}).ScalarMult(q, k)
|
||||
return Pairing(p, q2)
|
||||
}
|
||||
|
||||
// mulG1BaseThenPairing computes e = e(p,q)^k = e(kp,q)
|
||||
func mulG1BaseThenPairing(e *GT, q *G2, k *big.Int) {
|
||||
p1 := (&G1{}).ScalarBaseMult(k)
|
||||
pairing(e, p1, q)
|
||||
}
|
||||
|
||||
// mulG2BaseThenPairing computes e = e(p,q)^k = e(kp,q)
|
||||
func mulG2BaseThenPairing(p *G1, k *big.Int) *GT {
|
||||
q2 := (&G2{}).ScalarBaseMult(k)
|
||||
return Pairing(p, q2)
|
||||
}
|
||||
Reference in New Issue
Block a user