From d4a891bd2658dc05e63414fafdb131dda3164892 Mon Sep 17 00:00:00 2001 From: AlimMaster Date: Thu, 7 May 2026 15:31:20 +0700 Subject: [PATCH 1/3] docs(builder): clarify Felt division across builder docs --- docs/builder/smart-contracts/types.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/docs/builder/smart-contracts/types.md b/docs/builder/smart-contracts/types.md index 78ece75b..7d3434aa 100644 --- a/docs/builder/smart-contracts/types.md +++ b/docs/builder/smart-contracts/types.md @@ -67,6 +67,25 @@ x += felt!(1); // x is now felt!(6) x *= felt!(2); // x is now felt!(12) ``` +### Division + +`Felt` division only matches standard integer division when the result is exact. For `10 / 2`, both +`u64` arithmetic and `Felt` arithmetic produce `5`. But for `20 / 3`, the Miden VM computes +`20 * 3^(-1) mod p`, which yields a large field element instead of integer `6`. + +| Expression | `u64` result | `Felt` result | +|------------|--------------|---------------| +| `10 / 2` | `5` | `5` | +| `20 / 3` | `6` | `6148914689804861447` | + +```rust +let exact_u64 = 10_u64 / 2; // 5 +let exact_felt = felt!(10) / felt!(2); // 5 + +let integer_div = 20_u64 / 3; // 6 +let field_div = felt!(20) / felt!(3); // 6148914689804861447 +``` + :::note For business logic, prefer u64 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()`. ::: From e1ae4da4ebf919c2c0e85acf6427653419d85d5d Mon Sep 17 00:00:00 2001 From: AlimMaster Date: Thu, 7 May 2026 15:34:34 +0700 Subject: [PATCH 2/3] docs(builder): clarify Felt division across builder docs --- docs/builder/smart-contracts/patterns.md | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/docs/builder/smart-contracts/patterns.md b/docs/builder/smart-contracts/patterns.md index 114ec53a..58197c4a 100644 --- a/docs/builder/smart-contracts/patterns.md +++ b/docs/builder/smart-contracts/patterns.md @@ -57,11 +57,29 @@ let elapsed = current_block - last_block; For Felt arithmetic, values wrap modulo the prime field (no overflow panic), but the result may not be what you expect if you're treating Felts as integers. See [Types — Felt](./types#felt--field-elements) for details. +### When to use Felt vs u64 + +Use `Felt` when you need field-native behavior that must match the Miden VM exactly: + +- Hashing and commitment inputs +- Storage words and protocol-defined field values +- Arithmetic that is intentionally part of a field-based construction + +Use `u64` when you are working with business quantities and expect integer semantics: + +- Token amounts and balances +- Fee calculations and proportional splits +- Counters, limits, cooldowns, and similar control-flow values + +The `as_u64()` conversion is zero-cost and gives you standard Rust integer behavior. For DeFi-style +logic, convert out of `Felt`, do the arithmetic in `u64`, and convert back with +`Felt::from_u64_unchecked()` once you know the result is in range. + ### Anti-patterns - **Don't store secrets in contract code** — contract code is visible on-chain - **Don't skip nonce management** — prevents replay attacks -- **Be careful with Felt division** — Felt division computes the multiplicative inverse, not integer division. Convert to `u64` first for integer-style operations +- **Don't use Felt division for business logic** — convert to `u64` first when you need integer-style division or rounding ## `#![no_std]` environment From 9dc28c5c52c7293b0dbfd675f61cac3292d24509 Mon Sep 17 00:00:00 2001 From: AlimMaster Date: Thu, 7 May 2026 15:41:20 +0700 Subject: [PATCH 3/3] docs(builder): add Felt division pitfall for Rust compiler guide --- docs/builder/tutorials/helpers/pitfalls.md | 52 ++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/docs/builder/tutorials/helpers/pitfalls.md b/docs/builder/tutorials/helpers/pitfalls.md index 23ae65c7..cc03c7e2 100644 --- a/docs/builder/tutorials/helpers/pitfalls.md +++ b/docs/builder/tutorials/helpers/pitfalls.md @@ -338,6 +338,57 @@ Failure to validate before subtraction can lead to: --- +## Felt Division Is Not Integer Division + +### Problem + +Using `/` on `Felt` values can look correct in simple cases and then break as soon as the division +is not exact. + +```rust +let exact = Felt::new(10) / Felt::new(2); // 5 +let unexpected = Felt::new(20) / Felt::new(3); +// 6148914689804861447, not 6 +``` + +This is especially dangerous for token amounts, fee calculations, and proportional splits, where +developers usually expect integer division semantics. + +### Why This Happens + +`Felt` division in the Miden VM is field division. Instead of truncating or rounding, it multiplies +by the multiplicative inverse of the divisor in the Goldilocks field. + +That means: + +- `10 / 2` works out to `5`, so the behavior can look harmless at first +- `20 / 3` becomes `20 * 3^(-1) mod p`, which is `6148914689804861447` + +This is correct field arithmetic, but it is not the same operation as Rust integer division. + +### Solution + +For business logic, convert to `u64`, do the integer arithmetic there, and convert back only after +the calculation is complete: + +```rust +let total_amount: u64 = total.inner[0].as_u64(); +let recipients: u64 = recipient_count.as_u64(); + +let share = total_amount / recipients; +let share_felt = Felt::from_u64_unchecked(share); +``` + +Use `Felt` division only when you explicitly need field semantics for protocol, algebraic, or +cryptographic logic. + +:::warning Do not use Felt division for balances or pricing math +If the value represents an amount, balance, fee, or ratio that users reason about as an integer, +do the calculation in `u64`. +::: + +--- + ## Wallet Component Requirement ### Problem @@ -490,6 +541,7 @@ The native hash function changed from RPO to Poseidon2 in v0.14, so every MAST r | Too many args | "4 words" error | Group into Words, use inputs | | Array reversal | Wrong data order | Be consistent with construction | | Felt underflow | Balance wraps to huge number | Validate before subtraction | +| Felt division | Huge unexpected result from `/` | Convert to `u64` first | | Missing wallet | Asset operation fails | Add `BasicWallet` component | | Key mismatch | Zero balances | Use helper function for keys | | Note type | Wrong note visibility | Use 1 (Public) or 2 (Private) |