github.com/consensys/gnark-crypto@v0.14.0/ecc/bls12-377/fr/element_ops_purego.go (about) 1 //go:build !amd64 || purego 2 // +build !amd64 purego 3 4 // Copyright 2020 ConsenSys Software Inc. 5 // 6 // Licensed under the Apache License, Version 2.0 (the "License"); 7 // you may not use this file except in compliance with the License. 8 // You may obtain a copy of the License at 9 // 10 // http://www.apache.org/licenses/LICENSE-2.0 11 // 12 // Unless required by applicable law or agreed to in writing, software 13 // distributed under the License is distributed on an "AS IS" BASIS, 14 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 // See the License for the specific language governing permissions and 16 // limitations under the License. 17 18 // Code generated by consensys/gnark-crypto DO NOT EDIT 19 20 package fr 21 22 import "math/bits" 23 24 // MulBy3 x *= 3 (mod q) 25 func MulBy3(x *Element) { 26 _x := *x 27 x.Double(x).Add(x, &_x) 28 } 29 30 // MulBy5 x *= 5 (mod q) 31 func MulBy5(x *Element) { 32 _x := *x 33 x.Double(x).Double(x).Add(x, &_x) 34 } 35 36 // MulBy13 x *= 13 (mod q) 37 func MulBy13(x *Element) { 38 var y = Element{ 39 18434640649710993230, 40 12067750152132099910, 41 14024878721438555919, 42 347766975729306096, 43 } 44 x.Mul(x, &y) 45 } 46 47 // Butterfly sets 48 // 49 // a = a + b (mod q) 50 // b = a - b (mod q) 51 func Butterfly(a, b *Element) { 52 _butterflyGeneric(a, b) 53 } 54 55 func fromMont(z *Element) { 56 _fromMontGeneric(z) 57 } 58 59 func reduce(z *Element) { 60 _reduceGeneric(z) 61 } 62 63 // Mul z = x * y (mod q) 64 // 65 // x and y must be less than q 66 func (z *Element) Mul(x, y *Element) *Element { 67 68 // Implements CIOS multiplication -- section 2.3.2 of Tolga Acar's thesis 69 // https://www.microsoft.com/en-us/research/wp-content/uploads/1998/06/97Acar.pdf 70 // 71 // The algorithm: 72 // 73 // for i=0 to N-1 74 // C := 0 75 // for j=0 to N-1 76 // (C,t[j]) := t[j] + x[j]*y[i] + C 77 // (t[N+1],t[N]) := t[N] + C 78 // 79 // C := 0 80 // m := t[0]*q'[0] mod D 81 // (C,_) := t[0] + m*q[0] 82 // for j=1 to N-1 83 // (C,t[j-1]) := t[j] + m*q[j] + C 84 // 85 // (C,t[N-1]) := t[N] + C 86 // t[N] := t[N+1] + C 87 // 88 // → N is the number of machine words needed to store the modulus q 89 // → D is the word size. For example, on a 64-bit architecture D is 2 64 90 // → x[i], y[i], q[i] is the ith word of the numbers x,y,q 91 // → q'[0] is the lowest word of the number -q⁻¹ mod r. This quantity is pre-computed, as it does not depend on the inputs. 92 // → t is a temporary array of size N+2 93 // → C, S are machine words. A pair (C,S) refers to (hi-bits, lo-bits) of a two-word number 94 // 95 // As described here https://hackmd.io/@gnark/modular_multiplication we can get rid of one carry chain and simplify: 96 // (also described in https://eprint.iacr.org/2022/1400.pdf annex) 97 // 98 // for i=0 to N-1 99 // (A,t[0]) := t[0] + x[0]*y[i] 100 // m := t[0]*q'[0] mod W 101 // C,_ := t[0] + m*q[0] 102 // for j=1 to N-1 103 // (A,t[j]) := t[j] + x[j]*y[i] + A 104 // (C,t[j-1]) := t[j] + m*q[j] + C 105 // 106 // t[N-1] = C + A 107 // 108 // This optimization saves 5N + 2 additions in the algorithm, and can be used whenever the highest bit 109 // of the modulus is zero (and not all of the remaining bits are set). 110 111 var t0, t1, t2, t3 uint64 112 var u0, u1, u2, u3 uint64 113 { 114 var c0, c1, c2 uint64 115 v := x[0] 116 u0, t0 = bits.Mul64(v, y[0]) 117 u1, t1 = bits.Mul64(v, y[1]) 118 u2, t2 = bits.Mul64(v, y[2]) 119 u3, t3 = bits.Mul64(v, y[3]) 120 t1, c0 = bits.Add64(u0, t1, 0) 121 t2, c0 = bits.Add64(u1, t2, c0) 122 t3, c0 = bits.Add64(u2, t3, c0) 123 c2, _ = bits.Add64(u3, 0, c0) 124 125 m := qInvNeg * t0 126 127 u0, c1 = bits.Mul64(m, q0) 128 _, c0 = bits.Add64(t0, c1, 0) 129 u1, c1 = bits.Mul64(m, q1) 130 t0, c0 = bits.Add64(t1, c1, c0) 131 u2, c1 = bits.Mul64(m, q2) 132 t1, c0 = bits.Add64(t2, c1, c0) 133 u3, c1 = bits.Mul64(m, q3) 134 135 t2, c0 = bits.Add64(0, c1, c0) 136 u3, _ = bits.Add64(u3, 0, c0) 137 t0, c0 = bits.Add64(u0, t0, 0) 138 t1, c0 = bits.Add64(u1, t1, c0) 139 t2, c0 = bits.Add64(u2, t2, c0) 140 c2, _ = bits.Add64(c2, 0, c0) 141 t2, c0 = bits.Add64(t3, t2, 0) 142 t3, _ = bits.Add64(u3, c2, c0) 143 144 } 145 { 146 var c0, c1, c2 uint64 147 v := x[1] 148 u0, c1 = bits.Mul64(v, y[0]) 149 t0, c0 = bits.Add64(c1, t0, 0) 150 u1, c1 = bits.Mul64(v, y[1]) 151 t1, c0 = bits.Add64(c1, t1, c0) 152 u2, c1 = bits.Mul64(v, y[2]) 153 t2, c0 = bits.Add64(c1, t2, c0) 154 u3, c1 = bits.Mul64(v, y[3]) 155 t3, c0 = bits.Add64(c1, t3, c0) 156 157 c2, _ = bits.Add64(0, 0, c0) 158 t1, c0 = bits.Add64(u0, t1, 0) 159 t2, c0 = bits.Add64(u1, t2, c0) 160 t3, c0 = bits.Add64(u2, t3, c0) 161 c2, _ = bits.Add64(u3, c2, c0) 162 163 m := qInvNeg * t0 164 165 u0, c1 = bits.Mul64(m, q0) 166 _, c0 = bits.Add64(t0, c1, 0) 167 u1, c1 = bits.Mul64(m, q1) 168 t0, c0 = bits.Add64(t1, c1, c0) 169 u2, c1 = bits.Mul64(m, q2) 170 t1, c0 = bits.Add64(t2, c1, c0) 171 u3, c1 = bits.Mul64(m, q3) 172 173 t2, c0 = bits.Add64(0, c1, c0) 174 u3, _ = bits.Add64(u3, 0, c0) 175 t0, c0 = bits.Add64(u0, t0, 0) 176 t1, c0 = bits.Add64(u1, t1, c0) 177 t2, c0 = bits.Add64(u2, t2, c0) 178 c2, _ = bits.Add64(c2, 0, c0) 179 t2, c0 = bits.Add64(t3, t2, 0) 180 t3, _ = bits.Add64(u3, c2, c0) 181 182 } 183 { 184 var c0, c1, c2 uint64 185 v := x[2] 186 u0, c1 = bits.Mul64(v, y[0]) 187 t0, c0 = bits.Add64(c1, t0, 0) 188 u1, c1 = bits.Mul64(v, y[1]) 189 t1, c0 = bits.Add64(c1, t1, c0) 190 u2, c1 = bits.Mul64(v, y[2]) 191 t2, c0 = bits.Add64(c1, t2, c0) 192 u3, c1 = bits.Mul64(v, y[3]) 193 t3, c0 = bits.Add64(c1, t3, c0) 194 195 c2, _ = bits.Add64(0, 0, c0) 196 t1, c0 = bits.Add64(u0, t1, 0) 197 t2, c0 = bits.Add64(u1, t2, c0) 198 t3, c0 = bits.Add64(u2, t3, c0) 199 c2, _ = bits.Add64(u3, c2, c0) 200 201 m := qInvNeg * t0 202 203 u0, c1 = bits.Mul64(m, q0) 204 _, c0 = bits.Add64(t0, c1, 0) 205 u1, c1 = bits.Mul64(m, q1) 206 t0, c0 = bits.Add64(t1, c1, c0) 207 u2, c1 = bits.Mul64(m, q2) 208 t1, c0 = bits.Add64(t2, c1, c0) 209 u3, c1 = bits.Mul64(m, q3) 210 211 t2, c0 = bits.Add64(0, c1, c0) 212 u3, _ = bits.Add64(u3, 0, c0) 213 t0, c0 = bits.Add64(u0, t0, 0) 214 t1, c0 = bits.Add64(u1, t1, c0) 215 t2, c0 = bits.Add64(u2, t2, c0) 216 c2, _ = bits.Add64(c2, 0, c0) 217 t2, c0 = bits.Add64(t3, t2, 0) 218 t3, _ = bits.Add64(u3, c2, c0) 219 220 } 221 { 222 var c0, c1, c2 uint64 223 v := x[3] 224 u0, c1 = bits.Mul64(v, y[0]) 225 t0, c0 = bits.Add64(c1, t0, 0) 226 u1, c1 = bits.Mul64(v, y[1]) 227 t1, c0 = bits.Add64(c1, t1, c0) 228 u2, c1 = bits.Mul64(v, y[2]) 229 t2, c0 = bits.Add64(c1, t2, c0) 230 u3, c1 = bits.Mul64(v, y[3]) 231 t3, c0 = bits.Add64(c1, t3, c0) 232 233 c2, _ = bits.Add64(0, 0, c0) 234 t1, c0 = bits.Add64(u0, t1, 0) 235 t2, c0 = bits.Add64(u1, t2, c0) 236 t3, c0 = bits.Add64(u2, t3, c0) 237 c2, _ = bits.Add64(u3, c2, c0) 238 239 m := qInvNeg * t0 240 241 u0, c1 = bits.Mul64(m, q0) 242 _, c0 = bits.Add64(t0, c1, 0) 243 u1, c1 = bits.Mul64(m, q1) 244 t0, c0 = bits.Add64(t1, c1, c0) 245 u2, c1 = bits.Mul64(m, q2) 246 t1, c0 = bits.Add64(t2, c1, c0) 247 u3, c1 = bits.Mul64(m, q3) 248 249 t2, c0 = bits.Add64(0, c1, c0) 250 u3, _ = bits.Add64(u3, 0, c0) 251 t0, c0 = bits.Add64(u0, t0, 0) 252 t1, c0 = bits.Add64(u1, t1, c0) 253 t2, c0 = bits.Add64(u2, t2, c0) 254 c2, _ = bits.Add64(c2, 0, c0) 255 t2, c0 = bits.Add64(t3, t2, 0) 256 t3, _ = bits.Add64(u3, c2, c0) 257 258 } 259 z[0] = t0 260 z[1] = t1 261 z[2] = t2 262 z[3] = t3 263 264 // if z ⩾ q → z -= q 265 if !z.smallerThanModulus() { 266 var b uint64 267 z[0], b = bits.Sub64(z[0], q0, 0) 268 z[1], b = bits.Sub64(z[1], q1, b) 269 z[2], b = bits.Sub64(z[2], q2, b) 270 z[3], _ = bits.Sub64(z[3], q3, b) 271 } 272 return z 273 } 274 275 // Square z = x * x (mod q) 276 // 277 // x must be less than q 278 func (z *Element) Square(x *Element) *Element { 279 // see Mul for algorithm documentation 280 281 var t0, t1, t2, t3 uint64 282 var u0, u1, u2, u3 uint64 283 { 284 var c0, c1, c2 uint64 285 v := x[0] 286 u0, t0 = bits.Mul64(v, x[0]) 287 u1, t1 = bits.Mul64(v, x[1]) 288 u2, t2 = bits.Mul64(v, x[2]) 289 u3, t3 = bits.Mul64(v, x[3]) 290 t1, c0 = bits.Add64(u0, t1, 0) 291 t2, c0 = bits.Add64(u1, t2, c0) 292 t3, c0 = bits.Add64(u2, t3, c0) 293 c2, _ = bits.Add64(u3, 0, c0) 294 295 m := qInvNeg * t0 296 297 u0, c1 = bits.Mul64(m, q0) 298 _, c0 = bits.Add64(t0, c1, 0) 299 u1, c1 = bits.Mul64(m, q1) 300 t0, c0 = bits.Add64(t1, c1, c0) 301 u2, c1 = bits.Mul64(m, q2) 302 t1, c0 = bits.Add64(t2, c1, c0) 303 u3, c1 = bits.Mul64(m, q3) 304 305 t2, c0 = bits.Add64(0, c1, c0) 306 u3, _ = bits.Add64(u3, 0, c0) 307 t0, c0 = bits.Add64(u0, t0, 0) 308 t1, c0 = bits.Add64(u1, t1, c0) 309 t2, c0 = bits.Add64(u2, t2, c0) 310 c2, _ = bits.Add64(c2, 0, c0) 311 t2, c0 = bits.Add64(t3, t2, 0) 312 t3, _ = bits.Add64(u3, c2, c0) 313 314 } 315 { 316 var c0, c1, c2 uint64 317 v := x[1] 318 u0, c1 = bits.Mul64(v, x[0]) 319 t0, c0 = bits.Add64(c1, t0, 0) 320 u1, c1 = bits.Mul64(v, x[1]) 321 t1, c0 = bits.Add64(c1, t1, c0) 322 u2, c1 = bits.Mul64(v, x[2]) 323 t2, c0 = bits.Add64(c1, t2, c0) 324 u3, c1 = bits.Mul64(v, x[3]) 325 t3, c0 = bits.Add64(c1, t3, c0) 326 327 c2, _ = bits.Add64(0, 0, c0) 328 t1, c0 = bits.Add64(u0, t1, 0) 329 t2, c0 = bits.Add64(u1, t2, c0) 330 t3, c0 = bits.Add64(u2, t3, c0) 331 c2, _ = bits.Add64(u3, c2, c0) 332 333 m := qInvNeg * t0 334 335 u0, c1 = bits.Mul64(m, q0) 336 _, c0 = bits.Add64(t0, c1, 0) 337 u1, c1 = bits.Mul64(m, q1) 338 t0, c0 = bits.Add64(t1, c1, c0) 339 u2, c1 = bits.Mul64(m, q2) 340 t1, c0 = bits.Add64(t2, c1, c0) 341 u3, c1 = bits.Mul64(m, q3) 342 343 t2, c0 = bits.Add64(0, c1, c0) 344 u3, _ = bits.Add64(u3, 0, c0) 345 t0, c0 = bits.Add64(u0, t0, 0) 346 t1, c0 = bits.Add64(u1, t1, c0) 347 t2, c0 = bits.Add64(u2, t2, c0) 348 c2, _ = bits.Add64(c2, 0, c0) 349 t2, c0 = bits.Add64(t3, t2, 0) 350 t3, _ = bits.Add64(u3, c2, c0) 351 352 } 353 { 354 var c0, c1, c2 uint64 355 v := x[2] 356 u0, c1 = bits.Mul64(v, x[0]) 357 t0, c0 = bits.Add64(c1, t0, 0) 358 u1, c1 = bits.Mul64(v, x[1]) 359 t1, c0 = bits.Add64(c1, t1, c0) 360 u2, c1 = bits.Mul64(v, x[2]) 361 t2, c0 = bits.Add64(c1, t2, c0) 362 u3, c1 = bits.Mul64(v, x[3]) 363 t3, c0 = bits.Add64(c1, t3, c0) 364 365 c2, _ = bits.Add64(0, 0, c0) 366 t1, c0 = bits.Add64(u0, t1, 0) 367 t2, c0 = bits.Add64(u1, t2, c0) 368 t3, c0 = bits.Add64(u2, t3, c0) 369 c2, _ = bits.Add64(u3, c2, c0) 370 371 m := qInvNeg * t0 372 373 u0, c1 = bits.Mul64(m, q0) 374 _, c0 = bits.Add64(t0, c1, 0) 375 u1, c1 = bits.Mul64(m, q1) 376 t0, c0 = bits.Add64(t1, c1, c0) 377 u2, c1 = bits.Mul64(m, q2) 378 t1, c0 = bits.Add64(t2, c1, c0) 379 u3, c1 = bits.Mul64(m, q3) 380 381 t2, c0 = bits.Add64(0, c1, c0) 382 u3, _ = bits.Add64(u3, 0, c0) 383 t0, c0 = bits.Add64(u0, t0, 0) 384 t1, c0 = bits.Add64(u1, t1, c0) 385 t2, c0 = bits.Add64(u2, t2, c0) 386 c2, _ = bits.Add64(c2, 0, c0) 387 t2, c0 = bits.Add64(t3, t2, 0) 388 t3, _ = bits.Add64(u3, c2, c0) 389 390 } 391 { 392 var c0, c1, c2 uint64 393 v := x[3] 394 u0, c1 = bits.Mul64(v, x[0]) 395 t0, c0 = bits.Add64(c1, t0, 0) 396 u1, c1 = bits.Mul64(v, x[1]) 397 t1, c0 = bits.Add64(c1, t1, c0) 398 u2, c1 = bits.Mul64(v, x[2]) 399 t2, c0 = bits.Add64(c1, t2, c0) 400 u3, c1 = bits.Mul64(v, x[3]) 401 t3, c0 = bits.Add64(c1, t3, c0) 402 403 c2, _ = bits.Add64(0, 0, c0) 404 t1, c0 = bits.Add64(u0, t1, 0) 405 t2, c0 = bits.Add64(u1, t2, c0) 406 t3, c0 = bits.Add64(u2, t3, c0) 407 c2, _ = bits.Add64(u3, c2, c0) 408 409 m := qInvNeg * t0 410 411 u0, c1 = bits.Mul64(m, q0) 412 _, c0 = bits.Add64(t0, c1, 0) 413 u1, c1 = bits.Mul64(m, q1) 414 t0, c0 = bits.Add64(t1, c1, c0) 415 u2, c1 = bits.Mul64(m, q2) 416 t1, c0 = bits.Add64(t2, c1, c0) 417 u3, c1 = bits.Mul64(m, q3) 418 419 t2, c0 = bits.Add64(0, c1, c0) 420 u3, _ = bits.Add64(u3, 0, c0) 421 t0, c0 = bits.Add64(u0, t0, 0) 422 t1, c0 = bits.Add64(u1, t1, c0) 423 t2, c0 = bits.Add64(u2, t2, c0) 424 c2, _ = bits.Add64(c2, 0, c0) 425 t2, c0 = bits.Add64(t3, t2, 0) 426 t3, _ = bits.Add64(u3, c2, c0) 427 428 } 429 z[0] = t0 430 z[1] = t1 431 z[2] = t2 432 z[3] = t3 433 434 // if z ⩾ q → z -= q 435 if !z.smallerThanModulus() { 436 var b uint64 437 z[0], b = bits.Sub64(z[0], q0, 0) 438 z[1], b = bits.Sub64(z[1], q1, b) 439 z[2], b = bits.Sub64(z[2], q2, b) 440 z[3], _ = bits.Sub64(z[3], q3, b) 441 } 442 return z 443 }