Finite groups, cyclic groups, and generators — the foundation of elliptic curve crypto
💍 One Element to Rule Them All
Imagine a group where a single element can generate every other element...
...just by combining it with itself, over and over.
Cyclic Group: One seed that grows the entire garden. Clock arithmetic: start at 12, add 1 repeatedly → you visit every hour.
In ZK proofs, we ONLY use these groups. Today we learn why.
Agenda
Quick Groups recap
Gallery of Group examples
Finite groups & group order
Cyclic groups & generators
Primitive roots
Key properties: uniqueness of identity, cyclic ⇒ abelian
Groups in ZK proofs
Quick Recap: What is a Group?
A set with a binary operator that has four properties:
Closure: a □ b is always in the set
Associativity: (a □ b) □ c = a □ (b □ c)
Identity: there exists e such that a □ e = a
Inverse: for every a, there exists a' such that a □ a' = e
If the operator is also commutative, the group is abelian.
Example 1: The Trivial Group
# The set {0} with addition
# Closure: 0 + 0 = 0 ✓ (stays in set)
# Associative: (0+0)+0 = 0+(0+0) ✓
# Identity: 0 (adding 0 gives 0) ✓
# Inverse: 0's inverse is 0 ✓
# This is the smallest possible group
# A group CANNOT be empty — it must have at least the identity
Similarly, {1} under multiplication is a group.
These are trivial but valid — the smallest groups possible.
Example 2: Real Numbers under ×
Are real numbers a group under multiplication?
✓ Closed: product of reals is a real
✓ Associative: (a×b)×c = a×(b×c)
✓ Identity: 1
✗ Inverse: the inverse of a is 1/a, but 1/0 is undefined!
Zero has no multiplicative inverse.
But ℝ\{0} (reals excluding zero) under × IS a group!
Domain sensitivity: the exact same operation can form a group or not, depending on the set.
Domain Sensitivity
Same operation, different set, different result.
Set
Operation
Group?
Beginner reason
All integers ℤ
+
Yes
0 exists, and every number has an opposite
Integers ℤ
×
No
2 has no inverse inside integers (1/2 not in ℤ)
Non-zero reals ℝ\{0}
×
Yes
Every number has 1/a
𝔽ₚ
+ mod p
Yes
Inverse of a is p-a
𝔽ₚ\{0}
× mod p
Yes
Every non-zero has multiplicative inverse
Tiny change in the set can break a group. Always ask: what is the exact set?
Example: Matrices as Groups
✓ n×m matrices under +
Closed: sum is same dimensions
Associative: matrix + is associative
Identity: zero matrix
Inverse: negate each element
✓ n×n with det≠0 under ×
Closed: det(AB) = det(A)×det(B)
Associative: matrix × is
Identity: identity matrix
Inverse: matrix inverse exists
Note: n×n matrices with det=0 under × are NOT even a Monoid!
The identity matrix has det=1, not det=0, so it's excluded from the set.
Example: Polynomials under Addition
from galois import GF, Poly
GF7 = GF(7)
# Polynomials of degree ≤ 3 over GF(7) form a group under addition
f = Poly([3, 2, 5, 1], field=GF7) # 3x³ + 2x² + 5x + 1
g = Poly([4, 5, 2, 6], field=GF7) # 4x³ + 5x² + 2x + 6
# Closure: sum is still degree ≤ 3
print(f"f + g = {f + g}") # coefficients reduced mod 7
# Identity: zero polynomial
zero = Poly([0], field=GF7)
print(f"f + 0 = {f + zero}") # same as f
# Inverse: negate coefficients (mod 7)
neg_f = -f
print(f"f + (-f) = {f + neg_f}") # zero polynomial
Polynomials under × are NOT a group — degree increases, breaking closure for bounded degree.
Addition Modulo a Prime
p = 7
# Build the complete group table
print("Addition mod 7:")
print(" | " + " ".join(f"{b}" for b in range(p)))
print("---+" + "-" * (2 * p))
for a in range(p):
row = " ".join(f"{(a+b) % p}" for b in range(p))
print(f" {a} | {row}")
# Verify group properties:
# Identity: 0 (row/column 0 gives same element)
# Inverse of 5: 2 (because 5+2 = 7 ≡ 0)
for a in range(p):
inv = (p - a) % p
assert (a + inv) % p == 0
print(f" Inverse of {a} is {inv}")
Multiplication Modulo a Prime (Excluding 0)
Use set {1,2,3,4,5,6}. We exclude 0 because 0 has no multiplicative inverse.
p = 7
# Step 1: identity check
for a in range(1, p):
assert (a * 1) % p == a
# Step 2: find inverse of each element
for a in range(1, p):
inv = pow(a, -1, p)
print(f"{a} inverse is {inv} because {a}*{inv} % 7 = {(a*inv)%7}")
# Output pairs:
# 1<->1, 2<->4, 3<->5, 6<->6
Group order here is 6 (because there are 6 non-zero elements).
Finite Groups & Order
A finite group has a finite number of elements.
The order of a group is the number of elements in it.
𝔽₇ under addition: order = 7
𝔽₇\{0} under multiplication: order = 6
All integers under addition: infinite order
In ZK proofs, we ONLY use finite groups.
The order of the group determines the security level.
Cyclic Groups
A cyclic group is a group where every element can be generated by repeatedly applying the binary operator to a single generator element.
# Addition mod 7 is cyclic with generator 1:
p = 7
g = 1
print("Generating all elements from g=1:")
for i in range(p):
print(f" {i}*g mod 7 = {(i*g) % p}")
# Output: 0, 1, 2, 3, 4, 5, 6 — every element!
Starting from 1 and repeatedly adding 1 generates: 1, 2, 3, 4, 5, 6, 0 — every element of the group.
Multiplicative Cyclic Groups
Multiplication mod 7 (excluding 0) — not every element is a generator!
✗ Generator = 2?
p = 7
g = 2
print("Powers of 2 mod 7:")
for i in range(1, p):
print(f" 2^{i} = {pow(2,i,p)}")
# 2, 4, 1, 2, 4, 1...
# Only generates {1, 2, 4}
# NOT a generator!
✓ Generator = 3!
p = 7
g = 3
print("Powers of 3 mod 7:")
for i in range(1, p):
print(f" 3^{i} = {pow(3,i,p)}")
# 3, 2, 6, 4, 5, 1
# Generates {1,2,3,4,5,6}
# IS a generator!
An element that generates the entire multiplicative group is called a primitive root.
Finding Primitive Roots
Manual method first, library second.
# Manual check in mod 7
p = 7
for g in range(1, p):
seen = []
v = 1
for _ in range(p - 1):
v = (v * g) % p
seen.append(v)
ok = len(set(seen)) == (p - 1)
print(g, seen, "GEN" if ok else "no")
# Then optional automation:
from galois import GF
print(list(GF(7).primitive_elements))
In mod 7, primitive roots are 3 and 5.
⚡ Speed Round: Generator Hunt
Compute powers mod 7. Is the element a generator of ℤ₇*?
Element
Powers mod 7
Generator?
g = 2
2, 4, 1 (only 3 elements)
NO
g = 3
3, 2, 6, 4, 5, 1 (all 6!)
YES ✓
g = 4
4, 2, 1 (only 3 elements)
NO
g = 5
5, 4, 6, 2, 3, 1 (all 6!)
YES ✓
Only 2 out of 6 elements are generators. How many generators does mod 13 have? φ(p−1) = φ(12) = φ(4)×φ(3) = 2×2 = 4 generators
Cyclic ⇒ Abelian
If a group is cyclic, it is automatically abelian (commutative).
Proof sketch in one line:
If p = g^m and q = g^n, then p*q = g^(m+n) = g^(n+m) = q*p.
Elliptic curve groups in ZK are cyclic → therefore abelian
The converse is NOT true: abelian does not imply cyclic
ℝ under addition is abelian but NOT cyclic (no single generator)
The Identity Element is Unique
Proof by contradiction:
Suppose both e and e' are identity elements.
Then a □ a⁻¹ = e, and also a □ a⁻¹ = e'
So e = a □ a⁻¹ = e'
Therefore e = e'. ∎
A group has exactly one identity element
For addition groups: the identity is 0
For multiplication groups: the identity is 1
For elliptic curves: the identity is the "point at infinity"
This is exactly how scalar multiplication on elliptic curves works!
G, 2G, 3G, ... nG wraps around, just like b¹, b², b³... wraps mod p.
Groups in Zero Knowledge Proofs
Understanding groups gives you a vocabulary for ZK:
"Inverse" → you immediately know what this means
"Identity" → the neutral element
"Cyclic" → everything comes from a generator
"Order" → how many elements before wrapping
"Abelian" → order of operations doesn't matter
Groups help us reason about complex objects without understanding their implementation.
If someone tells you EC points form a group, you already know how they behave!
Preview: EC Points as a Cyclic Group
# This is what we'll be doing in Workshop 6:
# from py_ecc.bn128 import G1, multiply, add, eq, neg
# G1 is the generator point
# multiply(G1, 5) → 5G (add G to itself 5 times)
# add(A, B) → A + B (group binary operator)
# neg(A) → -A (group inverse)
# eq(A, B) → A == B
# Key identity:
# multiply(G1, a) + multiply(G1, b) = multiply(G1, a + b)
Every concept from this workshop maps directly to EC operations:
Generator = G1 | Identity = point at infinity | Inverse = neg(P)
Key Takeaways
Groups are sensitive to their domain — same operation, different sets, different structures
Finite groups have a specific order (number of elements)
Cyclic groups can be generated from a single element
Primitive roots generate the full multiplicative group
Cyclic ⇒ Abelian: cyclic groups are always commutative
Identity is unique: there's exactly one per group
In ZK, we exclusively use finite cyclic groups
Practice Problems
List all elements generated by 2 in the multiplicative group mod 11. Is 2 a primitive root?
Prove that if a group has prime order p, then every non-identity element is a generator.
Why can't strings under concatenation form a group? Identify which specific property fails.
For the group ℤ₁₃ under addition, find the inverse of every element.
Build the multiplication table for {1,2,3,4} mod 5. Verify all four group properties.
Find all primitive roots of GF(13) using the galois library or manually.
Next Workshop
Homomorphisms
Structure-preserving maps between groups
Many examples: integers → powers, strings → lengths
Homomorphic encryption
How ZK proofs use homomorphisms
Homomorphisms are the mathematical foundation of zero knowledge — proving computations without revealing inputs.