Skip to content
Open
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
e19129c
chore: gnark update
ivokub Nov 17, 2025
cb05285
chore: implement p256verify glue
ivokub Nov 17, 2025
332f497
fix: enforce public vars
ivokub Nov 18, 2025
7620614
test: add testdata generator
ivokub Nov 18, 2025
119bd71
feat: implement inputfiller
ivokub Nov 18, 2025
dae2651
test: do not write noop test cases
ivokub Nov 18, 2025
d4094d3
test: implement unit tests
ivokub Nov 18, 2025
2aa908b
test: include generated tests
ivokub Nov 18, 2025
1ae0acc
docs: refer to test vector location
ivokub Nov 18, 2025
bdfa261
chore: gnark update
ivokub Nov 19, 2025
0aab08d
docs: circuit size
ivokub Nov 19, 2025
abedf2e
fix: correct instance number calculation
ivokub Nov 19, 2025
81d6377
feat: loat p256 module
ivokub Nov 19, 2025
1cf0482
Merge branch 'feat/bls-glue' into feat/secp256r1
ivokub Nov 19, 2025
03437cf
feat: define p256 input instance count
ivokub Nov 19, 2025
9c19167
fix: ensure assignment is called
ivokub Nov 19, 2025
7b78570
chore: gnark update to master
ivokub Nov 24, 2025
d506919
fix: column names
ivokub Nov 24, 2025
8fa0879
Merge branch 'feat/bls-glue' into feat/secp256r1
ivokub Nov 24, 2025
4fbdc96
chore: connect zkevm p256 module with circuit
ivokub Nov 24, 2025
f6d1ddf
Merge branch 'feat/bls-glue' into feat/secp256r1
ivokub Nov 25, 2025
766211d
feat: implement p256 circuits serialization types in registry
ivokub Nov 25, 2025
984921e
fix: export types for serialization
ivokub Nov 25, 2025
ca69bc9
Merge branch 'feat/bls-glue' into feat/secp256r1
ivokub Nov 25, 2025
798d22c
Merge branch 'feat/bls-glue' into feat/secp256r1
ivokub Nov 25, 2025
20af8d8
fix: correct order of point coordinates in inputfiller
ivokub Nov 27, 2025
811afa0
Merge branch 'feat/bls-glue' into feat/secp256r1
ivokub Nov 29, 2025
b338b8d
fix(p256): number of circuit instances computed from limit
ivokub Nov 28, 2025
7114930
Merge branch 'feat/bls-glue' into feat/secp256r1
ivokub Dec 1, 2025
0e9acb0
test: add unit tests directly from trace
ivokub Dec 1, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
197 changes: 197 additions & 0 deletions prover/zkevm/prover/p256verify/arithmetization_integration_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
package p256verify

import (
"errors"
"os"
"path/filepath"
"slices"
"testing"

"github.com/consensys/go-corset/pkg/asm"
"github.com/consensys/go-corset/pkg/binfile"
"github.com/consensys/go-corset/pkg/ir"
"github.com/consensys/go-corset/pkg/ir/air"
"github.com/consensys/go-corset/pkg/ir/mir"
"github.com/consensys/go-corset/pkg/schema"
"github.com/consensys/go-corset/pkg/trace"
"github.com/consensys/go-corset/pkg/util/field/bls12_377"
"github.com/consensys/linea-monorepo/prover/maths/common/smartvectors"
"github.com/consensys/linea-monorepo/prover/maths/field"
"github.com/consensys/linea-monorepo/prover/protocol/compiler/plonkinwizard"
"github.com/consensys/linea-monorepo/prover/protocol/ifaces"
"github.com/consensys/linea-monorepo/prover/protocol/query"
"github.com/consensys/linea-monorepo/prover/protocol/wizard"
"github.com/consensys/linea-monorepo/prover/utils"
"github.com/consensys/linea-monorepo/prover/zkevm/arithmetization"
)

// integrationTestCompiler is the compiler used for integration tests
// it can be switched to dummy.Compile for faster tests that do not check
// the actual validity of the proof. But in that case, we do not use the
// wrapped gnark circuit builder externalizing range checks.
var integrationTestCompiler = plonkinwizard.Compile

// var integrationTestCompiler = dummy.Compile

const (
zkevmBin = "../../arithmetization/zkevm.bin"
)

func parseZkEvmBin(t *testing.T, path string) (*binfile.BinaryFile, *air.Schema[bls12_377.Element], schema.LimbsMap) {
zkevm, err := os.ReadFile(path)
if err != nil {
t.Fatal(err)
}
zkbinf, _, err := arithmetization.UnmarshalZkEVMBin(zkevm)
if err != nil {
t.Fatal(err)
}
zkSchema, mapping := arithmetization.CompileZkevmBin(zkbinf, &mir.OptimisationConfig{})
return zkbinf, zkSchema, mapping
}

