github.com/consensys/gnark-crypto@v0.14.0/internal/generator/tower/template/fq12over6over2/fq12.go.tmpl (about) 1 import ( 2 "math/big" 3 "errors" 4 "sync" 5 "github.com/consensys/gnark-crypto/ecc" 6 "github.com/consensys/gnark-crypto/ecc/{{.Curve.Name}}/fp" 7 "github.com/consensys/gnark-crypto/ecc/{{.Curve.Name}}/fr" 8 ) 9 10 var bigIntPool = sync.Pool{ 11 New: func() interface{} { 12 return new(big.Int) 13 }, 14 } 15 16 // E12 is a degree two finite field extension of fp6 17 type E12 struct { 18 C0, C1 E6 19 } 20 21 // Equal returns true if z equals x, false otherwise 22 func (z *E12) Equal(x *E12) bool { 23 return z.C0.Equal(&x.C0) && z.C1.Equal(&x.C1) 24 } 25 26 // String puts E12 in string form 27 func (z *E12) String() string { 28 return (z.C0.String() + "+(" + z.C1.String() + ")*w") 29 } 30 31 // SetString sets a E12 from string 32 func (z *E12) SetString(s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11 string) *E12 { 33 z.C0.SetString(s0, s1, s2, s3, s4, s5) 34 z.C1.SetString(s6, s7, s8, s9, s10, s11) 35 return z 36 } 37 38 // Set copies x into z and returns z 39 func (z *E12) Set(x *E12) *E12 { 40 z.C0 = x.C0 41 z.C1 = x.C1 42 return z 43 } 44 45 // SetOne sets z to 1 in Montgomery form and returns z 46 func (z *E12) SetOne() *E12 { 47 *z = E12{} 48 z.C0.B0.A0.SetOne() 49 return z 50 } 51 52 // Add sets z=x+y in E12 and returns z 53 func (z *E12) Add(x, y *E12) *E12 { 54 z.C0.Add(&x.C0, &y.C0) 55 z.C1.Add(&x.C1, &y.C1) 56 return z 57 } 58 59 // Sub sets z to x-y and returns z 60 func (z *E12) Sub(x, y *E12) *E12 { 61 z.C0.Sub(&x.C0, &y.C0) 62 z.C1.Sub(&x.C1, &y.C1) 63 return z 64 } 65 66 // Double sets z=2*x and returns z 67 func (z *E12) Double(x *E12) *E12 { 68 z.C0.Double(&x.C0) 69 z.C1.Double(&x.C1) 70 return z 71 } 72 73 // SetRandom used only in tests 74 func (z *E12) SetRandom() (*E12, error) { 75 if _, err := z.C0.SetRandom(); err != nil { 76 return nil, err 77 } 78 if _, err := z.C1.SetRandom(); err != nil { 79 return nil, err 80 } 81 return z, nil 82 } 83 84 // IsZero returns true if z is zero, false otherwise 85 func (z *E12) IsZero() bool { 86 return z.C0.IsZero() && z.C1.IsZero() 87 } 88 89 // IsOne returns true if z is one, false otherwise 90 func (z *E12) IsOne() bool { 91 return z.C0.IsOne() && z.C1.IsZero() 92 } 93 94 // Mul sets z=x*y in E12 and returns z 95 func (z *E12) Mul(x, y *E12) *E12 { 96 var a, b, c E6 97 a.Add(&x.C0, &x.C1) 98 b.Add(&y.C0, &y.C1) 99 a.Mul(&a, &b) 100 b.Mul(&x.C0, &y.C0) 101 c.Mul(&x.C1, &y.C1) 102 z.C1.Sub(&a, &b).Sub(&z.C1, &c) 103 z.C0.MulByNonResidue(&c).Add(&z.C0, &b) 104 return z 105 } 106 107 // Square sets z=x*x in E12 and returns z 108 func (z *E12) Square(x *E12) *E12 { 109 110 //Algorithm 22 from https://eprint.iacr.org/2010/354.pdf 111 var c0, c2, c3 E6 112 c0.Sub(&x.C0, &x.C1) 113 c3.MulByNonResidue(&x.C1).Neg(&c3).Add(&x.C0, &c3) 114 c2.Mul(&x.C0, &x.C1) 115 c0.Mul(&c0, &c3).Add(&c0, &c2) 116 z.C1.Double(&c2) 117 c2.MulByNonResidue(&c2) 118 z.C0.Add(&c0, &c2) 119 120 return z 121 } 122 123 // Karabina's compressed cyclotomic square 124 // https://eprint.iacr.org/2010/542.pdf 125 // Th. 3.2 with minor modifications to fit our tower 126 func (z *E12) CyclotomicSquareCompressed(x *E12) *E12 { 127 128 var t [7]E2 129 130 // t0 = g1^2 131 t[0].Square(&x.C0.B1) 132 // t1 = g5^2 133 t[1].Square(&x.C1.B2) 134 // t5 = g1 + g5 135 t[5].Add(&x.C0.B1, &x.C1.B2) 136 // t2 = (g1 + g5)^2 137 t[2].Square(&t[5]) 138 139 // t3 = g1^2 + g5^2 140 t[3].Add(&t[0], &t[1]) 141 // t5 = 2 * g1 * g5 142 t[5].Sub(&t[2], &t[3]) 143 144 // t6 = g3 + g2 145 t[6].Add(&x.C1.B0, &x.C0.B2) 146 // t3 = (g3 + g2)^2 147 t[3].Square(&t[6]) 148 // t2 = g3^2 149 t[2].Square(&x.C1.B0) 150 151 // t6 = 2 * nr * g1 * g5 152 t[6].MulByNonResidue(&t[5]) 153 // t5 = 4 * nr * g1 * g5 + 2 * g3 154 t[5].Add(&t[6], &x.C1.B0). 155 Double(&t[5]) 156 // z3 = 6 * nr * g1 * g5 + 2 * g3 157 z.C1.B0.Add(&t[5], &t[6]) 158 159 // t4 = nr * g5^2 160 t[4].MulByNonResidue(&t[1]) 161 // t5 = nr * g5^2 + g1^2 162 t[5].Add(&t[0], &t[4]) 163 // t6 = nr * g5^2 + g1^2 - g2 164 t[6].Sub(&t[5], &x.C0.B2) 165 166 // t1 = g2^2 167 t[1].Square(&x.C0.B2) 168 169 // t6 = 2 * nr * g5^2 + 2 * g1^2 - 2*g2 170 t[6].Double(&t[6]) 171 // z2 = 3 * nr * g5^2 + 3 * g1^2 - 2*g2 172 z.C0.B2.Add(&t[6], &t[5]) 173 174 // t4 = nr * g2^2 175 t[4].MulByNonResidue(&t[1]) 176 // t5 = g3^2 + nr * g2^2 177 t[5].Add(&t[2], &t[4]) 178 // t6 = g3^2 + nr * g2^2 - g1 179 t[6].Sub(&t[5], &x.C0.B1) 180 // t6 = 2 * g3^2 + 2 * nr * g2^2 - 2 * g1 181 t[6].Double(&t[6]) 182 // z1 = 3 * g3^2 + 3 * nr * g2^2 - 2 * g1 183 z.C0.B1.Add(&t[6], &t[5]) 184 185 // t0 = g2^2 + g3^2 186 t[0].Add(&t[2], &t[1]) 187 // t5 = 2 * g3 * g2 188 t[5].Sub(&t[3], &t[0]) 189 // t6 = 2 * g3 * g2 + g5 190 t[6].Add(&t[5], &x.C1.B2) 191 // t6 = 4 * g3 * g2 + 2 * g5 192 t[6].Double(&t[6]) 193 // z5 = 6 * g3 * g2 + 2 * g5 194 z.C1.B2.Add(&t[5], &t[6]) 195 196 return z 197 } 198 199 // DecompressKarabina Karabina's cyclotomic square result 200 // if g3 != 0 201 // g4 = (E * g5^2 + 3 * g1^2 - 2 * g2)/4g3 202 // if g3 == 0 203 // g4 = 2g1g5/g2 204 // 205 // if g3=g2=0 then g4=g5=g1=0 and g0=1 (x=1) 206 // Theorem 3.1 is well-defined for all x in Gϕₙ\{1} 207 func (z *E12) DecompressKarabina(x *E12) *E12 { 208 209 var t [3]E2 210 var one E2 211 one.SetOne() 212 213 if x.C1.B2.IsZero() /* g3 == 0 */ { 214 t[0].Mul(&x.C0.B1, &x.C1.B2). 215 Double(&t[0]) 216 // t1 = g2 217 t[1].Set(&x.C0.B2) 218 219 if t[1].IsZero() /* g2 == g3 == 0 */ { 220 return z.SetOne() 221 } 222 } else /* g3 != 0 */ { 223 224 // t0 = g1^2 225 t[0].Square(&x.C0.B1) 226 // t1 = 3 * g1^2 - 2 * g2 227 t[1].Sub(&t[0], &x.C0.B2). 228 Double(&t[1]). 229 Add(&t[1], &t[0]) 230 // t0 = E * g5^2 + t1 231 t[2].Square(&x.C1.B2) 232 t[0].MulByNonResidue(&t[2]). 233 Add(&t[0], &t[1]) 234 // t1 = 4 * g3 235 t[1].Double(&x.C1.B0). 236 Double(&t[1]) 237 } 238 239 // z4 = g4 240 z.C1.B1.Div(&t[0], &t[1]) // costly 241 242 // t1 = g2 * g1 243 t[1].Mul(&x.C0.B2, &x.C0.B1); 244 // t2 = 2 * g4^2 - 3 * g2 * g1 245 t[2].Square(&z.C1.B1). 246 Sub(&t[2], &t[1]). 247 Double(&t[2]). 248 Sub(&t[2], &t[1]) 249 // t1 = g3 * g5 (g3 can be 0) 250 t[1].Mul(&x.C1.B0, &x.C1.B2) 251 // c_0 = E * (2 * g4^2 + g3 * g5 - 3 * g2 * g1) + 1 252 t[2].Add(&t[2], &t[1]) 253 z.C0.B0.MulByNonResidue(&t[2]). 254 Add(&z.C0.B0, &one) 255 256 z.C0.B1.Set(&x.C0.B1) 257 z.C0.B2.Set(&x.C0.B2) 258 z.C1.B0.Set(&x.C1.B0) 259 z.C1.B2.Set(&x.C1.B2) 260 261 return z 262 } 263 264 // BatchDecompressKarabina multiple Karabina's cyclotomic square results 265 // if g3 != 0 266 // g4 = (E * g5^2 + 3 * g1^2 - 2 * g2)/4g3 267 // if g3 == 0 268 // g4 = 2g1g5/g2 269 // 270 // if g3=g2=0 then g4=g5=g1=0 and g0=1 (x=1) 271 // Theorem 3.1 is well-defined for all x in Gϕₙ\{1} 272 // 273 // Divisions by 4g3 or g2 is batched using Montgomery batch inverse 274 func BatchDecompressKarabina(x []E12) []E12 { 275 276 n := len(x) 277 if n == 0 { 278 return x 279 } 280 281 t0 := make([]E2, n) 282 t1 := make([]E2, n) 283 t2 := make([]E2, n) 284 zeroes := make([]bool, n) 285 286 var one E2 287 one.SetOne() 288 289 for i := 0; i < n; i++ { 290 if x[i].C1.B2.IsZero() /* g3 == 0 */ { 291 t0[i].Mul(&x[i].C0.B1, &x[i].C1.B2). 292 Double(&t0[i]) 293 // t1 = g2 294 t1[i].Set(&x[i].C0.B2) 295 296 if t1[i].IsZero() /* g3 == g2 == 0 */ { 297 x[i].SetOne() 298 zeroes[i] = true 299 continue 300 } 301 } else /* g3 != 0 */ { 302 // t0 = g1^2 303 t0[i].Square(&x[i].C0.B1) 304 // t1 = 3 * g1^2 - 2 * g2 305 t1[i].Sub(&t0[i], &x[i].C0.B2). 306 Double(&t1[i]). 307 Add(&t1[i], &t0[i]) 308 // t0 = E * g5^2 + t1 309 t2[i].Square(&x[i].C1.B2) 310 t0[i].MulByNonResidue(&t2[i]). 311 Add(&t0[i], &t1[i]) 312 // t1 = 4 * g3 313 t1[i].Double(&x[i].C1.B0). 314 Double(&t1[i]) 315 } 316 } 317 318 t1 = BatchInvertE2(t1) // costs 1 inverse 319 320 for i := 0; i < n; i++ { 321 if zeroes[i] { 322 continue 323 } 324 325 // z4 = g4 326 x[i].C1.B1.Mul(&t0[i], &t1[i]) 327 328 // t1 = g2 * g1 329 t1[i].Mul(&x[i].C0.B2, &x[i].C0.B1) 330 // t2 = 2 * g4^2 - 3 * g2 * g1 331 t2[i].Square(&x[i].C1.B1) 332 t2[i].Sub(&t2[i], &t1[i]) 333 t2[i].Double(&t2[i]) 334 t2[i].Sub(&t2[i], &t1[i]) 335 336 // t1 = g3 * g5 (g3s can be 0s) 337 t1[i].Mul(&x[i].C1.B0, &x[i].C1.B2) 338 // z0 = E * (2 * g4^2 + g3 * g5 - 3 * g2 * g1) + 1 339 t2[i].Add(&t2[i], &t1[i]) 340 x[i].C0.B0.MulByNonResidue(&t2[i]). 341 Add(&x[i].C0.B0, &one) 342 } 343 344 return x 345 } 346 347 // Granger-Scott's cyclotomic square 348 // https://eprint.iacr.org/2009/565.pdf, 3.2 349 func (z *E12) CyclotomicSquare(x *E12) *E12 { 350 351 // x=(x0,x1,x2,x3,x4,x5,x6,x7) in E2^6 352 // cyclosquare(x)=(3*x4^2*u + 3*x0^2 - 2*x0, 353 // 3*x2^2*u + 3*x3^2 - 2*x1, 354 // 3*x5^2*u + 3*x1^2 - 2*x2, 355 // 6*x1*x5*u + 2*x3, 356 // 6*x0*x4 + 2*x4, 357 // 6*x2*x3 + 2*x5) 358 359 var t [9]E2 360 361 t[0].Square(&x.C1.B1) 362 t[1].Square(&x.C0.B0) 363 t[6].Add(&x.C1.B1, &x.C0.B0).Square(&t[6]).Sub(&t[6], &t[0]).Sub(&t[6], &t[1]) // 2*x4*x0 364 t[2].Square(&x.C0.B2) 365 t[3].Square(&x.C1.B0) 366 t[7].Add(&x.C0.B2, &x.C1.B0).Square(&t[7]).Sub(&t[7], &t[2]).Sub(&t[7], &t[3]) // 2*x2*x3 367 t[4].Square(&x.C1.B2) 368 t[5].Square(&x.C0.B1) 369 t[8].Add(&x.C1.B2, &x.C0.B1).Square(&t[8]).Sub(&t[8], &t[4]).Sub(&t[8], &t[5]).MulByNonResidue(&t[8]) // 2*x5*x1*u 370 371 t[0].MulByNonResidue(&t[0]).Add(&t[0], &t[1]) // x4^2*u + x0^2 372 t[2].MulByNonResidue(&t[2]).Add(&t[2], &t[3]) // x2^2*u + x3^2 373 t[4].MulByNonResidue(&t[4]).Add(&t[4], &t[5]) // x5^2*u + x1^2 374 375 z.C0.B0.Sub(&t[0], &x.C0.B0).Double(&z.C0.B0).Add(&z.C0.B0, &t[0]) 376 z.C0.B1.Sub(&t[2], &x.C0.B1).Double(&z.C0.B1).Add(&z.C0.B1, &t[2]) 377 z.C0.B2.Sub(&t[4], &x.C0.B2).Double(&z.C0.B2).Add(&z.C0.B2, &t[4]) 378 379 z.C1.B0.Add(&t[8], &x.C1.B0).Double(&z.C1.B0).Add(&z.C1.B0, &t[8]) 380 z.C1.B1.Add(&t[6], &x.C1.B1).Double(&z.C1.B1).Add(&z.C1.B1, &t[6]) 381 z.C1.B2.Add(&t[7], &x.C1.B2).Double(&z.C1.B2).Add(&z.C1.B2, &t[7]) 382 383 return z 384 } 385 386 387 // Inverse sets z to the inverse of x in E12 and returns z 388 // 389 // if x == 0, sets and returns z = x 390 func (z *E12) Inverse(x *E12) *E12 { 391 // Algorithm 23 from https://eprint.iacr.org/2010/354.pdf 392 393 var t0, t1, tmp E6 394 t0.Square(&x.C0) 395 t1.Square(&x.C1) 396 tmp.MulByNonResidue(&t1) 397 t0.Sub(&t0, &tmp) 398 t1.Inverse(&t0) 399 z.C0.Mul(&x.C0, &t1) 400 z.C1.Mul(&x.C1, &t1).Neg(&z.C1) 401 402 return z 403 } 404 405 // BatchInvertE12 returns a new slice with every element in a inverted. 406 // It uses Montgomery batch inversion trick. 407 // 408 // if a[i] == 0, returns result[i] = a[i] 409 func BatchInvertE12(a []E12) []E12 { 410 res := make([]E12, len(a)) 411 if len(a) == 0 { 412 return res 413 } 414 415 zeroes := make([]bool, len(a)) 416 var accumulator E12 417 accumulator.SetOne() 418 419 for i := 0; i < len(a); i++ { 420 if a[i].IsZero() { 421 zeroes[i] = true 422 continue 423 } 424 res[i].Set(&accumulator) 425 accumulator.Mul(&accumulator, &a[i]) 426 } 427 428 accumulator.Inverse(&accumulator) 429 430 for i := len(a) - 1; i >= 0; i-- { 431 if zeroes[i] { 432 continue 433 } 434 res[i].Mul(&res[i], &accumulator) 435 accumulator.Mul(&accumulator, &a[i]) 436 } 437 438 return res 439 } 440 441 // Exp sets z=xᵏ (mod q¹²) and returns it 442 // uses 2-bits windowed method 443 func (z *E12) Exp(x E12, k *big.Int) *E12 { 444 if k.IsUint64() && k.Uint64() == 0 { 445 return z.SetOne() 446 } 447 448 e := k 449 if k.Sign() == -1 { 450 // negative k, we invert 451 // if k < 0: xᵏ (mod q¹²) == (x⁻¹)ᵏ (mod q¹²) 452 x.Inverse(&x) 453 454 // we negate k in a temp big.Int since 455 // Int.Bit(_) of k and -k is different 456 e = bigIntPool.Get().(*big.Int) 457 defer bigIntPool.Put(e) 458 e.Neg(k) 459 } 460 461 var res E12 462 var ops [3]E12 463 464 res.SetOne() 465 ops[0].Set(&x) 466 ops[1].Square(&ops[0]) 467 ops[2].Set(&ops[0]).Mul(&ops[2], &ops[1]) 468 469 b := e.Bytes() 470 for i := range b { 471 w := b[i] 472 mask := byte(0xc0) 473 for j := 0; j < 4; j++ { 474 res.Square(&res).Square(&res) 475 c := (w & mask) >> (6 - 2*j) 476 if c != 0 { 477 res.Mul(&res, &ops[c-1]) 478 } 479 mask = mask >> 2 480 } 481 } 482 z.Set(&res) 483 484 return z 485 } 486 487 // CyclotomicExp sets z=xᵏ (mod q¹²) and returns it 488 // uses 2-NAF decomposition 489 // x must be in the cyclotomic subgroup 490 // TODO: use a windowed method 491 func (z *E12) CyclotomicExp(x E12, k *big.Int) *E12 { 492 if k.IsUint64() && k.Uint64() == 0 { 493 return z.SetOne() 494 } 495 496 e := k 497 if k.Sign() == -1 { 498 // negative k, we invert (=conjugate) 499 // if k < 0: xᵏ (mod q¹²) == (x⁻¹)ᵏ (mod q¹²) 500 x.Conjugate(&x) 501 502 // we negate k in a temp big.Int since 503 // Int.Bit(_) of k and -k is different 504 e = bigIntPool.Get().(*big.Int) 505 defer bigIntPool.Put(e) 506 e.Neg(k) 507 } 508 509 var res, xInv E12 510 xInv.InverseUnitary(&x) 511 res.SetOne() 512 eNAF := make([]int8, e.BitLen()+3) 513 n := ecc.NafDecomposition(e, eNAF[:]) 514 for i := n - 1; i >= 0; i-- { 515 res.CyclotomicSquare(&res) 516 if eNAF[i] == 1 { 517 res.Mul(&res, &x) 518 } else if eNAF[i] == -1 { 519 res.Mul(&res, &xInv) 520 } 521 } 522 z.Set(&res) 523 return z 524 } 525 526 // ExpGLV sets z=xᵏ (q¹²) and returns it 527 // uses 2-dimensional GLV with 2-bits windowed method 528 // x must be in GT 529 // TODO: use 2-NAF 530 // TODO: use higher dimensional decomposition 531 func (z *E12) ExpGLV(x E12, k *big.Int) *E12 { 532 if k.IsUint64() && k.Uint64() == 0 { 533 return z.SetOne() 534 } 535 536 e := k 537 if k.Sign() == -1 { 538 // negative k, we invert (=conjugate) 539 // if k < 0: xᵏ (mod q¹²) == (x⁻¹)ᵏ (mod q¹²) 540 x.Conjugate(&x) 541 542 // we negate k in a temp big.Int since 543 // Int.Bit(_) of k and -k is different 544 e = bigIntPool.Get().(*big.Int) 545 defer bigIntPool.Put(e) 546 e.Neg(k) 547 } 548 549 var table [15]E12 550 var res E12 551 var s1, s2 fr.Element 552 553 res.SetOne() 554 555 // table[b3b2b1b0-1] = b3b2*Frobinius(x) + b1b0*x 556 table[0].Set(&x) 557 table[3].Frobenius(&x) 558 559 // split the scalar, modifies ±x, Frob(x) accordingly 560 s := ecc.SplitScalar(e, &glvBasis) 561 562 if s[0].Sign() == -1 { 563 s[0].Neg(&s[0]) 564 table[0].InverseUnitary(&table[0]) 565 } 566 if s[1].Sign() == -1 { 567 s[1].Neg(&s[1]) 568 table[3].InverseUnitary(&table[3]) 569 } 570 571 // precompute table (2 bits sliding window) 572 // table[b3b2b1b0-1] = b3b2*Frobenius(x) + b1b0*x if b3b2b1b0 != 0 573 table[1].CyclotomicSquare(&table[0]) 574 table[2].Mul(&table[1], &table[0]) 575 table[4].Mul(&table[3], &table[0]) 576 table[5].Mul(&table[3], &table[1]) 577 table[6].Mul(&table[3], &table[2]) 578 table[7].CyclotomicSquare(&table[3]) 579 table[8].Mul(&table[7], &table[0]) 580 table[9].Mul(&table[7], &table[1]) 581 table[10].Mul(&table[7], &table[2]) 582 table[11].Mul(&table[7], &table[3]) 583 table[12].Mul(&table[11], &table[0]) 584 table[13].Mul(&table[11], &table[1]) 585 table[14].Mul(&table[11], &table[2]) 586 587 // bounds on the lattice base vectors guarantee that s1, s2 are len(r)/2 bits long max 588 s1 = s1.SetBigInt(&s[0]).Bits() 589 s2 = s2.SetBigInt(&s[1]).Bits() 590 591 maxBit := s1.BitLen() 592 if s2.BitLen() > maxBit { 593 maxBit = s2.BitLen() 594 } 595 hiWordIndex := (maxBit - 1) / 64 596 597 // loop starts from len(s1)/2 due to the bounds 598 for i := hiWordIndex ; i >= 0; i-- { 599 mask := uint64(3) << 62 600 for j := 0; j < 32; j++ { 601 res.CyclotomicSquare(&res).CyclotomicSquare(&res) 602 b1 := (s1[i] & mask) >> (62 - 2*j) 603 b2 := (s2[i] & mask) >> (62 - 2*j) 604 if b1|b2 != 0 { 605 s := (b2<<2 | b1) 606 res.Mul(&res, &table[s-1]) 607 } 608 mask = mask >> 2 609 } 610 } 611 612 z.Set(&res) 613 return z 614 } 615 616 // InverseUnitary inverses a unitary element 617 func (z *E12) InverseUnitary(x *E12) *E12 { 618 return z.Conjugate(x) 619 } 620 621 // Conjugate sets z to x conjugated and returns z 622 func (z *E12) Conjugate(x *E12) *E12 { 623 *z = *x 624 z.C1.Neg(&z.C1) 625 return z 626 } 627 628 629 {{- $sizeOfFp := mul .Curve.Fp.NbWords 8}} 630 631 // SizeOfGT represents the size in bytes that a GT element need in binary form 632 const SizeOfGT = {{ $sizeOfFp }} * 12 633 634 // Marshal converts z to a byte slice 635 func (z *E12) Marshal() ([]byte) { 636 b := z.Bytes() 637 return b[:] 638 } 639 640 // Unmarshal is an alias to SetBytes() 641 func (z *E12) Unmarshal(buf []byte) error { 642 return z.SetBytes(buf) 643 } 644 645 // Bytes returns the regular (non montgomery) value 646 // of z as a big-endian byte array. 647 // z.C1.B2.A1 | z.C1.B2.A0 | z.C1.B1.A1 | ... 648 func (z *E12) Bytes() (r [SizeOfGT]byte) { 649 {{- $offset := mul $sizeOfFp 11}} 650 {{- template "putFp" dict "all" . "OffSet" $offset "From" "z.C0.B0.A0"}} 651 652 {{- $offset := mul $sizeOfFp 10}} 653 {{- template "putFp" dict "all" . "OffSet" $offset "From" "z.C0.B0.A1"}} 654 655 {{- $offset := mul $sizeOfFp 9}} 656 {{- template "putFp" dict "all" . "OffSet" $offset "From" "z.C0.B1.A0"}} 657 658 {{- $offset := mul $sizeOfFp 8}} 659 {{- template "putFp" dict "all" . "OffSet" $offset "From" "z.C0.B1.A1"}} 660 661 {{- $offset := mul $sizeOfFp 7}} 662 {{- template "putFp" dict "all" . "OffSet" $offset "From" "z.C0.B2.A0"}} 663 664 {{- $offset := mul $sizeOfFp 6}} 665 {{- template "putFp" dict "all" . "OffSet" $offset "From" "z.C0.B2.A1"}} 666 667 {{- $offset := mul $sizeOfFp 5}} 668 {{- template "putFp" dict "all" . "OffSet" $offset "From" "z.C1.B0.A0"}} 669 670 {{- $offset := mul $sizeOfFp 4}} 671 {{- template "putFp" dict "all" . "OffSet" $offset "From" "z.C1.B0.A1"}} 672 673 {{- $offset := mul $sizeOfFp 3}} 674 {{- template "putFp" dict "all" . "OffSet" $offset "From" "z.C1.B1.A0"}} 675 676 {{- $offset := mul $sizeOfFp 2}} 677 {{- template "putFp" dict "all" . "OffSet" $offset "From" "z.C1.B1.A1"}} 678 679 {{- $offset := mul $sizeOfFp 1}} 680 {{- template "putFp" dict "all" . "OffSet" $offset "From" "z.C1.B2.A0"}} 681 682 {{- $offset := mul $sizeOfFp 0}} 683 {{- template "putFp" dict "all" . "OffSet" $offset "From" "z.C1.B2.A1"}} 684 685 return 686 } 687 688 689 // SetBytes interprets e as the bytes of a big-endian GT 690 // sets z to that value (in Montgomery form), and returns z. 691 // size(e) == {{ $sizeOfFp }} * 12 692 // z.C1.B2.A1 | z.C1.B2.A0 | z.C1.B1.A1 | ... 693 func (z *E12) SetBytes(e []byte) error { 694 if len(e) != SizeOfGT { 695 return errors.New("invalid buffer size") 696 } 697 698 {{- $offset := mul $sizeOfFp 11}} 699 {{- template "readFp" dict "all" . "OffSet" $offset "To" "z.C0.B0.A0"}} 700 701 {{- $offset := mul $sizeOfFp 10}} 702 {{- template "readFp" dict "all" . "OffSet" $offset "To" "z.C0.B0.A1"}} 703 704 {{- $offset := mul $sizeOfFp 9}} 705 {{- template "readFp" dict "all" . "OffSet" $offset "To" "z.C0.B1.A0"}} 706 707 {{- $offset := mul $sizeOfFp 8}} 708 {{- template "readFp" dict "all" . "OffSet" $offset "To" "z.C0.B1.A1"}} 709 710 {{- $offset := mul $sizeOfFp 7}} 711 {{- template "readFp" dict "all" . "OffSet" $offset "To" "z.C0.B2.A0"}} 712 713 {{- $offset := mul $sizeOfFp 6}} 714 {{- template "readFp" dict "all" . "OffSet" $offset "To" "z.C0.B2.A1"}} 715 716 {{- $offset := mul $sizeOfFp 5}} 717 {{- template "readFp" dict "all" . "OffSet" $offset "To" "z.C1.B0.A0"}} 718 719 {{- $offset := mul $sizeOfFp 4}} 720 {{- template "readFp" dict "all" . "OffSet" $offset "To" "z.C1.B0.A1"}} 721 722 {{- $offset := mul $sizeOfFp 3}} 723 {{- template "readFp" dict "all" . "OffSet" $offset "To" "z.C1.B1.A0"}} 724 725 {{- $offset := mul $sizeOfFp 2}} 726 {{- template "readFp" dict "all" . "OffSet" $offset "To" "z.C1.B1.A1"}} 727 728 {{- $offset := mul $sizeOfFp 1}} 729 {{- template "readFp" dict "all" . "OffSet" $offset "To" "z.C1.B2.A0"}} 730 731 {{- $offset := mul $sizeOfFp 0}} 732 {{- template "readFp" dict "all" . "OffSet" $offset "To" "z.C1.B2.A1"}} 733 734 return nil 735 } 736 737 // IsInSubGroup ensures GT/E12 is in correct subgroup 738 func (z *E12) IsInSubGroup() bool { 739 {{- if eq .Curve.Name "bn254"}} 740 var a, b, _b E12 741 742 a.Frobenius(z) 743 b.Expt(z). 744 Expt(&b). 745 CyclotomicSquare(&b) 746 _b.CyclotomicSquare(&b) 747 b.Mul(&b, &_b) 748 {{ else }} 749 var a, b E12 750 751 // check z^(phi_k(p)) == 1 752 a.FrobeniusSquare(z) 753 b.FrobeniusSquare(&a).Mul(&b, z) 754 755 if !a.Equal(&b) { 756 return false 757 } 758 759 // check z^(p+1-t) == 1 760 a.Frobenius(z) 761 b.Expt(z) 762 {{ end }} 763 764 return a.Equal(&b) 765 } 766 767 {{- define "putFp"}} 768 fp.BigEndian.PutElement((*[fp.Bytes]byte)( r[{{$.OffSet}}:{{$.OffSet}} + fp.Bytes]), {{$.From}}) 769 {{- end}} 770 771 {{- define "readFp"}} 772 if err := {{$.To}}.SetBytesCanonical(e[{{$.OffSet}}:{{$.OffSet}} + fp.Bytes]); err != nil { 773 return err 774 } 775 {{- end}} 776 777 // CompressTorus GT/E12 element to half its size 778 // z must be in the cyclotomic subgroup 779 // i.e. z^(p^4-p^2+1)=1 780 // e.g. GT 781 // "COMPRESSION IN FINITE FIELDS AND TORUS-BASED CRYPTOGRAPHY", K. RUBIN AND A. SILVERBERG 782 // z.C1 == 0 only when z \in {-1,1} 783 func (z *E12) CompressTorus() (E6, error) { 784 785 if z.C1.IsZero() { 786 return E6{}, errors.New("invalid input") 787 } 788 789 var res, tmp, one E6 790 one.SetOne() 791 tmp.Inverse(&z.C1) 792 res.Add(&z.C0, &one). 793 Mul(&res, &tmp) 794 795 return res, nil 796 } 797 798 // BatchCompressTorus GT/E12 elements to half their size using a batch inversion. 799 // 800 // if len(x) == 0 or if any of the x[i].C1 coordinate is 0, this function returns an error. 801 func BatchCompressTorus(x []E12) ([]E6, error) { 802 803 n := len(x) 804 if n == 0 { 805 return nil, errors.New("invalid input size") 806 } 807 808 var one E6 809 one.SetOne() 810 res := make([]E6, n) 811 812 for i := 0; i < n; i++ { 813 res[i].Set(&x[i].C1) 814 // throw an error if any of the x[i].C1 is 0 815 if res[i].IsZero() { 816 return nil, errors.New("invalid input; C1 is 0") 817 } 818 } 819 820 t := BatchInvertE6(res) // costs 1 inverse 821 822 for i := 0; i < n; i++ { 823 res[i].Add(&x[i].C0, &one). 824 Mul(&res[i], &t[i]) 825 } 826 827 return res, nil 828 } 829 830 // DecompressTorus GT/E12 a compressed element 831 // element must be in the cyclotomic subgroup 832 // "COMPRESSION IN FINITE FIELDS AND TORUS-BASED CRYPTOGRAPHY", K. RUBIN AND A. SILVERBERG 833 func (z *E6) DecompressTorus() E12 { 834 835 var res, num, denum E12 836 num.C0.Set(z) 837 num.C1.SetOne() 838 denum.C0.Set(z) 839 denum.C1.SetOne().Neg(&denum.C1) 840 res.Inverse(&denum). 841 Mul(&res, &num) 842 843 return res 844 } 845 846 // BatchDecompressTorus GT/E12 compressed elements 847 // using a batch inversion 848 func BatchDecompressTorus(x []E6) ([]E12, error) { 849 850 n := len(x) 851 if n == 0 { 852 return []E12{}, errors.New("invalid input size") 853 } 854 855 res := make([]E12, n) 856 num := make([]E12, n) 857 denum := make([]E12, n) 858 859 for i := 0; i < n; i++ { 860 num[i].C0.Set(&x[i]) 861 num[i].C1.SetOne() 862 denum[i].C0.Set(&x[i]) 863 denum[i].C1.SetOne().Neg(&denum[i].C1) 864 } 865 866 denum = BatchInvertE12(denum) // costs 1 inverse 867 868 for i := 0; i < n; i++ { 869 res[i].Mul(&num[i], &denum[i]) 870 } 871 872 return res, nil 873 } 874 {{ template "base" .}}