github.com/consensys/gnark-crypto@v0.14.0/ecc/bls24-315/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-315/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 set 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 sub 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 set 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 set 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 // BatchDecompressKarabina multiple Karabina's cyclotomic square results 283 // if g3 != 0 284 // 285 // g4 = (E * g5^2 + 3 * g1^2 - 2 * g2)/4g3 286 // 287 // if g3 == 0 288 // 289 // g4 = 2g1g5/g2 290 // 291 // if g3=g2=0 then g4=g5=g1=0 and g0=1 (x=1) 292 // Theorem 3.1 is well-defined for all x in Gϕₙ\{1} 293 // 294 // Divisions by 4g3 or g2 is batched using Montgomery batch inverse 295 func BatchDecompressKarabina(x []E24) []E24 { 296 297 n := len(x) 298 if n == 0 { 299 return x 300 } 301 302 t0 := make([]E4, n) 303 t1 := make([]E4, n) 304 t2 := make([]E4, n) 305 306 var one E4 307 one.SetOne() 308 309 for i := 0; i < n; i++ { 310 // g3 == 0 311 if x[i].D1.C0.IsZero() { 312 t0[i].Mul(&x[i].D0.C1, &x[i].D1.C2). 313 Double(&t0[i]) 314 // t1 = g2 315 t1[i].Set(&x[i].D0.C2) 316 317 // g3 != 0 318 } else { 319 // t0 = g1^2 320 t0[i].Square(&x[i].D0.C1) 321 // t1 = 3 * g1^2 - 2 * g2 322 t1[i].Sub(&t0[i], &x[i].D0.C2). 323 Double(&t1[i]). 324 Add(&t1[i], &t0[i]) 325 // t0 = E * g5^2 + t1 326 t2[i].Square(&x[i].D1.C2) 327 t0[i].MulByNonResidue(&t2[i]). 328 Add(&t0[i], &t1[i]) 329 // t1 = 4 * g3 330 t1[i].Double(&x[i].D1.C0). 331 Double(&t1[i]) 332 } 333 } 334 335 t1 = BatchInvertE4(t1) // costs 1 inverse 336 337 for i := 0; i < n; i++ { 338 // z4 = g4 339 x[i].D1.C1.Mul(&t0[i], &t1[i]) 340 341 // t1 = g2 * g1 342 t1[i].Mul(&x[i].D0.C2, &x[i].D0.C1) 343 // t2 = 2 * g4² - 3 * g2 * g1 344 t2[i].Square(&x[i].D1.C1) 345 t2[i].Sub(&t2[i], &t1[i]) 346 t2[i].Double(&t2[i]) 347 t2[i].Sub(&t2[i], &t1[i]) 348 349 // t1 = g3 * g5 (g3s can be 0s) 350 t1[i].Mul(&x[i].D1.C0, &x[i].D1.C2) 351 // z0 = E * (2 * g4² + g3 * g5 - 3 * g2 * g1) + 1 352 t2[i].Add(&t2[i], &t1[i]) 353 x[i].D0.C0.MulByNonResidue(&t2[i]). 354 Add(&x[i].D0.C0, &one) 355 } 356 357 return x 358 } 359 360 // Granger-Scott's cyclotomic square 361 // https://eprint.iacr.org/2009/565.pdf, 3.2 362 func (z *E24) CyclotomicSquare(x *E24) *E24 { 363 364 // x=(x0,x1,x2,x3,x4,x5,x6,x7) in E4⁶ 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]E4 373 374 t[0].Square(&x.D1.C1) 375 t[1].Square(&x.D0.C0) 376 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 377 t[2].Square(&x.D0.C2) 378 t[3].Square(&x.D1.C0) 379 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 380 t[4].Square(&x.D1.C2) 381 t[5].Square(&x.D0.C1) 382 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 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.D0.C0.Sub(&t[0], &x.D0.C0).Double(&z.D0.C0).Add(&z.D0.C0, &t[0]) 389 z.D0.C1.Sub(&t[2], &x.D0.C1).Double(&z.D0.C1).Add(&z.D0.C1, &t[2]) 390 z.D0.C2.Sub(&t[4], &x.D0.C2).Double(&z.D0.C2).Add(&z.D0.C2, &t[4]) 391 392 z.D1.C0.Add(&t[8], &x.D1.C0).Double(&z.D1.C0).Add(&z.D1.C0, &t[8]) 393 z.D1.C1.Add(&t[6], &x.D1.C1).Double(&z.D1.C1).Add(&z.D1.C1, &t[6]) 394 z.D1.C2.Add(&t[7], &x.D1.C2).Double(&z.D1.C2).Add(&z.D1.C2, &t[7]) 395 396 return z 397 } 398 399 // Inverse set z to the inverse of x in E24 and return z 400 // 401 // if x == 0, sets and returns z = x 402 func (z *E24) Inverse(x *E24) *E24 { 403 // Algorithm 23 from https://eprint.iacr.org/2010/354.pdf 404 405 var t0, t1, tmp E12 406 t0.Square(&x.D0) 407 t1.Square(&x.D1) 408 tmp.MulByNonResidue(&t1) 409 t0.Sub(&t0, &tmp) 410 t1.Inverse(&t0) 411 z.D0.Mul(&x.D0, &t1) 412 z.D1.Mul(&x.D1, &t1).Neg(&z.D1) 413 414 return z 415 } 416 417 // BatchInvertE24 returns a new slice with every element inverted. 418 // Uses Montgomery batch inversion trick 419 // 420 // if a[i] == 0, returns result[i] = a[i] 421 func BatchInvertE24(a []E24) []E24 { 422 res := make([]E24, len(a)) 423 if len(a) == 0 { 424 return res 425 } 426 427 zeroes := make([]bool, len(a)) 428 var accumulator E24 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 *E24) Exp(x E24, k *big.Int) *E24 { 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 E24 474 var ops [3]E24 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 *E24) CyclotomicExp(x E24, k *big.Int) *E24 { 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 E24 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 *E24) ExpGLV(x E24, k *big.Int) *E24 { 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]E24 562 var res E24 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 inverse a unitary element 629 func (z *E24) InverseUnitary(x *E24) *E24 { 630 return z.Conjugate(x) 631 } 632 633 // Conjugate set z to x conjugated and return z 634 func (z *E24) Conjugate(x *E24) *E24 { 635 *z = *x 636 z.D1.Neg(&z.D1) 637 return z 638 } 639 640 // SizeOfGT represents the size in bytes that a GT element need in binary form 641 const sizeOfFp = 40 642 const SizeOfGT = sizeOfFp * 24 643 644 // Marshal converts z to a byte slice 645 func (z *E24) Marshal() []byte { 646 b := z.Bytes() 647 return b[:] 648 } 649 650 // Unmarshal is an alias to SetBytes() 651 func (z *E24) Unmarshal(buf []byte) error { 652 return z.SetBytes(buf) 653 } 654 655 func (z *E24) Bytes() (r [SizeOfGT]byte) { 656 657 offset := 0 658 var buf [sizeOfFp]byte 659 660 buf = z.D0.C0.B0.A0.Bytes() 661 copy(r[offset:offset+sizeOfFp], buf[:]) 662 offset += sizeOfFp 663 664 buf = z.D0.C0.B0.A1.Bytes() 665 copy(r[offset:offset+sizeOfFp], buf[:]) 666 offset += sizeOfFp 667 668 buf = z.D0.C0.B1.A0.Bytes() 669 copy(r[offset:offset+sizeOfFp], buf[:]) 670 offset += sizeOfFp 671 672 buf = z.D0.C0.B1.A1.Bytes() 673 copy(r[offset:offset+sizeOfFp], buf[:]) 674 offset += sizeOfFp 675 676 buf = z.D0.C1.B0.A0.Bytes() 677 copy(r[offset:offset+sizeOfFp], buf[:]) 678 offset += sizeOfFp 679 680 buf = z.D0.C1.B0.A1.Bytes() 681 copy(r[offset:offset+sizeOfFp], buf[:]) 682 offset += sizeOfFp 683 684 buf = z.D0.C1.B1.A0.Bytes() 685 copy(r[offset:offset+sizeOfFp], buf[:]) 686 offset += sizeOfFp 687 688 buf = z.D0.C1.B1.A1.Bytes() 689 copy(r[offset:offset+sizeOfFp], buf[:]) 690 offset += sizeOfFp 691 692 buf = z.D0.C2.B0.A0.Bytes() 693 copy(r[offset:offset+sizeOfFp], buf[:]) 694 offset += sizeOfFp 695 696 buf = z.D0.C2.B0.A1.Bytes() 697 copy(r[offset:offset+sizeOfFp], buf[:]) 698 offset += sizeOfFp 699 700 buf = z.D0.C2.B1.A0.Bytes() 701 copy(r[offset:offset+sizeOfFp], buf[:]) 702 offset += sizeOfFp 703 704 buf = z.D0.C2.B1.A1.Bytes() 705 copy(r[offset:offset+sizeOfFp], buf[:]) 706 offset += sizeOfFp 707 708 buf = z.D1.C0.B0.A0.Bytes() 709 copy(r[offset:offset+sizeOfFp], buf[:]) 710 offset += sizeOfFp 711 712 buf = z.D1.C0.B0.A1.Bytes() 713 copy(r[offset:offset+sizeOfFp], buf[:]) 714 offset += sizeOfFp 715 716 buf = z.D1.C0.B1.A0.Bytes() 717 copy(r[offset:offset+sizeOfFp], buf[:]) 718 offset += sizeOfFp 719 720 buf = z.D1.C0.B1.A1.Bytes() 721 copy(r[offset:offset+sizeOfFp], buf[:]) 722 offset += sizeOfFp 723 724 buf = z.D1.C1.B0.A0.Bytes() 725 copy(r[offset:offset+sizeOfFp], buf[:]) 726 offset += sizeOfFp 727 728 buf = z.D1.C1.B0.A1.Bytes() 729 copy(r[offset:offset+sizeOfFp], buf[:]) 730 offset += sizeOfFp 731 732 buf = z.D1.C1.B1.A0.Bytes() 733 copy(r[offset:offset+sizeOfFp], buf[:]) 734 offset += sizeOfFp 735 736 buf = z.D1.C1.B1.A1.Bytes() 737 copy(r[offset:offset+sizeOfFp], buf[:]) 738 offset += sizeOfFp 739 740 buf = z.D1.C2.B0.A0.Bytes() 741 copy(r[offset:offset+sizeOfFp], buf[:]) 742 offset += sizeOfFp 743 744 buf = z.D1.C2.B0.A1.Bytes() 745 copy(r[offset:offset+sizeOfFp], buf[:]) 746 offset += sizeOfFp 747 748 buf = z.D1.C2.B1.A0.Bytes() 749 copy(r[offset:offset+sizeOfFp], buf[:]) 750 offset += sizeOfFp 751 752 buf = z.D1.C2.B1.A1.Bytes() 753 copy(r[offset:offset+sizeOfFp], buf[:]) 754 755 return 756 } 757 758 // SetBytes interprets e as the bytes of a big-endian GT 759 // sets z to that value (in Montgomery form), and returns z. 760 func (z *E24) SetBytes(e []byte) error { 761 if len(e) != SizeOfGT { 762 return errors.New("invalid buffer size") 763 } 764 offset := 0 765 z.D0.C0.B0.A0.SetBytes(e[offset : offset+sizeOfFp]) 766 offset += sizeOfFp 767 z.D0.C0.B0.A1.SetBytes(e[offset : offset+sizeOfFp]) 768 offset += sizeOfFp 769 z.D0.C0.B1.A0.SetBytes(e[offset : offset+sizeOfFp]) 770 offset += sizeOfFp 771 z.D0.C0.B1.A1.SetBytes(e[offset : offset+sizeOfFp]) 772 offset += sizeOfFp 773 z.D0.C1.B0.A0.SetBytes(e[offset : offset+sizeOfFp]) 774 offset += sizeOfFp 775 z.D0.C1.B0.A1.SetBytes(e[offset : offset+sizeOfFp]) 776 offset += sizeOfFp 777 z.D0.C1.B1.A0.SetBytes(e[offset : offset+sizeOfFp]) 778 offset += sizeOfFp 779 z.D0.C1.B1.A1.SetBytes(e[offset : offset+sizeOfFp]) 780 offset += sizeOfFp 781 z.D0.C2.B0.A0.SetBytes(e[offset : offset+sizeOfFp]) 782 offset += sizeOfFp 783 z.D0.C2.B0.A1.SetBytes(e[offset : offset+sizeOfFp]) 784 offset += sizeOfFp 785 z.D0.C2.B1.A0.SetBytes(e[offset : offset+sizeOfFp]) 786 offset += sizeOfFp 787 z.D0.C2.B1.A1.SetBytes(e[offset : offset+sizeOfFp]) 788 offset += sizeOfFp 789 z.D1.C0.B0.A0.SetBytes(e[offset : offset+sizeOfFp]) 790 offset += sizeOfFp 791 z.D1.C0.B0.A1.SetBytes(e[offset : offset+sizeOfFp]) 792 offset += sizeOfFp 793 z.D1.C0.B1.A0.SetBytes(e[offset : offset+sizeOfFp]) 794 offset += sizeOfFp 795 z.D1.C0.B1.A1.SetBytes(e[offset : offset+sizeOfFp]) 796 offset += sizeOfFp 797 z.D1.C1.B0.A0.SetBytes(e[offset : offset+sizeOfFp]) 798 offset += sizeOfFp 799 z.D1.C1.B0.A1.SetBytes(e[offset : offset+sizeOfFp]) 800 offset += sizeOfFp 801 z.D1.C1.B1.A0.SetBytes(e[offset : offset+sizeOfFp]) 802 offset += sizeOfFp 803 z.D1.C1.B1.A1.SetBytes(e[offset : offset+sizeOfFp]) 804 offset += sizeOfFp 805 z.D1.C2.B0.A0.SetBytes(e[offset : offset+sizeOfFp]) 806 offset += sizeOfFp 807 z.D1.C2.B0.A1.SetBytes(e[offset : offset+sizeOfFp]) 808 offset += sizeOfFp 809 z.D1.C2.B1.A0.SetBytes(e[offset : offset+sizeOfFp]) 810 offset += sizeOfFp 811 z.D1.C2.B1.A1.SetBytes(e[offset : offset+sizeOfFp]) 812 813 return nil 814 } 815 816 // IsInSubGroup ensures GT/E24 is in correct subgroup 817 func (z *E24) IsInSubGroup() bool { 818 var a, b E24 819 820 // check z^(phi_k(p)) == 1 821 a.FrobeniusQuad(z) 822 b.FrobeniusQuad(&a).Mul(&b, z) 823 824 if !a.Equal(&b) { 825 return false 826 } 827 828 // check z^(p+1-t) == 1 829 a.Frobenius(z) 830 b.Expt(z) 831 832 return a.Equal(&b) 833 } 834 835 // CompressTorus GT/E24 element to half its size 836 // z must be in the cyclotomic subgroup 837 // i.e. z^(p⁴-p²+1)=1 838 // e.g. GT 839 // "COMPRESSION IN FINITE FIELDS AND TORUS-BASED CRYPTOGRAPHY", K. RUBIN AND A. SILVERBERG 840 // z.C1 == 0 only when z ∈ {-1,1} 841 func (z *E24) CompressTorus() (E12, error) { 842 843 if z.D1.IsZero() { 844 return E12{}, errors.New("invalid input") 845 } 846 847 var res, tmp, one E12 848 one.SetOne() 849 tmp.Inverse(&z.D1) 850 res.Add(&z.D0, &one). 851 Mul(&res, &tmp) 852 853 return res, nil 854 } 855 856 // BatchCompressTorus GT/E24 elements to half their size 857 // using a batch inversion 858 func BatchCompressTorus(x []E24) ([]E12, error) { 859 860 n := len(x) 861 if n == 0 { 862 return []E12{}, errors.New("invalid input size") 863 } 864 865 var one E12 866 one.SetOne() 867 res := make([]E12, n) 868 869 for i := 0; i < n; i++ { 870 res[i].Set(&x[i].D1) 871 // throw an error if any of the x[i].C1 is 0 872 if res[i].IsZero() { 873 return []E12{}, errors.New("invalid input") 874 } 875 } 876 877 t := BatchInvertE12(res) // costs 1 inverse 878 879 for i := 0; i < n; i++ { 880 res[i].Add(&x[i].D0, &one). 881 Mul(&res[i], &t[i]) 882 } 883 884 return res, nil 885 } 886 887 // DecompressTorus GT/E24 a compressed element 888 // element must be in the cyclotomic subgroup 889 // "COMPRESSION IN FINITE FIELDS AND TORUS-BASED CRYPTOGRAPHY", K. RUBIN AND A. SILVERBERG 890 func (z *E12) DecompressTorus() E24 { 891 892 var res, num, denum E24 893 num.D0.Set(z) 894 num.D1.SetOne() 895 denum.D0.Set(z) 896 denum.D1.SetOne().Neg(&denum.D1) 897 res.Inverse(&denum). 898 Mul(&res, &num) 899 900 return res 901 } 902 903 // BatchDecompressTorus GT/E24 compressed elements 904 // using a batch inversion 905 func BatchDecompressTorus(x []E12) ([]E24, error) { 906 907 n := len(x) 908 if n == 0 { 909 return []E24{}, errors.New("invalid input size") 910 } 911 912 res := make([]E24, n) 913 num := make([]E24, n) 914 denum := make([]E24, n) 915 916 for i := 0; i < n; i++ { 917 num[i].D0.Set(&x[i]) 918 num[i].D1.SetOne() 919 denum[i].D0.Set(&x[i]) 920 denum[i].D1.SetOne().Neg(&denum[i].D1) 921 } 922 923 denum = BatchInvertE24(denum) // costs 1 inverse 924 925 for i := 0; i < n; i++ { 926 res[i].Mul(&num[i], &denum[i]) 927 } 928 929 return res, nil 930 }