diff --git a/README.md b/README.md index 425cd8e..b970b10 100644 --- a/README.md +++ b/README.md @@ -3,35 +3,43 @@ 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] Encrypt - [x] Decrypt - [x] Blind - [x] Blind Signature -- [x] Unblind Signature +- [x] Unblind Signature- RSA- RSA - [x] Verify Signature - [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] Encrypt - [x] Decrypt - [x] Homomorphic Addition ## 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] Lagrange Interpolation to restore the secret from the shares ## 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 ## ECC -https://en.wikipedia.org/wiki/Elliptic-curve_cryptography +- https://en.wikipedia.org/wiki/Elliptic-curve_cryptography + - [x] define elliptic curve - [x] get point at X - [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 ## ECC ElGamal -https://en.wikipedia.org/wiki/ElGamal_encryption +- https://en.wikipedia.org/wiki/ElGamal_encryption + - [x] ECC ElGamal key generation - [x] ECC ElGamal Encrypton - [x] ECC ElGamal Decryption ## 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] ECDSA Sign - [x] ECDSA Verify 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] Generate Schnorr scheme - [x] Sign @@ -68,8 +79,13 @@ This is implemented followng the implementations and info from: - `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 - `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] G1, G2 operations --- diff --git a/bn128/bn128.go b/bn128/bn128.go new file mode 100644 index 0000000..29ff08d --- /dev/null +++ b/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 +} diff --git a/bn128/fq.go b/bn128/fq.go index 630b56c..615122e 100644 --- a/bn128/fq.go +++ b/bn128/fq.go @@ -1,6 +1,7 @@ package bn128 import ( + "bytes" "math/big" ) @@ -56,6 +57,10 @@ func (fq Fq) Mul(a, b *big.Int) *big.Int { 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 func (fq Fq) Inverse(a *big.Int) *big.Int { 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) 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 +} diff --git a/bn128/fq12.go b/bn128/fq12.go index 80d6131..757cc5f 100644 --- a/bn128/fq12.go +++ b/bn128/fq12.go @@ -1,6 +1,7 @@ package bn128 import ( + "bytes" "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 func (fq12 Fq12) Inverse(a [2][3][2]*big.Int) [2][3][2]*big.Int { t0 := fq12.F.Square(a[0]) diff --git a/bn128/fq2.go b/bn128/fq2.go index 66d76a1..401bab5 100644 --- a/bn128/fq2.go +++ b/bn128/fq2.go @@ -1,6 +1,7 @@ package bn128 import ( + "bytes" "math/big" ) @@ -73,6 +74,21 @@ func (fq2 Fq2) Mul(a, b [2]*big.Int) [2]*big.Int { 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 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), } } + +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]), + } +} diff --git a/bn128/fq6.go b/bn128/fq6.go index 90e7b4a..ed0ac81 100644 --- a/bn128/fq6.go +++ b/bn128/fq6.go @@ -1,6 +1,7 @@ package bn128 import ( + "bytes" "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 func (fq6 Fq6) Sub(a, b [3][2]*big.Int) [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 func (fq6 Fq6) Inverse(a [3][2]*big.Int) [3][2]*big.Int { t0 := fq6.F.Square(a[0]) diff --git a/bn128/g1.go b/bn128/g1.go new file mode 100644 index 0000000..19442f5 --- /dev/null +++ b/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} +} diff --git a/bn128/g1_test.go b/bn128/g1_test.go new file mode 100644 index 0000000..8c9adbe --- /dev/null +++ b/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())) +} diff --git a/bn128/g2.go b/bn128/g2.go new file mode 100644 index 0000000..614fe72 --- /dev/null +++ b/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, + } +} diff --git a/bn128/g2_test.go b/bn128/g2_test.go new file mode 100644 index 0000000..8a65dc1 --- /dev/null +++ b/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) +}