github.com/nova-foundation/go-ethereum@v1.0.1/crypto/bls12381/pairing.go (about) 1 // Copyright 2020 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package bls12381 18 19 type pair struct { 20 g1 *PointG1 21 g2 *PointG2 22 } 23 24 func newPair(g1 *PointG1, g2 *PointG2) pair { 25 return pair{g1, g2} 26 } 27 28 // Engine is BLS12-381 elliptic curve pairing engine 29 type Engine struct { 30 G1 *G1 31 G2 *G2 32 fp12 *fp12 33 fp2 *fp2 34 pairingEngineTemp 35 pairs []pair 36 } 37 38 // NewPairingEngine creates new pairing engine instance. 39 func NewPairingEngine() *Engine { 40 fp2 := newFp2() 41 fp6 := newFp6(fp2) 42 fp12 := newFp12(fp6) 43 g1 := NewG1() 44 g2 := newG2(fp2) 45 return &Engine{ 46 fp2: fp2, 47 fp12: fp12, 48 G1: g1, 49 G2: g2, 50 pairingEngineTemp: newEngineTemp(), 51 } 52 } 53 54 type pairingEngineTemp struct { 55 t2 [10]*fe2 56 t12 [9]fe12 57 } 58 59 func newEngineTemp() pairingEngineTemp { 60 t2 := [10]*fe2{} 61 for i := 0; i < 10; i++ { 62 t2[i] = &fe2{} 63 } 64 t12 := [9]fe12{} 65 return pairingEngineTemp{t2, t12} 66 } 67 68 // AddPair adds a g1, g2 point pair to pairing engine 69 func (e *Engine) AddPair(g1 *PointG1, g2 *PointG2) *Engine { 70 p := newPair(g1, g2) 71 if !e.isZero(p) { 72 e.affine(p) 73 e.pairs = append(e.pairs, p) 74 } 75 return e 76 } 77 78 // AddPairInv adds a G1, G2 point pair to pairing engine. G1 point is negated. 79 func (e *Engine) AddPairInv(g1 *PointG1, g2 *PointG2) *Engine { 80 e.G1.Neg(g1, g1) 81 e.AddPair(g1, g2) 82 return e 83 } 84 85 // Reset deletes added pairs. 86 func (e *Engine) Reset() *Engine { 87 e.pairs = []pair{} 88 return e 89 } 90 91 func (e *Engine) isZero(p pair) bool { 92 return e.G1.IsZero(p.g1) || e.G2.IsZero(p.g2) 93 } 94 95 func (e *Engine) affine(p pair) { 96 e.G1.Affine(p.g1) 97 e.G2.Affine(p.g2) 98 } 99 100 func (e *Engine) doublingStep(coeff *[3]fe2, r *PointG2) { 101 // Adaptation of Formula 3 in https://eprint.iacr.org/2010/526.pdf 102 fp2 := e.fp2 103 t := e.t2 104 fp2.mul(t[0], &r[0], &r[1]) 105 fp2.mulByFq(t[0], t[0], twoInv) 106 fp2.square(t[1], &r[1]) 107 fp2.square(t[2], &r[2]) 108 fp2.double(t[7], t[2]) 109 fp2.add(t[7], t[7], t[2]) 110 fp2.mulByB(t[3], t[7]) 111 fp2.double(t[4], t[3]) 112 fp2.add(t[4], t[4], t[3]) 113 fp2.add(t[5], t[1], t[4]) 114 fp2.mulByFq(t[5], t[5], twoInv) 115 fp2.add(t[6], &r[1], &r[2]) 116 fp2.square(t[6], t[6]) 117 fp2.add(t[7], t[2], t[1]) 118 fp2.sub(t[6], t[6], t[7]) 119 fp2.sub(&coeff[0], t[3], t[1]) 120 fp2.square(t[7], &r[0]) 121 fp2.sub(t[4], t[1], t[4]) 122 fp2.mul(&r[0], t[4], t[0]) 123 fp2.square(t[2], t[3]) 124 fp2.double(t[3], t[2]) 125 fp2.add(t[3], t[3], t[2]) 126 fp2.square(t[5], t[5]) 127 fp2.sub(&r[1], t[5], t[3]) 128 fp2.mul(&r[2], t[1], t[6]) 129 fp2.double(t[0], t[7]) 130 fp2.add(&coeff[1], t[0], t[7]) 131 fp2.neg(&coeff[2], t[6]) 132 } 133 134 func (e *Engine) additionStep(coeff *[3]fe2, r, q *PointG2) { 135 // Algorithm 12 in https://eprint.iacr.org/2010/526.pdf 136 fp2 := e.fp2 137 t := e.t2 138 fp2.mul(t[0], &q[1], &r[2]) 139 fp2.neg(t[0], t[0]) 140 fp2.add(t[0], t[0], &r[1]) 141 fp2.mul(t[1], &q[0], &r[2]) 142 fp2.neg(t[1], t[1]) 143 fp2.add(t[1], t[1], &r[0]) 144 fp2.square(t[2], t[0]) 145 fp2.square(t[3], t[1]) 146 fp2.mul(t[4], t[1], t[3]) 147 fp2.mul(t[2], &r[2], t[2]) 148 fp2.mul(t[3], &r[0], t[3]) 149 fp2.double(t[5], t[3]) 150 fp2.sub(t[5], t[4], t[5]) 151 fp2.add(t[5], t[5], t[2]) 152 fp2.mul(&r[0], t[1], t[5]) 153 fp2.sub(t[2], t[3], t[5]) 154 fp2.mul(t[2], t[2], t[0]) 155 fp2.mul(t[3], &r[1], t[4]) 156 fp2.sub(&r[1], t[2], t[3]) 157 fp2.mul(&r[2], &r[2], t[4]) 158 fp2.mul(t[2], t[1], &q[1]) 159 fp2.mul(t[3], t[0], &q[0]) 160 fp2.sub(&coeff[0], t[3], t[2]) 161 fp2.neg(&coeff[1], t[0]) 162 coeff[2].set(t[1]) 163 } 164 165 func (e *Engine) preCompute(ellCoeffs *[68][3]fe2, twistPoint *PointG2) { 166 // Algorithm 5 in https://eprint.iacr.org/2019/077.pdf 167 if e.G2.IsZero(twistPoint) { 168 return 169 } 170 r := new(PointG2).Set(twistPoint) 171 j := 0 172 for i := x.BitLen() - 2; i >= 0; i-- { 173 e.doublingStep(&ellCoeffs[j], r) 174 if x.Bit(i) != 0 { 175 j++ 176 ellCoeffs[j] = fe6{} 177 e.additionStep(&ellCoeffs[j], r, twistPoint) 178 } 179 j++ 180 } 181 } 182 183 func (e *Engine) millerLoop(f *fe12) { 184 pairs := e.pairs 185 ellCoeffs := make([][68][3]fe2, len(pairs)) 186 for i := 0; i < len(pairs); i++ { 187 e.preCompute(&ellCoeffs[i], pairs[i].g2) 188 } 189 fp12, fp2 := e.fp12, e.fp2 190 t := e.t2 191 f.one() 192 j := 0 193 for i := 62; /* x.BitLen() - 2 */ i >= 0; i-- { 194 if i != 62 { 195 fp12.square(f, f) 196 } 197 for i := 0; i <= len(pairs)-1; i++ { 198 fp2.mulByFq(t[0], &ellCoeffs[i][j][2], &pairs[i].g1[1]) 199 fp2.mulByFq(t[1], &ellCoeffs[i][j][1], &pairs[i].g1[0]) 200 fp12.mulBy014Assign(f, &ellCoeffs[i][j][0], t[1], t[0]) 201 } 202 if x.Bit(i) != 0 { 203 j++ 204 for i := 0; i <= len(pairs)-1; i++ { 205 fp2.mulByFq(t[0], &ellCoeffs[i][j][2], &pairs[i].g1[1]) 206 fp2.mulByFq(t[1], &ellCoeffs[i][j][1], &pairs[i].g1[0]) 207 fp12.mulBy014Assign(f, &ellCoeffs[i][j][0], t[1], t[0]) 208 } 209 } 210 j++ 211 } 212 fp12.conjugate(f, f) 213 } 214 215 func (e *Engine) exp(c, a *fe12) { 216 fp12 := e.fp12 217 fp12.cyclotomicExp(c, a, x) 218 fp12.conjugate(c, c) 219 } 220 221 func (e *Engine) finalExp(f *fe12) { 222 fp12 := e.fp12 223 t := e.t12 224 // easy part 225 fp12.frobeniusMap(&t[0], f, 6) 226 fp12.inverse(&t[1], f) 227 fp12.mul(&t[2], &t[0], &t[1]) 228 t[1].set(&t[2]) 229 fp12.frobeniusMapAssign(&t[2], 2) 230 fp12.mulAssign(&t[2], &t[1]) 231 fp12.cyclotomicSquare(&t[1], &t[2]) 232 fp12.conjugate(&t[1], &t[1]) 233 // hard part 234 e.exp(&t[3], &t[2]) 235 fp12.cyclotomicSquare(&t[4], &t[3]) 236 fp12.mul(&t[5], &t[1], &t[3]) 237 e.exp(&t[1], &t[5]) 238 e.exp(&t[0], &t[1]) 239 e.exp(&t[6], &t[0]) 240 fp12.mulAssign(&t[6], &t[4]) 241 e.exp(&t[4], &t[6]) 242 fp12.conjugate(&t[5], &t[5]) 243 fp12.mulAssign(&t[4], &t[5]) 244 fp12.mulAssign(&t[4], &t[2]) 245 fp12.conjugate(&t[5], &t[2]) 246 fp12.mulAssign(&t[1], &t[2]) 247 fp12.frobeniusMapAssign(&t[1], 3) 248 fp12.mulAssign(&t[6], &t[5]) 249 fp12.frobeniusMapAssign(&t[6], 1) 250 fp12.mulAssign(&t[3], &t[0]) 251 fp12.frobeniusMapAssign(&t[3], 2) 252 fp12.mulAssign(&t[3], &t[1]) 253 fp12.mulAssign(&t[3], &t[6]) 254 fp12.mul(f, &t[3], &t[4]) 255 } 256 257 func (e *Engine) calculate() *fe12 { 258 f := e.fp12.one() 259 if len(e.pairs) == 0 { 260 return f 261 } 262 e.millerLoop(f) 263 e.finalExp(f) 264 return f 265 } 266 267 // Check computes pairing and checks if result is equal to one 268 func (e *Engine) Check() bool { 269 return e.calculate().isOne() 270 } 271 272 // Result computes pairing and returns target group element as result. 273 func (e *Engine) Result() *E { 274 r := e.calculate() 275 e.Reset() 276 return r 277 } 278 279 // GT returns target group instance. 280 func (e *Engine) GT() *GT { 281 return NewGT() 282 }