Skip to content

Commit

Permalink
Prover/feat/Adding field extension support to Smartvectors (#569)
Browse files Browse the repository at this point in the history
* field extension support for the maths package
  • Loading branch information
bogdanbear authored Jan 17, 2025
1 parent 3c392be commit db31170
Show file tree
Hide file tree
Showing 69 changed files with 3,766 additions and 3,922 deletions.
48 changes: 48 additions & 0 deletions prover/maths/common/polyext/gnarkpoly.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package polyext

import (
"github.com/consensys/gnark/frontend"
"github.com/consensys/linea-monorepo/prover/maths/field"
"github.com/consensys/linea-monorepo/prover/maths/field/fext/gnarkfext"
)

// EvaluateLagrangeAnyDomainGnark mirrors [EvaluateLagrangesAnyDomain] but in
// a gnark circuit. The same usage precautions applies for it.
func EvaluateLagrangeAnyDomainGnark(api frontend.API, domain []gnarkfext.Variable, x gnarkfext.Variable) []gnarkfext.Variable {

outerAPI := gnarkfext.API{Inner: api}
lagrange := make([]gnarkfext.Variable, len(domain))

for i, hi := range domain {
lhix := gnarkfext.Variable{field.One(), field.Zero()}
for j, hj := range domain {
if i == j {
// Skip it
continue
}
// more convenient to store -h instead of h
factor := outerAPI.Sub(x, hj)
den := outerAPI.Sub(hi, hj) // so x - h
den = outerAPI.Inverse(den)

// accumulate the product
lhix = outerAPI.Mul(lhix, factor, den)
}
lagrange[i] = lhix
}

return lagrange

}

// EvaluateUnivariateGnark evaluate a univariate polynomial in a gnark circuit.
// It mirrors [EvalUnivariate].
func EvaluateUnivariateGnark(api frontend.API, pol []gnarkfext.Variable, x gnarkfext.Variable) gnarkfext.Variable {
res := gnarkfext.Variable{frontend.Variable(0), frontend.Variable(0)}
outerAPI := gnarkfext.API{Inner: api}
for i := len(pol) - 1; i >= 0; i-- {
res = outerAPI.Mul(res, x)
res = outerAPI.Add(res, pol[i])
}
return res
}
99 changes: 99 additions & 0 deletions prover/maths/common/polyext/gnarkpoly_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package polyext

import (
"github.com/consensys/linea-monorepo/prover/maths/common/vectorext"
"github.com/consensys/linea-monorepo/prover/maths/field/fext"
"github.com/consensys/linea-monorepo/prover/maths/field/fext/gnarkfext"
"testing"

"github.com/consensys/gnark/frontend"
"github.com/consensys/linea-monorepo/prover/utils/gnarkutil"
"github.com/stretchr/testify/require"
)

func TestGnarkEval(t *testing.T) {

t.Run("normal-poly", func(t *testing.T) {

def := func(api frontend.API) error {
outerAPI := gnarkfext.API{Inner: api}
var (
pol = vectorext.IntoGnarkAssignment(vectorext.ForTestFromPairs(1, 2, 3, 4, -1, -2))
x = gnarkfext.Variable{2, 1}
expected = gnarkfext.Variable{
-5*fext.RootPowers[1] + 3,
-2*fext.RootPowers[1] + 1,
}
res = EvaluateUnivariateGnark(api, pol, x)
)
outerAPI.AssertIsEqual(expected, res)
return nil
}

gnarkutil.AssertCircuitSolved(t, def)
})

t.Run("empty-poly", func(t *testing.T) {
def := func(api frontend.API) error {
outerAPI := gnarkfext.API{Inner: api}
var (
pol = vectorext.IntoGnarkAssignment([]fext.Element{})
x = gnarkfext.Variable{2, 3}
expected = gnarkfext.NewZero()
res = EvaluateUnivariateGnark(api, pol, x)
)
outerAPI.AssertIsEqual(expected, res)
return nil
}
gnarkutil.AssertCircuitSolved(t, def)
})

}

func TestGnarkEvalAnyDomain(t *testing.T) {

t.Run("single-variable", func(t *testing.T) {

def := func(api frontend.API) error {
outerAPI := gnarkfext.API{Inner: api}
var (
domain = vectorext.IntoGnarkAssignment(vectorext.ForTestFromPairs(0, 0))
x = gnarkfext.Variable{42, 0}
expected = vectorext.IntoGnarkAssignment(vectorext.ForTestFromPairs(1, 0))
res = EvaluateLagrangeAnyDomainGnark(api, domain, x)
)

require.Len(t, res, len(expected))
for i := range expected {
outerAPI.AssertIsEqual(expected[i], res[i])
}

return nil
}

gnarkutil.AssertCircuitSolved(t, def)
})

t.Run("multiple-variable", func(t *testing.T) {

def := func(api frontend.API) error {
outerAPI := gnarkfext.API{Inner: api}
var (
domain = vectorext.IntoGnarkAssignment(vectorext.ForTestFromPairs(0, 0, 1, 0))
x = gnarkfext.Variable{42, 0}
expected = vectorext.IntoGnarkAssignment(vectorext.ForTestFromPairs(-41, 0, 42, 0))
res = EvaluateLagrangeAnyDomainGnark(api, domain, x)
)

require.Len(t, res, len(expected))
for i := range expected {
outerAPI.AssertIsEqual(expected[i], res[i])
}

return nil
}

gnarkutil.AssertCircuitSolved(t, def)
})

}
8 changes: 7 additions & 1 deletion prover/maths/common/polyext/poly.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package polyext

import (
"github.com/consensys/linea-monorepo/prover/maths/common/smartvectors/vectorext"
"github.com/consensys/linea-monorepo/prover/maths/common/vectorext"
"github.com/consensys/linea-monorepo/prover/maths/field"
"github.com/consensys/linea-monorepo/prover/maths/field/fext"
"github.com/consensys/linea-monorepo/prover/utils"
)
Expand All @@ -22,6 +23,11 @@ func EvalUnivariate(pol []fext.Element, x fext.Element) fext.Element {
return res
}

func EvalUnivariateBase(pol []fext.Element, x field.Element) fext.Element {
wrappedX := fext.Element{x, field.Zero()}
return EvalUnivariate(pol, wrappedX)
}

// Mul multiplies two polynomials expressed by their coefficients using the
// naive method and writes the result in res. `a` and `b` may have distinct
// degrees and the result is returned in a slice of size len(a) + len(b) - 1.
Expand Down
Loading

0 comments on commit db31170

Please sign in to comment.