github.com/consensys/gnark-crypto@v0.14.0/ecc/bn254/fr/iop/ratios_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 iop
    18  
    19  import (
    20  	"testing"
    21  
    22  	"github.com/consensys/gnark-crypto/ecc/bn254/fr"
    23  	"github.com/consensys/gnark-crypto/ecc/bn254/fr/fft"
    24  )
    25  
    26  // getPermutation returns a deterministic permutation
    27  // of n elements where n is even. The result should be
    28  // interpreted as
    29  // a permutation σ(i)=permutation[i]
    30  // g is a generator of ℤ/nℤ
    31  func getPermutation(n, g int) []int {
    32  
    33  	res := make([]int, n)
    34  	a := g
    35  	for i := 0; i < n; i++ {
    36  		res[i] = a
    37  		a += g
    38  		a %= n
    39  	}
    40  	return res
    41  }
    42  
    43  func getPermutedPolynomials(sizePolynomials, nbPolynomials int) ([]*Polynomial, []*Polynomial, []int) {
    44  
    45  	numerator := make([]*Polynomial, nbPolynomials)
    46  	for i := 0; i < nbPolynomials; i++ {
    47  		numerator[i] = NewPolynomial(randomVector(sizePolynomials), Form{Basis: Lagrange, Layout: Regular})
    48  	}
    49  
    50  	// get permutation
    51  	sigma := getPermutation(sizePolynomials*nbPolynomials, 3)
    52  
    53  	// the denominator is the permuted version of the numerators
    54  	// concatenated
    55  	denominator := make([]*Polynomial, nbPolynomials)
    56  	for i := 0; i < nbPolynomials; i++ {
    57  		denominator[i] = NewPolynomial(randomVector(sizePolynomials), Form{Basis: Lagrange, Layout: Regular})
    58  	}
    59  	for i := 0; i < len(sigma); i++ {
    60  		id := int(sigma[i] / sizePolynomials)
    61  		od := sigma[i] % sizePolynomials
    62  		in := int(i / sizePolynomials)
    63  		on := i % sizePolynomials
    64  		denominator[in].Coefficients()[on].Set(&numerator[id].Coefficients()[od])
    65  	}
    66  
    67  	return numerator, denominator, sigma
    68  
    69  }
    70  
    71  func TestBuildRatioShuffledVectors(t *testing.T) {
    72  
    73  	// generate random vectors, interpreted in Lagrange form,
    74  	// regular layout. It is enough for this test if TestPutInLagrangeForm
    75  	// passes.
    76  	sizePolynomials := 8
    77  	nbPolynomials := 4
    78  	numerator, denominator, _ := getPermutedPolynomials(sizePolynomials, nbPolynomials)
    79  
    80  	// save the originals for further tests with polynomials in different forms
    81  	backupNumerator := make([]*Polynomial, nbPolynomials)
    82  	backupDenominator := make([]*Polynomial, nbPolynomials)
    83  	for i := 0; i < nbPolynomials; i++ {
    84  		backupNumerator[i] = numerator[i].Clone()
    85  		backupDenominator[i] = denominator[i].Clone()
    86  	}
    87  
    88  	// build the ratio polynomial
    89  	expectedForm := Form{Basis: Lagrange, Layout: Regular}
    90  	domain := fft.NewDomain(uint64(sizePolynomials))
    91  	var beta fr.Element
    92  	beta.SetRandom()
    93  	ratio, err := BuildRatioShuffledVectors(numerator, denominator, beta, expectedForm, domain)
    94  	if err != nil {
    95  		t.Fatal()
    96  	}
    97  
    98  	// check that the whole product is equal to one
    99  	var a, b, c, d fr.Element
   100  	b.SetOne()
   101  	d.SetOne()
   102  	for i := 0; i < nbPolynomials; i++ {
   103  		a.Sub(&beta, &numerator[i].Coefficients()[sizePolynomials-1])
   104  		b.Mul(&a, &b)
   105  		c.Sub(&beta, &denominator[i].Coefficients()[sizePolynomials-1])
   106  		d.Mul(&c, &d)
   107  	}
   108  	a.Mul(&b, &ratio.Coefficients()[sizePolynomials-1]).
   109  		Div(&a, &d)
   110  	var one fr.Element
   111  	one.SetOne()
   112  	if !a.Equal(&one) {
   113  		t.Fatal("accumulating ratio is not equal to one")
   114  	}
   115  
   116  	// check that the ratio is correct when the inputs are
   117  	// bit reversed
   118  	for i := 0; i < nbPolynomials; i++ {
   119  		numerator[i] = backupNumerator[i].Clone()
   120  		fft.BitReverse(numerator[i].Coefficients())
   121  		numerator[i].Layout = BitReverse
   122  
   123  		denominator[i] = backupDenominator[i].Clone()
   124  		fft.BitReverse(denominator[i].Coefficients())
   125  		denominator[i].Layout = BitReverse
   126  	}
   127  	{
   128  		var err error
   129  		_ratio, err := BuildRatioShuffledVectors(numerator, denominator, beta, expectedForm, domain)
   130  		if err != nil {
   131  			t.Fatal(err)
   132  		}
   133  		checkCoeffs := cmpCoefficents(_ratio.coefficients, ratio.coefficients)
   134  		if !checkCoeffs {
   135  			t.Fatal(err)
   136  		}
   137  	}
   138  
   139  	// check that the ratio is correct when the inputs are in
   140  	// canonical form, regular
   141  	for i := 0; i < nbPolynomials; i++ {
   142  		numerator[i] = backupNumerator[i].Clone()
   143  		domain.FFTInverse(numerator[i].Coefficients(), fft.DIF)
   144  		fft.BitReverse(numerator[i].Coefficients())
   145  		numerator[i].Basis = Canonical
   146  
   147  		denominator[i] = backupDenominator[i].Clone()
   148  		domain.FFTInverse(denominator[i].Coefficients(), fft.DIF)
   149  		fft.BitReverse(denominator[i].Coefficients())
   150  		denominator[i].Basis = Canonical
   151  	}
   152  	{
   153  		var err error
   154  		_ratio, err := BuildRatioShuffledVectors(numerator, denominator, beta, expectedForm, domain)
   155  		if err != nil {
   156  			t.Fatal(err)
   157  		}
   158  		checkCoeffs := cmpCoefficents(_ratio.coefficients, ratio.coefficients)
   159  		if !checkCoeffs {
   160  			t.Fatal("coefficients of ratio are not consistent")
   161  		}
   162  	}
   163  
   164  	// check that the ratio is correct when the inputs are in
   165  	// canonical form, bit reverse
   166  	for i := 0; i < nbPolynomials; i++ {
   167  		numerator[i] = backupNumerator[i].Clone()
   168  		domain.FFTInverse(numerator[i].Coefficients(), fft.DIF)
   169  		numerator[i].Layout = BitReverse
   170  		numerator[i].Basis = Canonical
   171  
   172  		denominator[i] = backupDenominator[i].Clone()
   173  		domain.FFTInverse(denominator[i].Coefficients(), fft.DIF)
   174  		denominator[i].Layout = BitReverse
   175  		denominator[i].Basis = Canonical
   176  	}
   177  	{
   178  		var err error
   179  		_ratio, err := BuildRatioShuffledVectors(numerator, denominator, beta, expectedForm, domain)
   180  		if err != nil {
   181  			t.Fatal(err)
   182  		}
   183  		checkCoeffs := cmpCoefficents(_ratio.coefficients, ratio.coefficients)
   184  		if !checkCoeffs {
   185  			t.Fatal("coefficients of ratio are not consistent")
   186  		}
   187  	}
   188  
   189  }
   190  
   191  // sizePolynomial*nbPolynomial must be divisible by 2.
   192  // The function generates a list of nbPolynomials (P_i) of size n=sizePolynomials
   193  // such that [P₁ ∥ .. ∥ P₂ ] is invariant under the permutation
   194  // σ defined by:
   195  // σ = (12)(34)..(2n-1 2n)
   196  // so σ is a product of cycles length 2.
   197  func getInvariantEntriesUnderPermutation(sizePolynomials, nbPolynomials int) ([]*Polynomial, []int64) {
   198  	res := make([]*Polynomial, nbPolynomials)
   199  	form := Form{Layout: Regular, Basis: Lagrange}
   200  	for i := 0; i < nbPolynomials; i++ {
   201  		v := make([]fr.Element, sizePolynomials)
   202  		res[i] = NewPolynomial(&v, form)
   203  		for j := 0; j < sizePolynomials/2; j++ {
   204  			res[i].Coefficients()[2*j].SetRandom()
   205  			res[i].Coefficients()[2*j+1].Set(&res[i].Coefficients()[2*j])
   206  		}
   207  	}
   208  	permutation := make([]int64, nbPolynomials*sizePolynomials)
   209  	for i := int64(0); i < int64(nbPolynomials*sizePolynomials/2); i++ {
   210  		permutation[2*i] = 2*i + 1
   211  		permutation[2*i+1] = 2 * i
   212  	}
   213  	return res, permutation
   214  }
   215  
   216  func TestBuildRatioCopyConstraint(t *testing.T) {
   217  
   218  	// generate random vectors, interpreted in Lagrange form,
   219  	// regular layout. It is enough for this test if TestPutInLagrangeForm
   220  	// passes.
   221  	sizePolynomials := 8
   222  	nbPolynomials := 4
   223  	entries, sigma := getInvariantEntriesUnderPermutation(sizePolynomials, nbPolynomials)
   224  
   225  	// save the originals for further tests with polynomials in different forms
   226  	backupEntries := make([]*Polynomial, nbPolynomials)
   227  	for i := 0; i < nbPolynomials; i++ {
   228  		backupEntries[i] = entries[i].Clone()
   229  	}
   230  
   231  	// build the ratio polynomial
   232  	expectedForm := Form{Basis: Lagrange, Layout: Regular}
   233  	domain := fft.NewDomain(uint64(sizePolynomials))
   234  	var beta, gamma fr.Element
   235  	beta.SetRandom()
   236  	gamma.SetRandom()
   237  	ratio, err := BuildRatioCopyConstraint(entries, sigma, beta, gamma, expectedForm, domain)
   238  	if err != nil {
   239  		t.Fatal()
   240  	}
   241  
   242  	// check that the whole product is equal to one
   243  	suppID := getSupportIdentityPermutation(nbPolynomials, domain)
   244  	var a, b, c, d fr.Element
   245  	b.SetOne()
   246  	d.SetOne()
   247  	for i := 0; i < nbPolynomials; i++ {
   248  		a.Mul(&beta, &suppID[(i+1)*sizePolynomials-1]).
   249  			Add(&a, &entries[i].Coefficients()[sizePolynomials-1]).
   250  			Add(&a, &gamma)
   251  		b.Mul(&b, &a)
   252  
   253  		c.Mul(&beta, &suppID[sigma[(i+1)*sizePolynomials-1]]).
   254  			Add(&c, &entries[i].Coefficients()[sizePolynomials-1]).
   255  			Add(&c, &gamma)
   256  		d.Mul(&d, &c)
   257  	}
   258  	a.Mul(&b, &ratio.Coefficients()[sizePolynomials-1]).
   259  		Div(&a, &d)
   260  	var one fr.Element
   261  	one.SetOne()
   262  	if !a.Equal(&one) {
   263  		t.Fatal("accumulating ratio is not equal to one")
   264  	}
   265  
   266  	// check that the ratio is correct when the inputs are
   267  	// bit reversed
   268  	for i := 0; i < nbPolynomials; i++ {
   269  		entries[i] = backupEntries[i].Clone()
   270  		fft.BitReverse(entries[i].Coefficients())
   271  		entries[i].Layout = BitReverse
   272  	}
   273  	{
   274  		var err error
   275  		_ratio, err := BuildRatioCopyConstraint(entries, sigma, beta, gamma, expectedForm, domain)
   276  		if err != nil {
   277  			t.Fatal(err)
   278  		}
   279  		checkCoeffs := cmpCoefficents(_ratio.coefficients, ratio.coefficients)
   280  		if !checkCoeffs {
   281  			t.Fatal(err)
   282  		}
   283  	}
   284  
   285  	// check that the ratio is correct when the inputs are in
   286  	// canonical form, regular
   287  	for i := 0; i < nbPolynomials; i++ {
   288  		entries[i] = backupEntries[i].Clone()
   289  		domain.FFTInverse(entries[i].Coefficients(), fft.DIF)
   290  		fft.BitReverse(entries[i].Coefficients())
   291  		entries[i].Layout = Regular
   292  		entries[i].Basis = Canonical
   293  	}
   294  	{
   295  		var err error
   296  		_ratio, err := BuildRatioCopyConstraint(entries, sigma, beta, gamma, expectedForm, domain)
   297  		if err != nil {
   298  			t.Fatal(err)
   299  		}
   300  		checkCoeffs := cmpCoefficents(_ratio.coefficients, ratio.coefficients)
   301  		if !checkCoeffs {
   302  			t.Fatal("coefficients of ratio are not consistent")
   303  		}
   304  	}
   305  
   306  	// check that the ratio is correct when the inputs are in
   307  	// canonical form, bit reverse
   308  	for i := 0; i < nbPolynomials; i++ {
   309  		entries[i] = backupEntries[i].Clone()
   310  		domain.FFTInverse(entries[i].Coefficients(), fft.DIF)
   311  		entries[i].Layout = BitReverse
   312  		entries[i].Basis = Canonical
   313  	}
   314  
   315  	{
   316  		var err error
   317  		_ratio, err := BuildRatioCopyConstraint(entries, sigma, beta, gamma, expectedForm, domain)
   318  		if err != nil {
   319  			t.Fatal(err)
   320  		}
   321  		checkCoeffs := cmpCoefficents(_ratio.coefficients, ratio.coefficients)
   322  		if !checkCoeffs {
   323  			t.Fatal("coefficients of ratio are not consistent")
   324  		}
   325  	}
   326  }