github.com/consensys/gnark-crypto@v0.14.0/ecc/bls12-377/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 bls12377 18 19 import ( 20 "github.com/consensys/gnark-crypto/ecc/bls12-377/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 {9381318728011785451, 8795417190580748876, 15171640721257608922, 11815547924113428908, 15499908520243100994, 75408755324413256}, 32 {12414498063752772717, 9915153185132073893, 5598625970987438951, 3342254783599619135, 3349592178919125510, 9993871847068096}, 33 {4662210776746950618, 10687085762534440940, 7484820859645808636, 2221301482234255553, 10609677459585442106, 9950135580589350}, 34 }, 35 x) 36 } 37 38 func g1IsogenyXDenominator(dst *fp.Element, x *fp.Element) { 39 g1EvalPolynomial(dst, 40 true, 41 []fp.Element{ 42 {12764504107591987636, 2767124593109192342, 3947759810240204190, 13369019134398476541, 13398368715676502040, 39975487388272384}, 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 {13844135623281082635, 637899392157745290, 5176720401210677272, 4780940929980393029, 13803251044890140836, 51447363642369244}, 53 {512010462697120695, 609509684909242946, 13763343875136563934, 2839514380057330869, 15407015190976871917, 114223893455203604}, 54 {14191436515319700132, 6479619458373647736, 9513056055282499867, 15178407828209519654, 12166396751953702822, 75539964123849493}, 55 {2331105388373475309, 5343542881267220470, 12965782466677680126, 1110650741117127776, 5304838729792721053, 4975067790294675}, 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 {8694832399336342723, 13482963304561246841, 6984108042366343277, 8355250559073919616, 16937021447778317421, 44890599540624877}, 67 {1100361703846424922, 5005767817281133373, 917019320419705433, 14251746270386956490, 5522097789867984932, 4443041874334878}, 68 {1400024175356859676, 8301373779327577028, 11843279430720612570, 3213569255776326391, 3301617999610402890, 119926462164817154}, 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{7563926049028936178, 2688164645460651601, 12112688591437172399, 3177973240564633687, 14764383749841851163, 52487407124055189} //tv1 = c6 98 99 var tv2, tv3, tv4, tv5 fp.Element 100 var exp big.Int 101 // c4 = 70368744177663 = 2⁴⁶ - 1 102 // q is odd so c1 is at least 1. 103 exp.SetBytes([]byte{63, 255, 255, 255, 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 = 1837921289030710838195067919506396475074392872918698035817074744121558668640693829665401097909504529 111 exp.SetBytes([]byte{3, 92, 116, 140, 47, 138, 33, 213, 140, 118, 11, 128, 217, 66, 146, 118, 52, 69, 179, 230, 1, 234, 39, 30, 61, 230, 196, 95, 116, 18, 144, 0, 46, 22, 186, 136, 96, 0, 0, 1, 10, 17}) 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 = 35184372088832 120 exp.SetBytes([]byte{32, 0, 0, 0, 0, 0}) 121 tv5.Exp(tv4, &exp) // 11. tv5 = tv4ᶜ⁵ 122 isQNr := g1NotOne(&tv5) // 12. isQR = tv5 == 1 123 c7 := fp.Element{13262060633605929793, 16269117706405780335, 1787999441809606207, 11078968899094441280, 17534011895423012165, 96686002316065324} 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), 46-2) // 18, 19: tv5 = 2ⁱ⁻² for i = c1 129 130 for i := 46; 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 [5] 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.Double(&res) 163 res.Add(&res, x) 164 165 *z = res 166 } 167 168 // https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#name-simplified-swu-method 169 // MapToCurve1 implements the SSWU map 170 // No cofactor clearing or isogeny 171 func MapToCurve1(u *fp.Element) G1Affine { 172 173 var sswuIsoCurveCoeffA = fp.Element{17252667382019449424, 8408110001211059699, 18415587021986261264, 10797086888535946954, 9462758283094809199, 54995354010328751} 174 var sswuIsoCurveCoeffB = fp.Element{11130294635325289193, 6502679372128844082, 15863297759487624914, 16270683149854112145, 3560014356538878812, 27923742146399959} 175 176 var tv1 fp.Element 177 tv1.Square(u) // 1. tv1 = u² 178 179 //mul tv1 by Z 180 g1MulByZ(&tv1, &tv1) // 2. tv1 = Z * tv1 181 182 var tv2 fp.Element 183 tv2.Square(&tv1) // 3. tv2 = tv1² 184 tv2.Add(&tv2, &tv1) // 4. tv2 = tv2 + tv1 185 186 var tv3 fp.Element 187 var tv4 fp.Element 188 tv4.SetOne() 189 tv3.Add(&tv2, &tv4) // 5. tv3 = tv2 + 1 190 tv3.Mul(&tv3, &sswuIsoCurveCoeffB) // 6. tv3 = B * tv3 191 192 tv2NZero := g1NotZero(&tv2) 193 194 // tv4 = Z 195 tv4 = fp.Element{9871116327010172167, 9167007004823125620, 18338974479346628539, 5649234265355377548, 13442091487463296847, 77904398905292312} 196 197 tv2.Neg(&tv2) 198 tv4.Select(int(tv2NZero), &tv4, &tv2) // 7. tv4 = CMOV(Z, -tv2, tv2 != 0) 199 tv4.Mul(&tv4, &sswuIsoCurveCoeffA) // 8. tv4 = A * tv4 200 201 tv2.Square(&tv3) // 9. tv2 = tv3² 202 203 var tv6 fp.Element 204 tv6.Square(&tv4) // 10. tv6 = tv4² 205 206 var tv5 fp.Element 207 tv5.Mul(&tv6, &sswuIsoCurveCoeffA) // 11. tv5 = A * tv6 208 209 tv2.Add(&tv2, &tv5) // 12. tv2 = tv2 + tv5 210 tv2.Mul(&tv2, &tv3) // 13. tv2 = tv2 * tv3 211 tv6.Mul(&tv6, &tv4) // 14. tv6 = tv6 * tv4 212 213 tv5.Mul(&tv6, &sswuIsoCurveCoeffB) // 15. tv5 = B * tv6 214 tv2.Add(&tv2, &tv5) // 16. tv2 = tv2 + tv5 215 216 var x fp.Element 217 x.Mul(&tv1, &tv3) // 17. x = tv1 * tv3 218 219 var y1 fp.Element 220 gx1NSquare := g1SqrtRatio(&y1, &tv2, &tv6) // 18. (is_gx1_square, y1) = sqrt_ratio(tv2, tv6) 221 222 var y fp.Element 223 y.Mul(&tv1, u) // 19. y = tv1 * u 224 225 y.Mul(&y, &y1) // 20. y = y * y1 226 227 x.Select(int(gx1NSquare), &tv3, &x) // 21. x = CMOV(x, tv3, is_gx1_square) 228 y.Select(int(gx1NSquare), &y1, &y) // 22. y = CMOV(y, y1, is_gx1_square) 229 230 y1.Neg(&y) 231 y.Select(int(g1Sgn0(u)^g1Sgn0(&y)), &y, &y1) 232 233 // 23. e1 = sgn0(u) == sgn0(y) 234 // 24. y = CMOV(-y, y, e1) 235 236 x.Div(&x, &tv4) // 25. x = x / tv4 237 238 return G1Affine{x, y} 239 } 240 241 func g1EvalPolynomial(z *fp.Element, monic bool, coefficients []fp.Element, x *fp.Element) { 242 dst := coefficients[len(coefficients)-1] 243 244 if monic { 245 dst.Add(&dst, x) 246 } 247 248 for i := len(coefficients) - 2; i >= 0; i-- { 249 dst.Mul(&dst, x) 250 dst.Add(&dst, &coefficients[i]) 251 } 252 253 z.Set(&dst) 254 } 255 256 // g1Sgn0 is an algebraic substitute for the notion of sign in ordered fields 257 // Namely, every non-zero quadratic residue in a finite field of characteristic =/= 2 has exactly two square roots, one of each sign 258 // https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#name-the-sgn0-function 259 // The sign of an element is not obviously related to that of its Montgomery form 260 func g1Sgn0(z *fp.Element) uint64 { 261 262 nonMont := z.Bits() 263 264 // m == 1 265 return nonMont[0] % 2 266 267 } 268 269 // MapToG1 invokes the SSWU map, and guarantees that the result is in g1 270 func MapToG1(u fp.Element) G1Affine { 271 res := MapToCurve1(&u) 272 //this is in an isogenous curve 273 g1Isogeny(&res) 274 res.ClearCofactor(&res) 275 return res 276 } 277 278 // EncodeToG1 hashes a message to a point on the G1 curve using the SSWU map. 279 // It is faster than HashToG1, but the result is not uniformly distributed. Unsuitable as a random oracle. 280 // dst stands for "domain separation tag", a string unique to the construction using the hash function 281 // https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#roadmap 282 func EncodeToG1(msg, dst []byte) (G1Affine, error) { 283 284 var res G1Affine 285 u, err := fp.Hash(msg, dst, 1) 286 if err != nil { 287 return res, err 288 } 289 290 res = MapToCurve1(&u[0]) 291 292 //this is in an isogenous curve 293 g1Isogeny(&res) 294 res.ClearCofactor(&res) 295 return res, nil 296 } 297 298 // HashToG1 hashes a message to a point on the G1 curve using the SSWU map. 299 // Slower than EncodeToG1, but usable as a random oracle. 300 // dst stands for "domain separation tag", a string unique to the construction using the hash function 301 // https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#roadmap 302 func HashToG1(msg, dst []byte) (G1Affine, error) { 303 u, err := fp.Hash(msg, dst, 2*1) 304 if err != nil { 305 return G1Affine{}, err 306 } 307 308 Q0 := MapToCurve1(&u[0]) 309 Q1 := MapToCurve1(&u[1]) 310 311 //TODO (perf): Add in E' first, then apply isogeny 312 g1Isogeny(&Q0) 313 g1Isogeny(&Q1) 314 315 var _Q0, _Q1 G1Jac 316 _Q0.FromAffine(&Q0) 317 _Q1.FromAffine(&Q1).AddAssign(&_Q0) 318 319 _Q1.ClearCofactor(&_Q1) 320 321 Q1.FromJacobian(&_Q1) 322 return Q1, nil 323 } 324 325 func g1NotZero(x *fp.Element) uint64 { 326 327 return x[0] | x[1] | x[2] | x[3] | x[4] | x[5] 328 329 }