Skip to main content
Version: 0.14 (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=264232+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=264232+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};

// Compile-time literal (validated at compile time)
let zero = felt!(0);
let one = felt!(1);
let answer = felt!(42);

// From u32 (always safe)
let f = Felt::from_u32(255);

// From u64 without range check (caller ensures value < p)
let f = Felt::from_u64_unchecked(1_000_000_000);

// From u64 with validation (returns Result)
let f = Felt::new(999).unwrap();

The felt!() macro currently only accepts values up to u32::MAX (4,294,967,295). For larger values, use Felt::from_u64_unchecked(). This limitation may be lifted in a future release.

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)

Felt arithmetic is modular — there are no overflow panics and no underflow protection. 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::from_u64_unchecked().

Comparison and conversion

let f = felt!(42);

// Convert to u64 (canonical representation)
let n: u64 = f.as_u64();

// Equality comparison
if f == felt!(42) { /* ... */ }

// For numeric comparisons, convert to u64 first
if f.as_u64() > 100 { /* ... */ }

// Check parity
if f.is_odd() { /* ... */ }

Converting Felt to u64 with .as_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_u64();
let b: u64 = felt_b.as_u64();
let sum = a.saturating_add(b); // safe addition
let diff = a.saturating_sub(b); // no underflow
let result = Felt::from_u64_unchecked(sum);

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

// Power of 2: computes 2^self
let power = felt!(10).pow2(); // 2^10 = 1024 (panics if self > 63)

Word — Four-element tuples

A Word is a tuple of four Felt values. It's the standard unit for storage, hashing, and data passing in Miden.

#[repr(C, align(16))]
pub struct Word {
pub inner: (Felt, Felt, Felt, 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 from array (via From trait)
let w = Word::from([felt!(1), felt!(2), felt!(3), felt!(4)]);

// From 4 u64 values (unchecked)
let w = Word::from_u64_unchecked(1, 2, 3, 4);

// From a single Felt (placed in position [3], positions [0]–[2] zeroed)
let w = Word::from(felt!(42)); // [felt!(0), felt!(0), felt!(0), felt!(42)]

// From a tuple
let w = Word::from((felt!(1), felt!(2), felt!(3), felt!(4)));

Indexing

let w = Word::from([felt!(10), felt!(20), felt!(30), felt!(40)]);

// Read by index
let first: Felt = w[0]; // felt!(10)
let last: Felt = w[3]; // felt!(40)

// Mutable indexing
let mut w = Word::from([felt!(0), felt!(0), felt!(0), felt!(0)]);
w[0] = felt!(99);

// Convert to array
let arr: [Felt; 4] = w.into();

// Convert to tuple
let tup: (Felt, Felt, Felt, Felt) = 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::from([
Felt::from_u64_unchecked(max_amount), // [0]: max amount
Felt::from_u64_unchecked(cooldown), // [1]: cooldown blocks
felt!(0), // [2]: unused
felt!(0), // [3]: unused
]);

// Unpack
let max_amount = config[0].as_u64();
let cooldown = config[1].as_u64();

Asset

Asset wraps a Word and represents either a fungible or non-fungible asset.

pub struct Asset {
pub inner: Word,
}

Encoding

Fungible assets (tokens):

IndexContent
inner[0]Amount
inner[1]0
inner[2]Faucet ID suffix
inner[3]Faucet ID prefix

Non-fungible assets (NFTs):

IndexContent
inner[0]Data hash element 0
inner[1]Data hash element 1
inner[2]Data hash element 2
inner[3]Faucet ID prefix

Working with assets

use miden::Asset;

// Create from a Word
let asset = Asset::new([felt!(100), felt!(0), faucet_suffix, faucet_prefix]);

// Read the amount (fungible)
let amount: u64 = asset.inner[0].as_u64();

// Build a fungible asset from faucet ID and amount
use miden::asset;
let asset = asset::build_fungible_asset(faucet_id, felt!(1000));

// Build a non-fungible asset
let nft = asset::build_non_fungible_asset(faucet_id, data_hash);

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 = active_account::get_id();
assert_eq(current.prefix, expected.prefix);
assert_eq(current.suffix, expected.suffix);

Other types

TypeDefinitionDescription
NoteIdx{ inner: Felt }Index of an output note in the current transaction
Tag{ inner: Felt }Note tag for filtering/routing
NoteType{ inner: Felt }Note visibility (public or private)
Recipient{ inner: Word }Computed note recipient (hash of serial number + script + inputs)
Digest{ inner: Word }Cryptographic hash output (RPO256)
StorageSlotId{ suffix: Felt, prefix: Felt }Identifies a storage slot

Type conversion table

FromToMethod
u32FeltFelt::from_u32(n)
u64FeltFelt::from_u64_unchecked(n) or Felt::new(n)?
literalFeltfelt!(n)
Feltu64f.as_u64()
FeltWordWord::from(f) — fills position 3, rest zeroed
WordFeltlet f: Felt = w.into() — extracts position 3
[Felt; 4]WordWord::from(arr)
Word[Felt; 4]let arr: [Felt; 4] = w.into()
(Felt, Felt, Felt, Felt)WordWord::from(tuple)
WordDigestDigest::from_word(w)
DigestWordlet w: Word = d.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