Modular Arithmetic
Goal
By the end of this chapter, you should be able to compute with remainders, understand congruence modulo , find greatest common divisors, compute modular inverses, and use repeated squaring for modular exponentiation.
You should also understand why repeated squaring is one of the basic operations behind verifiable delay functions.
Prerequisites
You should know the integers:
You do not need prior number theory. The only assumption is that you are comfortable with ordinary addition, multiplication, division with remainder, and basic loops.
Motivation
Many cryptographic systems work with finite sets of numbers. Instead of allowing integers to grow forever, we reduce them by a modulus and keep only a remainder. This gives a controlled arithmetic world where values stay bounded.
Modular arithmetic appears in finite fields, elliptic curves, signatures, hashing constructions, and verifiable delay functions. It is one of the foundational tools for the rest of the book.
Divisibility
An integer divides an integer if is an exact multiple of . We write:
This means there is an integer such that:
Example:
because .
But:
because no integer satisfies .
Remainders
When you divide one integer by another positive integer, you can write:
where:
- is the number being divided
- is the divisor
- is the quotient
- is the remainder
Example:
So the remainder when is divided by is .
In programming, this is the idea behind a % n, though programming languages
can differ on negative inputs. In this book, the remainder modulo is always
chosen from:
Congruence Modulo
Two integers are congruent modulo if they have the same remainder when divided by . We write:
Equivalent definition:
Example:
because:
and divides .
Another example:
because both and have remainder when divided by .
Modulo , every integer behaves like one of the numbers:
These are the residue classes modulo .
Modular Addition
To add modulo , add normally and then reduce the result modulo .
Example:
Modulo :
So:
This is clock arithmetic. If it is 8 o'clock and 9 hours pass, the clock shows 5 o'clock.
Modular Multiplication
To multiply modulo , multiply normally and reduce the result modulo .
Example:
Modulo :
So:
Modular multiplication keeps numbers bounded even when many multiplications are performed.
Greatest Common Divisor
The greatest common divisor of two integers and , written , is the largest positive integer that divides both and .
Example:
The positive divisors of are:
The positive divisors of are:
The common divisors are:
So:
If , then and are coprime.
Euclidean Algorithm
The Euclidean algorithm computes efficiently using repeated division with remainder.
The key fact is:
Example: compute .
First divide:
So:
Continue:
So:
Continue:
The last nonzero remainder is , so:
Pseudocode:
function gcd(a, b):
while b != 0:
r = a mod b
a = b
b = r
return abs(a)
Extended Euclidean Algorithm
The extended Euclidean algorithm finds more than the gcd. It finds integers and such that:
This is called Bezout's identity.
Example: find and for and .
We know:
Run the Euclidean algorithm:
Rearrange:
So and :
A slightly larger example shows the back-substitution pattern. Compute :
Now work backward:
Since :
Since :
Since :
So:
Pseudocode:
function extended_gcd(a, b):
old_r = a
r = b
old_s = 1
s = 0
old_t = 0
t = 1
while r != 0:
q = old_r div r
(old_r, r) = (r, old_r - q * r)
(old_s, s) = (s, old_s - q * s)
(old_t, t) = (t, old_t - q * t)
return (old_r, old_s, old_t)
The return values mean:
where .
Modular Inverses
A modular inverse of modulo is a number such that:
Not every number has a modular inverse. The number has an inverse modulo exactly when:
Example: find the inverse of modulo .
We need a number such that:
Try small values:
So:
For a larger example, use the extended Euclidean algorithm. Earlier we found:
Modulo , this becomes:
So the inverse of modulo is .
Pseudocode:
function inverse_mod(a, n):
(g, x, y) = extended_gcd(a, n)
if g != 1:
error "inverse does not exist"
return x mod n
Modular Exponentiation
Modular exponentiation means computing:
The direct method multiplies by itself times. That is too slow when is large.
Example:
Compute normally:
Then reduce:
So:
But for large exponents, we want to reduce as we go:
Same answer, smaller intermediate numbers.
Repeated Squaring
Repeated squaring computes powers efficiently by using the binary representation of the exponent.
Example: compute .
Write:
Compute powers by squaring:
Now multiply the powers for , , and :
So:
Pseudocode:
function pow_mod(base, exponent, modulus):
result = 1
base = base mod modulus
while exponent > 0:
if exponent is odd:
result = (result * base) mod modulus
base = (base * base) mod modulus
exponent = floor(exponent / 2)
return result
This algorithm uses only about squaring steps for exponent , plus some multiplications.
Why Repeated Squaring Matters for VDFs
Repeated squaring is fast when you are allowed to choose the exponent and use its binary representation. But VDFs are interested in a different shape of computation: a long chain of squarings that is deliberately hard to parallelize.
One simplified VDF-style operation is:
In a group where the order is unknown, the straightforward way to compute this is to square repeatedly:
y = x
repeat T times:
y = y * y
return y
After one step:
After two steps:
After three steps:
After steps:
The important intuition is that each squaring depends on the previous result. That dependency is what makes repeated squaring relevant to verifiable delay functions. This is not yet a full VDF construction or security proof; later chapters will add unknown-order groups and Wesolowski proofs.
Chia Connection
Chia uses proof of space and proof of time. The proof-of-time side relies on verifiable delay functions, and repeated squaring is the core sequential operation behind the VDF path studied later in this book.
Modular arithmetic also prepares us for finite fields, elliptic curves, and BLS signatures. In those chapters, values are often reduced modulo a prime or an algebraic modulus, and the arithmetic rules must be followed exactly.
This chapter gives the arithmetic vocabulary. Chia-specific constants, serialization formats, and consensus rules must still be checked against Chia documentation, Chia Network repositories, and protocol specifications.
Source starting points: Chia Proof of Time and Chia Proof of Space.
Common Pitfalls
Confusing division with modular inverse. In modular arithmetic, division by means multiplication by , and may not exist.
Forgetting the modulus. The statement is incomplete. You must say the modulus, such as .
Assuming every nonzero number has an inverse. This is true modulo a prime, but not true modulo every integer. For example, has no inverse modulo .
Letting intermediate values grow unnecessarily. Reduce modulo during the computation, not only at the end, especially in code.
Trusting % without checking negative behavior. Programming languages can
handle negative remainders differently. Mathematical residues modulo are
usually chosen from through .
Confusing fast exponentiation with VDF delay. Repeated squaring can be used for fast modular exponentiation, but VDFs rely on a sequential squaring process in a setting where shortcuts are not available in the same way.
Exercises
- Compute the remainder when is divided by .
- Decide whether . Explain your answer using divisibility.
- Compute and .
- Use the Euclidean algorithm to compute .
- Use the extended Euclidean algorithm to find integers and such that .
- Find the inverse of modulo , or explain why it does not exist.
- Find the inverse of modulo , or explain why it does not exist.
- Compute using repeated squaring.
- Write pseudocode for a function that tests whether has an inverse modulo .
- In your own words, explain why the computation is sequential.
Further Reading
- Later chapter: Groups
- Later chapter: Finite Fields
- Later chapter: Unknown-Order Groups
- Later chapter: Wesolowski VDF
- Any introductory number theory text covering congruences and the Euclidean algorithm