Skip to content

feat: hash AssetVaultKey before insertion into asset vault SMT#2912

Open
partylikeits1983 wants to merge 8 commits into
nextfrom
ajl-claude-hash-asset-vault-key-smt
Open

feat: hash AssetVaultKey before insertion into asset vault SMT#2912
partylikeits1983 wants to merge 8 commits into
nextfrom
ajl-claude-hash-asset-vault-key-smt

Conversation

@partylikeits1983
Copy link
Copy Markdown
Contributor

@partylikeits1983 partylikeits1983 commented May 12, 2026

Summary

Closes #2518.

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 degrading tree balance.

This PR mirrors the existing raw-key/hashed-key pattern already used by StorageMap in this crate:

  • AssetVaultKey::to_smt_key() returns the Poseidon2 hash of the raw key. to_leaf_index is rerouted through it.
  • AssetVault and PartialVault now store the SMT keyed by hashed keys, plus a BTreeMap<AssetVaultKey, Word> of raw keys for iteration and proof reconstruction.
  • AssetWitness carries both the SmtProof and the raw key(s) it covers; new validates each (key, value) pair against the proof.
  • The MASM kernel adds a private hash_asset_key helper (exec.poseidon2::hash) and injects it before every smt::set / smt::get / smt::peek in asset_vault.masm (same pattern as hash_map_key in account.masm).
  • Host-side read_vault_asset / read_vault_asset_witnesses updated for the new layout.

A regression test (two_non_fungible_assets_from_same_faucet_use_different_leaves) covers the original bug end-to-end.

Targets mmagician-claude-setup to keep the diff clean. Will be retargeted to next and rebased once that branch lands.

partylikeits1983 added a commit that referenced this pull request May 12, 2026
@partylikeits1983 partylikeits1983 changed the title feat: hash AssetVaultKey before insertion into asset vault SMT feat: hash AssetVaultKey before insertion into asset vault SMT May 12, 2026
@bobbinth
Copy link
Copy Markdown
Contributor

This is something we need to do but it'll also complicate asset retrieval from the AccountStateForest in the node (same issues as we've faced with storage map values). cc @kkovaacs.

@partylikeits1983 partylikeits1983 marked this pull request as ready for review May 13, 2026 03:39
Base automatically changed from mmagician-claude-setup to next May 13, 2026 05:43
Copy link
Copy Markdown
Contributor

@PhilippGackstatter PhilippGackstatter left a comment

Choose a reason for hiding this comment

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

I looked at parts of the asset vault related changes and left some comments.

Comment thread crates/miden-protocol/asm/kernels/transaction/lib/asset_vault.masm
Comment thread crates/miden-protocol/src/asset/vault/asset_witness.rs Outdated
Comment thread crates/miden-protocol/src/asset/vault/asset_witness.rs
Comment thread crates/miden-protocol/src/asset/vault/partial.rs
Comment thread crates/miden-protocol/src/asset/vault/partial.rs Outdated
Comment thread crates/miden-protocol/src/asset/vault/partial.rs Outdated
Comment thread crates/miden-protocol/src/asset/vault/vault_key.rs Outdated
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.
@partylikeits1983 partylikeits1983 added the pr-from-maintainers PRs that come from internal contributors or integration partners. They should be given priority label May 13, 2026
- 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).
@partylikeits1983 partylikeits1983 force-pushed the ajl-claude-hash-asset-vault-key-smt branch from cbb11d4 to 59521ea Compare May 13, 2026 18:43
claude and others added 3 commits May 13, 2026 14:56
- 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 }`.
…masm

Co-authored-by: Philipp Gackstatter <PhilippGackstatter@users.noreply.github.com>
@partylikeits1983 partylikeits1983 self-assigned this May 21, 2026
claude added 2 commits May 21, 2026 16:18
…-vault-key-smt

# Conflicts:
#	crates/miden-protocol/src/asset/vault/mod.rs
#	crates/miden-protocol/src/asset/vault/vault_key.rs
#	crates/miden-protocol/src/errors/mod.rs
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).
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.

Hash AssetVaultKey before inserting into asset vault SMT

4 participants