Skip to main content
Version: 0.17 (unstable)

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 (p=264−232+1p = 2^{64} - 2^{32} + 1), 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:

p=264−232+1=18446744069414584321p = 2^{64} - 2^{32} + 1 = 18446744069414584321

Felt uses modular arithmetic. Values wrap around the prime modulus, not at u64::MAX. Addition, subtraction, and multiplication all happen modulo pp. 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):

WordFieldContent
id.innera0
id.innerb0
id.innercFaucet ID suffix plus metadata byte
id.innerdFaucet ID prefix
valueaAmount
valueb0
valuec0
valued0

Non-fungible assets (the standard NonFungibleAsset encoding):

WordFieldContent
id.inneraData hash element 0
id.innerbData hash element 1
id.innercFaucet ID suffix plus metadata byte
id.innerdFaucet ID prefix
valuea..dData 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​

FromToMethod
u32FeltFelt::from_u32(n)
u64FeltFelt::new(n).unwrap()
literalFeltfelt!(n)
Feltu64f.as_canonical_u64()
[Felt; 4]WordWord::new(arr) or Word::from(arr)
[u32; 4] / [u16; 4] / [u8; 4] / [bool; 4]WordWord::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].

Full API docs on docs.rs: Felt, Word, Asset