github.com/consensys/gnark-crypto@v0.14.0/ecc/bw6-633/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-633/fp" 17 ) 18 19 // E3 is a degree-three finite field extension of fp2 20 type E3 struct { 21 A0, A1, A2 fp.Element 22 } 23 24 // Equal returns true if z equals x, false otherwise 25 // TODO can this be deleted? Should be able to use == operator instead 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 stringf 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.A0.SetZero() 41 z.A1.SetZero() 42 z.A2.SetZero() 43 return z 44 } 45 46 // Clone returns a copy of self 47 func (z *E3) Clone() *E3 { 48 return &E3{ 49 A0: z.A0, 50 A1: z.A1, 51 A2: z.A2, 52 } 53 } 54 55 // Set Sets a E3 elmt form another E3 elmt 56 func (z *E3) Set(x *E3) *E3 { 57 z.A0 = x.A0 58 z.A1 = x.A1 59 z.A2 = x.A2 60 return z 61 } 62 63 // SetOne sets z to 1 in Montgomery form and returns z 64 func (z *E3) SetOne() *E3 { 65 z.A0.SetOne() 66 z.A1.SetZero() 67 z.A2.SetZero() 68 return z 69 } 70 71 // SetRandom sets z to a random elmt 72 func (z *E3) SetRandom() (*E3, error) { 73 if _, err := z.A0.SetRandom(); err != nil { 74 return nil, err 75 } 76 if _, err := z.A1.SetRandom(); err != nil { 77 return nil, err 78 } 79 if _, err := z.A2.SetRandom(); err != nil { 80 return nil, err 81 } 82 return z, nil 83 } 84 85 // IsZero returns true if z is zero, false otherwise 86 func (z *E3) IsZero() bool { 87 return z.A0.IsZero() && z.A1.IsZero() && z.A2.IsZero() 88 } 89 90 // IsOne returns true if z is one, false otherwise 91 func (z *E3) IsOne() bool { 92 return z.A0.IsOne() && z.A1.IsZero() && z.A2.IsZero() 93 } 94 95 // Neg negates the E3 number 96 func (z *E3) Neg(x *E3) *E3 { 97 z.A0.Neg(&x.A0) 98 z.A1.Neg(&x.A1) 99 z.A2.Neg(&x.A2) 100 return z 101 } 102 103 // Add adds two elements of E3 104 func (z *E3) Add(x, y *E3) *E3 { 105 z.A0.Add(&x.A0, &y.A0) 106 z.A1.Add(&x.A1, &y.A1) 107 z.A2.Add(&x.A2, &y.A2) 108 return z 109 } 110 111 // Sub subtracts two elements of E3 112 func (z *E3) Sub(x, y *E3) *E3 { 113 z.A0.Sub(&x.A0, &y.A0) 114 z.A1.Sub(&x.A1, &y.A1) 115 z.A2.Sub(&x.A2, &y.A2) 116 return z 117 } 118 119 // Double doubles an element in E3 120 func (z *E3) Double(x *E3) *E3 { 121 z.A0.Double(&x.A0) 122 z.A1.Double(&x.A1) 123 z.A2.Double(&x.A2) 124 return z 125 } 126 127 // String puts E3 elmt in string form 128 func (z *E3) String() string { 129 return (z.A0.String() + "+(" + z.A1.String() + ")*u+(" + z.A2.String() + ")*u**2") 130 } 131 132 // MulByElement multiplies an element in E3 by an element in fp 133 func (z *E3) MulByElement(x *E3, y *fp.Element) *E3 { 134 var yCopy fp.Element 135 yCopy.Set(y) 136 z.A0.Mul(&x.A0, &yCopy) 137 z.A1.Mul(&x.A1, &yCopy) 138 z.A2.Mul(&x.A2, &yCopy) 139 return z 140 } 141 142 // MulBy12 multiplication by sparse element (0,b1,b2) 143 func (x *E3) MulBy12(b1, b2 *fp.Element) *E3 { 144 var t1, t2, c0, tmp, c1, c2 fp.Element 145 t1.Mul(&x.A1, b1) 146 t2.Mul(&x.A2, b2) 147 c0.Add(&x.A1, &x.A2) 148 tmp.Add(b1, b2) 149 c0.Mul(&c0, &tmp) 150 c0.Sub(&c0, &t1) 151 c0.Sub(&c0, &t2) 152 c0.MulByNonResidue(&c0) 153 c1.Add(&x.A0, &x.A1) 154 c1.Mul(&c1, b1) 155 c1.Sub(&c1, &t1) 156 tmp.MulByNonResidue(&t2) 157 c1.Add(&c1, &tmp) 158 tmp.Add(&x.A0, &x.A2) 159 c2.Mul(b2, &tmp) 160 c2.Sub(&c2, &t2) 161 c2.Add(&c2, &t1) 162 163 x.A0 = c0 164 x.A1 = c1 165 x.A2 = c2 166 167 return x 168 } 169 170 // MulBy01 multiplication by sparse element (c0,c1,0) 171 func (z *E3) MulBy01(c0, c1 *fp.Element) *E3 { 172 173 var a, b, tmp, t0, t1, t2 fp.Element 174 175 a.Mul(&z.A0, c0) 176 b.Mul(&z.A1, c1) 177 178 tmp.Add(&z.A1, &z.A2) 179 t0.Mul(c1, &tmp) 180 t0.Sub(&t0, &b) 181 t0.MulByNonResidue(&t0) 182 t0.Add(&t0, &a) 183 184 tmp.Add(&z.A0, &z.A2) 185 t2.Mul(c0, &tmp) 186 t2.Sub(&t2, &a) 187 t2.Add(&t2, &b) 188 189 t1.Add(c0, c1) 190 tmp.Add(&z.A0, &z.A1) 191 t1.Mul(&t1, &tmp) 192 t1.Sub(&t1, &a) 193 t1.Sub(&t1, &b) 194 195 z.A0.Set(&t0) 196 z.A1.Set(&t1) 197 z.A2.Set(&t2) 198 199 return z 200 } 201 202 // MulBy1 multiplication of E6 by sparse element (0, c1, 0) 203 func (z *E3) MulBy1(c1 *fp.Element) *E3 { 204 205 var b, tmp, t0, t1 fp.Element 206 b.Mul(&z.A1, c1) 207 208 tmp.Add(&z.A1, &z.A2) 209 t0.Mul(c1, &tmp) 210 t0.Sub(&t0, &b) 211 t0.MulByNonResidue(&t0) 212 213 tmp.Add(&z.A0, &z.A1) 214 t1.Mul(c1, &tmp) 215 t1.Sub(&t1, &b) 216 217 z.A0.Set(&t0) 218 z.A1.Set(&t1) 219 z.A2.Set(&b) 220 221 return z 222 } 223 224 // Mul sets z to the E3-product of x,y, returns z 225 func (z *E3) Mul(x, y *E3) *E3 { 226 // Karatsuba method for cubic extensions 227 // https://eprint.iacr.org/2006/471.pdf (section 4) 228 var t0, t1, t2, c0, c1, c2, tmp fp.Element 229 t0.Mul(&x.A0, &y.A0) 230 t1.Mul(&x.A1, &y.A1) 231 t2.Mul(&x.A2, &y.A2) 232 233 c0.Add(&x.A1, &x.A2) 234 tmp.Add(&y.A1, &y.A2) 235 c0.Mul(&c0, &tmp).Sub(&c0, &t1).Sub(&c0, &t2).MulByNonResidue(&c0).Add(&c0, &t0) 236 237 c1.Add(&x.A0, &x.A1) 238 tmp.Add(&y.A0, &y.A1) 239 c1.Mul(&c1, &tmp).Sub(&c1, &t0).Sub(&c1, &t1) 240 tmp.MulByNonResidue(&t2) 241 c1.Add(&c1, &tmp) 242 243 tmp.Add(&x.A0, &x.A2) 244 c2.Add(&y.A0, &y.A2).Mul(&c2, &tmp).Sub(&c2, &t0).Sub(&c2, &t2).Add(&c2, &t1) 245 246 z.A0.Set(&c0) 247 z.A1.Set(&c1) 248 z.A2.Set(&c2) 249 250 return z 251 } 252 253 // MulAssign sets z to the E3-product of z,y, returns z 254 func (z *E3) MulAssign(x *E3) *E3 { 255 z.Mul(z, x) 256 return z 257 } 258 259 // Square sets z to the E3-product of x,x, returns z 260 func (z *E3) Square(x *E3) *E3 { 261 262 // Algorithm 16 from https://eprint.iacr.org/2010/354.pdf 263 var c4, c5, c1, c2, c3, c0 fp.Element 264 c4.Mul(&x.A0, &x.A1).Double(&c4) 265 c5.Square(&x.A2) 266 c1.MulByNonResidue(&c5).Add(&c1, &c4) 267 c2.Sub(&c4, &c5) 268 c3.Square(&x.A0) 269 c4.Sub(&x.A0, &x.A1).Add(&c4, &x.A2) 270 c5.Mul(&x.A1, &x.A2).Double(&c5) 271 c4.Square(&c4) 272 c0.MulByNonResidue(&c5).Add(&c0, &c3) 273 z.A2.Add(&c2, &c4).Add(&z.A2, &c5).Sub(&z.A2, &c3) 274 z.A0.Set(&c0) 275 z.A1.Set(&c1) 276 277 return z 278 } 279 280 // MulByNonResidue mul x by (0,1,0) 281 func (z *E3) MulByNonResidue(x *E3) *E3 { 282 z.A2, z.A1, z.A0 = x.A1, x.A0, x.A2 283 z.A0.MulByNonResidue(&z.A0) 284 return z 285 } 286 287 // Inverse an element in E3 288 // 289 // if x == 0, sets and returns z = x 290 func (z *E3) Inverse(x *E3) *E3 { 291 // Algorithm 17 from https://eprint.iacr.org/2010/354.pdf 292 // step 9 is wrong in the paper it's t1-t4 293 var t0, t1, t2, t3, t4, t5, t6, c0, c1, c2, d1, d2 fp.Element 294 t0.Square(&x.A0) 295 t1.Square(&x.A1) 296 t2.Square(&x.A2) 297 t3.Mul(&x.A0, &x.A1) 298 t4.Mul(&x.A0, &x.A2) 299 t5.Mul(&x.A1, &x.A2) 300 c0.MulByNonResidue(&t5).Neg(&c0).Add(&c0, &t0) 301 c1.MulByNonResidue(&t2).Sub(&c1, &t3) 302 c2.Sub(&t1, &t4) 303 t6.Mul(&x.A0, &c0) 304 d1.Mul(&x.A2, &c1) 305 d2.Mul(&x.A1, &c2) 306 d1.Add(&d1, &d2).MulByNonResidue(&d1) 307 t6.Add(&t6, &d1) 308 t6.Inverse(&t6) 309 z.A0.Mul(&c0, &t6) 310 z.A1.Mul(&c1, &t6) 311 z.A2.Mul(&c2, &t6) 312 313 return z 314 } 315 316 // BatchInvertE3 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 BatchInvertE3(a []E3) []E3 { 321 res := make([]E3, len(a)) 322 if len(a) == 0 { 323 return res 324 } 325 326 zeroes := make([]bool, len(a)) 327 var accumulator E3 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 }