github.com/consensys/gnark-crypto@v0.14.0/ecc/stark-curve/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 // FOO 16 17 package starkcurve 18 19 import ( 20 "github.com/consensys/gnark-crypto/ecc/stark-curve/fp" 21 ) 22 23 // MapToCurve1 implements the Shallue and van de Woestijne method, applicable to any elliptic curve in Weierstrass form 24 // No cofactor clearing or isogeny 25 // https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#straightline-svdw 26 func MapToCurve1(u *fp.Element) G1Affine { 27 var tv1, tv2, tv3, tv4 fp.Element 28 var x1, x2, x3, gx1, gx2, gx, x, y fp.Element 29 var one fp.Element 30 var gx1NotSquare, gx1SquareOrGx2Not int 31 32 //constants 33 //c1 = g(Z) 34 //c2 = -Z / 2 35 //c3 = sqrt(-g(Z) * (3 * Z² + 4 * A)) # sgn0(c3) MUST equal 0 36 //c4 = -4 * g(Z) / (3 * Z² + 4 * A) 37 38 Z := fp.Element{18446744073709551585, 18446744073709551615, 18446744073709551615, 576460752303422960} 39 c1 := fp.Element{3863487492851900810, 7432612994240712710, 12360725113329547591, 88155977965379647} 40 c2 := fp.Element{16, 0, 0, 272} 41 c3 := fp.Element{9918255022489886019, 17523995898334911653, 15291095870552318715, 510280297527296511} 42 c4 := fp.Element{13603787781549958066, 11564287495042065550, 842475966830066354, 443734371708431777} 43 44 one.SetOne() 45 46 tv1.Square(u) // 1. tv1 = u² 47 tv1.Mul(&tv1, &c1) // 2. tv1 = tv1 * c1 48 tv2.Add(&one, &tv1) // 3. tv2 = 1 + tv1 49 tv1.Sub(&one, &tv1) // 4. tv1 = 1 - tv1 50 tv3.Mul(&tv1, &tv2) // 5. tv3 = tv1 * tv2 51 52 tv3.Inverse(&tv3) // 6. tv3 = inv0(tv3) 53 tv4.Mul(u, &tv1) // 7. tv4 = u * tv1 54 tv4.Mul(&tv4, &tv3) // 8. tv4 = tv4 * tv3 55 tv4.Mul(&tv4, &c3) // 9. tv4 = tv4 * c3 56 x1.Sub(&c2, &tv4) // 10. x1 = c2 - tv4 57 58 gx1.Square(&x1) // 11. gx1 = x1² 59 gx1.Add(&gx1, &one) // 12. gx1 = gx1 + A (A=1) 60 gx1.Mul(&gx1, &x1) // 13. gx1 = gx1 * x1 61 gx1.Add(&gx1, &bCurveCoeff) // 14. gx1 = gx1 + B 62 gx1NotSquare = gx1.Legendre() >> 1 // 15. e1 = is_square(gx1) 63 // gx1NotSquare = 0 if gx1 is a square, -1 otherwise 64 65 x2.Add(&c2, &tv4) // 16. x2 = c2 + tv4 66 gx2.Square(&x2) // 17. gx2 = x2² 67 gx2.Add(&gx2, &one) // 18. gx2 = gx2 + A (A=1) 68 gx2.Mul(&gx2, &x2) // 19. gx2 = gx2 * x2 69 gx2.Add(&gx2, &bCurveCoeff) // 20. gx2 = gx2 + B 70 71 { 72 gx2NotSquare := gx2.Legendre() >> 1 // gx2Square = 0 if gx2 is a square, -1 otherwise 73 gx1SquareOrGx2Not = gx2NotSquare | ^gx1NotSquare // 21. e2 = is_square(gx2) AND NOT e1 # Avoid short-circuit logic ops 74 } 75 76 x3.Square(&tv2) // 22. x3 = tv2² 77 x3.Mul(&x3, &tv3) // 23. x3 = x3 * tv3 78 x3.Square(&x3) // 24. x3 = x3² 79 x3.Mul(&x3, &c4) // 25. x3 = x3 * c4 80 81 x3.Add(&x3, &Z) // 26. x3 = x3 + Z 82 x.Select(gx1NotSquare, &x1, &x3) // 27. x = CMOV(x3, x1, e1) # x = x1 if gx1 is square, else x = x3 83 // Select x1 iff gx1 is square iff gx1NotSquare = 0 84 x.Select(gx1SquareOrGx2Not, &x2, &x) // 28. x = CMOV(x, x2, e2) # x = x2 if gx2 is square and gx1 is not 85 // Select x2 iff gx2 is square and gx1 is not, iff gx1SquareOrGx2Not = 0 86 gx.Square(&x) // 29. gx = x² 87 gx.Add(&gx, &one) // 30. gx = gx + A (A=1) 88 89 gx.Mul(&gx, &x) // 31. gx = gx * x 90 gx.Add(&gx, &bCurveCoeff) // 32. gx = gx + B 91 92 y.Sqrt(&gx) // 33. y = sqrt(gx) 93 signsNotEqual := g1Sgn0(u) ^ g1Sgn0(&y) // 34. e3 = sgn0(u) == sgn0(y) 94 95 tv1.Neg(&y) 96 y.Select(int(signsNotEqual), &y, &tv1) // 35. y = CMOV(-y, y, e3) # Select correct sign of y 97 return G1Affine{x, y} 98 } 99 100 // g1Sgn0 is an algebraic substitute for the notion of sign in ordered fields 101 // Namely, every non-zero quadratic residue in a finite field of characteristic =/= 2 has exactly two square roots, one of each sign 102 // https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#name-the-sgn0-function 103 // The sign of an element is not obviously related to that of its Montgomery form 104 func g1Sgn0(z *fp.Element) uint64 { 105 106 nonMont := z.Bits() 107 108 // m == 1 109 return nonMont[0] % 2 110 111 } 112 113 // MapToG1 invokes the SVDW map, and guarantees that the result is in g1 114 func MapToG1(u fp.Element) G1Affine { 115 res := MapToCurve1(&u) 116 return res 117 } 118 119 // EncodeToG1 hashes a message to a point on the G1 curve using the SVDW map. 120 // It is faster than HashToG1, but the result is not uniformly distributed. Unsuitable as a random oracle. 121 // dst stands for "domain separation tag", a string unique to the construction using the hash function 122 // https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#roadmap 123 func EncodeToG1(msg, dst []byte) (G1Affine, error) { 124 125 var res G1Affine 126 u, err := fp.Hash(msg, dst, 1) 127 if err != nil { 128 return res, err 129 } 130 131 res = MapToCurve1(&u[0]) 132 133 return res, nil 134 } 135 136 // HashToG1 hashes a message to a point on the G1 curve using the SVDW map. 137 // Slower than EncodeToG1, but usable as a random oracle. 138 // dst stands for "domain separation tag", a string unique to the construction using the hash function 139 // https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#roadmap 140 func HashToG1(msg, dst []byte) (G1Affine, error) { 141 u, err := fp.Hash(msg, dst, 2*1) 142 if err != nil { 143 return G1Affine{}, err 144 } 145 146 Q0 := MapToCurve1(&u[0]) 147 Q1 := MapToCurve1(&u[1]) 148 149 var _Q0, _Q1 G1Jac 150 _Q0.FromAffine(&Q0) 151 _Q1.FromAffine(&Q1).AddAssign(&_Q0) 152 153 Q1.FromJacobian(&_Q1) 154 return Q1, nil 155 }