github.com/consensys/gnark-crypto@v0.14.0/ecc/bw6-761/internal/fptower/e3.go (about) 1 // Copyright 2020 ConsenSys AG 2 // 3 // You may obtain a copy of the License at 4 // 5 // http://www.apache.org/licenses/LICENSE-2.0 6 // 7 // Unless required by applicable law or agreed to in writing, software 8 // distributed under the License is distributed on an "AS IS" BASIS, 9 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 // See the License for the specific language governing permissions and 11 // limitations under the License. 12 13 package fptower 14 15 import ( 16 "github.com/consensys/gnark-crypto/ecc/bw6-761/fp" 17 ) 18 19 // E3 is a degree-three finite field extension of fp3 20 type E3 struct { 21 A0, A1, A2 fp.Element 22 } 23 24 // Equal returns true if z equals x, false otherwise 25 // note this is more efficient than calling "z == x" 26 func (z *E3) Equal(x *E3) bool { 27 return z.A0.Equal(&x.A0) && z.A1.Equal(&x.A1) && z.A2.Equal(&x.A2) 28 } 29 30 // SetString sets a E3 elmt from string 31 func (z *E3) SetString(s1, s2, s3 string) *E3 { 32 z.A0.SetString(s1) 33 z.A1.SetString(s2) 34 z.A2.SetString(s3) 35 return z 36 } 37 38 // SetZero sets an E3 elmt to zero 39 func (z *E3) SetZero() *E3 { 40 *z = E3{} 41 return z 42 } 43 44 // Clone returns a copy of self 45 func (z *E3) Clone() *E3 { 46 return &E3{ 47 A0: z.A0, 48 A1: z.A1, 49 A2: z.A2, 50 } 51 } 52 53 // Set Sets a E3 elmt form another E3 elmt 54 func (z *E3) Set(x *E3) *E3 { 55 *z = *x 56 return z 57 } 58 59 // SetOne sets z to 1 in Montgomery form and returns z 60 func (z *E3) SetOne() *E3 { 61 z.A0.SetOne() 62 z.A1.SetZero() 63 z.A2.SetZero() 64 return z 65 } 66 67 // SetRandom sets z to a random elmt 68 func (z *E3) SetRandom() (*E3, error) { 69 if _, err := z.A0.SetRandom(); err != nil { 70 return nil, err 71 } 72 if _, err := z.A1.SetRandom(); err != nil { 73 return nil, err 74 } 75 if _, err := z.A2.SetRandom(); err != nil { 76 return nil, err 77 } 78 return z, nil 79 } 80 81 // IsZero returns true if z is zero, false otherwise 82 func (z *E3) IsZero() bool { 83 return z.A0.IsZero() && z.A1.IsZero() && z.A2.IsZero() 84 } 85 86 // IsOne returns true if z is one, false otherwise 87 func (z *E3) IsOne() bool { 88 return z.A0.IsOne() && z.A1.IsZero() && z.A2.IsZero() 89 } 90 91 // Neg negates the E3 number 92 func (z *E3) Neg(x *E3) *E3 { 93 z.A0.Neg(&x.A0) 94 z.A1.Neg(&x.A1) 95 z.A2.Neg(&x.A2) 96 return z 97 } 98 99 // Add adds two elements of E3 100 func (z *E3) Add(x, y *E3) *E3 { 101 z.A0.Add(&x.A0, &y.A0) 102 z.A1.Add(&x.A1, &y.A1) 103 z.A2.Add(&x.A2, &y.A2) 104 return z 105 } 106 107 // Sub subtracts two elements of E3 108 func (z *E3) Sub(x, y *E3) *E3 { 109 z.A0.Sub(&x.A0, &y.A0) 110 z.A1.Sub(&x.A1, &y.A1) 111 z.A2.Sub(&x.A2, &y.A2) 112 return z 113 } 114 115 // Double doubles an element in E3 116 func (z *E3) Double(x *E3) *E3 { 117 z.A0.Double(&x.A0) 118 z.A1.Double(&x.A1) 119 z.A2.Double(&x.A2) 120 return z 121 } 122 123 // String puts E3 elmt in string form 124 func (z *E3) String() string { 125 return (z.A0.String() + "+(" + z.A1.String() + ")*u+(" + z.A2.String() + ")*u**2") 126 } 127 128 // MulByElement multiplies an element in E3 by an element in fp 129 func (z *E3) MulByElement(x *E3, y *fp.Element) *E3 { 130 _y := *y 131 z.A0.Mul(&x.A0, &_y) 132 z.A1.Mul(&x.A1, &_y) 133 z.A2.Mul(&x.A2, &_y) 134 return z 135 } 136 137 // MulBy12 multiplication by sparse element (0,b1,b2) 138 func (x *E3) MulBy12(b1, b2 *fp.Element) *E3 { 139 var t1, t2, c0, tmp, c1, c2 fp.Element 140 t1.Mul(&x.A1, b1) 141 t2.Mul(&x.A2, b2) 142 c0.Add(&x.A1, &x.A2) 143 tmp.Add(b1, b2) 144 c0.Mul(&c0, &tmp) 145 c0.Sub(&c0, &t1) 146 c0.Sub(&c0, &t2) 147 c0.MulByNonResidue(&c0) 148 c1.Add(&x.A0, &x.A1) 149 c1.Mul(&c1, b1) 150 c1.Sub(&c1, &t1) 151 tmp.MulByNonResidue(&t2) 152 c1.Add(&c1, &tmp) 153 tmp.Add(&x.A0, &x.A2) 154 c2.Mul(b2, &tmp) 155 c2.Sub(&c2, &t2) 156 c2.Add(&c2, &t1) 157 158 x.A0 = c0 159 x.A1 = c1 160 x.A2 = c2 161 162 return x 163 } 164 165 // MulBy01 multiplication by sparse element (c0,c1,0) 166 func (z *E3) MulBy01(c0, c1 *fp.Element) *E3 { 167 168 var a, b, tmp, t0, t1, t2 fp.Element 169 170 a.Mul(&z.A0, c0) 171 b.Mul(&z.A1, c1) 172 173 tmp.Add(&z.A1, &z.A2) 174 t0.Mul(c1, &tmp) 175 t0.Sub(&t0, &b) 176 t0.MulByNonResidue(&t0) 177 t0.Add(&t0, &a) 178 179 tmp.Add(&z.A0, &z.A2) 180 t2.Mul(c0, &tmp) 181 t2.Sub(&t2, &a) 182 t2.Add(&t2, &b) 183 184 t1.Add(c0, c1) 185 tmp.Add(&z.A0, &z.A1) 186 t1.Mul(&t1, &tmp) 187 t1.Sub(&t1, &a) 188 t1.Sub(&t1, &b) 189 190 z.A0.Set(&t0) 191 z.A1.Set(&t1) 192 z.A2.Set(&t2) 193 194 return z 195 } 196 197 // MulBy1 multiplication of E6 by sparse element (0, c1, 0) 198 func (z *E3) MulBy1(c1 *fp.Element) *E3 { 199 200 var b, tmp, t0, t1 fp.Element 201 b.Mul(&z.A1, c1) 202 203 tmp.Add(&z.A1, &z.A2) 204 t0.Mul(c1, &tmp) 205 t0.Sub(&t0, &b) 206 t0.MulByNonResidue(&t0) 207 208 tmp.Add(&z.A0, &z.A1) 209 t1.Mul(c1, &tmp) 210 t1.Sub(&t1, &b) 211 212 z.A0.Set(&t0) 213 z.A1.Set(&t1) 214 z.A2.Set(&b) 215 216 return z 217 } 218 219 // Mul sets z to the E3-product of x,y, returns z 220 func (z *E3) Mul(x, y *E3) *E3 { 221 // Karatsuba method for cubic extensions 222 // https://eprint.iacr.org/2006/471.pdf (section 4) 223 var t0, t1, t2, c0, c1, c2, tmp fp.Element 224 t0.Mul(&x.A0, &y.A0) 225 t1.Mul(&x.A1, &y.A1) 226 t2.Mul(&x.A2, &y.A2) 227 228 c0.Add(&x.A1, &x.A2) 229 tmp.Add(&y.A1, &y.A2) 230 c0.Mul(&c0, &tmp).Sub(&c0, &t1).Sub(&c0, &t2).MulByNonResidue(&c0) 231 232 tmp.Add(&x.A0, &x.A2) 233 c2.Add(&y.A0, &y.A2).Mul(&c2, &tmp).Sub(&c2, &t0).Sub(&c2, &t2) 234 235 c1.Add(&x.A0, &x.A1) 236 tmp.Add(&y.A0, &y.A1) 237 c1.Mul(&c1, &tmp).Sub(&c1, &t0).Sub(&c1, &t1) 238 t2.MulByNonResidue(&t2) 239 240 z.A0.Add(&c0, &t0) 241 z.A1.Add(&c1, &t2) 242 z.A2.Add(&c2, &t1) 243 244 return z 245 } 246 247 // MulAssign sets z to the E3-product of z,y, returns z 248 func (z *E3) MulAssign(x *E3) *E3 { 249 return z.Mul(z, x) 250 } 251 252 // Square sets z to the E3-product of x,x, returns z 253 func (z *E3) Square(x *E3) *E3 { 254 255 // Algorithm 16 from https://eprint.iacr.org/2010/354.pdf 256 var c4, c5, c1, c2, c3, c0, c6 fp.Element 257 258 c6.Double(&x.A1) 259 c4.Mul(&x.A0, &c6) // x.A0 * xA1 * 2 260 c5.Square(&x.A2) 261 c1.MulByNonResidue(&c5).Add(&c1, &c4) 262 c2.Sub(&c4, &c5) 263 264 c3.Square(&x.A0) 265 c4.Sub(&x.A0, &x.A1).Add(&c4, &x.A2) 266 c5.Mul(&c6, &x.A2) // x.A1 * xA2 * 2 267 c4.Square(&c4) 268 c0.MulByNonResidue(&c5) 269 c4.Add(&c4, &c5).Sub(&c4, &c3) 270 271 z.A0.Add(&c0, &c3) 272 z.A1 = c1 273 z.A2.Add(&c2, &c4) 274 275 return z 276 } 277 278 // MulByNonResidue mul x by (0,1,0) 279 func (z *E3) MulByNonResidue(x *E3) *E3 { 280 z.A2, z.A1, z.A0 = x.A1, x.A0, x.A2 281 z.A0.MulByNonResidue(&z.A0) 282 return z 283 } 284 285 // Inverse an element in E3 286 // 287 // if x == 0, sets and returns z = x 288 func (z *E3) Inverse(x *E3) *E3 { 289 // Algorithm 17 from https://eprint.iacr.org/2010/354.pdf 290 // step 9 is wrong in the paper it's t1-t4 291 var t0, t1, t2, t3, t4, t5, t6, c0, c1, c2, d1, d2 fp.Element 292 t0.Square(&x.A0) 293 t1.Square(&x.A1) 294 t2.Square(&x.A2) 295 t3.Mul(&x.A0, &x.A1) 296 t4.Mul(&x.A0, &x.A2) 297 t5.Mul(&x.A1, &x.A2) 298 c0.MulByNonResidue(&t5).Neg(&c0).Add(&c0, &t0) 299 c1.MulByNonResidue(&t2).Sub(&c1, &t3) 300 c2.Sub(&t1, &t4) 301 t6.Mul(&x.A0, &c0) 302 d1.Mul(&x.A2, &c1) 303 d2.Mul(&x.A1, &c2) 304 d1.Add(&d1, &d2).MulByNonResidue(&d1) 305 t6.Add(&t6, &d1) 306 t6.Inverse(&t6) 307 z.A0.Mul(&c0, &t6) 308 z.A1.Mul(&c1, &t6) 309 z.A2.Mul(&c2, &t6) 310 311 return z 312 } 313 314 // BatchInvertE3 returns a new slice with every element in a inverted. 315 // It uses Montgomery batch inversion trick. 316 // 317 // if a[i] == 0, returns result[i] = a[i] 318 func BatchInvertE3(a []E3) []E3 { 319 res := make([]E3, len(a)) 320 if len(a) == 0 { 321 return res 322 } 323 324 zeroes := make([]bool, len(a)) 325 var accumulator E3 326 accumulator.SetOne() 327 328 for i := 0; i < len(a); i++ { 329 if a[i].IsZero() { 330 zeroes[i] = true 331 continue 332 } 333 res[i].Set(&accumulator) 334 accumulator.Mul(&accumulator, &a[i]) 335 } 336 337 accumulator.Inverse(&accumulator) 338 339 for i := len(a) - 1; i >= 0; i-- { 340 if zeroes[i] { 341 continue 342 } 343 res[i].Mul(&res[i], &accumulator) 344 accumulator.Mul(&accumulator, &a[i]) 345 } 346 347 return res 348 }