github.com/consensys/gnark-crypto@v0.14.0/ecc/bls24-315/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 bls24315
    18  
    19  import (
    20  	"github.com/consensys/gnark-crypto/ecc/bls24-315/fp"
    21  
    22  	"math/big"
    23  )
    24  
    25  //Note: This only works for simple extensions
    26  
    27  func g1IsogenyXNumerator(dst *fp.Element, x *fp.Element) {
    28  	g1EvalPolynomial(dst,
    29  		false,
    30  		[]fp.Element{
    31  			{11620002718874663739, 4984467296741409765, 9174718300976205935, 11374294140644765434, 331965326722599209},
    32  			{12794915441326992831, 3515443655574390653, 6174257928039766159, 70148989344615692, 200953992158149919},
    33  			{5852384876649512947, 11848499933279379168, 12693517207910261404, 4355336966086013201, 153982054162701797},
    34  		},
    35  		x)
    36  }
    37  
    38  func g1IsogenyXDenominator(dst *fp.Element, x *fp.Element) {
    39  	g1EvalPolynomial(dst,
    40  		true,
    41  		[]fp.Element{
    42  			{16605520835351066362, 4532778258980819953, 11041097066391022716, 6626569051763865297, 118015358745724890},
    43  		},
    44  		x)
    45  }
    46  
    47  func g1IsogenyYNumerator(dst *fp.Element, x *fp.Element, y *fp.Element) {
    48  	var _dst fp.Element
    49  	g1EvalPolynomial(&_dst,
    50  		false,
    51  		[]fp.Element{
    52  			{9734843649657667679, 9905469488516037607, 12244225131002460472, 12160927269755757379, 293726840634836990},
    53  			{332611309977308143, 8673449249147179720, 7968180610051701274, 525286427825436485, 27337445552095458},
    54  			{5937151911073875102, 12114288429387176123, 10459089249045026662, 1691716757613274170, 129980835765506182},
    55  			{6958041652386594810, 8306499057468875249, 14372428283824529086, 591175209446655968, 248441179553069595},
    56  		},
    57  		x)
    58  
    59  	dst.Mul(&_dst, y)
    60  }
    61  
    62  func g1IsogenyYDenominator(dst *fp.Element, x *fp.Element) {
    63  	g1EvalPolynomial(dst,
    64  		true,
    65  		[]fp.Element{
    66  			{7466136663908942255, 5910124112997814042, 598236406339551119, 15948603688162126360, 216078840945103380},
    67  			{16886107642822413408, 14927238232380936652, 17792216571653695247, 7051181952824703829, 174959651533410931},
    68  			{4859375930510419181, 8833836595284088531, 17071951839434271380, 4605949628774745540, 11145771293737278},
    69  		},
    70  		x)
    71  }
    72  
    73  func g1Isogeny(p *G1Affine) {
    74  
    75  	den := make([]fp.Element, 2)
    76  
    77  	g1IsogenyYDenominator(&den[1], &p.X)
    78  	g1IsogenyXDenominator(&den[0], &p.X)
    79  
    80  	g1IsogenyYNumerator(&p.Y, &p.X, &p.Y)
    81  	g1IsogenyXNumerator(&p.X, &p.X)
    82  
    83  	den = fp.BatchInvert(den)
    84  
    85  	p.X.Mul(&p.X, &den[0])
    86  	p.Y.Mul(&p.Y, &den[1])
    87  }
    88  
    89  // g1SqrtRatio computes the square root of u/v and returns 0 iff u/v was indeed a quadratic residue
    90  // if not, we get sqrt(Z * u / v). Recall that Z is non-residue
    91  // If v = 0, u/v is meaningless and the output is unspecified, without raising an error.
    92  // The main idea is that since the computation of the square root involves taking large powers of u/v, the inversion of v can be avoided
    93  func g1SqrtRatio(z *fp.Element, u *fp.Element, v *fp.Element) uint64 {
    94  
    95  	// https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#name-sqrt_ratio-for-any-field
    96  
    97  	tv1 := fp.Element{11195128742969911322, 1359304652430195240, 15267589139354181340, 10518360976114966361, 300769513466036652} //tv1 = c6
    98  
    99  	var tv2, tv3, tv4, tv5 fp.Element
   100  	var exp big.Int
   101  	// c4 = 1048575 = 2²⁰ - 1
   102  	// q is odd so c1 is at least 1.
   103  	exp.SetBytes([]byte{15, 255, 255})
   104  
   105  	tv2.Exp(*v, &exp) // 2. tv2 = vᶜ⁴
   106  	tv3.Square(&tv2)  // 3. tv3 = tv2²
   107  	tv3.Mul(&tv3, v)  // 4. tv3 = tv3 * v
   108  	tv5.Mul(u, &tv3)  // 5. tv5 = u * tv3
   109  
   110  	// c3 = 18932887415653914611351818986134037849871398170907377879650252106493894621432467626129921
   111  	exp.SetBytes([]byte{38, 17, 208, 21, 172, 54, 178, 134, 159, 186, 76, 95, 75, 226, 245, 126, 246, 14, 128, 213, 19, 208, 215, 2, 16, 247, 46, 210, 149, 239, 40, 19, 127, 64, 23, 250, 1})
   112  
   113  	tv5.Exp(tv5, &exp)  // 6. tv5 = tv5ᶜ³
   114  	tv5.Mul(&tv5, &tv2) // 7. tv5 = tv5 * tv2
   115  	tv2.Mul(&tv5, v)    // 8. tv2 = tv5 * v
   116  	tv3.Mul(&tv5, u)    // 9. tv3 = tv5 * u
   117  	tv4.Mul(&tv3, &tv2) // 10. tv4 = tv3 * tv2
   118  
   119  	// c5 = 524288
   120  	exp.SetBytes([]byte{8, 0, 0})
   121  	tv5.Exp(tv4, &exp)      // 11. tv5 = tv4ᶜ⁵
   122  	isQNr := g1NotOne(&tv5) // 12. isQR = tv5 == 1
   123  	c7 := fp.Element{1141794007209116247, 256324699145650176, 2958838397954514392, 9976887947641032208, 153331829745922234}
   124  	tv2.Mul(&tv3, &c7)                 // 13. tv2 = tv3 * c7
   125  	tv5.Mul(&tv4, &tv1)                // 14. tv5 = tv4 * tv1
   126  	tv3.Select(int(isQNr), &tv3, &tv2) // 15. tv3 = CMOV(tv2, tv3, isQR)
   127  	tv4.Select(int(isQNr), &tv4, &tv5) // 16. tv4 = CMOV(tv5, tv4, isQR)
   128  	exp.Lsh(big.NewInt(1), 20-2)       // 18, 19: tv5 = 2ⁱ⁻² for i = c1
   129  
   130  	for i := 20; i >= 2; i-- { // 17. for i in (c1, c1 - 1, ..., 2):
   131  
   132  		tv5.Exp(tv4, &exp)               // 20.    tv5 = tv4ᵗᵛ⁵
   133  		nE1 := g1NotOne(&tv5)            // 21.    e1 = tv5 == 1
   134  		tv2.Mul(&tv3, &tv1)              // 22.    tv2 = tv3 * tv1
   135  		tv1.Mul(&tv1, &tv1)              // 23.    tv1 = tv1 * tv1    Why not write square?
   136  		tv5.Mul(&tv4, &tv1)              // 24.    tv5 = tv4 * tv1
   137  		tv3.Select(int(nE1), &tv3, &tv2) // 25.    tv3 = CMOV(tv2, tv3, e1)
   138  		tv4.Select(int(nE1), &tv4, &tv5) // 26.    tv4 = CMOV(tv5, tv4, e1)
   139  
   140  		if i > 2 {
   141  			exp.Rsh(&exp, 1) // 18, 19. tv5 = 2ⁱ⁻²
   142  		}
   143  	}
   144  
   145  	*z = tv3
   146  	return isQNr
   147  }
   148  
   149  func g1NotOne(x *fp.Element) uint64 {
   150  
   151  	var one fp.Element
   152  	return one.SetOne().NotEqual(x)
   153  
   154  }
   155  
   156  // g1MulByZ multiplies x by [13] and stores the result in z
   157  func g1MulByZ(z *fp.Element, x *fp.Element) {
   158  
   159  	res := *x
   160  
   161  	res.Double(&res)
   162  	res.Add(&res, x)
   163  	res.Double(&res)
   164  	res.Double(&res)
   165  	res.Add(&res, x)
   166  
   167  	*z = res
   168  }
   169  
   170  // https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#name-simplified-swu-method
   171  // MapToCurve1 implements the SSWU map
   172  // No cofactor clearing or isogeny
   173  func MapToCurve1(u *fp.Element) G1Affine {
   174  
   175  	var sswuIsoCurveCoeffA = fp.Element{5402807948305211529, 9163880483319140034, 7646126700453841420, 11071466103913358468, 124200740526673728}
   176  	var sswuIsoCurveCoeffB = fp.Element{16058189711238232929, 8302337653269510588, 11411933349841587630, 8954038365926617417, 177308873523699836}
   177  
   178  	var tv1 fp.Element
   179  	tv1.Square(u) // 1.  tv1 = u²
   180  
   181  	//mul tv1 by Z
   182  	g1MulByZ(&tv1, &tv1) // 2.  tv1 = Z * tv1
   183  
   184  	var tv2 fp.Element
   185  	tv2.Square(&tv1)    // 3.  tv2 = tv1²
   186  	tv2.Add(&tv2, &tv1) // 4.  tv2 = tv2 + tv1
   187  
   188  	var tv3 fp.Element
   189  	var tv4 fp.Element
   190  	tv4.SetOne()
   191  	tv3.Add(&tv2, &tv4)                // 5.  tv3 = tv2 + 1
   192  	tv3.Mul(&tv3, &sswuIsoCurveCoeffB) // 6.  tv3 = B * tv3
   193  
   194  	tv2NZero := g1NotZero(&tv2)
   195  
   196  	// tv4 = Z
   197  	tv4 = fp.Element{8178485296672800069, 8476448362227282520, 14180928431697993131, 4308307642551989706, 120359802761433421}
   198  
   199  	tv2.Neg(&tv2)
   200  	tv4.Select(int(tv2NZero), &tv4, &tv2) // 7.  tv4 = CMOV(Z, -tv2, tv2 != 0)
   201  	tv4.Mul(&tv4, &sswuIsoCurveCoeffA)    // 8.  tv4 = A * tv4
   202  
   203  	tv2.Square(&tv3) // 9.  tv2 = tv3²
   204  
   205  	var tv6 fp.Element
   206  	tv6.Square(&tv4) // 10. tv6 = tv4²
   207  
   208  	var tv5 fp.Element
   209  	tv5.Mul(&tv6, &sswuIsoCurveCoeffA) // 11. tv5 = A * tv6
   210  
   211  	tv2.Add(&tv2, &tv5) // 12. tv2 = tv2 + tv5
   212  	tv2.Mul(&tv2, &tv3) // 13. tv2 = tv2 * tv3
   213  	tv6.Mul(&tv6, &tv4) // 14. tv6 = tv6 * tv4
   214  
   215  	tv5.Mul(&tv6, &sswuIsoCurveCoeffB) // 15. tv5 = B * tv6
   216  	tv2.Add(&tv2, &tv5)                // 16. tv2 = tv2 + tv5
   217  
   218  	var x fp.Element
   219  	x.Mul(&tv1, &tv3) // 17.   x = tv1 * tv3
   220  
   221  	var y1 fp.Element
   222  	gx1NSquare := g1SqrtRatio(&y1, &tv2, &tv6) // 18. (is_gx1_square, y1) = sqrt_ratio(tv2, tv6)
   223  
   224  	var y fp.Element
   225  	y.Mul(&tv1, u) // 19.   y = tv1 * u
   226  
   227  	y.Mul(&y, &y1) // 20.   y = y * y1
   228  
   229  	x.Select(int(gx1NSquare), &tv3, &x) // 21.   x = CMOV(x, tv3, is_gx1_square)
   230  	y.Select(int(gx1NSquare), &y1, &y)  // 22.   y = CMOV(y, y1, is_gx1_square)
   231  
   232  	y1.Neg(&y)
   233  	y.Select(int(g1Sgn0(u)^g1Sgn0(&y)), &y, &y1)
   234  
   235  	// 23.  e1 = sgn0(u) == sgn0(y)
   236  	// 24.   y = CMOV(-y, y, e1)
   237  
   238  	x.Div(&x, &tv4) // 25.   x = x / tv4
   239  
   240  	return G1Affine{x, y}
   241  }
   242  
   243  func g1EvalPolynomial(z *fp.Element, monic bool, coefficients []fp.Element, x *fp.Element) {
   244  	dst := coefficients[len(coefficients)-1]
   245  
   246  	if monic {
   247  		dst.Add(&dst, x)
   248  	}
   249  
   250  	for i := len(coefficients) - 2; i >= 0; i-- {
   251  		dst.Mul(&dst, x)
   252  		dst.Add(&dst, &coefficients[i])
   253  	}
   254  
   255  	z.Set(&dst)
   256  }
   257  
   258  // g1Sgn0 is an algebraic substitute for the notion of sign in ordered fields
   259  // Namely, every non-zero quadratic residue in a finite field of characteristic =/= 2 has exactly two square roots, one of each sign
   260  // https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#name-the-sgn0-function
   261  // The sign of an element is not obviously related to that of its Montgomery form
   262  func g1Sgn0(z *fp.Element) uint64 {
   263  
   264  	nonMont := z.Bits()
   265  
   266  	// m == 1
   267  	return nonMont[0] % 2
   268  
   269  }
   270  
   271  // MapToG1 invokes the SSWU map, and guarantees that the result is in g1
   272  func MapToG1(u fp.Element) G1Affine {
   273  	res := MapToCurve1(&u)
   274  	//this is in an isogenous curve
   275  	g1Isogeny(&res)
   276  	res.ClearCofactor(&res)
   277  	return res
   278  }
   279  
   280  // EncodeToG1 hashes a message to a point on the G1 curve using the SSWU map.
   281  // It is faster than HashToG1, but the result is not uniformly distributed. Unsuitable as a random oracle.
   282  // dst stands for "domain separation tag", a string unique to the construction using the hash function
   283  // https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#roadmap
   284  func EncodeToG1(msg, dst []byte) (G1Affine, error) {
   285  
   286  	var res G1Affine
   287  	u, err := fp.Hash(msg, dst, 1)
   288  	if err != nil {
   289  		return res, err
   290  	}
   291  
   292  	res = MapToCurve1(&u[0])
   293  
   294  	//this is in an isogenous curve
   295  	g1Isogeny(&res)
   296  	res.ClearCofactor(&res)
   297  	return res, nil
   298  }
   299  
   300  // HashToG1 hashes a message to a point on the G1 curve using the SSWU map.
   301  // Slower than EncodeToG1, but usable as a random oracle.
   302  // dst stands for "domain separation tag", a string unique to the construction using the hash function
   303  // https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#roadmap
   304  func HashToG1(msg, dst []byte) (G1Affine, error) {
   305  	u, err := fp.Hash(msg, dst, 2*1)
   306  	if err != nil {
   307  		return G1Affine{}, err
   308  	}
   309  
   310  	Q0 := MapToCurve1(&u[0])
   311  	Q1 := MapToCurve1(&u[1])
   312  
   313  	//TODO (perf): Add in E' first, then apply isogeny
   314  	g1Isogeny(&Q0)
   315  	g1Isogeny(&Q1)
   316  
   317  	var _Q0, _Q1 G1Jac
   318  	_Q0.FromAffine(&Q0)
   319  	_Q1.FromAffine(&Q1).AddAssign(&_Q0)
   320  
   321  	_Q1.ClearCofactor(&_Q1)
   322  
   323  	Q1.FromJacobian(&_Q1)
   324  	return Q1, nil
   325  }
   326  
   327  func g1NotZero(x *fp.Element) uint64 {
   328  
   329  	return x[0] | x[1] | x[2] | x[3] | x[4]
   330  
   331  }