func parseExpandedTrace(
t *testing.T,
path string,
zkbinf *binfile.BinaryFile,
zkSchema *air.Schema[bls12_377.Element],
mapping schema.LimbsMap,
) trace.Trace[bls12_377.Element] {
f, err := os.Open(path)
if err != nil {
t.Fatal(err)
}
defer f.Close()
rawTrace, _, err := arithmetization.ReadLtTraces(f)
if err != nil {
t.Fatal(err)
}
rawTrace, errs := asm.Propagate(zkbinf.Schema, rawTrace)
if err := errors.Join(errs...); err != nil {
t.Fatal(err)
}
expandedTrace, errs := ir.NewTraceBuilder[bls12_377.Element]().
WithValidation(true).
WithExpansion(true).
// WithDefensivePadding(true).
WithRegisterMapping(mapping).
WithParallelism(true).
WithBatchSize(1024).
Build(zkSchema, rawTrace)
if err := errors.Join(errs...); err != nil {
t.Fatal(err)
}
return expandedTrace
}

func parseColumns(
t *testing.T,
expandedTrace trace.Trace[bls12_377.Element],
neededColumns []string,
) (cols map[string]trace.Column[bls12_377.Element], maxLen uint) {
foundCols := 0
modId := uint(0)
moduleFound := false
for ; modId < expandedTrace.Width(); modId++ {
if expandedTrace.Module(modId).Name() == moduleName {
moduleFound = true
break
}
}
if !moduleFound {
t.Fatal("module not found")
return nil, 0
}
mod := expandedTrace.Module(modId)
cols = make(map[string]trace.Column[bls12_377.Element])
for colId := uint(0); colId < mod.Width(); colId++ {
col := mod.Column(colId)
if slices.Contains(neededColumns, col.Name()) {
cols[col.Name()] = col
maxLen = max(maxLen, col.Data().Len())
foundCols++
}
}
if foundCols == len(neededColumns) {
return cols, utils.NextPowerOfTwo(maxLen)
}
t.Fatal("not all columns found")
return nil, 0
}

func registerColumns(_ *testing.T, builder *wizard.Builder, cols map[string]trace.Column[bls12_377.Element], maxLen uint) {
for k := range cols {
builder.RegisterCommit(colNameFn(k), int(maxLen))
}
}

func assignColumns(_ *testing.T, run *wizard.ProverRuntime, cols map[string]trace.Column[bls12_377.Element], maxLen uint) {
for colName, col := range cols {
data := col.Data()
plain := make([]field.Element, data.Len())
for i := range plain {
plain[i] = data.Get(uint(i)).Element
}
run.AssignColumn(ifaces.ColID(colNameFn(colName)), smartvectors.RightZeroPadded(plain, int(maxLen)))
}
}

func testP256VerifyOnTrace(t *testing.T, path string, limits *Limits) {
if _, err := os.Stat(zkevmBin); errors.Is(err, os.ErrNotExist) {
t.Skipf("skipping arithmetization integration tests, `%s` missing", zkevmBin)
}
neededColumns := []string{
"ID",
"CIRCUIT_SELECTOR_P256_VERIFY",
"LIMB",
"INDEX",
"IS_P256_VERIFY_DATA",
"IS_P256_VERIFY_RESULT",
}
files, err := filepath.Glob(path)
if err != nil {
t.Fatal(err)
}
if len(files) == 0 {
t.Skipf("no trace files found matching regexp \"%s\", skipping trace-based tests", path)
}
zkbinf, zkSchema, mapping := parseZkEvmBin(t, zkevmBin)
var cmp *wizard.CompiledIOP
lastMaxLen := uint(0)
var p256Verify *P256Verify
for _, file := range files {
t.Run(file, func(t *testing.T) {
expandedTrace := parseExpandedTrace(t, file, zkbinf, zkSchema, mapping)
cols, maxLen := parseColumns(t, expandedTrace, neededColumns)
if cmp == nil || lastMaxLen < maxLen {
lastMaxLen = maxLen
cmp = wizard.Compile(
func(b *wizard.Builder) {
registerColumns(t, b, cols, maxLen)
p256Verify = newP256Verify(b.CompiledIOP, limits, newP256VerifyDataSource(b.CompiledIOP))
p256Verify = p256Verify.WithCircuit(b.CompiledIOP, query.PlonkRangeCheckOption(16, 6, true))
},
integrationTestCompiler,
)
}
proof := wizard.Prove(cmp,
func(run *wizard.ProverRuntime) {
assignColumns(t, run, cols, lastMaxLen)
p256Verify.Assign(run)
})

if err := wizard.Verify(cmp, proof); err != nil {
t.Fatal("proof failed", err)
}
t.Log("proof succeeded")
})
}
}

func TestP256VerifyOnTrace(t *testing.T) {
limits := &Limits{
NbInputInstances: 6,
LimitCalls: 128,
}
testP256VerifyOnTrace(t, "testdata/*.lt", limits)
}
Loading