github.com/consensys/gnark-crypto@v0.14.0/ecc/bls24-317/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 bls24317
    18  
    19  import (
    20  	"github.com/consensys/gnark-crypto/ecc/bls24-317/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  			{13523513236317711848, 15327023349232218118, 8703648794266574884, 8264167271110563191, 40794431846902569},
    32  			{8812074666074491586, 50960250954420133, 14056404179861272537, 929938412739573318, 947153270783672532},
    33  			{15051608682446262522, 9488224519772198430, 11710444855428888956, 16398015671457218553, 1029622088557318610},
    34  			{4296820476805851409, 10780602457143466946, 10247933845608112961, 6951059907314751932, 722213278859423782},
    35  			{14764184048304945149, 5865289230433310091, 5581095008736809995, 9208735173835224741, 528727552546926153},
    36  			{11398597359936714397, 1594057801015249474, 13954376621701424207, 16271868308895978452, 690753220876234821},
    37  		},
    38  		x)
    39  }
    40  
    41  func g1IsogenyXDenominator(dst *fp.Element, x *fp.Element) {
    42  	g1EvalPolynomial(dst,
    43  		true,
    44  		[]fp.Element{
    45  			{5399775903125704630, 4517816096475473808, 8510054034683086600, 15646083100922413141, 906999227924553668},
    46  			{828013697853572132, 458878942468938987, 5757230941761973224, 5158770805028806783, 869290263606291835},
    47  			{11118632362304015867, 6158437615457151578, 8167114226690349799, 18398210184903822958, 32908558142489459},
    48  			{17284245259114832476, 13149059755030257718, 10930970338758309391, 1062425496339030960, 261139743832662079},
    49  		},
    50  		x)
    51  }
    52  
    53  func g1IsogenyYNumerator(dst *fp.Element, x *fp.Element, y *fp.Element) {
    54  	var _dst fp.Element
    55  	g1EvalPolynomial(&_dst,
    56  		false,
    57  		[]fp.Element{
    58  			{5736138424590314750, 6015908605773073009, 6156792889286183843, 17896612273365749807, 821435345686805089},
    59  			{9373359301599115869, 655867965241119234, 3304264667834595975, 12237805962366901484, 297609776634465799},
    60  			{3480981777823324659, 9475237666221295368, 11936228663660569620, 16004883291078000733, 694053280005543484},
    61  			{4229115995671887337, 9233280055297188894, 1359384483422747035, 11273993240180143056, 469494085796341224},
    62  			{18113844587232876680, 14242937351038565984, 777537960123335163, 6685524189684440232, 980736769871245076},
    63  			{11922196649017768415, 7237889860522244398, 3155125612682980193, 3938240406780725187, 665921220498498902},
    64  			{3446223578941560630, 13846992323172164671, 12292264306216531556, 7620005162288670125, 97432066185489249},
    65  		},
    66  		x)
    67  
    68  	dst.Mul(&_dst, y)
    69  }
    70  
    71  func g1IsogenyYDenominator(dst *fp.Element, x *fp.Element) {
    72  	g1EvalPolynomial(dst,
    73  		true,
    74  		[]fp.Element{
    75  			{8602082813304143536, 14359122824402329793, 2469007073274644071, 4254406725226729972, 992519966230345268},
    76  			{3085489453415801238, 15662911842127999867, 9714633693652399946, 9543599792786380558, 789455890382293440},
    77  			{17898042109793411276, 8772407166446083546, 16320058043659241709, 18250219114565265632, 721227617678419637},
    78  			{12665654738497754715, 10529888736786073619, 14298592531231225548, 714005056864991408, 1088730156414821854},
    79  			{11181082342903713721, 9065467944505387329, 647327075925674801, 8268923912961120967, 264633289965085690},
    80  			{7479623814962697098, 10500217595690610770, 16396455508137464087, 10817010281363322248, 391709615748993118},
    81  		},
    82  		x)
    83  }
    84  
    85  func g1Isogeny(p *G1Affine) {
    86  
    87  	den := make([]fp.Element, 2)
    88  
    89  	g1IsogenyYDenominator(&den[1], &p.X)
    90  	g1IsogenyXDenominator(&den[0], &p.X)
    91  
    92  	g1IsogenyYNumerator(&p.Y, &p.X, &p.Y)
    93  	g1IsogenyXNumerator(&p.X, &p.X)
    94  
    95  	den = fp.BatchInvert(den)
    96  
    97  	p.X.Mul(&p.X, &den[0])
    98  	p.Y.Mul(&p.Y, &den[1])
    99  }
   100  
   101  // g1SqrtRatio computes the square root of u/v and returns 0 iff u/v was indeed a quadratic residue
   102  // if not, we get sqrt(Z * u / v). Recall that Z is non-residue
   103  // If v = 0, u/v is meaningless and the output is unspecified, without raising an error.
   104  // 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
   105  func g1SqrtRatio(z *fp.Element, u *fp.Element, v *fp.Element) uint64 {
   106  	// https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#name-optimized-sqrt_ratio-for-q- (3 mod 4)
   107  	var tv1 fp.Element
   108  	tv1.Square(v) // 1. tv1 = v²
   109  	var tv2 fp.Element
   110  	tv2.Mul(u, v)       // 2. tv2 = u * v
   111  	tv1.Mul(&tv1, &tv2) // 3. tv1 = tv1 * tv2
   112  
   113  	var y1 fp.Element
   114  	{
   115  		var c1 big.Int
   116  		// c1 = 34098267776073977878774941477068514265486278030354898494302534825976493299308006404506539182762
   117  		c1.SetBytes([]byte{4, 22, 50, 136, 155, 216, 34, 75, 60, 163, 241, 104, 45, 254, 116, 14, 69, 166, 152, 121, 161, 49, 205, 17, 181, 188, 206, 121, 13, 9, 47, 223, 163, 84, 75, 149, 151, 106, 202, 170}) // c1 = (q - 3) / 4     # Integer arithmetic
   118  
   119  		y1.Exp(tv1, &c1) // 4. y1 = tv1ᶜ¹
   120  	}
   121  
   122  	y1.Mul(&y1, &tv2) // 5. y1 = y1 * tv2
   123  
   124  	var y2 fp.Element
   125  	// c2 = sqrt(-Z)
   126  	tv3 := fp.Element{10652859563586318787, 3643689439157831556, 9236201363192486412, 11781990169133948855, 1044489031832785863}
   127  	y2.Mul(&y1, &tv3)              // 6. y2 = y1 * c2
   128  	tv3.Square(&y1)                // 7. tv3 = y1²
   129  	tv3.Mul(&tv3, v)               // 8. tv3 = tv3 * v
   130  	isQNr := tv3.NotEqual(u)       // 9. isQR = tv3 == u
   131  	z.Select(int(isQNr), &y1, &y2) // 10. y = CMOV(y2, y1, isQR)
   132  	return isQNr
   133  }
   134  
   135  // g1MulByZ multiplies x by [8] and stores the result in z
   136  func g1MulByZ(z *fp.Element, x *fp.Element) {
   137  
   138  	res := *x
   139  
   140  	res.Double(&res)
   141  	res.Double(&res)
   142  	res.Double(&res)
   143  
   144  	*z = res
   145  }
   146  
   147  // https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#name-simplified-swu-method
   148  // MapToCurve1 implements the SSWU map
   149  // No cofactor clearing or isogeny
   150  func MapToCurve1(u *fp.Element) G1Affine {
   151  
   152  	var sswuIsoCurveCoeffA = fp.Element{2751493217506761890, 10508083672876982400, 9568653941102734201, 1934905759174260726, 590687129635764257}
   153  	var sswuIsoCurveCoeffB = fp.Element{14477170886729819615, 1154054877908840441, 13400991584556574205, 3277375072715511934, 979998381373634863}
   154  
   155  	var tv1 fp.Element
   156  	tv1.Square(u) // 1.  tv1 = u²
   157  
   158  	//mul tv1 by Z
   159  	g1MulByZ(&tv1, &tv1) // 2.  tv1 = Z * tv1
   160  
   161  	var tv2 fp.Element
   162  	tv2.Square(&tv1)    // 3.  tv2 = tv1²
   163  	tv2.Add(&tv2, &tv1) // 4.  tv2 = tv2 + tv1
   164  
   165  	var tv3 fp.Element
   166  	var tv4 fp.Element
   167  	tv4.SetOne()
   168  	tv3.Add(&tv2, &tv4)                // 5.  tv3 = tv2 + 1
   169  	tv3.Mul(&tv3, &sswuIsoCurveCoeffB) // 6.  tv3 = B * tv3
   170  
   171  	tv2NZero := g1NotZero(&tv2)
   172  
   173  	// tv4 = Z
   174  	tv4 = fp.Element{18400687542797871745, 809728271075671860, 17770696641280178537, 10361798156408411167, 334758614216279309}
   175  
   176  	tv2.Neg(&tv2)
   177  	tv4.Select(int(tv2NZero), &tv4, &tv2) // 7.  tv4 = CMOV(Z, -tv2, tv2 != 0)
   178  	tv4.Mul(&tv4, &sswuIsoCurveCoeffA)    // 8.  tv4 = A * tv4
   179  
   180  	tv2.Square(&tv3) // 9.  tv2 = tv3²
   181  
   182  	var tv6 fp.Element
   183  	tv6.Square(&tv4) // 10. tv6 = tv4²
   184  
   185  	var tv5 fp.Element
   186  	tv5.Mul(&tv6, &sswuIsoCurveCoeffA) // 11. tv5 = A * tv6
   187  
   188  	tv2.Add(&tv2, &tv5) // 12. tv2 = tv2 + tv5
   189  	tv2.Mul(&tv2, &tv3) // 13. tv2 = tv2 * tv3
   190  	tv6.Mul(&tv6, &tv4) // 14. tv6 = tv6 * tv4
   191  
   192  	tv5.Mul(&tv6, &sswuIsoCurveCoeffB) // 15. tv5 = B * tv6
   193  	tv2.Add(&tv2, &tv5)                // 16. tv2 = tv2 + tv5
   194  
   195  	var x fp.Element
   196  	x.Mul(&tv1, &tv3) // 17.   x = tv1 * tv3
   197  
   198  	var y1 fp.Element
   199  	gx1NSquare := g1SqrtRatio(&y1, &tv2, &tv6) // 18. (is_gx1_square, y1) = sqrt_ratio(tv2, tv6)
   200  
   201  	var y fp.Element
   202  	y.Mul(&tv1, u) // 19.   y = tv1 * u
   203  
   204  	y.Mul(&y, &y1) // 20.   y = y * y1
   205  
   206  	x.Select(int(gx1NSquare), &tv3, &x) // 21.   x = CMOV(x, tv3, is_gx1_square)
   207  	y.Select(int(gx1NSquare), &y1, &y)  // 22.   y = CMOV(y, y1, is_gx1_square)
   208  
   209  	y1.Neg(&y)
   210  	y.Select(int(g1Sgn0(u)^g1Sgn0(&y)), &y, &y1)
   211  
   212  	// 23.  e1 = sgn0(u) == sgn0(y)
   213  	// 24.   y = CMOV(-y, y, e1)
   214  
   215  	x.Div(&x, &tv4) // 25.   x = x / tv4
   216  
   217  	return G1Affine{x, y}
   218  }
   219  
   220  func g1EvalPolynomial(z *fp.Element, monic bool, coefficients []fp.Element, x *fp.Element) {
   221  	dst := coefficients[len(coefficients)-1]
   222  
   223  	if monic {
   224  		dst.Add(&dst, x)
   225  	}
   226  
   227  	for i := len(coefficients) - 2; i >= 0; i-- {
   228  		dst.Mul(&dst, x)
   229  		dst.Add(&dst, &coefficients[i])
   230  	}
   231  
   232  	z.Set(&dst)
   233  }
   234  
   235  // g1Sgn0 is an algebraic substitute for the notion of sign in ordered fields
   236  // Namely, every non-zero quadratic residue in a finite field of characteristic =/= 2 has exactly two square roots, one of each sign
   237  // https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#name-the-sgn0-function
   238  // The sign of an element is not obviously related to that of its Montgomery form
   239  func g1Sgn0(z *fp.Element) uint64 {
   240  
   241  	nonMont := z.Bits()
   242  
   243  	// m == 1
   244  	return nonMont[0] % 2
   245  
   246  }
   247  
   248  // MapToG1 invokes the SSWU map, and guarantees that the result is in g1
   249  func MapToG1(u fp.Element) G1Affine {
   250  	res := MapToCurve1(&u)
   251  	//this is in an isogenous curve
   252  	g1Isogeny(&res)
   253  	res.ClearCofactor(&res)
   254  	return res
   255  }
   256  
   257  // EncodeToG1 hashes a message to a point on the G1 curve using the SSWU map.
   258  // It is faster than HashToG1, but the result is not uniformly distributed. Unsuitable as a random oracle.
   259  // dst stands for "domain separation tag", a string unique to the construction using the hash function
   260  // https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#roadmap
   261  func EncodeToG1(msg, dst []byte) (G1Affine, error) {
   262  
   263  	var res G1Affine
   264  	u, err := fp.Hash(msg, dst, 1)
   265  	if err != nil {
   266  		return res, err
   267  	}
   268  
   269  	res = MapToCurve1(&u[0])
   270  
   271  	//this is in an isogenous curve
   272  	g1Isogeny(&res)
   273  	res.ClearCofactor(&res)
   274  	return res, nil
   275  }
   276  
   277  // HashToG1 hashes a message to a point on the G1 curve using the SSWU map.
   278  // Slower than EncodeToG1, but usable as a random oracle.
   279  // dst stands for "domain separation tag", a string unique to the construction using the hash function
   280  // https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#roadmap
   281  func HashToG1(msg, dst []byte) (G1Affine, error) {
   282  	u, err := fp.Hash(msg, dst, 2*1)
   283  	if err != nil {
   284  		return G1Affine{}, err
   285  	}
   286  
   287  	Q0 := MapToCurve1(&u[0])
   288  	Q1 := MapToCurve1(&u[1])
   289  
   290  	//TODO (perf): Add in E' first, then apply isogeny
   291  	g1Isogeny(&Q0)
   292  	g1Isogeny(&Q1)
   293  
   294  	var _Q0, _Q1 G1Jac
   295  	_Q0.FromAffine(&Q0)
   296  	_Q1.FromAffine(&Q1).AddAssign(&_Q0)
   297  
   298  	_Q1.ClearCofactor(&_Q1)
   299  
   300  	Q1.FromJacobian(&_Q1)
   301  	return Q1, nil
   302  }
   303  
   304  func g1NotZero(x *fp.Element) uint64 {
   305  
   306  	return x[0] | x[1] | x[2] | x[3] | x[4]
   307  
   308  }