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 }