Introducing Achronyme — a language for zero-knowledge proofs. Read the announcement arrow_right_alt

Field Elements

Prime field arithmetic — BN254, BLS12-381, and Goldilocks.

A field element is a number in a prime field — integers modulo a prime p. All arithmetic is modular: addition, subtraction, and multiplication wrap around at p, and division computes the modular inverse.

Supported Fields

Achronyme supports three prime fields via the FieldBackend trait:

FieldModulus bitsReprUse case
BN254 (default)254[u64; 4] MontgomeryGroth16, Ethereum (EVM precompiles)
BLS12-381255[u64; 4] MontgomeryZcash, Filecoin, Ethereum beacon chain
Goldilocks64u64 directSTARKs (Plonky2/Plonky3), fast prover

The default field is BN254 (the same field used by circom, snarkjs, and Ethereum):

p = 21888242871839275222246405745257275088548364400416034343698204186575808495617

Int vs Field

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

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.

Navigation