Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
23b7ad7
fix(common_constraints): merkle tests are passing
arijitdutta67 Nov 11, 2025
0cce6dd
fix(accumulator): compilation errors fixes (wip)
arijitdutta67 Nov 11, 2025
40587f4
fix(accumulator): fix constant
arijitdutta67 Nov 13, 2025
f44ffe6
feat(flat-proof): bit decompose with slices of pos columns (wip)
arijitdutta67 Nov 14, 2025
d60b149
fix(flat-proof): bug fix, test passing
arijitdutta67 Nov 14, 2025
f2ec528
minor: remove and reinstate print statements
arijitdutta67 Nov 18, 2025
d9ebfff
Merge branch 'prover/dev-small-fields' into prover/fix-state-manager
arijitdutta67 Nov 18, 2025
9081c28
fix(accumulator): fix define column dimension
arijitdutta67 Nov 18, 2025
9c39010
fix(accumulator/assign): remove mimc with posseidon2
arijitdutta67 Nov 19, 2025
e3ef6d0
fix: mimc_config to poseidon2 config
arijitdutta67 Nov 20, 2025
2f8b1dd
fix(accumulator-assign): fixed all compilation error
arijitdutta67 Nov 21, 2025
500469f
fix(accumulator-define): fix all define compiler error to run assign …
arijitdutta67 Nov 21, 2025
7ca4666
fix(accumulator-define): fix the qname compiler error
arijitdutta67 Nov 21, 2025
43fdaa5
fix: fix the poseidon encoding for u64 and fieldhash
arijitdutta67 Nov 24, 2025
b29f89c
fix: change pos from 4 to 16 limbs as it involves hashing
arijitdutta67 Nov 24, 2025
2261b08
fix: debug wip
arijitdutta67 Nov 24, 2025
663ecea
fix: debug empty leaf
arijitdutta67 Nov 24, 2025
df5e650
fix: leaf length fixed, test passing
arijitdutta67 Nov 24, 2025
9ee0769
fix: deletion test fixed, all assign tests are passing now
arijitdutta67 Nov 24, 2025
a81b344
fix(accumulator): changing mimc to poseidon query (wip)
arijitdutta67 Nov 25, 2025
4e8504e
fix(define accumulator): added poseidon2 queries for leaf hashes
arijitdutta67 Nov 26, 2025
aebbbc8
fix(accumulator): poseidon2 query for top root is added
arijitdutta67 Nov 26, 2025
ac37e7f
fix(mock): change mimc to poseidon2
arijitdutta67 Nov 27, 2025
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/backend/execution/statemanager/access_pattern.go
Original file line number Diff line number Diff line change
Expand Up @@ -377,8 +377,8 @@ func checkStorageTraceOrder(traces []DecodedTrace) (err error) {
next = traces[i+1].Underlying
currRW = curr.RWInt()
nextRW = next.RWInt()
currHKey = curr.HKey(MIMC_CONFIG)
nextHKey = next.HKey(MIMC_CONFIG)
currHKey = curr.HKey(POSEIDON2_CONFIG)
nextHKey = next.HKey(POSEIDON2_CONFIG)
)

