Skip to content

feat(batch kernel): wire up INPUT_NOTES_COMMITMENT & note erasure#2905

Open
mmagician wants to merge 33 commits into
nextfrom
mmagician-claude/batch-kernel-logic
Open

feat(batch kernel): wire up INPUT_NOTES_COMMITMENT & note erasure#2905
mmagician wants to merge 33 commits into
nextfrom
mmagician-claude/batch-kernel-logic

Conversation

@mmagician

@mmagician mmagician commented May 12, 2026

Copy link
Copy Markdown
Collaborator

Builds on the batch kernel skeleton (#2904) to fill in the first part of the verification chain. The kernel recomputes the batch INPUT_NOTES_COMMITMENT as the nullifier-sorted, post-erasure commitment matching ProposedBatch::input_notes().commitment(). Output notes are processed only to track erasure; computing BATCH_NOTE_TREE_ROOT and the expiration_block_num running-minimum are deferred to follow-up PRs.

What this does

Prologue

Verification of data layers

The kernel takes [BLOCK_COMMITMENT, BATCH_ID, pad(8)] and walks a layered advice map, each layer keyed by a hash the previous layer verified. It then writes all this data to memory. The advice map is structured as:

  • Layer 1 - BATCH_ID -> the (tx_id, account_id) tuple list
  • Layer 2 - each tx_id_i -> the transaction header preimage, i.e. [INIT_ACCOUNT_COMMITMENT_i, FINAL_ACCOUNT_COMMITMENT_i, INPUT_NOTES_COMMITMENT_i, OUTPUT_NOTES_COMMITMENT_i, FEE_ASSET_i]. For the scope of this PR, we only care about the input & output notes commitments.
  • Layer 3a - each INPUT_NOTES_COMMITMENT_i -> (NULLIFIER, EMPTY_OR_COMMITMENT) tuples
  • Layer 3b - each OUTPUT_NOTES_COMMITMENT_i -> (NOTE_DETAILS_COMMITMENT, METADATA_COMMITMENT) tuples

The prologue only verifies Layers 1 and 2: it writes the tuple list and the per-transaction headers (which include each INPUT_NOTES_COMMITMENT_i / OUTPUT_NOTES_COMMITMENT_i) to memory, in tx_id order. The Layer 3 note pre-images are not loaded here — they are streamed in per transaction later (see Note matching).

Loading "global" notes

So at this point we have, in tx_id order, each transaction's verified input/output notes commitments — but our goal is to compute INPUT_NOTES_COMMITMENT over the notes sorted by their nullifier, and post-erasure.
To do this, we load two more lists into memory, supplied by the host and unverified (for now):

  • input note list, sorted by their nullifier, via prepare_input_note_list
  • output note list, sorted by their note id, via prepare_output_note_list

So at the end of the prologue's prepare_batch, for both input and output notes we have a verified tx_id-ordered view (the per-transaction commitments) and an untrusted nullifier/note-id-sorted list.

The next step is to match them.

Note tracker

Note erasure

A note is erased when it is created and consumed within the same batch. Only an unauthenticated input note (one carrying a note id) can be erased, so for each such entry in the input list we look up its note id in the output list. If it is found, the note is created somewhere in the batch and is a candidate for erasure: we flag the input entry expected-to-be-erased and link it to the matching output entry.

This is a static, order-independent pass over the (untrusted) sorted lists. Whether the erasure is actually valid — the creating transaction runs before the consuming one — is enforced during matching.

Note matching

So far we've determined erasure, but the nullifier/note-id-sorted lists are still untrusted.

We now process one transaction at a time. Its note tuples are piped from the advice provider into a small scratch buffer — re-used for each transaction, so only one transaction's notes are written to scratch memory at a time — and verified by asserting their hash equals that transaction's INPUT_NOTES_COMMITMENT_i / OUTPUT_NOTES_COMMITMENT_i. Then, for each note, we look it up in the untrusted list — input notes by nullifier, output notes by note id — assert the looked-up entry matches, and mark it {consumed for inputs, created for outputs}.

Because every verified per-transaction note must be found, each entry may be marked at most once, and the lists are strictly sorted (no duplicates), this proves the untrusted lists are exactly the per-transaction note sets: the host cannot inject, omit, or duplicate notes.

Epilogue

Once every note is matched, we:

  • assert every input entry was consumed, every output entry was created, and no erasure is left pending — so the host could not tamper with the list;
  • compute INPUT_NOTES_COMMITMENT as the sequential hash over the non-erased input entries in nullifier order, reproducing build_input_note_commitment

@mmagician mmagician changed the title feat: batch kernel verification chain + tests feat: minimal batch kernel May 12, 2026
Comment thread crates/miden-protocol/asm/kernels/batch/lib/prologue.masm Outdated
Comment thread crates/miden-protocol/asm/kernels/batch/lib/prologue.masm Outdated
@mmagician mmagician force-pushed the mmagician-claude/batch-kernel-logic branch from 9b2a31a to 7e97e87 Compare June 1, 2026 10:11
@mmagician mmagician changed the title feat: minimal batch kernel feat: verify batch tx list, tx headers, and input-notes commitment Jun 1, 2026
@mmagician mmagician force-pushed the mmagician-claude/batch-kernel-logic branch 2 times, most recently from 7dbd6b7 to 5bccee1 Compare June 1, 2026 11:25
@mmagician mmagician changed the title feat: verify batch tx list, tx headers, and input-notes commitment feat(batch kernel): verify INPUT_NOTES_COMMITMENT Jun 1, 2026
@mmagician mmagician force-pushed the mmagician-claude/batch-kernel-logic branch from 5bccee1 to 133f9bb Compare June 1, 2026 11:38
Comment thread crates/miden-protocol/asm/kernels/batch/main.masm Outdated
Comment thread crates/miden-protocol/asm/kernels/batch/main.masm Outdated
Comment thread crates/miden-protocol/asm/kernels/batch/main.masm Outdated
Comment thread crates/miden-protocol/asm/kernels/batch/main.masm Outdated
Comment thread crates/miden-protocol/src/batch/kernel.rs Outdated
Comment thread crates/miden-protocol/src/transaction/transaction_id.rs
Comment thread crates/miden-protocol/src/transaction/transaction_id.rs
Comment thread crates/miden-testing/src/kernel_tests/batch/test_batch_kernel.rs Outdated
Comment thread crates/miden-testing/src/kernel_tests/batch/test_batch_kernel.rs Outdated
Comment thread crates/miden-testing/src/kernel_tests/batch/test_batch_kernel.rs Outdated
@mmagician mmagician force-pushed the mmagician-claude/batch-kernel-logic branch from 133f9bb to 59c2efb Compare June 1, 2026 13:51
Base automatically changed from mmagician-claude/batch-kernel-skeleton to next June 3, 2026 07:39
claude added 4 commits June 3, 2026 09:43
Fill in the batch kernel to verify the batch's transaction list against
its BATCH_ID (Layer 1), verify each transaction header (Layer 2), and
recompute the batch INPUT_NOTES_COMMITMENT from the verified per-tx input
notes (Layer 3). Output-notes (BATCH_NOTE_TREE_ROOT) and the expiration
running-min stay as zero placeholders, wired up in follow-up PRs.
… injection

Add BatchExecutor::extend_advice_inputs (mirroring TransactionContextBuilder)
so the kernel's rejection paths can be exercised through the normal executor
with tampered advice, and drop the low-level run_kernel test helper. The three
negative tests now corrupt the Layer 1/2/3 advice-map entries via the executor.
Match the operand-stack (# =>) and advice-stack (# AS =>) comment style used
throughout the rest of the protocol assembly.
Reconstruct the batch's input notes from a host-provided global list sorted by
nullifier, bind every per-transaction input note to that list (lookup via
sorted_array::find_key_value, with consumption + note-id checks so the host
cannot omit, inject, duplicate, or alter notes), and hash the list to emit
INPUT_NOTES_COMMITMENT == ProposedBatch::input_notes().commitment() for batches
without intra-batch note erasure. BatchExecutor loads the CoreLibrary itself so
the sorted_array event handlers are registered, and BatchVerifier now verifies
against the real input-notes commitment.

Intra-batch note erasure is a follow-up; the output-note advice (sorted list +
per-tx output tuples) and the output memory regions are provided here as
scaffolding for it.
@mmagician mmagician force-pushed the mmagician-claude/batch-kernel-logic branch from 093ac8e to 622bee3 Compare June 3, 2026 12:32
claude added 7 commits June 3, 2026 12:47
…ut notes

Add the output-note half of the note tracker: load the host-provided
note-id-sorted output list, bind every per-transaction output note to it
(deriving each NoteId via poseidon2::merge of its details/metadata commitments),
and cross-reference the two lists to mark notes that are both created and
consumed within the batch. Processing transactions in batch order (outputs
before inputs) with a 1->2 erasure gate rejects consuming such a note before
its creator runs (circular/incorrectly-ordered dependencies), and the epilogue
hashes only the surviving input notes. INPUT_NOTES_COMMITMENT now matches
ProposedBatch::input_notes().commitment() for batches with intra-batch erasure.
…gate

Process each transaction's input notes before its output notes. With
outputs-first, a note created and consumed by the same transaction had its
erasure flag advanced to 2 before the consume check, so it was erased instead
of rejected. Inputs-first means the consume sees the flag still at 1 (the
creating output has not been processed yet), tripping the consume-before-create
gate, matching the Rust note tracker's rejection. Cross-transaction erasure is
unaffected (an earlier transaction's outputs are still processed before any
later transaction's inputs).

Adds a test that drives the gate by claiming a consumed note is created in-batch
without any transaction creating it.
…tives

Extract the batch kernel's MASM error constants (build.rs + the
errors::batch_kernel module, mirroring tx_kernel/protocol) and assert the
exact ERR_BATCH_* raised by each global-list binding and erasure negative test
(via matches_execution_error), instead of just checking is_err. The three
layer-tamper tests still assert only failure, since their hash check uses
pipe_preimage_to_memory's bare assertion, which carries no named error code.
Rewrite comments that referenced the PR's development history ("currently",
"still all-zero placeholders", "not yet", "wired up in follow-up PRs") so they
describe what the code does. Tighten the CHANGELOG entry to match the
surrounding single-sentence style.
Address review feedback on PR #2905:

- Add bounds asserts so the kernel rejects oversized inputs before they
  overflow the fixed-size memory regions: the per-batch transaction count,
  the two global note-list lengths, and each transaction's note-set length
  are checked against MAX_TRANSACTIONS_PER_BATCH / MAX_NOTES_PER_BATCH. The
  global-list check is the load-bearing one, since those lists are not bound
  by a commitment hash.
- Make note_tracker.masm the single source of truth for the advice-map
  sentinel keys: build.rs generates the matching Rust constants, and both
  the kernel and the tests derive them, removing the duplicated literals.
- Add epilogue negative tests (unconsumed input note, uncreated output note)
  and an oversized-list bound test.
Address pre-push review findings on the batch verifier and output stack:

- BatchVerifier::verify now returns the verified proof's security level
  instead of discarding it, so the acceptance test pins the proof's actual
  level (via a zero-minimum verify) rather than assuming the hardcoded
  MIN_PROOF_SECURITY_LEVEL constant equals it.
- Rename the verifier's stored minimum to min_proof_security_level to
  distinguish it from the actual verified level.
- Add a BatchOutputs::into_stack_outputs round-trip unit test covering
  distinct, non-zero fields.
The BATCH_ID and reference block commitment come from the ProvenBatch's
own fields and are not recomputed from its transactions, so a successful
verification binds nothing the batch's constructor could not forge. State
this in the warning and restate the trust-boundary caveat on verify().
Comment thread crates/miden-protocol/build.rs Outdated
Comment thread crates/miden-tx-batch-prover/src/batch_executor.rs Outdated
Comment thread crates/miden-tx-batch-prover/src/batch_executor.rs Outdated
Comment thread crates/miden-testing/src/kernel_tests/batch/test_batch_kernel.rs Outdated
Comment thread crates/miden-testing/src/kernel_tests/batch/test_batch_kernel.rs Outdated
Comment thread crates/miden-testing/src/kernel_tests/batch/test_batch_kernel.rs Outdated
Comment thread crates/miden-testing/src/kernel_tests/batch/test_batch_kernel.rs Outdated
Comment thread crates/miden-testing/src/kernel_tests/batch/test_batch_kernel.rs Outdated
Comment thread crates/miden-protocol/src/batch/kernel.rs
- note_tracker.masm: lowercase pointer names in stack-state comments.
- kernel.rs: rename generated module to generated_constants; rename the
  per-tx note Vec to preimage_data.
- test_batch_kernel.rs: introduce FELTS_PER_NOTE_ENTRY and use
  MAX_INPUT_NOTES_PER_BATCH instead of magic 8/1024; parametrize the three
  tampered-advice tests with rstest; drop the thin note-list-key wrappers in
  favor of BatchKernel::{input,output}_note_list_key.
- build.rs / batch_executor.rs: trim verbose doc comments.
Comment thread crates/miden-protocol/asm/kernels/batch/lib/prologue.masm Outdated
Comment thread crates/miden-protocol/asm/kernels/batch/lib/prologue.masm Outdated
Comment thread crates/miden-protocol/asm/kernels/batch/lib/memory.masm
Comment thread crates/miden-protocol/asm/kernels/batch/lib/prologue.masm
Comment thread crates/miden-protocol/asm/kernels/batch/lib/prologue.masm
Comment thread crates/miden-protocol/asm/kernels/batch/lib/memory.masm Outdated
Comment thread crates/miden-protocol/asm/kernels/batch/lib/memory.masm Outdated
Comment thread crates/miden-protocol/asm/kernels/batch/lib/memory.masm Outdated
Comment thread crates/miden-protocol/asm/kernels/batch/lib/memory.masm Outdated
Comment thread crates/miden-protocol/asm/kernels/batch/lib/memory.masm Outdated
claude added 5 commits June 4, 2026 15:53
- memory.masm: drop redundant [4] suffixes on uppercase words; add the
  per-tx-header layout to the memory table; define what an erasure
  "creator" is; split complex word-loading getters onto commented lines;
  prefer idx over i in index doc comments.
- prologue.masm: drop the redundant "is the batch's BatchId value" clause;
  replace "..." stack comments with nested-bracket notation; add an
  advice-stack comment after the Layer 2 mapvaln; explain the div.4.
Restructure the note tracker to mirror the tx kernel's stage layout:
- prologue: prepare_batch now also loads and strict-sorts the global input-
  and output-note lists (the list-loading procs move here from note_tracker).
- note_tracker: keeps the erasure cross-reference and per-tx binding, exposed
  via a new run entry point track_notes.
- epilogue (new lib module): the consumed/created/erasure assertions and the
  commitment computation; hash_non_erased_input_notes becomes
  compute_input_notes_commitment, plus a placeholder compute_output_notes_commitment
  (empty word, wired into the BATCH_NOTE_TREE_ROOT output) and a finalize entry
  point returning both commitments.
- main: prologue -> note_tracker::track_notes -> epilogue::finalize, then
  truncate to the 16-felt output region.
The consumed-exactly-once and no-pending-erasure checks iterate the same
input entries as the commitment hash loop, so assert them inline per entry
instead of in two separate sweeps. The output-note created check stays its
own pass over the output list.
Replace the magic 0xBA7C000x sentinels with keys derived by hashing a
domain message. build.rs hashes each message once and emits the value to
both the kernel (a generated note_list_keys.masm module the prologue pushes)
and the Rust advice builder, so the two sides agree by construction and no
magic hex remains. The key word is still four equal felts of the value.
Resolve the test_batch_kernel.rs import conflict from the
miden-tx-batch-prover -> miden-tx-batch crate rename on next; the
BatchVerifier additions carried into the renamed crate via directory-rename
detection. cargo check --all-targets, batch suite (51 tests), and make lint
all pass.
Comment thread crates/miden-protocol/asm/kernels/batch/main.masm Outdated
Comment thread crates/miden-protocol/asm/kernels/batch/main.masm Outdated
Comment thread crates/miden-protocol/asm/kernels/batch/main.masm Outdated
Comment thread crates/miden-protocol/asm/kernels/batch/main.masm Outdated
Comment thread crates/miden-protocol/asm/kernels/batch/main.masm Outdated
Comment thread crates/miden-protocol/asm/kernels/batch/lib/prologue.masm Outdated
Comment thread crates/miden-protocol/asm/kernels/batch/lib/prologue.masm Outdated
Comment thread crates/miden-protocol/asm/kernels/batch/lib/prologue.masm Outdated
Comment thread crates/miden-protocol/asm/kernels/batch/lib/prologue.masm Outdated
Comment thread crates/miden-protocol/asm/kernels/batch/lib/prologue.masm Outdated
claude added 2 commits June 12, 2026 16:52
- main.masm / prologue.masm: tighten the doc comments per review (reword the
  program/validation summary, the INPUT_NOTES_COMMITMENT description and the
  Layer 2 step; drop redundant lines) and replace the output truncation with
  swapdw dropw dropw.
- note-list keys: make each key a full poseidon2-hash word instead of a felt
  repeated four times. build.rs now emits a generated MASM proc per key that
  pushes the word, so the prologue execs it (no dup dup dup), and the Rust
  advice builder uses the matching [u64; 4] word.
Replace the generate_batch_kernel_keys codegen (a generated MASM module +
Rust constants + reverse-push-order workaround) with the assembler's native
word(...) constant: the prologue defines

    const INPUT_NOTE_LIST_KEY=word("miden::batch_kernel::input_note_list")

and pushes it directly, while the Rust advice builder derives the same word
from the same message via miden_core's hash_string_to_word. Both sides hash
the identical domain string with the identical function, so they agree by
construction (asserted implicitly by the kernel's advice lookups in tests).
Removes the build.rs key generation entirely.
Comment thread crates/miden-protocol/asm/kernels/batch/lib/note_tracker.masm Outdated
Comment thread crates/miden-protocol/asm/kernels/batch/lib/note_tracker.masm
Comment thread crates/miden-protocol/asm/kernels/batch/lib/note_tracker.masm Outdated
Comment thread crates/miden-protocol/asm/kernels/batch/lib/note_tracker.masm
Comment thread crates/miden-protocol/asm/kernels/batch/lib/note_tracker.masm Outdated
Comment thread crates/miden-protocol/asm/kernels/batch/lib/note_tracker.masm Outdated
Comment thread crates/miden-protocol/asm/kernels/batch/lib/note_tracker.masm Outdated
Comment thread crates/miden-protocol/asm/kernels/batch/lib/note_tracker.masm
Comment thread crates/miden-protocol/asm/kernels/batch/lib/prologue.masm Outdated
Comment thread crates/miden-protocol/src/batch/kernel.rs Outdated
Comment thread crates/miden-protocol/src/batch/kernel.rs Outdated
Address review comments asking for more explanation:
- Define what "binding" a per-transaction note means (look it up in the
  batch's sorted list and mark the entry; proves the list is exactly the
  per-tx note set) on bind_per_tx_notes, and trim the input-before-output
  rationale to one sentence.
- Explain the scratch region and add per-block inline comments and stack
  comments to the per-tx input/output binding procs.
- Comment the empty-commitment fast path.
- Reword the bind_scratch_* summaries.
- Rename "global ... note list" to "batch ... note list" within this file
  (matching the error messages).
Comment thread crates/miden-protocol/asm/kernels/batch/lib/epilogue.masm
Comment thread crates/miden-protocol/asm/kernels/batch/lib/epilogue.masm Outdated
Comment thread crates/miden-protocol/asm/kernels/batch/lib/epilogue.masm
Comment thread crates/miden-protocol/asm/kernels/batch/lib/epilogue.masm
claude added 7 commits June 12, 2026 18:01
Rename the 'global input/output-note list' to 'nullifier-sorted input-note
list' / 'note-id-sorted output-note list' across the batch kernel (docs,
error messages, section headers, the memory-layout table, and load_note_list),
distinguishing the sorted batch lists from the per-transaction notes per
review.
- absorb_input_entry: use poseidon2::absorb_double_words_from_memory instead
  of manually loading the rate words and permuting (the loaded rate words were
  immediately discarded), per review.
- compute_input_notes_commitment: split into commented blocks; clarify that
  the empty-set commitment is the empty word (matching build_input_note_commitment's
  early return), not the hash of zero elements.
- Trim the verbose advice-key comments in prologue.masm and kernel.rs and drop
  the word "sentinel".
- remove the unused SCRATCH_WORDS_COUNT/WORD_INDEX slots and accessors
  (note counts are derived from pipe_preimage_to_memory's end_ptr)
- document the duplicate-note-id conservative abort in the erasure
  cross-reference and the non-multiple-of-8 advice-length failure mode
  in load_note_list
- reword the main.masm output docs: the placeholder outputs are bound
  by the proof, just not yet derived from batch data
…sert

Absorb contiguous non-erased entries in a single
absorb_double_words_from_memory call, so the hasher state round-trips
through memory once per run (once in total for a batch with no
erasures) instead of once per entry.

Also remove the epilogue's pending-erasure assert: an entry with
erasure == 1 either was consumed - tripping the note tracker's ordering
gate at consume time (erasure never transitions back to 1) - or was
not, tripping the epilogue's consumption assert. This also removes the
error constant duplicated with note_tracker.masm.
- tampered-advice case for Layer 3' (OUTPUT_NOTES_COMMITMENT preimage)
- oversized output-note list, layer-1 tuple list, and per-transaction
  note set (each length assert fires before its hash check)
- consumed-twice / created-twice checks, driven by executing the kernel
  directly with a forged BATCH_ID over a duplicated transaction tuple
  list, modeling a malicious prover bypassing ProposedBatch validation
- gate BatchExecutor::extend_advice_inputs behind the testing feature
  since it exists only to drive these rejection paths
Replace the test-only execute_kernel_raw helper with a testing-gated
BatchExecutor::with_batch_id override (mirroring extend_advice_inputs),
so the consumed-twice / created-twice tests run through the real
executor path instead of duplicating processor/host setup.
claude added 3 commits June 12, 2026 21:38
Make BatchExecutor a stateless unit struct again. The production
execute path derives its inputs and delegates to a private
execute_with_inputs; the testing-gated execute_with_advice_overrides
entry point merges override advice and delegates to the same body, so
execute contains no testing-only code.

Also drop the forged-batch-id override and the consumed-twice /
created-twice tests that needed it: those kernel checks are unreachable
through a valid ProposedBatch and are not worth a test-only input path.
…executor

Replace the testing-gated execute_with_advice_overrides with a plain
advice_inputs parameter on BatchExecutor::execute, mirroring how
TransactionArgs carry caller advice into the transaction executor (and
execute_tx_view_script's advice_inputs parameter). Advice is untrusted
by design - the kernel verifies everything it consumes - so extending
it is a legitimate production capability, not a testing hook. No
cfg-gated code remains in the executor.
Trim test doc comments to what each test exercises, drop comments that
restate the code or justify choices that only made sense during review
(cross-references to the tx-kernel test layout, duplicated section
headers, redundant TODO), and tighten the remaining prose.
Comment thread crates/miden-tx-batch/src/batch_executor.rs Outdated
Comment thread crates/miden-protocol/src/batch/kernel.rs Outdated
Comment thread crates/miden-protocol/src/batch/kernel.rs Outdated
Comment thread crates/miden-protocol/src/batch/kernel.rs Outdated
Comment thread crates/miden-protocol/src/batch/kernel.rs Outdated
Comment thread crates/miden-protocol/src/batch/kernel.rs Outdated
Comment thread crates/miden-protocol/src/batch/kernel.rs
Comment thread crates/miden-protocol/asm/kernels/batch/lib/epilogue.masm Outdated
Comment thread crates/miden-protocol/asm/kernels/batch/lib/epilogue.masm Outdated
Comment thread crates/miden-protocol/asm/kernels/batch/lib/epilogue.masm Outdated
@mmagician mmagician added the pr-from-maintainers PRs that come from internal contributors or integration partners. They should be given priority label Jun 12, 2026
claude and others added 2 commits June 12, 2026 22:43
- strongly type the note lists in build_advice_inputs (Nullifier,
  NoteId)
- rename Layer 3 / Layer 3' to Layer 3a / 3b across kernel docs;
  relabel the prologue's global-list step to avoid the collision
- clarify everywhere that input notes sort by nullifier and output
  notes by note id
- drop NULLIFIER[4]-style suffixes (uppercase already means word) and
  apply the suggested doc/comment trims
- shorten the batch error messages per suggestions (the duplicated
  consumed-before-created constant is kept in sync in note_tracker)
@mmagician mmagician marked this pull request as ready for review June 12, 2026 22:49
@mmagician mmagician changed the title feat(batch kernel): verify INPUT_NOTES_COMMITMENT feat(batch kernel): wire up INPUT_NOTES_COMMITMENT & note erasure Jun 12, 2026
for note_commit in tx.input_notes().iter() {
let nullifier = note_commit.nullifier();
let note_id_or_empty =
note_commit.header().map_or(Word::empty(), |header| header.id().as_word());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

NoteTracker turns an unauthenticated note with a valid inclusion proof into InputNoteCommitment::from(nullifier), so batch.input_notes().commitment() hashes (NULLIFIER, EMPTY). This advice path still puts (NULLIFIER, NOTE_ID) in the global list, so the epilogue emits a different commitment and that batch should fail verification. A regression test with unauthenticated_note_proofs would catch it.

Could this use the batch-level input note representation instead of the per-tx one?

# => [num_notes, num_words, KEY, write_ptr]
# A length that is not a multiple of 8 felts wraps `num_notes` (field `div`) to a non-u32
# felt, which the range check below rejects.
dup u32lte.MAX_NOTES_PER_BATCH assert.err=ERR_BATCH_NOTE_LIST_TOO_LONG

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ProposedBatch checks MAX_INPUT_NOTES_PER_BATCH / MAX_OUTPUT_NOTES_PER_BATCH after erasure, but this list is pre-erasure.

A batch can have more than 1024 notes created and consumed inside the batch, end with at most 1024 final notes, pass ProposedBatch, and then fail here because the kernel stores the pre-erasure lists in fixed 1024-entry regions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr-from-maintainers PRs that come from internal contributors or integration partners. They should be given priority

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants