github.com/consensys/gnark-crypto@v0.14.0/field/goldilocks/element_ops_purego.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  // Code generated by consensys/gnark-crypto DO NOT EDIT
    16  
    17  package goldilocks
    18  
    19  import "math/bits"
    20  
    21  // MulBy3 x *= 3 (mod q)
    22  func MulBy3(x *Element) {
    23  	var y Element
    24  	y.SetUint64(3)
    25  	x.Mul(x, &y)
    26  }
    27  
    28  // MulBy5 x *= 5 (mod q)
    29  func MulBy5(x *Element) {
    30  	var y Element
    31  	y.SetUint64(5)
    32  	x.Mul(x, &y)
    33  }
    34  
    35  // MulBy13 x *= 13 (mod q)
    36  func MulBy13(x *Element) {
    37  	var y Element
    38  	y.SetUint64(13)
    39  	x.Mul(x, &y)
    40  }
    41  
    42  // Butterfly sets
    43  //
    44  //	a = a + b (mod q)
    45  //	b = a - b (mod q)
    46  func Butterfly(a, b *Element) {
    47  	_butterflyGeneric(a, b)
    48  }
    49  
    50  func fromMont(z *Element) {
    51  	_fromMontGeneric(z)
    52  }
    53  
    54  func reduce(z *Element) {
    55  	_reduceGeneric(z)
    56  }
    57  
    58  // Mul z = x * y (mod q)
    59  func (z *Element) Mul(x, y *Element) *Element {
    60  
    61  	// In fact, since the modulus R fits on one register, the CIOS algorithm gets reduced to standard REDC (textbook Montgomery reduction):
    62  	// hi, lo := x * y
    63  	// m := (lo * qInvNeg) mod R
    64  	// (*) r := (hi * R + lo + m * q) / R
    65  	// reduce r if necessary
    66  
    67  	// On the emphasized line, we get r = hi + (lo + m * q) / R
    68  	// If we write hi2, lo2 = m * q then R | m * q - lo2 ⇒ R | (lo * qInvNeg) q - lo2 = -lo - lo2
    69  	// This shows lo + lo2 = 0 mod R. i.e. lo + lo2 = 0 if lo = 0 and R otherwise.
    70  	// Which finally gives (lo + m * q) / R = (lo + lo2 + R hi2) / R = hi2 + (lo+lo2) / R = hi2 + (lo != 0)
    71  	// This "optimization" lets us do away with one MUL instruction on ARM architectures and is available for all q < R.
    72  
    73  	var r uint64
    74  	hi, lo := bits.Mul64(x[0], y[0])
    75  	if lo != 0 {
    76  		hi++ // x[0] * y[0] ≤ 2¹²⁸ - 2⁶⁵ + 1, meaning hi ≤ 2⁶⁴ - 2 so no need to worry about overflow
    77  	}
    78  	m := lo * qInvNeg
    79  	hi2, _ := bits.Mul64(m, q)
    80  	r, carry := bits.Add64(hi2, hi, 0)
    81  
    82  	if carry != 0 || r >= q {
    83  		// we need to reduce
    84  		r -= q
    85  	}
    86  	z[0] = r
    87  
    88  	return z
    89  }
    90  
    91  // Square z = x * x (mod q)
    92  func (z *Element) Square(x *Element) *Element {
    93  	// see Mul for algorithm documentation
    94  
    95  	// In fact, since the modulus R fits on one register, the CIOS algorithm gets reduced to standard REDC (textbook Montgomery reduction):
    96  	// hi, lo := x * y
    97  	// m := (lo * qInvNeg) mod R
    98  	// (*) r := (hi * R + lo + m * q) / R
    99  	// reduce r if necessary
   100  
   101  	// On the emphasized line, we get r = hi + (lo + m * q) / R
   102  	// If we write hi2, lo2 = m * q then R | m * q - lo2 ⇒ R | (lo * qInvNeg) q - lo2 = -lo - lo2
   103  	// This shows lo + lo2 = 0 mod R. i.e. lo + lo2 = 0 if lo = 0 and R otherwise.
   104  	// Which finally gives (lo + m * q) / R = (lo + lo2 + R hi2) / R = hi2 + (lo+lo2) / R = hi2 + (lo != 0)
   105  	// This "optimization" lets us do away with one MUL instruction on ARM architectures and is available for all q < R.
   106  
   107  	var r uint64
   108  	hi, lo := bits.Mul64(x[0], x[0])
   109  	if lo != 0 {
   110  		hi++ // x[0] * y[0] ≤ 2¹²⁸ - 2⁶⁵ + 1, meaning hi ≤ 2⁶⁴ - 2 so no need to worry about overflow
   111  	}
   112  	m := lo * qInvNeg
   113  	hi2, _ := bits.Mul64(m, q)
   114  	r, carry := bits.Add64(hi2, hi, 0)
   115  
   116  	if carry != 0 || r >= q {
   117  		// we need to reduce
   118  		r -= q
   119  	}
   120  	z[0] = r
   121  
   122  	return z
   123  }