Skip to content

feat(avm)!: Unify nullifier, written slots and retrieved bytecodes tree traces#20949

Merged
sirasistant merged 11 commits into
merge-train/avmfrom
arv/unify_generic_indexed_tree_checks
Mar 5, 2026
Merged

feat(avm)!: Unify nullifier, written slots and retrieved bytecodes tree traces#20949
sirasistant merged 11 commits into
merge-train/avmfrom
arv/unify_generic_indexed_tree_checks

Conversation

@sirasistant

Copy link
Copy Markdown
Contributor

Nullifier tree check was a superset of written slots and retrieved bytecodes tree check. Unify all three into the nullifier tree check implementation generalized as "indexed tree check"

@@ -0,0 +1,282 @@
include "merkle_check.pil";

@sirasistant sirasistant Feb 27, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It's the old nullifier check renamed, with internal renamings of nullifier => value, leaf_not_exists renamed to not_exists, parametrized tree height and siloing separator, and exposing tree_size_after_write.

@@ -0,0 +1,398 @@
#include <gmock/gmock.h>

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It's the old nullifier tree check test

@@ -0,0 +1,233 @@
#include "barretenberg/vm2/simulation/gadgets/indexed_tree_check.hpp"

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It's the nullifier tree check renamed and with updated comments and minor changes. Diff it manually.

@@ -0,0 +1,404 @@
#include "barretenberg/vm2/simulation/gadgets/indexed_tree_check.hpp"

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Also the old nullifier gadget test renamed :/

#include "barretenberg/vm2/tracegen/lib/discard_reconstruction.hpp"

namespace bb::avm2::tracegen {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Also the nullifier one renamed with minor changes.

Base automatically changed from arv/pre_audit_nullifier_tree_check to merge-train/avm March 2, 2026 13:24
@sirasistant sirasistant force-pushed the arv/unify_generic_indexed_tree_checks branch from 47d6285 to 2b23284 Compare March 2, 2026 16:27
@sirasistant sirasistant force-pushed the arv/unify_generic_indexed_tree_checks branch from af66ee4 to 5ee027f Compare March 3, 2026 11:11

@MirandaWood MirandaWood left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Amazing stuff 🤩 Great work consolidating all our indexed tree circuits without missing any crucial checks!

Comment on lines +25 to +30
* This gadget is generic and can be used for any indexed tree with just one value per leaf (nullifier tree, retrieved bytecodes tree,
* written public data slots tree, etc.). The caller provides the tree height, and optionally a siloing
* separator and contract address to silo the value before insertion.
*
* Values can be optionally siloed with a contract address to bind them to their originating contract.
* The siloing_separator and address are provided by the caller when sel_silo is set.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nice!!

// ========= HANDLE REDUNDANT WRITES =========
// sel_insert implies sel since write implies sel
pol commit sel_insert; // @boolean (by definition)
sel_insert = write * (1 - exists);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think we can use not_exists rather than 1 - exists here now!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

ah yes!

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Ahh thanks for updating these! Sorry if it was a pain - I smashed these helpers out pretty quickly 😅

});

indexed_tree_check.assert_read(class_id,
std::nullopt,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Small thing (can come later!) - could we comment the nullopts here and in the public data slots simulator? I found myself easily losing track of which optional property was which 😅

bool WrittenPublicDataSlotsTreeCheck::contains(const AztecAddress& contract_address, const FF& slot)
{
FF leaf_slot = compute_leaf_slot(contract_address, slot);
FF leaf_slot = unconstrained_compute_leaf_slot(contract_address, slot);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Just to check my understanding - we now use unconstrained here because the new indexed tree check performs this (constrained) as part of the siloing?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

yep!

Comment thread barretenberg/cpp/pil/vm2/execution.pil Outdated
Comment on lines +791 to +793
// Shared between nullifier_exists.pil and emit_nullifier.pil.
// Lookup constant support: Can be removed when we support constants in lookups.
pol commit nullifier_tree_height;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Sorry another nit - could we clarify here that the constant value is set conditionally in nullifier_exists.pil and emit_nullifier.pil? Even something like // ~Shared between~ Constant height set in nullifier_exists.pil and emit_nullifier.pil. to make it a bit clearer it's not unconstrained anywhere that matters

@sirasistant sirasistant enabled auto-merge (squash) March 4, 2026 11:12
@sirasistant sirasistant disabled auto-merge March 4, 2026 11:19
@sirasistant sirasistant enabled auto-merge (squash) March 5, 2026 15:06
@sirasistant sirasistant merged commit b25f6aa into merge-train/avm Mar 5, 2026
10 checks passed
@sirasistant sirasistant deleted the arv/unify_generic_indexed_tree_checks branch March 5, 2026 15:19
@AztecBot AztecBot mentioned this pull request Mar 5, 2026
github-merge-queue Bot pushed a commit that referenced this pull request Mar 5, 2026
BEGIN_COMMIT_OVERRIDE
fix(avm)!: memory pre-audit (#21058)
fix(avm)!: memory trace changes (#21059)
fix!: AVM was missing range check on remainder for div in ALU (#21074)
feat: run AVM NAPI simulations on dedicated threads instead of libuv
pool (#21138)
feat(avm)!: Unify nullifier, written slots and retrieved bytecodes tree
traces (#20949)
fix(avm)!: public inputs pre-audit (#21162)
END_COMMIT_OVERRIDE
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants