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}}