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

     1  import (
     2  	"testing"
     3  
     4  	"github.com/consensys/gnark-crypto/ecc"
     5  	"github.com/consensys/gnark-crypto/ecc/{{ .Name }}/fr"
     6  	"github.com/consensys/gnark-crypto/ecc/{{ .Name }}/fr/fft"
     7  )
     8  
     9  // computes x₃ in h(x₁,x₂,x₃) = x₁^{2}*x₂ + x₃ - x₁^{3}
    10  // from x₁ and x₂.
    11  func computex3(x []fr.Element) fr.Element {
    12  
    13  	var a, b fr.Element
    14  	a.Square(&x[0]).Mul(&a, &x[1])
    15  	b.Square(&x[0]).Mul(&b, &x[0])
    16  	a.Sub(&b, &a)
    17  	return a
    18  
    19  }
    20  
    21  func buildPoly(size int, form Form) *Polynomial {
    22  	v := make([]fr.Element, size)
    23  	return NewPolynomial(&v, form)
    24  }
    25  
    26  func TestDivideByXMinusOne(t *testing.T) {
    27  
    28  	f := func(_ int, x ...fr.Element) fr.Element {
    29  		var a, b fr.Element
    30  		a.Square(&x[0]).Mul(&a, &x[1]).Add(&a, &x[2])
    31  		b.Square(&x[0]).Mul(&b, &x[0])
    32  		a.Sub(&a, &b)
    33  		return a
    34  	}
    35  
    36  	// create the multivariate polynomial h
    37  	// h(x₁,x₂,x₃) = x₁^{2}*x₂ + x₃ - x₁^{3}
    38  	nbEntries := 3
    39  
    40  	// create an instance (f_i) where h holds
    41  	sizeSystem := 8
    42  
    43  	form := Form{Basis: Lagrange, Layout: Regular}
    44  
    45  	entries := make([]*Polynomial, nbEntries)
    46  	entries[0] = buildPoly(sizeSystem, form)
    47  	entries[1] = buildPoly(sizeSystem, form)
    48  	entries[2] = buildPoly(sizeSystem, form)
    49  
    50  	for i := 0; i < sizeSystem; i++ {
    51  
    52  		entries[0].Coefficients()[i].SetRandom()
    53  		entries[1].Coefficients()[i].SetRandom()
    54  		tmp := computex3(
    55  			[]fr.Element{entries[0].Coefficients()[i],
    56  				entries[1].Coefficients()[i]})
    57  		entries[2].Coefficients()[i].Set(&tmp)
    58  
    59  		x := []fr.Element{
    60  			entries[0].GetCoeff(i),
    61  			entries[1].GetCoeff(i),
    62  			entries[2].GetCoeff(i),
    63  		}
    64  		a := f(0, x...)
    65  		if !a.IsZero() {
    66  			t.Fatal("system does not vanish on x^n-1")
    67  		}
    68  	}
    69  
    70  	// compute the quotient where the entries are in Regular layout
    71  	var domains [2]*fft.Domain
    72  	domains[0] = fft.NewDomain(uint64(sizeSystem))
    73  	domains[1] = fft.NewDomain(ecc.NextPowerOfTwo(uint64(3 * sizeSystem)))
    74  
    75  	entries[0].ToCanonical(domains[0]).
    76  		ToRegular().
    77  		ToLagrangeCoset(domains[1]).
    78  		ToRegular()
    79  
    80  	entries[1].ToCanonical(domains[0]).
    81  		ToRegular().
    82  		ToLagrangeCoset(domains[1]).
    83  		ToRegular()
    84  
    85  	entries[2].ToCanonical(domains[0]).
    86  		ToRegular().
    87  		ToLagrangeCoset(domains[1]).
    88  		ToRegular()
    89  
    90  	expectedForm := Form{Layout: BitReverse, Basis: LagrangeCoset}
    91  	h, err := Evaluate(f, nil, expectedForm, entries...)
    92  	if err != nil {
    93  		t.Fatal(err)
    94  	}
    95  
    96  	q, err := DivideByXMinusOne(h, domains)
    97  	if err != nil {
    98  		t.Fatal(err)
    99  	}
   100  
   101  	// evaluate the quotient at a random point and check that
   102  	// the relation holds.
   103  	var x fr.Element
   104  	x.SetRandom()
   105  	qx := q.Evaluate(x)
   106  	entries[0].ToCanonical(domains[1])
   107  	entries[1].ToCanonical(domains[1])
   108  	entries[2].ToCanonical(domains[1])
   109  	ax := entries[0].Evaluate(x)
   110  	bx := entries[1].Evaluate(x)
   111  	cx := entries[2].Evaluate(x)
   112  	hx := f(0, ax, bx, cx)
   113  
   114  	var xnminusone, one fr.Element
   115  	one.SetOne()
   116  	xnminusone.Set(&x).
   117  		Square(&xnminusone).
   118  		Square(&xnminusone).
   119  		Square(&xnminusone).
   120  		Sub(&xnminusone, &one)
   121  	qx.Mul(&qx, &xnminusone)
   122  	if !qx.Equal(&hx) {
   123  		t.Fatal("error computing quotient")
   124  	}
   125  }