package bn128 import ( "errors" "math/big" "github.com/arnaucube/go-snark-study/fields" ) // Bn128 is the data structure of the BN128 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 fields.Fq Fq2 fields.Fq2 Fq6 fields.Fq6 Fq12 fields.Fq12 G1 G1 G2 G2 LoopCount *big.Int LoopCountNeg bool TwoInv *big.Int CoefB *big.Int TwistCoefB [2]*big.Int Twist [2]*big.Int FrobeniusCoeffsC11 *big.Int TwistMulByQX [2]*big.Int TwistMulByQY [2]*big.Int FinalExp *big.Int } // NewBn128 returns the BN128 func NewBn128() (Bn128, error) { var b Bn128 q, ok := new(big.Int).SetString("21888242871839275222246405745257275088696311157297823662689037894645226208583", 10) if !ok { return b, errors.New("err with q") } b.Q = q r, ok := new(big.Int).SetString("21888242871839275222246405745257275088548364400416034343698204186575808495617", 10) 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") } b.Gg2 = [2][2]*big.Int{ [2]*big.Int{ g2_00, g2_01, }, [2]*big.Int{ g2_10, g2_11, }, } b.Fq1 = fields.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 = fields.NewFq2(b.Fq1, b.NonResidueFq2) b.Fq6 = fields.NewFq6(b.Fq2, b.NonResidueFq6) b.Fq12 = fields.NewFq12(b.Fq6, b.Fq2, b.NonResidueFq6) b.G1 = NewG1(b.Fq1, b.Gg1) b.G2 = NewG2(b.Fq2, b.Gg2) err := b.preparePairing() if err != nil { return b, err } return b, nil } // NewFqR returns a new Finite Field over R func NewFqR() (fields.Fq, error) { r, ok := new(big.Int).SetString("21888242871839275222246405745257275088548364400416034343698204186575808495617", 10) if !ok { return fields.Fq{}, errors.New("err parsing R") } fqR := fields.NewFq(r) return fqR, nil } func (bn128 *Bn128) preparePairing() error { var ok bool bn128.LoopCount, ok = new(big.Int).SetString("29793968203157093288", 10) if !ok { return errors.New("err with LoopCount from string") } bn128.LoopCountNeg = false bn128.TwoInv = bn128.Fq1.Inverse(big.NewInt(int64(2))) bn128.CoefB = big.NewInt(int64(3)) bn128.Twist = [2]*big.Int{ big.NewInt(int64(9)), big.NewInt(int64(1)), } bn128.TwistCoefB = bn128.Fq2.MulScalar(bn128.Fq2.Inverse(bn128.Twist), bn128.CoefB) bn128.FrobeniusCoeffsC11, ok = new(big.Int).SetString("21888242871839275222246405745257275088696311157297823662689037894645226208582", 10) if !ok { return errors.New("error parsing frobeniusCoeffsC11") } a, ok := new(big.Int).SetString("21575463638280843010398324269430826099269044274347216827212613867836435027261", 10) if !ok { return errors.New("error parsing a") } b, ok := new(big.Int).SetString("10307601595873709700152284273816112264069230130616436755625194854815875713954", 10) if !ok { return errors.New("error parsing b") } bn128.TwistMulByQX = [2]*big.Int{ a, b, } a, ok = new(big.Int).SetString("2821565182194536844548159561693502659359617185244120367078079554186484126554", 10) if !ok { return errors.New("error parsing a") } b, ok = new(big.Int).SetString("3505843767911556378687030309984248845540243509899259641013678093033130930403", 10) if !ok { return errors.New("error parsing b") } bn128.TwistMulByQY = [2]*big.Int{ a, b, } bn128.FinalExp, ok = new(big.Int).SetString("552484233613224096312617126783173147097382103762957654188882734314196910839907541213974502761540629817009608548654680343627701153829446747810907373256841551006201639677726139946029199968412598804882391702273019083653272047566316584365559776493027495458238373902875937659943504873220554161550525926302303331747463515644711876653177129578303191095900909191624817826566688241804408081892785725967931714097716709526092261278071952560171111444072049229123565057483750161460024353346284167282452756217662335528813519139808291170539072125381230815729071544861602750936964829313608137325426383735122175229541155376346436093930287402089517426973178917569713384748081827255472576937471496195752727188261435633271238710131736096299798168852925540549342330775279877006784354801422249722573783561685179618816480037695005515426162362431072245638324744480", 10) if !ok { return errors.New("error parsing finalExp") } return nil } // Pairing calculates the BN128 Pairing of two given values func (bn128 Bn128) Pairing(p1 [3]*big.Int, p2 [3][2]*big.Int) [2][3][2]*big.Int { pre1 := bn128.preComputeG1(p1) pre2 := bn128.preComputeG2(p2) r1 := bn128.MillerLoop(pre1, pre2) res := bn128.finalExponentiation(r1) return res } type AteG1Precomp struct { Px *big.Int Py *big.Int } func (bn128 Bn128) preComputeG1(p [3]*big.Int) AteG1Precomp { pCopy := bn128.G1.Affine(p) res := AteG1Precomp{ Px: pCopy[0], Py: pCopy[1], } return res } type EllCoeffs struct { Ell0 [2]*big.Int EllVW [2]*big.Int EllVV [2]*big.Int } type AteG2Precomp struct { Qx [2]*big.Int Qy [2]*big.Int Coeffs []EllCoeffs } func (bn128 Bn128) preComputeG2(p [3][2]*big.Int) AteG2Precomp { qCopy := bn128.G2.Affine(p) res := AteG2Precomp{ qCopy[0], qCopy[1], []EllCoeffs{}, } r := [3][2]*big.Int{ bn128.Fq2.Copy(qCopy[0]), bn128.Fq2.Copy(qCopy[1]), bn128.Fq2.One(), } var c EllCoeffs for i := bn128.LoopCount.BitLen() - 2; i >= 0; i-- { bit := bn128.LoopCount.Bit(i) c, r = bn128.doublingStep(r) res.Coeffs = append(res.Coeffs, c) if bit == 1 { c, r = bn128.mixedAdditionStep(qCopy, r) res.Coeffs = append(res.Coeffs, c) } } q1 := bn128.G2.Affine(bn128.g2MulByQ(qCopy)) if !bn128.Fq2.Equal(q1[2], bn128.Fq2.One()) { // return res, errors.New("q1[2] != Fq2.One") panic(errors.New("q1[2] != Fq2.One()")) } q2 := bn128.G2.Affine(bn128.g2MulByQ(q1)) if !bn128.Fq2.Equal(q2[2], bn128.Fq2.One()) { // return res, errors.New("q2[2] != Fq2.One") panic(errors.New("q2[2] != Fq2.One()")) } if bn128.LoopCountNeg { r[1] = bn128.Fq2.Neg(r[1]) } q2[1] = bn128.Fq2.Neg(q2[1]) c, r = bn128.mixedAdditionStep(q1, r) res.Coeffs = append(res.Coeffs, c) c, r = bn128.mixedAdditionStep(q2, r) res.Coeffs = append(res.Coeffs, c) return res } func (bn128 Bn128) doublingStep(current [3][2]*big.Int) (EllCoeffs, [3][2]*big.Int) { x := current[0] y := current[1] z := current[2] a := bn128.Fq2.MulScalar(bn128.Fq2.Mul(x, y), bn128.TwoInv) b := bn128.Fq2.Square(y) c := bn128.Fq2.Square(z) d := bn128.Fq2.Add(c, bn128.Fq2.Add(c, c)) e := bn128.Fq2.Mul(bn128.TwistCoefB, d) f := bn128.Fq2.Add(e, bn128.Fq2.Add(e, e)) g := bn128.Fq2.MulScalar(bn128.Fq2.Add(b, f), bn128.TwoInv) h := bn128.Fq2.Sub( bn128.Fq2.Square(bn128.Fq2.Add(y, z)), bn128.Fq2.Add(b, c)) i := bn128.Fq2.Sub(e, b) j := bn128.Fq2.Square(x) eSqr := bn128.Fq2.Square(e) current[0] = bn128.Fq2.Mul(a, bn128.Fq2.Sub(b, f)) current[1] = bn128.Fq2.Sub(bn128.Fq2.Sub(bn128.Fq2.Square(g), eSqr), bn128.Fq2.Add(eSqr, eSqr)) current[2] = bn128.Fq2.Mul(b, h) res := EllCoeffs{ Ell0: bn128.Fq2.Mul(i, bn128.Twist), EllVW: bn128.Fq2.Neg(h), EllVV: bn128.Fq2.Add(j, bn128.Fq2.Add(j, j)), } return res, current } func (bn128 Bn128) mixedAdditionStep(base, current [3][2]*big.Int) (EllCoeffs, [3][2]*big.Int) { x1 := current[0] y1 := current[1] z1 := current[2] x2 := base[0] y2 := base[1] d := bn128.Fq2.Sub(x1, bn128.Fq2.Mul(x2, z1)) e := bn128.Fq2.Sub(y1, bn128.Fq2.Mul(y2, z1)) f := bn128.Fq2.Square(d) g := bn128.Fq2.Square(e) h := bn128.Fq2.Mul(d, f) i := bn128.Fq2.Mul(x1, f) j := bn128.Fq2.Sub( bn128.Fq2.Add(h, bn128.Fq2.Mul(z1, g)), bn128.Fq2.Add(i, i)) current[0] = bn128.Fq2.Mul(d, j) current[1] = bn128.Fq2.Sub( bn128.Fq2.Mul(e, bn128.Fq2.Sub(i, j)), bn128.Fq2.Mul(h, y1)) current[2] = bn128.Fq2.Mul(z1, h) coef := EllCoeffs{ Ell0: bn128.Fq2.Mul( bn128.Twist, bn128.Fq2.Sub( bn128.Fq2.Mul(e, x2), bn128.Fq2.Mul(d, y2))), EllVW: d, EllVV: bn128.Fq2.Neg(e), } return coef, current } func (bn128 Bn128) g2MulByQ(p [3][2]*big.Int) [3][2]*big.Int { fmx := [2]*big.Int{ p[0][0], bn128.Fq1.Mul(p[0][1], bn128.Fq1.Copy(bn128.FrobeniusCoeffsC11)), } fmy := [2]*big.Int{ p[1][0], bn128.Fq1.Mul(p[1][1], bn128.Fq1.Copy(bn128.FrobeniusCoeffsC11)), } fmz := [2]*big.Int{ p[2][0], bn128.Fq1.Mul(p[2][1], bn128.Fq1.Copy(bn128.FrobeniusCoeffsC11)), } return [3][2]*big.Int{ bn128.Fq2.Mul(bn128.TwistMulByQX, fmx), bn128.Fq2.Mul(bn128.TwistMulByQY, fmy), fmz, } } func (bn128 Bn128) MillerLoop(pre1 AteG1Precomp, pre2 AteG2Precomp) [2][3][2]*big.Int { // https://cryptojedi.org/papers/dclxvi-20100714.pdf // https://eprint.iacr.org/2008/096.pdf idx := 0 var c EllCoeffs f := bn128.Fq12.One() for i := bn128.LoopCount.BitLen() - 2; i >= 0; i-- { bit := bn128.LoopCount.Bit(i) c = pre2.Coeffs[idx] idx++ f = bn128.Fq12.Square(f) f = bn128.mulBy024(f, c.Ell0, bn128.Fq2.MulScalar(c.EllVW, pre1.Py), bn128.Fq2.MulScalar(c.EllVV, pre1.Px)) if bit == 1 { c = pre2.Coeffs[idx] idx++ f = bn128.mulBy024( f, c.Ell0, bn128.Fq2.MulScalar(c.EllVW, pre1.Py), bn128.Fq2.MulScalar(c.EllVV, pre1.Px)) } } if bn128.LoopCountNeg { f = bn128.Fq12.Inverse(f) } c = pre2.Coeffs[idx] idx++ f = bn128.mulBy024( f, c.Ell0, bn128.Fq2.MulScalar(c.EllVW, pre1.Py), bn128.Fq2.MulScalar(c.EllVV, pre1.Px)) c = pre2.Coeffs[idx] idx++ f = bn128.mulBy024( f, c.Ell0, bn128.Fq2.MulScalar(c.EllVW, pre1.Py), bn128.Fq2.MulScalar(c.EllVV, pre1.Px)) return f } func (bn128 Bn128) mulBy024(a [2][3][2]*big.Int, ell0, ellVW, ellVV [2]*big.Int) [2][3][2]*big.Int { b := [2][3][2]*big.Int{ [3][2]*big.Int{ ell0, bn128.Fq2.Zero(), ellVV, }, [3][2]*big.Int{ bn128.Fq2.Zero(), ellVW, bn128.Fq2.Zero(), }, } return bn128.Fq12.Mul(a, b) } func (bn128 Bn128) finalExponentiation(r [2][3][2]*big.Int) [2][3][2]*big.Int { res := bn128.Fq12.Exp(r, bn128.FinalExp) return res }