Skip to content

Tracking PR for v0.16.0 release#2976

Draft
bobbinth wants to merge 119 commits into
mainfrom
next
Draft

Tracking PR for v0.16.0 release#2976
bobbinth wants to merge 119 commits into
mainfrom
next

Conversation

@bobbinth

Copy link
Copy Markdown
Contributor

This is a tracking PR for v0.16.0 release.

bobbinth and others added 30 commits May 22, 2026 14:15
* feat: implement Clone for TransactionContextBuilder

* chore: add unwrap_unauthorized_err
* feat(agglayer): reject duplicate GER insertions

Adds a duplicate-detection guard to `bridge_config::update_ger`: after
calling `set_map_item`, the OLD_VALUE returned is compared against
EMPTY_WORD; if it is not empty the GER was already registered and the
transaction panics with ERR_GER_ALREADY_REGISTERED.

Note on Solidity divergence: the Solidity GlobalExitRootManager treats
duplicate GER insertions as idempotent no-ops. Miden intentionally
rejects them because a permanently-unconsumable network note is a worse
failure mode than an explicit transaction revert. This divergence is
documented in SPEC.md.

Docs updated on `update_ger`, the `update_ger.masm` note script, and
SPEC.md (Panics row + Section 2.3 prose). A new integration test
(`update_ger_rejects_duplicate`) verifies that a second UPDATE_GER note
carrying the same GER value is rejected with the expected error code.

Closes #2708

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* chore: add CHANGELOG entry for #2983

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* review: combine padw+assert_eqw and use assert_transaction_executor_error!

- bridge_config.masm: collapse the `padw` / `assert_eqw` pair onto a single
  line as suggested in review.
- tests: replace the manual `is_err()` + `error_msg.contains(...)` block
  with the standard `assert_transaction_executor_error!` macro.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* review: use word::eqz + assert instead of padw + assert_eqw

Slightly cheaper than the `padw`-then-`assert_eqw` pair: `word::eqz`
consumes the 4-felt `OLD_VALUE` and pushes a single 0/1 flag, then a
plain `assert.err=...` verifies it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
The MASM doc-comment and formatting conventions previously captured in
masm_doc_comment_fmt.md are now covered by the .claude/skills/masm-*
skill files plus the MASM formatting tool. Maintaining a separate
hand-written guide is redundant and prone to drift, so remove it.

Closes #2021

Co-authored-by: Claude (Opus) <noreply@anthropic.com>
The protocol does not prevent adding multiple attachments with the same
scheme to a note (e.g. two NetworkAccountTarget attachments). Document
that doing so is discouraged as it brings no additional benefit and only
increases public on-chain data and fees, and clarify in the rustdoc that
the first matching attachment is treated as the canonical one.

Closes #2873

Co-authored-by: Claude (Opus) <noreply@anthropic.com>
* refactor: include leaves number in BURN note ID computation

* Apply suggestions from code review

Co-authored-by: Marti <marcin.gorny.94@protonmail.com>

---------

Co-authored-by: Marti <marti@miden.team>
Co-authored-by: Marti <marcin.gorny.94@protonmail.com>
* Extend execution-error assertion macros with patter and any arms

* Fix formating

* Apply PR review feedback
…k level (#2993)

* feat: reject consuming and creating same note in a tx

* feat: erase notes on the fly

* chore: remove unused `NoteCommitmentMismatch` error variants

* chore: add changelog

* chore: rename input/output note tracker functions

* feat: reintroduce `NoteTracker` for readability

* chore: improve clarity of comments

* chore: format changelog

* chore: add second cross-tx circular dep test
* feat: rename storage delta to patch

* chore: add changelog
* refactor(protocol): relocate TransactionVerifier into miden-protocol

Move TransactionVerifier and TransactionVerifierError from miden-tx to
miden-protocol (transaction module + errors) with no behavior change.
This lets ProposedBatch (in miden-protocol) verify transaction proofs in
a follow-up without a miden-protocol -> miden-tx dependency cycle.

TransactionVerifier is a thin wrapper over types already in
miden-protocol (TransactionKernel, CoreLibrary, miden-verifier), so the
move adds no new dependencies: miden-tx no longer needs miden-verifier,
and miden-tx-batch-prover no longer needs miden-tx. No re-export is kept
from miden-tx (a breaking change to its public surface); in-repo
importers now use miden_protocol::transaction::TransactionVerifier.

* refactor(protocol): verify transaction proofs in ProposedBatch::new

Move per-transaction proof verification from LocalBatchProver into
ProposedBatch construction. ProposedBatch::new now takes a
proof_security_level and verifies each transaction's ExecutionProof (via
the relocated TransactionVerifier) after the structural batch validation,
which is factored into a private new_batch_inner.

A testing-gated new_unverified skips verification for batches built from
mock/dummy-proof transactions. Deserialization reconstructs via
new_batch_inner (no re-verification; documented), so serialized batches
do not require valid proofs to be read back. LocalBatchProver loses its
verify loop and proof_security_level, collapsing to a single prove.

ProposedBatchError gains a typed TransactionVerificationFailed variant;
the now-unused ProvenBatchError::TransactionVerificationFailed is removed.
MockChain and the batch structural tests build via new_unverified.

* Apply suggestions from code review

Co-authored-by: Marti <marcin.gorny.94@protonmail.com>

---------

