Browse Source

bn128 G1 and G2 operations

master
arnaucube 6 years ago
parent
commit
3d67f7912e
10 changed files with 597 additions and 11 deletions
  1. +27
    -11
      README.md
  2. +88
    -0
      bn128/bn128.go
  3. +17
    -0
      bn128/fq.go
  4. +17
    -0
      bn128/fq12.go
  5. +27
    -0
      bn128/fq2.go
  6. +21
    -0
      bn128/fq6.go
  7. +169
    -0
      bn128/g1.go
  8. +30
    -0
      bn128/g1_test.go
  9. +174
    -0
      bn128/g2.go
  10. +27
    -0
      bn128/g2_test.go

+ 27
- 11
README.md

@ -3,35 +3,43 @@
Crypto algorithms from scratch. Academic purposes only. Crypto algorithms from scratch. Academic purposes only.
## RSA
https://en.wikipedia.org/wiki/RSA_(cryptosystem)#
## RSA cryptosystem & Blind signature & Homomorphic Multiplication
- https://en.wikipedia.org/wiki/RSA_(cryptosystem)#
- https://en.wikipedia.org/wiki/Blind_signature
- https://en.wikipedia.org/wiki/Homomorphic_encryption
- [x] GenerateKeyPair - [x] GenerateKeyPair
- [x] Encrypt - [x] Encrypt
- [x] Decrypt - [x] Decrypt
- [x] Blind - [x] Blind
- [x] Blind Signature - [x] Blind Signature
- [x] Unblind Signature
- [x] Unblind Signature- RSA- RSA
- [x] Verify Signature - [x] Verify Signature
- [x] Homomorphic Multiplication - [x] Homomorphic Multiplication
## Paillier
https://en.wikipedia.org/wiki/Paillier_cryptosystem
## Paillier cryptosystem & Homomorphic Addition
- https://en.wikipedia.org/wiki/Paillier_cryptosystem
- https://en.wikipedia.org/wiki/Homomorphic_encryption
- [x] GenerateKeyPair - [x] GenerateKeyPair
- [x] Encrypt - [x] Encrypt
- [x] Decrypt - [x] Decrypt
- [x] Homomorphic Addition - [x] Homomorphic Addition
## Shamir Secret Sharing ## Shamir Secret Sharing
https://en.wikipedia.org/wiki/Shamir%27s_Secret_Sharing
- https://en.wikipedia.org/wiki/Shamir%27s_Secret_Sharing
- [x] create secret sharing from number of secrets needed, number of shares, random point p, secret to share - [x] create secret sharing from number of secrets needed, number of shares, random point p, secret to share
- [x] Lagrange Interpolation to restore the secret from the shares - [x] Lagrange Interpolation to restore the secret from the shares
## Diffie-Hellman ## Diffie-Hellman
https://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange
- https://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange
- [x] key exchange - [x] key exchange
## ECC ## ECC
https://en.wikipedia.org/wiki/Elliptic-curve_cryptography
- https://en.wikipedia.org/wiki/Elliptic-curve_cryptography
- [x] define elliptic curve - [x] define elliptic curve
- [x] get point at X - [x] get point at X
- [x] get order of a Point on the elliptic curve - [x] get order of a Point on the elliptic curve
@ -39,20 +47,23 @@ https://en.wikipedia.org/wiki/Elliptic-curve_cryptography
- [x] Multiply a point n times on the elliptic curve - [x] Multiply a point n times on the elliptic curve
## ECC ElGamal ## ECC ElGamal
https://en.wikipedia.org/wiki/ElGamal_encryption
- https://en.wikipedia.org/wiki/ElGamal_encryption
- [x] ECC ElGamal key generation - [x] ECC ElGamal key generation
- [x] ECC ElGamal Encrypton - [x] ECC ElGamal Encrypton
- [x] ECC ElGamal Decryption - [x] ECC ElGamal Decryption
## ECC ECDSA ## ECC ECDSA
https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm
- https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm
- [x] define ECDSA data structure - [x] define ECDSA data structure
- [x] ECDSA Sign - [x] ECDSA Sign
- [x] ECDSA Verify signature - [x] ECDSA Verify signature
## Schnorr signature ## Schnorr signature
https://en.wikipedia.org/wiki/Schnorr_signature
- https://en.wikipedia.org/wiki/Schnorr_signature
- [x] Hash[M || R] (where M is the msg bytes and R is a Point on the ECC, using sha256 hash function) - [x] Hash[M || R] (where M is the msg bytes and R is a Point on the ECC, using sha256 hash function)
- [x] Generate Schnorr scheme - [x] Generate Schnorr scheme
- [x] Sign - [x] Sign
@ -68,8 +79,13 @@ This is implemented followng the implementations and info from:
- `Multiplication and Squaring on Pairing-Friendly - `Multiplication and Squaring on Pairing-Friendly
Fields`, Augusto Jun Devegili, Colm Ó hÉigeartaigh, Michael Scott, and Ricardo Dahab https://pdfs.semanticscholar.org/3e01/de88d7428076b2547b60072088507d881bf1.pdf Fields`, Augusto Jun Devegili, Colm Ó hÉigeartaigh, Michael Scott, and Ricardo Dahab https://pdfs.semanticscholar.org/3e01/de88d7428076b2547b60072088507d881bf1.pdf
- `Optimal Pairings`, Frederik Vercauteren https://www.cosic.esat.kuleuven.be/bcrypt/optimal.pdf - `Optimal Pairings`, Frederik Vercauteren https://www.cosic.esat.kuleuven.be/bcrypt/optimal.pdf
- `Double-and-Add with Relative Jacobian
Coordinates`, Björn Fay https://eprint.iacr.org/2014/1014.pdf
- `Fast and Regular Algorithms for Scalar Multiplication
over Elliptic Curves`, Matthieu Rivain https://eprint.iacr.org/2011/338.pdf
- [x] Fq, Fq2, Fq6, Fq12 operations - [x] Fq, Fq2, Fq6, Fq12 operations
- [x] G1, G2 operations
--- ---

