Skip to main content
Version: 0.14 (unstable)

Hashing & Stack Changes

The native hash function changed from RPO to Poseidon2, and the operand stack is now little-endian. These are the most fundamental changes in v0.14 — every digest and every multi-limb operation is affected.


Native Hash Function: RPO → Poseidon2

Summary

The VM's native sponge hash flipped from RPO to Poseidon2. Rust type names (Word, Hasher, digests) are unchanged but every digest the VM produces is different: MAST roots, advice-map keys derived from hashing, account/note commitments, transaction IDs — none of them roundtrip with 0.13 artifacts.

Migration Steps

  1. Re-assemble every .masl and .masp from source under 0.22 (the MAST format version was bumped — old serialized forests will not deserialize anyway).
  2. Re-derive any persisted commitments (account commitments, note commitments, advice-map keys, MAST roots).
  3. Discard any cached transaction IDs, proven transactions, and proofs from 0.13.
  4. If you hard-coded MAST root literals in tests, regenerate them.

Common Errors

Error MessageCauseSolution
MastForest deserialization failed: unexpected versionMAST format version bumped along with the hash changeRe-assemble from source under 0.22.
transaction id mismatch / account commitment mismatchOld digest computed under RPORecompute from current state under 0.14.

Operand Stack Is Little-Endian

Summary

Every multi-limb operation in the VM was unified around "low limb closest to the top of the stack". Before 0.14 conventions were mixed: u64 lived on the stack as [hi, lo], hperm consumed [R1, R0, C] and produced its digest at indices 4..8, mem_stream returned words with the address-highest word on top. After 0.14 the low-significance limb is always on top: u64 is [lo, hi], hperm takes [R0, R1, C] with the digest at indices 0..4, and mem_stream returns the words in address-ascending order.

This affects MASM that uses u32split, u32widening_mul, u32madd, hperm, hmerge, mem_stream, adv_pipe, adv.insert_hdword, adv.insert_hdword_d, adv.insert_hqword, adv.insert_hperm, all of std::math::u64, all of std::math::u256, and ext2 extension-field values.

Affected Code

MASM (u64 add):

# Before (0.13): [b_hi, b_lo, a_hi, a_lo, ...] -> [c_hi, c_lo, ...]
push.0.0xFFFFFFFF push.0.1
exec.::std::math::u64::wrapping_add

# After (0.14): [b_lo, b_hi, a_lo, a_hi, ...] -> [c_lo, c_hi, ...]
push.0xFFFFFFFF.0 push.1.0
exec.::std::math::u64::wrapping_add

MASM (hperm and digest extraction): the input is now [R0, R1, C, ...] (was [R1, R0, C, ...]) and the digest comes out at indices 0..4 (was 4..8).

MASM (hmerge): input is now [A, B, ...] -> [hash(A || B), ...] (was [B, A, ...]).

Rust (StackInputs / StackOutputs):

For StackInputs::try_from_ints([1, 2, 3, 4]) the first element (1) is the top of the stack — no reversal. When seeding a u64, push [lo, hi], not [hi, lo]. Same when reading StackOutputs: stack[0] is the top.

Migration Steps

  1. Audit every MASM call into std::math::u64 / u256 and flip the limb order in adjacent push/movdn/movup instructions.
  2. Audit every hperm/hmerge site and update the index where you extract the digest (it moved from [4..8] to [0..4]).
  3. Audit mem_stream / adv_pipe users — the word at the address now lands on top, not buried.
  4. In Rust, drop any [Felt; 16] reversal helpers you used to construct stacks "in pretty order".

Common Errors

Error MessageCauseSolution
assertion failed: ... (off-by-one in u64 arithmetic)Limb order flippedPush [lo, hi] instead of [hi, lo].
expected hash 0x... at clock cycle ...Digest at wrong stack offsetThe digest is now at indices 0..4, not 4..8.

Falcon Module Rename

Summary

Because the native hash flipped to Poseidon2, the Falcon-512 verifier was rewritten and renamed. The MASM module path moved to miden::core::crypto::dsa::falcon512_poseidon2 and the Rust auth scheme variant is Falcon512Poseidon2.

Affected Code

MASM:

# Before (0.13)
use.miden::core::crypto::dsa::falcon512rpo
exec.falcon512rpo::verify

# After (0.14)
use.miden::core::crypto::dsa::falcon512_poseidon2
exec.falcon512_poseidon2::verify

Rust:

// Before (0.13)
use miden_protocol::account::auth::AuthScheme;
let scheme = AuthScheme::Falcon512Rpo;

// After (0.14)
use miden_protocol::account::auth::AuthScheme;
let scheme = AuthScheme::Falcon512Poseidon2;

Common Errors

Error MessageCauseSolution
unknown module miden::core::crypto::dsa::falcon512rpoModule renamedUse falcon512_poseidon2.
no variant or associated item named Falcon512Rpo for AuthSchemeVariant renamedUse AuthScheme::Falcon512Poseidon2.