Types
Miden's type system is built around field elements rather than standard integers. All computation inside the Miden VM is modular arithmetic over the Goldilocks prime field (), so overflow and division behave differently from standard integers. Felt is the native numeric type, Word is a tuple of four Felts used for storage and hashing, and Asset encodes fungible and non-fungible assets as Words.
Felt — Field elements
Felt is the fundamental numeric type in Miden. It represents an element of the Goldilocks prime field:
Felt uses modular arithmetic. Values wrap around the prime modulus, not at u64::MAX. Addition, subtraction, and multiplication all happen modulo . Division computes the multiplicative inverse, not integer division.
Creating Felt values
use miden::{felt, Felt};
// Literal construction (validated when evaluated)
let zero = felt!(0);
let one = felt!(1);
let answer = felt!(42);
// From u32 (always safe)
let f = Felt::from_u32(255);
// From u64 (fallible if the value is outside the field)
let f = Felt::new(1_000_000_000).unwrap();
// Built-in zero / one constants
let z = Felt::ZERO;
let o = Felt::ONE;
The felt!() macro accepts integer literals representable as u64 and
validates them through Felt::new(...).unwrap(). An out-of-field literal
panics when evaluated; it is not currently rejected by cargo check. For
runtime values, use the fallible Felt::new(...) and handle the error.
Arithmetic
let a = felt!(10);
let b = felt!(3);
// Standard arithmetic (modular)
let sum = a + b; // felt!(13)
let diff = a - b; // felt!(7)
let prod = a * b; // felt!(30)
let neg = -a; // p - 10
// Division computes multiplicative inverse
// a / b = a * b^(-1) mod p
let quot = a / b; // NOT integer 3 — it's 10 * inverse(3) mod p
// In-place operators
let mut x = felt!(5);
x += felt!(1); // x is now felt!(6)
x *= felt!(2); // x is now felt!(12)
For computing amounts, balances, counters, or any value where overflow/underflow behavior matters, convert to u64 first, perform the arithmetic, then convert back with Felt::new(...).unwrap() or explicit error handling.
Comparison and conversion
let f = felt!(42);
// Convert to u64 (canonical representation)
let n: u64 = f.as_canonical_u64();
// Equality comparison
if f == felt!(42) { /* ... */ }
// For numeric comparisons, convert to u64 first
if f.as_canonical_u64() > 100 { /* ... */ }
// Check parity
if f.is_odd() { /* ... */ }
Converting Felt to u64 with .as_canonical_u64() gives you standard Rust integer arithmetic — with overflow and underflow protection from Rust's debug-mode checks and saturating_* / checked_* methods. For business logic involving amounts, limits, or counters, prefer u64 arithmetic:
// Convert, compute in u64, convert back
let a: u64 = felt_a.as_canonical_u64();
let b: u64 = felt_b.as_canonical_u64();
let sum = a.saturating_add(b); // safe addition
let diff = a.saturating_sub(b); // no underflow
let result = Felt::new(sum).unwrap();
Saturating arithmetic prevents u64 overflow, but the result can still be outside the field. The final unwrap() panics if sum >= p; handle that conversion explicitly when the inputs are not bounded.
Advanced operations
let f = felt!(7);
// Multiplicative inverse: f * f.inv() == felt!(1)
let inv = f.inv(); // Panics if f == felt!(0)
// Exponentiation: base^exponent mod p
let result = f.exp(felt!(3)); // 7^3 mod p = 343
// Squaring: f^2
let square = f * f; // 7^2 mod p = 49
In the contract-target implementation of miden-field 0.35.0, Felt::square() calls the pow2 intrinsic, which computes 2^f rather than f^2. Use f * f as shown above: for felt!(7), this gives 49 rather than 128.
Word — Four field elements
A Word holds four Felt values. It's the standard unit for storage, hashing, and data passing in Miden.
#[repr(C)]
pub struct Word {
pub a: Felt,
pub b: Felt,
pub c: Felt,
pub d: Felt,
}
Creating Words
use miden::{felt, Felt, Word};
// From an array of 4 Felts
let w = Word::new([felt!(1), felt!(2), felt!(3), felt!(4)]);
// Shorthand via `From<[Felt; 4]>`
let w: Word = [felt!(1), felt!(2), felt!(3), felt!(4)].into();
// Shorthand via `From<[u32; 4]>` (or [u8; 4] / [u16; 4] / [bool; 4])
let w = Word::from([1u32, 2, 3, 4]);
// All-zero word
let z = Word::empty(); // same as Word::default()
Indexing
let w = Word::new([felt!(10), felt!(20), felt!(30), felt!(40)]);
// Named fields
let a: Felt = w.a; // felt!(10)
let d: Felt = w.d; // felt!(40)
// Convert to array
let arr: [Felt; 4] = w.into_elements();
// or via the `From<Word> for [Felt; 4]` impl
let arr2: [Felt; 4] = w.into();
Packing data into Words
Since each storage slot holds one Word, you'll often pack multiple values:
// Pack two u64 values into a Word
let config = Word::new([
Felt::new(max_amount).unwrap(), // a: max amount
Felt::new(cooldown).unwrap(), // b: cooldown blocks
felt!(0), // c: unused
felt!(0), // d: unused
]);
// Unpack via named fields
let max_amount = config.a.as_canonical_u64();
let cooldown = config.b.as_canonical_u64();
Asset
Asset represents either a fungible or non-fungible asset. In contract code it is two words — an id: AssetId (the asset ID used by the vault) and a value (encoding the fungible amount or non-fungible data).
pub struct Asset {
pub id: AssetId,
pub value: Word,
}
Encoding
Fungible assets (tokens):
| Word | Field | Content |
|---|---|---|
id.inner | a | 0 |
id.inner | b | 0 |
id.inner | c | Faucet ID suffix plus metadata byte |
id.inner | d | Faucet ID prefix |
value | a | Amount |
value | b | 0 |
value | c | 0 |
value | d | 0 |
Non-fungible assets (the standard NonFungibleAsset encoding):
| Word | Field | Content |
|---|---|---|
id.inner | a | Data hash element 0 |
id.inner | b | Data hash element 1 |
id.inner | c | Faucet ID suffix plus metadata byte |
id.inner | d | Faucet ID prefix |
value | a..d | Data hash elements 0–3 |
The low metadata byte in id.inner.c encodes version 1 in bits 0-3 and AssetComposition in bits 4-5; bits 6-7 are reserved and must be zero. Whether assets invoke callbacks is encoded in the faucet account ID when that account is built. Use the AssetId readers instead of hand-decoding the metadata.
Working with assets
use miden::{Asset, AssetId, Word, felt};
// Build a fungible asset from ID + value words supplied by the host.
// Fungible ID = [0, 0, faucet_suffix_with_metadata, faucet_prefix],
// with low metadata byte 0x11 (version 1, fungible composition).
// fungible value = [amount, 0, 0, 0].
let asset = Asset::new(
Word::from([felt!(0), felt!(0), faucet_suffix_with_metadata, faucet_prefix]),
Word::from([felt!(100), felt!(0), felt!(0), felt!(0)]),
);
// Read the amount (fungible): first limb of `value`.
let amount: u64 = asset.value.a.as_canonical_u64();
// Assets passed into contract procedures are already constructed by the host.
// Use the typed ID when querying the active account vault.
let asset_id: AssetId = asset.id;
let is_present = miden::active_account::has_asset(asset_id);
On the client / host side, miden-protocol exposes Asset as an AssetId plus an AssetValue, with id() / value() / to_id_word() / to_value_word() / from_id_and_value_words() helpers. Inside a Rust contract the SDK exposes the two-word struct shown above, with value still a Word.
See the protocol v0.17 definitions of Asset and AssetId for the host types and encoding rules.
AccountId
Identifies an account with two Felt values:
pub struct AccountId {
pub prefix: Felt,
pub suffix: Felt,
}
use miden::AccountId;
let id = AccountId::new(prefix_felt, suffix_felt);
// Use in comparisons
let current: AccountId = self.get_id();
assert_eq!(current.prefix, expected.prefix);
assert_eq!(current.suffix, expected.suffix);
Other types
The SDK also provides NoteIdx, Tag, NoteType, Recipient, Digest, and StorageSlotId. See the full API docs on docs.rs for their definitions.
Type conversion table
| From | To | Method |
|---|---|---|
u32 | Felt | Felt::from_u32(n) |
u64 | Felt | Felt::new(n).unwrap() |
| literal | Felt | felt!(n) |
Felt | u64 | f.as_canonical_u64() |
[Felt; 4] | Word | Word::new(arr) or Word::from(arr) |
[u32; 4] / [u16; 4] / [u8; 4] / [bool; 4] | Word | Word::from(arr) |
Word | [Felt; 4] | w.into_elements() or let arr: [Felt; 4] = w.into() |
Use these types in component definitions, store and retrieve Words from persistent storage, or define your own types for public APIs with #[export_type].