github.com/consensys/gnark-crypto@v0.14.0/ecc/bls24-315/internal/fptower/e12.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 21 // E12 is a degree three finite field extension of fp4 22 type E12 struct { 23 C0, C1, C2 E4 24 } 25 26 // Equal returns true if z equals x, false otherwise 27 func (z *E12) Equal(x *E12) bool { 28 return z.C0.Equal(&x.C0) && z.C1.Equal(&x.C1) && z.C2.Equal(&x.C2) 29 } 30 31 // String puts E12 elmt in string form 32 func (z *E12) String() string { 33 return (z.C0.String() + "+(" + z.C1.String() + ")*w+(" + z.C2.String() + ")*w**2") 34 } 35 36 // SetString sets a E12 elmt from stringf 37 func (z *E12) SetString(s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11 string) *E12 { 38 z.C0.SetString(s0, s1, s2, s3) 39 z.C1.SetString(s4, s5, s6, s7) 40 z.C2.SetString(s8, s9, s10, s11) 41 return z 42 } 43 44 // Set Sets a E12 elmt form another E12 elmt 45 func (z *E12) Set(x *E12) *E12 { 46 z.C0 = x.C0 47 z.C1 = x.C1 48 z.C2 = x.C2 49 return z 50 } 51 52 // SetOne sets z to 1 in Montgomery form and returns z 53 func (z *E12) SetOne() *E12 { 54 *z = E12{} 55 z.C0.B0.A0.SetOne() 56 return z 57 } 58 59 // SetRandom set z to a random elmt 60 func (z *E12) SetRandom() (*E12, error) { 61 if _, err := z.C0.SetRandom(); err != nil { 62 return nil, err 63 } 64 if _, err := z.C1.SetRandom(); err != nil { 65 return nil, err 66 } 67 if _, err := z.C2.SetRandom(); err != nil { 68 return nil, err 69 } 70 return z, nil 71 } 72 73 // IsZero returns true if z is zero, false otherwise 74 func (z *E12) IsZero() bool { 75 return z.C0.IsZero() && z.C1.IsZero() && z.C2.IsZero() 76 } 77 78 // IsOne returns true if z is one, false otherwise 79 func (z *E12) IsOne() bool { 80 return z.C0.IsOne() && z.C1.IsZero() && z.C2.IsZero() 81 } 82 83 // Add adds two elements of E12 84 func (z *E12) Add(x, y *E12) *E12 { 85 z.C0.Add(&x.C0, &y.C0) 86 z.C1.Add(&x.C1, &y.C1) 87 z.C2.Add(&x.C2, &y.C2) 88 return z 89 } 90 91 // Neg negates the E12 number 92 func (z *E12) Neg(x *E12) *E12 { 93 z.C0.Neg(&x.C0) 94 z.C1.Neg(&x.C1) 95 z.C2.Neg(&x.C2) 96 return z 97 } 98 99 // Sub two elements of E12 100 func (z *E12) Sub(x, y *E12) *E12 { 101 z.C0.Sub(&x.C0, &y.C0) 102 z.C1.Sub(&x.C1, &y.C1) 103 z.C2.Sub(&x.C2, &y.C2) 104 return z 105 } 106 107 // Double doubles an element in E12 108 func (z *E12) Double(x *E12) *E12 { 109 z.C0.Double(&x.C0) 110 z.C1.Double(&x.C1) 111 z.C2.Double(&x.C2) 112 return z 113 } 114 115 // MulByNonResidue mul x by (0,1,0) 116 func (z *E12) MulByNonResidue(x *E12) *E12 { 117 z.C2, z.C1, z.C0 = x.C1, x.C0, x.C2 118 z.C0.MulByNonResidue(&z.C0) 119 return z 120 } 121 122 // Mul sets z to the E12 product of x,y, returns z 123 func (z *E12) Mul(x, y *E12) *E12 { 124 // Algorithm 13 from https://eprint.iacr.org/2010/354.pdf 125 var t0, t1, t2, c0, c1, c2, tmp E4 126 t0.Mul(&x.C0, &y.C0) 127 t1.Mul(&x.C1, &y.C1) 128 t2.Mul(&x.C2, &y.C2) 129 130 c0.Add(&x.C1, &x.C2) 131 tmp.Add(&y.C1, &y.C2) 132 c0.Mul(&c0, &tmp).Sub(&c0, &t1).Sub(&c0, &t2).MulByNonResidue(&c0).Add(&c0, &t0) 133 134 c1.Add(&x.C0, &x.C1) 135 tmp.Add(&y.C0, &y.C1) 136 c1.Mul(&c1, &tmp).Sub(&c1, &t0).Sub(&c1, &t1) 137 tmp.MulByNonResidue(&t2) 138 c1.Add(&c1, &tmp) 139 140 tmp.Add(&x.C0, &x.C2) 141 c2.Add(&y.C0, &y.C2).Mul(&c2, &tmp).Sub(&c2, &t0).Sub(&c2, &t2).Add(&c2, &t1) 142 143 z.C0.Set(&c0) 144 z.C1.Set(&c1) 145 z.C2.Set(&c2) 146 147 return z 148 } 149 150 // Square sets z to the E12 product of x,x, returns z 151 func (z *E12) Square(x *E12) *E12 { 152 153 // Algorithm 16 from https://eprint.iacr.org/2010/354.pdf 154 var c4, c5, c1, c2, c3, c0 E4 155 c4.Mul(&x.C0, &x.C1).Double(&c4) 156 c5.Square(&x.C2) 157 c1.MulByNonResidue(&c5).Add(&c1, &c4) 158 c2.Sub(&c4, &c5) 159 c3.Square(&x.C0) 160 c4.Sub(&x.C0, &x.C1).Add(&c4, &x.C2) 161 c5.Mul(&x.C1, &x.C2).Double(&c5) 162 c4.Square(&c4) 163 c0.MulByNonResidue(&c5).Add(&c0, &c3) 164 z.C2.Add(&c2, &c4).Add(&z.C2, &c5).Sub(&z.C2, &c3) 165 z.C0.Set(&c0) 166 z.C1.Set(&c1) 167 168 return z 169 } 170 171 // Inverse an element in E12 172 // 173 // if x == 0, sets and returns z = x 174 func (z *E12) Inverse(x *E12) *E12 { 175 // Algorithm 17 from https://eprint.iacr.org/2010/354.pdf 176 // step 9 is wrong in the paper it's t1-t4 177 var t0, t1, t2, t3, t4, t5, t6, c0, c1, c2, d1, d2 E4 178 t0.Square(&x.C0) 179 t1.Square(&x.C1) 180 t2.Square(&x.C2) 181 t3.Mul(&x.C0, &x.C1) 182 t4.Mul(&x.C0, &x.C2) 183 t5.Mul(&x.C1, &x.C2) 184 c0.MulByNonResidue(&t5).Sub(&t0, &c0) 185 c1.MulByNonResidue(&t2).Sub(&c1, &t3) 186 c2.Sub(&t1, &t4) 187 t6.Mul(&x.C0, &c0) 188 d1.Mul(&x.C2, &c1) 189 d2.Mul(&x.C1, &c2) 190 d1.Add(&d1, &d2).MulByNonResidue(&d1) 191 t6.Add(&t6, &d1) 192 t6.Inverse(&t6) 193 z.C0.Mul(&c0, &t6) 194 z.C1.Mul(&c1, &t6) 195 z.C2.Mul(&c2, &t6) 196 197 return z 198 } 199 200 // BatchInvertE12 returns a new slice with every element inverted. 201 // Uses Montgomery batch inversion trick 202 // 203 // if a[i] == 0, returns result[i] = a[i] 204 func BatchInvertE12(a []E12) []E12 { 205 res := make([]E12, len(a)) 206 if len(a) == 0 { 207 return res 208 } 209 210 zeroes := make([]bool, len(a)) 211 var accumulator E12 212 accumulator.SetOne() 213 214 for i := 0; i < len(a); i++ { 215 if a[i].IsZero() { 216 zeroes[i] = true 217 continue 218 } 219 res[i].Set(&accumulator) 220 accumulator.Mul(&accumulator, &a[i]) 221 } 222 223 accumulator.Inverse(&accumulator) 224 225 for i := len(a) - 1; i >= 0; i-- { 226 if zeroes[i] { 227 continue 228 } 229 res[i].Mul(&res[i], &accumulator) 230 accumulator.Mul(&accumulator, &a[i]) 231 } 232 233 return res 234 } 235 236 // Exp sets z=xᵏ (mod q¹²) and returns it 237 // uses 2-bits windowed method 238 func (z *E12) Exp(x E12, k *big.Int) *E12 { 239 if k.IsUint64() && k.Uint64() == 0 { 240 return z.SetOne() 241 } 242 243 e := k 244 if k.Sign() == -1 { 245 // negative k, we invert 246 // if k < 0: xᵏ (mod q¹²) == (x⁻¹)ᵏ (mod q¹²) 247 x.Inverse(&x) 248 249 // we negate k in a temp big.Int since 250 // Int.Bit(_) of k and -k is different 251 e = bigIntPool.Get().(*big.Int) 252 defer bigIntPool.Put(e) 253 e.Neg(k) 254 } 255 256 var res E12 257 var ops [3]E12 258 259 res.SetOne() 260 ops[0].Set(&x) 261 ops[1].Square(&ops[0]) 262 ops[2].Set(&ops[0]).Mul(&ops[2], &ops[1]) 263 264 b := e.Bytes() 265 for i := range b { 266 w := b[i] 267 mask := byte(0xc0) 268 for j := 0; j < 4; j++ { 269 res.Square(&res).Square(&res) 270 c := (w & mask) >> (6 - 2*j) 271 if c != 0 { 272 res.Mul(&res, &ops[c-1]) 273 } 274 mask = mask >> 2 275 } 276 } 277 z.Set(&res) 278 279 return z 280 } 281 282 // InverseUnitary inverse a unitary element 283 func (z *E12) InverseUnitary(x *E12) *E12 { 284 return z.Conjugate(x) 285 } 286 287 // Conjugate set z to x conjugated and return z 288 func (z *E12) Conjugate(x *E12) *E12 { 289 z.C0.Conjugate(&x.C0) 290 z.C1.Conjugate(&x.C1).Neg(&z.C1) 291 z.C2.Conjugate(&x.C2) 292 return z 293 } 294 295 // MulBy01 multiplication by sparse element (c0,c1,0) 296 func (z *E12) MulBy01(c0, c1 *E4) *E12 { 297 298 var a, b, tmp, t0, t1, t2 E4 299 300 a.Mul(&z.C0, c0) 301 b.Mul(&z.C1, c1) 302 303 tmp.Add(&z.C1, &z.C2) 304 t0.Mul(c1, &tmp) 305 t0.Sub(&t0, &b) 306 t0.MulByNonResidue(&t0) 307 t0.Add(&t0, &a) 308 309 tmp.Add(&z.C0, &z.C2) 310 t2.Mul(c0, &tmp) 311 t2.Sub(&t2, &a) 312 t2.Add(&t2, &b) 313 314 t1.Add(c0, c1) 315 tmp.Add(&z.C0, &z.C1) 316 t1.Mul(&t1, &tmp) 317 t1.Sub(&t1, &a) 318 t1.Sub(&t1, &b) 319 320 z.C0.Set(&t0) 321 z.C1.Set(&t1) 322 z.C2.Set(&t2) 323 324 return z 325 } 326 327 // MulByE2 multiplies an element in E12 by an element in E2 328 func (z *E12) MulByE2(x *E12, y *E4) *E12 { 329 var yCopy E4 330 yCopy.Set(y) 331 z.C0.Mul(&x.C0, &yCopy) 332 z.C1.Mul(&x.C1, &yCopy) 333 z.C2.Mul(&x.C2, &yCopy) 334 return z 335 }