github.com/consensys/gnark-crypto@v0.14.0/ecc/bls12-378/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  		914279102867832731,
    40  		5956798511920709511,
    41  		10193226651174906632,
    42  		329804807099814901,
    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  }