github.com/consensys/gnark-crypto@v0.14.0/ecc/bn254/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 bn254 18 19 import ( 20 "github.com/consensys/gnark-crypto/ecc/bn254/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{15230403791020821917, 754611498739239741, 7381016538464732716, 1011752739694698287} 39 c1 := fp.Element{1248766071674976557, 10548065924188627562, 16242874202584236114, 560012691975822483} 40 c2 := fp.Element{12997850613838968789, 14304628359724097447, 2950087706404981016, 1237622763554136189} 41 c3 := fp.Element{8972444824031832946, 5898165201680709844, 10690697896010808308, 824354360198587078} 42 c4 := fp.Element{12077013577332951089, 1872782865047492001, 13514471836495169457, 415649166299893576} 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 //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. 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 // 18. gx2 = gx2 + A See line 12 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 // 30. gx = gx + A 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 } 156 157 func g1NotZero(x *fp.Element) uint64 { 158 159 return x[0] | x[1] | x[2] | x[3] 160 161 }