+ 88
- 0
bn128/bn128.go

@ -0,0 +1,88 @@
package bn128
import (
"errors"
"math/big"
)
type Bn128 struct {
Q *big.Int
R *big.Int
Gg1 [2]*big.Int
Gg2 [2][2]*big.Int
NonResidueFq2 *big.Int
NonResidueFq6 [2]*big.Int
Fq1 Fq
Fq2 Fq2
Fq6 Fq6
Fq12 Fq12
G1 G1
G2 G2
}
func NewBn128() (Bn128, error) {
var b Bn128
q, ok := new(big.Int).SetString("21888242871839275222246405745257275088696311157297823662689037894645226208583", 10) // i
if !ok {
return b, errors.New("err with q")
}
b.Q = q
r, ok := new(big.Int).SetString("21888242871839275222246405745257275088548364400416034343698204186575808495617", 10) // i
if !ok {
return b, errors.New("err with r")
}
b.R = r
b.Gg1 = [2]*big.Int{
big.NewInt(int64(1)),
big.NewInt(int64(2)),
}
g2_00, ok := new(big.Int).SetString("10857046999023057135944570762232829481370756359578518086990519993285655852781", 10)
if !ok {
return b, errors.New("err with g2_00")
}
g2_01, ok := new(big.Int).SetString("11559732032986387107991004021392285783925812861821192530917403151452391805634", 10)
if !ok {
return b, errors.New("err with g2_00")
}
g2_10, ok := new(big.Int).SetString("8495653923123431417604973247489272438418190587263600148770280649306958101930", 10)
if !ok {
return b, errors.New("err with g2_00")
}
g2_11, ok := new(big.Int).SetString("4082367875863433681332203403145435568316851327593401208105741076214120093531", 10)
if !ok {
return b, errors.New("err with g2_00")
}
g2_0 := [2]*big.Int{
g2_00,
g2_01,
}
g2_1 := [2]*big.Int{
g2_10,
g2_11,
}
b.Gg2 = [2][2]*big.Int{
g2_0,
g2_1,
}
b.Fq1 = NewFq(q)
b.NonResidueFq2, ok = new(big.Int).SetString("21888242871839275222246405745257275088696311157297823662689037894645226208582", 10) // i
if !ok {
return b, errors.New("err with nonResidueFq2")
}
b.NonResidueFq6 = [2]*big.Int{
big.NewInt(int64(9)),
big.NewInt(int64(1)),
}
b.Fq2 = Fq2{b.Fq1, b.NonResidueFq2}
b.Fq6 = Fq6{b.Fq2, b.NonResidueFq6}
b.Fq12 = Fq12{b.Fq6, b.Fq2, b.NonResidueFq6}
b.G1 = NewG1(b.Fq1, b.Gg1)
b.G2 = NewG2(b.Fq2, b.Gg2)
return b, nil
}

