github.com/consensys/gnark-crypto@v0.14.0/ecc/bn254/hash_to_g2.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 "github.com/consensys/gnark-crypto/ecc/bn254/internal/fptower" 22 ) 23 24 // MapToCurve2 implements the Shallue and van de Woestijne method, applicable to any elliptic curve in Weierstrass form 25 // No cofactor clearing or isogeny 26 // https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#straightline-svdw 27 func MapToCurve2(u *fptower.E2) G2Affine { 28 var tv1, tv2, tv3, tv4 fptower.E2 29 var x1, x2, x3, gx1, gx2, gx, x, y fptower.E2 30 var one fptower.E2 31 var gx1NotSquare, gx1SquareOrGx2Not int 32 33 //constants 34 //c1 = g(Z) 35 //c2 = -Z / 2 36 //c3 = sqrt(-g(Z) * (3 * Z² + 4 * A)) # sgn0(c3) MUST equal 0 37 //c4 = -4 * g(Z) / (3 * Z² + 4 * A) 38 39 Z := fptower.E2{ 40 A0: fp.Element{15230403791020821917, 754611498739239741, 7381016538464732716, 1011752739694698287}, 41 A1: fp.Element{0}, 42 } 43 c1 := fptower.E2{ 44 A0: fp.Element{15219334786797146878, 8431472696017589261, 15336528771359260718, 196732871012706162}, 45 A1: fp.Element{4100506350182530919, 7345568344173317438, 15513160039642431658, 90557763186888013}, 46 } 47 c2 := fptower.E2{ 48 A0: fp.Element{12997850613838968789, 14304628359724097447, 2950087706404981016, 1237622763554136189}, 49 A1: fp.Element{0}, 50 } 51 c3 := fptower.E2{ 52 A0: fp.Element{12298500088583694207, 17447120171744064890, 14097510924717921191, 2278398337453771183}, 53 A1: fp.Element{4693446565795584099, 18320164443970680666, 6792758484113206563, 2989688171181581768}, 54 } 55 c4 := fptower.E2{ 56 A0: fp.Element{7191623630069643826, 8333948550768170742, 13001081703983517696, 2062355016518372226}, 57 A1: fp.Element{11163104453509316115, 7271947710149976975, 4894807947557820282, 3366254582553786647}, 58 } 59 60 one.SetOne() 61 62 tv1.Square(u) // 1. tv1 = u² 63 tv1.Mul(&tv1, &c1) // 2. tv1 = tv1 * c1 64 tv2.Add(&one, &tv1) // 3. tv2 = 1 + tv1 65 tv1.Sub(&one, &tv1) // 4. tv1 = 1 - tv1 66 tv3.Mul(&tv1, &tv2) // 5. tv3 = tv1 * tv2 67 68 tv3.Inverse(&tv3) // 6. tv3 = inv0(tv3) 69 tv4.Mul(u, &tv1) // 7. tv4 = u * tv1 70 tv4.Mul(&tv4, &tv3) // 8. tv4 = tv4 * tv3 71 tv4.Mul(&tv4, &c3) // 9. tv4 = tv4 * c3 72 x1.Sub(&c2, &tv4) // 10. x1 = c2 - tv4 73 74 gx1.Square(&x1) // 11. gx1 = x1² 75 //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. 76 gx1.Mul(&gx1, &x1) // 13. gx1 = gx1 * x1 77 gx1.Add(&gx1, &bTwistCurveCoeff) // 14. gx1 = gx1 + B 78 gx1NotSquare = gx1.Legendre() >> 1 // 15. e1 = is_square(gx1) 79 // gx1NotSquare = 0 if gx1 is a square, -1 otherwise 80 81 x2.Add(&c2, &tv4) // 16. x2 = c2 + tv4 82 gx2.Square(&x2) // 17. gx2 = x2² 83 // 18. gx2 = gx2 + A See line 12 84 gx2.Mul(&gx2, &x2) // 19. gx2 = gx2 * x2 85 gx2.Add(&gx2, &bTwistCurveCoeff) // 20. gx2 = gx2 + B 86 87 { 88 gx2NotSquare := gx2.Legendre() >> 1 // gx2Square = 0 if gx2 is a square, -1 otherwise 89 gx1SquareOrGx2Not = gx2NotSquare | ^gx1NotSquare // 21. e2 = is_square(gx2) AND NOT e1 # Avoid short-circuit logic ops 90 } 91 92 x3.Square(&tv2) // 22. x3 = tv2² 93 x3.Mul(&x3, &tv3) // 23. x3 = x3 * tv3 94 x3.Square(&x3) // 24. x3 = x3² 95 x3.Mul(&x3, &c4) // 25. x3 = x3 * c4 96 97 x3.Add(&x3, &Z) // 26. x3 = x3 + Z 98 x.Select(gx1NotSquare, &x1, &x3) // 27. x = CMOV(x3, x1, e1) # x = x1 if gx1 is square, else x = x3 99 // Select x1 iff gx1 is square iff gx1NotSquare = 0 100 x.Select(gx1SquareOrGx2Not, &x2, &x) // 28. x = CMOV(x, x2, e2) # x = x2 if gx2 is square and gx1 is not 101 // Select x2 iff gx2 is square and gx1 is not, iff gx1SquareOrGx2Not = 0 102 gx.Square(&x) // 29. gx = x² 103 // 30. gx = gx + A 104 105 gx.Mul(&gx, &x) // 31. gx = gx * x 106 gx.Add(&gx, &bTwistCurveCoeff) // 32. gx = gx + B 107 108 y.Sqrt(&gx) // 33. y = sqrt(gx) 109 signsNotEqual := g2Sgn0(u) ^ g2Sgn0(&y) // 34. e3 = sgn0(u) == sgn0(y) 110 111 tv1.Neg(&y) 112 y.Select(int(signsNotEqual), &y, &tv1) // 35. y = CMOV(-y, y, e3) # Select correct sign of y 113 return G2Affine{x, y} 114 } 115 116 // g2Sgn0 is an algebraic substitute for the notion of sign in ordered fields 117 // Namely, every non-zero quadratic residue in a finite field of characteristic =/= 2 has exactly two square roots, one of each sign 118 // https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#name-the-sgn0-function 119 // The sign of an element is not obviously related to that of its Montgomery form 120 func g2Sgn0(z *fptower.E2) uint64 { 121 122 nonMont := z.Bits() 123 124 sign := uint64(0) // 1. sign = 0 125 zero := uint64(1) // 2. zero = 1 126 var signI uint64 127 var zeroI uint64 128 129 // 3. i = 1 130 signI = nonMont.A0[0] % 2 // 4. sign_i = x_i mod 2 131 zeroI = g1NotZero(&nonMont.A0) 132 zeroI = 1 ^ (zeroI|-zeroI)>>63 // 5. zero_i = x_i == 0 133 sign = sign | (zero & signI) // 6. sign = sign OR (zero AND sign_i) # Avoid short-circuit logic ops 134 zero = zero & zeroI // 7. zero = zero AND zero_i 135 // 3. i = 2 136 signI = nonMont.A1[0] % 2 // 4. sign_i = x_i mod 2 137 // 5. zero_i = x_i == 0 138 sign = sign | (zero & signI) // 6. sign = sign OR (zero AND sign_i) # Avoid short-circuit logic ops 139 // 7. zero = zero AND zero_i 140 return sign 141 142 } 143 144 // MapToG2 invokes the SVDW map, and guarantees that the result is in g2 145 func MapToG2(u fptower.E2) G2Affine { 146 res := MapToCurve2(&u) 147 res.ClearCofactor(&res) 148 return res 149 } 150 151 // EncodeToG2 hashes a message to a point on the G2 curve using the SVDW map. 152 // It is faster than HashToG2, but the result is not uniformly distributed. Unsuitable as a random oracle. 153 // dst stands for "domain separation tag", a string unique to the construction using the hash function 154 // https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#roadmap 155 func EncodeToG2(msg, dst []byte) (G2Affine, error) { 156 157 var res G2Affine 158 u, err := fp.Hash(msg, dst, 2) 159 if err != nil { 160 return res, err 161 } 162 163 res = MapToCurve2(&fptower.E2{ 164 A0: u[0], 165 A1: u[1], 166 }) 167 168 res.ClearCofactor(&res) 169 return res, nil 170 } 171 172 // HashToG2 hashes a message to a point on the G2 curve using the SVDW map. 173 // Slower than EncodeToG2, but usable as a random oracle. 174 // dst stands for "domain separation tag", a string unique to the construction using the hash function 175 // https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#roadmap 176 func HashToG2(msg, dst []byte) (G2Affine, error) { 177 u, err := fp.Hash(msg, dst, 2*2) 178 if err != nil { 179 return G2Affine{}, err 180 } 181 182 Q0 := MapToCurve2(&fptower.E2{ 183 A0: u[0], 184 A1: u[1], 185 }) 186 Q1 := MapToCurve2(&fptower.E2{ 187 A0: u[2+0], 188 A1: u[2+1], 189 }) 190 191 var _Q0, _Q1 G2Jac 192 _Q0.FromAffine(&Q0) 193 _Q1.FromAffine(&Q1).AddAssign(&_Q0) 194 195 _Q1.ClearCofactor(&_Q1) 196 197 Q1.FromJacobian(&_Q1) 198 return Q1, nil 199 } 200 201 func g2NotZero(x *fptower.E2) uint64 { 202 //Assuming G1 is over Fp and that if hashing is available for G2, it also is for G1 203 return g1NotZero(&x.A0) | g1NotZero(&x.A1) 204 205 }