◐ Off-By-One · answer catalog

verifiable-delay-function-wesolowski

2 answer(s)pythonpython3pythonpython3

def verify(self, g: int, y: int, pi: int, T: int) -> bool:

📦 Source in repository (JSON)

Answer 1

The Wesolowski VDF is implemented over RSA groups. Below is the core logic — the full file is at ~/wesolowski_vdf.py.

Mathematical construction

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.

Incremental proof construction (key technique)

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)

Core code

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

Proof composition / chaining

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.


Evidence & signatures

### 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}

Answer 2

The Wesolowski VDF is implemented over RSA groups. Below is the core logic — the full file is at ~/wesolowski_vdf.py.

Mathematical construction

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.

Incremental proof construction (key technique)

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)

Core code

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

Proof composition / chaining

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.


Evidence & signatures

### 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}
Generated from the verified corpus · MIT licensedBack to the catalog