Root Cause: owner_action and faucet_policy_action call active_note::get_storage before rejecting invalid storage lengths, forcing O(n) hashing/memory writes on oversized notes.
Toy example:
- An attacker publishes a public
OwnerAction note with the correct script root but num_storage_items = 1024.
- A network executor attempts to execute the note.
- The script calls
active_note::get_storage, which pipes and hashes all 1024 items.
- The script later rejects due to an unexpected storage length, after paying the full storage-processing cost.
Location: crates/miden-standards/asm/standards/notes/owner_action.masm#L61-L97
The OwnerAction and FaucetPolicyAction note scripts are intended to dispatch management actions based on a selector stored in note storage (see owner_action::main and faucet_policy_action::main). At the protocol layer, note storage can contain up to MAX_NOTE_STORAGE_ITEMS = 1024.
Both scripts unconditionally call active_note::get_storage at the start of main, which triggers write_storage_to_memory. This helper loads the full storage preimage from the advice map (adv.push_mapvaln.8), writes all elements to memory, and recomputes the storage commitment via mem::pipe_elements_preimage_to_memory. Only after this work do the scripts read the selector and enforce the expected storage lengths (e.g., execute_transfer_ownership and load_policy_root_window).
As a result, a public note with a valid management script root but an oversized storage length will always force bounded but avoidable O(num_storage_items) hashing and memory writes before failing. Repeated submission of such notes can degrade the throughput of any executor/prover that automatically attempts execution of public management notes without prefiltering by storage length.
Consider introducing and using a lightweight active_note helper that returns (NOTE_STORAGE_COMMITMENT, num_storage_items) without piping the full storage to memory (modeled after input_note::get_storage_info), and rejecting invalid lengths before calling active_note::get_storage. For OwnerAction, an upfront check that num_storage_items is in {1, 3} can reject all oversized notes without reading the selector; for FaucetPolicyAction, enforcing num_storage_items == 5 upfront avoids processing arbitrarily long storages.
Root Cause:
owner_actionandfaucet_policy_actioncallactive_note::get_storagebefore rejecting invalid storage lengths, forcing O(n) hashing/memory writes on oversized notes.Toy example:
OwnerActionnote with the correct script root butnum_storage_items = 1024.active_note::get_storage, which pipes and hashes all 1024 items.Location:
crates/miden-standards/asm/standards/notes/owner_action.masm#L61-L97The
OwnerActionandFaucetPolicyActionnote scripts are intended to dispatch management actions based on a selector stored in note storage (seeowner_action::mainandfaucet_policy_action::main). At the protocol layer, note storage can contain up toMAX_NOTE_STORAGE_ITEMS = 1024.Both scripts unconditionally call
active_note::get_storageat the start ofmain, which triggerswrite_storage_to_memory. This helper loads the full storage preimage from the advice map (adv.push_mapvaln.8), writes all elements to memory, and recomputes the storage commitment viamem::pipe_elements_preimage_to_memory. Only after this work do the scripts read the selector and enforce the expected storage lengths (e.g.,execute_transfer_ownershipandload_policy_root_window).As a result, a public note with a valid management script root but an oversized storage length will always force bounded but avoidable O(
num_storage_items) hashing and memory writes before failing. Repeated submission of such notes can degrade the throughput of any executor/prover that automatically attempts execution of public management notes without prefiltering by storage length.Consider introducing and using a lightweight
active_notehelper that returns(NOTE_STORAGE_COMMITMENT, num_storage_items)without piping the full storage to memory (modeled afterinput_note::get_storage_info), and rejecting invalid lengths before callingactive_note::get_storage. ForOwnerAction, an upfront check thatnum_storage_itemsis in{1, 3}can reject all oversized notes without reading the selector; forFaucetPolicyAction, enforcingnum_storage_items == 5upfront avoids processing arbitrarily long storages.