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/full recursion #350

Open
wants to merge 27 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
45baca1
(feat): Implements the full-recursion and test for a simple test
AlexandreBelling Oct 23, 2024
ac1408c
debug the full-recursion
AlexandreBelling Oct 24, 2024
51bfc31
add a benchmarking tool
AlexandreBelling Oct 24, 2024
f87efb9
msg(sticker): better error in the sticker
AlexandreBelling Nov 20, 2024
3347f76
test(full-recursion): adds a test for double full-recursion (overflow…
AlexandreBelling Nov 20, 2024
eee7af9
fix: sort out the packages after rebasing
AlexandreBelling Dec 3, 2024
ac44e9b
Merge branch 'main' of github.com:Consensys/linea-monorepo into prove…
AlexandreBelling Dec 18, 2024
94f60e9
fix(pi): renaming of the public inputs
AlexandreBelling Dec 18, 2024
486f9e3
fix(hasher): adjust the code to using a [hash.StateStorer]
AlexandreBelling Dec 18, 2024
c95f338
fix(pairing): pass the new format for fp12 elements
AlexandreBelling Dec 18, 2024
b3baf4b
Merge branch 'main' of github.com:Consensys/linea-monorepo into prove…
AlexandreBelling Dec 18, 2024
0eb24e8
doc(plonk): adds more doc in plonk.alignment.go
AlexandreBelling Dec 18, 2024
14edc4c
doc(fs-hook): improves the documentation of the FiatShamirHook field.
AlexandreBelling Dec 18, 2024
5ecabb0
docs(skipping): adds doc on the ByRoundRegister
AlexandreBelling Dec 18, 2024
3c9e7b0
feat(pubinp): move the zkevm public inputs to using the new public-in…
AlexandreBelling Dec 18, 2024
49badaa
fixup
AlexandreBelling Dec 18, 2024
318d5eb
doc(column-store): adds documentation for the more precise methods re…
AlexandreBelling Dec 18, 2024
1b18118
stop keeping the middle fs history
AlexandreBelling Dec 19, 2024
094fc0a
debug the full-recursion
AlexandreBelling Oct 24, 2024
3f9cf9a
fix the full recursion compiler
AlexandreBelling Nov 27, 2024
0d2982a
fix: remove the replace statement in the go mod
AlexandreBelling Dec 19, 2024
1001f87
doc(fix): fix the doc of the public input
AlexandreBelling Dec 20, 2024
afd5fc2
clean(self-recursion): remove the self-recursion tuning file
AlexandreBelling Dec 20, 2024
8b928f0
doc(vortex): explain the separation between the verifier steps
AlexandreBelling Dec 20, 2024
29a64c5
doc(full-recursion): documents the prover and verifier actions
AlexandreBelling Dec 20, 2024
87e1de4
doc(columns): improve the documentation on the IncludeInProverFS
AlexandreBelling Dec 20, 2024
e63a62e
Merge branch 'main' of github.com:Consensys/linea-monorepo into prove…
AlexandreBelling Dec 20, 2024
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
17 changes: 17 additions & 0 deletions prover/crypto/fiatshamir/fiatshamir.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"hash"
"math"

gmimc "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/mimc"
"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"
Expand Down Expand Up @@ -43,6 +44,22 @@ func NewMiMCFiatShamir() *State {
}
}

// State returns the internal state of the Fiat-Shamir hasher. Only works for
// MiMC.
func (s *State) State() []field.Element {
AlexandreBelling marked this conversation as resolved.
Show resolved Hide resolved
_ = s.hasher.Sum(nil)
b := s.hasher.(*gmimc.Digest).State()
f := new(field.Element).SetBytes(b)
return []field.Element{*f}
}

// SetState sets the fiat-shamir state to the requested value
func (s *State) SetState(f []field.Element) {
_ = s.hasher.Sum(nil)
b := f[0].Bytes()
s.hasher.(*gmimc.Digest).SetState(b[:])
}

// Update the Fiat-Shamir state with a one or more of field elements. The
// function as no-op if the caller supplies no field elements.
func (fs *State) Update(vec ...field.Element) {
Expand Down
28 changes: 28 additions & 0 deletions prover/crypto/fiatshamir/snark.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,34 @@ func NewGnarkFiatShamir(api frontend.API, factory *gkrmimc.HasherFactory) *Gnark
}
}

