Learn / Math / Finite Fields
06. Finite Fields
Modular Arithmetic · Lesson 7 of 18 · 4:08
The name for everything the last two lessons built — a closed system of addition, subtraction, multiplication, and division — and why every signal inside a Circom circuit is secretly an element of one.

The last two lessons built modular addition, subtraction, multiplication, and — through modular inverses — division. Today all four get packaged into one idea with a name: a finite field.

What a field actually is

Strip away the “modular” part for a moment. A field is just a set of numbers where addition, subtraction, multiplication, and division all work, and the result never leaves that same set. The real numbers are the everyday example: add, subtract, multiply, or divide any two of them (division by zero aside, which is never allowed anywhere) and the answer is still a real number.

A field, informally

A set where +,−,×,÷+, -, \times, \div all stay inside the set. The real numbers are one example — division by 00 is the one operation that’s never defined, in any field.

Defining GF(p)

A finite field, written GF(p)GF(p), is the exact same idea, just with a finite set to work in: the numbers 00 through p−1p - 1, with every operation done modulo pp.

GF(p)

GF(p)={0,1,2,…,p−1},arithmetic done  mod pGF(p) = \{0, 1, 2, \ldots, p-1\}, \quad \text{arithmetic done } \bmod p

Addition, subtraction, and multiplication mod pp were already covered two lessons back. Division works because of the lesson right before this one: every nonzero number has a modular inverse, as long as pp is prime — which is exactly why it’s GF(p)GF(p), built on a prime, and not GF(n)GF(n) for just any modulus.

Closure: the property that makes it a field

The one property that defines a field is closure — no matter which of the four operations gets used, the result can never escape the set. Running the test against GF(7)GF(7) makes this concrete:

closure test — GF(7) = {0, 1, 2, 3, 4, 5, 6} add 5 + 4 mod 7 = 2 ✓ inside the set subtract 5 − 6 mod 7 = 6 ✓ inside the set multiply 5 × 6 mod 7 = 2 ✓ inside the set divide 5 ÷ 6 mod 7 = 4 ✓ inside the set
Fig. 1 — all four operations on GF(7), each one landing back inside {0, ..., 6}.

Every single result stays inside {0,1,…,6}\{0, 1, \ldots, 6\} — including the division, which only works at all because 66 has a modular inverse mod 77.

A full worked example: GF(5)

The smallest field worth looking at closely is GF(5)GF(5) — the set {0,1,2,3,4}\{0, 1, 2, 3, 4\}. Every nonzero element pairs up with exactly one other element as its inverse, with nothing left over:

GF(5) = {0, 1, 2, 3, 4} — every inverse 1 1 × 1 = 1 → mod 5 = 1 1⁻¹ = 1 2 2 × 3 = 6 → mod 5 = 1 2⁻¹ = 3 3 3 × 2 = 6 → mod 5 = 1 3⁻¹ = 2 4 4 × 4 = 16 → mod 5 = 1 4⁻¹ = 4 every non-zero element pairs up with exactly one other — nothing is left out
Fig. 2 — every nonzero element of GF(5), matched with its inverse. Nothing is left out.

11 is its own inverse, 44 is its own inverse, and 22 and 33 pair up with each other — four numbers, two pairs, zero exceptions.

Why p has to be prime

The previous lesson already supplied the counter-example: 22 has no inverse mod 66, because gcd⁡(2,6)=2\gcd(2, 6) = 2, not 11. Read as a field test, that single failure is enough to disqualify mod 66 entirely.

mod 6 2 × x ≡ 1 (mod 6) no x ever works ✗ not a field — gcd(2,6) = 2 mod 7 2 × 4 = 8 ≡ 1 (mod 7) every non-zero number works ✓ a true field — 7 is prime
Fig. 3 — mod 6 fails closure under division; mod 7 passes, because 7 is prime.

One missing inverse is all it takes — if even a single nonzero element has no partner, division stops being defined for every input, and the set fails to be a field. That single requirement, that the modulus be prime, is why every ZK system builds its arithmetic on a prime.

Field elements are circuit signals

Here’s the payoff for all of this: in Circom, every signal in a circuit is a finite field element — a number somewhere between 00 and p−1p - 1, where pp is the same enormous BN254 prime introduced back in the divisibility lesson.

signal <== value value is a number between 0 and p-1 value ∈ GF(p) p = the BN254 prime from the divisibility lesson +, −, ×, ÷ in a circuit are all finite-field operations
Fig. 4 — a Circom signal isn't just a number — it's an element of GF(p), with p the BN254 prime.

Every +, -, *, and / written in circuit code is, underneath, a finite field operation — the same four operations this lesson just finished defining, just running at a scale no one ever does by hand.

Why the field has to be huge

A small prime like 77 or 101101 would satisfy every definition in this lesson just as well as BN254’s prime does — so why not use one? The field’s size is exactly what determines how much room exists for a secret value to hide in.

GF(7) 7 elements ✗ brute-forceable instantly GF(BN254 prime) ≈ 2254 elements ✓ computationally infeasible to search
Fig. 5 — GF(7) is small enough to search directly; GF(BN254 prime) is nowhere close.
The scale that matters

GF(7)GF(7) has 77 elements — trivial to search by hand. The BN254 field has roughly 22542^{254} elements: computationally invisible to search, even though it’s built from exactly the same clean structure as GF(7)GF(7). Every idea in this lesson scales up unchanged; only the size of the haystack changes.

Addition, subtraction, multiplication, division, all closed, all built on a single prime — that’s the entire structure a Circom circuit runs on. The next lessons build on top of it: polynomials, which turn a field’s numbers into something that can encode an entire computation at once.