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