The 3D sim treats modpow(g, a, p) as a black box — it prints the final residue and never shows the arithmetic. This 2D companion computes something genuinely different: it traces the actual square-and-multiply steps the algorithm takes, bit by bit through the binary expansion of the private exponent, and draws that trajectory as a path on a "clock" of the 22 nonzero residues mod p=23 arranged around a circle:
r = 1
for each bit of exponent, most-significant first:
r = r*r mod p (square — always)
if bit == 1: r = r*g mod p (multiply — only on a 1-bit)
draw an arrow r_prev -> r_new after every step
It also checks something the 3D sim assumes but never verifies on-screen: that g=5 is a primitive root mod 23, i.e. its multiplicative order is exactly p−1=22, so the powers g¹…g²² hit all 22 nonzero residues with no repeats before cycling back to 1. That's computed live at load time (not hard-coded) and is why the small toy group here has a genuinely non-trivial 22-element key space instead of collapsing onto a short cycle.
The replay-defense side is rebuilt as a live timeline chart instead of the 3D sim's one-shot log message: a moving "now" cursor sweeps rightward in real time after a handshake completes, the accepted freshness window is shaded, and pressing "Replay captured packet now" drops a marker at whatever instant you actually clicked — so you can watch the accept/reject boundary happen instead of reading a single number.
Verified with a standalone Node script: square-and-multiply matches naive repeated multiplication for every exponent 0–40; g=5's multiplicative order mod 23 is exactly 22 and its 22 powers are a full permutation of the nonzero residues; 20,000 random Diffie-Hellman exchanges produced matching shared keys 20,000/20,000 times; 20,000 simulated MITM (no-auth) sessions produced mismatched Alice/Bob keys 18,822/20,000 times, with the remaining ~5.9% coincidental matches roughly tracking the naive 1/22≈4.5% estimate for this residue space (the small gap is because exponents are drawn from a narrow 2–18 range, not uniformly); and 5,000 blind signature-forgery attempts against the toy signing key succeeded 0 times.
- Clock (left) — 22 ticks around a circle, one per nonzero residue mod 23; the trace for Alice's exponent is drawn in blue, Bob's in green, one arrow per square-and-multiply step, ending on the public value A or B.
- Node diagram (right) — Alice, Bob and (if toggled) Mallory as flat 2D nodes; a small square travels along the connecting line for every message the protocol sends, colored red when Mallory has substituted her own value.
- Timeline (bottom) — time since the last completed handshake; the shaded band is the accepted freshness window; the sweeping cursor is real wall-clock time, not a replay of history.
Real-world relevance: this is the same modular-exponentiation machinery (at production-sized primes) underneath TLS's finite-field Diffie-Hellman groups, and the same freshness-window + nonce-cache defense underneath TLS sequence numbers, Kerberos timestamps and WireGuard's rolling counters.