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