github.com/consensys/gnark-crypto@v0.14.0/ecc/bls24-317/internal/fptower/e4.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 "math/big" 19 20 "github.com/consensys/gnark-crypto/ecc/bls24-317/fp" 21 ) 22 23 // E4 is a degree two finite field extension of fp2 24 type E4 struct { 25 B0, B1 E2 26 } 27 28 // Equal returns true if z equals x, false otherwise 29 func (z *E4) Equal(x *E4) bool { 30 return z.B0.Equal(&x.B0) && z.B1.Equal(&x.B1) 31 } 32 33 // Cmp compares (lexicographic order) z and x and returns: 34 // 35 // -1 if z < x 36 // 0 if z == x 37 // +1 if z > x 38 func (z *E4) Cmp(x *E4) int { 39 if a1 := z.B1.Cmp(&x.B1); a1 != 0 { 40 return a1 41 } 42 return z.B0.Cmp(&x.B0) 43 } 44 45 // LexicographicallyLargest returns true if this element is strictly lexicographically 46 // larger than its negation, false otherwise 47 func (z *E4) LexicographicallyLargest() bool { 48 // adapted from github.com/zkcrypto/bls12_381 49 if z.B1.IsZero() { 50 return z.B0.LexicographicallyLargest() 51 } 52 return z.B1.LexicographicallyLargest() 53 } 54 55 // String puts E4 in string form 56 func (z *E4) String() string { 57 return (z.B0.String() + "+(" + z.B1.String() + ")*v") 58 } 59 60 // SetString sets a E4 from string 61 func (z *E4) SetString(s0, s1, s2, s3 string) *E4 { 62 z.B0.SetString(s0, s1) 63 z.B1.SetString(s2, s3) 64 return z 65 } 66 67 // Set copies x into z and returns z 68 func (z *E4) Set(x *E4) *E4 { 69 z.B0 = x.B0 70 z.B1 = x.B1 71 return z 72 } 73 74 // SetZero sets an E4 elmt to zero 75 func (z *E4) SetZero() *E4 { 76 z.B0.SetZero() 77 z.B1.SetZero() 78 return z 79 } 80 81 // SetOne sets z to 1 in Montgomery form and returns z 82 func (z *E4) SetOne() *E4 { 83 *z = E4{} 84 z.B0.A0.SetOne() 85 return z 86 } 87 88 // MulByElement multiplies an element in E4 by an element in fp 89 func (z *E4) MulByElement(x *E4, y *fp.Element) *E4 { 90 var yCopy fp.Element 91 yCopy.Set(y) 92 z.B0.MulByElement(&x.B0, &yCopy) 93 z.B1.MulByElement(&x.B1, &yCopy) 94 return z 95 } 96 97 // Add sets z=x+y in E4 and returns z 98 func (z *E4) Add(x, y *E4) *E4 { 99 z.B0.Add(&x.B0, &y.B0) 100 z.B1.Add(&x.B1, &y.B1) 101 return z 102 } 103 104 // Sub sets z to x-y and returns z 105 func (z *E4) Sub(x, y *E4) *E4 { 106 z.B0.Sub(&x.B0, &y.B0) 107 z.B1.Sub(&x.B1, &y.B1) 108 return z 109 } 110 111 // Double sets z=2*x and returns z 112 func (z *E4) Double(x *E4) *E4 { 113 z.B0.Double(&x.B0) 114 z.B1.Double(&x.B1) 115 return z 116 } 117 118 // Neg negates an E4 element 119 func (z *E4) Neg(x *E4) *E4 { 120 z.B0.Neg(&x.B0) 121 z.B1.Neg(&x.B1) 122 return z 123 } 124 125 // SetRandom used only in tests 126 func (z *E4) SetRandom() (*E4, error) { 127 if _, err := z.B0.SetRandom(); err != nil { 128 return nil, err 129 } 130 if _, err := z.B1.SetRandom(); err != nil { 131 return nil, err 132 } 133 return z, nil 134 } 135 136 // IsZero returns true if z is zero, false otherwise 137 func (z *E4) IsZero() bool { 138 return z.B0.IsZero() && z.B1.IsZero() 139 } 140 141 // IsOne returns true if z is one, false otherwise 142 func (z *E4) IsOne() bool { 143 return z.B0.IsOne() && z.B1.IsZero() 144 } 145 146 // MulByNonResidue mul x by (0,1) 147 func (z *E4) MulByNonResidue(x *E4) *E4 { 148 z.B1, z.B0 = x.B0, x.B1 149 z.B0.MulByNonResidue(&z.B0) 150 return z 151 } 152 153 // MulByNonResidueInv mul x by (0,1)⁻¹ 154 func (z *E4) MulByNonResidueInv(x *E4) *E4 { 155 a := x.B1 156 var uInv E2 157 uInv.A0.SetString("68196535552147955757549882954137028530972556060709796988605069651952986598616012809013078365526") 158 uInv.A1.SetString("68196535552147955757549882954137028530972556060709796988605069651952986598616012809013078365525") 159 z.B1.Mul(&x.B0, &uInv) 160 z.B0 = a 161 return z 162 } 163 164 // Mul sets z=x*y in E4 and returns z 165 func (z *E4) Mul(x, y *E4) *E4 { 166 var a, b, c E2 167 a.Add(&x.B0, &x.B1) 168 b.Add(&y.B0, &y.B1) 169 a.Mul(&a, &b) 170 b.Mul(&x.B0, &y.B0) 171 c.Mul(&x.B1, &y.B1) 172 z.B1.Sub(&a, &b).Sub(&z.B1, &c) 173 z.B0.MulByNonResidue(&c).Add(&z.B0, &b) 174 return z 175 } 176 177 // Square sets z=x*x in E4 and returns z 178 func (z *E4) Square(x *E4) *E4 { 179 180 //Algorithm 22 from https://eprint.iacr.org/2010/354.pdf 181 var c0, c2, c3 E2 182 c0.Sub(&x.B0, &x.B1) 183 c3.MulByNonResidue(&x.B1).Sub(&x.B0, &c3) 184 c2.Mul(&x.B0, &x.B1) 185 c0.Mul(&c0, &c3).Add(&c0, &c2) 186 z.B1.Double(&c2) 187 c2.MulByNonResidue(&c2) 188 z.B0.Add(&c0, &c2) 189 190 return z 191 } 192 193 // Inverse sets z to the inverse of x in E4 and returns z 194 // 195 // if x == 0, sets and returns z = x 196 func (z *E4) Inverse(x *E4) *E4 { 197 // Algorithm 23 from https://eprint.iacr.org/2010/354.pdf 198 199 var t0, t1, tmp E2 200 t0.Square(&x.B0) 201 t1.Square(&x.B1) 202 tmp.MulByNonResidue(&t1) 203 t0.Sub(&t0, &tmp) 204 t1.Inverse(&t0) 205 z.B0.Mul(&x.B0, &t1) 206 z.B1.Mul(&x.B1, &t1).Neg(&z.B1) 207 208 return z 209 } 210 211 // Exp sets z=xᵏ (mod q⁴) and returns it 212 func (z *E4) Exp(x E4, k *big.Int) *E4 { 213 if k.IsUint64() && k.Uint64() == 0 { 214 return z.SetOne() 215 } 216 217 e := k 218 if k.Sign() == -1 { 219 // negative k, we invert 220 // if k < 0: xᵏ (mod q⁴) == (x⁻¹)ᵏ (mod q⁴) 221 x.Inverse(&x) 222 223 // we negate k in a temp big.Int since 224 // Int.Bit(_) of k and -k is different 225 e = bigIntPool.Get().(*big.Int) 226 defer bigIntPool.Put(e) 227 e.Neg(k) 228 } 229 230 z.SetOne() 231 b := e.Bytes() 232 for i := 0; i < len(b); i++ { 233 w := b[i] 234 for j := 0; j < 8; j++ { 235 z.Square(z) 236 if (w & (0b10000000 >> j)) != 0 { 237 z.Mul(z, &x) 238 } 239 } 240 } 241 242 return z 243 } 244 245 // Conjugate sets z to x conjugated and returns z 246 func (z *E4) Conjugate(x *E4) *E4 { 247 z.B0 = x.B0 248 z.B1.Neg(&x.B1) 249 return z 250 } 251 252 func (z *E4) Halve() { 253 254 z.B0.A0.Halve() 255 z.B0.A1.Halve() 256 z.B1.A0.Halve() 257 z.B1.A1.Halve() 258 } 259 260 // norm sets x to the norm of z 261 func (z *E4) norm(x *E2) { 262 var tmp E2 263 tmp.Square(&z.B1).MulByNonResidue(&tmp) 264 x.Square(&z.B0).Sub(x, &tmp) 265 } 266 267 // Legendre returns the Legendre symbol of z 268 func (z *E4) Legendre() int { 269 var n E2 270 z.norm(&n) 271 return n.Legendre() 272 } 273 274 // Sqrt sets z to the square root of and returns z 275 // The function does not test whether the square root 276 // exists or not, it's up to the caller to call 277 // Legendre beforehand. 278 // cf https://eprint.iacr.org/2012/685.pdf (algo 10) 279 func (z *E4) Sqrt(x *E4) *E4 { 280 281 // precomputation 282 var b, c, d, e, f, x0, _g E4 283 var _b, o E2 284 285 // c must be a non square (works for p=1 mod 12 hence 1 mod 4, only bls377 has such a p currently) 286 c.B1.SetOne() 287 288 q := fp.Modulus() 289 var exp, one big.Int 290 one.SetUint64(1) 291 exp.Mul(q, q).Sub(&exp, &one).Rsh(&exp, 1) 292 d.Exp(c, &exp) 293 e.Mul(&d, &c).Inverse(&e) 294 f.Mul(&d, &c).Square(&f) 295 296 // computation 297 exp.Rsh(&exp, 1) 298 b.Exp(*x, &exp) 299 b.norm(&_b) 300 o.SetOne() 301 if _b.Equal(&o) { 302 x0.Square(&b).Mul(&x0, x) 303 _b.Set(&x0.B0).Sqrt(&_b) 304 _g.B0.Set(&_b) 305 z.Conjugate(&b).Mul(z, &_g) 306 return z 307 } 308 x0.Square(&b).Mul(&x0, x).Mul(&x0, &f) 309 _b.Set(&x0.B0).Sqrt(&_b) 310 _g.B0.Set(&_b) 311 z.Conjugate(&b).Mul(z, &_g).Mul(z, &e) 312 313 return z 314 } 315 316 // BatchInvertE4 returns a new slice with every element in a inverted. 317 // It uses Montgomery batch inversion trick. 318 // 319 // if a[i] == 0, returns result[i] = a[i] 320 func BatchInvertE4(a []E4) []E4 { 321 res := make([]E4, len(a)) 322 if len(a) == 0 { 323 return res 324 } 325 326 zeroes := make([]bool, len(a)) 327 var accumulator E4 328 accumulator.SetOne() 329 330 for i := 0; i < len(a); i++ { 331 if a[i].IsZero() { 332 zeroes[i] = true 333 continue 334 } 335 res[i].Set(&accumulator) 336 accumulator.Mul(&accumulator, &a[i]) 337 } 338 339 accumulator.Inverse(&accumulator) 340 341 for i := len(a) - 1; i >= 0; i-- { 342 if zeroes[i] { 343 continue 344 } 345 res[i].Mul(&res[i], &accumulator) 346 accumulator.Mul(&accumulator, &a[i]) 347 } 348 349 return res 350 } 351 352 // Div divides an element in E4 by an element in E4 353 func (z *E4) Div(x *E4, y *E4) *E4 { 354 var r E4 355 r.Inverse(y).Mul(x, &r) 356 return z.Set(&r) 357 }