feat(standards): add NetworkAccount auth component#2817
feat(standards): add NetworkAccount auth component#2817partylikeits1983 wants to merge 29 commits intonextfrom
NetworkAccount auth component#2817Conversation
Adds tx_get_script_root to the transaction kernel API so that MASM auth code can read the executed tx script root (zero word if no script ran). Required by the upcoming NetworkAccount auth component (#2814). - lib/memory.masm: new get_tx_script_root word getter - lib/tx.masm: re-export as tx::get_script_root - api.masm: new tx_get_script_root public kernel procedure - kernel_proc_offsets.masm: new TX_GET_SCRIPT_ROOT_OFFSET=51 - protocol/tx.masm: new user-facing tx::get_script_root wrapper - tests: returns expected root when script is set, zero word otherwise Part of #2813, related to #2797.
Adds a new auth component intended for network-owned accounts such as the AggLayer bridge and the AggLayer faucet. Replaces the NoAuth pattern which lets any transaction emit output notes authored by the account. The auth procedure enforces two invariants: 1. Rejects the transaction if a tx script was executed, using `tx::get_script_root` from the kernel. 2. Rejects the transaction if any consumed input note's script root is not present in the whitelist stored at a well-known storage slot. If both checks pass, the nonce is incremented when the account state changed or the account is new, matching NoAuth/SingleSig behavior. The whitelist is a StorageMap keyed by script root (with a sentinel value marking presence) and is fixed at account creation. A mutable whitelist is a possible future improvement. - new network_account.masm auth component - new NetworkAccount Rust struct with From<NetworkAccount> for AccountComponent - register library in components::mod and extend StandardAccountComponent - extend AccountComponentInterface and AccountInterfaceExt with AuthNetworkAccount variant (maps to AuthMethod::NoAuth for now) - unit tests for the Rust builder - integration tests in tests/auth/network_account.rs covering tx-script-reject, non-whitelisted-note-reject, and happy-path Part of #2814. Depends on #2813 (merged via #2816). Related to the #2797 fix.
NetworkAccount auth component
Drop the stale AggLayer-faucet reference in the doc comment (the component is used by network faucets more generally) and rewrite the WHITELIST_SENTINEL comment to explain why a non-empty marker value is needed (storage maps use the empty word as the "key absent" marker). Also shorten the fully qualified miden_protocol::Felt path to use a direct Felt import, matching the pattern used elsewhere in the crate.
…work_account.masm Document the post-stack state after the if.true/end block that conditionally increments the nonce, matching the commenting style used by the rest of the procedure.
…` in identifiers Keep `tx_script` in the names to match the well-defined concept, per review on #2816. Renames: - kernel lib `tx::get_script_root` -> `tx::get_tx_script_root` - kernel api proc `tx_get_script_root` -> `tx_get_tx_script_root` - offset const `TX_GET_SCRIPT_ROOT_OFFSET` -> `TX_GET_TX_SCRIPT_ROOT_OFFSET` - user-facing wrapper `tx::get_script_root` -> `tx::get_tx_script_root` Updates call sites and the CHANGELOG entry accordingly.
…Account Update the auth call site and drop the stale CHANGELOG bullet left behind by the merge of `ajl-kernel-tx-script-root`.
… example accounts Reword the doc-comment example from "AggLayer bridge and a network faucet" to "network faucets and the AggLayer bridge" to foreground the general case over the specific deployment. Expand the WHITELIST_SENTINEL comment to define the term "sentinel value" and explain why we call the constant one: we only check that the stored value differs from the empty word, so the contents carry no information on their own.
PhilippGackstatter
left a comment
There was a problem hiding this comment.
Looks good! I took a high level look.
As mentioned in #2797 (comment), I would suggest renaming this from the more general NetworkAccount to something like NoteScriptAllowlistAuth.
Also, I suggest renaming whitelist to allowlist.
I don't mind generalizing this, but then I don't think Approach 1We could move most of the logic into a module somewhere in the standards library (e.g., under Then, these procedures could be used from the Approach 2Put the logic of the into a separate component Between these two approaches, I have a slight preference towards the first approach - mostly because I think it is a bit simpler and doesn't require us to think too much about how this functionality will be used outside of network components in the future.
If we go with approach 1 above, I'd actually name the storage slot something like: |
Do you mean that the logic in If so, I agree on the The protocol/crates/miden-standards/src/account/faucets/token_metadata.rs Lines 197 to 201 in f2c6625 This type defines the storage layout conversion and the slot name ( So, I agree with approach 1 and would scope this functionality under:
And support this with the The only open question is how a network account would easily add this auth functionality in a "one-liner", and for this I think we need an auth component like |
I was thinking that this procedure would take the storage slot name as a parameter (see the signature in my comment). This way, different auth components could have their own storage slots to hold the set of allowed notes. |
Co-authored-by: Philipp Gackstatter <PhilippGackstatter@users.noreply.github.com>
…ount.masm Co-authored-by: Philipp Gackstatter <PhilippGackstatter@users.noreply.github.com>
…ount.masm Co-authored-by: Philipp Gackstatter <PhilippGackstatter@users.noreply.github.com>
Co-authored-by: Philipp Gackstatter <PhilippGackstatter@users.noreply.github.com>
Agreed with approach 1 and with passing the storage slot name as parameter. We already handle this very similarly with the double-word array, which is just a module and then other components (e.g. the As to whether allowlist is the right approach, or perhaps a flag that would prevent accounts from producing output notes unless called via an account procedure (IIUC) as was suggest by @bobbinth: for the specific use case that @partylikeis1983 is solving for - AggLayer - I think it makes sense to restrict the type of notes that an account can consume. We only want canonical notes to be processed by the bridge account. One "downside" to this approach is that if the canonical note script ever changes for whatever reason (I wouldn't discard that it will, due to bugs or optimizations), we need to be able to update the allow list. So we would additionally need a helper allowlist setter only writeable by the owner, and a network note to trigger the update ( Note: since issuing updates to the allowlist is done via ( Separately, the feature suggested by Bobbin is of independent interest, which we might want to pursue independently. We could open an issue, but unless a concrete use case for it arises, I'd defer tackling it to post-launch. |
…omponent # Conflicts: # crates/miden-protocol/asm/kernels/transaction/api.masm # crates/miden-protocol/asm/kernels/transaction/lib/memory.masm # crates/miden-protocol/asm/kernels/transaction/lib/tx.masm # crates/miden-protocol/asm/protocol/tx.masm # crates/miden-testing/src/kernel_tests/tx/test_tx.rs
|
Implemented the suggestions above:
|
bobbinth
left a comment
There was a problem hiding this comment.
Looks good! Thank you! I left some comments about naming - but the code itself looks great!
…ount Re-frame the auth component around the network account use case per review feedback. Keeps the shared `note_script_allowlist` primitives module (assert_no_tx_script / assert_all_input_notes_allowed) untouched.
The renamed `AuthNetworkAccount` identifier is shorter than the original, so rustfmt collapses these arms onto a single (or fewer) line(s).
bobbinth
left a comment
There was a problem hiding this comment.
Looks good! Thank you! I left just two more minor comments inline.
- Use `AuthNetworkAccount` consistently in network_account.masm doc comments (replaces the two stray `NetworkAccountAuth` references). - Drop `components::` from `AuthNetworkAccount::NAME` so the component name is a prefix of its storage-slot name (`miden::standards::auth::network_account::allowed_note_scripts`). The same `components::` cleanup is needed for the other auth components (no_auth, singlesig, singlesig_acl, multisig, guarded_multisig) and is tracked separately, per Bobbin's note that it should not land in this PR. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
bobbinth
left a comment
There was a problem hiding this comment.
All looks good! Thank you!
Adapts the network-account auth test to the NoteScriptRoot newtype introduced in #2851; matches the repo convention of converting at the boundary rather than widening the AuthNetworkAccount API.
Resolves: #2814
Summary
Adds a new auth component intended for network-owned accounts (AggLayer bridge, AggLayer faucet). Replaces the
NoAuthpattern which lets any transaction emit output notes authored by the account and thus forge bridge-authoredMINTnotes (see #2797).The auth procedure enforces two invariants:
tx::get_script_rootfrom the kernel (added in feat(kernel): expose tx script root via public kernel procedure #2816).If both checks pass, the nonce is incremented when the account state changed or the account is new, matching the
NoAuth/SingleSigbehavior.Changes
asm/account_components/auth/network_account.masm— new auth procedureauth_tx_network_account.src/account/auth/network_account.rs—NetworkAccountRust struct withFrom<NetworkAccount> for AccountComponentand unit tests.src/account/components/mod.rs— registersNETWORK_ACCOUNT_LIBRARY, addsnetwork_account_library(), extendsStandardAccountComponentwithAuthNetworkAccount.src/account/interface/component.rs,extension.rs— extendAccountComponentInterfacewithAuthNetworkAccount(maps toAuthMethod::NoAuthfor now; a distinctAuthMethodvariant can be added later if needed).tests/auth/network_account.rs— integration tests covering: tx-script rejection, non-whitelisted-note rejection, and the happy path.Storage layout
miden::standards::auth::network_account::whitelist.Word). Values: sentinel[1, 0, 0, 0]marking presence.Stacking
This PR is stacked on #2816 (PR 1 of the #2797 fix chain). It is the second PR of three; the AggLayer wire-up in #2815 will land on top.
Closes #2814. Related to #2797.