github.com/consensys/gnark-crypto@v0.14.0/ecc/secp256k1/hash_to_g1.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 secp256k1
    18  
    19  import (
    20  	"github.com/consensys/gnark-crypto/ecc/secp256k1/fp"
    21  )
    22  
    23  // MapToCurve1 implements the Shallue and van de Woestijne method, applicable to any elliptic curve in Weierstrass form
    24  // No cofactor clearing or isogeny
    25  // https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#straightline-svdw
    26  func MapToCurve1(u *fp.Element) G1Affine {
    27  	var tv1, tv2, tv3, tv4 fp.Element
    28  	var x1, x2, x3, gx1, gx2, gx, x, y fp.Element
    29  	var one fp.Element
    30  	var gx1NotSquare, gx1SquareOrGx2Not int
    31  
    32  	//constants
    33  	//c1 = g(Z)
    34  	//c2 = -Z / 2
    35  	//c3 = sqrt(-g(Z) * (3 * Z² + 4 * A))     # sgn0(c3) MUST equal 0
    36  	//c4 = -4 * g(Z) / (3 * Z² + 4 * A)
    37  
    38  	Z := fp.Element{4294968273}
    39  	c1 := fp.Element{34359746184}
    40  	c2 := fp.Element{18446744069414583343, 18446744073709551615, 18446744073709551615, 9223372036854775807}
    41  	c3 := fp.Element{17776356894683298668, 8246953344079101458, 5263337950127723085, 5166576015932556431}
    42  	c4 := fp.Element{18446744023601588431, 18446744073709551615, 18446744073709551615, 18446744073709551615}
    43  
    44  	one.SetOne()
    45  
    46  	tv1.Square(u)       //    1.  tv1 = u²
    47  	tv1.Mul(&tv1, &c1)  //    2.  tv1 = tv1 * c1
    48  	tv2.Add(&one, &tv1) //    3.  tv2 = 1 + tv1
    49  	tv1.Sub(&one, &tv1) //    4.  tv1 = 1 - tv1
    50  	tv3.Mul(&tv1, &tv2) //    5.  tv3 = tv1 * tv2
    51  
    52  	tv3.Inverse(&tv3)   //    6.  tv3 = inv0(tv3)
    53  	tv4.Mul(u, &tv1)    //    7.  tv4 = u * tv1
    54  	tv4.Mul(&tv4, &tv3) //    8.  tv4 = tv4 * tv3
    55  	tv4.Mul(&tv4, &c3)  //    9.  tv4 = tv4 * c3
    56  	x1.Sub(&c2, &tv4)   //    10.  x1 = c2 - tv4
    57  
    58  	gx1.Square(&x1) //    11. gx1 = x1²
    59  	//12. gx1 = gx1 + A     All curves in gnark-crypto have A=0 (j-invariant=0). It is crucial to include this step if the curve has nonzero A coefficient.
    60  	gx1.Mul(&gx1, &x1)                 //    13. gx1 = gx1 * x1
    61  	gx1.Add(&gx1, &bCurveCoeff)        //    14. gx1 = gx1 + B
    62  	gx1NotSquare = gx1.Legendre() >> 1 //    15.  e1 = is_square(gx1)
    63  	// gx1NotSquare = 0 if gx1 is a square, -1 otherwise
    64  
    65  	x2.Add(&c2, &tv4) //    16.  x2 = c2 + tv4
    66  	gx2.Square(&x2)   //    17. gx2 = x2²
    67  	//    18. gx2 = gx2 + A     See line 12
    68  	gx2.Mul(&gx2, &x2)          //    19. gx2 = gx2 * x2
    69  	gx2.Add(&gx2, &bCurveCoeff) //    20. gx2 = gx2 + B
    70  
    71  	{
    72  		gx2NotSquare := gx2.Legendre() >> 1              // gx2Square = 0 if gx2 is a square, -1 otherwise
    73  		gx1SquareOrGx2Not = gx2NotSquare | ^gx1NotSquare //    21.  e2 = is_square(gx2) AND NOT e1   # Avoid short-circuit logic ops
    74  	}
    75  
    76  	x3.Square(&tv2)   //    22.  x3 = tv2²
    77  	x3.Mul(&x3, &tv3) //    23.  x3 = x3 * tv3
    78  	x3.Square(&x3)    //    24.  x3 = x3²
    79  	x3.Mul(&x3, &c4)  //    25.  x3 = x3 * c4
    80  
    81  	x3.Add(&x3, &Z)                  //    26.  x3 = x3 + Z
    82  	x.Select(gx1NotSquare, &x1, &x3) //    27.   x = CMOV(x3, x1, e1)   # x = x1 if gx1 is square, else x = x3
    83  	// Select x1 iff gx1 is square iff gx1NotSquare = 0
    84  	x.Select(gx1SquareOrGx2Not, &x2, &x) //    28.   x = CMOV(x, x2, e2)    # x = x2 if gx2 is square and gx1 is not
    85  	// Select x2 iff gx2 is square and gx1 is not, iff gx1SquareOrGx2Not = 0
    86  	gx.Square(&x) //    29.  gx = x²
    87  	//    30.  gx = gx + A
    88  
    89  	gx.Mul(&gx, &x)           //    31.  gx = gx * x
    90  	gx.Add(&gx, &bCurveCoeff) //    32.  gx = gx + B
    91  
    92  	y.Sqrt(&gx)                             //    33.   y = sqrt(gx)
    93  	signsNotEqual := g1Sgn0(u) ^ g1Sgn0(&y) //    34.  e3 = sgn0(u) == sgn0(y)
    94  
    95  	tv1.Neg(&y)
    96  	y.Select(int(signsNotEqual), &y, &tv1) //    35.   y = CMOV(-y, y, e3)       # Select correct sign of y
    97  	return G1Affine{x, y}
    98  }
    99  
   100  // g1Sgn0 is an algebraic substitute for the notion of sign in ordered fields
   101  // Namely, every non-zero quadratic residue in a finite field of characteristic =/= 2 has exactly two square roots, one of each sign
   102  // https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#name-the-sgn0-function
   103  // The sign of an element is not obviously related to that of its Montgomery form
   104  func g1Sgn0(z *fp.Element) uint64 {
   105  
   106  	nonMont := z.Bits()
   107  
   108  	// m == 1
   109  	return nonMont[0] % 2
   110  
   111  }
   112  
   113  // MapToG1 invokes the SVDW map, and guarantees that the result is in g1
   114  func MapToG1(u fp.Element) G1Affine {
   115  	res := MapToCurve1(&u)
   116  	return res
   117  }
   118  
   119  // EncodeToG1 hashes a message to a point on the G1 curve using the SVDW map.
   120  // It is faster than HashToG1, but the result is not uniformly distributed. Unsuitable as a random oracle.
   121  // dst stands for "domain separation tag", a string unique to the construction using the hash function
   122  // https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#roadmap
   123  func EncodeToG1(msg, dst []byte) (G1Affine, error) {
   124  
   125  	var res G1Affine
   126  	u, err := fp.Hash(msg, dst, 1)
   127  	if err != nil {
   128  		return res, err
   129  	}
   130  
   131  	res = MapToCurve1(&u[0])
   132  
   133  	return res, nil
   134  }
   135  
   136  // HashToG1 hashes a message to a point on the G1 curve using the SVDW map.
   137  // Slower than EncodeToG1, but usable as a random oracle.
   138  // dst stands for "domain separation tag", a string unique to the construction using the hash function
   139  // https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#roadmap
   140  func HashToG1(msg, dst []byte) (G1Affine, error) {
   141  	u, err := fp.Hash(msg, dst, 2*1)
   142  	if err != nil {
   143  		return G1Affine{}, err
   144  	}
   145  
   146  	Q0 := MapToCurve1(&u[0])
   147  	Q1 := MapToCurve1(&u[1])
   148  
   149  	var _Q0, _Q1 G1Jac
   150  	_Q0.FromAffine(&Q0)
   151  	_Q1.FromAffine(&Q1).AddAssign(&_Q0)
   152  
   153  	Q1.FromJacobian(&_Q1)
   154  	return Q1, nil
   155  }
   156  
   157  func g1NotZero(x *fp.Element) uint64 {
   158  
   159  	return x[0] | x[1] | x[2] | x[3]
   160  
   161  }