github.com/consensys/gnark-crypto@v0.14.0/ecc/bls24-315/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 bls24315
    18  
    19  import (
    20  	"github.com/consensys/gnark-crypto/ecc/bls24-315/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  		"39705142154296798234718093138458736353730097451069869796965271356892223115922042164250209681439",
   230  	)
   231  
   232  	B.SetString(
   233  		"22",
   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