github.com/consensys/gnark-crypto@v0.14.0/ecc/bw6-761/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 bw6761 18 19 import ( 20 "github.com/consensys/gnark-crypto/ecc/bw6-761/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 {8909527437822417859, 3882721843441849971, 10272758549140236519, 14003949960675888070, 3082674948893537730, 15057121805406331995, 9473729116041321980, 4728985833820774787, 8655877921490901299, 4190069830971789310, 5954844214359654504, 3167048922498340}, 32 {18108974101656748848, 2338690158884275892, 6508602482182596491, 4145012576748966774, 3414660410706516893, 2573833883260883150, 6164918126664265221, 14548675305047459086, 16639788212446610270, 18398701356395340891, 6095608892147913870, 52477293239851844}, 33 {9054487050828374424, 10392717116296913754, 3254301241091298245, 11295878325229259195, 1707330205353258446, 10510288978485217383, 3082459063332132610, 7274337652523729543, 17543266143078080943, 9199350678197670445, 3047804446073956935, 26238646619925922}, 34 }, 35 x) 36 } 37 38 func g1IsogenyXDenominator(dst *fp.Element, x *fp.Element) { 39 g1EvalPolynomial(dst, 40 true, 41 []fp.Element{ 42 {289919226011913130, 13019990545710127566, 4409829457611675068, 13030600802816293865, 15696054586628993047, 9353078419867322391, 5664203968291172875, 5090703637405909511, 17774776443174359288, 10018561694451762270, 12632664537138156478, 46143195394855163}, 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 {9682176248893090322, 2627273429413213811, 1155528216520376823, 1734722477587034670, 13988724381275734601, 17289533515091656624, 2581744904959040264, 16263110058591731584, 231510300096278344, 819211016254091825, 9584860091064199543, 19904548774929241}, 53 {14209419774307277534, 17047004024416446496, 12006050873920801753, 7382661640201664267, 5619017447097588016, 4097933930624713700, 13346346473479882378, 10676906847998820547, 18226515408490094624, 14642258392207702855, 11108762314101178010, 33023872084892202}, 54 {8716717078775571656, 12731407275181189647, 9762903723273894736, 15440890901978225969, 5121990616059775339, 13084122861746100533, 9247377189996397831, 3376268883861637013, 15736310281815139598, 9151307960883459721, 9143413338221870806, 78715939859777766}, 55 {4527243525414187212, 14419730595003232685, 10850522657400424930, 5647939162614629597, 10077037139531405031, 5255144489242608691, 10764601568520842113, 12860540863116640579, 17995005108393816279, 13823047375953611030, 1523902223036978467, 13119323309962961}, 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 {2800676018270776722, 404959871884879410, 14461481433037540995, 11679465559666498996, 9481399069190242817, 18023312492583527742, 3661347334798803492, 4152305114258814443, 3867985292375803742, 13391491194096551019, 1887398969680023676, 20806804014868441}, 67 {4201014027406165083, 9830811844682094923, 3245478075846759876, 8295826302644972687, 14222098603785364226, 8588224665165739997, 14715393039052981047, 6228457671388221664, 15025349975418481421, 1640492717435274912, 12054470491374811323, 31210206022302661}, 68 {1690257235147301491, 3999098444797791463, 11640570174130445566, 9646961545794767555, 1990010047514562840, 18364734666159086263, 16718249672545350429, 7166856194535316732, 10485397052507485351, 16714307291500037780, 4352991985123392508, 56546597402289384}, 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 // https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#name-optimized-sqrt_ratio-for-q- (3 mod 4) 95 var tv1 fp.Element 96 tv1.Square(v) // 1. tv1 = v² 97 var tv2 fp.Element 98 tv2.Mul(u, v) // 2. tv2 = u * v 99 tv1.Mul(&tv1, &tv2) // 3. tv1 = tv1 * tv2 100 101 var y1 fp.Element 102 { 103 var c1 big.Int 104 // c1 = 1722862596078933134849197420568914385619917228134037527378447540052405855560872934021920795822352921910216141938446653362790439780138561939837377924781325399737901274844627212593135907855899198987974925107492278210691228279767074 105 c1.SetBytes([]byte{72, 186, 9, 62, 224, 243, 130, 180, 97, 242, 80, 1, 62, 191, 207, 174, 73, 134, 26, 160, 116, 81, 162, 20, 160, 157, 123, 224, 33, 239, 144, 92, 30, 233, 142, 57, 97, 58, 70, 64, 243, 174, 191, 201, 109, 8, 193, 33, 162, 114, 59, 68, 190, 127, 100, 28, 119, 52, 247, 28, 250, 255, 203, 166, 40, 69, 176, 149, 153, 234, 62, 5, 131, 62, 43, 186, 188, 41, 13, 249, 164, 79, 154, 28, 0, 0, 32, 189, 39, 64, 0, 0, 0, 0, 34}) // c1 = (q - 3) / 4 # Integer arithmetic 106 107 y1.Exp(tv1, &c1) // 4. y1 = tv1ᶜ¹ 108 } 109 110 y1.Mul(&y1, &tv2) // 5. y1 = y1 * tv2 111 112 var y2 fp.Element 113 // c2 = sqrt(-Z) 114 tv3 := fp.Element{10289215067249928212, 13987875627487618797, 10154775028297877632, 5892581882377791321, 12835424790914788634, 14963278386355512102, 10283221901563449361, 9868336211540881409, 7345304935218488881, 6998778443322886180, 9453359982570584357, 56775348355244645} 115 y2.Mul(&y1, &tv3) // 6. y2 = y1 * c2 116 tv3.Square(&y1) // 7. tv3 = y1² 117 tv3.Mul(&tv3, v) // 8. tv3 = tv3 * v 118 isQNr := tv3.NotEqual(u) // 9. isQR = tv3 == u 119 z.Select(int(isQNr), &y1, &y2) // 10. y = CMOV(y2, y1, isQR) 120 return isQNr 121 } 122 123 // g1MulByZ multiplies x by [2] and stores the result in z 124 func g1MulByZ(z *fp.Element, x *fp.Element) { 125 126 res := *x 127 128 res.Double(&res) 129 130 *z = res 131 } 132 133 // https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#name-simplified-swu-method 134 // MapToCurve1 implements the SSWU map 135 // No cofactor clearing or isogeny 136 func MapToCurve1(u *fp.Element) G1Affine { 137 138 var sswuIsoCurveCoeffA = fp.Element{12169852093062392636, 3867460573998792965, 2540986171999662608, 3377838107874487171, 6313266756742099767, 5994530928773814047, 5007141583730923456, 2345996307867737670, 7096861766432061441, 10014420324597579745, 8416419844935780388, 63340978449966806} 139 var sswuIsoCurveCoeffB = fp.Element{9514135687797572479, 9972495974968977338, 17954535578332286571, 7437044986470910914, 13903267017721129281, 1871129682978723308, 13401268269932482209, 739043012311877982, 12116264695643437343, 1632209977726909861, 3621981106970059143, 65605772132525947} 140 141 var tv1 fp.Element 142 tv1.Square(u) // 1. tv1 = u² 143 144 //mul tv1 by Z 145 g1MulByZ(&tv1, &tv1) // 2. tv1 = Z * tv1 146 147 var tv2 fp.Element 148 tv2.Square(&tv1) // 3. tv2 = tv1² 149 tv2.Add(&tv2, &tv1) // 4. tv2 = tv2 + tv1 150 151 var tv3 fp.Element 152 var tv4 fp.Element 153 tv4.SetOne() 154 tv3.Add(&tv2, &tv4) // 5. tv3 = tv2 + 1 155 tv3.Mul(&tv3, &sswuIsoCurveCoeffB) // 6. tv3 = B * tv3 156 157 tv2NZero := g1NotZero(&tv2) 158 159 // tv4 = Z 160 tv4 = fp.Element{289919226011913130, 13019990545710127566, 4409829457611675068, 13030600802816293865, 15696054586628993047, 9353078419867322391, 5664203968291172875, 5090703637405909511, 17774776443174359288, 10018561694451762270, 12632664537138156478, 46143195394855163} 161 162 tv2.Neg(&tv2) 163 tv4.Select(int(tv2NZero), &tv4, &tv2) // 7. tv4 = CMOV(Z, -tv2, tv2 != 0) 164 tv4.Mul(&tv4, &sswuIsoCurveCoeffA) // 8. tv4 = A * tv4 165 166 tv2.Square(&tv3) // 9. tv2 = tv3² 167 168 var tv6 fp.Element 169 tv6.Square(&tv4) // 10. tv6 = tv4² 170 171 var tv5 fp.Element 172 tv5.Mul(&tv6, &sswuIsoCurveCoeffA) // 11. tv5 = A * tv6 173 174 tv2.Add(&tv2, &tv5) // 12. tv2 = tv2 + tv5 175 tv2.Mul(&tv2, &tv3) // 13. tv2 = tv2 * tv3 176 tv6.Mul(&tv6, &tv4) // 14. tv6 = tv6 * tv4 177 178 tv5.Mul(&tv6, &sswuIsoCurveCoeffB) // 15. tv5 = B * tv6 179 tv2.Add(&tv2, &tv5) // 16. tv2 = tv2 + tv5 180 181 var x fp.Element 182 x.Mul(&tv1, &tv3) // 17. x = tv1 * tv3 183 184 var y1 fp.Element 185 gx1NSquare := g1SqrtRatio(&y1, &tv2, &tv6) // 18. (is_gx1_square, y1) = sqrt_ratio(tv2, tv6) 186 187 var y fp.Element 188 y.Mul(&tv1, u) // 19. y = tv1 * u 189 190 y.Mul(&y, &y1) // 20. y = y * y1 191 192 x.Select(int(gx1NSquare), &tv3, &x) // 21. x = CMOV(x, tv3, is_gx1_square) 193 y.Select(int(gx1NSquare), &y1, &y) // 22. y = CMOV(y, y1, is_gx1_square) 194 195 y1.Neg(&y) 196 y.Select(int(g1Sgn0(u)^g1Sgn0(&y)), &y, &y1) 197 198 // 23. e1 = sgn0(u) == sgn0(y) 199 // 24. y = CMOV(-y, y, e1) 200 201 x.Div(&x, &tv4) // 25. x = x / tv4 202 203 return G1Affine{x, y} 204 } 205 206 func g1EvalPolynomial(z *fp.Element, monic bool, coefficients []fp.Element, x *fp.Element) { 207 dst := coefficients[len(coefficients)-1] 208 209 if monic { 210 dst.Add(&dst, x) 211 } 212 213 for i := len(coefficients) - 2; i >= 0; i-- { 214 dst.Mul(&dst, x) 215 dst.Add(&dst, &coefficients[i]) 216 } 217 218 z.Set(&dst) 219 } 220 221 // g1Sgn0 is an algebraic substitute for the notion of sign in ordered fields 222 // Namely, every non-zero quadratic residue in a finite field of characteristic =/= 2 has exactly two square roots, one of each sign 223 // https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#name-the-sgn0-function 224 // The sign of an element is not obviously related to that of its Montgomery form 225 func g1Sgn0(z *fp.Element) uint64 { 226 227 nonMont := z.Bits() 228 229 // m == 1 230 return nonMont[0] % 2 231 232 } 233 234 // MapToG1 invokes the SSWU map, and guarantees that the result is in g1 235 func MapToG1(u fp.Element) G1Affine { 236 res := MapToCurve1(&u) 237 //this is in an isogenous curve 238 g1Isogeny(&res) 239 res.ClearCofactor(&res) 240 return res 241 } 242 243 // EncodeToG1 hashes a message to a point on the G1 curve using the SSWU map. 244 // It is faster than HashToG1, but the result is not uniformly distributed. Unsuitable as a random oracle. 245 // dst stands for "domain separation tag", a string unique to the construction using the hash function 246 // https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#roadmap 247 func EncodeToG1(msg, dst []byte) (G1Affine, error) { 248 249 var res G1Affine 250 u, err := fp.Hash(msg, dst, 1) 251 if err != nil { 252 return res, err 253 } 254 255 res = MapToCurve1(&u[0]) 256 257 //this is in an isogenous curve 258 g1Isogeny(&res) 259 res.ClearCofactor(&res) 260 return res, nil 261 } 262 263 // HashToG1 hashes a message to a point on the G1 curve using the SSWU map. 264 // Slower than EncodeToG1, but usable as a random oracle. 265 // dst stands for "domain separation tag", a string unique to the construction using the hash function 266 // https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#roadmap 267 func HashToG1(msg, dst []byte) (G1Affine, error) { 268 u, err := fp.Hash(msg, dst, 2*1) 269 if err != nil { 270 return G1Affine{}, err 271 } 272 273 Q0 := MapToCurve1(&u[0]) 274 Q1 := MapToCurve1(&u[1]) 275 276 //TODO (perf): Add in E' first, then apply isogeny 277 g1Isogeny(&Q0) 278 g1Isogeny(&Q1) 279 280 var _Q0, _Q1 G1Jac 281 _Q0.FromAffine(&Q0) 282 _Q1.FromAffine(&Q1).AddAssign(&_Q0) 283 284 _Q1.ClearCofactor(&_Q1) 285 286 Q1.FromJacobian(&_Q1) 287 return Q1, nil 288 } 289 290 func g1NotZero(x *fp.Element) uint64 { 291 292 return x[0] | x[1] | x[2] | x[3] | x[4] | x[5] | x[6] | x[7] | x[8] | x[9] | x[10] | x[11] 293 294 }