Co-authored-by: Claude (Opus) <noreply@anthropic.com>
…ss (#2999)

The code-reviewer and security-reviewer agents treat every finding as
blocking, with no notion of deliberately-staged work. A skeleton or
placeholder that is explicitly documented as incomplete, warns against
misuse, and is not wired into a path that relies on the missing behavior
was being flagged as a blocking Critical/Important/Warning, forcing a
bypass of the pre-push gate.

Add a "documented, intentional incompleteness" rule to both agents:
downgrade such a limitation to a Nit/Note (which the pre-push hook does
not block on) when it is documented, warned about, and self-contained;
keep the high severity when the documentation is missing or misleading,
or when the incomplete code is actually reachable from a trust boundary.

Co-authored-by: Claude (Opus) <noreply@anthropic.com>
…2988) (#3005)

* feat(protocol): add active_note::is_public / is_private (#2988)

Cherry-pick the reusable protocol-level building blocks from #2988,
which was merged to the agglayer branch as an agglayer-specific
B2AGG bridge-out hardening:

  - active_note::is_public
  - active_note::is_private

Both procs read the active note's metadata and decode its note
type via the existing note::metadata_into_note_type primitive
(from #2738), then compare against NOTE_TYPE_PUBLIC /
NOTE_TYPE_PRIVATE from miden::protocol::util::note. A parameterized
kernel test covers the Public and Private cases.

The agglayer-only files from #2988 (bridge_out.masm, B2AGG.masm,
tests/agglayer/bridge_out.rs) and the constant-value flip the PR
applied on agglayer's NoteType encoding are intentionally not
brought along: next already encodes Private=0, Public=1, and the
existing metadata_into_note_type is tailored to next's metadata
bit layout.

Co-Authored-By: Claude (Opus) <noreply@anthropic.com>

* fix(agglayer): enforce NoteType::Public for B2AGG bridge-out notes (#2988)

Cherry-pick the bridge-side half of #2988 to next. The B2AGG note
type lives in NoteMetadata, not in the recipient commitment, so an
attacker could submit a note with an identical recipient,
attachment, and asset but NoteType::Private. consensus would accept
it, the leaf would be folded into the on-chain Local Exit Tree, but
aggkit could never recover the pre-image off-chain — the LET mirror
would permanently desync and the bridge-out path would brick.

Add an active_note::is_public assert at the top of bridge_out,
extend the bridge_out and b2agg.masm doc comments, and parameterize
the existing destination-network-is-Miden test into
test_bridge_out_rejects_invalid_b2agg_note covering the
recipient-identical private-note case too.

Co-Authored-By: Claude (Opus) <noreply@anthropic.com>

* Apply suggestions from code review

Co-authored-by: Philipp Gackstatter <PhilippGackstatter@users.noreply.github.com>

* chore: fmt files

---------

Co-authored-by: Claude (Opus) <noreply@anthropic.com>
Co-authored-by: Marti <marti@miden.team>
Co-authored-by: Philipp Gackstatter <PhilippGackstatter@users.noreply.github.com>
…2755)

* Patch crypto with Clones

* Split reader writer impls

* Fix impl read write matching

* Split NullifierTreeBackend reader writer

* Replace write with reader traits

* Lint

* update crypto after revert

* Back to v0.14

* Back to v0.15

* Fix trait bound readers

* Update crypto dep

* Changelog

* Update crypto branch

* Update deps

* Update deps

* Update deps

* Update deps

* Add reader()

* Update deps

* Bump crypto v0.24

* Changelog

* Update changelog

* Move id prefix to smt fn to account id key

* Move account tree impls

* Move nullifier tree impls

* Add AccountTree::with_storage_from_entries

* Changelog

* fix docs

---------

Co-authored-by: Marti <marti@miden.team>
…ng (#3015)

* docs(overview): clarify transaction definition and execution vs proving

* docs(overview): refine transaction definition per review

Address Philipp's review note: a transaction is not always the state
transition of an account. Reframe so account mutation is one of two
possible effects (mutating storage/vault, or creating/consuming notes),
and note that the account need not be mutated at all.

* docs: add changelog entry for #3015
…g tooling (#2997)

* fix(hooks): base pre-push review on the integration branch

The pre-push reviewer derived its diff base from the branch's own
upstream tracking ref (@{u}). For a branch that merged next in, the
merge-base against its pre-merge remote tip swept the entire merged
history into the reviewed diff, so the code-reviewer and
security-reviewer ended up checking all of next instead of just the
branch's own change.

Resolve the review base from the remote default branch (origin/HEAD,
i.e. origin/next) instead. merge-base(HEAD, origin/next) is then the
branch's divergence point, so the reviewed diff is exactly this
branch's contribution, even after merging next in. Adds unit tests
for _diff_base.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Update .claude/hooks/pre_push_review.py

* chore(hooks): drop the _diff_base unit test

Not needed for this change.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(reviewers): diff the integration branch / PR, not the local checkout

Apply the same diff-base correction this PR makes to pre_push_review.py
across the agents it spawns and the changelog agent:

- code-reviewer / security-reviewer diffed `@{upstream}...HEAD`, which (like
  the hook before this PR) drags the whole merged history into the review once
  the integration branch is merged in. Point them at the remote default branch
  (`origin/HEAD`) instead.
- changelog-manager classified a local `git diff origin/next...HEAD`, which
  analyzes whatever branch the cwd is on rather than the PR being created.
  Classify `gh pr diff <N>` instead, so it always sees the PR's own diff (this
  also fixes creating a PR for one branch from a worktree on another).

---------

Co-authored-by: Claude (Opus) <noreply@anthropic.com>
… review (#3024)

Co-authored-by: Claude (Opus) <noreply@anthropic.com>
* feat: add skeleton batch kernel + ProvenBatch proof field

Establishes the public input/output contract for the batch kernel (#1122)
plus the Rust plumbing that surrounds it, without any verification logic.

- main.masm drops TRANSACTIONS_COMMITMENT + BLOCK_HASH and exits; the VM's
  depth >= 16 invariant leaves the all-zero 16-felt output region in place.
- BatchKernel struct exposes prepare_inputs / build_input_stack /
  build_output_stack / parse_output_stack; build_advice_inputs returns the
  default empty AdviceInputs since the skeleton ignores advice data.
- ProvenBatch carries a proof: ExecutionProof field through
  new_unchecked and serde.
- LocalBatchProver::prove now runs the kernel via miden_prover::prove and
  attaches the proof to the returned ProvenBatch. The kernel's public
  outputs are not yet cross-checked against the proposed batch; that lands
  with the verification logic.
- prove_dummy retained for tests that don't want proof generation.

Smoke test exercises the full plumbing: builds a realistic two-transaction
ProposedBatch, runs the kernel via FastProcessor, asserts the parsed
outputs are empty / zero.

TODO list in main.masm enumerates the checks the verification PR will
introduce.

* Apply suggestions from code review

Co-authored-by: Marti <marcin.gorny.94@protonmail.com>

* chore(protocol): drop premature BATCH error category

The batch kernel is compiled separately and its MASM errors are not
extracted by generate_error_constants (which only scans the transaction
kernel dir), so the BATCH entry in TX_KERNEL_ERROR_CATEGORIES is inert.
Batch error handling will be added properly alongside the verification
logic.

* refactor(protocol): order build_input_stack params to match stack layout

Pass transactions_commitment before block_hash so the parameter order
matches the documented input stack [TRANSACTIONS_COMMITMENT, BLOCK_HASH].
Also drop the now-stale reference to the main.masm TODO from the
BatchKernel doc comment.

* refactor(batch-prover): remove unused proof_security_level accessor

The getter had no callers.

* refactor(protocol): simplify batch output padding check

Replace the two separate pad-word checks with a single scan over every
cell after batch_expiration_block_num, dropping the EXPIRATION_PAD_WORD_*
and TRAILING_PAD_WORD_FELT_IDX constants.

* test(batch): reuse shared chain setup helpers

Expose TestSetup and setup_chain from the proposed_batch test module and
reuse them in the batch kernel smoke test instead of re-implementing the
identical TestSetup/setup/generate_account fixtures.

* docs: trim verbose batch kernel CHANGELOG entry

* refactor(protocol): name batch kernel inputs BATCH_ID and BLOCK_COMMITMENT

Rename the batch kernel's public inputs from TRANSACTIONS_COMMITMENT to
BATCH_ID (consistent with the `BatchId` type the value comes from) and
from BLOCK_HASH to BLOCK_COMMITMENT (we no longer use "hash"). Trim the
over-detailed BATCH_ID doc comment down to just referencing `BatchId`.

Addresses review comments on PR #2904.

* refactor(protocol): use Felt::ZERO associated constant

Prefer the associated constant `Felt::ZERO` over the bare `ZERO` import
in the batch output padding check.

Addresses a review comment on PR #2904.

* refactor(protocol): type batch kernel errors instead of stringifying

Stringifying the kernel error via `to_string` discarded the source error
chain. Wrap the real source instead: `BatchKernelExecutionFailed` now
carries `#[source] ExecutionError`, and a dedicated
`BatchKernelOutputInvalid(#[source] BatchOutputError)` variant covers
output-stack parsing failures. The batch prover maps these directly.

Addresses a review comment on PR #2904.

* test(batch): rename batch_kernel module to test_batch_kernel

Adopt the `test_*` naming used by `kernel_tests/tx/test_*.rs` so the
`kernel_tests::batch::batch_kernel` path is no longer redundant and
future per-feature batch kernel test modules slot in consistently.

Addresses a review comment on PR #2904.

* chore: shorten comment

* chore: fmt

* refactor(batch-prover): split batch execution and proving

Separate batch kernel execution from proof generation, mirroring the
transaction flow's ExecutedTransaction:

  ProposedBatch -> BatchExecutor::execute -> ExecutedBatch
  ExecutedBatch -> LocalBatchProver::prove -> ProvenBatch

`BatchExecutor::execute` runs the batch kernel (via the synchronous trace
APIs, `execute_trace_inputs_sync`), validates the output stack shape, and
returns an `ExecutedBatch` holding the trace inputs. `LocalBatchProver`
now consumes an `ExecutedBatch` and only builds the trace + proof (via
`prove_from_trace_sync`), so the flow is fully synchronous. Transaction
proofs are already verified in `ProposedBatch::new`, so the executor does
not re-verify them.

This lets tests exercise raw batch execution without re-proving. The
batch kernel smoke test now goes through `BatchExecutor`, removing the
inline FastProcessor setup, and a new test covers the execute -> prove
path.

Addresses review comment T19 on PR #2904.

* Update crates/miden-tx-batch-prover/src/batch_executor.rs

* refactor(protocol): return a BatchOutput from parse_output_stack

Introduce a `BatchOutput` type (mirroring `TransactionOutputs`) that
encapsulates the batch kernel's parsed outputs — input/output note
commitments and the batch expiration block number — instead of returning
a raw `(Word, Word, BlockNumber)` tuple. The output-stack layout indices
move onto `BatchOutput` as associated constants.

Addresses review comment T15 on PR #2904.

* refactor(protocol): put BLOCK_COMMITMENT on top of the batch input stack

Order the batch kernel's public inputs as [BLOCK_COMMITMENT, BATCH_ID]
to stay consistent with the transaction kernel's input layout.

Addresses a review comment on PR #2904.

* refactor(protocol): name the batch output BATCH_NOTE_TREE_ROOT

Rename the batch kernel's second output from OUTPUT_NOTES_COMMITMENT to
BATCH_NOTE_TREE_ROOT (and the `BatchOutput` field/accessor/layout const
accordingly). The end-goal output is the root of the batch's note tree,
which lets the block kernel aggregate per-batch note trees instead of a
flat output-notes commitment; renaming now fixes the contract name even
though the value is still wired up in a follow-up.

Addresses a review comment on PR #2904.

* refactor(batch): strong-type build_input_stack batch_id param

Take `BatchId` instead of a raw `Word` so the input contract is expressed
through the domain type.

* refactor(batch): rename BatchOutput to BatchOutputs

The type holds multiple outputs; rename it for consistency with
`TransactionOutputs`.

* refactor(batch): move output parsing onto BatchOutputs and return errors

Replace `BatchKernel::parse_output_stack` with `BatchOutputs::parse`, and
return `BatchOutputError::OutputStackInvalid` instead of panicking when a
required output word or element is missing from the stack.

* refactor(batch): expose typed BatchOutputs from ExecutedBatch

Store the parsed `BatchOutputs` on `ExecutedBatch` and expose it via a
typed `batch_outputs()` accessor, replacing the raw `stack_outputs()`.

* test(batch): cover BatchOutputs::parse error branches

Add unit tests for the well-formed stack, non-zero padding rejection, and
oversized expiration block number rejection.

* Apply suggestion from @mmagician

---------

Co-authored-by: Claude (Opus) <noreply@anthropic.com>
…3032)

Adds a regression test that pushes a marker word before calling
active_note::get_metadata and asserts the metadata word is added directly
on top of it. This catches the regression where an empty NOTE_ATTACHMENT
word leaked onto the stack alongside the metadata.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…d` traits (#3009)

* refactor: unify account/nullifier SMT backends into shared SmtBackend traits

Replaces the near-identical AccountTreeBackend/NullifierTreeBackend trait
pairs with a single Word-valued SmtBackendReader + SmtBackend pair, impl'd
once for Smt and once for LargeSmt. The NullifierBlock value wrapping moves
from the backend into NullifierTree's own accessors, leaving the backend
layer value-agnostic. Removes both per-tree backend.rs modules.

* test: add reader() coverage; fix changelog and backend docs

Addresses pre-push review findings on the SMT backend unification:
- correct the CHANGELOG entry to name the shared SmtBackend/SmtBackendReader
  traits instead of the removed per-tree reader traits
- disambiguate the writer-impl section headers in smt_backend.rs
- document that with_storage_from_entries panics (not errors) on storage
  failures, matching large_smt_error_to_merkle_error behavior
- add reader() tests asserting the read-only view shares root and entries

* refactor: unify duplicate-entry error handling across account backends

Removes the redundant AccountTreeError::DuplicateEntries variant and maps
the LargeSmt-backed with_storage_from_entries duplicate case through the same
prefix-extracting helper as the Smt-backed with_entries, so both constructors
surface DuplicateStateCommitments { prefix }. Adds a duplicate-entry test,
documents the read-only reader() invariant, and aligns the leaves()/entries()
lifetime style.

* docs: reference PR #3009 in changelog entry

* test: drop tautological reader_matches_source_tree tests

These only asserted that a freshly created reader view equals its source,
which exercises no meaningful logic. The duplicate-entry test (real error
path) is kept.

* Apply suggestions from code review

Co-authored-by: Marti <marcin.gorny.94@protonmail.com>

* docs: fix unresolved intra-doc links in SmtBackendReader

Use inline `[`leaves`](Self::leaves)` / `[`entries`](Self::entries)` links
instead of reference-style links, which rustdoc failed to resolve under
`-D warnings`.

---------

Co-authored-by: Claude (Opus) <noreply@anthropic.com>
Co-authored-by: Bobbin Threadbare <43513081+bobbinth@users.noreply.github.com>
* feat(batch-prover): verify batch kernel execution proofs

Add `BatchVerifier`, the verification counterpart to `LocalBatchProver`.
It reconstructs the batch kernel's public input stack from a
`ProvenBatch` (`BatchId` + reference block commitment) and verifies the
attached `ExecutionProof` against the batch kernel program via
`miden_verifier::verify`.

The skeleton kernel emits the all-zero output region, so verification
checks the proof against that empty-output contract; binding the batch's
real commitments lands with the kernel verification logic. The verifier
is documented as not yet usable at a trust boundary.

Tests build a real batch proof via `BatchExecutor` + `LocalBatchProver`
and cover the positive path (verify + insufficient-security-level
rejection) and the negative path (dummy proof rejected).

* refactor(batch-prover): align BatchVerifier with new input order

Adapt the verifier to the base-branch changes merged in: feed the kernel
public inputs as [BLOCK_COMMITMENT, BATCH_ID] (matching the reordered
build_input_stack signature) and update the docs/comments to reference the
batch note tree root output.

* test(batch-prover): assert against the proof's actual security level

Use proven.proof_security_level() in the accept test: requiring exactly
that level succeeds and requiring one more bit fails, instead of the
arbitrary 0 / u32::MAX bounds.

* refactor(protocol): replace build_output_stack with BatchOutput::into_stack_outputs

Encoding a BatchOutput into the kernel's output stack belongs on BatchOutput
itself, mirroring BatchKernel::parse_output_stack (the inverse) and reusing the
layout constants it already owns. The verifier now constructs a typed all-zero
BatchOutput and converts it, which reads more clearly than passing three loose
words to a free function.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
(cherry picked from commit 9e91ae3)

* fix(batch-prover): pass BatchId to build_input_stack after rebase

next changed BatchKernel::build_input_stack to take a BatchId instead of a
Word; the rebased BatchVerifier still passed batch.id().as_word(), which broke
the build. Pass batch.id() directly.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude (Opus) <noreply@anthropic.com>
* init

* changelog

* collapse constructors into custom

* add bon builder

* lint

* remove panic add error

* apply suggestions

* add AccountComponent::has_procedure

---------

Co-authored-by: Bobbin Threadbare <43513081+bobbinth@users.noreply.github.com>
* feat: Add `AccountPatch` and `AccountVaultPatch`

* feat: track vault updates for both delta and patch

* chore: return initial asset value from asset_vault proc

* chore: track initial and final asset values

* chore: add changelog

* fix: broken doc link

* chore: unify separate maps in vault tracker into one

* chore: new_nonce -> final_nonce, old_nonce -> initial_nonce

* chore: move AccountStoragePatch to patch module

* chore: remove buggy `assets` iterator

* chore: leave note for why headers are appended

* chore: vault_patch -> vault

* chore: simplify `is_empty` impl

* chore: clarify asset value / empty word in patch docs

* chore: `AccountDeltaTracker` -> `AccountUpdateTracker`

* feat: domain-separate delta and patch commitment headers

Add distinct domain separators to the headers of `AccountDelta` and
`AccountPatch` commitments so the two contexts can never collide,
even when their bodies are identical. The asset, value-slot, and
map-slot domains are renumbered to 3/4/5 to leave 1/2 reserved for
the delta/patch headers, and the shared constants are centralized in
a new `commitment_domain` module.

* fix: docs on with_assets

* fix: lower case domain_delta

* fix: invert vault patch normalization to drop unchanged entries

* chore: name add_asset/remove_asset output FINAL_ASSET_VALUE

---------

Co-authored-by: Claude (Opus) <noreply@anthropic.com>
* add active_account::has_storage_slot

* changelog

* fix comment
* refactor: cycle count golfing

* chore: add changelog
* add min burn amount policy

* changelog

* apply suggestions

---------

Co-authored-by: Bobbin Threadbare <43513081+bobbinth@users.noreply.github.com>
* use active_account::has_storage_slot

* add invoke_{send/receive}_policy

* changelog

---------

Co-authored-by: Bobbin Threadbare <43513081+bobbinth@users.noreply.github.com>
* feat: hash AssetVaultKey before insertion into asset vault SMT

Two non-fungible assets issued by the same faucet share the third element
of their raw AssetVaultKey (the faucet ID suffix), which the SMT uses to
determine leaf membership. Without hashing, they always landed in the same
leaf, risking the per-leaf cap and harming tree balance.

Mirrors the existing raw-key/hashed-key pattern used by StorageMap:
- AssetVaultKey::to_smt_key() returns Poseidon2 hash of the raw key.
- AssetVault and PartialVault store the SMT keyed by hashed keys, plus a
  BTreeMap<AssetVaultKey, Word> of raw keys for iteration and proofs.
- AssetWitness carries both the SmtProof and the raw key(s) it covers.
- The MASM kernel injects exec.poseidon2::hash before every smt::set,
  smt::get, smt::peek in asset_vault.masm (same as hash_map_key in
  account.masm).

Closes #2518.

* chore: add CHANGELOG entry for #2912

* fix: address review feedback on AssetVaultKey hashing

- Make `PartialVault::add` atomic: extend `entries` only after SMT proof
  insertion succeeds, preserving the entries-subset-of-SMT invariant on
  error.
- Filter zero-amount fungible assets out of `AssetVault::new`'s `entries`
  map so the map and the underlying SMT stay in sync (the SMT treats
  empty values as no-ops).
- Correct the suffix/prefix wording: `LeafIndex<Word>` uses `value[3]`,
  which is the faucet ID prefix, not the suffix. Fixed in
  `vault_key.rs`, `vault/mod.rs` doc + test, and `docs/src/asset.md`.
- Tighten `AssetWitness::new_unchecked`: document the proof-vs-pair
  precondition explicitly and `debug_assert!` it.
- Add `PartialVault::with_witnesses` and `PartialVault::add` tests:
  happy-path (with round-trip serialization for `with_witnesses`) and
  root-mismatch failure paths (the `add` failure doubles as a regression
  test for the atomicity fix above).

* refactor: address PhilippGackstatter's review on AssetVaultKey hashing

- Rename `AssetVaultKey::to_smt_key` to `hash` and have it return a new
  `AssetVaultKeyHash` newtype (mirrors `StorageMapKey::hash` ->
  `StorageMapKeyHash`). Updates all call sites and the MASM
  `hash_asset_key` doc to point at `AssetVaultKey::hash`.
- Restrict `AssetWitness::entries` to `pub(super)`; it is an internal
  helper used by `PartialVault` and not part of the public surface.
- Rework `Deserializable for PartialVault` to use `read_many_iter` for
  `num_entries` (protects against unbounded length prefixes) and route
  through a new private `from_partial_smt_and_keys` constructor that
  performs the per-entry validation. Repurposes the previously-dead
  `PartialAssetVaultError::InvalidAssetInSmt` variant as
  `InvalidAssetForKey { key, value, source }`.

* Update crates/miden-protocol/asm/kernels/transaction/lib/asset_vault.masm

Co-authored-by: Philipp Gackstatter <PhilippGackstatter@users.noreply.github.com>

* fix: budget post-compute-fee cycles for vault key hashing

Hashing the AssetVaultKey before the asset vault SMT set adds a fixed
cost to the fee-removal smt::set in the epilogue, pushing the measured
post-compute-fee cycle count (863) past the old estimate (858).

Add a dedicated VAULT_KEY_HASH_CYCLES=50 constant (in epilogue.masm and
the mirrored test) rather than inflating SMT_SET_ADDITIONAL_CYCLES, whose
documented meaning is smt::set's worst-minus-best spread. The fee
estimate stays a safe upper bound (608+250+50=908 > 863).

* refactor: address Fumuran's review on asset_vault MASM

- Move hash_asset_key into a HELPER PROCEDURES section at the bottom of
  asset_vault.masm and add a set_asset helper that hashes the key
  internally, replacing the four duplicated hash + smt::set call sites.
- Shorten the ESTIMATED_AFTER_COMPUTE_FEE_CYCLES doc comment in
  epilogue.masm.

* refactor: address review comments on asset vault SMT hashing

- Remove AssetVaultKey::to_leaf_index; callers now use hash().to_leaf_index()
- AssetWitness: trim new_unchecked docs, use read_many_iter in read_from, add
  into_parts() used by PartialVault::add
- PartialVault: validate (key, value) pairs even when empty and filter empty
  values out of entries across all constructors (mirrors AssetVault::new); add
  a public assets() iterator, gate entries() to tests, and have leaves() drop
  the leaf index; add a constructor validation test
- Simplify TransactionInputs::read_vault_asset via read_vault_asset_witnesses
- asset_vault.masm: drop the `...` placeholder from set_asset stack comments
- Trim PR-level wording from the AssetVault doc comment

* Update CHANGELOG.md

Co-authored-by: Marti <marti@miden.team>

* Update crates/miden-protocol/src/asset/vault/vault_key.rs

Co-authored-by: Marti <marti@miden.team>

* Update crates/miden-protocol/src/asset/vault/vault_key.rs

Co-authored-by: Marti <marti@miden.team>

* rename HASHED_ASSET_KEY stack comments to ASSET_KEY_HASH

* clarify read_vault_asset error vs None semantics

* fix: insert into asset_tree before mutating entries in insert_entry

Keeps the raw-entry map and SMT in sync if the fallible SMT insert fails.

* use expect over indexing for single witness; clarify collision-test comment

---------

Co-authored-by: Claude (Opus) <noreply@anthropic.com>
Co-authored-by: Philipp Gackstatter <PhilippGackstatter@users.noreply.github.com>
Co-authored-by: Marti <marti@miden.team>
…3061)

* feat: recompute batch ID on deserialization

* chore: add changelog

* chore: add RUSTSEC-2026-0173 to deny.toml
* feat(mockchain): support private note attachments

* chore: changleog

* chore: comment
onurinanc and others added 30 commits July 1, 2026 19:38
…SigAcl` refactor (#3180)

* remove all_authority_gated_setter_roots after AuthSingleSigAcl refactor

* changelog

---------

Co-authored-by: Bobbin Threadbare <43513081+bobbinth@users.noreply.github.com>
…k proving phase (#3152)

* refactor: use Poseidon2 as a hash function during the proving benchmarks

* chore: update changelog

* fix: add ECDSA benchmark variants and restructure time-counting IDs

Addresses PR #3152 review feedback:
- Add ECDSA variants for every signature-authenticated benchmark (two P2ID,
  create P2ID) in both the cycle-counting and time-counting suites; single P2ID
  already had both. CLAIM/B2AGG authenticate the bridge account via network auth
  (no signature), so they keep a single variant.
- Build the time-counting Criterion IDs programmatically so they encode the
  signing scheme and the proving hash function, e.g.
  'Execute and prove transaction/poseidon2-falcon/single-p2id-note' and
  'Execute and prove transaction/poseidon2/claim-note-l1'.
- Regenerate bench-tx.json, refresh README examples, update CHANGELOG and the
  trace-contract test expectations.

* fix: make Poseidon2 the default LocalTransactionProver hash function

Addresses PR #3152 review: instead of a Poseidon2-specific convenience
constructor, change the prover default itself. Remove the with_poseidon2()
and with_blake3() constructors and give LocalTransactionProver a manual
Default impl that uses Poseidon2; the benchmark now proves via
LocalTransactionProver::default().

* chore: update changelog

* chore: update the format of the bench-transaction README, update the benchmark example

* fix: split hash and signing into separate benchmark ID segments

Addresses PR #3152 review: the execute-and-prove IDs now read
'poseidon2/falcon/single-p2id-note' instead of 'poseidon2-falcon/...',
keeping the hash function and signing scheme as distinct path segments.

* chore: update readme

---------

Co-authored-by: Claude (Opus) <noreply@anthropic.com>
Co-authored-by: Bobbin Threadbare <43513081+bobbinth@users.noreply.github.com>
* feat: add `@account_procedure` to define account component interface

* review: simplify `AccountComponentCode`

* review: add TODO on components that should use call invocation
* chore: replace `dummy` with `AccountIdBuilder`

* feat: add immutable callback flag to account ID

* chore: add changelog

* chore: address review comments

* chore: address review comments
* docs(notes): clarify purpose, serial number, and nullifier terms

Address the outstanding items from the Notes page review and align
terminology with the current (v0.15) protocol:

- Purpose & scope: enumerate the three roles of a note (asset
  transfer, account notification via note presence, and account
  state change via the note's storage) rather than implying notes
  are only for asset transfers.
- Serial number: replace the one-line explanation with the
  commitment/nullifier framing, introducing both concepts before
  describing how the serial number guarantees uniqueness and
  protects privacy. Uses "commitment" terminology throughout.
- Nullifier: define each term in the nullifier formula
  (SERIAL_NUM, SCRIPT_ROOT, STORAGE_COMMITMENT, ASSET_COMMITMENT,
  METADATA, ATTACHMENTS_COMMITMENT), grounded in Nullifier::new,
  and fix a remaining "note's hash" reference to "note's commitment".
- Note tag: correct the SWAP tag example from "2 bits" to "1 bit"
  of the note's type, reflecting the NoteType 1-bit encoding
  introduced in v0.15.0.

The original "define vault_hash" item is obsolete: the nullifier
formula was rewritten and vault_hash no longer appears on the page.
Note tag composition is already documented under Note discovery.

* docs: add changelog entry for #3016

* docs(notes): address review — note ID terminology, nullifier accuracy, purpose framing

Incorporate @PhilippGackstatter's review:
- Collapse the note-purpose list to two items and reframe the second as
  'invoking an account's public procedures' (a note acts through the
  account interface via its script, it does not passively mutate state).
- Keep the Serial number section focused; drop the inline commitment/
  nullifier concept dump and link to the nullifier section instead.
- Fix the privacy claim: a leaked serial number alone cannot recompute a
  nullifier, since the nullifier depends on all note components.
- Note that the nullifier is itself a commitment to the note, computed
  differently from the note ID so neither derives from the other.
- Use 'note ID' consistently (the term formerly called 'note commitment').

* docs(notes): fix broken attachments anchor in nullifier component list

* docs(notes): state the serial-number/nullifier privacy property directly

Reword the serial-number Privacy bullet and the nullifier closing
paragraph so they read as neutral documentation for a first-time reader
rather than qualifications aimed at a specific concern. Same facts: the
serial number is one of the nullifier's secret inputs, and a private
note's components are never exposed to the operator.
* clear pending nomination on renounce_ownership

* build ownership word in save order in accept_ownership

* assert owner is non-zero in accept_ownership

* changelog

* reverse nomination check removal

* add account_id::eqz helper

* merge next
* feat: migrate standards to miden-project

* feat: migrate standards to miden-project

Migrate the miden-standards crate to the miden-project build model, matching
the protocol crate migration.

- Restructure asm/account_components into per-component miden-project.toml
  projects under asm/components, and turn the standards library into a project
  rooted at standards/mod.masm.
- Rework the build script to assemble each project into a MAST package (.masp)
  via a package registry seeded with the protocol, tx-kernel and core packages,
  replacing the previous .masl library assembly.
- Load shipped components/library from .masp packages instead of .masl, and
  update account_component_code! to reference packages by name.

* review: add standards workspace

* review: omit mod on component name

* review: rename `TransactionKernel::package()`

* review: fix cargo shear

* chore: changelog

* review: assemble whole workspace, add `miden-project` build ep

* review: small changes
* Upgrade Miden VM and crypto dependencies

* Address dependency upgrade review findings

* Validate kernel API offset exports

* Preserve package debug info after MAST upgrade

* Tighten dependency upgrade cleanup

* chore: Changelog

* Fix dependency upgrade CI

* Fix package rustdoc links

* Exclude transaction benchmark from no-std build

* Restore transaction benchmark no-std build

* chore: explain transaction bench feature gate

* chore: tighten MASM imports

* Fix rebase fallout

* Address dependency upgrade rebase fallout

* Address review feedback

* test: preserve debug output during execution

* fix: repair dependency upgrade build

* fix: address package upgrade review feedback

* fix: address follow-up review comments
…nd `Rbac` components (#3205)

* align ownable2step and rbac procedure ordering

* document sender-based access control's authentication assumption

* changelog
* feat: migrate transaction scripts to library and add
`@transaction_script` attribute

* review: use TRANSACTION_SCRIPT_ATTRIBUTE constant

* review: add `TransactionScript::from_library_reference`

* review: test script formatting

* review: use `TransactionScript::from_library` and
`NoteScript::from_library`

* chore: fmt
* review: use `account_component_code!` macro

* review: move and rename pausable mod

---------

Co-authored-by: Bobbin Threadbare <43513081+bobbinth@users.noreply.github.com>
* chore: use `CoreLibrary` package directly

* chore: inline registry construction in build.rs
…Id` (#3186)

* refactor: rename `AssetId` to `AssetClass`

Renames the within-faucet asset discriminator type `AssetId` to
`AssetClass`, freeing up the `AssetId` name for the vault key rename.
Updates the type, its field/accessor on the vault key, error variants,
MASM procedures and error constants, and the docs.

Part of #3079.

* refactor: rename `AssetVaultKey` to `AssetId`

Renames the asset vault key type to `AssetId` (and `AssetVaultKeyHash`
to `AssetIdHash`), so an asset is identified by an `AssetId` just as
accounts and notes are identified by `AccountId` and `NoteId`. The
`Asset::vault_key()` accessor becomes `Asset::id()`, the `vault_key`
identifiers and `vault key` prose become `asset_id` / asset ID across
Rust, MASM and docs, and the `FungibleAssetInconsistentVaultKeys` error
variant becomes `FungibleAssetInconsistentIds`.

The MASM asset-key naming is correspondingly renamed to asset ID: the
stack words `ASSET_KEY`/`ASSET_KEY_HASH` become `ASSET_ID`/`ASSET_ID_HASH`,
the procedures `hash_asset_key`, `is_fungible_asset_key` and
`is_non_fungible_asset_key` become `hash_asset_id`, `is_fungible_asset_id`
and `is_non_fungible_asset_id`, and the `ERR_*_ASSET_KEY_*` error
constants and `asset_key` identifiers follow suit across MASM, the inline
MASM in tests, and the docs.

Closes #3079.

* fix: address review comments on asset ID rename

---------

Co-authored-by: Bobbin Threadbare <43513081+bobbinth@users.noreply.github.com>
…fixes (#3209)

* follow slot naming convention for authority config slot

* express authority kind as a MASM enum

* enforce canonical authority config word on read

* changelog

---------

Co-authored-by: Bobbin Threadbare <43513081+bobbinth@users.noreply.github.com>
* add account_id::validate_structure

* changelog
* add MockTransactionBuilder and migrate few test to MockChain::build_transaction

* Refine MockTransactionBuilder API and docs after review comments

* rename MockTransactionBuilder output-note methods to expected_output_note(s)

* fix:remove debug mode from MockTransactionBuilder after merging next
* feat(agglayer): add faucet deregistration

Adds a bridge-admin-gated `deregister_faucet` MASM procedure that revokes a
faucet, clearing every entry registration wrote for it: the `faucet_registry_map`,
`token_registry_map`, and all four `faucet_metadata_map` sub-keys. Wired through a
new `DEREGISTER_AGG_BRIDGE` note script and a `DeregisterAggBridgeNote` Rust
builder. After deregistration, in-flight B2AGG and CLAIM notes referencing the
cleared faucet fail their existing registration checks.

The token registry is pair-keyed on (origin_token_address, origin_network). Rather
than trusting note-supplied values, `deregister_faucet` reads the faucet's
registered address and network back from its own `faucet_metadata_map` (via
`get_faucet_conversion_info`) and recomputes the key, so the cleared token-registry
entry is provably the one `register_faucet` wrote and the two registries cannot
desynchronize. The note therefore carries only the faucet id (2 felts).

- bridge_config.masm: new `deregister_faucet` proc reusing
  `assert_sender_is_bridge_admin`, `assert_faucet_registered`,
  `get_faucet_conversion_info`, and `hash_token_address`.
- components/bridge.masm: re-export `deregister_faucet`.
- note_scripts/deregister_agg_bridge.masm: new note script.
- src/deregister_note.rs: new `DeregisterAggBridgeNote` builder.
- bridge.rs: add the DEREGISTER script root to the network-account note allowlist.
- tests/agglayer/config_bridge.rs: round-trip test verifying all three maps are
  cleared, an end-to-end test proving the faucet is revoked, and negative tests for
  `ERR_FAUCET_NOT_REGISTERED` and `ERR_SENDER_NOT_BRIDGE_ADMIN`.
- SPEC.md, CHANGELOG.md: documentation updates.

* Update crates/miden-agglayer/asm/agglayer/bridge/bridge_config.masm

Co-authored-by: Marti <marti@miden.team>

* Apply suggestions from code review

Co-authored-by: Marti <marcin.gorny.94@protonmail.com>

* refactor(agglayer): rename DEREGISTER_AGG_BRIDGE to DEREGISTER_AGG_FAUCET

The note deregisters a faucet, not the bridge, so the name was misleading.
Renames the note script file, its constants and error codes, the
DeregisterAggFaucetNote Rust builder, the script-root allowlist entry, and
all doc/spec references. Addresses review feedback.

* docs(agglayer): trim verbose comments in deregistration code

Address review feedback on over-verbose, self-explanatory comments:
- bridge_config.masm: condense the deregister_faucet doc, drop the numbered
  list that restated the prose with concrete slots, shorten the stale-key
  caveat, document the locals (#! Locals:), and remove the claim_note.rs aside.
- deregister_agg_faucet.masm: drop the rationale paragraph and the redundant
  'Where:' block that repeated the storage layout.
- bridge_in.masm: shorten the claim re-check comment.
- deregister_note.rs: trim the struct and builder docs.

* docs(agglayer): condense deregistration prose in SPEC and CHANGELOG

Address review feedback that the deregistration descriptions are too verbose:
- SPEC 3.1: halve the deregister_faucet step list and fold the stale-key caveat
  into a single sentence.
- SPEC 7.1: shorten the deregistration paragraph to a summary plus a cross-link
  to section 4.4, dropping mechanism detail already covered there.
- CHANGELOG: tighten the entry to two sentences.

* docs(agglayer): fix off-by-one stack comments in deregister_faucet

The stack-layout annotations in the token_registry clearing section summed to
15 (and the KEY/VALUE windows were mislabeled), as flagged in review. Recount
each '# =>' window to a full 16 elements.

* refactor(agglayer): loop over faucet_metadata sub-keys in deregister_faucet

Replace the four near-identical set_map_item blocks that clear the metadata
sub-keys with a single repeat.4 loop over the consecutive sub-key constants,
and use padw instead of push.0.0.0.0 for the cleared values. Addresses review
feedback; behavior is unchanged (deregister tests still pass).

* test(agglayer): bundle deregister failure cases with rstest

Merge test_deregister_agg_faucet_fails_when_not_registered and
_fails_when_sender_not_admin into a single rstest parameterized over
(register_first, sender_is_attacker, expected_err). Addresses review feedback.

* docs(agglayer): reword awkward 'register_faucet wrote' phrasing

* test(agglayer): fold revocation case into the deregister rstest

Merge test_deregister_agg_faucet_revokes_registration into the
test_deregister_agg_faucet_rejects_invalid rstest as an `already_deregistered`
case (new `deregister_first` parameter that performs a prior successful
deregistration before the asserted attempt).

* docs(agglayer): simplify deregister_faucet header and loop spacing

Drop the token_registry key-derivation and stale-key paragraphs from the
deregister_faucet header comment (both are covered in SPEC 3.1 and the
bridge_in.masm claim re-check), and add blank lines after the stack-layout
comments in the metadata-clearing loop to match the file's style.

* docs(agglayer): condense the metadata-clearing loop comment to one line

* feat(agglayer): clear prior token key on faucet re-registration

register_faucet now clears a faucet's previous token_registry key when the
same faucet is re-registered under a different (origin_token_address,
origin_network). It reads the prior (address, network) from the
not-yet-overwritten faucet_metadata and clears the derived key before writing
the new entry, so a token_registry key never outlives the registration that
created it.

This fixes the stale-key case at its source: deregister_faucet only has the
faucet's current metadata and could not reach a stale key. The claim-side
assert_faucet_registered re-check is kept as defense-in-depth (and its comment
reworded accordingly). Adds a new is_faucet_registered helper.

Replaces test_claim_rejects_deregistered_faucet_via_stale_token_key with
test_reregister_clears_prior_token_key, which asserts a CLAIM via the prior
network's token key is rejected with ERR_TOKEN_NOT_REGISTERED after
re-registration.

* docs(agglayer): condense the deregistration paragraph in section 7.1

The section 4.4 chapter already covers what DEREGISTER_AGG_FAUCET clears and
the in-flight-note warning, so trim the section 7.1 mention to its first
sentence plus the cross-reference.

* docs(agglayer): reword the token-key clearing comment

Frame the cleared key as "potentially populated from a prior registration"
rather than tying it to re-registration, since the if.true guard means it is
only present when the faucet was already registered.

* docs(agglayer): trim redundant tail of the token-key clearing comment

Drop the sentence restating the consequence and the metadata read; both are
already conveyed by the first sentence and the get_faucet_conversion_info call
immediately below.

* docs(agglayer): fix pad counts and multi-element notation in stack comments

Stack trackers in the re-registration block and deregister_faucet treated
the bottom padding as a pool that shrinks when values are pushed; count
the persistent pads physically instead, and use addr(5) span notation
per review feedback.

---------

Co-authored-by: Bobbin Threadbare <43513081+bobbinth@users.noreply.github.com>
Co-authored-by: Marti <marti@miden.team>
Co-authored-by: Marti <marcin.gorny.94@protonmail.com>
)

* reject zero version in

* changelog

* chore: fix lint

* chore: fix build

---------

Co-authored-by: Bobbin Threadbare <43513081+bobbinth@users.noreply.github.com>
Co-authored-by: Bobbin Threadbare <bobbinth@protonmail.com>
…f bricking (#3206)

* degrade non-binary exempt marker safely instead of bricking

* changelog

* fix comment

---------

Co-authored-by: Bobbin Threadbare <43513081+bobbinth@users.noreply.github.com>
* document that foreign procedure reads may be outdated

* changelog

* recommend expiration delta

* fix documentation

* apply suggestions

* changelog

---------

Co-authored-by: Bobbin Threadbare <43513081+bobbinth@users.noreply.github.com>
* Initial sig impl

* Add as_keys()

* Refactor BlockSignatures

* Lint

* Move verification to sig construction

* Add min sig check to constructor

* Use vec instead of constant

* Remove invariants from new()

* Dedupe test fns

* Changelog

* Fix changelog

* Use with_capacity

* Max 5 validators

* Move changelog line

* RM assert_signatures_verify

* Bump crossbeam-epoch for cargo deny check

* Check block sigs count
* feat: unify asset_vault::add_asset path

* feat: unify faucet::mint

* chore: add changelog

* chore: run benchmarks on next

* chore: run benchmarks on current PR
* add guardian component

* changelog

* apply suggestions

* deduplicate account id from felt pair
* remove super admin from RBAC

* changelog

* fix comments

* make RoleSymbol Ord match its encoded Felt key

* optimize RBAC membership read/write paths

* apply suggestions

* nit

* remove owner dependency from rbac

* apply suggestions

---------

Co-authored-by: Marti <marti@miden.team>
…, comment fixes, and PROC_ROOT validation (#3211)

* fix multisig getters call API

* reduce cycle costs

* correct stack-layout and advice-map comments

* warn that growing the signer set does not re-scale overrides

* validate PROC_ROOT belongs to the account in set_procedure_threshold

* changelog

* apply suggestions

* lint

* clarify auth_tx replay protection comes from assert_new_tx, not SALT

* remove unused @Locals(1) from auth_tx

* remove redundant dupw/dropw in tx_policy proc-call check

* explain advice-loaded config is covered by ACCOUNT_DELTA_COMMITMENT

* rename assert_new_tx to record_and_assert_new_tx

* fix inaccurate auth-component comments

* assert reconciled threshold config before approver-map cleanup

* use truncate_stack in tests

* fix

* apply suggestions
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.