@ -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 |
|||
} |
@ -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} |
|||
} |
@ -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())) |
|||
} |
@ -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, |
|||
} |
|||
} |
@ -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) |
|||
} |