+ 17
- 0
bn128/fq.go

@ -1,6 +1,7 @@
package bn128 package bn128
import ( import (
"bytes"
"math/big" "math/big"
) )
@ -56,6 +57,10 @@ func (fq Fq) Mul(a, b *big.Int) *big.Int {
return new(big.Int).Mod(m, fq.Q) return new(big.Int).Mod(m, fq.Q)
} }
func (fq Fq) MulScalar(base, e *big.Int) *big.Int {
return fq.Mul(base, e)
}
// Inverse returns the inverse on the Fq // Inverse returns the inverse on the Fq
func (fq Fq) Inverse(a *big.Int) *big.Int { func (fq Fq) Inverse(a *big.Int) *big.Int {
return new(big.Int).ModInverse(a, fq.Q) return new(big.Int).ModInverse(a, fq.Q)
@ -72,3 +77,15 @@ func (fq Fq) Square(a *big.Int) *big.Int {
m := new(big.Int).Mul(a, a) m := new(big.Int).Mul(a, a)
return new(big.Int).Mod(m, fq.Q) return new(big.Int).Mod(m, fq.Q)
} }
func (fq Fq) IsZero(a *big.Int) bool {
return bytes.Equal(a.Bytes(), fq.Zero().Bytes())
}
func (fq Fq) Copy(a *big.Int) *big.Int {
return new(big.Int).SetBytes(a.Bytes())
}
func (fq Fq) Affine(a *big.Int) *big.Int {
return a
}

+ 17
- 0
bn128/fq12.go

@ -1,6 +1,7 @@
package bn128 package bn128
import ( import (
"bytes"
"math/big" "math/big"
) )
@ -82,6 +83,22 @@ func (fq12 Fq12) Mul(a, b [2][3][2]*big.Int) [2][3][2]*big.Int {
} }
} }
func (fq12 Fq12) MulScalar(base [2][3][2]*big.Int, e *big.Int) [2][3][2]*big.Int {
res := fq12.Zero()
rem := e
exp := base
for !bytes.Equal(rem.Bytes(), big.NewInt(int64(0)).Bytes()) {
// if rem % 2 == 1
if bytes.Equal(new(big.Int).Rem(rem, big.NewInt(int64(2))).Bytes(), big.NewInt(int64(1)).Bytes()) {
res = fq12.Add(res, exp)
}
exp = fq12.Double(exp)
rem = rem.Rsh(rem, 1) // rem = rem >> 1
}
return res
}
// Inverse returns the inverse on the Fq12 // Inverse returns the inverse on the Fq12
func (fq12 Fq12) Inverse(a [2][3][2]*big.Int) [2][3][2]*big.Int { func (fq12 Fq12) Inverse(a [2][3][2]*big.Int) [2][3][2]*big.Int {
t0 := fq12.F.Square(a[0]) t0 := fq12.F.Square(a[0])

+ 27
- 0
bn128/fq2.go

@ -1,6 +1,7 @@
package bn128 package bn128
import ( import (
"bytes"
"math/big" "math/big"
) )
@ -73,6 +74,21 @@ func (fq2 Fq2) Mul(a, b [2]*big.Int) [2]*big.Int {
fq2.F.Add(v0, v1)), fq2.F.Add(v0, v1)),
} }
} }
func (fq2 Fq2) MulScalar(base [2]*big.Int, e *big.Int) [2]*big.Int {
res := fq2.Zero()
rem := e
exp := base
for !bytes.Equal(rem.Bytes(), big.NewInt(int64(0)).Bytes()) {
// if rem % 2 == 1
if bytes.Equal(new(big.Int).Rem(rem, big.NewInt(int64(2))).Bytes(), big.NewInt(int64(1)).Bytes()) {
res = fq2.Add(res, exp)
}
exp = fq2.Double(exp)
rem = rem.Rsh(rem, 1) // rem = rem >> 1
}
return res
}
// Inverse returns the inverse on the Fq2 // Inverse returns the inverse on the Fq2
func (fq2 Fq2) Inverse(a [2]*big.Int) [2]*big.Int { func (fq2 Fq2) Inverse(a [2]*big.Int) [2]*big.Int {
@ -108,3 +124,14 @@ func (fq2 Fq2) Square(a [2]*big.Int) [2]*big.Int {
fq2.F.Add(ab, ab), fq2.F.Add(ab, ab),
} }
} }
func (fq2 Fq2) IsZero(a [2]*big.Int) bool {
return fq2.F.IsZero(a[0]) && fq2.F.IsZero(a[1])
}
func (fq2 Fq2) Affine(a [2]*big.Int) [2]*big.Int {
return [2]*big.Int{
fq2.F.Affine(a[0]),
fq2.F.Affine(a[1]),
}
}

