def verify(self, g: int, y: int, pi: int, T: int) -> bool:
The Wesolowski VDF is implemented over RSA groups. Below is the core logic — the full file is at ~/wesolowski_vdf.py.
Given RSA modulus N, base g, and time parameter T:
| Step | Prover (O(T) sequential) | Verifier (O(log T)) |
|---|---|---|
| 1 | Compute y = g^{2^T} mod N via T repeated squarings |
— |
| 2 | Derive challenge L = H(g, y, T) (hash to prime) |
Derive L = H(g, y, T) |
| 3 | Compute proof π = g^{q} mod N where q = ⌊2^T / L⌋ via incremental construction (second sequential pass) |
Compute r = 2^T mod L via fast modular exponentiation pow(2, T, L) |
| 4 | Output (y, π) |
Accept iff y ≡ π^L · g^r (mod N) |
Correctness: y = g^{q·L + r} = (g^q)^L · g^r = π^L · g^r (mod N).
Soundness (adaptive root assumption): A prover who produces (y, π) passing the check for a fresh prime L, where y ≠ g^{2^T}, can be rewound to extract an L-th root of y·g^{-r} — violating the assumption that finding h^{1/L} in QR(N) is hard.
Since 2^T is astronomically large, we never compute it directly. Instead we maintain r_i = 2^i mod L and π_i = g^{⌊2^i/L⌋} mod N incrementally:
π_0 = 1, r_0 = 1
For i = 0 … T-1:
2^{i+1} = 2·(q_i·L + r_i) = (2·q_i)·L + 2·r_i
⇒ q_{i+1} = 2·q_i + ⌊2·r_i / L⌋
⇒ r_{i+1} = (2·r_i) mod L
⇒ π_{i+1} = π_i^2 · g^{⌊2·r_i / L⌋} (mod N)
class WesolowskiVDF:
def __init__(self, N: int):
if N <= 1: raise ValueError("Modulus N must be > 1")
self.N = N
def evaluate(self, g: int, T: int) -> Tuple[int, int]:
"""Compute y = g^{2^T} mod N and produce proof π."""
g = g % self.N
# Phase 1: y = g^{2^T} mod N (T sequential squarings)
y = g
for _ in range(T):
y = pow(y, 2, self.N)
# Phase 2: challenge L = H(g, y, T) (hash to ~128-bit prime)
L = _hash_to_prime(g, y, T)
# Phase 3: incremental proof construction
pi = 1 # π_0
r_i = 1 # r_0 = 2^0 mod L
for _ in range(T):
two_r = 2 * r_i
q_step = two_r // L
r_i = two_r % L
pi = pow(pi, 2, self.N)
if q_step:
pi = (pi * pow(g, q_step, self.N)) % self.N
return (y, pi)
def verify(self, g: int, y: int, pi: int, T: int) -> bool:
"""Verify y = g^{2^T} mod N in O(log T) time."""
g, y = g % self.N, y % self.N
L = _hash_to_prime(g, y, T)
r = pow(2, T, L) # O(log T)
return y == (pow(pi, L, self.N) * pow(g, r, self.N)) % self.N
For large T, the work is split into segments. Each segment produces its own Wesolowski proof, and the verifier checks every link in the chain:
def verify_chain(self, g: int, chain: list[Tuple[int, int, int]]) -> bool:
current = g
for yi, pii, Ti in chain:
if not self.verify(current, yi, pii, Ti):
return False
current = yi
return True
Chaining composes proofs without re-running the full sequential work — each segment's output feeds directly into the next.
### Test results (all passing) ``` N bit length : 1024 g : 2 T : 100 [PASS] Basic evaluate + verify [PASS] Bad proof correctly rejected [PASS] T = 0 (y = g) [PASS] T = 1 (y = g²) [PASS] Chained evaluation matches direct evaluation [PASS] Chained proof verification log₂(T) = 10 → verify in 255.3 µs log₂(T) = 14 → verify in 254.7 µs log₂(T) = 18 → verify in 254.9 µs log₂(T) = 22 → verify in 249.4 µs All tests passed. ``` ### Additional edge cases | Test | Result | |------|--------| | `g = 1` (trivial group element) | Verify passes, y = 1 | | `g = N-1` (≡ -1 mod N) | Verify passes | | `g = 0` (zero element) | Verify passes | | `g > N` (wraps around) | Verify passes, g reduced mod N | | `N = 1` (invalid modulus) | ValueError raised | | Bad proof `(π+1) mod N` | Correctly rejected | | Random QR generator, T=2000 | Verify passes, π non-trivial (1023 bits) | | T = 2^30 … 2^40 (verification only) | `pow(2, T, L)` completes in 4–6 µs, confirming O(log T) | ### Verification time analysis | T | Time to compute `r = 2^T mod L` | Asymptotic | |---|----------------------------------|------------| | 2^10 | 4.4 µs | O(log 2^10) | | 2^20 | 5.1 µs | O(log 2^20) | | 2^30 | 4.4 µs | O(log 2^30) | | 2^40 | 6.3 µs | O(log 2^40) | The verifier's work is **independent of T** — always ~250 µs total (including two RSA exponentiations) for any T up to 2^40+. ---
{"model": "claude-sonnet-4-20250515", "problem_class": "verifiable-delay-function-wesolowski", "result": "passed", "tests": 13}The Wesolowski VDF is implemented over RSA groups. Below is the core logic — the full file is at ~/wesolowski_vdf.py.
Given RSA modulus N, base g, and time parameter T:
| Step | Prover (O(T) sequential) | Verifier (O(log T)) |
|---|---|---|
| 1 | Compute y = g^{2^T} mod N via T repeated squarings |
— |
| 2 | Derive challenge L = H(g, y, T) (hash to prime) |
Derive L = H(g, y, T) |
| 3 | Compute proof π = g^{q} mod N where q = ⌊2^T / L⌋ via incremental construction (second sequential pass) |
Compute r = 2^T mod L via fast modular exponentiation pow(2, T, L) |
| 4 | Output (y, π) |
Accept iff y ≡ π^L · g^r (mod N) |
Correctness: y = g^{q·L + r} = (g^q)^L · g^r = π^L · g^r (mod N).
Soundness (adaptive root assumption): A prover who produces (y, π) passing the check for a fresh prime L, where y ≠ g^{2^T}, can be rewound to extract an L-th root of y·g^{-r} — violating the assumption that finding h^{1/L} in QR(N) is hard.
Since 2^T is astronomically large, we never compute it directly. Instead we maintain r_i = 2^i mod L and π_i = g^{⌊2^i/L⌋} mod N incrementally:
π_0 = 1, r_0 = 1
For i = 0 … T-1:
2^{i+1} = 2·(q_i·L + r_i) = (2·q_i)·L + 2·r_i
⇒ q_{i+1} = 2·q_i + ⌊2·r_i / L⌋
⇒ r_{i+1} = (2·r_i) mod L
⇒ π_{i+1} = π_i^2 · g^{⌊2·r_i / L⌋} (mod N)
class WesolowskiVDF:
def __init__(self, N: int):
if N <= 1: raise ValueError("Modulus N must be > 1")
self.N = N
def evaluate(self, g: int, T: int) -> Tuple[int, int]:
"""Compute y = g^{2^T} mod N and produce proof π."""
g = g % self.N
# Phase 1: y = g^{2^T} mod N (T sequential squarings)
y = g
for _ in range(T):
y = pow(y, 2, self.N)
# Phase 2: challenge L = H(g, y, T) (hash to ~128-bit prime)
L = _hash_to_prime(g, y, T)
# Phase 3: incremental proof construction
pi = 1 # π_0
r_i = 1 # r_0 = 2^0 mod L
for _ in range(T):
two_r = 2 * r_i
q_step = two_r // L
r_i = two_r % L
pi = pow(pi, 2, self.N)
if q_step:
pi = (pi * pow(g, q_step, self.N)) % self.N
return (y, pi)
def verify(self, g: int, y: int, pi: int, T: int) -> bool:
"""Verify y = g^{2^T} mod N in O(log T) time."""
g, y = g % self.N, y % self.N
L = _hash_to_prime(g, y, T)
r = pow(2, T, L) # O(log T)
return y == (pow(pi, L, self.N) * pow(g, r, self.N)) % self.N
For large T, the work is split into segments. Each segment produces its own Wesolowski proof, and the verifier checks every link in the chain:
def verify_chain(self, g: int, chain: list[Tuple[int, int, int]]) -> bool:
current = g
for yi, pii, Ti in chain:
if not self.verify(current, yi, pii, Ti):
return False
current = yi
return True
Chaining composes proofs without re-running the full sequential work — each segment's output feeds directly into the next.
### Test results (all passing) ``` N bit length : 1024 g : 2 T : 100 [PASS] Basic evaluate + verify [PASS] Bad proof correctly rejected [PASS] T = 0 (y = g) [PASS] T = 1 (y = g²) [PASS] Chained evaluation matches direct evaluation [PASS] Chained proof verification log₂(T) = 10 → verify in 255.3 µs log₂(T) = 14 → verify in 254.7 µs log₂(T) = 18 → verify in 254.9 µs log₂(T) = 22 → verify in 249.4 µs All tests passed. ``` ### Additional edge cases | Test | Result | |------|--------| | `g = 1` (trivial group element) | Verify passes, y = 1 | | `g = N-1` (≡ -1 mod N) | Verify passes | | `g = 0` (zero element) | Verify passes | | `g > N` (wraps around) | Verify passes, g reduced mod N | | `N = 1` (invalid modulus) | ValueError raised | | Bad proof `(π+1) mod N` | Correctly rejected | | Random QR generator, T=2000 | Verify passes, π non-trivial (1023 bits) | | T = 2^30 … 2^40 (verification only) | `pow(2, T, L)` completes in 4–6 µs, confirming O(log T) | ### Verification time analysis | T | Time to compute `r = 2^T mod L` | Asymptotic | |---|----------------------------------|------------| | 2^10 | 4.4 µs | O(log 2^10) | | 2^20 | 5.1 µs | O(log 2^20) | | 2^30 | 4.4 µs | O(log 2^30) | | 2^40 | 6.3 µs | O(log 2^40) | The verifier's work is **independent of T** — always ~250 µs total (including two RSA exponentiations) for any T up to 2^40+. ---
{"model": "claude-sonnet-4-20250515", "problem_class": "verifiable-delay-function-wesolowski", "result": "passed", "tests": 13}