From 1c84ce038cdb07f3ce4f7ce1d40bd1ecf287febf Mon Sep 17 00:00:00 2001 From: arijitdutta67 Date: Tue, 21 Jan 2025 18:51:17 +0530 Subject: [PATCH 01/13] added projection query --- prover/protocol/query/projection.go | 117 ++++++++++++++++++++--- prover/protocol/query/projection_test.go | 62 ++++++++++++ prover/protocol/wizard/compiled.go | 9 ++ 3 files changed, 177 insertions(+), 11 deletions(-) create mode 100644 prover/protocol/query/projection_test.go diff --git a/prover/protocol/query/projection.go b/prover/protocol/query/projection.go index 319708919..44b763104 100644 --- a/prover/protocol/query/projection.go +++ b/prover/protocol/query/projection.go @@ -1,35 +1,102 @@ package query import ( + "fmt" + "github.com/consensys/gnark/frontend" + "github.com/consensys/linea-monorepo/prover/maths/field" "github.com/consensys/linea-monorepo/prover/protocol/ifaces" + "github.com/consensys/linea-monorepo/prover/utils" ) +type ProjectionInput struct { + ColumnA, ColumnB []ifaces.Column + FilterA, FilterB ifaces.Column +} type Projection struct { - ID ifaces.QueryID - ColumnsA, ColumnsB []ifaces.Column - FilterA, FilterB ifaces.Column + Round int + ID ifaces.QueryID + Inp ProjectionInput } -// NewInclusion constructs an inclusion. Will panic if it is mal-formed +// NewProjection constructs a projection. Will panic if it is mal-formed func NewProjection( + round int, id ifaces.QueryID, - columnsA, columnsB []ifaces.Column, - filterA, filterB ifaces.Column, + inp ProjectionInput, ) Projection { + var ( + sizeA = inp.FilterA.Size() + sizeB = inp.FilterB.Size() + numCol = len(inp.ColumnA) + ) + if len(inp.ColumnB) != numCol { + utils.Panic("A and B must have the same number of columns") + } + + if ifaces.AssertSameLength(inp.ColumnA...) != sizeA { + utils.Panic("A and its filter do not have the same column sizes") + } - return Projection{ColumnsA: columnsA, ColumnsB: columnsB, ID: id, FilterA: filterA, FilterB: filterB} + if ifaces.AssertSameLength(inp.ColumnB...) != sizeB { + utils.Panic("B and its filter do not have the same column sizes") + } + return Projection{Round: round, ID: id, Inp: inp} } // Name implements the [ifaces.Query] interface -func (r Projection) Name() ifaces.QueryID { - return r.ID +func (p Projection) Name() ifaces.QueryID { + return p.ID } // Check implements the [ifaces.Query] interface -func (r Projection) Check(run ifaces.Runtime) error { +func (p Projection) Check(run ifaces.Runtime) error { + var ( + numCols = len(p.Inp.ColumnA) + sizeA = p.Inp.ColumnA[0].Size() + sizeB = p.Inp.ColumnB[0].Size() + linCombRand, evalRand field.Element + a = make([]ifaces.ColAssignment, numCols) + b = make([]ifaces.ColAssignment, numCols) + fA = p.Inp.FilterA.GetColAssignment(run).IntoRegVecSaveAlloc() + fB = p.Inp.FilterB.GetColAssignment(run).IntoRegVecSaveAlloc() + aLinComb = make([]field.Element, sizeA) + bLinComb = make([]field.Element, sizeB) + ) + _, errAlpha := linCombRand.SetRandom() + _, errBeta := evalRand.SetRandom() + if errAlpha != nil { + // Cannot happen unless the entropy was exhausted + panic(errAlpha) + } + if errBeta != nil { + // Cannot happen unless the entropy was exhausted + panic(errBeta) + } + // Populate a + for colIndex, pol := range p.Inp.ColumnA { + a[colIndex] = pol.GetColAssignment(run) + } + // Populate b + for colIndex, pol := range p.Inp.ColumnB { + b[colIndex] = pol.GetColAssignment(run) + } + // Compute the linear combination of the columns of a and b + for row := 0; row < sizeA; row++ { + aLinComb[row] = rowLinComb(linCombRand, row, a) + } + for row := 0; row < sizeB; row++ { + bLinComb[row] = rowLinComb(linCombRand, row, b) + } + var ( + hornerA = cmptHorner(aLinComb, fA, evalRand) + hornerB = cmptHorner(bLinComb, fB, evalRand) + ) + if hornerA[0] != hornerB[0] { + return fmt.Errorf("the projection query %v check is not satisfied", p.ID) + } - panic("unimplemented") + return nil } // GnarkCheck implements the [ifaces.Query] interface. It will panic in this @@ -38,3 +105,31 @@ func (r Projection) Check(run ifaces.Runtime) error { func (i Projection) CheckGnark(api frontend.API, run ifaces.GnarkRuntime) { panic("UNSUPPORTED : can't check an Projection query directly into the circuit") } + +// cmptHorner computes a random Horner accumulation of the filtered elements +// starting from the last entry down to the first entry. The final value is +// stored in the last entry of the returned slice. +// Todo: send it to a common utility package +func cmptHorner(c, fC []field.Element, x field.Element) []field.Element { + + var ( + horner = make([]field.Element, len(c)) + prev field.Element + ) + + for i := len(horner) - 1; i >= 0; i-- { + + if !fC[i].IsZero() && !fC[i].IsOne() { + utils.Panic("we expected the filter to be binary") + } + + if fC[i].IsOne() { + prev.Mul(&prev, &x) + prev.Add(&prev, &c[i]) + } + + horner[i] = prev + } + + return horner +} diff --git a/prover/protocol/query/projection_test.go b/prover/protocol/query/projection_test.go new file mode 100644 index 000000000..4b0498e4d --- /dev/null +++ b/prover/protocol/query/projection_test.go @@ -0,0 +1,62 @@ +package query_test + +import ( + "testing" + + "github.com/consensys/linea-monorepo/prover/maths/common/smartvectors" + "github.com/consensys/linea-monorepo/prover/maths/field" + "github.com/consensys/linea-monorepo/prover/protocol/ifaces" + "github.com/consensys/linea-monorepo/prover/protocol/query" + "github.com/consensys/linea-monorepo/prover/protocol/wizard" +) + +func TestProjection(t *testing.T) { + var ( + runS *wizard.ProverRuntime + P ifaces.Query + round = 0 + flagSizeA = 512 + flagSizeB = 256 + flagA, flagB, columnA, columnB ifaces.Column + ) + + define := func(build *wizard.Builder) { + comp := build.CompiledIOP + flagA = comp.InsertCommit(round, ifaces.ColID("FilterA"), flagSizeA) + flagB = comp.InsertCommit(round, ifaces.ColID("FliterB"), flagSizeB) + columnA = comp.InsertCommit(round, ifaces.ColID("ColumnA"), flagSizeA) + columnB = comp.InsertCommit(round, ifaces.ColID("ColumnB"), flagSizeB) + P = comp.InsertProjection(round, "ProjectionTest", + query.ProjectionInput{ColumnA: []ifaces.Column{columnA}, ColumnB: []ifaces.Column{columnB}, FilterA: flagA, FilterB: flagB}) + + } + prover := func(run *wizard.ProverRuntime) { + runS = run + // assign filters and columns + flagAWit := make([]field.Element, flagSizeA) + columnAWit := make([]field.Element, flagSizeA) + flagBWit := make([]field.Element, flagSizeB) + columnBWit := make([]field.Element, flagSizeB) + for i := 0; i < 10; i++ { + flagAWit[i] = field.One() + columnAWit[i] = field.NewElement(uint64(i)) + } + for i := flagSizeB - 10; i < flagSizeB; i++ { + flagBWit[i] = field.One() + columnBWit[i] = field.NewElement(uint64(i - (flagSizeB - 10))) + } + run.AssignColumn(flagA.GetColID(), smartvectors.RightZeroPadded(flagAWit, flagSizeA)) + run.AssignColumn(flagB.GetColID(), smartvectors.RightZeroPadded(flagBWit, flagSizeB)) + run.AssignColumn(columnB.GetColID(), smartvectors.RightZeroPadded(columnBWit, flagSizeB)) + run.AssignColumn(columnA.GetColID(), smartvectors.RightZeroPadded(columnAWit, flagSizeA)) + } + var ( + comp_ = wizard.Compile(define) + _ = wizard.Prove(comp_, prover) + errG = P.Check(runS) + ) + + if errG != nil { + t.Fatalf("error verifying the projection query: %v", errG.Error()) + } +} diff --git a/prover/protocol/wizard/compiled.go b/prover/protocol/wizard/compiled.go index af3c80f74..31f4036a3 100644 --- a/prover/protocol/wizard/compiled.go +++ b/prover/protocol/wizard/compiled.go @@ -653,3 +653,12 @@ func (c *CompiledIOP) InsertGrandProduct(round int, id ifaces.QueryID, in map[in c.QueriesParams.AddToRound(round, q.Name(), q) return q } + +// Register a Projection query +func (c *CompiledIOP) InsertProjection(round int, id ifaces.QueryID, in query.ProjectionInput) query.Projection { + c.assertConsistentRound(round) + q := query.NewProjection(round,id, in) + // Finally registers the query + c.QueriesNoParams.AddToRound(round, q.Name(), q) + return q +} From 82734442d197d3a20908cd35e5238e51b3634130 Mon Sep 17 00:00:00 2001 From: arijitdutta67 Date: Thu, 23 Jan 2025 12:07:30 +0530 Subject: [PATCH 02/13] compiler for projection added --- .../protocol/compiler/projection/compiler.go | 158 ++++++++++++++++++ .../compiler/projection/compiler_test.go | 62 +++++++ prover/protocol/compiler/projection/prover.go | 128 ++++++++++++++ prover/protocol/compiler/projection/utils.go | 33 ++++ .../protocol/compiler/projection/verifier.go | 54 ++++++ 5 files changed, 435 insertions(+) create mode 100644 prover/protocol/compiler/projection/compiler.go create mode 100644 prover/protocol/compiler/projection/compiler_test.go create mode 100644 prover/protocol/compiler/projection/prover.go create mode 100644 prover/protocol/compiler/projection/utils.go create mode 100644 prover/protocol/compiler/projection/verifier.go diff --git a/prover/protocol/compiler/projection/compiler.go b/prover/protocol/compiler/projection/compiler.go new file mode 100644 index 000000000..4c6aa8960 --- /dev/null +++ b/prover/protocol/compiler/projection/compiler.go @@ -0,0 +1,158 @@ +package projection + +import ( + "github.com/consensys/linea-monorepo/prover/protocol/coin" + "github.com/consensys/linea-monorepo/prover/protocol/column" + "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/protocol/wizardutils" + sym "github.com/consensys/linea-monorepo/prover/symbolic" +) + +// CompileProjection compiles [query.Projection] queries +func CompileProjection(comp *wizard.CompiledIOP) { + + for _, qName := range comp.QueriesNoParams.AllUnignoredKeys() { + // Filter out non projection queries + projection, ok := comp.QueriesNoParams.Data(qName).(query.Projection) + if !ok { + continue + } + + // This ensures that the projection query is not used again in the + // compilation process. We know that the query was not already ignored at the beginning + // because we are iterating over the unignored keys. + comp.QueriesNoParams.MarkAsIgnored(qName) + round := comp.QueriesNoParams.Round(qName) + compile(comp, round, projection) + } + +} + +func compile(comp *wizard.CompiledIOP, round int, projection query.Projection) { + var ( + compRound = round + sizeA = projection.Inp.FilterA.Size() + sizeB = projection.Inp.FilterB.Size() + numCol = len(projection.Inp.ColumnA) + a, b, af, bf any + queryName = projection.ID + columnsA = projection.Inp.ColumnA + columnsB = projection.Inp.ColumnB + filterA = projection.Inp.FilterA + filterB = projection.Inp.FilterB + ) + + // a and b are storing the columns used to compute the linear combination + // of the columnsA and columnsB. The initial assignment is for the case + // where there is only a single column. If there is more than one column + // then they will store an expression computing a random linear + // combination of the columns. + a, b = projection.Inp.ColumnA[0], projection.Inp.ColumnB[0] + + // af and bf are as a and b but shifted by -1. They are initially + // assigned assuming the case where the number of column is 1 and + // replaced later by a random linear combination if not. They are meant + // to be used in the local constraints to point to the last entry of the + // "a" and "b". + af, bf = column.Shift(projection.Inp.ColumnA[0], -1), column.Shift(projection.Inp.ColumnB[0], -1) + + if numCol > 0 { + compRound++ + alpha := comp.InsertCoin(compRound, coin.Namef("%v_MERGING_COIN", queryName), coin.Field) + a = wizardutils.RandLinCombColSymbolic(alpha, columnsA) + b = wizardutils.RandLinCombColSymbolic(alpha, columnsB) + + afs := make([]ifaces.Column, numCol) + bfs := make([]ifaces.Column, numCol) + + for i := range afs { + afs[i] = column.Shift(columnsA[i], -1) + bfs[i] = column.Shift(columnsB[i], -1) + } + + af = wizardutils.RandLinCombColSymbolic(alpha, afs) + bf = wizardutils.RandLinCombColSymbolic(alpha, bfs) + } + + var ( + aExpr, _, _ = wizardutils.AsExpr(a) + bExpr, _, _ = wizardutils.AsExpr(b) + pa = projectionProverAction{ + Name: queryName, + EvalCoin: comp.InsertCoin(compRound, coin.Namef("%v_EVAL_COIN", queryName), coin.Field), + FilterA: filterA, + FilterB: filterB, + ColA: columnsA, + ColB: columnsB, + ABoard: aExpr.Board(), + BBoard: bExpr.Board(), + HornerA: comp.InsertCommit(compRound, ifaces.ColIDf("%v_HORNER_A", queryName), sizeA), + HornerB: comp.InsertCommit(compRound, ifaces.ColIDf("%v_HORNER_B", queryName), sizeB), + } + ) + + comp.InsertGlobal( + compRound, + ifaces.QueryIDf("%v_HORNER_A_GLOBAL", queryName), + sym.Sub( + pa.HornerA, + sym.Mul( + sym.Sub(1, pa.FilterA), + column.Shift(pa.HornerA, 1), + ), + sym.Mul( + pa.FilterA, + sym.Add( + a, + sym.Mul( + pa.EvalCoin, + column.Shift(pa.HornerA, 1), + ), + ), + ), + ), + ) + + comp.InsertGlobal( + compRound, + ifaces.QueryIDf("%v_HORNER_B_GLOBAL", queryName), + sym.Sub( + pa.HornerB, + sym.Mul( + sym.Sub(1, pa.FilterB), + column.Shift(pa.HornerB, 1), + ), + sym.Mul( + pa.FilterB, + sym.Add(b, sym.Mul(pa.EvalCoin, column.Shift(pa.HornerB, 1))), + ), + ), + ) + + comp.InsertLocal( + compRound, + ifaces.QueryIDf("%v_HORNER_A_LOCAL_END", queryName), + sym.Sub( + column.Shift(pa.HornerA, -1), + sym.Mul(column.Shift(pa.FilterA, -1), af), + ), + ) + + comp.InsertLocal( + compRound, + ifaces.QueryIDf("%v_HORNER_B_LOCAL_END", queryName), + sym.Sub( + column.Shift(pa.HornerB, -1), + sym.Mul(column.Shift(pa.FilterB, -1), bf), + ), + ) + + pa.HornerA0 = comp.InsertLocalOpening(compRound, ifaces.QueryIDf("%v_HORNER_A0", queryName), pa.HornerA) + pa.HornerB0 = comp.InsertLocalOpening(compRound, ifaces.QueryIDf("%v_HORNER_B0", queryName), pa.HornerB) + + comp.RegisterProverAction(compRound, pa) + comp.RegisterVerifierAction(compRound, &projectionVerifierAction{HornerA0: pa.HornerA0, HornerB0: pa.HornerB0, Name: queryName}) + +} diff --git a/prover/protocol/compiler/projection/compiler_test.go b/prover/protocol/compiler/projection/compiler_test.go new file mode 100644 index 000000000..aadeb9bfa --- /dev/null +++ b/prover/protocol/compiler/projection/compiler_test.go @@ -0,0 +1,62 @@ +package projection_test + +import ( + "testing" + + "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/dummy" + "github.com/consensys/linea-monorepo/prover/protocol/compiler/projection" + "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/stretchr/testify/assert" +) + +func makeTestCaseProjection() ( + define wizard.DefineFunc, + prover wizard.ProverStep, +) { + round := 0 + flagSizeA := 512 + flagSizeB := 256 + var flagA, flagB, columnA, columnB ifaces.Column + define = func(build *wizard.Builder) { + comp := build.CompiledIOP + flagA = comp.InsertCommit(round, ifaces.ColID("FilterA"), flagSizeA) + flagB = comp.InsertCommit(round, ifaces.ColID("FliterB"), flagSizeB) + columnA = comp.InsertCommit(round, ifaces.ColID("ColumnA"), flagSizeA) + columnB = comp.InsertCommit(round, ifaces.ColID("ColumnB"), flagSizeB) + comp.InsertProjection(round, "Projection_Compilation_Test", query.ProjectionInput{ColumnA: []ifaces.Column{columnA}, ColumnB: []ifaces.Column{columnB}, FilterA: flagA, FilterB: flagB}) + + } + prover = func(run *wizard.ProverRuntime) { + // assign filters and columns + flagAWit := make([]field.Element, flagSizeA) + columnAWit := make([]field.Element, flagSizeA) + flagBWit := make([]field.Element, flagSizeB) + columnBWit := make([]field.Element, flagSizeB) + for i := 0; i < 10; i++ { + flagAWit[i] = field.One() + columnAWit[i] = field.NewElement(uint64(i)) + } + for i := flagSizeB - 10; i < flagSizeB; i++ { + flagBWit[i] = field.One() + columnBWit[i] = field.NewElement(uint64(i - (flagSizeB - 10))) + } + run.AssignColumn(flagA.GetColID(), smartvectors.RightZeroPadded(flagAWit, flagSizeA)) + run.AssignColumn(flagB.GetColID(), smartvectors.RightZeroPadded(flagBWit, flagSizeB)) + run.AssignColumn(columnB.GetColID(), smartvectors.RightZeroPadded(columnBWit, flagSizeB)) + run.AssignColumn(columnA.GetColID(), smartvectors.RightZeroPadded(columnAWit, flagSizeA)) + } + return define, prover +} + +func TestProjectionQuery(t *testing.T) { + + define, prover := makeTestCaseProjection() + comp := wizard.Compile(define, projection.CompileProjection, dummy.CompileAtProverLvl) + + proof := wizard.Prove(comp, prover) + assert.NoErrorf(t, wizard.Verify(comp, proof), "invalid proof") +} diff --git a/prover/protocol/compiler/projection/prover.go b/prover/protocol/compiler/projection/prover.go new file mode 100644 index 000000000..68f1f5320 --- /dev/null +++ b/prover/protocol/compiler/projection/prover.go @@ -0,0 +1,128 @@ +package projection + +import ( + "fmt" + "strings" + + "github.com/consensys/linea-monorepo/prover/maths/common/smartvectors" + "github.com/consensys/linea-monorepo/prover/maths/field" + "github.com/consensys/linea-monorepo/prover/protocol/coin" + "github.com/consensys/linea-monorepo/prover/protocol/column" + "github.com/consensys/linea-monorepo/prover/protocol/ifaces" + "github.com/consensys/linea-monorepo/prover/protocol/query" + "github.com/consensys/linea-monorepo/prover/protocol/wizard" + sym "github.com/consensys/linea-monorepo/prover/symbolic" + "github.com/sirupsen/logrus" +) + +// projectionProverAction is a compilation artefact generated during the +// execution of the [InsertProjection] and which implements the +// [wizard.ProverAction]. It is meant to compute to assign the "Horner" columns +// and their respective local opening queries. +type projectionProverAction struct { + Name ifaces.QueryID + FilterA, FilterB ifaces.Column + ColA, ColB []ifaces.Column + ABoard, BBoard sym.ExpressionBoard + EvalCoin coin.Info + HornerA, HornerB ifaces.Column + HornerA0, HornerB0 query.LocalOpening +} + +// Run implements the [wizard.ProverAction] interface. +func (pa projectionProverAction) Run(run *wizard.ProverRuntime) { + + var ( + a = column.EvalExprColumn(run, pa.ABoard).IntoRegVecSaveAlloc() + b = column.EvalExprColumn(run, pa.BBoard).IntoRegVecSaveAlloc() + fA = pa.FilterA.GetColAssignment(run).IntoRegVecSaveAlloc() + fB = pa.FilterB.GetColAssignment(run).IntoRegVecSaveAlloc() + x = run.GetRandomCoinField(pa.EvalCoin.Name) + hornerA = cmptHorner(a, fA, x) + hornerB = cmptHorner(b, fB, x) + ) + + run.AssignColumn(pa.HornerA.GetColID(), smartvectors.NewRegular(hornerA)) + run.AssignColumn(pa.HornerB.GetColID(), smartvectors.NewRegular(hornerB)) + run.AssignLocalPoint(pa.HornerA0.ID, hornerA[0]) + run.AssignLocalPoint(pa.HornerB0.ID, hornerB[0]) + + if hornerA[0] != hornerB[0] { + + var ( + colA = make([][]field.Element, len(pa.ColA)) + colB = make([][]field.Element, len(pa.ColB)) + cntA = 0 + cntB = 0 + rowsA = [][]string{} + rowsB = [][]string{} + ) + + for c := range pa.ColA { + colA[c] = pa.ColA[c].GetColAssignment(run).IntoRegVecSaveAlloc() + colB[c] = pa.ColB[c].GetColAssignment(run).IntoRegVecSaveAlloc() + } + + for i := range fA { + + if fA[i].IsZero() { + continue + } + + row := make([]string, len(pa.ColA)) + + for c := range pa.ColA { + fString := colA[c][i].Text(16) + if colA[c][i].IsUint64() && colA[c][i].Uint64() < 1000000 { + fString = colA[c][i].String() + } + row[c] = fmt.Sprintf("%v=%v", pa.ColA[c].GetColID(), fString) + } + + rowsA = append(rowsA, row) + cntA++ + } + + for i := range fB { + + if fB[i].IsZero() { + continue + } + + row := make([]string, len(pa.ColB)) + + for c := range pa.ColB { + fString := colB[c][i].Text(16) + if colB[c][i].IsUint64() && colB[c][i].Uint64() < 1000000 { + fString = colB[c][i].String() + } + row[c] = fmt.Sprintf("%v=%v", pa.ColB[c].GetColID(), fString) + } + + rowsB = append(rowsB, row) + cntB++ + } + + larger := max(len(rowsA), len(rowsB)) + + for i := 0; i < larger; i++ { + + var ( + fa = "* * * * * *" + fb = "* * * * * *" + ) + + if i < len(rowsA) { + fa = strings.Join(rowsA[i], " ") + } + + if i < len(rowsB) { + fb = strings.Join(rowsB[i], " ") + } + + fmt.Printf("row=%v %v %v\n", i, fa, fb) + } + + logrus.Errorf("projection query %v failed", pa.Name) + } +} diff --git a/prover/protocol/compiler/projection/utils.go b/prover/protocol/compiler/projection/utils.go new file mode 100644 index 000000000..2a46bf90d --- /dev/null +++ b/prover/protocol/compiler/projection/utils.go @@ -0,0 +1,33 @@ +package projection + +import ( + "github.com/consensys/linea-monorepo/prover/maths/field" + "github.com/consensys/linea-monorepo/prover/utils" +) + +// cmptHorner computes a random Horner accumulation of the filtered elements +// starting from the last entry down to the first entry. The final value is +// stored in the last entry of the returned slice. +func cmptHorner(c, fC []field.Element, x field.Element) []field.Element { + + var ( + horner = make([]field.Element, len(c)) + prev field.Element + ) + + for i := len(horner) - 1; i >= 0; i-- { + + if !fC[i].IsZero() && !fC[i].IsOne() { + utils.Panic("we expected the filter to be binary") + } + + if fC[i].IsOne() { + prev.Mul(&prev, &x) + prev.Add(&prev, &c[i]) + } + + horner[i] = prev + } + + return horner +} diff --git a/prover/protocol/compiler/projection/verifier.go b/prover/protocol/compiler/projection/verifier.go new file mode 100644 index 000000000..59b4f4d0d --- /dev/null +++ b/prover/protocol/compiler/projection/verifier.go @@ -0,0 +1,54 @@ +package projection + +import ( + "fmt" + + "github.com/consensys/gnark/frontend" + "github.com/consensys/linea-monorepo/prover/protocol/ifaces" + "github.com/consensys/linea-monorepo/prover/protocol/query" + "github.com/consensys/linea-monorepo/prover/protocol/wizard" +) + +// projectionVerifierAction is a compilation artifact generated during the +// execution of the [InsertProjection] and which implements the [wizard.VerifierAction] +// interface. It is meant to perform the verifier checks that the first values +// of the two Horner are equals. +type projectionVerifierAction struct { + Name ifaces.QueryID + HornerA0, HornerB0 query.LocalOpening + skipped bool +} + +// Run implements the [wizard.VerifierAction] interface. +func (va *projectionVerifierAction) Run(run *wizard.VerifierRuntime) error { + + var ( + a = run.GetLocalPointEvalParams(va.HornerA0.ID).Y + b = run.GetLocalPointEvalParams(va.HornerB0.ID).Y + ) + + if a != b { + return fmt.Errorf("the horner check of the projection query `%v` did not pass", va.Name) + } + + return nil +} + +// RunGnark implements the [wizard.VerifierAction] interface. +func (va *projectionVerifierAction) RunGnark(api frontend.API, run *wizard.WizardVerifierCircuit) { + + var ( + a = run.GetLocalPointEvalParams(va.HornerA0.ID).Y + b = run.GetLocalPointEvalParams(va.HornerB0.ID).Y + ) + + api.AssertIsEqual(a, b) +} + +func (va *projectionVerifierAction) Skip() { + va.skipped = true +} + +func (va *projectionVerifierAction) IsSkipped() bool { + return va.skipped +} From 5ed77a6da3ca89a7650275877db6bdc74ff9c0d2 Mon Sep 17 00:00:00 2001 From: arijitdutta67 Date: Thu, 23 Jan 2025 12:27:38 +0530 Subject: [PATCH 03/13] compiler added to arcane --- .../linea/nativecompressor/rlp_blocks.bin | Bin 0 -> 57530 bytes prover/protocol/compiler/arcane.go | 2 + .../protocol/compiler/projection/compiler.go | 2 +- prover/protocol/dedicated/plonk/alignment.go | 2 +- .../dedicated/projection/projection.go | 6 +- .../dedicated/projection/projection_query.go | 52 ++++++++++++++++++ .../dedicated/projection/projection_test.go | 2 +- prover/protocol/query/projection.go | 18 +++--- prover/protocol/wizard/compiled.go | 2 +- prover/zkevm/prover/ecdsa/adress.go | 8 +-- prover/zkevm/prover/ecdsa/ecdata.go | 2 +- prover/zkevm/prover/ecdsa/unaligned_gnark.go | 2 +- .../zkevm/prover/ecpair/ecpair_constraints.go | 6 +- .../zkevm/prover/hash/importpad/import_pad.go | 2 +- .../prover/hash/keccak/acc_module/data_acc.go | 2 +- .../prover/hash/keccak/acc_module/info_acc.go | 4 +- .../hash/keccak/keccak_single_provider.go | 4 +- prover/zkevm/prover/hash/keccak/keccakf/io.go | 2 +- prover/zkevm/prover/hash/packing/lane.go | 4 +- prover/zkevm/prover/hash/sha2/sha2.go | 4 +- prover/zkevm/prover/hash/sha2/sha2_block.go | 2 +- prover/zkevm/prover/modexp/module.go | 2 +- .../execution_data_collector.go | 10 ++-- .../block_txn_metadata_fetcher.go | 2 +- .../rlp_txn_fetcher.go | 2 +- .../timestamp_fetcher.go | 2 +- .../txn_data_fetcher.go | 2 +- .../prover/publicInput/logs/extracted_data.go | 2 +- .../mimccodehash/input_consistency.go | 2 +- 29 files changed, 103 insertions(+), 49 deletions(-) create mode 100644 jvm-libs/blob-compressor/src/test/resources/net/consensys/linea/nativecompressor/rlp_blocks.bin create mode 100644 prover/protocol/dedicated/projection/projection_query.go diff --git a/jvm-libs/blob-compressor/src/test/resources/net/consensys/linea/nativecompressor/rlp_blocks.bin b/jvm-libs/blob-compressor/src/test/resources/net/consensys/linea/nativecompressor/rlp_blocks.bin new file mode 100644 index 0000000000000000000000000000000000000000..82c04c3ff910b96015701321b0da8f673357e801 GIT binary patch literal 57530 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 Date: Thu, 23 Jan 2025 12:44:14 +0530 Subject: [PATCH 04/13] minor fix added --- prover/protocol/dedicated/projection/projection.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/prover/protocol/dedicated/projection/projection.go b/prover/protocol/dedicated/projection/projection.go index 68078f9a5..4edd80fa3 100644 --- a/prover/protocol/dedicated/projection/projection.go +++ b/prover/protocol/dedicated/projection/projection.go @@ -44,7 +44,7 @@ import ( ) // projectionProverAction is a compilation artefact generated during the -// execution of the [RegisterProjection] and which implements the +// execution of the [InsertProjection] and which implements the // [wizard.ProverAction]. It is meant to compute to assign the "Horner" columns // and their respective local opening queries. type projectionProverAction struct { @@ -58,7 +58,7 @@ type projectionProverAction struct { } // projectionVerifierAction is a compilation artifact generated during the -// execution of the [RegisterProjection] and which implements the [wizard.VerifierAction] +// execution of the [InsertProjection] and which implements the [wizard.VerifierAction] // interface. It is meant to perform the verifier checks that the first values // of the two Horner are equals. type projectionVerifierAction struct { @@ -67,7 +67,7 @@ type projectionVerifierAction struct { skipped bool } -// RegisterProjection applies a projection query between sets (columnsA, filterA) +// InsertProjection applies a projection query between sets (columnsA, filterA) // and (columnsB,filterB). // // Note: The filters are supposed to be binary. From 53f1b9b5bc0077d8a5e7d63599659ca62aded4af Mon Sep 17 00:00:00 2001 From: arijitdutta67 Date: Thu, 23 Jan 2025 15:30:24 +0530 Subject: [PATCH 05/13] fix lint error --- prover/backend/execution/prove.go | 1 + 1 file changed, 1 insertion(+) diff --git a/prover/backend/execution/prove.go b/prover/backend/execution/prove.go index 4970e344f..6452a23f3 100644 --- a/prover/backend/execution/prove.go +++ b/prover/backend/execution/prove.go @@ -1,3 +1,4 @@ +//nolint:gosec // Ignoring weak randomness error package execution import ( From e918986f368d3b47bbd155d2c96d9dc11df8f503 Mon Sep 17 00:00:00 2001 From: arijitdutta67 Date: Thu, 23 Jan 2025 16:10:12 +0530 Subject: [PATCH 06/13] duplicate name fix --- .../execution_data_collector/execution_data_collector.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prover/zkevm/prover/publicInput/execution_data_collector/execution_data_collector.go b/prover/zkevm/prover/publicInput/execution_data_collector/execution_data_collector.go index 97bce8c4f..2d691d0df 100644 --- a/prover/zkevm/prover/publicInput/execution_data_collector/execution_data_collector.go +++ b/prover/zkevm/prover/publicInput/execution_data_collector/execution_data_collector.go @@ -937,7 +937,7 @@ func LookupQueries(comp *wizard.CompiledIOP, } comp.InsertInclusionDoubleConditional(0, - ifaces.QueryIDf("%s_BLOCK_METADATA_PROJECTION", name), + ifaces.QueryIDf("%s_BLOCK_METADATA_DOUBLE_CONDITIONAL_LOOKUP", name), metadataTable, // including table edcMetadataTable, // included table metadata.FilterFetched, From 0617f347b6755c87537b4456159ca8ff1381dc3e Mon Sep 17 00:00:00 2001 From: arijitdutta67 Date: Fri, 24 Jan 2025 13:11:48 +0530 Subject: [PATCH 07/13] removing cptHolter to math poly --- prover/maths/common/poly/poly.go | 28 ++++++++++++++++ prover/protocol/compiler/projection/prover.go | 5 +-- prover/protocol/compiler/projection/utils.go | 33 ------------------- .../dedicated/projection/projection.go | 1 + prover/protocol/query/projection.go | 33 ++----------------- 5 files changed, 35 insertions(+), 65 deletions(-) delete mode 100644 prover/protocol/compiler/projection/utils.go diff --git a/prover/maths/common/poly/poly.go b/prover/maths/common/poly/poly.go index 902ddc164..dfa685144 100644 --- a/prover/maths/common/poly/poly.go +++ b/prover/maths/common/poly/poly.go @@ -122,3 +122,31 @@ func EvaluateLagrangesAnyDomain(domain []field.Element, x field.Element) []field return lagrange } + +// CmptHorner computes a random Horner accumulation of the filtered elements +// starting from the last entry down to the first entry. The final value is +// stored in the last entry of the returned slice. +// Todo: send it to a common utility package +func CmptHorner(c, fC []field.Element, x field.Element) []field.Element { + + var ( + horner = make([]field.Element, len(c)) + prev field.Element + ) + + for i := len(horner) - 1; i >= 0; i-- { + + if !fC[i].IsZero() && !fC[i].IsOne() { + utils.Panic("we expected the filter to be binary") + } + + if fC[i].IsOne() { + prev.Mul(&prev, &x) + prev.Add(&prev, &c[i]) + } + + horner[i] = prev + } + + return horner +} diff --git a/prover/protocol/compiler/projection/prover.go b/prover/protocol/compiler/projection/prover.go index 68f1f5320..7726a0d3e 100644 --- a/prover/protocol/compiler/projection/prover.go +++ b/prover/protocol/compiler/projection/prover.go @@ -4,6 +4,7 @@ import ( "fmt" "strings" + "github.com/consensys/linea-monorepo/prover/maths/common/poly" "github.com/consensys/linea-monorepo/prover/maths/common/smartvectors" "github.com/consensys/linea-monorepo/prover/maths/field" "github.com/consensys/linea-monorepo/prover/protocol/coin" @@ -38,8 +39,8 @@ func (pa projectionProverAction) Run(run *wizard.ProverRuntime) { fA = pa.FilterA.GetColAssignment(run).IntoRegVecSaveAlloc() fB = pa.FilterB.GetColAssignment(run).IntoRegVecSaveAlloc() x = run.GetRandomCoinField(pa.EvalCoin.Name) - hornerA = cmptHorner(a, fA, x) - hornerB = cmptHorner(b, fB, x) + hornerA = poly.CmptHorner(a, fA, x) + hornerB = poly.CmptHorner(b, fB, x) ) run.AssignColumn(pa.HornerA.GetColID(), smartvectors.NewRegular(hornerA)) diff --git a/prover/protocol/compiler/projection/utils.go b/prover/protocol/compiler/projection/utils.go deleted file mode 100644 index 2a46bf90d..000000000 --- a/prover/protocol/compiler/projection/utils.go +++ /dev/null @@ -1,33 +0,0 @@ -package projection - -import ( - "github.com/consensys/linea-monorepo/prover/maths/field" - "github.com/consensys/linea-monorepo/prover/utils" -) - -// cmptHorner computes a random Horner accumulation of the filtered elements -// starting from the last entry down to the first entry. The final value is -// stored in the last entry of the returned slice. -func cmptHorner(c, fC []field.Element, x field.Element) []field.Element { - - var ( - horner = make([]field.Element, len(c)) - prev field.Element - ) - - for i := len(horner) - 1; i >= 0; i-- { - - if !fC[i].IsZero() && !fC[i].IsOne() { - utils.Panic("we expected the filter to be binary") - } - - if fC[i].IsOne() { - prev.Mul(&prev, &x) - prev.Add(&prev, &c[i]) - } - - horner[i] = prev - } - - return horner -} diff --git a/prover/protocol/dedicated/projection/projection.go b/prover/protocol/dedicated/projection/projection.go index 4edd80fa3..2960a0e3e 100644 --- a/prover/protocol/dedicated/projection/projection.go +++ b/prover/protocol/dedicated/projection/projection.go @@ -1,4 +1,5 @@ /* +To be deprecated and replaced with projection as a query. Package projection implements the utilities for the projection query. A projection query between sets (columnsA,filterA) and (columnsB,filterB) asserts diff --git a/prover/protocol/query/projection.go b/prover/protocol/query/projection.go index e4ec5ecf3..45f88eb0f 100644 --- a/prover/protocol/query/projection.go +++ b/prover/protocol/query/projection.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/consensys/gnark/frontend" + "github.com/consensys/linea-monorepo/prover/maths/common/poly" "github.com/consensys/linea-monorepo/prover/maths/field" "github.com/consensys/linea-monorepo/prover/protocol/ifaces" "github.com/consensys/linea-monorepo/prover/utils" @@ -89,8 +90,8 @@ func (p Projection) Check(run ifaces.Runtime) error { bLinComb[row] = rowLinComb(linCombRand, row, b) } var ( - hornerA = cmptHorner(aLinComb, fA, evalRand) - hornerB = cmptHorner(bLinComb, fB, evalRand) + hornerA = poly.CmptHorner(aLinComb, fA, evalRand) + hornerB = poly.CmptHorner(bLinComb, fB, evalRand) ) if hornerA[0] != hornerB[0] { return fmt.Errorf("the projection query %v check is not satisfied", p.ID) @@ -105,31 +106,3 @@ func (p Projection) Check(run ifaces.Runtime) error { func (i Projection) CheckGnark(api frontend.API, run ifaces.GnarkRuntime) { panic("UNSUPPORTED : can't check an Projection query directly into the circuit") } - -// cmptHorner computes a random Horner accumulation of the filtered elements -// starting from the last entry down to the first entry. The final value is -// stored in the last entry of the returned slice. -// Todo: send it to a common utility package -func cmptHorner(c, fC []field.Element, x field.Element) []field.Element { - - var ( - horner = make([]field.Element, len(c)) - prev field.Element - ) - - for i := len(horner) - 1; i >= 0; i-- { - - if !fC[i].IsZero() && !fC[i].IsOne() { - utils.Panic("we expected the filter to be binary") - } - - if fC[i].IsOne() { - prev.Mul(&prev, &x) - prev.Add(&prev, &c[i]) - } - - horner[i] = prev - } - - return horner -} From bb9d900dfeee9f0dbe2bde312e80422d72077e6e Mon Sep 17 00:00:00 2001 From: arijitdutta67 Date: Fri, 24 Jan 2025 17:13:55 +0530 Subject: [PATCH 08/13] shifted the no lint command --- prover/backend/execution/prove.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/prover/backend/execution/prove.go b/prover/backend/execution/prove.go index 6452a23f3..6da2cd4f4 100644 --- a/prover/backend/execution/prove.go +++ b/prover/backend/execution/prove.go @@ -1,4 +1,3 @@ -//nolint:gosec // Ignoring weak randomness error package execution import ( @@ -191,7 +190,7 @@ func mustProveAndPass( case config.ProverModeEncodeOnly: profiling.ProfileTrace("encode-decode-no-circuit", true, false, func() { - filepath := "/tmp/wizard-assignment/blob-" + strconv.Itoa(rand.Int()) + ".bin" + filepath := "/tmp/wizard-assignment/blob-" + strconv.Itoa(rand.Int()) + ".bin" //nolint:gosec // Ignoring weak randomness error encodeOnlyZkEvm := zkevm.EncodeOnlyZkEvm(traces) numChunks := runtime.GOMAXPROCS(0) From 8cc8cb731b46394e0775098c4a0b1a80af4ec254 Mon Sep 17 00:00:00 2001 From: arijitdutta67 Date: Fri, 24 Jan 2025 17:34:15 +0530 Subject: [PATCH 09/13] added bin file in gitignore --- prover/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/prover/.gitignore b/prover/.gitignore index 0ae1e78a1..6062ea203 100644 --- a/prover/.gitignore +++ b/prover/.gitignore @@ -85,3 +85,4 @@ integration-testing/testdata/prover-requests/ # Authorize the kzg srs folder prover-assets/** !prover-assets/kzgsrs/** +jvm-libs/blob-compressor/src/test/resources/net/consensys/linea/nativecompressor/rlp_blocks.bin From b01f73c3cf372501baea560f6dfae7229ba234fa Mon Sep 17 00:00:00 2001 From: arijitdutta67 Date: Fri, 24 Jan 2025 17:55:35 +0530 Subject: [PATCH 10/13] removed gitignore change --- prover/.gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/prover/.gitignore b/prover/.gitignore index 6062ea203..0ae1e78a1 100644 --- a/prover/.gitignore +++ b/prover/.gitignore @@ -85,4 +85,3 @@ integration-testing/testdata/prover-requests/ # Authorize the kzg srs folder prover-assets/** !prover-assets/kzgsrs/** -jvm-libs/blob-compressor/src/test/resources/net/consensys/linea/nativecompressor/rlp_blocks.bin From 204bc5cd401bd82393cf57175e8aeaa4e366fff6 Mon Sep 17 00:00:00 2001 From: arijitdutta67 Date: Fri, 24 Jan 2025 18:26:39 +0530 Subject: [PATCH 11/13] remove bin file --- .../linea/nativecompressor/rlp_blocks.bin | Bin 57530 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 jvm-libs/blob-compressor/src/test/resources/net/consensys/linea/nativecompressor/rlp_blocks.bin diff --git a/jvm-libs/blob-compressor/src/test/resources/net/consensys/linea/nativecompressor/rlp_blocks.bin b/jvm-libs/blob-compressor/src/test/resources/net/consensys/linea/nativecompressor/rlp_blocks.bin deleted file mode 100644 index 82c04c3ff910b96015701321b0da8f673357e801..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 57530 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 Date: Sat, 25 Jan 2025 10:01:10 +0530 Subject: [PATCH 12/13] code simplification as Alex suggested --- prover/go.mod | 2 +- prover/protocol/column/column.go | 9 + prover/protocol/compiler/mimc/manual.go | 2 +- .../compiler/projection/compiler_test.go | 2 +- .../protocol/dedicated/byte32cmp/byte32cmp.go | 4 +- .../dedicated/byte32cmp/multi_limb_cmp.go | 5 +- prover/protocol/dedicated/merkle/merkle.go | 4 +- prover/protocol/dedicated/plonk/alignment.go | 3 +- .../dedicated/projection/projection.go | 377 ------------------ .../dedicated/projection/projection_query.go | 52 --- .../dedicated/projection/projection_test.go | 61 --- prover/protocol/query/projection_test.go | 2 +- prover/protocol/wizard/compiled.go | 33 +- prover/protocol/wizardutils/utils.go | 9 - prover/zkevm/prover/common/hashing.go | 4 +- prover/zkevm/prover/ecdsa/adress.go | 39 +- prover/zkevm/prover/ecdsa/ecdata.go | 12 +- prover/zkevm/prover/ecdsa/unaligned_gnark.go | 14 +- .../zkevm/prover/ecpair/ecpair_constraints.go | 37 +- .../zkevm/prover/hash/importpad/import_pad.go | 14 +- .../prover/hash/keccak/acc_module/data_acc.go | 14 +- .../prover/hash/keccak/acc_module/info_acc.go | 26 +- .../hash/keccak/keccak_single_provider.go | 25 +- prover/zkevm/prover/hash/keccak/keccakf/io.go | 12 +- prover/zkevm/prover/hash/packing/lane.go | 23 +- prover/zkevm/prover/hash/sha2/sha2.go | 25 +- prover/zkevm/prover/hash/sha2/sha2_block.go | 22 +- prover/zkevm/prover/modexp/module.go | 15 +- .../execution_data_collector.go | 58 ++- .../block_txn_metadata_fetcher.go | 13 +- .../rlp_txn_fetcher.go | 14 +- .../timestamp_fetcher.go | 14 +- .../txn_data_fetcher.go | 14 +- .../prover/publicInput/logs/extracted_data.go | 9 +- .../mimccodehash/input_consistency.go | 14 +- 35 files changed, 251 insertions(+), 732 deletions(-) delete mode 100644 prover/protocol/dedicated/projection/projection.go delete mode 100644 prover/protocol/dedicated/projection/projection_query.go delete mode 100644 prover/protocol/dedicated/projection/projection_test.go diff --git a/prover/go.mod b/prover/go.mod index c14ce8408..da5975647 100644 --- a/prover/go.mod +++ b/prover/go.mod @@ -18,6 +18,7 @@ require ( github.com/iancoleman/strcase v0.3.0 github.com/icza/bitio v1.1.0 github.com/leanovate/gopter v0.2.11 + github.com/pierrec/lz4/v4 v4.1.21 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.19.1 github.com/rs/zerolog v1.33.0 @@ -76,7 +77,6 @@ require ( github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/pelletier/go-toml/v2 v2.2.2 // indirect - github.com/pierrec/lz4/v4 v4.1.21 // indirect github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.55.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect diff --git a/prover/protocol/column/column.go b/prover/protocol/column/column.go index 18af77a92..02eea4206 100644 --- a/prover/protocol/column/column.go +++ b/prover/protocol/column/column.go @@ -188,3 +188,12 @@ func RandLinCombColAssignment(run ifaces.Runtime, coinVal field.Element, hs []if } return witnessCollapsed } + +// maximal round of declaration for a list of commitment +func MaxRound(handles ...ifaces.Column) int { + res := 0 + for _, handle := range handles { + res = utils.Max(res, handle.Round()) + } + return res +} diff --git a/prover/protocol/compiler/mimc/manual.go b/prover/protocol/compiler/mimc/manual.go index 50885feb6..7560f8e41 100644 --- a/prover/protocol/compiler/mimc/manual.go +++ b/prover/protocol/compiler/mimc/manual.go @@ -25,7 +25,7 @@ func manualCheckMiMCBlock(comp *wizard.CompiledIOP, blocks, oldStates, newStates newStates: newStates, } - round := wizardutils.MaxRound(blocks, oldStates, newStates) + round := column.MaxRound(blocks, oldStates, newStates) // Creates an intermediate column for each round s := blocks diff --git a/prover/protocol/compiler/projection/compiler_test.go b/prover/protocol/compiler/projection/compiler_test.go index aadeb9bfa..20c9e8de3 100644 --- a/prover/protocol/compiler/projection/compiler_test.go +++ b/prover/protocol/compiler/projection/compiler_test.go @@ -27,7 +27,7 @@ func makeTestCaseProjection() ( flagB = comp.InsertCommit(round, ifaces.ColID("FliterB"), flagSizeB) columnA = comp.InsertCommit(round, ifaces.ColID("ColumnA"), flagSizeA) columnB = comp.InsertCommit(round, ifaces.ColID("ColumnB"), flagSizeB) - comp.InsertProjection(round, "Projection_Compilation_Test", query.ProjectionInput{ColumnA: []ifaces.Column{columnA}, ColumnB: []ifaces.Column{columnB}, FilterA: flagA, FilterB: flagB}) + comp.InsertProjection("Projection_Compilation_Test", query.ProjectionInput{ColumnA: []ifaces.Column{columnA}, ColumnB: []ifaces.Column{columnB}, FilterA: flagA, FilterB: flagB}) } prover = func(run *wizard.ProverRuntime) { diff --git a/prover/protocol/dedicated/byte32cmp/byte32cmp.go b/prover/protocol/dedicated/byte32cmp/byte32cmp.go index 0a51d7043..dc161ae93 100644 --- a/prover/protocol/dedicated/byte32cmp/byte32cmp.go +++ b/prover/protocol/dedicated/byte32cmp/byte32cmp.go @@ -1,9 +1,9 @@ package byte32cmp import ( + "github.com/consensys/linea-monorepo/prover/protocol/column" "github.com/consensys/linea-monorepo/prover/protocol/ifaces" "github.com/consensys/linea-monorepo/prover/protocol/wizard" - "github.com/consensys/linea-monorepo/prover/protocol/wizardutils" "github.com/consensys/linea-monorepo/prover/symbolic" ) @@ -20,7 +20,7 @@ func Bytes32Cmp( activeRow *symbolic.Expression, ) { bcp := BytesCmpCtx{} - round := wizardutils.MaxRound(columnA, columnB) + round := column.MaxRound(columnA, columnB) bcp.round = round bcp.columnA = columnA bcp.columnB = columnB diff --git a/prover/protocol/dedicated/byte32cmp/multi_limb_cmp.go b/prover/protocol/dedicated/byte32cmp/multi_limb_cmp.go index 35d96e11d..5b7450a49 100644 --- a/prover/protocol/dedicated/byte32cmp/multi_limb_cmp.go +++ b/prover/protocol/dedicated/byte32cmp/multi_limb_cmp.go @@ -10,7 +10,6 @@ import ( "github.com/consensys/linea-monorepo/prover/protocol/dedicated" "github.com/consensys/linea-monorepo/prover/protocol/ifaces" "github.com/consensys/linea-monorepo/prover/protocol/wizard" - "github.com/consensys/linea-monorepo/prover/protocol/wizardutils" sym "github.com/consensys/linea-monorepo/prover/symbolic" "github.com/consensys/linea-monorepo/prover/utils" "github.com/consensys/linea-monorepo/prover/utils/parallel" @@ -96,8 +95,8 @@ func CmpMultiLimbs(comp *wizard.CompiledIOP, a, b LimbColumns) (isGreater, isEqu var ( isBigEndian = a.IsBigEndian - roundA = wizardutils.MaxRound(a.Limbs...) - round = max(roundA, wizardutils.MaxRound(b.Limbs...)) + roundA = column.MaxRound(a.Limbs...) + round = max(roundA, column.MaxRound(b.Limbs...)) numLimbs = len(a.Limbs) numBitsPerLimbs = a.LimbBitSize ctx = &multiLimbCmp{ diff --git a/prover/protocol/dedicated/merkle/merkle.go b/prover/protocol/dedicated/merkle/merkle.go index ff794e92c..76f495aac 100644 --- a/prover/protocol/dedicated/merkle/merkle.go +++ b/prover/protocol/dedicated/merkle/merkle.go @@ -4,9 +4,9 @@ import ( "github.com/consensys/linea-monorepo/prover/crypto/state-management/smt" "github.com/consensys/linea-monorepo/prover/maths/common/smartvectors" "github.com/consensys/linea-monorepo/prover/maths/field" + "github.com/consensys/linea-monorepo/prover/protocol/column" "github.com/consensys/linea-monorepo/prover/protocol/ifaces" "github.com/consensys/linea-monorepo/prover/protocol/wizard" - "github.com/consensys/linea-monorepo/prover/protocol/wizardutils" "github.com/consensys/linea-monorepo/prover/utils" ) @@ -63,7 +63,7 @@ func merkleProofCheck( useNextProof bool, ) { - round := wizardutils.MaxRound(proofs, roots, leaves, pos) + round := column.MaxRound(proofs, roots, leaves, pos) // define the compute module cm := ComputeMod{} cm.Cols.Proof = proofs diff --git a/prover/protocol/dedicated/plonk/alignment.go b/prover/protocol/dedicated/plonk/alignment.go index 668b61353..2ac362c49 100644 --- a/prover/protocol/dedicated/plonk/alignment.go +++ b/prover/protocol/dedicated/plonk/alignment.go @@ -10,7 +10,6 @@ import ( "github.com/consensys/linea-monorepo/prover/maths/common/smartvectors" "github.com/consensys/linea-monorepo/prover/maths/field" "github.com/consensys/linea-monorepo/prover/protocol/column" - "github.com/consensys/linea-monorepo/prover/protocol/dedicated/projection" "github.com/consensys/linea-monorepo/prover/protocol/ifaces" "github.com/consensys/linea-monorepo/prover/protocol/query" "github.com/consensys/linea-monorepo/prover/protocol/wizard" @@ -273,7 +272,7 @@ func (a *Alignment) csIsActive(comp *wizard.CompiledIOP) { // csProjection ensures the data in the [Alignment.Data] column is the same as // the data provided by the [Alignment.CircuitInput]. func (a *Alignment) csProjection(comp *wizard.CompiledIOP) { - projection.RegisterProjection(comp, ifaces.QueryIDf("%v_PROJECTION", a.Name), []ifaces.Column{a.DataToCircuit}, []ifaces.Column{a.CircuitInput}, a.DataToCircuitMask, a.ActualCircuitInputMask) + comp.InsertProjection(ifaces.QueryIDf("%v_PROJECTION", a.Name), query.ProjectionInput{ColumnA: []ifaces.Column{a.DataToCircuit}, ColumnB: []ifaces.Column{a.CircuitInput}, FilterA: a.DataToCircuitMask, FilterB: a.ActualCircuitInputMask}) } // csProjectionSelector constraints that the projection selection diff --git a/prover/protocol/dedicated/projection/projection.go b/prover/protocol/dedicated/projection/projection.go deleted file mode 100644 index 2960a0e3e..000000000 --- a/prover/protocol/dedicated/projection/projection.go +++ /dev/null @@ -1,377 +0,0 @@ -/* -To be deprecated and replaced with projection as a query. -Package projection implements the utilities for the projection query. - -A projection query between sets (columnsA,filterA) and (columnsB,filterB) asserts -whether the columnsA filtered by filterA is the same as columnsB filtered by -filterB, preserving the order. - -Example: - -FilterA = (1,0,0,1,1), ColumnA := (aO,a1,a2,a3,a4) - -FiletrB := (0,0,1,0,0,0,0,0,1,1), ColumnB :=(b0,b1,b2,b3,b4,b5,b6,b7,b8,b9) - -Thus we have, - -ColumnA filtered by FilterA = (a0,a3,a4) - -ColumnB filtered by FilterB = (b2,b8,b9) - -The projection query checks if a0 = b2, a3 = b8, a4 = b9 - -Note that the query imposes that: - - the number of 1 in the filters are equal - - the order of filtered elements is preserved -*/ -package projection - -import ( - "fmt" - "strings" - - "github.com/consensys/gnark/frontend" - "github.com/consensys/linea-monorepo/prover/maths/common/smartvectors" - "github.com/consensys/linea-monorepo/prover/maths/field" - "github.com/consensys/linea-monorepo/prover/protocol/coin" - "github.com/consensys/linea-monorepo/prover/protocol/column" - "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/protocol/wizardutils" - sym "github.com/consensys/linea-monorepo/prover/symbolic" - "github.com/consensys/linea-monorepo/prover/utils" - "github.com/sirupsen/logrus" -) - -// projectionProverAction is a compilation artefact generated during the -// execution of the [InsertProjection] and which implements the -// [wizard.ProverAction]. It is meant to compute to assign the "Horner" columns -// and their respective local opening queries. -type projectionProverAction struct { - Name ifaces.QueryID - FilterA, FilterB ifaces.Column - ColA, ColB []ifaces.Column - ABoard, BBoard sym.ExpressionBoard - EvalCoin coin.Info - HornerA, HornerB ifaces.Column - HornerA0, HornerB0 query.LocalOpening -} - -// projectionVerifierAction is a compilation artifact generated during the -// execution of the [InsertProjection] and which implements the [wizard.VerifierAction] -// interface. It is meant to perform the verifier checks that the first values -// of the two Horner are equals. -type projectionVerifierAction struct { - Name ifaces.QueryID - HornerA0, HornerB0 query.LocalOpening - skipped bool -} - -// InsertProjection applies a projection query between sets (columnsA, filterA) -// and (columnsB,filterB). -// -// Note: The filters are supposed to be binary. -// These binary constraints are not handled here and should have been imposed -// before calling the function. -func InsertProjection( - comp *wizard.CompiledIOP, - queryName ifaces.QueryID, - columnsA, columnsB []ifaces.Column, - filterA, filterB ifaces.Column, -) { - - var ( - sizeA = filterA.Size() - sizeB = filterB.Size() - numCol = len(columnsA) - round = max( - wizardutils.MaxRound(columnsA...), - wizardutils.MaxRound(columnsB...), - filterA.Round(), - filterB.Round(), - ) - - // a and b are storing the columns used to compute the linear combination - // of the columnsA and columnsB. The initial assignment is for the case - // where there is only a single column. If there is more than one column - // then they will store an expression computing a random linear - // combination of the columns. - a, b any = columnsA[0], columnsB[0] - - // af and bf are as a and b but shifted by -1. They are initially - // assigned assuming the case where the number of column is 1 and - // replaced later by a random linear combination if not. They are meant - // to be used in the local constraints to point to the last entry of the - // "a" and "b". - af, bf any = column.Shift(columnsA[0], -1), column.Shift(columnsB[0], -1) - ) - - if len(columnsB) != numCol { - utils.Panic("A and B must have the same number of columns") - } - - if ifaces.AssertSameLength(columnsA...) != sizeA { - utils.Panic("A and its filter do not have the same column sizes") - } - - if ifaces.AssertSameLength(columnsB...) != sizeB { - utils.Panic("B and its filter do not have the same column sizes") - } - - if numCol > 0 { - round++ - alpha := comp.InsertCoin(round, coin.Namef("%v_MERGING_COIN", queryName), coin.Field) - a = wizardutils.RandLinCombColSymbolic(alpha, columnsA) - b = wizardutils.RandLinCombColSymbolic(alpha, columnsB) - - afs := make([]ifaces.Column, numCol) - bfs := make([]ifaces.Column, numCol) - - for i := range afs { - afs[i] = column.Shift(columnsA[i], -1) - bfs[i] = column.Shift(columnsB[i], -1) - } - - af = wizardutils.RandLinCombColSymbolic(alpha, afs) - bf = wizardutils.RandLinCombColSymbolic(alpha, bfs) - } - - var ( - aExpr, _, _ = wizardutils.AsExpr(a) - bExpr, _, _ = wizardutils.AsExpr(b) - pa = projectionProverAction{ - Name: queryName, - EvalCoin: comp.InsertCoin(round, coin.Namef("%v_EVAL_COIN", queryName), coin.Field), - FilterA: filterA, - FilterB: filterB, - ColA: columnsA, - ColB: columnsB, - ABoard: aExpr.Board(), - BBoard: bExpr.Board(), - HornerA: comp.InsertCommit(round, ifaces.ColIDf("%v_HORNER_A", queryName), sizeA), - HornerB: comp.InsertCommit(round, ifaces.ColIDf("%v_HORNER_B", queryName), sizeB), - } - ) - - comp.InsertGlobal( - 0, - ifaces.QueryIDf("%v_HORNER_A_GLOBAL", queryName), - sym.Sub( - pa.HornerA, - sym.Mul( - sym.Sub(1, pa.FilterA), - column.Shift(pa.HornerA, 1), - ), - sym.Mul( - pa.FilterA, - sym.Add( - a, - sym.Mul( - pa.EvalCoin, - column.Shift(pa.HornerA, 1), - ), - ), - ), - ), - ) - - comp.InsertGlobal( - 0, - ifaces.QueryIDf("%v_HORNER_B_GLOBAL", queryName), - sym.Sub( - pa.HornerB, - sym.Mul( - sym.Sub(1, pa.FilterB), - column.Shift(pa.HornerB, 1), - ), - sym.Mul( - pa.FilterB, - sym.Add(b, sym.Mul(pa.EvalCoin, column.Shift(pa.HornerB, 1))), - ), - ), - ) - - comp.InsertLocal( - 0, - ifaces.QueryIDf("%v_HORNER_A_LOCAL_END", queryName), - sym.Sub( - column.Shift(pa.HornerA, -1), - sym.Mul(column.Shift(pa.FilterA, -1), af), - ), - ) - - comp.InsertLocal( - 0, - ifaces.QueryIDf("%v_HORNER_B_LOCAL_END", queryName), - sym.Sub( - column.Shift(pa.HornerB, -1), - sym.Mul(column.Shift(pa.FilterB, -1), bf), - ), - ) - - pa.HornerA0 = comp.InsertLocalOpening(round, ifaces.QueryIDf("%v_HORNER_A0", queryName), pa.HornerA) - pa.HornerB0 = comp.InsertLocalOpening(round, ifaces.QueryIDf("%v_HORNER_B0", queryName), pa.HornerB) - - comp.RegisterProverAction(round, pa) - comp.RegisterVerifierAction(round, &projectionVerifierAction{HornerA0: pa.HornerA0, HornerB0: pa.HornerB0, Name: queryName}) -} - -// Run implements the [wizard.ProverAction] interface. -func (pa projectionProverAction) Run(run *wizard.ProverRuntime) { - - var ( - a = column.EvalExprColumn(run, pa.ABoard).IntoRegVecSaveAlloc() - b = column.EvalExprColumn(run, pa.BBoard).IntoRegVecSaveAlloc() - fA = pa.FilterA.GetColAssignment(run).IntoRegVecSaveAlloc() - fB = pa.FilterB.GetColAssignment(run).IntoRegVecSaveAlloc() - x = run.GetRandomCoinField(pa.EvalCoin.Name) - hornerA = cmptHorner(a, fA, x) - hornerB = cmptHorner(b, fB, x) - ) - - run.AssignColumn(pa.HornerA.GetColID(), smartvectors.NewRegular(hornerA)) - run.AssignColumn(pa.HornerB.GetColID(), smartvectors.NewRegular(hornerB)) - run.AssignLocalPoint(pa.HornerA0.ID, hornerA[0]) - run.AssignLocalPoint(pa.HornerB0.ID, hornerB[0]) - - if hornerA[0] != hornerB[0] { - - var ( - colA = make([][]field.Element, len(pa.ColA)) - colB = make([][]field.Element, len(pa.ColB)) - cntA = 0 - cntB = 0 - rowsA = [][]string{} - rowsB = [][]string{} - ) - - for c := range pa.ColA { - colA[c] = pa.ColA[c].GetColAssignment(run).IntoRegVecSaveAlloc() - colB[c] = pa.ColB[c].GetColAssignment(run).IntoRegVecSaveAlloc() - } - - for i := range fA { - - if fA[i].IsZero() { - continue - } - - row := make([]string, len(pa.ColA)) - - for c := range pa.ColA { - fString := colA[c][i].Text(16) - if colA[c][i].IsUint64() && colA[c][i].Uint64() < 1000000 { - fString = colA[c][i].String() - } - row[c] = fmt.Sprintf("%v=%v", pa.ColA[c].GetColID(), fString) - } - - rowsA = append(rowsA, row) - cntA++ - } - - for i := range fB { - - if fB[i].IsZero() { - continue - } - - row := make([]string, len(pa.ColB)) - - for c := range pa.ColB { - fString := colB[c][i].Text(16) - if colB[c][i].IsUint64() && colB[c][i].Uint64() < 1000000 { - fString = colB[c][i].String() - } - row[c] = fmt.Sprintf("%v=%v", pa.ColB[c].GetColID(), fString) - } - - rowsB = append(rowsB, row) - cntB++ - } - - larger := max(len(rowsA), len(rowsB)) - - for i := 0; i < larger; i++ { - - var ( - fa = "* * * * * *" - fb = "* * * * * *" - ) - - if i < len(rowsA) { - fa = strings.Join(rowsA[i], " ") - } - - if i < len(rowsB) { - fb = strings.Join(rowsB[i], " ") - } - - fmt.Printf("row=%v %v %v\n", i, fa, fb) - } - - logrus.Errorf("projection query %v failed", pa.Name) - } -} - -// Run implements the [wizard.VerifierAction] interface. -func (va *projectionVerifierAction) Run(run *wizard.VerifierRuntime) error { - - var ( - a = run.GetLocalPointEvalParams(va.HornerA0.ID).Y - b = run.GetLocalPointEvalParams(va.HornerB0.ID).Y - ) - - if a != b { - return fmt.Errorf("the horner check of the projection query `%v` did not pass", va.Name) - } - - return nil -} - -// RunGnark implements the [wizard.VerifierAction] interface. -func (va *projectionVerifierAction) RunGnark(api frontend.API, run *wizard.WizardVerifierCircuit) { - - var ( - a = run.GetLocalPointEvalParams(va.HornerA0.ID).Y - b = run.GetLocalPointEvalParams(va.HornerB0.ID).Y - ) - - api.AssertIsEqual(a, b) -} - -func (va *projectionVerifierAction) Skip() { - va.skipped = true -} - -func (va *projectionVerifierAction) IsSkipped() bool { - return va.skipped -} - -// cmptHorner computes a random Horner accumulation of the filtered elements -// starting from the last entry down to the first entry. The final value is -// stored in the last entry of the returned slice. -func cmptHorner(c, fC []field.Element, x field.Element) []field.Element { - - var ( - horner = make([]field.Element, len(c)) - prev field.Element - ) - - for i := len(horner) - 1; i >= 0; i-- { - - if !fC[i].IsZero() && !fC[i].IsOne() { - utils.Panic("we expected the filter to be binary") - } - - if fC[i].IsOne() { - prev.Mul(&prev, &x) - prev.Add(&prev, &c[i]) - } - - horner[i] = prev - } - - return horner -} diff --git a/prover/protocol/dedicated/projection/projection_query.go b/prover/protocol/dedicated/projection/projection_query.go deleted file mode 100644 index b8b6e5ae7..000000000 --- a/prover/protocol/dedicated/projection/projection_query.go +++ /dev/null @@ -1,52 +0,0 @@ -package projection - -/* -Package projection implements the utilities for the projection query. - -A projection query between sets (columnsA,filterA) and (columnsB,filterB) asserts -whether the columnsA filtered by filterA is the same as columnsB filtered by -filterB, preserving the order. - -Example: - -FilterA = (1,0,0,1,1), ColumnA := (aO,a1,a2,a3,a4) - -FiletrB := (0,0,1,0,0,0,0,0,1,1), ColumnB :=(b0,b1,b2,b3,b4,b5,b6,b7,b8,b9) - -Thus we have, - -ColumnA filtered by FilterA = (a0,a3,a4) - -ColumnB filtered by FilterB = (b2,b8,b9) - -The projection query checks if a0 = b2, a3 = b8, a4 = b9 - -Note that the query imposes that: - - the number of 1 in the filters are equal - - the order of filtered elements is preserved -*/ - -import ( - "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/protocol/wizardutils" -) - -func RegisterProjection( - comp *wizard.CompiledIOP, - queryName ifaces.QueryID, - columnsA, columnsB []ifaces.Column, - filterA, filterB ifaces.Column, -) { - - var ( - round = max( - wizardutils.MaxRound(columnsA...), - wizardutils.MaxRound(columnsB...), - filterA.Round(), - filterB.Round(), - ) - ) - comp.InsertProjection(round, queryName, query.ProjectionInput{ColumnA: columnsA, ColumnB: columnsB, FilterA: filterA, FilterB: filterB}) -} diff --git a/prover/protocol/dedicated/projection/projection_test.go b/prover/protocol/dedicated/projection/projection_test.go deleted file mode 100644 index 4de92cf9e..000000000 --- a/prover/protocol/dedicated/projection/projection_test.go +++ /dev/null @@ -1,61 +0,0 @@ -package projection - -import ( - "testing" - - "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/dummy" - "github.com/consensys/linea-monorepo/prover/protocol/ifaces" - "github.com/consensys/linea-monorepo/prover/protocol/wizard" - "github.com/stretchr/testify/assert" -) - -func makeTestCaseProjection() ( - define wizard.DefineFunc, - prover wizard.ProverStep, -) { - round := 0 - flagSizeA := 512 - flagSizeB := 256 - var flagA, flagB, columnA, columnB ifaces.Column - define = func(build *wizard.Builder) { - comp := build.CompiledIOP - flagA = comp.InsertCommit(round, ifaces.ColID("FilterA"), flagSizeA) - flagB = comp.InsertCommit(round, ifaces.ColID("FliterB"), flagSizeB) - columnA = comp.InsertCommit(round, ifaces.ColID("ColumnA"), flagSizeA) - columnB = comp.InsertCommit(round, ifaces.ColID("ColumnB"), flagSizeB) - RegisterProjection(comp, ifaces.QueryIDf("OrderPreserving"), - []ifaces.Column{columnA}, []ifaces.Column{columnB}, flagA, flagB) - - } - prover = func(run *wizard.ProverRuntime) { - // assign filters and columns - flagAWit := make([]field.Element, flagSizeA) - columnAWit := make([]field.Element, flagSizeA) - flagBWit := make([]field.Element, flagSizeB) - columnBWit := make([]field.Element, flagSizeB) - for i := 0; i < 10; i++ { - flagAWit[i] = field.One() - columnAWit[i] = field.NewElement(uint64(i)) - } - for i := flagSizeB - 10; i < flagSizeB; i++ { - flagBWit[i] = field.One() - columnBWit[i] = field.NewElement(uint64(i - (flagSizeB - 10))) - } - run.AssignColumn(flagA.GetColID(), smartvectors.RightZeroPadded(flagAWit, flagSizeA)) - run.AssignColumn(flagB.GetColID(), smartvectors.RightZeroPadded(flagBWit, flagSizeB)) - run.AssignColumn(columnB.GetColID(), smartvectors.RightZeroPadded(columnBWit, flagSizeB)) - run.AssignColumn(columnA.GetColID(), smartvectors.RightZeroPadded(columnAWit, flagSizeA)) - } - return define, prover -} - -func TestProjectionQuery(t *testing.T) { - - define, prover := makeTestCaseProjection() - comp := wizard.Compile(define, dummy.Compile) - - proof := wizard.Prove(comp, prover) - assert.NoErrorf(t, wizard.Verify(comp, proof), "invalid proof") -} diff --git a/prover/protocol/query/projection_test.go b/prover/protocol/query/projection_test.go index 4b0498e4d..bd1a307fa 100644 --- a/prover/protocol/query/projection_test.go +++ b/prover/protocol/query/projection_test.go @@ -26,7 +26,7 @@ func TestProjection(t *testing.T) { flagB = comp.InsertCommit(round, ifaces.ColID("FliterB"), flagSizeB) columnA = comp.InsertCommit(round, ifaces.ColID("ColumnA"), flagSizeA) columnB = comp.InsertCommit(round, ifaces.ColID("ColumnB"), flagSizeB) - P = comp.InsertProjection(round, "ProjectionTest", + P = comp.InsertProjection("ProjectionTest", query.ProjectionInput{ColumnA: []ifaces.Column{columnA}, ColumnB: []ifaces.Column{columnB}, FilterA: flagA, FilterB: flagB}) } diff --git a/prover/protocol/wizard/compiled.go b/prover/protocol/wizard/compiled.go index fb06c680b..b24f861bd 100644 --- a/prover/protocol/wizard/compiled.go +++ b/prover/protocol/wizard/compiled.go @@ -654,8 +654,37 @@ func (c *CompiledIOP) InsertGrandProduct(round int, id ifaces.QueryID, in map[in return q } -// Register a Projection query -func (c *CompiledIOP) InsertProjection(round int, id ifaces.QueryID, in query.ProjectionInput) query.Projection { +/* +A projection query between sets (columnsA,filterA) and (columnsB,filterB) asserts +whether the columnsA filtered by filterA is the same as columnsB filtered by +filterB, preserving the order. + +Example: + +FilterA = (1,0,0,1,1), ColumnA := (aO,a1,a2,a3,a4) + +FiletrB := (0,0,1,0,0,0,0,0,1,1), ColumnB :=(b0,b1,b2,b3,b4,b5,b6,b7,b8,b9) + +Thus we have, + +ColumnA filtered by FilterA = (a0,a3,a4) + +ColumnB filtered by FilterB = (b2,b8,b9) + +The projection query checks if a0 = b2, a3 = b8, a4 = b9 + +Note that the query imposes that: + - the number of 1 in the filters are equal + - the order of filtered elements is preserved +*/ +func (c *CompiledIOP) InsertProjection(id ifaces.QueryID, in query.ProjectionInput) query.Projection { + var ( + round = max( + column.MaxRound(in.ColumnA...), + column.MaxRound(in.ColumnB...), + in.FilterA.Round(), + in.FilterB.Round()) + ) c.assertConsistentRound(round) q := query.NewProjection(round, id, in) // Finally registers the query diff --git a/prover/protocol/wizardutils/utils.go b/prover/protocol/wizardutils/utils.go index 764092a1f..9694c6f63 100644 --- a/prover/protocol/wizardutils/utils.go +++ b/prover/protocol/wizardutils/utils.go @@ -42,15 +42,6 @@ func LastRoundToEval(expr *symbolic.Expression) int { return maxRound } -// maximal round of declaration for a list of commitment -func MaxRound(handles ...ifaces.Column) int { - res := 0 - for _, handle := range handles { - res = utils.Max(res, handle.Round()) - } - return res -} - // DeriveName is used to construct either [ifaces.QueryID] or [ifaces.ColID] or // [coin.Name]. The function will format [ifaces.Query], [ifaces.Column] or // [coin.Info] using their names or IDs, in the other cases it will use the diff --git a/prover/zkevm/prover/common/hashing.go b/prover/zkevm/prover/common/hashing.go index a82cdbb32..14584476f 100644 --- a/prover/zkevm/prover/common/hashing.go +++ b/prover/zkevm/prover/common/hashing.go @@ -4,10 +4,10 @@ import ( "github.com/consensys/linea-monorepo/prover/crypto/mimc" "github.com/consensys/linea-monorepo/prover/maths/common/smartvectors" "github.com/consensys/linea-monorepo/prover/maths/field" + "github.com/consensys/linea-monorepo/prover/protocol/column" "github.com/consensys/linea-monorepo/prover/protocol/column/verifiercol" "github.com/consensys/linea-monorepo/prover/protocol/ifaces" "github.com/consensys/linea-monorepo/prover/protocol/wizard" - "github.com/consensys/linea-monorepo/prover/protocol/wizardutils" "github.com/consensys/linea-monorepo/prover/utils" "github.com/consensys/linea-monorepo/prover/utils/parallel" ) @@ -34,7 +34,7 @@ func HashOf(comp *wizard.CompiledIOP, inputCols []ifaces.Column) (ifaces.Column, InputCols: inputCols, IntermediateHashes: make([]ifaces.Column, len(inputCols)), } - round = wizardutils.MaxRound(inputCols...) + round = column.MaxRound(inputCols...) ctxID = len(comp.ListCommitments()) numRows = ifaces.AssertSameLength(inputCols...) prevState = verifiercol.NewConstantCol(field.Zero(), numRows) diff --git a/prover/zkevm/prover/ecdsa/adress.go b/prover/zkevm/prover/ecdsa/adress.go index 662203def..b2d4a11d5 100644 --- a/prover/zkevm/prover/ecdsa/adress.go +++ b/prover/zkevm/prover/ecdsa/adress.go @@ -8,8 +8,8 @@ import ( "github.com/consensys/linea-monorepo/prover/protocol/column" "github.com/consensys/linea-monorepo/prover/protocol/dedicated" "github.com/consensys/linea-monorepo/prover/protocol/dedicated/byte32cmp" - "github.com/consensys/linea-monorepo/prover/protocol/dedicated/projection" "github.com/consensys/linea-monorepo/prover/protocol/ifaces" + "github.com/consensys/linea-monorepo/prover/protocol/query" "github.com/consensys/linea-monorepo/prover/protocol/wizard" sym "github.com/consensys/linea-monorepo/prover/symbolic" "github.com/consensys/linea-monorepo/prover/zkevm/prover/common" @@ -99,26 +99,29 @@ func newAddress(comp *wizard.CompiledIOP, size int, ecRec *EcRecover, ac *antich // projection from ecRecover to address columns // ecdata is already projected over our ecRecover. Thus, we only project from our ecrecover. - projection.RegisterProjection(comp, ifaces.QueryIDf("Project_AddressHi_EcRec"), - []ifaces.Column{ecRec.Limb}, []ifaces.Column{addr.addressHi}, - addr.isAddressHiEcRec, addr.isAddressFromEcRec, - ) + comp.InsertProjection(ifaces.QueryIDf("Project_AddressHi_EcRec"), query.ProjectionInput{ColumnA: []ifaces.Column{ecRec.Limb}, + ColumnB: []ifaces.Column{addr.addressHi}, + FilterA: addr.isAddressHiEcRec, + FilterB: addr.isAddressFromEcRec}) - projection.RegisterProjection(comp, ifaces.QueryIDf("Project_AddressLo_EcRec"), - []ifaces.Column{ecRec.Limb}, []ifaces.Column{addr.addressLo}, - column.Shift(addr.isAddressHiEcRec, -1), addr.isAddressFromEcRec, - ) + comp.InsertProjection(ifaces.QueryIDf("Project_AddressLo_EcRec"), + query.ProjectionInput{ColumnA: []ifaces.Column{ecRec.Limb}, + ColumnB: []ifaces.Column{addr.addressLo}, + FilterA: column.Shift(addr.isAddressHiEcRec, -1), + FilterB: addr.isAddressFromEcRec}) // projection from txn-data to address columns - projection.RegisterProjection(comp, ifaces.QueryIDf("Project_AddressHi_TxnData"), - []ifaces.Column{td.fromHi}, []ifaces.Column{addr.addressHi}, - td.isFrom, addr.isAddressFromTxnData, - ) - - projection.RegisterProjection(comp, ifaces.QueryIDf("Project_AddressLO_TxnData"), - []ifaces.Column{td.fromLo}, []ifaces.Column{addr.addressLo}, - td.isFrom, addr.isAddressFromTxnData, - ) + comp.InsertProjection(ifaces.QueryIDf("Project_AddressHi_TxnData"), + query.ProjectionInput{ColumnA: []ifaces.Column{td.fromHi}, + ColumnB: []ifaces.Column{addr.addressHi}, + FilterA: td.isFrom, + FilterB: addr.isAddressFromTxnData}) + + comp.InsertProjection(ifaces.QueryIDf("Project_AddressLO_TxnData"), + query.ProjectionInput{ColumnA: []ifaces.Column{td.fromLo}, + ColumnB: []ifaces.Column{addr.addressLo}, + FilterA: td.isFrom, + FilterB: addr.isAddressFromTxnData}) // impose that hashNum = ac.ID + 1 comp.InsertGlobal(0, ifaces.QueryIDf("Hash_NUM_IS_ID"), diff --git a/prover/zkevm/prover/ecdsa/ecdata.go b/prover/zkevm/prover/ecdsa/ecdata.go index c01c2dde4..c1b2f335b 100644 --- a/prover/zkevm/prover/ecdsa/ecdata.go +++ b/prover/zkevm/prover/ecdsa/ecdata.go @@ -3,8 +3,8 @@ package ecdsa import ( "github.com/consensys/linea-monorepo/prover/maths/common/smartvectors" "github.com/consensys/linea-monorepo/prover/maths/field" - "github.com/consensys/linea-monorepo/prover/protocol/dedicated/projection" "github.com/consensys/linea-monorepo/prover/protocol/ifaces" + "github.com/consensys/linea-monorepo/prover/protocol/query" "github.com/consensys/linea-monorepo/prover/protocol/wizard" sym "github.com/consensys/linea-monorepo/prover/symbolic" commoncs "github.com/consensys/linea-monorepo/prover/zkevm/prover/common/common_constraints" @@ -166,11 +166,11 @@ func (ec *EcRecover) assignFromEcDataSource(run *wizard.ProverRuntime, src *ecDa } func (ec *EcRecover) csEcDataProjection(comp *wizard.CompiledIOP, src *ecDataSource) { - projection.RegisterProjection(comp, ifaces.QueryIDf("%v_PROJECT_ECDATA", NAME_ECRECOVER), - []ifaces.Column{ec.EcRecoverID, ec.Limb, ec.SuccessBit, ec.EcRecoverIndex, ec.EcRecoverIsData, ec.EcRecoverIsRes}, - []ifaces.Column{src.ID, src.Limb, src.SuccessBit, src.Index, src.IsData, src.IsRes}, - ec.AuxProjectionMask, src.CsEcrecover, - ) + comp.InsertProjection(ifaces.QueryIDf("%v_PROJECT_ECDATA", NAME_ECRECOVER), + query.ProjectionInput{ColumnA: []ifaces.Column{ec.EcRecoverID, ec.Limb, ec.SuccessBit, ec.EcRecoverIndex, ec.EcRecoverIsData, ec.EcRecoverIsRes}, + ColumnB: []ifaces.Column{src.ID, src.Limb, src.SuccessBit, src.Index, src.IsData, src.IsRes}, + FilterA: ec.AuxProjectionMask, + FilterB: src.CsEcrecover}) } func (ec *EcRecover) csConstraintAuxProjectionMask(comp *wizard.CompiledIOP) { diff --git a/prover/zkevm/prover/ecdsa/unaligned_gnark.go b/prover/zkevm/prover/ecdsa/unaligned_gnark.go index 5edeacddd..7b63fbef7 100644 --- a/prover/zkevm/prover/ecdsa/unaligned_gnark.go +++ b/prover/zkevm/prover/ecdsa/unaligned_gnark.go @@ -8,8 +8,8 @@ import ( "github.com/consensys/linea-monorepo/prover/maths/field" "github.com/consensys/linea-monorepo/prover/protocol/column" "github.com/consensys/linea-monorepo/prover/protocol/dedicated" - "github.com/consensys/linea-monorepo/prover/protocol/dedicated/projection" "github.com/consensys/linea-monorepo/prover/protocol/ifaces" + "github.com/consensys/linea-monorepo/prover/protocol/query" "github.com/consensys/linea-monorepo/prover/protocol/wizard" sym "github.com/consensys/linea-monorepo/prover/symbolic" "github.com/consensys/linea-monorepo/prover/utils" @@ -349,14 +349,12 @@ func (d *UnalignedGnarkData) csProjectionEcRecover(comp *wizard.CompiledIOP, src )), ) // that we have projected correctly ecrecover - projection.RegisterProjection( - comp, + comp.InsertProjection( ifaces.QueryIDf("%v_PROJECT_ECRECOVER", NAME_UNALIGNED_GNARKDATA), - []ifaces.Column{src.Limb}, - []ifaces.Column{d.GnarkData}, - d.isEcrecoverAndFetching, - d.isNotPublicKeyAndPushing, - ) + query.ProjectionInput{ColumnA: []ifaces.Column{src.Limb}, + ColumnB: []ifaces.Column{d.GnarkData}, + FilterA: d.isEcrecoverAndFetching, + FilterB: d.isNotPublicKeyAndPushing}) } func (d *UnalignedGnarkData) csTxHash(comp *wizard.CompiledIOP, src *unalignedGnarkDataSource) { diff --git a/prover/zkevm/prover/ecpair/ecpair_constraints.go b/prover/zkevm/prover/ecpair/ecpair_constraints.go index 6456f81c7..789a3745e 100644 --- a/prover/zkevm/prover/ecpair/ecpair_constraints.go +++ b/prover/zkevm/prover/ecpair/ecpair_constraints.go @@ -5,8 +5,8 @@ import ( "github.com/consensys/linea-monorepo/prover/protocol/column" "github.com/consensys/linea-monorepo/prover/protocol/column/verifiercol" "github.com/consensys/linea-monorepo/prover/protocol/dedicated" - "github.com/consensys/linea-monorepo/prover/protocol/dedicated/projection" "github.com/consensys/linea-monorepo/prover/protocol/ifaces" + "github.com/consensys/linea-monorepo/prover/protocol/query" "github.com/consensys/linea-monorepo/prover/protocol/wizard" sym "github.com/consensys/linea-monorepo/prover/symbolic" common "github.com/consensys/linea-monorepo/prover/zkevm/prover/common/common_constraints" @@ -53,19 +53,18 @@ func (ec *ECPair) csOffWhenInactive(comp *wizard.CompiledIOP) { func (ec *ECPair) csProjections(comp *wizard.CompiledIOP) { // we project data from the arithmetization correctly to the unaligned part of the circuit - projection.RegisterProjection( - comp, ifaces.QueryIDf("%v_PROJECTION_PAIRING", nameECPair), - []ifaces.Column{ec.ECPairSource.Limb, ec.ECPairSource.AccPairings, ec.ECPairSource.TotalPairings, ec.ECPairSource.ID}, - []ifaces.Column{ec.UnalignedPairingData.Limb, ec.UnalignedPairingData.PairID, ec.UnalignedPairingData.TotalPairs, ec.UnalignedPairingData.InstanceID}, - ec.ECPairSource.CsEcpairing, - ec.UnalignedPairingData.IsPulling, - ) - projection.RegisterProjection( - comp, ifaces.QueryIDf("%v_PROJECTION_MEMBERSHIP", nameECPair), - []ifaces.Column{ec.ECPairSource.Limb, ec.ECPairSource.SuccessBit}, - []ifaces.Column{ec.UnalignedG2MembershipData.Limb, ec.UnalignedG2MembershipData.SuccessBit}, - ec.ECPairSource.CsG2Membership, ec.UnalignedG2MembershipData.IsPulling, - ) + comp.InsertProjection(ifaces.QueryIDf("%v_PROJECTION_PAIRING", nameECPair), + query.ProjectionInput{ColumnA: []ifaces.Column{ec.ECPairSource.Limb, ec.ECPairSource.AccPairings, ec.ECPairSource.TotalPairings, ec.ECPairSource.ID}, + ColumnB: []ifaces.Column{ec.UnalignedPairingData.Limb, ec.UnalignedPairingData.PairID, ec.UnalignedPairingData.TotalPairs, ec.UnalignedPairingData.InstanceID}, + FilterA: ec.ECPairSource.CsEcpairing, + FilterB: ec.UnalignedPairingData.IsPulling}) + + comp.InsertProjection( + ifaces.QueryIDf("%v_PROJECTION_MEMBERSHIP", nameECPair), + query.ProjectionInput{ColumnA: []ifaces.Column{ec.ECPairSource.Limb, ec.ECPairSource.SuccessBit}, + ColumnB: []ifaces.Column{ec.UnalignedG2MembershipData.Limb, ec.UnalignedG2MembershipData.SuccessBit}, + FilterA: ec.ECPairSource.CsG2Membership, + FilterB: ec.UnalignedG2MembershipData.IsPulling}) } func (ec *ECPair) csMembershipComputedResult(comp *wizard.CompiledIOP) { @@ -151,12 +150,12 @@ func (ec *ECPair) csAccumulatorInit(comp *wizard.CompiledIOP) { func (ec *ECPair) csAccumulatorConsistency(comp *wizard.CompiledIOP) { // that the accumulator between pairs is consistent - projection.RegisterProjection( - comp, + comp.InsertProjection( ifaces.QueryIDf("%v_ACCUMULATOR_CONSISTENCY", nameECPair), - []ifaces.Column{ec.UnalignedPairingData.Limb}, []ifaces.Column{ec.UnalignedPairingData.Limb}, - ec.UnalignedPairingData.IsAccumulatorCurr, ec.UnalignedPairingData.IsAccumulatorPrev, - ) + query.ProjectionInput{ColumnA: []ifaces.Column{ec.UnalignedPairingData.Limb}, + ColumnB: []ifaces.Column{ec.UnalignedPairingData.Limb}, + FilterA: ec.UnalignedPairingData.IsAccumulatorCurr, + FilterB: ec.UnalignedPairingData.IsAccumulatorPrev}) } func (ec *ECPair) csLastPairToFinalExp(comp *wizard.CompiledIOP) { diff --git a/prover/zkevm/prover/hash/importpad/import_pad.go b/prover/zkevm/prover/hash/importpad/import_pad.go index b748d6e3b..63b8cef80 100644 --- a/prover/zkevm/prover/hash/importpad/import_pad.go +++ b/prover/zkevm/prover/hash/importpad/import_pad.go @@ -4,8 +4,8 @@ import ( "github.com/consensys/linea-monorepo/prover/maths/field" "github.com/consensys/linea-monorepo/prover/protocol/column" "github.com/consensys/linea-monorepo/prover/protocol/dedicated" - "github.com/consensys/linea-monorepo/prover/protocol/dedicated/projection" "github.com/consensys/linea-monorepo/prover/protocol/ifaces" + "github.com/consensys/linea-monorepo/prover/protocol/query" "github.com/consensys/linea-monorepo/prover/protocol/wizard" sym "github.com/consensys/linea-monorepo/prover/symbolic" "github.com/consensys/linea-monorepo/prover/zkevm/prover/common" @@ -184,14 +184,12 @@ func ImportAndPad(comp *wizard.CompiledIOP, inp ImportAndPadInputs, numRows int) res.IsPadded, ) - projection.RegisterProjection( - comp, + comp.InsertProjection( ifaces.QueryIDf("%v_IMPORT_PAD_PROJECTION", inp.Name), - []ifaces.Column{inp.Src.Data.HashNum, inp.Src.Data.Limb, inp.Src.Data.NBytes, inp.Src.Data.Index}, - []ifaces.Column{res.HashNum, res.Limbs, res.NBytes, res.Index}, - inp.Src.Data.ToHash, - res.IsInserted, - ) + query.ProjectionInput{ColumnA: []ifaces.Column{inp.Src.Data.HashNum, inp.Src.Data.Limb, inp.Src.Data.NBytes, inp.Src.Data.Index}, + ColumnB: []ifaces.Column{res.HashNum, res.Limbs, res.NBytes, res.Index}, + FilterA: inp.Src.Data.ToHash, + FilterB: res.IsInserted}) return res } diff --git a/prover/zkevm/prover/hash/keccak/acc_module/data_acc.go b/prover/zkevm/prover/hash/keccak/acc_module/data_acc.go index d3a6adad6..0ab376f03 100644 --- a/prover/zkevm/prover/hash/keccak/acc_module/data_acc.go +++ b/prover/zkevm/prover/hash/keccak/acc_module/data_acc.go @@ -5,8 +5,8 @@ import ( "github.com/consensys/linea-monorepo/prover/maths/common/smartvectors" "github.com/consensys/linea-monorepo/prover/maths/common/vector" "github.com/consensys/linea-monorepo/prover/maths/field" - projection "github.com/consensys/linea-monorepo/prover/protocol/dedicated/projection" "github.com/consensys/linea-monorepo/prover/protocol/ifaces" + "github.com/consensys/linea-monorepo/prover/protocol/query" "github.com/consensys/linea-monorepo/prover/protocol/wizard" sym "github.com/consensys/linea-monorepo/prover/symbolic" "github.com/consensys/linea-monorepo/prover/utils" @@ -70,12 +70,12 @@ func NewGenericDataAccumulator(comp *wizard.CompiledIOP, inp GenericAccumulatorI // projection among providers and stitched module for i, gbm := range d.Inputs.ProvidersData { - projection.RegisterProjection(comp, ifaces.QueryIDf("Stitch_Modules_%v", i), - []ifaces.Column{gbm.HashNum, gbm.Limb, gbm.NBytes, gbm.Index}, - []ifaces.Column{d.Provider.HashNum, d.Provider.Limb, d.Provider.NBytes, d.Provider.Index}, - gbm.ToHash, - d.sFilters[i], - ) + comp.InsertProjection(ifaces.QueryIDf("Stitch_Modules_%v", i), + query.ProjectionInput{ColumnA: []ifaces.Column{gbm.HashNum, gbm.Limb, gbm.NBytes, gbm.Index}, + ColumnB: []ifaces.Column{d.Provider.HashNum, d.Provider.Limb, d.Provider.NBytes, d.Provider.Index}, + FilterA: gbm.ToHash, + FilterB: d.sFilters[i]}) + } return d diff --git a/prover/zkevm/prover/hash/keccak/acc_module/info_acc.go b/prover/zkevm/prover/hash/keccak/acc_module/info_acc.go index dca21098f..bff6687ac 100644 --- a/prover/zkevm/prover/hash/keccak/acc_module/info_acc.go +++ b/prover/zkevm/prover/hash/keccak/acc_module/info_acc.go @@ -4,8 +4,8 @@ import ( "github.com/consensys/linea-monorepo/prover/maths/common/smartvectors" "github.com/consensys/linea-monorepo/prover/maths/common/vector" "github.com/consensys/linea-monorepo/prover/maths/field" - projection "github.com/consensys/linea-monorepo/prover/protocol/dedicated/projection" "github.com/consensys/linea-monorepo/prover/protocol/ifaces" + "github.com/consensys/linea-monorepo/prover/protocol/query" "github.com/consensys/linea-monorepo/prover/protocol/wizard" sym "github.com/consensys/linea-monorepo/prover/symbolic" "github.com/consensys/linea-monorepo/prover/utils" @@ -59,19 +59,17 @@ func NewGenericInfoAccumulator(comp *wizard.CompiledIOP, inp GenericAccumulatorI // projection among providers and stitched module for i, gbm := range info.Inputs.ProvidersInfo { - projection.RegisterProjection(comp, ifaces.QueryIDf("Stitch_Modules_Hi_%v", i), - []ifaces.Column{gbm.HashHi}, - []ifaces.Column{info.Provider.HashHi}, - gbm.IsHashHi, - info.sFilters[i], - ) - - projection.RegisterProjection(comp, ifaces.QueryIDf("Stitch_Modules_Lo_%v", i), - []ifaces.Column{gbm.HashLo}, - []ifaces.Column{info.Provider.HashLo}, - gbm.IsHashLo, - info.sFilters[i], - ) + comp.InsertProjection(ifaces.QueryIDf("Stitch_Modules_Hi_%v", i), + query.ProjectionInput{ColumnA: []ifaces.Column{gbm.HashHi}, + ColumnB: []ifaces.Column{info.Provider.HashHi}, + FilterA: gbm.IsHashHi, + FilterB: info.sFilters[i]}) + + comp.InsertProjection(ifaces.QueryIDf("Stitch_Modules_Lo_%v", i), + query.ProjectionInput{ColumnA: []ifaces.Column{gbm.HashLo}, + ColumnB: []ifaces.Column{info.Provider.HashLo}, + FilterA: gbm.IsHashLo, + FilterB: info.sFilters[i]}) } return info } diff --git a/prover/zkevm/prover/hash/keccak/keccak_single_provider.go b/prover/zkevm/prover/hash/keccak/keccak_single_provider.go index ec42008c4..622a617a7 100644 --- a/prover/zkevm/prover/hash/keccak/keccak_single_provider.go +++ b/prover/zkevm/prover/hash/keccak/keccak_single_provider.go @@ -4,8 +4,8 @@ package keccak import ( - "github.com/consensys/linea-monorepo/prover/protocol/dedicated/projection" "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/prover/hash/generic" @@ -82,18 +82,17 @@ func NewKeccakSingleProvider(comp *wizard.CompiledIOP, inp KeccakSingleProviderI cKeccak = NewKeccakOverBlocks(comp, cKeccakInp) ) - projection.RegisterProjection(comp, "KECCAK_RES_HI", - []ifaces.Column{cKeccak.HashHi}, - []ifaces.Column{inp.Provider.Info.HashHi}, - cKeccak.IsActive, - inp.Provider.Info.IsHashHi, - ) - projection.RegisterProjection(comp, "KECCAK_RES_LO", - []ifaces.Column{cKeccak.HashLo}, - []ifaces.Column{inp.Provider.Info.HashLo}, - cKeccak.IsActive, - inp.Provider.Info.IsHashLo, - ) + comp.InsertProjection("KECCAK_RES_HI", + query.ProjectionInput{ColumnA: []ifaces.Column{cKeccak.HashHi}, + ColumnB: []ifaces.Column{inp.Provider.Info.HashHi}, + FilterA: cKeccak.IsActive, + FilterB: inp.Provider.Info.IsHashHi}) + + comp.InsertProjection("KECCAK_RES_LO", + query.ProjectionInput{ColumnA: []ifaces.Column{cKeccak.HashLo}, + ColumnB: []ifaces.Column{inp.Provider.Info.HashLo}, + FilterA: cKeccak.IsActive, + FilterB: inp.Provider.Info.IsHashLo}) // set the module m := &KeccakSingleProvider{ diff --git a/prover/zkevm/prover/hash/keccak/keccakf/io.go b/prover/zkevm/prover/hash/keccak/keccakf/io.go index 5dda1a8d3..0151cd04e 100644 --- a/prover/zkevm/prover/hash/keccak/keccakf/io.go +++ b/prover/zkevm/prover/hash/keccak/keccakf/io.go @@ -4,8 +4,8 @@ import ( "github.com/consensys/linea-monorepo/prover/crypto/keccak" "github.com/consensys/linea-monorepo/prover/maths/field" "github.com/consensys/linea-monorepo/prover/protocol/column" - "github.com/consensys/linea-monorepo/prover/protocol/dedicated/projection" "github.com/consensys/linea-monorepo/prover/protocol/ifaces" + "github.com/consensys/linea-monorepo/prover/protocol/query" "github.com/consensys/linea-monorepo/prover/protocol/wizard" sym "github.com/consensys/linea-monorepo/prover/symbolic" "github.com/consensys/linea-monorepo/prover/utils" @@ -229,11 +229,11 @@ func (io *InputOutput) csHashOutput(comp *wizard.CompiledIOP) { colB = append(colB, io.HashOutputSlicesBaseB[2][:]...) colB = append(colB, io.HashOutputSlicesBaseB[3][:]...) - projection.RegisterProjection(comp, ifaces.QueryIDf("HashOutput_Projection"), - colB, colA, - io.IsActive, - io.IsHashOutPut, - ) + comp.InsertProjection(ifaces.QueryIDf("HashOutput_Projection"), + query.ProjectionInput{ColumnA: colB, + ColumnB: colA, + FilterA: io.IsActive, + FilterB: io.IsHashOutPut}) } // It assigns the columns specific to the submodule. diff --git a/prover/zkevm/prover/hash/packing/lane.go b/prover/zkevm/prover/hash/packing/lane.go index f55697546..995a342bc 100644 --- a/prover/zkevm/prover/hash/packing/lane.go +++ b/prover/zkevm/prover/hash/packing/lane.go @@ -4,8 +4,8 @@ import ( "github.com/consensys/linea-monorepo/prover/maths/common/smartvectors" "github.com/consensys/linea-monorepo/prover/maths/field" "github.com/consensys/linea-monorepo/prover/protocol/column" - "github.com/consensys/linea-monorepo/prover/protocol/dedicated/projection" "github.com/consensys/linea-monorepo/prover/protocol/ifaces" + "github.com/consensys/linea-monorepo/prover/protocol/query" "github.com/consensys/linea-monorepo/prover/protocol/wizard" sym "github.com/consensys/linea-monorepo/prover/symbolic" "github.com/consensys/linea-monorepo/prover/utils" @@ -81,11 +81,11 @@ func newLane(comp *wizard.CompiledIOP, spaghetti spaghettiCtx, pckInp PackingInp // constraints over isFirstLaneOfNewHash // Project the isFirstLaneOfNewHash from isFirstSliceOfNewHash - projection.RegisterProjection(comp, ifaces.QueryIDf("Project_IsFirstLaneOfHash_"+pckInp.Name), - []ifaces.Column{isFirstSliceOfNewHash}, - []ifaces.Column{l.IsFirstLaneOfNewHash}, - l.isLaneComplete, l.IsLaneActive) - + comp.InsertProjection(ifaces.QueryIDf("Project_IsFirstLaneOfHash_"+pckInp.Name), + query.ProjectionInput{ColumnA: []ifaces.Column{isFirstSliceOfNewHash}, + ColumnB: []ifaces.Column{l.IsFirstLaneOfNewHash}, + FilterA: l.isLaneComplete, + FilterB: l.IsLaneActive}) return l } @@ -135,12 +135,11 @@ func (l *laneRepacking) csRecomposeToLanes(comp *wizard.CompiledIOP, s spaghetti ) // Project the lanes from ipTracker over the Lane column. - projection.RegisterProjection(comp, ifaces.QueryIDf("%v_ProjectOverLanes", l.Inputs.pckInp.Name), - []ifaces.Column{ipTracker}, - []ifaces.Column{l.Lanes}, - l.isLaneComplete, l.IsLaneActive, - ) - + comp.InsertProjection(ifaces.QueryIDf("%v_ProjectOverLanes", l.Inputs.pckInp.Name), + query.ProjectionInput{ColumnA: []ifaces.Column{ipTracker}, + ColumnB: []ifaces.Column{l.Lanes}, + FilterA: l.isLaneComplete, + FilterB: l.IsLaneActive}) } // It assigns the columns specific to the submodule diff --git a/prover/zkevm/prover/hash/sha2/sha2.go b/prover/zkevm/prover/hash/sha2/sha2.go index 938b91058..b7c3169a8 100644 --- a/prover/zkevm/prover/hash/sha2/sha2.go +++ b/prover/zkevm/prover/hash/sha2/sha2.go @@ -4,8 +4,8 @@ package sha2 import ( "github.com/consensys/linea-monorepo/prover/protocol/column" - "github.com/consensys/linea-monorepo/prover/protocol/dedicated/projection" "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/prover/hash/generic" @@ -112,18 +112,17 @@ func newSha2SingleProvider(comp *wizard.CompiledIOP, inp Sha2SingleProviderInput cSha2 = newSha2BlockModule(comp, cSha2Inp).WithCircuit(comp) ) - projection.RegisterProjection(comp, "SHA2_RES_HI", - []ifaces.Column{cSha2.HashHi}, - []ifaces.Column{inp.Provider.Info.HashHi}, - cSha2.IsEffFirstLaneOfNewHash, - inp.Provider.Info.IsHashHi, - ) - projection.RegisterProjection(comp, "SHA2_RES_LO", - []ifaces.Column{cSha2.HashLo}, - []ifaces.Column{inp.Provider.Info.HashLo}, - cSha2.IsEffFirstLaneOfNewHash, - inp.Provider.Info.IsHashLo, - ) + comp.InsertProjection("SHA2_RES_HI", + query.ProjectionInput{ColumnA: []ifaces.Column{cSha2.HashHi}, + ColumnB: []ifaces.Column{inp.Provider.Info.HashHi}, + FilterA: cSha2.IsEffFirstLaneOfNewHash, + FilterB: inp.Provider.Info.IsHashHi}) + + comp.InsertProjection("SHA2_RES_LO", + query.ProjectionInput{ColumnA: []ifaces.Column{cSha2.HashLo}, + ColumnB: []ifaces.Column{inp.Provider.Info.HashLo}, + FilterA: cSha2.IsEffFirstLaneOfNewHash, + FilterB: inp.Provider.Info.IsHashLo}) // set the module m := &Sha2SingleProvider{ diff --git a/prover/zkevm/prover/hash/sha2/sha2_block.go b/prover/zkevm/prover/hash/sha2/sha2_block.go index 65a15b970..bd5c05749 100644 --- a/prover/zkevm/prover/hash/sha2/sha2_block.go +++ b/prover/zkevm/prover/hash/sha2/sha2_block.go @@ -6,8 +6,8 @@ import ( "github.com/consensys/linea-monorepo/prover/protocol/column" "github.com/consensys/linea-monorepo/prover/protocol/dedicated" "github.com/consensys/linea-monorepo/prover/protocol/dedicated/plonk" - "github.com/consensys/linea-monorepo/prover/protocol/dedicated/projection" "github.com/consensys/linea-monorepo/prover/protocol/ifaces" + "github.com/consensys/linea-monorepo/prover/protocol/query" "github.com/consensys/linea-monorepo/prover/protocol/wizard" sym "github.com/consensys/linea-monorepo/prover/symbolic" "github.com/consensys/linea-monorepo/prover/utils" @@ -290,20 +290,14 @@ func newSha2BlockModule(comp *wizard.CompiledIOP, inp *sha2BlocksInputs) *sha2Bl // The following query ensures that the data in limbs corresponding to // limbs are exactly those provided by the input module. - projection.RegisterProjection( - comp, + comp.InsertProjection( ifaces.QueryIDf("%v_PROJECTION_INPUT", inp.Name), - []ifaces.Column{ - res.Inputs.IsFirstLaneOfNewHash, - res.Inputs.PackedUint32, - }, - []ifaces.Column{ - column.Shift(res.IsEffFirstLaneOfNewHash, -2), - res.Limbs, - }, - res.Inputs.Selector, - res.IsEffBlock, - ) + query.ProjectionInput{ColumnA: []ifaces.Column{res.Inputs.IsFirstLaneOfNewHash, + res.Inputs.PackedUint32}, + ColumnB: []ifaces.Column{column.Shift(res.IsEffFirstLaneOfNewHash, -2), + res.Limbs}, + FilterA: res.Inputs.Selector, + FilterB: res.IsEffBlock}) // As per the padding technique we use, the HashHi and HashLo should not // be zero when isActive. diff --git a/prover/zkevm/prover/modexp/module.go b/prover/zkevm/prover/modexp/module.go index c2dd9bf60..b384529fa 100644 --- a/prover/zkevm/prover/modexp/module.go +++ b/prover/zkevm/prover/modexp/module.go @@ -5,8 +5,8 @@ import ( "github.com/consensys/linea-monorepo/prover/maths/field" "github.com/consensys/linea-monorepo/prover/protocol/column" "github.com/consensys/linea-monorepo/prover/protocol/dedicated/plonk" - "github.com/consensys/linea-monorepo/prover/protocol/dedicated/projection" "github.com/consensys/linea-monorepo/prover/protocol/ifaces" + "github.com/consensys/linea-monorepo/prover/protocol/query" "github.com/consensys/linea-monorepo/prover/protocol/variables" "github.com/consensys/linea-monorepo/prover/protocol/wizard" sym "github.com/consensys/linea-monorepo/prover/symbolic" @@ -96,15 +96,12 @@ func newModule(comp *wizard.CompiledIOP, input Input) *Module { mod.csIsSmallAndLarge(comp) mod.csToCirc(comp) - projection.RegisterProjection( - comp, + comp.InsertProjection( "MODEXP_BLKMDXP_PROJECTION", - []ifaces.Column{mod.Input.Limbs}, - []ifaces.Column{mod.Limbs}, - mod.Input.isModExp, - mod.IsActive, - ) - + query.ProjectionInput{ColumnA: []ifaces.Column{mod.Input.Limbs}, + ColumnB: []ifaces.Column{mod.Limbs}, + FilterA: mod.Input.isModExp, + FilterB: mod.IsActive}) return mod } diff --git a/prover/zkevm/prover/publicInput/execution_data_collector/execution_data_collector.go b/prover/zkevm/prover/publicInput/execution_data_collector/execution_data_collector.go index 2d691d0df..6f6848a73 100644 --- a/prover/zkevm/prover/publicInput/execution_data_collector/execution_data_collector.go +++ b/prover/zkevm/prover/publicInput/execution_data_collector/execution_data_collector.go @@ -6,8 +6,8 @@ import ( "github.com/consensys/linea-monorepo/prover/protocol/accessors" "github.com/consensys/linea-monorepo/prover/protocol/column" "github.com/consensys/linea-monorepo/prover/protocol/dedicated" - "github.com/consensys/linea-monorepo/prover/protocol/dedicated/projection" "github.com/consensys/linea-monorepo/prover/protocol/ifaces" + "github.com/consensys/linea-monorepo/prover/protocol/query" "github.com/consensys/linea-monorepo/prover/protocol/wizard" sym "github.com/consensys/linea-monorepo/prover/symbolic" arith "github.com/consensys/linea-monorepo/prover/zkevm/prover/publicInput/arith_struct" @@ -808,14 +808,12 @@ func ProjectionQueries(comp *wizard.CompiledIOP, edc.LastAbsTxIDBlock, } - projection.RegisterProjection(comp, + comp.InsertProjection( ifaces.QueryIDf("%s_BLOCK_METADATA_PROJECTION", name), - edcMetadataTable, - metadataTable, - edc.IsNoTx, // We filter on rows where the blockdata is loaded. - metadata.FilterFetched, - ) - + query.ProjectionInput{ColumnA: edcMetadataTable, + ColumnB: metadataTable, + FilterA: edc.IsNoTx, // We filter on rows where the blockdata is loaded. + FilterB: metadata.FilterFetched}) // Because we filtered on edc.IsNoTx=1, we also ensure that FirstAbsTxIDBlock and LastAbsTxIDBlock // remain constant in the DefineConstantConstraints function. // we do not need to also check the constancy of TotalNoTxBlock, as it is only used when IsNoTx=1 @@ -833,13 +831,12 @@ func ProjectionQueries(comp *wizard.CompiledIOP, edc.UnalignedLimb, } - projection.RegisterProjection(comp, + comp.InsertProjection( ifaces.QueryIDf("%s_TIMESTAMP_PROJECTION", name), - edcTimestamps, - timestampTable, - edc.IsTimestamp, // filter on IsTimestamp=1 - timestamps.FilterFetched, - ) + query.ProjectionInput{ColumnA: edcTimestamps, + ColumnB: timestampTable, + FilterA: edc.IsTimestamp, // filter on IsTimestamp=1 + FilterB: timestamps.FilterFetched}) // Prepare a projection query to the TxnData fetcher, to check the Hi part of the sender address. // compute the fetcher table, directly tied to the arithmetization. @@ -855,13 +852,12 @@ func ProjectionQueries(comp *wizard.CompiledIOP, edc.UnalignedLimb, } - projection.RegisterProjection(comp, + comp.InsertProjection( ifaces.QueryIDf("%s_SENDER_ADDRESS_HI_PROJECTION", name), - edcTxnSenderAddressTableHi, - txnDataTableHi, - edc.IsAddrHi, // filter on IsAddrHi=1 - txnData.FilterFetched, - ) + query.ProjectionInput{ColumnA: edcTxnSenderAddressTableHi, + ColumnB: txnDataTableHi, + FilterA: edc.IsAddrHi, // filter on IsAddrHi=1 + FilterB: txnData.FilterFetched}) // Prepare the projection query to the TxnData fetcher, to check the Lo part of the sender address. // compute the fetcher table, directly tied to the arithmetization. @@ -877,13 +873,12 @@ func ProjectionQueries(comp *wizard.CompiledIOP, edc.UnalignedLimb, } - projection.RegisterProjection(comp, + comp.InsertProjection( ifaces.QueryIDf("%s_SENDER_ADDRESS_LO_PROJECTION", name), - edcTxnSenderAddressTableLo, - txnDataTableLo, - edc.IsAddrLo, // filter on IsAddrLo=1 - txnData.FilterFetched, - ) + query.ProjectionInput{ColumnA: edcTxnSenderAddressTableLo, + ColumnB: txnDataTableLo, + FilterA: edc.IsAddrLo, // filter on IsAddrLo=1 + FilterB: txnData.FilterFetched}) // Prepare the projection query to the RlpTxn fetcher, to check: // AbsTxNum, AbsTxNumMax, Limb, NBytes and EndOfRlpSegment. @@ -906,13 +901,12 @@ func ProjectionQueries(comp *wizard.CompiledIOP, // EndOfRlpSegment is also constrained in DefineZeroizationConstraints, with respect to IsActive. } - projection.RegisterProjection(comp, + comp.InsertProjection( ifaces.QueryIDf("%s_RLP_LIMB_DATA_PROJECTION", name), - edcRlpDataTable, - rlpDataTable, - edc.IsTxRLP, // filter on IsTxRLP=1 - rlp.FilterFetched, - ) + query.ProjectionInput{ColumnA: edcRlpDataTable, + ColumnB: rlpDataTable, + FilterA: edc.IsTxRLP, // filter on IsTxRLP=1 + FilterB: rlp.FilterFetched}) } // LookupQueries computes lookup queries to the BlockTxnMetadata arithmetization fetcher: diff --git a/prover/zkevm/prover/publicInput/fetchers_arithmetization/block_txn_metadata_fetcher.go b/prover/zkevm/prover/publicInput/fetchers_arithmetization/block_txn_metadata_fetcher.go index 6680af39f..1db5a8d10 100644 --- a/prover/zkevm/prover/publicInput/fetchers_arithmetization/block_txn_metadata_fetcher.go +++ b/prover/zkevm/prover/publicInput/fetchers_arithmetization/block_txn_metadata_fetcher.go @@ -5,8 +5,8 @@ import ( "github.com/consensys/linea-monorepo/prover/maths/field" "github.com/consensys/linea-monorepo/prover/protocol/column" "github.com/consensys/linea-monorepo/prover/protocol/dedicated" - "github.com/consensys/linea-monorepo/prover/protocol/dedicated/projection" "github.com/consensys/linea-monorepo/prover/protocol/ifaces" + "github.com/consensys/linea-monorepo/prover/protocol/query" "github.com/consensys/linea-monorepo/prover/protocol/wizard" sym "github.com/consensys/linea-monorepo/prover/symbolic" arith "github.com/consensys/linea-monorepo/prover/zkevm/prover/publicInput/arith_struct" @@ -130,13 +130,12 @@ func DefineBlockTxnMetaData(comp *wizard.CompiledIOP, btm *BlockTxnMetadata, nam } // a projection query to check that the sender addresses are fetched correctly - projection.RegisterProjection(comp, + comp.InsertProjection( ifaces.QueryIDf("%s_PROJECTION", name), - fetcherTable, - arithTable, - btm.FilterFetched, - btm.FilterArith, - ) + query.ProjectionInput{ColumnA: fetcherTable, + ColumnB: arithTable, + FilterA: btm.FilterFetched, + FilterB: btm.FilterArith}) } func AssignBlockTxnMetadata(run *wizard.ProverRuntime, btm BlockTxnMetadata, td *arith.TxnData) { diff --git a/prover/zkevm/prover/publicInput/fetchers_arithmetization/rlp_txn_fetcher.go b/prover/zkevm/prover/publicInput/fetchers_arithmetization/rlp_txn_fetcher.go index 03fa2a345..7dfa14609 100644 --- a/prover/zkevm/prover/publicInput/fetchers_arithmetization/rlp_txn_fetcher.go +++ b/prover/zkevm/prover/publicInput/fetchers_arithmetization/rlp_txn_fetcher.go @@ -6,8 +6,8 @@ import ( "github.com/consensys/linea-monorepo/prover/protocol/accessors" "github.com/consensys/linea-monorepo/prover/protocol/column" "github.com/consensys/linea-monorepo/prover/protocol/dedicated" - "github.com/consensys/linea-monorepo/prover/protocol/dedicated/projection" "github.com/consensys/linea-monorepo/prover/protocol/ifaces" + "github.com/consensys/linea-monorepo/prover/protocol/query" "github.com/consensys/linea-monorepo/prover/protocol/wizard" sym "github.com/consensys/linea-monorepo/prover/symbolic" arith "github.com/consensys/linea-monorepo/prover/zkevm/prover/publicInput/arith_struct" @@ -148,13 +148,13 @@ func DefineRlpTxnFetcher(comp *wizard.CompiledIOP, fetcher *RlpTxnFetcher, name } // a projection query to check that the timestamp data is fetched correctly - projection.RegisterProjection(comp, + comp.InsertProjection( ifaces.QueryIDf("%s_RLP_TXN_PROJECTION", name), - fetcherTable, - arithTable, - fetcher.FilterFetched, - rlpTxnArith.ToHashByProver, // filter lights up on the arithmetization's RlpTxn rows that contain rlp transaction data - ) + query.ProjectionInput{ColumnA: fetcherTable, + ColumnB: arithTable, + FilterA: fetcher.FilterFetched, + // filter lights up on the arithmetization's RlpTxn rows that contain rlp transaction data + FilterB: rlpTxnArith.ToHashByProver}) } func AssignRlpTxnFetcher(run *wizard.ProverRuntime, fetcher *RlpTxnFetcher, rlpTxnArith *arith.RlpTxn) { diff --git a/prover/zkevm/prover/publicInput/fetchers_arithmetization/timestamp_fetcher.go b/prover/zkevm/prover/publicInput/fetchers_arithmetization/timestamp_fetcher.go index 83c746d97..195fd3546 100644 --- a/prover/zkevm/prover/publicInput/fetchers_arithmetization/timestamp_fetcher.go +++ b/prover/zkevm/prover/publicInput/fetchers_arithmetization/timestamp_fetcher.go @@ -6,8 +6,8 @@ import ( "github.com/consensys/linea-monorepo/prover/protocol/accessors" "github.com/consensys/linea-monorepo/prover/protocol/column" "github.com/consensys/linea-monorepo/prover/protocol/dedicated" - "github.com/consensys/linea-monorepo/prover/protocol/dedicated/projection" "github.com/consensys/linea-monorepo/prover/protocol/ifaces" + "github.com/consensys/linea-monorepo/prover/protocol/query" "github.com/consensys/linea-monorepo/prover/protocol/wizard" sym "github.com/consensys/linea-monorepo/prover/symbolic" arith "github.com/consensys/linea-monorepo/prover/zkevm/prover/publicInput/arith_struct" @@ -182,13 +182,13 @@ func DefineTimestampFetcher(comp *wizard.CompiledIOP, fetcher *TimestampFetcher, } // a projection query to check that the timestamp data is fetched correctly - projection.RegisterProjection(comp, + comp.InsertProjection( ifaces.QueryIDf("%s_TIMESTAMP_PROJECTION", name), - fetcherTable, - arithTable, - fetcher.FilterFetched, - fetcher.SelectorTimestamp, // filter lights up on the arithmetization's BlockDataCols rows that contain timestamp data - ) + query.ProjectionInput{ColumnA: fetcherTable, + ColumnB: arithTable, + FilterA: fetcher.FilterFetched, + // filter lights up on the arithmetization's BlockDataCols rows that contain timestamp data + FilterB: fetcher.SelectorTimestamp}) // constrain the First/Last Block ID counters ConstrainFirstAndLastBlockID(comp, fetcher, name, bdc) diff --git a/prover/zkevm/prover/publicInput/fetchers_arithmetization/txn_data_fetcher.go b/prover/zkevm/prover/publicInput/fetchers_arithmetization/txn_data_fetcher.go index 86c193ee3..825a43ac6 100644 --- a/prover/zkevm/prover/publicInput/fetchers_arithmetization/txn_data_fetcher.go +++ b/prover/zkevm/prover/publicInput/fetchers_arithmetization/txn_data_fetcher.go @@ -5,8 +5,8 @@ import ( "github.com/consensys/linea-monorepo/prover/maths/field" "github.com/consensys/linea-monorepo/prover/protocol/column" "github.com/consensys/linea-monorepo/prover/protocol/dedicated" - "github.com/consensys/linea-monorepo/prover/protocol/dedicated/projection" "github.com/consensys/linea-monorepo/prover/protocol/ifaces" + "github.com/consensys/linea-monorepo/prover/protocol/query" "github.com/consensys/linea-monorepo/prover/protocol/wizard" sym "github.com/consensys/linea-monorepo/prover/symbolic" arith "github.com/consensys/linea-monorepo/prover/zkevm/prover/publicInput/arith_struct" @@ -81,13 +81,13 @@ func DefineTxnDataFetcher(comp *wizard.CompiledIOP, fetcher *TxnDataFetcher, nam } // a projection query to check that the sender addresses are fetched correctly - projection.RegisterProjection(comp, + comp.InsertProjection( ifaces.QueryIDf("%s_TXN_DATA_FETCHER_PROJECTION", name), - fetcherTable, - arithTable, - fetcher.FilterFetched, - fetcher.SelectorFromAddress, // filter lights up on the arithmetization's TxnData rows that contain sender address data - ) + query.ProjectionInput{ColumnA: fetcherTable, + ColumnB: arithTable, + FilterA: fetcher.FilterFetched, + // filter lights up on the arithmetization's TxnData rows that contain sender address data + FilterB: fetcher.SelectorFromAddress}) } // AssignTxnDataFetcher assigns the data in the TxnDataFetcher using data fetched from the TxnData diff --git a/prover/zkevm/prover/publicInput/logs/extracted_data.go b/prover/zkevm/prover/publicInput/logs/extracted_data.go index 756f6d663..1e86056a0 100644 --- a/prover/zkevm/prover/publicInput/logs/extracted_data.go +++ b/prover/zkevm/prover/publicInput/logs/extracted_data.go @@ -4,8 +4,8 @@ import ( "github.com/consensys/linea-monorepo/prover/maths/common/smartvectors" "github.com/consensys/linea-monorepo/prover/maths/field" "github.com/consensys/linea-monorepo/prover/protocol/column" - "github.com/consensys/linea-monorepo/prover/protocol/dedicated/projection" "github.com/consensys/linea-monorepo/prover/protocol/ifaces" + "github.com/consensys/linea-monorepo/prover/protocol/query" "github.com/consensys/linea-monorepo/prover/protocol/wizard" sym "github.com/consensys/linea-monorepo/prover/symbolic" util "github.com/consensys/linea-monorepo/prover/zkevm/prover/publicInput/utilities" @@ -92,7 +92,12 @@ func DefineExtractedData(comp *wizard.CompiledIOP, logCols LogColumns, sel Selec ), ) // a projection query to check that the messages are fetched correctly - projection.RegisterProjection(comp, ifaces.QueryIDf("%s_LOGS_PROJECTION", GetName(logType)), fetchedTable, logsTable, fetched.filterFetched, fetched.filterArith) + comp.InsertProjection( + ifaces.QueryIDf("%s_LOGS_PROJECTION", GetName(logType)), + query.ProjectionInput{ColumnA: fetchedTable, + ColumnB: logsTable, + FilterA: fetched.filterFetched, + FilterB: fetched.filterArith}) } // CheckBridgeAddress checks if a row does indeed contain the data corresponding to a the bridge address diff --git a/prover/zkevm/prover/statemanager/mimccodehash/input_consistency.go b/prover/zkevm/prover/statemanager/mimccodehash/input_consistency.go index b8c0377d5..b42153b87 100644 --- a/prover/zkevm/prover/statemanager/mimccodehash/input_consistency.go +++ b/prover/zkevm/prover/statemanager/mimccodehash/input_consistency.go @@ -1,8 +1,8 @@ package mimccodehash import ( - "github.com/consensys/linea-monorepo/prover/protocol/dedicated/projection" "github.com/consensys/linea-monorepo/prover/protocol/ifaces" + "github.com/consensys/linea-monorepo/prover/protocol/query" "github.com/consensys/linea-monorepo/prover/protocol/wizard" ) @@ -27,12 +27,12 @@ func (mch *Module) ConnectToRom(comp *wizard.CompiledIOP, romInput.complete(comp) // Projection query between romInput and MiMCCodeHash module - projection.RegisterProjection(comp, ifaces.QueryIDf("PROJECTION_ROM_MIMC_CODE_HASH_%v", mch.inputs.Name), - []ifaces.Column{romInput.CFI, romInput.Acc, romInput.CodeSize}, - []ifaces.Column{mch.CFI, mch.Limb, mch.CodeSize}, - romInput.CounterIsEqualToNBytesMinusOne, - mch.IsActive, - ) + comp.InsertProjection( + ifaces.QueryIDf("PROJECTION_ROM_MIMC_CODE_HASH_%v", mch.inputs.Name), + query.ProjectionInput{ColumnA: []ifaces.Column{romInput.CFI, romInput.Acc, romInput.CodeSize}, + ColumnB: []ifaces.Column{mch.CFI, mch.Limb, mch.CodeSize}, + FilterA: romInput.CounterIsEqualToNBytesMinusOne, + FilterB: mch.IsActive}) // Lookup between romLexInput and mch for // {CFI, codeHashHi, codeHashLo} From ebd64c3625ce1b35f79d3e380665e21f45b8a211 Mon Sep 17 00:00:00 2001 From: arijitdutta67 Date: Sat, 25 Jan 2025 10:16:26 +0530 Subject: [PATCH 13/13] fix in lpp --- prover/protocol/distributed/lpp/lpp.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/prover/protocol/distributed/lpp/lpp.go b/prover/protocol/distributed/lpp/lpp.go index ed9fbf142..55ebf510c 100644 --- a/prover/protocol/distributed/lpp/lpp.go +++ b/prover/protocol/distributed/lpp/lpp.go @@ -148,9 +148,9 @@ func getLPPColumns(c *wizard.CompiledIOP) []ifaces.Column { lppColumns = append(lppColumns, v.B[i]...) } case query.Projection: - lppColumns = append(lppColumns, v.ColumnsA...) - lppColumns = append(lppColumns, v.ColumnsB...) - lppColumns = append(lppColumns, v.FilterA, v.FilterB) + lppColumns = append(lppColumns, v.Inp.ColumnA...) + lppColumns = append(lppColumns, v.Inp.ColumnB...) + lppColumns = append(lppColumns, v.Inp.FilterA, v.Inp.FilterB) default: //do noting