// SetState mutates the fiat-shamir state of
func (fs *GnarkFiatShamir) SetState(state []frontend.Variable) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We still to validate the API change on gnark side


switch hsh := fs.hasher.(type) {
case interface {
SetState([]frontend.Variable) error
}:
if err := hsh.SetState(state); err != nil {
panic(err)
}
default:
panic("unexpected hasher type")
}
}

// State mutates the fiat-shamir state of
func (fs *GnarkFiatShamir) State() []frontend.Variable {

switch hsh := fs.hasher.(type) {
case interface {
State() []frontend.Variable
}:
return hsh.State()
default:
panic("unexpected hasher type")
}
}

// Update updates the Fiat-Shamir state with a vector of frontend.Variable
// representing field element each.
func (fs *GnarkFiatShamir) Update(vec ...frontend.Variable) {
Expand Down
25 changes: 25 additions & 0 deletions prover/crypto/mimc/gkrmimc/helper.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package gkrmimc

import (
"errors"
"math/big"

"github.com/consensys/gnark/frontend"
Expand Down Expand Up @@ -107,6 +108,30 @@ func (h *Hasher) Sum() frontend.Variable {
return curr
}

// SetState manually sets the state of the hasher to the provided value. In the
// case of MiMC only a single frontend variable is expected to represent the
// state.
func (h *Hasher) SetState(newState []frontend.Variable) error {

if len(h.data) > 0 {
return errors.New("the hasher is not in an initial state")
}

if len(newState) != 1 {
return errors.New("the MiMC hasher expects a single field element to represent the state")
}

h.state = newState[0]
return nil
}

// State returns the inner-state of the hasher. In the context of MiMC only a
// single field element is returned.
func (h *Hasher) State() []frontend.Variable {
_ = h.Sum() // to flush the hasher
return []frontend.Variable{h.state}
}

// compress calls returns a frontend.Variable holding the result of applying
// the compression function of MiMC over state and block. The alleged returned
// result is pushed on the stack of all the claims to verify.
Expand Down
2 changes: 1 addition & 1 deletion prover/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ require (
github.com/consensys/bavard v0.1.22
github.com/consensys/compress v0.2.5
github.com/consensys/gnark v0.11.1-0.20240910135928-e8cb61d0be1d
github.com/consensys/gnark-crypto v0.14.1-0.20241007145620-e26bbdf97a4a
github.com/consensys/gnark-crypto v0.14.1-0.20241024164653-80568304fcb0
github.com/consensys/go-corset v0.0.0-20241009181119-b687f2ec84ed
github.com/crate-crypto/go-kzg-4844 v1.1.0
github.com/dlclark/regexp2 v1.11.2
Expand Down
4 changes: 2 additions & 2 deletions prover/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,8 @@ github.com/consensys/compress v0.2.5 h1:gJr1hKzbOD36JFsF1AN8lfXz1yevnJi1YolffY19
github.com/consensys/compress v0.2.5/go.mod h1:pyM+ZXiNUh7/0+AUjUf9RKUM6vSH7T/fsn5LLS0j1Tk=
github.com/consensys/gnark v0.11.1-0.20240910135928-e8cb61d0be1d h1:TmNupI1+K5/LOg1K0kqEhRf5sZwRtxXah5iTHQ6fJvw=
github.com/consensys/gnark v0.11.1-0.20240910135928-e8cb61d0be1d/go.mod h1:f9CH911SPCrbSZp5z9LYzJ3rZvI7mOUzzf48lCZO/5o=
github.com/consensys/gnark-crypto v0.14.1-0.20241007145620-e26bbdf97a4a h1:yUHuYq+v1C3maTwnntLYhTDmboq3scSo1PQIl375/sE=
github.com/consensys/gnark-crypto v0.14.1-0.20241007145620-e26bbdf97a4a/go.mod h1:F/hJyWBcTr1sWeifAKfEN3aVb3G4U5zheEC8IbWQun4=
github.com/consensys/gnark-crypto v0.14.1-0.20241024164653-80568304fcb0 h1:Y1HVVcu6QxFFtyHNuK5E6FN4nbOd5YtqinTLMjnjcH4=
github.com/consensys/gnark-crypto v0.14.1-0.20241024164653-80568304fcb0/go.mod h1:F/hJyWBcTr1sWeifAKfEN3aVb3G4U5zheEC8IbWQun4=
github.com/consensys/go-corset v0.0.0-20241009181119-b687f2ec84ed h1:tA+JpjGO3tB2+Q7lsrlDper2L5BcvgS2sNd6DLS2ViM=
github.com/consensys/go-corset v0.0.0-20241009181119-b687f2ec84ed/go.mod h1:J64guTfpmfXl4Yk2D7lsWdYg0ilP+N8JWPudP7+sZpA=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
Expand Down
31 changes: 31 additions & 0 deletions prover/protocol/column/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ type storedColumnInfo struct {
ID ifaces.ColID
// Status of the commitment
Status Status
// IncludeInProverFS states the prover should include the column in his FS
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, mention that this is meaningful for ignored columns

// transcript. This is used for columns that are recursed using FullRecursion.
IncludeInProverFS bool
}

// AddToRound constructs a [Natural], registers it in the [Store] and returns
Expand Down Expand Up @@ -444,3 +447,31 @@ func assertCorrectStatusTransition(old, new Status) {
utils.Panic("attempted the transition %v -> %v, which is forbidden", old.String(), new.String())
}
}

func (s *Store) IgnoreButKeepInProverTranscript(colName ifaces.ColID) {
AlexandreBelling marked this conversation as resolved.
Show resolved Hide resolved
in := s.info(colName)
in.Status = Ignored
in.IncludeInProverFS = true
}

func (s *Store) IsIgnoredAndNotKeptInTranscript(colName ifaces.ColID) bool {
in := s.info(colName)
return in.Status == Ignored && !in.IncludeInProverFS
}

func (s *Store) AllKeysProofsOrIgnoredButKeptInProverTranscript(round int) []ifaces.ColID {
res := []ifaces.ColID{}
rnd := s.byRounds.MustGet(round) // precomputed are always at round zero

for i, info := range rnd {

ok := (info.Status == Proof) || (info.Status == Ignored && info.IncludeInProverFS)
if !ok {
continue
}

res = append(res, rnd[i].ID)
}

return res
}
193 changes: 193 additions & 0 deletions prover/protocol/compiler/fullrecursion/actions.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
package fullrecursion

import (
"fmt"

"github.com/consensys/gnark/frontend"
"github.com/consensys/linea-monorepo/prover/maths/field"
"github.com/consensys/linea-monorepo/prover/protocol/wizard"
)

type CircuitAssignment fullRecursionCtx
AlexandreBelling marked this conversation as resolved.
Show resolved Hide resolved

func (c CircuitAssignment) Run(run *wizard.ProverRuntime) {
c.PlonkInWizard.ProverAction.Run(run, WitnessAssigner(c))
}

type ReplacementAssignment fullRecursionCtx

func (c ReplacementAssignment) Run(run *wizard.ProverRuntime) {
params := run.GetUnivariateParams(c.PolyQuery.QueryID)
run.AssignUnivariate(c.PolyQueryReplacement.QueryID, params.X, params.Ys...)

oldRoots := c.PcsCtx.Items.MerkleRoots
for i := range c.MerkleRootsReplacement {

if c.PcsCtx.Items.MerkleRoots[i] == nil {
continue
}

run.AssignColumn(
c.MerkleRootsReplacement[i].GetColID(),
oldRoots[i].GetColAssignment(run),
)
}
}

type LocalOpeningAssignment fullRecursionCtx

func (c LocalOpeningAssignment) Run(run *wizard.ProverRuntime) {
for i := range c.LocalOpenings {
run.AssignLocalPoint(
c.LocalOpenings[i].ID,
c.PlonkInWizard.PI.GetColAssignmentAt(run, i),
)
}
}

type ConsistencyCheck struct {
fullRecursionCtx
isSkipped bool
}

func (c *ConsistencyCheck) Run(run *wizard.VerifierRuntime) error {

var (
initialFsCirc = run.GetLocalPointEvalParams(c.LocalOpenings[0].ID).Y
initialFsRt = run.FiatShamirHistory[c.FirstRound+1][0][0]
piCursor = 2
)

if initialFsCirc != initialFsRt {
return fmt.Errorf("full recursion: the initial FS do not match")
}

for i := range c.NonEmptyMerkleRootPositions {

var (
pos = c.NonEmptyMerkleRootPositions[i]
fromRt = c.MerkleRootsReplacement[pos].GetColAssignmentAt(run, 0)
fromCirc = run.GetLocalPointEvalParams(c.LocalOpenings[piCursor+i].ID).Y
)

if fromRt != fromCirc {
return fmt.Errorf("full recursion: the commitment does not match (pos: %v)", i)
}
}

piCursor += len(c.NonEmptyMerkleRootPositions)

var (
paramsRt = run.GetUnivariateParams(c.PolyQueryReplacement.QueryID)
xRt = paramsRt.X
xCirc = run.GetLocalPointEvalParams(c.LocalOpenings[piCursor].ID).Y
)

if xRt != xCirc {
return fmt.Errorf("full recursion: the Ys does not match")
}

piCursor++

for i := range paramsRt.Ys {

var (
fromRt = paramsRt.Ys[i]
fromCirc = run.GetLocalPointEvalParams(c.LocalOpenings[piCursor+i].ID).Y
)

if fromRt != fromCirc {
return fmt.Errorf("full recursion: the Ys does not match (pos: %v)", i)
}
}

piCursor += len(paramsRt.Ys)

// The public inputs do not need to be checked because they are redefined in
// term of the local openings directly. So checking it would amount to checking
// that the local openings are equal to themselves.

return nil
}

func (c *ConsistencyCheck) RunGnark(api frontend.API, run *wizard.WizardVerifierCircuit) {

var (
initialFsCirc = run.GetLocalPointEvalParams(c.LocalOpenings[0].ID).Y
initialFsRt = run.FiatShamirHistory[c.FirstRound+1][0][0]
piCursor = 2
)

api.AssertIsEqual(initialFsCirc, initialFsRt)

for i := range c.NonEmptyMerkleRootPositions {

var (
pos = c.NonEmptyMerkleRootPositions[i]
fromRt = c.MerkleRootsReplacement[pos].GetColAssignmentGnarkAt(run, 0)
fromCirc = run.GetLocalPointEvalParams(c.LocalOpenings[piCursor+i].ID).Y
)

api.AssertIsEqual(fromRt, fromCirc)
}

piCursor += len(c.NonEmptyMerkleRootPositions)

var (
paramsRt = run.GetUnivariateParams(c.PolyQueryReplacement.QueryID)
xRt = paramsRt.X
xCirc = run.GetLocalPointEvalParams(c.LocalOpenings[piCursor].ID).Y
)

api.AssertIsEqual(xRt, xCirc)

piCursor++

for i := range paramsRt.Ys {

var (
fromRt = paramsRt.Ys[i]
fromCirc = run.GetLocalPointEvalParams(c.LocalOpenings[piCursor+i].ID).Y
)

api.AssertIsEqual(fromRt, fromCirc)
}

piCursor += len(paramsRt.Ys)

// The public inputs do not need to be checked because they are redefined in
// term of the local openings directly. So checking it would amount to checking
// that the local openings are equal to themselves.
}

func (c *ConsistencyCheck) Skip() {
c.isSkipped = true
}

func (c *ConsistencyCheck) IsSkipped() bool {
return c.isSkipped
}

type ResetFsActions struct {
fullRecursionCtx
isSkipped bool
}

func (r *ResetFsActions) Run(run *wizard.VerifierRuntime) error {
finalFsCirc := run.GetLocalPointEvalParams(r.LocalOpenings[1].ID).Y
run.FS.SetState([]field.Element{finalFsCirc})
return nil
}

func (r *ResetFsActions) RunGnark(api frontend.API, run *wizard.WizardVerifierCircuit) {
finalFsCirc := run.GetLocalPointEvalParams(r.LocalOpenings[1].ID).Y
run.FS.SetState([]frontend.Variable{finalFsCirc})
}

func (r *ResetFsActions) Skip() {
r.isSkipped = true
}

func (r *ResetFsActions) IsSkipped() bool {
return r.isSkipped
}
Loading
Loading