github.com/consensys/gnark-crypto@v0.14.0/internal/generator/ecc/template/sswu.go.tmpl (about) 1 {{define "sswu"}} 2 "math/big" 3 ) 4 {{$isogenyNeeded := notNil .Isogeny}} 5 {{$CoordType := .Point.CoordType}} 6 {{$CurveName := .Point.PointName}} 7 {{$CurveTitle := toTitle $CurveName}} 8 {{$TowerDegree := .Field.Degree}} 9 {{$AffineType := print $CurveTitle "Affine"}} 10 {{$JacType := print $CurveTitle "Jac"}} 11 {{$IsG1 := eq $CurveTitle "G1"}} 12 {{$CurveIndex := select $IsG1 "2" "1"}} 13 {{$package := select (eq $TowerDegree 1) "fptower" "fp"}} 14 {{$sswuCurveACoeff := select $isogenyNeeded "This is meant to produce an error. Since most likely A = 0, there is opportunity for optimizations that need to be looked at." "sswuIsoCurveCoeffA"}} 15 {{$sswuCurveBCoeff := select $isogenyNeeded "bCurveConf" "sswuIsoCurveCoeffB"}} 16 17 //Note: This only works for simple extensions 18 19 20 {{ if $isogenyNeeded }} 21 22 func {{$CurveName}}IsogenyXNumerator(dst *{{$CoordType}}, x *{{$CoordType}}) { 23 {{$CurveName}}EvalPolynomial(dst, 24 false, 25 []{{$CoordType}} { 26 {{- range $c := .Isogeny.XMap.Num}} 27 {{ asElement $c}}, 28 {{- end}} 29 }, 30 x) 31 } 32 33 func {{$CurveName}}IsogenyXDenominator(dst *{{$CoordType}}, x *{{$CoordType}}) { 34 {{$CurveName}}EvalPolynomial(dst, 35 true, 36 []{{$CoordType}} { 37 {{- range $c := .Isogeny.XMap.Den}} 38 {{ asElement $c}}, 39 {{- end}} 40 }, 41 x) 42 } 43 44 func {{$CurveName}}IsogenyYNumerator(dst *{{$CoordType}}, x *{{$CoordType}}, y *{{$CoordType}}) { 45 var _dst {{$CoordType}} 46 {{$CurveName}}EvalPolynomial(&_dst, 47 false, 48 []{{$CoordType}} { 49 {{- range $c := .Isogeny.YMap.Num}} 50 {{ asElement $c}}, 51 {{- end}} 52 }, 53 x) 54 55 dst.Mul(&_dst, y) 56 } 57 58 func {{$CurveName}}IsogenyYDenominator(dst *{{$CoordType}}, x *{{$CoordType}}) { 59 {{$CurveName}}EvalPolynomial(dst, 60 true, 61 []{{$CoordType}} { 62 {{- range $c := .Isogeny.YMap.Den}} 63 {{ asElement $c}}, 64 {{- end}} 65 }, 66 x) 67 } 68 69 func {{$CurveName}}Isogeny(p *{{$AffineType}}) { 70 71 den := make([]{{$CoordType}}, 2) 72 73 {{$CurveName}}IsogenyYDenominator(&den[1], &p.X) 74 {{$CurveName}}IsogenyXDenominator(&den[0], &p.X) 75 76 {{$CurveName}}IsogenyYNumerator(&p.Y, &p.X, &p.Y) 77 {{$CurveName}}IsogenyXNumerator(&p.X, &p.X) 78 79 {{if eq $CoordType "fptower.E2"}} 80 den = {{$package}}.BatchInvertE2(den) 81 {{- else if eq $CoordType "fptower.E4"}} 82 den = {{$package}}.BatchInvertE4(den) 83 {{- else}} 84 den = {{$package}}.BatchInvert(den) 85 {{- end}} 86 87 p.X.Mul(&p.X, &den[0]) 88 p.Y.Mul(&p.Y, &den[1]) 89 } 90 91 {{ end }} 92 93 {{ $cInts := index .PrecomputedParams 0 }} 94 95 {{ $c1Int := index $cInts 0}} 96 {{ $c1IntBytes := printList (bytes $c1Int ) }} 97 98 // {{$CurveName}}SqrtRatio computes the square root of u/v and returns 0 iff u/v was indeed a quadratic residue 99 // if not, we get sqrt(Z * u / v). Recall that Z is non-residue 100 // If v = 0, u/v is meaningless and the output is unspecified, without raising an error. 101 // 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 102 func {{$CurveName}}SqrtRatio(z *{{$CoordType}}, u *{{$CoordType}}, v *{{$CoordType}}) uint64 { 103 {{ if eq (mod .FieldSizeMod256 4) 3 }} // https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#name-optimized-sqrt_ratio-for-q- (3 mod 4) 104 var tv1 {{$CoordType}} 105 tv1.Square(v) // 1. tv1 = v² 106 var tv2 {{$CoordType}} 107 tv2.Mul(u, v) // 2. tv2 = u * v 108 tv1.Mul(&tv1, &tv2) // 3. tv1 = tv1 * tv2 109 110 var y1 {{$CoordType}} 111 { 112 var c1 big.Int 113 // c1 = {{ $c1Int }} 114 c1.SetBytes([]byte{ {{ $c1IntBytes }} }) // c1 = (q - 3) / 4 # Integer arithmetic 115 116 y1.Exp(tv1, &c1) // 4. y1 = tv1ᶜ¹ 117 } 118 119 y1.Mul(&y1, &tv2) // 5. y1 = y1 * tv2 120 121 var y2 {{$CoordType}} 122 // c2 = sqrt(-Z) 123 tv3 := {{$CoordType}} {{ asElement (index .PrecomputedParams 1)}} 124 y2.Mul(&y1, &tv3) // 6. y2 = y1 * c2 125 tv3.Square(&y1) // 7. tv3 = y1² 126 tv3.Mul(&tv3, v) // 8. tv3 = tv3 * v 127 isQNr := tv3.NotEqual(u) // 9. isQR = tv3 == u 128 z.Select(int(isQNr), &y1, &y2) // 10. y = CMOV(y2, y1, isQR) 129 return isQNr 130 } 131 132 {{ end }} 133 134 {{ if eq (mod .FieldSizeMod256 8) 5 }} // https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#name-optimized-sqrt_ratio-for-q-5 (mod 8) 135 136 var tv1, tv2 {{$CoordType}} 137 tv1.Square(v) // 1. tv1 = v² 138 tv2.Mul(&tv1, v) // 2. tv2 = tv1 * v 139 tv1.Square(&tv1) // 3. tv1 = tv1² 140 tv2.Mul(&tv2, u) // 4. tv2 = tv2 * u 141 tv1.Mul(&tv1, &tv2) // 5. tv1 = tv1 * tv2 142 143 var c1 big.Int 144 // c1 = (q - 5) / 8 = {{ $c1Int }} 145 c1.SetBytes([]byte { {{ $c1IntBytes }} }) 146 var y1 {{$CoordType}} 147 y1.Exp(tv1, &c1) // 6. y1 = tv1ᶜ¹ 148 y1.Mul(&y1, &tv2) // 7. y1 = y1 * tv2 149 // c2 = sqrt(-1) 150 c2 := {{$CoordType}} {{asElement (index .PrecomputedParams 1)}} 151 tv1.Mul(&y1, &c2) // 8. tv1 = y1 * c2 152 tv2.Square(&tv1) // 9. tv2 = tv1² 153 tv2.Mul(&tv2, v) // 10. tv2 = tv2 * v 154 // 11. e1 = tv2 == u 155 y1.Select(int(tv2.NotEqual(u)), &tv1, &y1) // 12. y1 = CMOV(y1, tv1, e1) 156 tv2.Square(&y1) // 13. tv2 = y1² 157 tv2.Mul(&tv2, v) // 14. tv2 = tv2 * v 158 isQNr := tv2.NotEqual(u) // 15. isQR = tv2 == u 159 // c3 = sqrt(Z / c2) 160 y2 := {{$CoordType}} {{asElement (index .PrecomputedParams 2)}} 161 y2.Mul(&y1, &y2) // 16. y2 = y1 * c3 162 tv1.Mul(&y2, &c2) // 17. tv1 = y2 * c2 163 tv2.Square(&tv1) // 18. tv2 = tv1² 164 tv2.Mul(&tv2, v) // 19. tv2 = tv2 * v 165 var tv3 {{$CoordType}} 166 // Z = [{{printList .Z}}] 167 {{$CurveName}}MulByZ(&tv3, u) // 20. tv3 = Z * u 168 // 21. e2 = tv2 == tv3 169 y2.Select(int(tv2.NotEqual(&tv3)), &tv1, &y2) // 22. y2 = CMOV(y2, tv1, e2) 170 z.Select(int(isQNr), &y1, &y2) // 23. y = CMOV(y2, y1, isQR) 171 return isQNr 172 } 173 174 {{ end }} 175 176 {{ if eq (mod .FieldSizeMod256 8) 1 }}// https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#name-sqrt_ratio-for-any-field 177 178 {{ $c2Int := index $cInts 1}} 179 {{ $c2IntBytes := printList (bytes $c2Int ) }} 180 181 {{ $c3Int := index $cInts 2}} 182 {{ $c3IntBytes := printList (bytes $c3Int ) }} 183 184 {{ $c4Int := index $cInts 3}} 185 {{ $c4IntBytes := printList (bytes $c4Int ) }} 186 187 {{ $c5Int := index $cInts 4}} 188 {{ $c5IntBytes := printList (bytes $c5Int ) }} 189 190 tv1 := {{$CoordType}} {{asElement (index .PrecomputedParams 1) }} //tv1 = c6 191 192 var tv2, tv3, tv4, tv5 {{$CoordType}} 193 var exp big.Int 194 // c4 = {{ $c4Int }} = 2{{supScr $c1Int}} - 1 195 // q is odd so c1 is at least 1. 196 exp.SetBytes([]byte { {{ $c4IntBytes }} }) 197 198 tv2.Exp(*v, &exp) // 2. tv2 = vᶜ⁴ 199 tv3.Square(&tv2) // 3. tv3 = tv2² 200 tv3.Mul(&tv3, v) // 4. tv3 = tv3 * v 201 tv5.Mul(u, &tv3) // 5. tv5 = u * tv3 202 203 // c3 = {{ $c3Int }} 204 exp.SetBytes([]byte { {{ $c3IntBytes }} }) 205 206 tv5.Exp(tv5, &exp) // 6. tv5 = tv5ᶜ³ 207 tv5.Mul(&tv5, &tv2) // 7. tv5 = tv5 * tv2 208 tv2.Mul(&tv5, v) // 8. tv2 = tv5 * v 209 tv3.Mul(&tv5, u) // 9. tv3 = tv5 * u 210 tv4.Mul(&tv3, &tv2) // 10. tv4 = tv3 * tv2 211 212 // c5 = {{ $c5Int }} 213 exp.SetBytes([]byte { {{ $c5IntBytes }} }) 214 tv5.Exp(tv4, &exp) // 11. tv5 = tv4ᶜ⁵ 215 isQNr := {{$CurveName}}NotOne(&tv5) // 12. isQR = tv5 == 1 216 c7 := {{$CoordType}} {{asElement (index .PrecomputedParams 2) }} 217 tv2.Mul(&tv3, &c7) // 13. tv2 = tv3 * c7 218 tv5.Mul(&tv4, &tv1) // 14. tv5 = tv4 * tv1 219 tv3.Select(int(isQNr), &tv3, &tv2) // 15. tv3 = CMOV(tv2, tv3, isQR) 220 tv4.Select(int(isQNr), &tv4, &tv5) // 16. tv4 = CMOV(tv5, tv4, isQR) 221 exp.Lsh( big.NewInt(1), {{ $c1Int }} - 2) // 18, 19: tv5 = 2ⁱ⁻² for i = c1 222 223 for i := {{ $c1Int }}; i >= 2; i -- { // 17. for i in (c1, c1 - 1, ..., 2): 224 225 tv5.Exp(tv4, &exp) // 20. tv5 = tv4ᵗᵛ⁵ 226 nE1 := {{$CurveName}}NotOne(&tv5) // 21. e1 = tv5 == 1 227 tv2.Mul(&tv3, &tv1) // 22. tv2 = tv3 * tv1 228 tv1.Mul(&tv1, &tv1) // 23. tv1 = tv1 * tv1 Why not write square? 229 tv5.Mul(&tv4, &tv1) // 24. tv5 = tv4 * tv1 230 tv3.Select(int(nE1), &tv3, &tv2) // 25. tv3 = CMOV(tv2, tv3, e1) 231 tv4.Select(int(nE1), &tv4, &tv5) // 26. tv4 = CMOV(tv5, tv4, e1) 232 233 if i > 2 { 234 exp.Rsh(&exp, 1) // 18, 19. tv5 = 2ⁱ⁻² 235 } 236 } 237 238 *z = tv3 239 return isQNr 240 } 241 242 func {{$CurveName}}NotOne(x *{{$CoordType}}) uint64 { 243 {{if eq $TowerDegree 1 }} 244 var one {{$CoordType}} 245 return one.SetOne().NotEqual(x) 246 {{else}} 247 //Assuming hash is implemented for G1 and that the curve is over Fp 248 var one fp.Element 249 return one.SetOne().NotEqual(&x.{{.FieldCoordName}}0) {{range $i := interval 1 $TowerDegree}} | g1NotZero(&x.{{$.FieldCoordName}}{{$i}}) {{end}} 250 {{end}} 251 } 252 {{ end }} 253 254 // {{$CurveName}}MulByZ multiplies x by [{{printList .Z}}] and stores the result in z 255 func {{$CurveName}}MulByZ(z *{{$CoordType}}, x *{{$CoordType}}) { 256 257 {{ if eq $TowerDegree 1 }} 258 259 {{ $Z := index .Z 0}} 260 261 {{ $ZBitsHi2Lo := reverse (bits $Z) }} 262 {{ $op := "Add"}} 263 {{- if lt $Z 0 }} 264 {{ $op = "Sub" }} 265 var res {{$CoordType}} 266 res.Neg(x) 267 {{- end }} 268 {{- if gt $Z 0 }} 269 res := *x 270 {{- end }} 271 272 {{if ge (len $ZBitsHi2Lo) 2 }} 273 res.Double(&res) 274 275 {{- range $bit := noFirst (noLast $ZBitsHi2Lo) }} 276 {{- if $bit }} 277 res.{{$op}}(&res, x) 278 {{- end }} 279 res.Double(&res) 280 {{- end }} 281 282 {{- if last $ZBitsHi2Lo }} 283 res.{{$op}}(&res, x) 284 {{- end }} 285 286 {{end}} 287 288 *z = res {{ else }} 289 z.Mul(x, &{{$CoordType}} {{asElement .Z }}) 290 291 {{ end }}} 292 293 // https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#name-simplified-swu-method 294 // MapToCurve{{$CurveIndex}} implements the SSWU map 295 // No cofactor clearing or isogeny 296 func MapToCurve{{$CurveIndex}}(u *{{$CoordType}}) {{$AffineType}} { 297 298 {{if $isogenyNeeded}} 299 var {{$sswuCurveACoeff}} = {{$CoordType}} {{asElement .A}} 300 var {{$sswuCurveBCoeff}} = {{$CoordType}} {{asElement .B}} 301 {{end}} 302 303 var tv1 {{$CoordType}} 304 tv1.Square(u) // 1. tv1 = u² 305 306 //mul tv1 by Z 307 {{$CurveName}}MulByZ(&tv1, &tv1) // 2. tv1 = Z * tv1 308 309 var tv2 {{$CoordType}} 310 tv2.Square(&tv1) // 3. tv2 = tv1² 311 tv2.Add(&tv2, &tv1) // 4. tv2 = tv2 + tv1 312 313 var tv3 {{$CoordType}} 314 var tv4 {{$CoordType}} 315 tv4.SetOne() 316 tv3.Add(&tv2, &tv4) // 5. tv3 = tv2 + 1 317 tv3.Mul(&tv3, &{{$sswuCurveBCoeff}}) // 6. tv3 = B * tv3 318 319 tv2NZero := {{$CurveName}}NotZero(&tv2) 320 321 // tv4 = Z 322 tv4 = {{$CoordType}}{{ asElement .Z }} 323 324 tv2.Neg(&tv2) 325 tv4.Select(int(tv2NZero), &tv4, &tv2) // 7. tv4 = CMOV(Z, -tv2, tv2 != 0) 326 tv4.Mul(&tv4, &{{$sswuCurveACoeff}}) // 8. tv4 = A * tv4 327 328 tv2.Square(&tv3) // 9. tv2 = tv3² 329 330 var tv6 {{$CoordType}} 331 tv6.Square(&tv4) // 10. tv6 = tv4² 332 333 var tv5 {{$CoordType}} 334 tv5.Mul(&tv6, &{{$sswuCurveACoeff}}) // 11. tv5 = A * tv6 335 336 tv2.Add(&tv2, &tv5) // 12. tv2 = tv2 + tv5 337 tv2.Mul(&tv2, &tv3) // 13. tv2 = tv2 * tv3 338 tv6.Mul(&tv6, &tv4) // 14. tv6 = tv6 * tv4 339 340 tv5.Mul(&tv6, &{{$sswuCurveBCoeff}}) // 15. tv5 = B * tv6 341 tv2.Add(&tv2, &tv5) // 16. tv2 = tv2 + tv5 342 343 var x {{$CoordType}} 344 x.Mul(&tv1, &tv3) // 17. x = tv1 * tv3 345 346 var y1 {{$CoordType}} 347 gx1NSquare := {{$CurveName}}SqrtRatio(&y1, &tv2, &tv6) // 18. (is_gx1_square, y1) = sqrt_ratio(tv2, tv6) 348 349 var y {{$CoordType}} 350 y.Mul(&tv1, u) // 19. y = tv1 * u 351 352 y.Mul(&y, &y1) // 20. y = y * y1 353 354 x.Select(int(gx1NSquare), &tv3, &x) // 21. x = CMOV(x, tv3, is_gx1_square) 355 y.Select(int(gx1NSquare), &y1, &y) // 22. y = CMOV(y, y1, is_gx1_square) 356 357 y1.Neg(&y) 358 y.Select(int({{$CurveName}}Sgn0(u)^{{$CurveName}}Sgn0(&y)), &y, &y1) 359 360 // 23. e1 = sgn0(u) == sgn0(y) 361 // 24. y = CMOV(-y, y, e1) 362 363 x.Div(&x, &tv4) // 25. x = x / tv4 364 365 return {{$AffineType}}{x, y} 366 } 367 368 func {{$CurveName}}EvalPolynomial(z *{{$CoordType}}, monic bool, coefficients []{{$CoordType}}, x *{{$CoordType}}) { 369 dst := coefficients[len(coefficients) - 1] 370 371 if monic { 372 dst.Add(&dst, x) 373 } 374 375 for i := len(coefficients) - 2; i >= 0; i-- { 376 dst.Mul(&dst, x) 377 dst.Add(&dst, &coefficients[i]) 378 } 379 380 z.Set(&dst) 381 } 382 383 {{end}}