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,
|
|
}
|
|
}
|