github.com/consensys/gnark-crypto@v0.14.0/internal/generator/ecc/template/svdw.go.tmpl (about) 1 {{define "svdw"}} 2 ) 3 {{$TowerDegree := .Field.Degree}} 4 {{$CoordType := .Point.CoordType}} 5 {{$CurveName := .Point.PointName}} 6 {{$CurveTitle := toTitle $CurveName}} 7 {{$AffineType := print $CurveTitle "Affine"}} 8 {{$IsG1 := eq $CurveTitle "G1"}} 9 {{$CurveIndex := "2"}} 10 {{$B := "bTwistCurveCoeff"}} 11 {{if $IsG1}}{{$CurveIndex = "1"}}{{$B = "bCurveCoeff"}}{{end}} 12 13 14 // MapToCurve{{$CurveIndex}} implements the Shallue and van de Woestijne method, applicable to any elliptic curve in Weierstrass form 15 // No cofactor clearing or isogeny 16 // https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#straightline-svdw 17 func MapToCurve{{$CurveIndex}}(u *{{$CoordType}}) {{$AffineType}} { 18 var tv1, tv2, tv3, tv4 {{$CoordType}} 19 var x1, x2, x3, gx1, gx2, gx, x, y {{$CoordType}} 20 var one {{$CoordType}} 21 var gx1NotSquare, gx1SquareOrGx2Not int 22 23 //constants 24 //c1 = g(Z) 25 //c2 = -Z / 2 26 //c3 = sqrt(-g(Z) * (3 * Z² + 4 * A)) # sgn0(c3) MUST equal 0 27 //c4 = -4 * g(Z) / (3 * Z² + 4 * A) 28 29 Z := {{$CoordType}}{{asElement (index $.PrecomputedParams 0)}} 30 c1 := {{$CoordType}}{{asElement (index $.PrecomputedParams 1)}} 31 c2 := {{$CoordType}}{{asElement (index $.PrecomputedParams 2)}} 32 c3 := {{$CoordType}}{{asElement (index $.PrecomputedParams 3)}} 33 c4 := {{$CoordType}}{{asElement (index $.PrecomputedParams 4)}} 34 35 one.SetOne() 36 37 tv1.Square(u) // 1. tv1 = u² 38 tv1.Mul(&tv1, &c1) // 2. tv1 = tv1 * c1 39 tv2.Add(&one, &tv1) // 3. tv2 = 1 + tv1 40 tv1.Sub(&one, &tv1) // 4. tv1 = 1 - tv1 41 tv3.Mul(&tv1, &tv2) // 5. tv3 = tv1 * tv2 42 43 tv3.Inverse(&tv3) // 6. tv3 = inv0(tv3) 44 tv4.Mul(u, &tv1) // 7. tv4 = u * tv1 45 tv4.Mul(&tv4, &tv3) // 8. tv4 = tv4 * tv3 46 tv4.Mul(&tv4, &c3) // 9. tv4 = tv4 * c3 47 x1.Sub(&c2, &tv4) // 10. x1 = c2 - tv4 48 49 gx1.Square(&x1) // 11. gx1 = x1² 50 //12. gx1 = gx1 + A All curves in gnark-crypto have A=0 (j-invariant=0). It is crucial to include this step if the curve has nonzero A coefficient. 51 gx1.Mul(&gx1, &x1) // 13. gx1 = gx1 * x1 52 gx1.Add(&gx1, &{{$B}}) // 14. gx1 = gx1 + B 53 gx1NotSquare = gx1.Legendre() >> 1 // 15. e1 = is_square(gx1) 54 // gx1NotSquare = 0 if gx1 is a square, -1 otherwise 55 56 x2.Add(&c2, &tv4) // 16. x2 = c2 + tv4 57 gx2.Square(&x2) // 17. gx2 = x2² 58 // 18. gx2 = gx2 + A See line 12 59 gx2.Mul(&gx2, &x2) // 19. gx2 = gx2 * x2 60 gx2.Add(&gx2, &{{$B}}) // 20. gx2 = gx2 + B 61 62 { 63 gx2NotSquare := gx2.Legendre() >> 1 // gx2Square = 0 if gx2 is a square, -1 otherwise 64 gx1SquareOrGx2Not = gx2NotSquare | ^gx1NotSquare // 21. e2 = is_square(gx2) AND NOT e1 # Avoid short-circuit logic ops 65 } 66 67 x3.Square(&tv2) // 22. x3 = tv2² 68 x3.Mul(&x3, &tv3) // 23. x3 = x3 * tv3 69 x3.Square(&x3) // 24. x3 = x3² 70 x3.Mul(&x3, &c4) // 25. x3 = x3 * c4 71 72 x3.Add(&x3, &Z) // 26. x3 = x3 + Z 73 x.Select(gx1NotSquare, &x1, &x3) // 27. x = CMOV(x3, x1, e1) # x = x1 if gx1 is square, else x = x3 74 // Select x1 iff gx1 is square iff gx1NotSquare = 0 75 x.Select(gx1SquareOrGx2Not, &x2, &x) // 28. x = CMOV(x, x2, e2) # x = x2 if gx2 is square and gx1 is not 76 // Select x2 iff gx2 is square and gx1 is not, iff gx1SquareOrGx2Not = 0 77 gx.Square(&x) // 29. gx = x² 78 // 30. gx = gx + A 79 80 gx.Mul(&gx, &x) // 31. gx = gx * x 81 gx.Add(&gx, &{{$B}}) // 32. gx = gx + B 82 83 y.Sqrt(&gx) // 33. y = sqrt(gx) 84 signsNotEqual := {{$CurveName}}Sgn0(u) ^ {{$CurveName}}Sgn0(&y) // 34. e3 = sgn0(u) == sgn0(y) 85 86 tv1.Neg(&y) 87 y.Select(int(signsNotEqual), &y, &tv1) // 35. y = CMOV(-y, y, e3) # Select correct sign of y 88 return {{$AffineType}}{x, y} 89 } 90 91 {{end}}