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: beta v1 setup #179

Draft
wants to merge 18 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all 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
7 changes: 7 additions & 0 deletions kzgsrs/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Ignore everything
*

# But not these files...
!.gitignore
!kzg_srs_canonical_259_bn254_aztec.memdump
!kzg_srs_canonical_259_bls12377_aleo.memdump
48 changes: 45 additions & 3 deletions prover/circuits/execution/pi_wizard_extraction.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,12 +113,54 @@ func checkPublicInputs(
)
)

// The way the chainID is extracted is by comparing a length-1 column accessor
// with the content of the transactions RLP. If there is at least one single
// non-legacy transaction, its RLP will contain the chainID (not used by the
// rest of the arithmetization) and the constraint will check that this
// chainID match the one we extract. This consequently ensure that all the
// non-legacy transactions have the same chainID.
//
// In case every transaction of the current batch is a legacy transaction,
// the constraints for the chainID and chainIDNbBytes are loose because there
// nothing to compare with the alleged chainID of the block. In that case,
// we do not impose additional constraint as it means that the same transactions
// would have given the same result regardless of the chainID. The prover
// will "honestly" use 0 as a value for the chainID but this is not enforced.
//
// The problem is that the witness value for `gnarkFuncInp.ChainID` will
// still be the "right" value. And thus, a direct equality constraint would
// not apply. We solve that by conditionning the equality-check to the case
// where the extracted chain-ID is non-zero.
//
// This gives us the following case disjunction.
//
// 1/ Only legacy transactions in the batch: the "fetched" chainID is a free
// value for the prover.
// a) The prover chooses zero => the corresponding public input is again
// a free value
// b) The prover chooses a non-zero value => the public input is enforced
// to be equal to that non-zero value.
//
// In both (1.a) and (1.b) the public value of the chainID is a free value.
// And this is fine because every value of the chainID would have yielded the
// same exectution result.
//
// 2/ There is at least one non-legacy transaction in the batch: the "fetched"
// chainID is the "actual" value.
// a) That chainID is always non-zero as Linea only uses non-zero chain-IDs
// so the corresponding public input is enforced to be equal to it.
api.AssertIsEqual(
api.Div(
api.Mul(
api.Sub(
api.Div(
wvc.GetLocalPointEvalParams(wizardFuncInp.ChainID.ID).Y,
twoPow112,
),
gnarkFuncInp.ChainID,
),
wvc.GetLocalPointEvalParams(wizardFuncInp.ChainID.ID).Y,
twoPow112,
),
gnarkFuncInp.ChainID,
0,
)

api.AssertIsEqual(bridgeAddress, gnarkFuncInp.L2MessageServiceAddr)
Expand Down
54 changes: 48 additions & 6 deletions prover/circuits/pi-interconnection/circuit.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package pi_interconnection

import (
"errors"
"fmt"
"math"
"math/big"
"slices"
Expand All @@ -25,6 +24,12 @@ import (
"github.com/consensys/linea-monorepo/prover/circuits/internal"
"github.com/consensys/linea-monorepo/prover/circuits/pi-interconnection/keccak"
"github.com/consensys/linea-monorepo/prover/crypto/mimc/gkrmimc"
"github.com/consensys/linea-monorepo/prover/crypto/ringsis"
"github.com/consensys/linea-monorepo/prover/protocol/compiler"
"github.com/consensys/linea-monorepo/prover/protocol/compiler/cleanup"
mimcComp "github.com/consensys/linea-monorepo/prover/protocol/compiler/mimc"
"github.com/consensys/linea-monorepo/prover/protocol/compiler/selfrecursion"
"github.com/consensys/linea-monorepo/prover/protocol/compiler/vortex"
"github.com/consensys/linea-monorepo/prover/protocol/wizard"
"github.com/consensys/linea-monorepo/prover/utils"
)
Expand All @@ -50,6 +55,10 @@ type Circuit struct {
MockKeccakWizard bool // for testing purposes, bypass expensive keccak verification
}

// type alias to denote a wizard-compilation suite. This is used when calling
// compile and provides internal parameters for the wizard package.
type compilationSuite = []func(*wizard.CompiledIOP)

func (c *Circuit) Define(api frontend.API) error {
maxNbDecompression, maxNbExecution := len(c.DecompressionPublicInput), len(c.ExecutionPublicInput)
if len(c.DecompressionFPIQ) != maxNbDecompression || len(c.ExecutionFPIQ) != maxNbExecution {
Expand Down Expand Up @@ -325,19 +334,52 @@ func (b builder) Compile() (constraint.ConstraintSystem, error) {
if err != nil {
return nil, err
}
const estimatedNbConstraints = 35_000_000
const estimatedNbConstraints = 1 << 27
cs, err := frontend.Compile(ecc.BLS12_377.ScalarField(), scs.NewBuilder, c.Circuit, frontend.WithCapacity(estimatedNbConstraints))
if err != nil {
return nil, err
}
if nbC := cs.GetNbConstraints(); nbC > estimatedNbConstraints || estimatedNbConstraints-nbC > 5_000_000 {
return nil, fmt.Errorf("constraint estimate is off; got %d", nbC)
}

return cs, nil
}

func WizardCompilationParameters() []func(iop *wizard.CompiledIOP) {
panic("implement me") // TODO @alexandre.belling
var (
sisInstance = ringsis.Params{LogTwoBound: 16, LogTwoDegree: 6}

fullCompilationSuite = compilationSuite{

compiler.Arcane(1<<10, 1<<18, false),
vortex.Compile(
2,
vortex.ForceNumOpenedColumns(256),
vortex.WithSISParams(&sisInstance),
),

selfrecursion.SelfRecurse,
cleanup.CleanUp,
mimcComp.CompileMiMC,
compiler.Arcane(1<<10, 1<<16, false),
vortex.Compile(
8,
vortex.ForceNumOpenedColumns(64),
vortex.WithSISParams(&sisInstance),
),

selfrecursion.SelfRecurse,
cleanup.CleanUp,
mimcComp.CompileMiMC,
compiler.Arcane(1<<10, 1<<13, false),
vortex.Compile(
8,
vortex.ForceNumOpenedColumns(64),
vortex.ReplaceSisByMimc(),
),
}
)

return fullCompilationSuite

}

// GetMaxNbCircuitsSum computes MaxNbDecompression + MaxNbExecution from the compiled constraint system
Expand Down
3 changes: 3 additions & 0 deletions prover/circuits/pi-interconnection/keccak/assign.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/consensys/gnark/std/compress"
"github.com/consensys/linea-monorepo/prover/circuits/internal"
"github.com/consensys/linea-monorepo/prover/protocol/wizard"
"github.com/sirupsen/logrus"
"golang.org/x/crypto/sha3"
)

Expand Down Expand Up @@ -87,6 +88,8 @@ func (h *StrictHasherCompiler) Compile(wizardCompilationOpts ...func(iop *wizard
nbKeccakF += l/blockNbBytesIn + 1 // extra room for padding
}

logrus.Infof("Public-input interconnection requires %v keccak permutations", nbKeccakF)

wc := NewWizardVerifierSubCircuit(nbKeccakF, wizardCompilationOpts...)

return CompiledStrictHasher{
Expand Down
12 changes: 9 additions & 3 deletions prover/circuits/pi-interconnection/keccak/customize_keccak.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package keccak

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

Expand All @@ -16,19 +17,24 @@ type module struct {
// The correctness of original blocks is checked outside of the module,
// where one also should assert that the expected blocks are the same as correct original blocks.
func NewCustomizedKeccak(comp *wizard.CompiledIOP, maxNbKeccakF int) *module {

var (
size = utils.NextPowerOfTwo(generic.KeccakUsecase.NbOfLanesPerBlock() * maxNbKeccakF)

inp = keccak.KeccakOverBlockInputs{
LaneInfo: keccak.LaneInfo{
Lanes: comp.InsertCommit(0, "Lane", size),
IsFirstLaneOfNewHash: comp.InsertCommit(0, "IsFirstLaneOfNewHash", size),
IsLaneActive: comp.InsertCommit(0, "IsLaneActive", size),
Lanes: comp.InsertProof(0, "Lane", size),
IsFirstLaneOfNewHash: comp.InsertProof(0, "IsFirstLaneOfNewHash", size),
IsLaneActive: comp.InsertProof(0, "IsLaneActive", size),
},
MaxNumKeccakF: maxNbKeccakF,
}
m = keccak.NewKeccakOverBlocks(comp, inp)
)

comp.Columns.SetStatus("HASH_OUTPUT_Hash_Lo", column.Proof)
comp.Columns.SetStatus("HASH_OUTPUT_Hash_Hi", column.Proof)

return &module{
keccak: *m,
}
Expand Down
18 changes: 13 additions & 5 deletions prover/circuits/setup_manifest.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"os"
"path"
"strconv"
"time"

"github.com/consensys/gnark-crypto/ecc"
Expand Down Expand Up @@ -51,12 +52,19 @@ func (m *SetupManifest) GetInt(key string) (int, error) {
return 0, err
}

i, ok := v.(int)
if !ok {
return 0, fmt.Errorf("flag `%s` is not an int", key)
switch i := v.(type) {
case int:
return i, nil
case int64:
return int(i), nil
case float64:
return int(i), nil
case string:
// If stored as a string, try to parse it as an int
return strconv.Atoi(i)
default:
return 0, fmt.Errorf("flag `%s` is not an int, got %T", key, v)
}

return i, nil
}

func (m *SetupManifest) GetString(key string) (string, error) {
Expand Down
2 changes: 1 addition & 1 deletion prover/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ type Aggregation struct {

// AllowedInputs determines the "inner" plonk circuits the "outer" aggregation circuit can aggregate.
// Order matters.
AllowedInputs []string `mapstructure:"allowed_inputs" validate:"required,dive,oneof=execution-dummy execution execution-large blob-decompression-dummy blob-decompression-v0 blob-decompression-v1"`
AllowedInputs []string `mapstructure:"allowed_inputs" validate:"required,dive,oneof=execution-dummy execution execution-large blob-decompression-dummy blob-decompression-v0 blob-decompression-v1 emulation-dummy aggregation emulation public-input-interconnection"`

// note @gbotrel keeping that around in case we need to support two emulation contract
// during a migration.
Expand Down
12 changes: 10 additions & 2 deletions prover/lib/compressor/blob/blob.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,24 @@ func DictionaryChecksum(dict []byte, version uint16) ([]byte, error) {
return nil, errors.New("unsupported version")
}

// GetRepoRootPath assumes that current working directory is within the repo
// GetRepoRootPath returns the root path of the repository
func GetRepoRootPath() (string, error) {
// First, check if the deployment path exists
deploymentPath := "/opt/linea"
if _, err := os.Stat(deploymentPath); err == nil {
return deploymentPath, nil
}

// If not found, fall back to checking the local development path based on the current directory
wd, err := os.Getwd()
if err != nil {
return "", err
}

const repoName = "linea-monorepo"
i := strings.LastIndex(wd, repoName)
if i == -1 {
return "", errors.New("could not find repo root")
return "", errors.New("could not find repo root. Current working directory: " + wd)
}
i += len(repoName)
return wd[:i], nil
Expand Down
4 changes: 2 additions & 2 deletions prover/lib/compressor/blob/v1/blob_maker.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ const (
NbElemsEncodingBytes = 2

// These also impact the circuit constraints (compile / setup time)
MaxUncompressedBytes = 740 * 1024 // defines the max size we can handle for a blob (uncompressed) input
MaxUsableBytes = 32 * 4096 // defines the number of bytes available in a blob
MaxUncompressedBytes = 756000 // defines the max size we can handle for a blob (uncompressed) input
MaxUsableBytes = 32 * 4096 // defines the number of bytes available in a blob
)

// BlobMaker is a bm for RLP encoded blocks (see EIP-4844).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,21 @@ func ConstrainChainID(comp *wizard.CompiledIOP, fetcher *RlpTxnFetcher, name str
// get accessors
accChainID := accessors.NewFromPublicColumn(fetcher.ChainID, 0)
accNBytesChainID := accessors.NewFromPublicColumn(fetcher.NBytesChainID, 0)

// The way the chainID is extracted is by comparing a length-1 column accessor
// with the content of the transactions RLP. If there is at least one single
// non-legacy transaction, its RLP will contain the chainID (not used by the
// rest of the arithmetization) and the constraint will check that this
// chainID match the one we extract. This consequently ensure that all the
// non-legacy transactions have the same chainID.
//
// In case every transaction of the current batch is a legacy transaction,
// the constraints for the chainID and chainIDNbBytes are loose because there
// nothing to compare with the alleged chainID of the block. In that case,
// we do not impose additional constraint as it means that the same transactions
// would have given the same result regardless of the chainID. The prover
// will "honestly" use 0 as a value for the chainID but this is not enforced.

// constraint for the ChainID column
comp.InsertGlobal(
0,
Expand Down
Loading