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 }