github.com/consensys/gnark-crypto@v0.14.0/ecc/bn254/hash_to_g2.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 bn254
    18  
    19  import (
    20  	"github.com/consensys/gnark-crypto/ecc/bn254/fp"
    21  	"github.com/consensys/gnark-crypto/ecc/bn254/internal/fptower"
    22  )
    23  
    24  // MapToCurve2 implements the Shallue and van de Woestijne method, applicable to any elliptic curve in Weierstrass form
    25  // No cofactor clearing or isogeny
    26  // https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#straightline-svdw
    27  func MapToCurve2(u *fptower.E2) G2Affine {
    28  	var tv1, tv2, tv3, tv4 fptower.E2
    29  	var x1, x2, x3, gx1, gx2, gx, x, y fptower.E2
    30  	var one fptower.E2
    31  	var gx1NotSquare, gx1SquareOrGx2Not int
    32  
    33  	//constants
    34  	//c1 = g(Z)
    35  	//c2 = -Z / 2
    36  	//c3 = sqrt(-g(Z) * (3 * Z² + 4 * A))     # sgn0(c3) MUST equal 0
    37  	//c4 = -4 * g(Z) / (3 * Z² + 4 * A)
    38  
    39  	Z := fptower.E2{
    40  		A0: fp.Element{15230403791020821917, 754611498739239741, 7381016538464732716, 1011752739694698287},
    41  		A1: fp.Element{0},
    42  	}
    43  	c1 := fptower.E2{
    44  		A0: fp.Element{15219334786797146878, 8431472696017589261, 15336528771359260718, 196732871012706162},
    45  		A1: fp.Element{4100506350182530919, 7345568344173317438, 15513160039642431658, 90557763186888013},
    46  	}
    47  	c2 := fptower.E2{
    48  		A0: fp.Element{12997850613838968789, 14304628359724097447, 2950087706404981016, 1237622763554136189},
    49  		A1: fp.Element{0},
    50  	}
    51  	c3 := fptower.E2{
    52  		A0: fp.Element{12298500088583694207, 17447120171744064890, 14097510924717921191, 2278398337453771183},
    53  		A1: fp.Element{4693446565795584099, 18320164443970680666, 6792758484113206563, 2989688171181581768},
    54  	}
    55  	c4 := fptower.E2{
    56  		A0: fp.Element{7191623630069643826, 8333948550768170742, 13001081703983517696, 2062355016518372226},
    57  		A1: fp.Element{11163104453509316115, 7271947710149976975, 4894807947557820282, 3366254582553786647},
    58  	}
    59  
    60  	one.SetOne()
    61  
    62  	tv1.Square(u)       //    1.  tv1 = u²
    63  	tv1.Mul(&tv1, &c1)  //    2.  tv1 = tv1 * c1
    64  	tv2.Add(&one, &tv1) //    3.  tv2 = 1 + tv1
    65  	tv1.Sub(&one, &tv1) //    4.  tv1 = 1 - tv1
    66  	tv3.Mul(&tv1, &tv2) //    5.  tv3 = tv1 * tv2
    67  
    68  	tv3.Inverse(&tv3)   //    6.  tv3 = inv0(tv3)
    69  	tv4.Mul(u, &tv1)    //    7.  tv4 = u * tv1
    70  	tv4.Mul(&tv4, &tv3) //    8.  tv4 = tv4 * tv3
    71  	tv4.Mul(&tv4, &c3)  //    9.  tv4 = tv4 * c3
    72  	x1.Sub(&c2, &tv4)   //    10.  x1 = c2 - tv4
    73  
    74  	gx1.Square(&x1) //    11. gx1 = x1²
    75  	//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.
    76  	gx1.Mul(&gx1, &x1)                 //    13. gx1 = gx1 * x1
    77  	gx1.Add(&gx1, &bTwistCurveCoeff)   //    14. gx1 = gx1 + B
    78  	gx1NotSquare = gx1.Legendre() >> 1 //    15.  e1 = is_square(gx1)
    79  	// gx1NotSquare = 0 if gx1 is a square, -1 otherwise
    80  
    81  	x2.Add(&c2, &tv4) //    16.  x2 = c2 + tv4
    82  	gx2.Square(&x2)   //    17. gx2 = x2²
    83  	//    18. gx2 = gx2 + A     See line 12
    84  	gx2.Mul(&gx2, &x2)               //    19. gx2 = gx2 * x2
    85  	gx2.Add(&gx2, &bTwistCurveCoeff) //    20. gx2 = gx2 + B
    86  
    87  	{
    88  		gx2NotSquare := gx2.Legendre() >> 1              // gx2Square = 0 if gx2 is a square, -1 otherwise
    89  		gx1SquareOrGx2Not = gx2NotSquare | ^gx1NotSquare //    21.  e2 = is_square(gx2) AND NOT e1   # Avoid short-circuit logic ops
    90  	}
    91  
    92  	x3.Square(&tv2)   //    22.  x3 = tv2²
    93  	x3.Mul(&x3, &tv3) //    23.  x3 = x3 * tv3
    94  	x3.Square(&x3)    //    24.  x3 = x3²
    95  	x3.Mul(&x3, &c4)  //    25.  x3 = x3 * c4
    96  
    97  	x3.Add(&x3, &Z)                  //    26.  x3 = x3 + Z
    98  	x.Select(gx1NotSquare, &x1, &x3) //    27.   x = CMOV(x3, x1, e1)   # x = x1 if gx1 is square, else x = x3
    99  	// Select x1 iff gx1 is square iff gx1NotSquare = 0
   100  	x.Select(gx1SquareOrGx2Not, &x2, &x) //    28.   x = CMOV(x, x2, e2)    # x = x2 if gx2 is square and gx1 is not
   101  	// Select x2 iff gx2 is square and gx1 is not, iff gx1SquareOrGx2Not = 0
   102  	gx.Square(&x) //    29.  gx = x²
   103  	//    30.  gx = gx + A
   104  
   105  	gx.Mul(&gx, &x)                //    31.  gx = gx * x
   106  	gx.Add(&gx, &bTwistCurveCoeff) //    32.  gx = gx + B
   107  
   108  	y.Sqrt(&gx)                             //    33.   y = sqrt(gx)
   109  	signsNotEqual := g2Sgn0(u) ^ g2Sgn0(&y) //    34.  e3 = sgn0(u) == sgn0(y)
   110  
   111  	tv1.Neg(&y)
   112  	y.Select(int(signsNotEqual), &y, &tv1) //    35.   y = CMOV(-y, y, e3)       # Select correct sign of y
   113  	return G2Affine{x, y}
   114  }
   115  
   116  // g2Sgn0 is an algebraic substitute for the notion of sign in ordered fields
   117  // Namely, every non-zero quadratic residue in a finite field of characteristic =/= 2 has exactly two square roots, one of each sign
   118  // https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#name-the-sgn0-function
   119  // The sign of an element is not obviously related to that of its Montgomery form
   120  func g2Sgn0(z *fptower.E2) uint64 {
   121  
   122  	nonMont := z.Bits()
   123  
   124  	sign := uint64(0) // 1. sign = 0
   125  	zero := uint64(1) // 2. zero = 1
   126  	var signI uint64
   127  	var zeroI uint64
   128  
   129  	// 3. i = 1
   130  	signI = nonMont.A0[0] % 2 // 4.   sign_i = x_i mod 2
   131  	zeroI = g1NotZero(&nonMont.A0)
   132  	zeroI = 1 ^ (zeroI|-zeroI)>>63 // 5.   zero_i = x_i == 0
   133  	sign = sign | (zero & signI)   // 6.   sign = sign OR (zero AND sign_i) # Avoid short-circuit logic ops
   134  	zero = zero & zeroI            // 7.   zero = zero AND zero_i
   135  	// 3. i = 2
   136  	signI = nonMont.A1[0] % 2 // 4.   sign_i = x_i mod 2
   137  	// 5.   zero_i = x_i == 0
   138  	sign = sign | (zero & signI) // 6.   sign = sign OR (zero AND sign_i) # Avoid short-circuit logic ops
   139  	// 7.   zero = zero AND zero_i
   140  	return sign
   141  
   142  }
   143  
   144  // MapToG2 invokes the SVDW map, and guarantees that the result is in g2
   145  func MapToG2(u fptower.E2) G2Affine {
   146  	res := MapToCurve2(&u)
   147  	res.ClearCofactor(&res)
   148  	return res
   149  }
   150  
   151  // EncodeToG2 hashes a message to a point on the G2 curve using the SVDW map.
   152  // It is faster than HashToG2, but the result is not uniformly distributed. Unsuitable as a random oracle.
   153  // dst stands for "domain separation tag", a string unique to the construction using the hash function
   154  // https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#roadmap
   155  func EncodeToG2(msg, dst []byte) (G2Affine, error) {
   156  
   157  	var res G2Affine
   158  	u, err := fp.Hash(msg, dst, 2)
   159  	if err != nil {
   160  		return res, err
   161  	}
   162  
   163  	res = MapToCurve2(&fptower.E2{
   164  		A0: u[0],
   165  		A1: u[1],
   166  	})
   167  
   168  	res.ClearCofactor(&res)
   169  	return res, nil
   170  }
   171  
   172  // HashToG2 hashes a message to a point on the G2 curve using the SVDW map.
   173  // Slower than EncodeToG2, but usable as a random oracle.
   174  // dst stands for "domain separation tag", a string unique to the construction using the hash function
   175  // https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#roadmap
   176  func HashToG2(msg, dst []byte) (G2Affine, error) {
   177  	u, err := fp.Hash(msg, dst, 2*2)
   178  	if err != nil {
   179  		return G2Affine{}, err
   180  	}
   181  
   182  	Q0 := MapToCurve2(&fptower.E2{
   183  		A0: u[0],
   184  		A1: u[1],
   185  	})
   186  	Q1 := MapToCurve2(&fptower.E2{
   187  		A0: u[2+0],
   188  		A1: u[2+1],
   189  	})
   190  
   191  	var _Q0, _Q1 G2Jac
   192  	_Q0.FromAffine(&Q0)
   193  	_Q1.FromAffine(&Q1).AddAssign(&_Q0)
   194  
   195  	_Q1.ClearCofactor(&_Q1)
   196  
   197  	Q1.FromJacobian(&_Q1)
   198  	return Q1, nil
   199  }
   200  
   201  func g2NotZero(x *fptower.E2) uint64 {
   202  	//Assuming G1 is over Fp and that if hashing is available for G2, it also is for G1
   203  	return g1NotZero(&x.A0) | g1NotZero(&x.A1)
   204  
   205  }