Prover(fix): setup execution-large (#844)

* fix execution large circuitID and add sanity-check for traces limits checksum between setup and config

* fix: add sync.once fullZkEvmSetup and fullZkEvmSetupLarge for setup

* fix: prover large cbor Unmarshal error "exceeded max number of elements"
- use default value (131072) x 1024 for MaxArrayElements and MaxMapPairs
This commit is contained in:
Leo Jeong
2025-04-08 15:25:22 +09:00
committed by GitHub
parent dbe61ed3af
commit bc96f16aea
4 changed files with 106 additions and 42 deletions

View File

@@ -1,6 +1,9 @@
package execution
import (
"fmt"
"path/filepath"
"github.com/consensys/gnark-crypto/ecc"
"github.com/consensys/linea-monorepo/prover/circuits"
"github.com/consensys/linea-monorepo/prover/circuits/dummy"
@@ -23,11 +26,6 @@ func Prove(cfg *config.Config, req *Request, large bool) (*Response, error) {
// Set MonitorParams before any proving happens
profiling.SetMonitorParams(cfg)
traces := &cfg.TracesLimits
if large {
traces = &cfg.TracesLimitsLarge
}
var resp Response
// TODO @gbotrel wrap profiling in the caller; so that we can properly return errors
@@ -48,8 +46,8 @@ func Prove(cfg *config.Config, req *Request, large bool) (*Response, error) {
// - NewFromString can panic
out.Proof, out.VerifyingKeyShaSum = mustProveAndPass(
cfg,
traces,
NewWitness(cfg, req, &out),
large,
)
out.Version = cfg.Version
@@ -75,10 +73,15 @@ func Prove(cfg *config.Config, req *Request, large bool) (*Response, error) {
// when calling it twice.
func mustProveAndPass(
cfg *config.Config,
traces *config.TracesLimits,
w *Witness,
large bool,
) (proofHexString string, vkeyShaSum string) {
traces := &cfg.TracesLimits
if large {
traces = &cfg.TracesLimitsLarge
}
switch cfg.Execution.ProverMode {
case config.ProverModeDev, config.ProverModePartial:
if cfg.Execution.ProverMode == config.ProverModePartial {
@@ -119,8 +122,21 @@ func mustProveAndPass(
errSetup error
chSetupDone = make(chan struct{})
)
circuitID := circuits.ExecutionCircuitID
if large {
circuitID = circuits.ExecutionLargeCircuitID
}
// Sanity-check trace limits checksum between setup and config
if err := SanityCheckTracesChecksum(circuitID, traces, cfg); err != nil {
utils.Panic("traces checksum in the setup manifest does not match the one in the config: %v", err)
}
// Start loading the setup
go func() {
setup, errSetup = circuits.LoadSetup(cfg, circuits.ExecutionCircuitID)
logrus.Infof("Loading setup - circuitID: %s", circuitID)
setup, errSetup = circuits.LoadSetup(cfg, circuitID)
close(chSetupDone)
}()
@@ -139,21 +155,6 @@ func mustProveAndPass(
utils.Panic("could not load setup: %v", errSetup)
}
// ensure the checksum for the traces in the setup matches the one in the config
setupCfgChecksum, err := setup.Manifest.GetString("cfg_checksum")
if err != nil {
utils.Panic("could not get the traces checksum from the setup manifest: %v", err)
}
if setupCfgChecksum != traces.Checksum() {
// This check is failing on prod but works locally.
// @alex: since this is a setup-related constraint, it would likely be
// more interesting to directly include that information in the setup
// instead of the config. That way we are guaranteed to not pass the
// wrong value at runtime.
utils.Panic("traces checksum in the setup manifest does not match the one in the config")
}
// TODO: implements the collection of the functional inputs from the prover response
return execution.MakeProof(traces, setup, fullZkEvm.WizardIOP, proof, *w.FuncInp), setup.VerifyingKeyDigest()
@@ -187,3 +188,31 @@ func mustProveAndPass(
panic("not implemented")
}
}
// SanityCheckTraceChecksum ensures the checksum for the traces in the setup matches the one in the config
func SanityCheckTracesChecksum(circuitID circuits.CircuitID, traces *config.TracesLimits, cfg *config.Config) error {
// read setup manifest
manifestPath := filepath.Join(cfg.PathForSetup(string(circuitID)), config.ManifestFileName)
manifest, err := circuits.ReadSetupManifest(manifestPath)
if err != nil {
utils.Panic("could not read the setup manifest: %v", err)
}
// read manifest traces checksum
setupCfgChecksum, err := manifest.GetString("cfg_checksum")
if err != nil {
utils.Panic("could not get the traces checksum from the setup manifest: %v", err)
}
if setupCfgChecksum != traces.Checksum() {
// This check is failing on prod but works locally.
// @alex: since this is a setup-related constraint, it would likely be
// more interesting to directly include that information in the setup
// instead of the config. That way we are guaranteed to not pass the
// wrong value at runtime.
return fmt.Errorf("setup (%s): '%s' vs config: '%s'", circuitID, setupCfgChecksum, traces.Checksum())
}
return nil
}

View File

@@ -99,20 +99,23 @@ func Setup(context context.Context, args SetupArgs) error {
// we skip aggregation in this first loop since the setup is more complex
continue
}
logrus.Infof("setting up %s", c)
logrus.Infof("Setting up %s", c)
var builder circuits.Builder
extraFlags := make(map[string]any)
// let's compile the circuit.
switch c {
case circuits.ExecutionCircuitID, circuits.ExecutionLargeCircuitID:
case circuits.ExecutionCircuitID:
limits := cfg.TracesLimits
if c == circuits.ExecutionLargeCircuitID {
limits = cfg.TracesLimitsLarge
}
extraFlags["cfg_checksum"] = limits.Checksum()
zkEvm := zkevm.FullZkEvm(&limits, cfg)
zkEvm := zkevm.FullZkEvmSetup(&limits, cfg)
builder = execution.NewBuilder(zkEvm)
case circuits.ExecutionLargeCircuitID:
limits := cfg.TracesLimitsLarge
extraFlags["cfg_checksum"] = limits.Checksum()
zkEvm := zkevm.FullZkEvmSetupLarge(&limits, cfg)
builder = execution.NewBuilder(zkEvm)
case circuits.BlobDecompressionV0CircuitID:
@@ -270,7 +273,7 @@ func updateSetup(ctx context.Context, cfg *config.Config, force bool, srsProvide
}
// compile the circuit
logrus.Infof("compiling %s", circuit)
logrus.Infof("Compiling %s", circuit)
ccs, err := builder.Compile()
if err != nil {
return fmt.Errorf("failed to compile circuit %s: %w", circuit, err)
@@ -279,33 +282,38 @@ func updateSetup(ctx context.Context, cfg *config.Config, force bool, srsProvide
// derive the asset paths
setupPath := cfg.PathForSetup(string(circuit))
manifestPath := filepath.Join(setupPath, config.ManifestFileName)
logrus.Infof("Manifest path: %s", manifestPath)
// check if setup can be skipped
if !force {
// we may want to skip setup if the files already exist
// and the checksums match
// read manifest if already exists
if manifest, err := circuits.ReadSetupManifest(manifestPath); err == nil {
circuitDigest, err := circuits.CircuitDigest(ccs)
if err != nil {
return fmt.Errorf("failed to compute circuit digest for circuit %s: %w", circuit, err)
}
logrus.Infof("Manifest checksum: %s, Computed circuit digest: %s", manifest.Checksums.Circuit, circuitDigest)
if manifest.Checksums.Circuit == circuitDigest {
logrus.Infof("skipping %s (already setup)", circuit)
logrus.Infof("Skipping %s (already setup)", circuit)
return nil
}
}
}
// run the actual setup
logrus.Infof("plonk setup for %s", circuit)
logrus.Infof("Plonk setup for %s", circuit)
setup, err := circuits.MakeSetup(ctx, circuit, ccs, srsProvider, extraFlags)
if err != nil {
return fmt.Errorf("failed to setup circuit %s: %w", circuit, err)
}
logrus.Infof("writing assets for %s", circuit)
return setup.WriteTo(setupPath)
// write the assets
err = setup.WriteTo(setupPath)
if err != nil {
return fmt.Errorf("failed to write assets for circuit %s: %w", circuit, err)
}
logrus.Infof("Successfully wrote circuit %s to %s", circuit, setupPath)
return nil
}
// listOfChecksums Computes a list of SHA256 checksums for a list of assets, the result is given

View File

@@ -29,7 +29,16 @@ func serializeAnyWithCborPkg(x any) json.RawMessage {
// deserializeAnyWithCborPkg calls [json.Unmarshal] and wraps the error if any.
func deserializeAnyWithCborPkg(data json.RawMessage, x any) error {
if err := cbor.Unmarshal(data, x); err != nil {
opts := cbor.DecOptions{
MaxArrayElements: 134217728, // MaxArrayElements specifies the max number of elements for CBOR arrays.
MaxMapPairs: 134217728, // MaxMapPairs specifies the max number of key-value pairs for CBOR maps.
}
decMode, err := opts.DecMode()
if err != nil {
return fmt.Errorf("failed to create CBOR decoder mode: %w", err)
}
if err := decMode.Unmarshal(data, x); err != nil {
return fmt.Errorf("cbor.Unmarshal failed: %w", err)
}
return nil

View File

@@ -26,10 +26,14 @@ import (
)
var (
fullZkEvm *ZkEvm
fullZkEvmCheckOnly *ZkEvm
onceFullZkEvm = sync.Once{}
onceFullZkEvmCheckOnly = sync.Once{}
fullZkEvm *ZkEvm
fullZkEvmCheckOnly *ZkEvm
fullZkEvmSetup *ZkEvm
fullZkEvmSetupLarge *ZkEvm
onceFullZkEvm = sync.Once{}
onceFullZkEvmCheckOnly = sync.Once{}
onceFullZkEvmSetup = sync.Once{}
onceFullZkEvmSetupLarge = sync.Once{}
// This is the SIS instance, that has been found to minimize the overhead of
// recursion. It is changed w.r.t to the estimated because the estimated one
@@ -121,6 +125,20 @@ func FullZkEVMCheckOnly(tl *config.TracesLimits, cfg *config.Config) *ZkEvm {
return fullZkEvmCheckOnly
}
func FullZkEvmSetup(tl *config.TracesLimits, cfg *config.Config) *ZkEvm {
onceFullZkEvmSetup.Do(func() {
fullZkEvmSetup = FullZKEVMWithSuite(tl, fullCompilationSuite, cfg)
})
return fullZkEvmSetup
}
func FullZkEvmSetupLarge(tl *config.TracesLimits, cfg *config.Config) *ZkEvm {
onceFullZkEvmSetupLarge.Do(func() {
fullZkEvmSetupLarge = FullZKEVMWithSuite(tl, fullCompilationSuite, cfg)
})
return fullZkEvmSetupLarge
}
// FullZKEVMWithSuite returns a compiled zkEVM with the given compilation suite.
// It can be used to benchmark the compilation time of the zkEVM and helps with
// performance optimization.