if currRW > nextRW {
Expand Down
8 changes: 4 additions & 4 deletions prover/backend/execution/statemanager/proof_checks.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,8 @@ func checkProofsWorldState(traces []DecodedTrace) (oldRootHash, newRootHash Dige
if i < len(traces)-1 {

var (
currHKey = traces[i].Underlying.HKey(MIMC_CONFIG)
nextHKey = traces[i+1].Underlying.HKey(MIMC_CONFIG)
currHKey = traces[i].Underlying.HKey(POSEIDON2_CONFIG)
nextHKey = traces[i+1].Underlying.HKey(POSEIDON2_CONFIG)
)

if types.Bytes32Cmp(currHKey, nextHKey) > 0 {
Expand Down Expand Up @@ -221,7 +221,7 @@ func bootstrapVerifierStateFromST(trace DecodedTrace) (vs StorageVerifier) {

vs = StorageVerifier{
Location: trace.Location,
Config: MIMC_CONFIG,
Config: POSEIDON2_CONFIG,
}

switch t := trace.Underlying.(type) {
Expand Down Expand Up @@ -252,7 +252,7 @@ func bootstrapVerifierStateFromWS(trace DecodedTrace) (vs AccountVerifier) {

vs = AccountVerifier{
Location: trace.Location,
Config: MIMC_CONFIG,
Config: POSEIDON2_CONFIG,
}

switch t := trace.Underlying.(type) {
Expand Down
30 changes: 15 additions & 15 deletions prover/backend/execution/statemanager/test_vectors_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func DummyDigest(i int) (d eth.Digest) {
}

func Hash(t io.WriterTo) types.Bytes32 {
hasher := eth.MIMC_CONFIG.HashFunc()
hasher := eth.POSEIDON2_CONFIG.HashFunc()
t.WriteTo(hasher)
return types.AsBytes32(hasher.Sum(nil))
}
Expand Down Expand Up @@ -60,7 +60,7 @@ func TestEmptyStorageTrieHash(t *testing.T) {
- Root hash of the empty world state
*/
func TestEmptyWorldStateMiMC(t *testing.T) {
worldstate := eth.NewWorldState(eth.MIMC_CONFIG)
worldstate := eth.NewWorldState(eth.POSEIDON2_CONFIG)
// should be the top root of an empty accumulator
assert.Equal(t, "0x07977874126658098c066972282d4c85f230520af3847e297fe7524f976873e5", worldstate.AccountTrie.TopRoot().Hex())
}
Expand All @@ -71,11 +71,11 @@ func TestEmptyWorldStateMiMC(t *testing.T) {
*/
func TestWorldStateWithAnAccountMiMC(t *testing.T) {

account := eth.NewEOA(eth.MIMC_CONFIG, 65, big.NewInt(835))
account := eth.NewEOA(eth.POSEIDON2_CONFIG, 65, big.NewInt(835))
// This gives a non-zero dummy address to the account
address := DummyAddress(36)

worldstate := eth.NewWorldState(eth.MIMC_CONFIG)
worldstate := eth.NewWorldState(eth.POSEIDON2_CONFIG)
worldstate.AccountTrie.InsertAndProve(address, account)

// check that the hash of the inserted account matches
Expand All @@ -94,14 +94,14 @@ func TestWorldStateWithAnAccountMiMC(t *testing.T) {
*/
func TestWorldStateWithTwoAccountMiMC(t *testing.T) {

accountA := eth.NewEOA(eth.MIMC_CONFIG, 65, big.NewInt(835))
accountA := eth.NewEOA(eth.POSEIDON2_CONFIG, 65, big.NewInt(835))
// This gives a non-zero dummy address to the account
addressA := DummyAddress(36)

accountB := eth.NewEOA(eth.MIMC_CONFIG, 42, big.NewInt(354))
accountB := eth.NewEOA(eth.POSEIDON2_CONFIG, 42, big.NewInt(354))
addressB := DummyAddress(41) // must be a different address or the insert will panic

worldstate := eth.NewWorldState(eth.MIMC_CONFIG)
worldstate := eth.NewWorldState(eth.POSEIDON2_CONFIG)
worldstate.AccountTrie.InsertAndProve(addressA, accountA)
worldstate.AccountTrie.InsertAndProve(addressB, accountB)

Expand All @@ -120,19 +120,19 @@ func TestWorldStateWithTwoAccountMiMC(t *testing.T) {
func TestWorldStateEoaAndContractMiMC(t *testing.T) {

// dummy EOA
accountA := eth.NewEOA(eth.MIMC_CONFIG, 65, big.NewInt(835))
accountA := eth.NewEOA(eth.POSEIDON2_CONFIG, 65, big.NewInt(835))
addressA := DummyAddress(36)

// dummy Account
accountB := eth.NewContractEmptyStorage(eth.MIMC_CONFIG, 41, big.NewInt(15353), DummyDigest(75), DummyFullByte(15), 7)
accountB := eth.NewContractEmptyStorage(eth.POSEIDON2_CONFIG, 41, big.NewInt(15353), DummyDigest(75), DummyFullByte(15), 7)
addressB := DummyAddress(47)

worldstate := eth.NewWorldState(eth.MIMC_CONFIG)
worldstate := eth.NewWorldState(eth.POSEIDON2_CONFIG)
worldstate.AccountTrie.InsertAndProve(addressA, accountA)
worldstate.AccountTrie.InsertAndProve(addressB, accountB)

// Give a storage trie to B
worldstate.StorageTries.InsertNew(addressB, eth.NewStorageTrie(eth.MIMC_CONFIG, addressB))
worldstate.StorageTries.InsertNew(addressB, eth.NewStorageTrie(eth.POSEIDON2_CONFIG, addressB))

// The storage tries map stores pointers to the storage tries so we don't need to
// update the map after modifying the storage however, we still need to manually
Expand Down Expand Up @@ -190,18 +190,18 @@ insert C
func TestAddAaddBdelAaddCMiMC(t *testing.T) {

// dummy EOA
accountA := eth.NewEOA(eth.MIMC_CONFIG, 65, big.NewInt(835))
accountA := eth.NewEOA(eth.POSEIDON2_CONFIG, 65, big.NewInt(835))
addressA := DummyAddress(36)

// dummy Account
accountB := eth.NewContractEmptyStorage(eth.MIMC_CONFIG, 41, big.NewInt(15353), DummyDigest(75), DummyFullByte(15), 7)
accountB := eth.NewContractEmptyStorage(eth.POSEIDON2_CONFIG, 41, big.NewInt(15353), DummyDigest(75), DummyFullByte(15), 7)
addressB := DummyAddress(47)

// dummy Contract
accountC := eth.NewContractEmptyStorage(eth.MIMC_CONFIG, 48, big.NewInt(9835), DummyDigest(54), DummyFullByte(85), 19)
accountC := eth.NewContractEmptyStorage(eth.POSEIDON2_CONFIG, 48, big.NewInt(9835), DummyDigest(54), DummyFullByte(85), 19)
addressC := DummyAddress(120)

worldstate := eth.NewWorldState(eth.MIMC_CONFIG)
worldstate := eth.NewWorldState(eth.POSEIDON2_CONFIG)
worldstate.AccountTrie.InsertAndProve(addressA, accountA)
worldstate.AccountTrie.InsertAndProve(addressB, accountB)
worldstate.AccountTrie.DeleteAndProve(addressA)
Expand Down
8 changes: 4 additions & 4 deletions prover/backend/execution/statemanager/worldstate.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ package statemanager
import (
"math/big"

"github.com/consensys/linea-monorepo/prover/crypto/poseidon2"
"github.com/consensys/linea-monorepo/prover/crypto/state-management/accumulator"
"github.com/consensys/linea-monorepo/prover/crypto/state-management/hashtypes"
"github.com/consensys/linea-monorepo/prover/crypto/state-management/smt"
"github.com/consensys/linea-monorepo/prover/utils/collection"
"github.com/consensys/linea-monorepo/prover/utils/types"
Expand All @@ -13,8 +13,8 @@ import (

const WS_LOCATION = "0x"

var MIMC_CONFIG = &smt.Config{
HashFunc: hashtypes.Poseidon2,
var POSEIDON2_CONFIG = &smt.Config{
HashFunc: poseidon2.Poseidon2,
Depth: 40,
}

Expand Down Expand Up @@ -74,7 +74,7 @@ func NewContractEmptyStorage(
}
}

var MIMC_EMPTY_STORAGE = EmptyStorageTrieHash(MIMC_CONFIG)
var MIMC_EMPTY_STORAGE = EmptyStorageTrieHash(POSEIDON2_CONFIG)

func NewAccountTrie(config *smt.Config) *AccountTrie {
return accumulator.InitializeProverState[Address, Account](config, WS_LOCATION)
Expand Down
127 changes: 97 additions & 30 deletions prover/protocol/dedicated/bits/bitdecompose.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,75 +6,124 @@ import (
"github.com/consensys/linea-monorepo/prover/protocol/ifaces"
"github.com/consensys/linea-monorepo/prover/protocol/wizard"
"github.com/consensys/linea-monorepo/prover/symbolic"
"github.com/consensys/linea-monorepo/prover/zkevm/prover/common"
)

// BitDecomposed represents the output of a bit decomposition of
// a column. The struct implements the [wizard.ProverAction] interface
// a slice of columns. The struct implements the [wizard.ProverAction] interface
// to self-assign itself.
type BitDecomposed struct {
// Packed is the input of the bit-decomposition
Packed ifaces.Column
// packed is the input of the bit-decomposition
packed []ifaces.Column
// Bits lists the decomposed bits of the "packed" column in LSbit
// order.
Bits []ifaces.Column
isPackedLimbNotZero []ifaces.Column
}

// BitDecompose generates a bit decomposition of a column and returns
// a struct that implements the [wizard.ProverAction] interface to
// self-assign itself.
func BitDecompose(comp *wizard.CompiledIOP, packed ifaces.Column, numBits int) *BitDecomposed {
func BitDecompose(comp *wizard.CompiledIOP, packed []ifaces.Column, numBits int) *BitDecomposed {

var (
round = packed.Round()
bitExpr = []*symbolic.Expression{}
bd = &BitDecomposed{
Packed: packed,
round = packed[0].Round()
bd = &BitDecomposed{
packed: packed,
Bits: make([]ifaces.Column, numBits),
}
)

for i := 0; i < numBits; i++ {
bd.Bits[i] = comp.InsertCommit(round, ifaces.ColIDf("%v_BIT_%v", packed.GetColID(), i), packed.Size(), true)
MustBeBoolean(comp, bd.Bits[i])
bitExpr = append(bitExpr, symbolic.NewVariable(bd.Bits[i]))
bitExpr := []*symbolic.Expression{}

for j := 0; j < numBits; j++ {
bd.Bits[j] = comp.InsertCommit(round, ifaces.ColIDf("%v_BIT_%v", packed[0].GetColID(), j), packed[0].Size(), true)
MustBeBoolean(comp, bd.Bits[j])
bitExpr = append(bitExpr, symbolic.NewVariable(bd.Bits[j]))
}

// This constraint ensures that the recombined bits are equal to the
// original column.
comp.InsertGlobal(
round,
ifaces.QueryID(packed.GetColID())+"_BIT_RECOMBINATION",
symbolic.Sub(
packed,
symbolic.NewPolyEval(symbolic.NewConstant(2), bitExpr),
),
)
for i := 0; i < len(packed); i++ {
bd.isPackedLimbNotZero = append(bd.isPackedLimbNotZero, comp.InsertCommit(round, ifaces.ColIDf("IS_PACKED_NOT_ZERO_%v", i), packed[0].Size(), true))
}

for i := len(packed) - 1; i >= 0; i-- {
ind := len(packed) - i - 1

if ind < len(bd.Bits)/16 {
break
}

comp.InsertGlobal(
round,
ifaces.QueryIDf("%v_BIT_RECOMBINATION", packed[i].GetColID()),
symbolic.Mul(
bd.isPackedLimbNotZero[ind],
symbolic.Sub(
packed[i],
symbolic.NewPolyEval(symbolic.NewConstant(2), bitExpr[ind*16:ind*16+16]),
),
),
)
}

return bd
}

// Run implements the [wizard.ProverAction] interface and assigns the bits
// columns
func (bd *BitDecomposed) Run(run *wizard.ProverRuntime) {

v := bd.Packed.GetColAssignment(run)
bits := make([][]field.Element, len(bd.Bits))

for x := range v.IterateCompact() {
// Obtain packed elements from
var elements [][]field.Element
for i, packed := range bd.packed {

v := packed.GetColAssignment(run)
var packedElements []field.Element
var packedElementsIsZero []field.Element

for colElement := range v.IterateCompact() {
packedElements = append(packedElements, colElement)

isPackedLimbNotZero := field.One()
if colElement.IsZero() {
isPackedLimbNotZero = field.Zero()
}

packedElementsIsZero = append(packedElementsIsZero, isPackedLimbNotZero)
}

run.AssignColumn(bd.isPackedLimbNotZero[i].GetColID(), smartvectors.RightZeroPadded(packedElementsIsZero, bd.packed[0].Size()))

elements = append(elements, packedElements)
}

for i := range elements[0] {
var el []field.Element
for j := range elements {
el = append(el, elements[j][i])
}

x := combineElements(el)

x := x.Uint64()
if !x.IsUint64() {
panic("can handle 64 bits at most")
}

for i := range bd.Bits {
if x>>i&1 == 1 {
bits[i] = append(bits[i], field.One())
xNum := x.Uint64()
for j := range len(bd.Bits) {
if xNum>>j&1 == 1 {
bits[j] = append(bits[j], field.One())
} else {
bits[i] = append(bits[i], field.Zero())
bits[j] = append(bits[j], field.Zero())
}
}
}

for i := range bd.Bits {
run.AssignColumn(bd.Bits[i].GetColID(), smartvectors.FromCompactWithShape(v, bits[i]))
for i, bitCol := range bd.Bits {
run.AssignColumn(bitCol.GetColID(), smartvectors.FromCompactWithShape(bd.packed[0].GetColAssignment(run), bits[i]))
}
}

Expand All @@ -87,3 +136,21 @@ func MustBeBoolean(comp *wizard.CompiledIOP, col ifaces.Column) {
ifaces.QueryID(col.GetColID())+"_IS_BOOLEAN",
symbolic.Sub(col, symbolic.Mul(col, col)))
}

// combineElements combines an array of limb elements into a single element.
// It extracts a specific suffix of bytes from each field.Element
// in the input slice and concatenates them into a single byte slice.
// It then uses this concatenated byte slice to initialize and return a new
// field.Element.
func combineElements(elements []field.Element) field.Element {
var bytes []byte
for _, element := range elements {
elementBytes := element.Bytes()
bytes = append(bytes, elementBytes[len(elementBytes)-common.LimbBytes:]...)
}

var res field.Element
res.SetBytes(bytes)

return res
}
Loading
Loading