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