+ 21
- 0
bn128/fq6.go

@ -1,6 +1,7 @@
package bn128 package bn128
import ( import (
"bytes"
"math/big" "math/big"
) )
@ -42,6 +43,10 @@ func (fq6 Fq6) Add(a, b [3][2]*big.Int) [3][2]*big.Int {
} }
} }
func (fq6 Fq6) Double(a [3][2]*big.Int) [3][2]*big.Int {
return fq6.Add(a, a)
}
// Sub performs a substraction on the Fq6 // Sub performs a substraction on the Fq6
func (fq6 Fq6) Sub(a, b [3][2]*big.Int) [3][2]*big.Int { func (fq6 Fq6) Sub(a, b [3][2]*big.Int) [3][2]*big.Int {
return [3][2]*big.Int{ return [3][2]*big.Int{
@ -89,6 +94,22 @@ func (fq6 Fq6) Mul(a, b [3][2]*big.Int) [3][2]*big.Int {
} }
} }
func (fq6 Fq6) MulScalar(base [3][2]*big.Int, e *big.Int) [3][2]*big.Int {
res := fq6.Zero()
rem := e
exp := base
for !bytes.Equal(rem.Bytes(), big.NewInt(int64(0)).Bytes()) {
// if rem % 2 == 1
if bytes.Equal(new(big.Int).Rem(rem, big.NewInt(int64(2))).Bytes(), big.NewInt(int64(1)).Bytes()) {
res = fq6.Add(res, exp)
}
exp = fq6.Double(exp)
rem = rem.Rsh(rem, 1) // rem = rem >> 1
}
return res
}
// Inverse returns the inverse on the Fq6 // Inverse returns the inverse on the Fq6
func (fq6 Fq6) Inverse(a [3][2]*big.Int) [3][2]*big.Int { func (fq6 Fq6) Inverse(a [3][2]*big.Int) [3][2]*big.Int {
t0 := fq6.F.Square(a[0]) t0 := fq6.F.Square(a[0])

+ 169
- 0
bn128/g1.go

@ -0,0 +1,169 @@
package bn128
import (
"bytes"
"math/big"
)
type G1 struct {
F Fq
G [3]*big.Int
}
func NewG1(f Fq, g [2]*big.Int) G1 {
var g1 G1
g1.F = f
g1.G = [3]*big.Int{
g[0],
g[1],
g1.F.One(),
}
return g1
}
func (g1 G1) Zero() [2]*big.Int {
return [2]*big.Int{g1.F.Zero(), g1.F.Zero()}
}
func (g1 G1) IsZero(p [3]*big.Int) bool {
return g1.F.IsZero(p[2])
}
func (g1 G1) Add(p1, p2 [3]*big.Int) [3]*big.Int {
// https://en.wikibooks.org/wiki/Cryptography/Prime_Curve/Jacobian_Coordinates
// https://github.com/zcash/zcash/blob/master/src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_g1.cpp#L208
// http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/addition/add-2007-bl.op3
if g1.IsZero(p1) {
return p2
}
if g1.IsZero(p2) {
return p1
}
x1 := p1[0]
y1 := p1[1]
z1 := p1[2]
x2 := p2[0]
y2 := p2[1]
z2 := p2[2]
z1z1 := g1.F.Square(z1)
z2z2 := g1.F.Square(z2)
u1 := g1.F.Mul(x1, z2z2)
u2 := g1.F.Mul(x2, z1z1)
t0 := g1.F.Mul(z2, z2z2)
s1 := g1.F.Mul(y1, t0)
t1 := g1.F.Mul(z1, z1z1)
s2 := g1.F.Mul(y2, t1)
h := g1.F.Sub(u2, u1)
t2 := g1.F.Add(h, h)
i := g1.F.Square(t2)
j := g1.F.Mul(h, i)
t3 := g1.F.Sub(s2, s1)
r := g1.F.Add(t3, t3)
v := g1.F.Mul(u1, i)
t4 := g1.F.Square(r)
t5 := g1.F.Add(v, v)
t6 := g1.F.Sub(t4, j)
x3 := g1.F.Sub(t6, t5)
t7 := g1.F.Sub(v, x3)
t8 := g1.F.Mul(s1, j)
t9 := g1.F.Add(t8, t8)
t10 := g1.F.Mul(r, t7)
y3 := g1.F.Sub(t10, t9)
t11 := g1.F.Add(z1, z2)
t12 := g1.F.Square(t11)
t13 := g1.F.Sub(t12, z1z1)
t14 := g1.F.Sub(t13, z2z2)
z3 := g1.F.Mul(t14, h)
return [3]*big.Int{x3, y3, z3}
}
func (g1 G1) Neg(p [3]*big.Int) [3]*big.Int {
return [3]*big.Int{
p[0],
g1.F.Neg(p[1]),
p[2],
}
}
func (g1 G1) Sub(a, b [3]*big.Int) [3]*big.Int {
return g1.Add(a, g1.Neg(b))
}
func (g1 G1) Double(p [3]*big.Int) [3]*big.Int {
// https://en.wikibooks.org/wiki/Cryptography/Prime_Curve/Jacobian_Coordinates
// http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/doubling/dbl-2009-l.op3
// https://github.com/zcash/zcash/blob/master/src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_g1.cpp#L325
if g1.IsZero(p) {
return p
}
a := g1.F.Square(p[0])
b := g1.F.Square(p[1])
c := g1.F.Square(b)
t0 := g1.F.Add(p[0], b)
t1 := g1.F.Square(t0)
t2 := g1.F.Sub(t1, a)
t3 := g1.F.Sub(t2, c)
d := g1.F.Double(t3)
e := g1.F.Add(g1.F.Add(a, a), a) // e = 3*a
f := g1.F.Square(e)
t4 := g1.F.Double(d)
x3 := g1.F.Sub(f, t4)
t5 := g1.F.Sub(d, x3)
twoC := g1.F.Add(c, c)
fourC := g1.F.Add(twoC, twoC)
t6 := g1.F.Add(fourC, fourC)
t7 := g1.F.Mul(e, t5)
y3 := g1.F.Sub(t7, t6)
t8 := g1.F.Mul(p[1], p[2])
z3 := g1.F.Double(t8)
return [3]*big.Int{x3, y3, z3}
}
func (g1 G1) MulScalar(base [3]*big.Int, e *big.Int) [3]*big.Int {
// res := g1.Zero()
res := [3]*big.Int{g1.F.Zero(), g1.F.Zero(), g1.F.Zero()}
rem := e
exp := base
for !bytes.Equal(rem.Bytes(), big.NewInt(int64(0)).Bytes()) {
// if rem % 2 == 1
if bytes.Equal(new(big.Int).Rem(rem, big.NewInt(int64(2))).Bytes(), big.NewInt(int64(1)).Bytes()) {
res = g1.Add(res, exp)
}
exp = g1.Double(exp)
rem = rem.Rsh(rem, 1) // rem = rem >> 1
}
return res
}
func (g1 G1) Affine(p [3]*big.Int) [2]*big.Int {
if g1.IsZero(p) {
return g1.Zero()
}
zinv := g1.F.Inverse(p[2])
zinv2 := g1.F.Square(zinv)
x := g1.F.Mul(p[0], zinv2)
zinv3 := g1.F.Mul(zinv2, zinv)
y := g1.F.Mul(p[1], zinv3)
return [2]*big.Int{x, y}
}

+ 30
- 0
bn128/g1_test.go

@ -0,0 +1,30 @@
package bn128
import (
"math/big"
"testing"
"github.com/arnaucube/cryptofun/utils"
"github.com/stretchr/testify/assert"
)
func TestG1(t *testing.T) {
bn128, err := NewBn128()
assert.Nil(t, err)
r1 := big.NewInt(int64(33))
r2 := big.NewInt(int64(44))
gr1 := bn128.G1.MulScalar(bn128.G1.G, bn128.Fq1.Copy(r1))
gr2 := bn128.G1.MulScalar(bn128.G1.G, bn128.Fq1.Copy(r2))
grsum1 := bn128.G1.Add(gr1, gr2)
r1r2 := bn128.Fq1.Add(r1, r2)
grsum2 := bn128.G1.MulScalar(bn128.G1.G, r1r2)
a := bn128.G1.Affine(grsum1)
b := bn128.G1.Affine(grsum2)
assert.Equal(t, a, b)
assert.Equal(t, "0x2f978c0ab89ebaa576866706b14787f360c4d6c3869efe5a72f7c3651a72ff00", utils.BytesToHex(a[0].Bytes()))
assert.Equal(t, "0x12e4ba7f0edca8b4fa668fe153aebd908d322dc26ad964d4cd314795844b62b2", utils.BytesToHex(a[1].Bytes()))
}

+ 174
- 0
bn128/g2.go

@ -0,0 +1,174 @@
package bn128
import (
"bytes"
"math/big"
)
type G2 struct {
F Fq2
G [3][2]*big.Int
}
func NewG2(f Fq2, g [2][2]*big.Int) G2 {
var g2 G2
g2.F = f
g2.G = [3][2]*big.Int{
g[0],
g[1],
g2.F.One(),
}
return g2
}
func (g2 G2) Zero() [2][2]*big.Int {
return [2][2]*big.Int{g2.F.Zero(), g2.F.Zero()}
}
func (g2 G2) IsZero(p [3][2]*big.Int) bool {
return g2.F.IsZero(p[2])
}
func (g2 G2) Add(p1, p2 [3][2]*big.Int) [3][2]*big.Int {
// https://en.wikibooks.org/wiki/Cryptography/Prime_Curve/Jacobian_Coordinates
// https://github.com/zcash/zcash/blob/master/src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_g2.cpp#L208
// http://hyperelliptic.org/EFD/g2p/auto-code/shortw/jacobian-0/addition/add-2007-bl.op3
if g2.IsZero(p1) {
return p2
}
if g2.IsZero(p2) {
return p1
}
x1 := p1[0]
y1 := p1[1]
z1 := p1[2]
x2 := p2[0]
y2 := p2[1]
z2 := p2[2]
z1z1 := g2.F.Square(z1)
z2z2 := g2.F.Square(z2)
u1 := g2.F.Mul(x1, z2z2)
u2 := g2.F.Mul(x2, z1z1)
t0 := g2.F.Mul(z2, z2z2)
s1 := g2.F.Mul(y1, t0)
t1 := g2.F.Mul(z1, z1z1)
s2 := g2.F.Mul(y2, t1)
h := g2.F.Sub(u2, u1)
t2 := g2.F.Add(h, h)
i := g2.F.Square(t2)
j := g2.F.Mul(h, i)
t3 := g2.F.Sub(s2, s1)
r := g2.F.Add(t3, t3)
v := g2.F.Mul(u1, i)
t4 := g2.F.Square(r)
t5 := g2.F.Add(v, v)
t6 := g2.F.Sub(t4, j)
x3 := g2.F.Sub(t6, t5)
t7 := g2.F.Sub(v, x3)
t8 := g2.F.Mul(s1, j)
t9 := g2.F.Add(t8, t8)
t10 := g2.F.Mul(r, t7)
y3 := g2.F.Sub(t10, t9)
t11 := g2.F.Add(z1, z2)
t12 := g2.F.Square(t11)
t13 := g2.F.Sub(t12, z1z1)
t14 := g2.F.Sub(t13, z2z2)
z3 := g2.F.Mul(t14, h)
return [3][2]*big.Int{x3, y3, z3}
}
func (g2 G2) Neg(p [3][2]*big.Int) [3][2]*big.Int {
return [3][2]*big.Int{
p[0],
g2.F.Neg(p[1]),
p[2],
}
}
func (g2 G2) Sub(a, b [3][2]*big.Int) [3][2]*big.Int {
return g2.Add(a, g2.Neg(b))
}
func (g2 G2) Double(p [3][2]*big.Int) [3][2]*big.Int {
// https://en.wikibooks.org/wiki/Cryptography/Prime_Curve/Jacobian_Coordinates
// http://hyperelliptic.org/EFD/g2p/auto-code/shortw/jacobian-0/doubling/dbl-2009-l.op3
// https://github.com/zcash/zcash/blob/master/src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_g2.cpp#L325
if g2.IsZero(p) {
return p
}
a := g2.F.Square(p[0])
b := g2.F.Square(p[1])
c := g2.F.Square(b)
t0 := g2.F.Add(p[0], b)
t1 := g2.F.Square(t0)
t2 := g2.F.Sub(t1, a)
t3 := g2.F.Sub(t2, c)
d := g2.F.Double(t3)
e := g2.F.Add(g2.F.Add(a, a), a) // e = 3*a
f := g2.F.Square(e)
t4 := g2.F.Double(d)
x3 := g2.F.Sub(f, t4)
t5 := g2.F.Sub(d, x3)
twoC := g2.F.Add(c, c)
fourC := g2.F.Add(twoC, twoC)
t6 := g2.F.Add(fourC, fourC)
t7 := g2.F.Mul(e, t5)
y3 := g2.F.Sub(t7, t6)
t8 := g2.F.Mul(p[1], p[2])
z3 := g2.F.Double(t8)
return [3][2]*big.Int{x3, y3, z3}
}
func (g2 G2) MulScalar(base [3][2]*big.Int, e *big.Int) [3][2]*big.Int {
// res := g2.Zero()
res := [3][2]*big.Int{g2.F.Zero(), g2.F.Zero(), g2.F.Zero()}
rem := e
exp := base
for !bytes.Equal(rem.Bytes(), big.NewInt(int64(0)).Bytes()) {
// if rem % 2 == 1
if bytes.Equal(new(big.Int).Rem(rem, big.NewInt(int64(2))).Bytes(), big.NewInt(int64(1)).Bytes()) {
res = g2.Add(res, exp)
}
exp = g2.Double(exp)
rem = rem.Rsh(rem, 1) // rem = rem >> 1
}
return res
}
func (g2 G2) Affine(p [3][2]*big.Int) [2][2]*big.Int {
if g2.IsZero(p) {
return g2.Zero()
}
zinv := g2.F.Inverse(p[2])
zinv2 := g2.F.Square(zinv)
x := g2.F.Mul(p[0], zinv2)
zinv3 := g2.F.Mul(zinv2, zinv)
y := g2.F.Mul(p[1], zinv3)
return [2][2]*big.Int{
x,
y,
}
}

+ 27
- 0
bn128/g2_test.go

@ -0,0 +1,27 @@
package bn128
import (
"math/big"
"testing"
"github.com/stretchr/testify/assert"
)
func TestG2(t *testing.T) {
bn128, err := NewBn128()
assert.Nil(t, err)
r1 := big.NewInt(int64(33))
r2 := big.NewInt(int64(44))
gr1 := bn128.G2.MulScalar(bn128.G2.G, bn128.Fq1.Copy(r1))
gr2 := bn128.G2.MulScalar(bn128.G2.G, bn128.Fq1.Copy(r2))
grsum1 := bn128.G2.Add(gr1, gr2)
r1r2 := bn128.Fq1.Add(r1, r2)
grsum2 := bn128.G2.MulScalar(bn128.G2.G, r1r2)
a := bn128.G2.Affine(grsum1)
b := bn128.G2.Affine(grsum2)
assert.Equal(t, a, b)
}

Loading…
Cancel
Save