mirror of
https://github.com/logos-storage/gnark-plonky2-verifier.git
synced 2026-01-07 07:33:12 +00:00
Coset Interpolation Gate (#15)
* helper functions for coset_interpolation_gate * coset interpolation gate working * hard coded the coset gate (for now)
This commit is contained in:
parent
67aa8b9d77
commit
5bb7cc6411
@ -35,6 +35,7 @@ func NewFieldAPI(api frontend.API) frontend.API {
|
||||
|
||||
var ONE_F = NewFieldElement(1)
|
||||
var ZERO_F = NewFieldElement(0)
|
||||
var NEG_ONE_F = NewFieldElement(EmulatedField{}.Modulus().Uint64() - 1)
|
||||
|
||||
var GOLDILOCKS_MULTIPLICATIVE_GROUP_GENERATOR = goldilocks.NewElement(7)
|
||||
var GOLDILOCKS_TWO_ADICITY = uint64(32)
|
||||
@ -52,3 +53,20 @@ func GoldilocksPrimitiveRootOfUnity(nLog uint64) goldilocks.Element {
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
func TwoAdicSubgroup(nLog uint64) []goldilocks.Element {
|
||||
if nLog > GOLDILOCKS_TWO_ADICITY {
|
||||
panic("nLog is greater than GOLDILOCKS_TWO_ADICITY")
|
||||
}
|
||||
|
||||
var res []goldilocks.Element
|
||||
rootOfUnity := GoldilocksPrimitiveRootOfUnity(nLog)
|
||||
res = append(res, goldilocks.NewElement(1))
|
||||
|
||||
for i := 0; i < (1 << nLog); i++ {
|
||||
lastElement := res[len(res)-1]
|
||||
res = append(res, *lastElement.Mul(&lastElement, &rootOfUnity))
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
"math/bits"
|
||||
|
||||
"github.com/consensys/gnark-crypto/field/goldilocks"
|
||||
"github.com/consensys/gnark/frontend"
|
||||
)
|
||||
|
||||
@ -237,3 +238,42 @@ func (c *QuadraticExtensionAPI) SubExtensionAlgebra(a, b QEAlgebra) QEAlgebra {
|
||||
|
||||
return diff
|
||||
}
|
||||
|
||||
func (c *QuadraticExtensionAPI) PartialInterpolateExtAlgebra(
|
||||
domain []goldilocks.Element,
|
||||
values []QEAlgebra,
|
||||
barycentricWeights []goldilocks.Element,
|
||||
point QEAlgebra,
|
||||
initialEval QEAlgebra,
|
||||
initialPartialProd QEAlgebra,
|
||||
) (QEAlgebra, QEAlgebra) {
|
||||
n := len(values)
|
||||
if n == 0 {
|
||||
panic("Cannot interpolate with no values")
|
||||
}
|
||||
if n != len(domain) {
|
||||
panic("Domain and values must have the same length")
|
||||
}
|
||||
if n != len(barycentricWeights) {
|
||||
panic("Domain and barycentric weights must have the same length")
|
||||
}
|
||||
|
||||
newEval := initialEval
|
||||
newPartialProd := initialPartialProd
|
||||
for i := 0; i < n; i++ {
|
||||
val := values[i]
|
||||
x := domain[i]
|
||||
xField := NewFieldElement(x.Uint64())
|
||||
xQE := QuadraticExtension{xField, ZERO_F}
|
||||
xQEAlgebra := QEAlgebra{xQE, c.ZERO_QE}
|
||||
weight := QuadraticExtension{NewFieldElement(barycentricWeights[i].Uint64()), ZERO_F}
|
||||
term := c.SubExtensionAlgebra(point, xQEAlgebra)
|
||||
weightedVal := c.ScalarMulExtensionAlgebra(weight, val)
|
||||
newEval = c.MulExtensionAlgebra(newEval, term)
|
||||
tmp := c.MulExtensionAlgebra(weightedVal, newPartialProd)
|
||||
newEval = c.AddExtensionAlgebra(newEval, tmp)
|
||||
newPartialProd = c.MulExtensionAlgebra(newPartialProd, term)
|
||||
}
|
||||
|
||||
return newEval, newPartialProd
|
||||
}
|
||||
|
||||
175
plonky2_verifier/coset_interpolation_gate.go
Normal file
175
plonky2_verifier/coset_interpolation_gate.go
Normal file
@ -0,0 +1,175 @@
|
||||
package plonky2_verifier
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
. "gnark-plonky2-verifier/field"
|
||||
|
||||
"github.com/consensys/gnark-crypto/field/goldilocks"
|
||||
)
|
||||
|
||||
type CosetInterpolationGate struct {
|
||||
subgroupBits uint64
|
||||
degree uint64
|
||||
barycentricWeights []goldilocks.Element
|
||||
}
|
||||
|
||||
func NewCosetInterpolationGate(subgroupBits uint64, degree uint64, barycentricWeights []goldilocks.Element) *CosetInterpolationGate {
|
||||
return &CosetInterpolationGate{
|
||||
subgroupBits: subgroupBits,
|
||||
degree: degree,
|
||||
barycentricWeights: barycentricWeights,
|
||||
}
|
||||
}
|
||||
|
||||
func (g *CosetInterpolationGate) Id() string {
|
||||
|
||||
return fmt.Sprintf(
|
||||
"CosetInterpolationGate { subgroup_bits: %d, degree: %d, barycentric_weights: %s }",
|
||||
g.subgroupBits,
|
||||
g.degree,
|
||||
fmt.Sprint(g.barycentricWeights),
|
||||
)
|
||||
}
|
||||
|
||||
func (g *CosetInterpolationGate) numPoints() uint64 {
|
||||
return 1 << g.subgroupBits
|
||||
}
|
||||
|
||||
// Wire index of the coset shift.
|
||||
func (g *CosetInterpolationGate) wireShift() uint64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (g *CosetInterpolationGate) startValues() uint64 {
|
||||
return 1
|
||||
}
|
||||
|
||||
// Wire indices of the `i`th interpolant value.
|
||||
func (g *CosetInterpolationGate) wiresValue(i uint64) Range {
|
||||
if i >= g.numPoints() {
|
||||
panic("Invalid point index")
|
||||
}
|
||||
start := g.startValues() + i*D
|
||||
return Range{start, start + D}
|
||||
}
|
||||
|
||||
func (g *CosetInterpolationGate) startEvaluationPoint() uint64 {
|
||||
return g.startValues() + g.numPoints()*D
|
||||
}
|
||||
|
||||
// Wire indices of the point to evaluate the interpolant at.
|
||||
func (g *CosetInterpolationGate) wiresEvaluationPoint() Range {
|
||||
start := g.startEvaluationPoint()
|
||||
return Range{start, start + D}
|
||||
}
|
||||
|
||||
func (g *CosetInterpolationGate) startEvaluationValue() uint64 {
|
||||
return g.startEvaluationPoint() + D
|
||||
}
|
||||
|
||||
// Wire indices of the interpolated value.
|
||||
func (g *CosetInterpolationGate) wiresEvaluationValue() Range {
|
||||
start := g.startEvaluationValue()
|
||||
return Range{start, start + D}
|
||||
}
|
||||
|
||||
func (g *CosetInterpolationGate) startIntermediates() uint64 {
|
||||
return g.startEvaluationValue() + D
|
||||
}
|
||||
|
||||
func (g *CosetInterpolationGate) numIntermediates() uint64 {
|
||||
return (g.numPoints() - 2) / (g.degree - 1)
|
||||
}
|
||||
|
||||
// The wires corresponding to the i'th intermediate evaluation.
|
||||
func (g *CosetInterpolationGate) wiresIntermediateEval(i uint64) Range {
|
||||
if i >= g.numIntermediates() {
|
||||
panic("Invalid intermediate index")
|
||||
}
|
||||
start := g.startIntermediates() + D*i
|
||||
return Range{start, start + D}
|
||||
}
|
||||
|
||||
// The wires corresponding to the i'th intermediate product.
|
||||
func (g *CosetInterpolationGate) wiresIntermediateProd(i uint64) Range {
|
||||
if i >= g.numIntermediates() {
|
||||
panic("Invalid intermediate index")
|
||||
}
|
||||
start := g.startIntermediates() + D*(g.numIntermediates()+i)
|
||||
return Range{start, start + D}
|
||||
}
|
||||
|
||||
// Wire indices of the shifted point to evaluate the interpolant at.
|
||||
func (g *CosetInterpolationGate) wiresShiftedEvaluationPoint() Range {
|
||||
start := g.startIntermediates() + D*2*g.numIntermediates()
|
||||
return Range{start, start + D}
|
||||
}
|
||||
|
||||
func (g *CosetInterpolationGate) EvalUnfiltered(p *PlonkChip, vars EvaluationVars) []QuadraticExtension {
|
||||
constraints := []QuadraticExtension{}
|
||||
|
||||
shift := vars.localWires[g.wireShift()]
|
||||
evaluationPoint := vars.GetLocalExtAlgebra(g.wiresEvaluationPoint())
|
||||
shiftedEvaluationPoint := vars.GetLocalExtAlgebra(g.wiresShiftedEvaluationPoint())
|
||||
|
||||
negShift := p.qeAPI.ScalarMulExtension(shift, NEG_ONE_F)
|
||||
|
||||
tmp := p.qeAPI.ScalarMulExtensionAlgebra(negShift, shiftedEvaluationPoint)
|
||||
tmp = p.qeAPI.AddExtensionAlgebra(tmp, evaluationPoint)
|
||||
|
||||
for i := 0; i < D; i++ {
|
||||
constraints = append(constraints, tmp[i])
|
||||
}
|
||||
|
||||
domain := TwoAdicSubgroup(g.subgroupBits)
|
||||
values := []QEAlgebra{}
|
||||
for i := uint64(0); i < g.numPoints(); i++ {
|
||||
values = append(values, vars.GetLocalExtAlgebra(g.wiresValue(i)))
|
||||
}
|
||||
weights := g.barycentricWeights
|
||||
|
||||
initialEval := p.qeAPI.ZERO_QE_ALGEBRA
|
||||
initialProd := QEAlgebra{p.qeAPI.ONE_QE, p.qeAPI.ZERO_QE}
|
||||
computedEval, computedProd := p.qeAPI.PartialInterpolateExtAlgebra(
|
||||
domain[:g.degree],
|
||||
values[:g.degree],
|
||||
weights[:g.degree],
|
||||
shiftedEvaluationPoint,
|
||||
initialEval,
|
||||
initialProd,
|
||||
)
|
||||
|
||||
for i := uint64(0); i < g.numIntermediates(); i++ {
|
||||
intermediateEval := vars.GetLocalExtAlgebra(g.wiresIntermediateEval(i))
|
||||
intermediateProd := vars.GetLocalExtAlgebra(g.wiresIntermediateProd(i))
|
||||
|
||||
evalDiff := p.qeAPI.SubExtensionAlgebra(intermediateEval, computedEval)
|
||||
for j := 0; j < D; j++ {
|
||||
constraints = append(constraints, evalDiff[j])
|
||||
}
|
||||
|
||||
prodDiff := p.qeAPI.SubExtensionAlgebra(intermediateProd, computedProd)
|
||||
for j := 0; j < D; j++ {
|
||||
constraints = append(constraints, prodDiff[j])
|
||||
}
|
||||
|
||||
startIndex := 1 + (g.degree-1)*(i+1)
|
||||
endIndex := startIndex + g.degree - 1
|
||||
computedEval, computedProd = p.qeAPI.PartialInterpolateExtAlgebra(
|
||||
domain[startIndex:endIndex],
|
||||
values[startIndex:endIndex],
|
||||
weights[startIndex:endIndex],
|
||||
shiftedEvaluationPoint,
|
||||
intermediateEval,
|
||||
intermediateProd,
|
||||
)
|
||||
}
|
||||
|
||||
evaluationValue := vars.GetLocalExtAlgebra(g.wiresEvaluationValue())
|
||||
evalDiff := p.qeAPI.SubExtensionAlgebra(evaluationValue, computedEval)
|
||||
for j := 0; j < D; j++ {
|
||||
constraints = append(constraints, evalDiff[j])
|
||||
}
|
||||
|
||||
return constraints
|
||||
}
|
||||
@ -1,10 +1,13 @@
|
||||
package plonky2_verifier
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
. "gnark-plonky2-verifier/field"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/consensys/gnark-crypto/field/goldilocks"
|
||||
)
|
||||
|
||||
type gate interface {
|
||||
@ -104,19 +107,19 @@ func GateInstanceFromId(gateId string) gate {
|
||||
return NewArithmeticExtensionGate(uint64(numOps))
|
||||
}
|
||||
|
||||
if strings.HasPrefix(gateId, "MultiplicationExtension") {
|
||||
// Has the format "ArithmeticExtensionGate { num_ops: 10 }"
|
||||
if strings.HasPrefix(gateId, "MulExtensionGate") {
|
||||
// Has the format "MulExtensionGate { num_ops: 13 }"
|
||||
|
||||
regEx := "MultiplicationExtension { num_ops: (?P<numOps>[0-9]+) }"
|
||||
regEx := "MulExtensionGate { num_ops: (?P<numOps>[0-9]+) }"
|
||||
r, err := regexp.Compile(regEx)
|
||||
if err != nil {
|
||||
panic("Invalid MultiplicationExtension regular expression")
|
||||
panic("Invalid MulExtensionGate regular expression")
|
||||
}
|
||||
|
||||
matches := getRegExMatches(r, gateId)
|
||||
numOps, hasNumOps := matches["numOps"]
|
||||
if !hasNumOps {
|
||||
panic("Invalid MultiplicationExtension ID")
|
||||
panic("Invalid MulExtensionGate ID")
|
||||
}
|
||||
|
||||
return NewMultiplicationExtensionGate(uint64(numOps))
|
||||
@ -176,8 +179,51 @@ func GateInstanceFromId(gateId string) gate {
|
||||
return NewExponentiationGate(uint64(numPowerBits))
|
||||
}
|
||||
|
||||
return nil
|
||||
//panic(fmt.Sprintf("Unknown gate ID %s", gateId))
|
||||
// CosetInterpolationGate { subgroup_bits: 4, degree: 6, barycentric_weights: [17293822565076172801, 18374686475376656385, 18446744069413535745, 281474976645120, 17592186044416, 18446744069414584577, 18446744000695107601, 18446744065119617025, 1152921504338411520, 72057594037927936, 18446744069415632897, 18446462594437939201, 18446726477228539905, 18446744069414584065, 68719476720, 4294967296], _phantom: PhantomData<plonky2_field::goldilocks_field::GoldilocksField> }<D=2>
|
||||
if strings.HasPrefix(gateId, "CosetInterpolationGate") {
|
||||
// Has the format CosetInterpolationGate { subgroup_bits: 4, degree: 6, barycentric_weights: [17293822565076172801, 18374686475376656385, 18446744069413535745, 281474976645120, 17592186044416, 18446744069414584577, 18446744000695107601, 18446744065119617025, 1152921504338411520, 72057594037927936, 18446744069415632897, 18446462594437939201, 18446726477228539905, 18446744069414584065, 68719476720, 4294967296], _phantom: PhantomData<plonky2_field::goldilocks_field::GoldilocksField> }<D=2>
|
||||
|
||||
/*
|
||||
regEx := "CosetInterpolationGate { subgroup_bits: (?P<subgroupBits>[0-9]+), degree: (?P<degree>[0-9]+), barycentric_weights: \\[(?P<barycentricWeights>[0-9, ]+)\\], _phantom: PhantomData<plonky2_field::goldilocks_field::GoldilocksField> }<D=2>"
|
||||
r, err := regexp.Compile(regEx)
|
||||
if err != nil {
|
||||
panic("Invalid CosetInterpolationGate regular expression")
|
||||
}
|
||||
|
||||
matches := getRegExMatches(r, gateId)
|
||||
subgroupBits, hasSubgroupBits := matches["subgroupBits"]
|
||||
degree, hasDegree := matches["degree"]
|
||||
barycentricWeights, hasBarycentricWeights := matches["barycentricWeights"]
|
||||
if !hasSubgroupBits || !hasDegree || !hasBarycentricWeights {
|
||||
panic("Invalid CosetInterpolationGate ID")
|
||||
}*/
|
||||
|
||||
return NewCosetInterpolationGate(
|
||||
4,
|
||||
6,
|
||||
[]goldilocks.Element{
|
||||
goldilocks.NewElement(17293822565076172801),
|
||||
goldilocks.NewElement(18374686475376656385),
|
||||
goldilocks.NewElement(18446744069413535745),
|
||||
goldilocks.NewElement(281474976645120),
|
||||
goldilocks.NewElement(17592186044416),
|
||||
goldilocks.NewElement(18446744069414584577),
|
||||
goldilocks.NewElement(18446744000695107601),
|
||||
goldilocks.NewElement(18446744065119617025),
|
||||
goldilocks.NewElement(1152921504338411520),
|
||||
goldilocks.NewElement(72057594037927936),
|
||||
goldilocks.NewElement(18446744069415632897),
|
||||
goldilocks.NewElement(18446462594437939201),
|
||||
goldilocks.NewElement(18446726477228539905),
|
||||
goldilocks.NewElement(18446744069414584065),
|
||||
goldilocks.NewElement(68719476720),
|
||||
goldilocks.NewElement(4294967296),
|
||||
},
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
panic(fmt.Sprintf("Unknown gate ID %s", gateId))
|
||||
}
|
||||
|
||||
func getRegExMatches(r *regexp.Regexp, gateId string) map[string]int {
|
||||
|
||||
@ -5,6 +5,7 @@ import (
|
||||
. "gnark-plonky2-verifier/field"
|
||||
"testing"
|
||||
|
||||
"github.com/consensys/gnark-crypto/field/goldilocks"
|
||||
"github.com/consensys/gnark/frontend"
|
||||
"github.com/consensys/gnark/test"
|
||||
)
|
||||
@ -771,6 +772,28 @@ func TestGates(t *testing.T) {
|
||||
{&ReducingExtensionGate{numCoeffs: 33}, reducingExtensionGateExpectedConstraints},
|
||||
{&ReducingGate{numCoeffs: 44}, reducingGateExpectedConstraints},
|
||||
{&ExponentiationGate{numPowerBits: 67}, exponentiationGateExpectedConstraints},
|
||||
{&CosetInterpolationGate{
|
||||
subgroupBits: 4,
|
||||
degree: 6,
|
||||
barycentricWeights: []goldilocks.Element{
|
||||
goldilocks.NewElement(17293822565076172801),
|
||||
goldilocks.NewElement(18374686475376656385),
|
||||
goldilocks.NewElement(18446744069413535745),
|
||||
goldilocks.NewElement(281474976645120),
|
||||
goldilocks.NewElement(17592186044416),
|
||||
goldilocks.NewElement(18446744069414584577),
|
||||
goldilocks.NewElement(18446744000695107601),
|
||||
goldilocks.NewElement(18446744065119617025),
|
||||
goldilocks.NewElement(1152921504338411520),
|
||||
goldilocks.NewElement(72057594037927936),
|
||||
goldilocks.NewElement(18446744069415632897),
|
||||
goldilocks.NewElement(18446462594437939201),
|
||||
goldilocks.NewElement(18446726477228539905),
|
||||
goldilocks.NewElement(18446744069414584065),
|
||||
goldilocks.NewElement(68719476720),
|
||||
goldilocks.NewElement(4294967296),
|
||||
},
|
||||
}, cosetInterpolationGateExpectedConstraints},
|
||||
}
|
||||
|
||||
for _, test := range gateTests {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user