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