Field Elements
BN254 scalar field arithmetic.
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.
Int vs Field
| Int | Field | |
|---|---|---|
| Range | -2^59 to 2^59-1 | 0 to p-1 |
| Overflow | Runtime error | Wraps modulo p |
| Negation | -x | p - x |
| Division | Truncating (7 / 2 = 3) | Modular inverse (1/2 = (p+1)/2) |
| Storage | Inline (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
Creating Field Elements
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
Arithmetic
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 Circuits
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.