github.com/consensys/gnark-crypto@v0.14.0/internal/generator/fri/template/fri.test.go.tmpl (about)

     1  import (
     2  	"crypto/sha256"
     3  	"fmt"
     4  	"math/big"
     5  	"testing"
     6  
     7  	"github.com/consensys/gnark-crypto/ecc/{{.Name}}/fr"
     8  	"github.com/leanovate/gopter"
     9  	"github.com/leanovate/gopter/gen"
    10  	"github.com/leanovate/gopter/prop"
    11  )
    12  
    13  // logFiber returns u, v such that {g^u, g^v} = f⁻¹((g²)^{_p})
    14  func logFiber(_p, _n int) (_u, _v big.Int) {
    15  	if _p%2 == 0 {
    16  		_u.SetInt64(int64(_p / 2))
    17  		_v.SetInt64(int64(_p/2 + _n/2))
    18  	} else {
    19  		l := (_n - 1 - _p) / 2
    20  		_u.SetInt64(int64(_n - 1 - l))
    21  		_v.SetInt64(int64(_n - 1 - l - _n/2))
    22  	}
    23  	return
    24  }
    25  
    26  func randomPolynomial(size uint64, seed int32) []fr.Element {
    27  	p := make([]fr.Element, size)
    28  	p[0].SetUint64(uint64(seed))
    29  	for i := 1; i < len(p); i++ {
    30  		p[i].Square(&p[i-1])
    31  	}
    32  	return p
    33  }
    34  
    35  // convertOrderCanonical convert the index i, an entry in a
    36  // sorted polynomial, to the corresponding entry in canonical
    37  // representation. n is the size of the polynomial.
    38  func convertSortedCanonical(i, n int) int {
    39  	if i%2 == 0 {
    40  		return i / 2
    41  	} else {
    42  		l := (n - 1 - i) / 2
    43  		return n - 1 - l
    44  	}
    45  }
    46  
    47  func TestFRI(t *testing.T) {
    48  
    49  	parameters := gopter.DefaultTestParameters()
    50  	parameters.MinSuccessfulTests = 10
    51  
    52  	properties := gopter.NewProperties(parameters)
    53  
    54  	size := 4096
    55  
    56  	properties.Property("verifying wrong opening should fail", prop.ForAll(
    57  
    58  		func(m int32) bool {
    59  
    60  			_s := RADIX_2_FRI.New(uint64(size), sha256.New())
    61  			s := _s.(radixTwoFri)
    62  
    63  			p := randomPolynomial(uint64(size), m)
    64  
    65  			pos := int64(m % 4096)
    66  			pp, _ := s.BuildProofOfProximity(p)
    67  
    68  			openingProof, err := s.Open(p, uint64(pos))
    69  			if err != nil {
    70  				t.Fatal(err)
    71  			}
    72  
    73  			// check the Merkle path
    74  			tamperedPosition := pos + 1
    75  			err = s.VerifyOpening(uint64(tamperedPosition), openingProof, pp)
    76  
    77  			return err != nil
    78  
    79  		},
    80  		gen.Int32Range(1, int32(rho*size)),
    81  	))
    82  
    83  	properties.Property("verifying correct opening should succeed", prop.ForAll(
    84  
    85  		func(m int32) bool {
    86  
    87  			_s := RADIX_2_FRI.New(uint64(size), sha256.New())
    88  			s := _s.(radixTwoFri)
    89  
    90  			p := randomPolynomial(uint64(size), m)
    91  
    92  			pos := uint64(m % int32(size))
    93  			pp, _ := s.BuildProofOfProximity(p)
    94  
    95  			openingProof, err := s.Open(p, uint64(pos))
    96  			if err != nil {
    97  				t.Fatal(err)
    98  			}
    99  
   100  			// check the Merkle path
   101  			err = s.VerifyOpening(uint64(pos), openingProof, pp)
   102  
   103  			return err == nil
   104  
   105  		},
   106  		gen.Int32Range(0, int32(rho*size)),
   107  	))
   108  
   109  	properties.Property("The claimed value of a polynomial should match P(x)", prop.ForAll(
   110  		func(m int32) bool {
   111  
   112  			_s := RADIX_2_FRI.New(uint64(size), sha256.New())
   113  			s := _s.(radixTwoFri)
   114  
   115  			p := randomPolynomial(uint64(size), m)
   116  
   117  			// check the opening value
   118  			var g fr.Element
   119  			pos := int64(m % 4096)
   120  			g.Set(&s.domain.Generator)
   121  			g.Exp(g, big.NewInt(pos))
   122  
   123  			var val fr.Element
   124  			for i := len(p) - 1; i >= 0; i-- {
   125  				val.Mul(&val, &g)
   126  				val.Add(&p[i], &val)
   127  			}
   128  
   129  			openingProof, err := s.Open(p, uint64(pos))
   130  			if err != nil {
   131  				t.Fatal(err)
   132  			}
   133  
   134  			return openingProof.ClaimedValue.Equal(&val)
   135  
   136  		},
   137  		gen.Int32Range(0, int32(rho*size)),
   138  	))
   139  
   140  	properties.Property("Derive queries position: points should belong the correct fiber", prop.ForAll(
   141  
   142  		func(m int32) bool {
   143  
   144  			_s := RADIX_2_FRI.New(uint64(size), sha256.New())
   145  			s := _s.(radixTwoFri)
   146  
   147  			var g fr.Element
   148  
   149  			_m := int(m) % size
   150  			pos := s.deriveQueriesPositions(_m, int(s.domain.Cardinality))
   151  			g.Set(&s.domain.Generator)
   152  			n := int(s.domain.Cardinality)
   153  
   154  			for i := 0; i < len(pos)-1; i++ {
   155  
   156  				u, v := logFiber(pos[i], n)
   157  
   158  				var g1, g2, g3 fr.Element
   159  				g1.Exp(g, &u).Square(&g1)
   160  				g2.Exp(g, &v).Square(&g2)
   161  				nextPos := convertSortedCanonical(pos[i+1], n/2)
   162  				g3.Square(&g).Exp(g3, big.NewInt(int64(nextPos)))
   163  
   164  				if !g1.Equal(&g2) || !g1.Equal(&g3) {
   165  					return false
   166  				}
   167  				g.Square(&g)
   168  				n = n >> 1
   169  			}
   170  			return true
   171  		},
   172  		gen.Int32Range(0, int32(rho*size)),
   173  	))
   174  
   175  	properties.Property("verifying a correctly formed proof should succeed", prop.ForAll(
   176  
   177  		func(s int32) bool {
   178  
   179  			p := randomPolynomial(uint64(size), s)
   180  
   181  			iop := RADIX_2_FRI.New(uint64(size), sha256.New())
   182  			proof, err := iop.BuildProofOfProximity(p)
   183  			if err != nil {
   184  				t.Fatal(err)
   185  			}
   186  
   187  			err = iop.VerifyProofOfProximity(proof)
   188  			return err == nil
   189  		},
   190  		gen.Int32Range(0, int32(rho*size)),
   191  	))
   192  
   193  	properties.TestingRun(t, gopter.ConsoleReporter(false))
   194  
   195  }
   196  
   197  // Benchmarks
   198  
   199  func BenchmarkProximityVerification(b *testing.B) {
   200  
   201  	baseSize := 16
   202  
   203  	for i := 0; i < 10; i++ {
   204  
   205  		size := baseSize << i
   206  		p := make([]fr.Element, size)
   207  		for k := 0; k < size; k++ {
   208  			p[k].SetRandom()
   209  		}
   210  
   211  		iop := RADIX_2_FRI.New(uint64(size), sha256.New())
   212  		proof, _ := iop.BuildProofOfProximity(p)
   213  
   214  		b.Run(fmt.Sprintf("Polynomial size %d", size), func(b *testing.B) {
   215  			b.ResetTimer()
   216  			for l := 0; l < b.N; l++ {
   217  				iop.VerifyProofOfProximity(proof)
   218  			}
   219  		})
   220  
   221  	}
   222  }