Conversation
* 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>
* 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
…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 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>
…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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This is a tracking PR for v0.16.0 release.