Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prover/Adding Initial Compiler for Permutation Query #386

Merged
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions prover/protocol/compiler/permutation/compiler.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,11 @@ func dispatchPermutation(
var (
isMultiColumn = len(q.A[0]) > 1
alpha coin.Info
beta = comp.InsertCoin(round+1, deriveName[coin.Name](q, "BETA"), coin.Field)
beta = comp.InsertCoin(round+1, DeriveName[coin.Name](q, "BETA"), coin.Field)
)

if isMultiColumn {
alpha = comp.InsertCoin(round+1, deriveName[coin.Name](q, "ALPHA"), coin.Field)
alpha = comp.InsertCoin(round+1, DeriveName[coin.Name](q, "ALPHA"), coin.Field)
}

for k, aOrB := range [2][][]ifaces.Column{q.A, q.B} {
Expand Down
4 changes: 2 additions & 2 deletions prover/protocol/compiler/permutation/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import (

const permutationStr = "PERMUTATION"

// deriveName constructs a name for the permutation context
func deriveName[R ~string](q query.Permutation, ss ...any) R {
// DeriveName constructs a name for the permutation context
func DeriveName[R ~string](q query.Permutation, ss ...any) R {
ss = append([]any{permutationStr, q}, ss...)
return wizardutils.DeriveName[R](ss...)
}
Expand Down
7 changes: 7 additions & 0 deletions prover/protocol/distributed/compiler/global/global.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package global

import "github.com/consensys/linea-monorepo/prover/protocol/wizard"

func IntoDistributedGlobal(comp *wizard.CompiledIOP) {
panic("unimplemented")
}
7 changes: 7 additions & 0 deletions prover/protocol/distributed/compiler/inclusion/inclusion.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package inclusion

import "github.com/consensys/linea-monorepo/prover/protocol/wizard"

func IntoLogDerivativeSum(comp *wizard.CompiledIOP) {
panic("unimplemented")
}
7 changes: 7 additions & 0 deletions prover/protocol/distributed/compiler/local/local.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package local

import "github.com/consensys/linea-monorepo/prover/protocol/wizard"

func IntoDistributedLocal(comp *wizard.CompiledIOP) {
panic("unimplemented")
}
130 changes: 130 additions & 0 deletions prover/protocol/distributed/compiler/permutation/permutation.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
package permutation

import (
"github.com/consensys/linea-monorepo/prover/protocol/coin"
"github.com/consensys/linea-monorepo/prover/protocol/compiler/permutation"
"github.com/consensys/linea-monorepo/prover/protocol/distributed"
modulediscoverer "github.com/consensys/linea-monorepo/prover/protocol/distributed/module_discoverer"
"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"
"github.com/consensys/linea-monorepo/prover/symbolic"
)

/*
The below function does the following:
1. For a given target module name, it finds all the relevant permutation query and combine them into a big grand product query
2. (ToDo) It adds relevant constraints
*/
type PermutationIntoGrandProductCtx struct {
numerator *symbolic.Expression // aimed at storing the expressions Ai + \beta_i
arijitdutta67 marked this conversation as resolved.
Show resolved Hide resolved
denominator *symbolic.Expression // aimed at storing the expressions Bi + \beta_i
}

// Return a new PermutationIntoGrandProductCtx with numerator and denominator set as symobilc constant 1
func newPermutationIntoGrandProductCtx() *PermutationIntoGrandProductCtx {
permCtx := PermutationIntoGrandProductCtx{}
permCtx.numerator = symbolic.NewConstant(1)
permCtx.denominator = symbolic.NewConstant(1)
return &permCtx
}

func AddGdProductQuery(initialComp, moduleComp *wizard.CompiledIOP,
targetModuleName distributed.ModuleName) {
numRounds := initialComp.NumRounds()
permCtx := newPermutationIntoGrandProductCtx()
/*
Handles the lookups and permutations checks
*/
for i := 0; i < numRounds; i++ {
queries := initialComp.QueriesNoParams.AllKeysAt(i)
for j, qName := range queries {
// Skip if it was already compiled
if initialComp.QueriesNoParams.IsIgnored(qName) {
continue
}

switch q_ := initialComp.QueriesNoParams.Data(qName).(type) {
case query.Permutation:
{
colNameA := modulediscoverer.ModuleDiscoverer(q_.A[0][0])
colNameB := modulediscoverer.ModuleDiscoverer(q_.B[0][0])
if colNameA == targetModuleName && colNameB != targetModuleName {
permCtx.push(moduleComp, &q_, i, j, true, false)
} else if colNameA != targetModuleName && colNameB == targetModuleName {
permCtx.push(moduleComp, &q_, i, j, false, false)
} else if colNameA == targetModuleName && colNameB == targetModuleName {
permCtx.push(moduleComp, &q_, i, j, true, true)
} else {
continue
}
}
default:
continue
}
}
}
// Reduce a permutation query into a GrandProduct query
moduleComp.InsertGrandProduct(0, ifaces.QueryIDf(targetModuleName), permCtx.numerator, permCtx.denominator)
}

// The below function does the following:
// 1. Register beta and alpha (for the random linear combination in case A and B are multi-columns)
// 2. Tell the prover that they are not needed to be sampled as they are to be fetched from the randomness beacon
func (p *PermutationIntoGrandProductCtx) push(comp *wizard.CompiledIOP, q *query.Permutation, round, queryInRound int, isNumerator, isBoth bool) {
/*
Sanity checks : Mark the query as compiled and make sure that
it was not previously compiled.
*/
if comp.QueriesNoParams.MarkAsIgnored(q.ID) {
panic("did not expect that a query no param could be ignored at this stage")
}
var (
isMultiColumn = len(q.A[0]) > 1
alpha coin.Info
// beta has to be different for different queries for a perticular round for the soundness of z-packing
beta = comp.InsertCoin(round+1, permutation.DeriveName[coin.Name](*q, "BETA_%v", queryInRound), coin.Field)
)

if isMultiColumn {
// alpha has to be different for different queries for a perticular round for the soundness of z-packing
alpha = comp.InsertCoin(round+1, permutation.DeriveName[coin.Name](*q, "ALPHA_%v", queryInRound), coin.Field)

}
if isNumerator && !isBoth {
// Take only the numerator
factor := computeFactor(q.A, isMultiColumn, alpha, beta)
p.numerator = symbolic.Mul(p.numerator, factor)
} else if !isNumerator && !isBoth {
// Take only the denominator
factor := computeFactor(q.B, isMultiColumn, alpha, beta)
p.denominator = symbolic.Mul(p.denominator, factor)
} else if isNumerator && isBoth {
// Take both the numerator and the denominator
numFactor := computeFactor(q.A, isMultiColumn, alpha, beta)
denFactor := computeFactor(q.B, isMultiColumn, alpha, beta)
p.numerator = symbolic.Mul(p.numerator, numFactor)
p.denominator = symbolic.Mul(p.denominator, denFactor)
} else if !isNumerator && isBoth {
panic("Invalid case")
}

}

func computeFactor(aOrB [][]ifaces.Column, isMultiColumn bool, alpha, beta coin.Info) *symbolic.Expression {
var (
numFrag = len(aOrB)
factor = symbolic.NewConstant(1)
)

for frag := range numFrag {
fragFactor := symbolic.NewVariable(aOrB[frag][0])
if isMultiColumn {
fragFactor = wizardutils.RandLinCombColSymbolic(alpha, aOrB[frag])
}
fragFactor = symbolic.Add(fragFactor, beta)
factor = symbolic.Mul(factor, fragFactor)
}
return factor
}
7 changes: 7 additions & 0 deletions prover/protocol/distributed/compiler/projection/projection.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package projection

import "github.com/consensys/linea-monorepo/prover/protocol/wizard"

func IntoGrandSum(comp *wizard.CompiledIOP) {
panic("unimplemented")
}
72 changes: 72 additions & 0 deletions prover/protocol/distributed/distributed.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package distributed

import (
"github.com/consensys/linea-monorepo/prover/maths/field"
"github.com/consensys/linea-monorepo/prover/protocol/ifaces"
"github.com/consensys/linea-monorepo/prover/protocol/wizard"
)

type ModuleName = string

type DistributedWizard struct {
Bootstrapper *wizard.CompiledIOP
DistributedModules []DistributedModule
Aggregator *wizard.CompiledIOP
}

// DistributedModule implements the utilities relevant to a single segment.
type DistributedModule struct {
LookupPermProj *wizard.CompiledIOP
GlobalLocal *wizard.CompiledIOP
VK [2]field.Element
}

type ModuleDiscoverer interface {
// Analyze is responsible for letting the module discoverer compute how to
// group best the columns into modules.
Analyze(comp *wizard.CompiledIOP)
NbModules() int
ModuleList(comp *wizard.CompiledIOP) []ModuleName
FindModule(col ifaces.Column) ModuleName
}

// This transforms the initial wizard. So it is not really the initial
// wizard anymore. That means the caller can forget about "initialWizard"
// after calling the function.
// maxNbSegment is a large max for the number of segments in a module.
func Distribute(initialWizard *wizard.CompiledIOP, disc ModuleDiscoverer, maxNbSegments int) DistributedWizard {
// it updates the map of Modules-Columns (that is a field of initialWizard).
disc.Analyze(initialWizard)

moduleLs := disc.ModuleList(initialWizard)
distModules := []DistributedModule{}

for _, modName := range moduleLs {
// Segment Compilation;
// Compile every dist module with the same sequence of compilation steps for uniformity
distMod := extractDistModule(initialWizard, disc, modName)
distModules = append(distModules, distMod)
}

// for each [DistributedModule] it checks the consistency among
// its replications where the number of replications is maxNbSegments.
aggr := aggregator(maxNbSegments, distModules, moduleLs)

return DistributedWizard{
Bootstrapper: initialWizard,
DistributedModules: distModules,
Aggregator: aggr,
}
}

func addSplittingStep(comp *wizard.CompiledIOP, disc ModuleDiscoverer) {
panic("unimplemented")
}

func extractDistModule(comp *wizard.CompiledIOP, disc ModuleDiscoverer, moduleName ModuleName) DistributedModule {
panic("unimplemented")
}

func aggregator(n int, idsModules []DistributedModule, moduleNames []string) *wizard.CompiledIOP {
panic("unimplemented")
}
12 changes: 12 additions & 0 deletions prover/protocol/distributed/module_discoverer/module_discoverer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package modulediscoverer

import (
"github.com/consensys/linea-monorepo/prover/protocol/distributed"
"github.com/consensys/linea-monorepo/prover/protocol/ifaces"
)

// This function extract the module name of a given column by
// seperating the string that appear before the first period
func ModuleDiscoverer(col ifaces.Column) distributed.ModuleName {
arijitdutta67 marked this conversation as resolved.
Show resolved Hide resolved
panic("unimplemented")
}
39 changes: 39 additions & 0 deletions prover/protocol/query/grand_product.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package query

import (
"github.com/consensys/gnark/frontend"
"github.com/consensys/linea-monorepo/prover/protocol/ifaces"
"github.com/consensys/linea-monorepo/prover/symbolic"
"github.com/consensys/linea-monorepo/prover/utils"
)

// The GrandProduct query enables splitting of the Permutation query between sub-provers
// by splitting the grand product Z = \prod(A_i+\beta)/(B_i+\beta) itself.
type GrandProduct struct {
arijitdutta67 marked this conversation as resolved.
Show resolved Hide resolved
ID ifaces.QueryID
Numerator *symbolic.Expression // stores A as multi-column
Denominator *symbolic.Expression // stores B as multi-column
Round int
}

func NewGrandProduct(round int, id ifaces.QueryID, numerator, denominator *symbolic.Expression) GrandProduct {
return GrandProduct{
ID: id,
Numerator: numerator,
Denominator: denominator,
Round: round,
}
}

func (g GrandProduct) Name() ifaces.QueryID {
return g.ID
}

func (g GrandProduct) Check(run ifaces.Runtime) error {
utils.Panic("Unimplemented")
return nil
}

func (g GrandProduct) CheckGnark(api frontend.API, run ifaces.GnarkRuntime) {
utils.Panic("Unimplemented")
}
9 changes: 9 additions & 0 deletions prover/protocol/wizard/compiled.go
Original file line number Diff line number Diff line change
Expand Up @@ -629,3 +629,12 @@ func (c *CompiledIOP) RegisterVerifierAction(round int, action VerifierAction) {
// switch.
c.InsertVerifier(round, action.Run, action.RunGnark)
}

// Register a GrandProduct query
func (c *CompiledIOP) InsertGrandProduct(round int, id ifaces.QueryID, numerator, denominator *symbolic.Expression) query.GrandProduct {
c.assertConsistentRound(round)
q := query.NewGrandProduct(round, id, numerator, denominator)
// Finally registers the query
c.QueriesParams.AddToRound(round, q.Name(), q)
return q
}