Skip to content

Commit

Permalink
Merge pull request #186 from Consensys/183-used-column-index-instead-…
Browse files Browse the repository at this point in the history
…of-column-name

Feat: Use Column Index instead of Column Name
  • Loading branch information
DavePearce authored Jun 25, 2024
2 parents 721e3bc + cd957c2 commit 1ded643
Show file tree
Hide file tree
Showing 22 changed files with 356 additions and 166 deletions.
2 changes: 1 addition & 1 deletion pkg/air/gadgets/bits.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func ApplyBitwidthGadget(col uint, nbits uint, schema *air.Schema) {
name := schema.Columns().Nth(col).Name()
coefficient := fr.NewElement(1)
// Add decomposition assignment
index := schema.AddAssignment(assignment.NewByteDecomposition(name, n))
index := schema.AddAssignment(assignment.NewByteDecomposition(name, col, n))
// Construct Columns
for i := uint(0); i < n; i++ {
// Create Column + Constraint
Expand Down
31 changes: 25 additions & 6 deletions pkg/binfile/computation.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package binfile

import (
"fmt"

"github.com/consensys/go-corset/pkg/hir"
sc "github.com/consensys/go-corset/pkg/schema"
)
Expand All @@ -26,14 +28,31 @@ type jsonSortedComputation struct {
func (e jsonComputationSet) addToSchema(schema *hir.Schema) {
for _, c := range e.Computations {
if c.Sorted != nil {
refs := asColumnRefs(c.Sorted.Tos)
sources := asColumnRefs(c.Sorted.Froms)
targetRefs := asColumnRefs(c.Sorted.Tos)
sourceRefs := asColumnRefs(c.Sorted.Froms)
// Sanity check assumptions
if len(sourceRefs) != len(targetRefs) {
panic("differing number of source / target columns in sorted permutation")
}
// Convert source refs into column indexes
sources := make([]uint, len(sourceRefs))
// Convert target refs into columns
targets := make([]sc.Column, len(refs))
targets := make([]sc.Column, len(targetRefs))
//
for i, r := range targetRefs {
cid, ok := sc.ColumnIndexOf(schema, sourceRefs[i])
// Sanity check source column exists
if !ok {
panic(fmt.Sprintf("unknown column %s", sourceRefs[i]))
}
// Determine type of source column
ith := schema.Columns().Nth(cid).Type()
// Sanity check we have a sensible type here.
if ith.AsUint() == nil {
panic(fmt.Sprintf("source column %s has field type", sourceRefs[i]))
}

for i, r := range refs {
// TODO: correctly determine type
ith := &sc.FieldType{}
sources[i] = cid
targets[i] = sc.NewColumn(r, ith)
}
// Finally, add the permutation column
Expand Down
2 changes: 1 addition & 1 deletion pkg/binfile/constraint.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func (e jsonConstraint) addToSchema(schema *hir.Schema) {
// "Sorted" computations.
if e.Vanishes != nil {
// Translate the vanishing expression
expr := e.Vanishes.Expr.ToHir()
expr := e.Vanishes.Expr.ToHir(schema)
// Translate Domain
domain := e.Vanishes.Domain.toHir()
// Construct the vanishing constraint
Expand Down
8 changes: 7 additions & 1 deletion pkg/binfile/constraint_set.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"

"github.com/consensys/go-corset/pkg/hir"
sc "github.com/consensys/go-corset/pkg/schema"
)

// This is very much a Work-In-Progress :)
Expand Down Expand Up @@ -110,7 +111,12 @@ func HirSchemaFromJson(bytes []byte) (schema *hir.Schema, err error) {
schema.AddDataColumn(c.Handle, t)
// Check whether a type constraint required or not.
if c.MustProve {
schema.AddTypeConstraint(c.Handle, t)
cid, ok := sc.ColumnIndexOf(schema, c.Handle)
if !ok {
panic(fmt.Sprintf("unknown column %s", c.Handle))
}

schema.AddTypeConstraint(cid, t)
}
}
}
Expand Down
31 changes: 19 additions & 12 deletions pkg/binfile/expr.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

"github.com/consensys/gnark-crypto/ecc/bls12-377/fr"
"github.com/consensys/go-corset/pkg/hir"
sc "github.com/consensys/go-corset/pkg/schema"
)

// type jsonHandle struct {
Expand Down Expand Up @@ -59,24 +60,24 @@ type jsonExprColumn struct {
// should not generate an error provided the original JSON was
// well-formed.

func (e *jsonTypedExpr) ToHir() hir.Expr {
func (e *jsonTypedExpr) ToHir(schema *hir.Schema) hir.Expr {
if e.Expr.Column != nil {
return e.Expr.Column.ToHir()
return e.Expr.Column.ToHir(schema)
} else if e.Expr.Const != nil {
return e.Expr.Const.ToHir()
return e.Expr.Const.ToHir(schema)
} else if e.Expr.Funcall != nil {
return e.Expr.Funcall.ToHir()
return e.Expr.Funcall.ToHir(schema)
} else if e.Expr.List != nil {
// Parse the arguments
return jsonListToHir(e.Expr.List)
return jsonListToHir(e.Expr.List, schema)
}

panic("Unknown JSON expression encountered")
}

// ToHir converts a big integer represented as a sequence of unsigned 32bit
// words into HIR constant expression.
func (e *jsonExprConst) ToHir() hir.Expr {
func (e *jsonExprConst) ToHir(schema *hir.Schema) hir.Expr {
sign := int(e.BigInt[0].(float64))
words := e.BigInt[1].([]any)
// Begin
Expand Down Expand Up @@ -109,16 +110,22 @@ func (e *jsonExprConst) ToHir() hir.Expr {
return &hir.Constant{Val: num}
}

func (e *jsonExprColumn) ToHir() hir.Expr {
func (e *jsonExprColumn) ToHir(schema *hir.Schema) hir.Expr {
cref := asColumnRef(e.Handle)
return &hir.ColumnAccess{Column: cref, Shift: e.Shift}
cid, ok := sc.ColumnIndexOf(schema, cref)

if !ok {
panic(fmt.Sprintf("unknown column %s", cref))
}

return &hir.ColumnAccess{Column: cid, Shift: e.Shift}
}

func (e *jsonExprFuncall) ToHir() hir.Expr {
func (e *jsonExprFuncall) ToHir(schema *hir.Schema) hir.Expr {
// Parse the arguments
args := make([]hir.Expr, len(e.Args))
for i := 0; i < len(e.Args); i++ {
args[i] = e.Args[i].ToHir()
args[i] = e.Args[i].ToHir(schema)
}
// Construct appropriate expression
switch e.Func {
Expand Down Expand Up @@ -155,10 +162,10 @@ func (e *jsonExprFuncall) ToHir() hir.Expr {
panic(fmt.Sprintf("HANDLE %s\n", e.Func))
}

func jsonListToHir(Args []jsonTypedExpr) hir.Expr {
func jsonListToHir(Args []jsonTypedExpr, schema *hir.Schema) hir.Expr {
args := make([]hir.Expr, len(Args))
for i := 0; i < len(Args); i++ {
args[i] = Args[i].ToHir()
args[i] = Args[i].ToHir(schema)
}

return &hir.List{Args: args}
Expand Down
9 changes: 4 additions & 5 deletions pkg/cmd/debug.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ var debugCmd = &cobra.Command{
fmt.Println(cmd.UsageString())
os.Exit(1)
}
stats := getFlag(cmd, "stats")
hir := getFlag(cmd, "hir")
mir := getFlag(cmd, "mir")
air := getFlag(cmd, "air")
Expand All @@ -29,19 +28,19 @@ var debugCmd = &cobra.Command{
airSchema := mirSchema.LowerToAir()
// Print constraints
if hir {
printSchema(hirSchema, stats)
printSchema(hirSchema)
}
if mir {
printSchema(mirSchema, stats)
printSchema(mirSchema)
}
if air {
printSchema(airSchema, stats)
printSchema(airSchema)
}
},
}

// Print out all declarations included in a given
func printSchema(schema schema.Schema, stats bool) {
func printSchema(schema schema.Schema) {
panic("todo")
}

Expand Down
89 changes: 89 additions & 0 deletions pkg/hir/environment.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package hir

import "fmt"

// ===================================================================
// Environment
// ===================================================================

// Identifies a specific column within the environment.
type columnRef struct {
module uint
column string
}

// Environment maps module and column names to their (respective) module and
// column indices. The environment also keeps trace of which modules / columns
// are declared so we can sanity check them when they are referred to (e.g. in a
// constraint).
type Environment struct {
// Maps module names to their module indices.
modules map[string]uint
// Maps column references to their column indices.
columns map[columnRef]uint
}

// EmptyEnvironment constructs an empty environment.
func EmptyEnvironment() *Environment {
modules := make(map[string]uint)
columns := make(map[columnRef]uint)

return &Environment{modules, columns}
}

// RegisterModule registers a new module within this environment. Observe that
// this will panic if the module already exists.
func (p *Environment) RegisterModule(module string) uint {
if p.HasModule(module) {
panic(fmt.Sprintf("module %s already exists", module))
}

mid := uint(len(p.modules))
p.modules[module] = mid

return mid
}

// RegisterColumn registesr a new column within a given module. Observe that
// this will panic if the column already exists.
func (p *Environment) RegisterColumn(module uint, column string) uint {
if p.HasColumn(module, column) {
panic(fmt.Sprintf("column %d:%s already exists", module, column))
}

cid := uint(len(p.columns))
cref := columnRef{module, column}
p.columns[cref] = cid

return cid
}

// LookupModule determines the module index for a given named module, or return
// false if no such module exists.
func (p *Environment) LookupModule(module string) (uint, bool) {
mid, ok := p.modules[module]
return mid, ok
}

// LookupColumn determines the column index for a given named column in a given
// module, or return false if no such column exists.
func (p *Environment) LookupColumn(module uint, column string) (uint, bool) {
cref := columnRef{module, column}
cid, ok := p.columns[cref]

return cid, ok
}

// HasModule checks whether a given module exists, or not.
func (p *Environment) HasModule(module string) bool {
_, ok := p.LookupModule(module)
// Discard column index
return ok
}

// HasColumn checks whether a given module has a given column, or not.
func (p *Environment) HasColumn(module uint, column string) bool {
_, ok := p.LookupColumn(module, column)
// Discard column index
return ok
}
2 changes: 1 addition & 1 deletion pkg/hir/eval.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
// value at that row of the column in question or nil is that row is
// out-of-bounds.
func (e *ColumnAccess) EvalAllAt(k int, tr trace.Trace) []*fr.Element {
val := tr.ColumnByName(e.Column).Get(k + e.Shift)
val := tr.ColumnByIndex(e.Column).Get(k + e.Shift)

var clone fr.Element
// Clone original value
Expand Down
2 changes: 1 addition & 1 deletion pkg/hir/expr.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ func (p *Normalise) Bounds() util.Bounds {
// accesses the STAMP column at row 5, whilst CT(-1) accesses the CT column at
// row 4.
type ColumnAccess struct {
Column string
Column uint
Shift int
}

Expand Down
13 changes: 4 additions & 9 deletions pkg/hir/lower.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ func (p *Schema) LowerToMir() *mir.Schema {
// Second, lower permutations
for _, asn := range p.assignments {
col := asn.(Permutation)
mirSchema.AddPermutationColumns(col.Targets(), col.Signs, col.Sources)
mirSchema.AddPermutationColumns(col.Targets(), col.Signs(), col.Sources())
}
// Third, lower constraints
for _, c := range p.constraints {
Expand All @@ -43,10 +43,10 @@ func (p *Schema) LowerToMir() *mir.Schema {
func lowerConstraintToMir(c sc.Constraint, schema *mir.Schema) {
// Check what kind of constraint we have
if v, ok := c.(VanishingConstraint); ok {
mir_exprs := v.Constraint.Expr.LowerTo(schema)
mir_exprs := v.Constraint().Expr.LowerTo(schema)
// Add individual constraints arising
for _, mir_expr := range mir_exprs {
schema.AddVanishingConstraint(v.Handle, v.Domain, mir_expr)
schema.AddVanishingConstraint(v.Handle(), v.Domain(), mir_expr)
}
} else if v, ok := c.(*constraint.TypeConstraint); ok {
schema.AddTypeConstraint(v.Target(), v.Type())
Expand Down Expand Up @@ -213,12 +213,7 @@ func lowerBody(e Expr, schema *mir.Schema) mir.Expr {
} else if p, ok := e.(*Constant); ok {
return &mir.Constant{Value: p.Val}
} else if p, ok := e.(*ColumnAccess); ok {
if index, ok := sc.ColumnIndexOf(schema, p.Column); ok {
return &mir.ColumnAccess{Column: index, Shift: p.Shift}
}
// Should be unreachable as all columns should have been vetted earlier
// in the pipeline.
panic(fmt.Sprintf("invalid column access for %s", p.Column))
return &mir.ColumnAccess{Column: p.Column, Shift: p.Shift}
} else if p, ok := e.(*Mul); ok {
return &mir.Mul{Args: lowerBodies(p.Args, schema)}
} else if p, ok := e.(*Normalise); ok {
Expand Down
Loading

0 comments on commit 1ded643

Please sign in to comment.