github.com/consensys/gnark-crypto@v0.14.0/ecc/bls12-381/hash_to_g1_test.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 bls12381 18 19 import ( 20 "github.com/consensys/gnark-crypto/ecc/bls12-381/fp" 21 "github.com/leanovate/gopter" 22 "github.com/leanovate/gopter/prop" 23 "math/rand" 24 "testing" 25 ) 26 27 func TestG1SqrtRatio(t *testing.T) { 28 t.Parallel() 29 parameters := gopter.DefaultTestParameters() 30 if testing.Short() { 31 parameters.MinSuccessfulTests = nbFuzzShort 32 } else { 33 parameters.MinSuccessfulTests = nbFuzz 34 } 35 36 properties := gopter.NewProperties(parameters) 37 38 gen := GenFp() 39 40 properties.Property("G1SqrtRatio must square back to the right value", prop.ForAll( 41 func(u fp.Element, v fp.Element) bool { 42 43 var seen fp.Element 44 qr := g1SqrtRatio(&seen, &u, &v) == 0 45 46 seen. 47 Square(&seen). 48 Mul(&seen, &v) 49 50 var ref fp.Element 51 if qr { 52 ref = u 53 } else { 54 g1MulByZ(&ref, &u) 55 } 56 57 return seen.Equal(&ref) 58 }, gen, gen)) 59 60 properties.TestingRun(t, gopter.ConsoleReporter(false)) 61 } 62 63 func TestHashToFpG1(t *testing.T) { 64 for _, c := range encodeToG1Vector.cases { 65 elems, err := fp.Hash([]byte(c.msg), encodeToG1Vector.dst, 1) 66 if err != nil { 67 t.Error(err) 68 } 69 g1TestMatchCoord(t, "u", c.msg, c.u, g1CoordAt(elems, 0)) 70 } 71 72 for _, c := range hashToG1Vector.cases { 73 elems, err := fp.Hash([]byte(c.msg), hashToG1Vector.dst, 2*1) 74 if err != nil { 75 t.Error(err) 76 } 77 g1TestMatchCoord(t, "u0", c.msg, c.u0, g1CoordAt(elems, 0)) 78 g1TestMatchCoord(t, "u1", c.msg, c.u1, g1CoordAt(elems, 1)) 79 } 80 } 81 82 func TestMapToCurve1(t *testing.T) { 83 t.Parallel() 84 parameters := gopter.DefaultTestParameters() 85 if testing.Short() { 86 parameters.MinSuccessfulTests = nbFuzzShort 87 } else { 88 parameters.MinSuccessfulTests = nbFuzz 89 } 90 91 properties := gopter.NewProperties(parameters) 92 93 properties.Property("[G1] mapping output must be on curve", prop.ForAll( 94 func(a fp.Element) bool { 95 96 g := MapToCurve1(&a) 97 98 if !isOnE1Prime(g) { 99 t.Log("Mapping output not on E' curve") 100 return false 101 } 102 g1Isogeny(&g) 103 104 if !g.IsOnCurve() { 105 t.Log("Isogeny∘SSWU output not on curve") 106 return false 107 } 108 109 return true 110 }, 111 GenFp(), 112 )) 113 114 properties.TestingRun(t, gopter.ConsoleReporter(false)) 115 116 for _, c := range encodeToG1Vector.cases { 117 var u fp.Element 118 g1CoordSetString(&u, c.u) 119 q := MapToCurve1(&u) 120 g1Isogeny(&q) 121 g1TestMatchPoint(t, "Q", c.msg, c.Q, &q) 122 } 123 124 for _, c := range hashToG1Vector.cases { 125 var u fp.Element 126 g1CoordSetString(&u, c.u0) 127 q := MapToCurve1(&u) 128 g1Isogeny(&q) 129 g1TestMatchPoint(t, "Q0", c.msg, c.Q0, &q) 130 131 g1CoordSetString(&u, c.u1) 132 q = MapToCurve1(&u) 133 g1Isogeny(&q) 134 g1TestMatchPoint(t, "Q1", c.msg, c.Q1, &q) 135 } 136 } 137 138 func TestMapToG1(t *testing.T) { 139 t.Parallel() 140 parameters := gopter.DefaultTestParameters() 141 if testing.Short() { 142 parameters.MinSuccessfulTests = nbFuzzShort 143 } else { 144 parameters.MinSuccessfulTests = nbFuzz 145 } 146 147 properties := gopter.NewProperties(parameters) 148 149 properties.Property("[G1] mapping to curve should output point on the curve", prop.ForAll( 150 func(a fp.Element) bool { 151 g := MapToG1(a) 152 return g.IsInSubGroup() 153 }, 154 GenFp(), 155 )) 156 157 properties.Property("[G1] mapping to curve should be deterministic", prop.ForAll( 158 func(a fp.Element) bool { 159 g1 := MapToG1(a) 160 g2 := MapToG1(a) 161 return g1.Equal(&g2) 162 }, 163 GenFp(), 164 )) 165 166 properties.TestingRun(t, gopter.ConsoleReporter(false)) 167 } 168 169 func TestEncodeToG1(t *testing.T) { 170 t.Parallel() 171 for _, c := range encodeToG1Vector.cases { 172 p, err := EncodeToG1([]byte(c.msg), encodeToG1Vector.dst) 173 if err != nil { 174 t.Fatal(err) 175 } 176 g1TestMatchPoint(t, "P", c.msg, c.P, &p) 177 } 178 } 179 180 func TestHashToG1(t *testing.T) { 181 t.Parallel() 182 for _, c := range hashToG1Vector.cases { 183 p, err := HashToG1([]byte(c.msg), hashToG1Vector.dst) 184 if err != nil { 185 t.Fatal(err) 186 } 187 g1TestMatchPoint(t, "P", c.msg, c.P, &p) 188 } 189 } 190 191 func BenchmarkEncodeToG1(b *testing.B) { 192 const size = 54 193 bytes := make([]byte, size) 194 dst := encodeToG1Vector.dst 195 b.ResetTimer() 196 197 for i := 0; i < b.N; i++ { 198 199 bytes[rand.Int()%size] = byte(rand.Int()) //#nosec G404 weak rng is fine here 200 201 if _, err := EncodeToG1(bytes, dst); err != nil { 202 b.Fail() 203 } 204 } 205 } 206 207 func BenchmarkHashToG1(b *testing.B) { 208 const size = 54 209 bytes := make([]byte, size) 210 dst := hashToG1Vector.dst 211 b.ResetTimer() 212 213 for i := 0; i < b.N; i++ { 214 215 bytes[rand.Int()%size] = byte(rand.Int()) //#nosec G404 weak rng is fine here 216 217 if _, err := HashToG1(bytes, dst); err != nil { 218 b.Fail() 219 } 220 } 221 } 222 223 // TODO: Crude. Do something clever in Jacobian 224 func isOnE1Prime(p G1Affine) bool { 225 226 var A, B fp.Element 227 228 A.SetString( 229 "12190336318893619529228877361869031420615612348429846051986726275283378313155663745811710833465465981901188123677", 230 ) 231 232 B.SetString( 233 "2906670324641927570491258158026293881577086121416628140204402091718288198173574630967936031029026176254968826637280", 234 ) 235 236 var LHS fp.Element 237 LHS. 238 Square(&p.Y). 239 Sub(&LHS, &B) 240 241 var RHS fp.Element 242 RHS. 243 Square(&p.X). 244 Add(&RHS, &A). 245 Mul(&RHS, &p.X) 246 247 return LHS.Equal(&RHS) 248 } 249 250 // Only works on simple extensions (two-story towers) 251 func g1CoordSetString(z *fp.Element, s string) { 252 z.SetString(s) 253 } 254 255 func g1CoordAt(slice []fp.Element, i int) fp.Element { 256 return slice[i] 257 } 258 259 func g1TestMatchCoord(t *testing.T, coordName string, msg string, expectedStr string, seen fp.Element) { 260 var expected fp.Element 261 262 g1CoordSetString(&expected, expectedStr) 263 264 if !expected.Equal(&seen) { 265 t.Errorf("mismatch on \"%s\", %s:\n\texpected %s\n\tsaw %s", msg, coordName, expected.String(), &seen) 266 } 267 } 268 269 func g1TestMatchPoint(t *testing.T, pointName string, msg string, expected point, seen *G1Affine) { 270 g1TestMatchCoord(t, pointName+".x", msg, expected.x, seen.X) 271 g1TestMatchCoord(t, pointName+".y", msg, expected.y, seen.Y) 272 } 273 274 type hashTestVector struct { 275 dst []byte 276 cases []hashTestCase 277 } 278 279 type encodeTestVector struct { 280 dst []byte 281 cases []encodeTestCase 282 } 283 284 type point struct { 285 x string 286 y string 287 } 288 289 type encodeTestCase struct { 290 msg string 291 P point //pY a coordinate of P, the final output 292 u string //u hashed onto the field 293 Q point //Q map to curve output 294 } 295 296 type hashTestCase struct { 297 msg string 298 P point //pY a coordinate of P, the final output 299 u0 string //u0 hashed onto the field 300 u1 string //u1 extra hashed onto the field 301 Q0 point //Q0 map to curve output 302 Q1 point //Q1 extra map to curve output 303 } 304 305 var encodeToG1Vector encodeTestVector 306 var hashToG1Vector hashTestVector