Skip to content

Field Elements

A field element is a number in the BN254 scalar field — integers modulo the prime:

p = 21888242871839275222246405745257275088548364400416034343698204186575808495617

All arithmetic on field elements is modular: addition, subtraction, and multiplication wrap around at p, and division computes the modular inverse.

IntField
Range-2^59 to 2^59-10 to p-1
OverflowRuntime errorWraps modulo p
Negation-xp - x
DivisionTruncating (7 / 2 = 3)Modular inverse (1/2 = (p+1)/2)
StorageInline (60-bit tagged)Heap-allocated (256-bit Montgomery)

Int and Field are distinct types. Mixing them in arithmetic is a runtime error:

0p3 + 5 // Error: Cannot mix Int and Field
0p3 + 0p5 // OK: 0p8

Use the 0p prefix to create field elements. It works like 0x for hex:

let a = 0p42 // decimal field literal
let b = 0pxFF // hex field literal (0px prefix)
let c = 0pb1010 // binary field literal (0pb prefix)
let d = 0p12345 // large decimal

Field elements support +, -, *, /, ^, and ==:

let a = 0p10
let b = 0p3
let sum = a + b // 0p13
let diff = a - b // 0p7
let prod = a * b // 0p30
let quot = a / b // modular inverse of 3, times 10
let pow = a ^ 5 // 10^5 mod p
// Negative exponents compute modular inverse
let inv = a ^ -1 // same as 0p1 / a

In circuit mode (prove {} blocks and circuit CLI), all values are field elements implicitly. Integer variables captured by a prove {} block are converted to field elements automatically:

let x = 42
prove(x: Public) {
// x is automatically converted to 0p42 inside the circuit
assert_eq(x, 42)
}

This is the only place where Int→Field conversion happens implicitly. In regular VM execution, the conversion must always be explicit via 0p field literals.