Metadata-Version: 2.4
Name: flock-zorch
Version: 0.1.0
Summary: flock-zorch — a GPU prover for flock's binary-field R1CS PIOP, built on zorch's scheme-agnostic blocks.
Author: The Flock-Zorch Authors
License: Apache-2.0
Project-URL: Repository, https://github.com/fractalyze/flock-zorch
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.11
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy
Requires-Dist: pyzorch>=0.1.0
Requires-Dist: frx>=0.10.0.dev0
Requires-Dist: zk-dtypes>=0.0.10
Dynamic: license-file

# flock-zorch

A GPU prover for **flock**'s binary-field R1CS PIOP — the scheme from
[*Flock: Fast Proving for Batch Boolean Computations*](https://eprint.iacr.org/2026/1329)
(eprint 2026/1329) — built on Fractalyze's **zorch** stack. The whole prover is
authored once in Python/**FRX** (Fractalyze's JAX fork), and the compiler emits
the hardware code: the same readable source targets CPU and GPU, and its output
matches the reference flock prover bit-for-bit.

The point is a **single FRX/MLIR codebase, not a GPU rewrite of the proving
logic**. flock's prover is written as a clean statement of the math; FRX lowers
it to StableHLO/MLIR, and the compiler — carrying native finite-field dtypes
(`zk_dtypes`) and the carryless-multiply lowerings for GF(2¹²⁸) — compiles that
down to each target. The expensive field-arithmetic optimization lives in
compiler passes, out of the prover, and the byte-match gate guarantees those
transforms never change the output. The same program can shard across multiple
devices (GSPMD) without hand-written communication.

flock is an R1CS-over-GF(2¹²⁸) prover: two sumcheck PIOPs (zerocheck + lincheck)
over a Ligerito polynomial commitment, with a SHA-256 Fiat-Shamir
transcript, targeting hash-circuit statements (Keccak-f[1600], Keccak3, SHA-256,
BLAKE3). flock-zorch assembles that specific prover from zorch's scheme-agnostic
blocks (`Round`, Fiat-Shamir, `Polynomial`, `PCS`, fold, zero-check) and adds
only the flock-specific pieces the byte-match needs (GHASH-basis field, the
round-1 URM, the ∞-trick round loop, F128↔bytes serialization). The full prover
`prover.prove_fast` produces the complete `R1csProof` — commit → bind →
zerocheck → lincheck → batched dual-claim open, one shared challenger,
device-resident — reproducing flock `prove`'s proof bit-for-bit.

## Installation

**Python 3.11 on Linux x86_64 only.**

Run with `JAX_ENABLE_X64=true` — the GF(2¹²⁸) dtypes are 64-bit lane pairs and
x32 truncates them.

### CPU

```sh
pip install flock-zorch
```

### GPU (CUDA 12)

```sh
pip install flock-zorch 'frx[cuda12]' \
    --extra-index-url https://fractalyze.github.io/pypi/simple/
```

The extra index carries the CUDA plugin wheels, which are too large for PyPI's
per-file limit. It is not needed for the CPU tier.

### Verify

```sh
JAX_ENABLE_X64=true python -c \
    "import frx, flock_zorch.prover; print(frx.devices()); print(flock_zorch.__version__)"
```

`[CpuDevice(id=0)]` means the CPU tier; a CUDA install prints the GPU devices.
Importing `flock_zorch.prover` rather than the package is deliberate: the package
`__init__` is a docstring, so a bare import stays green on an x32 interpreter and
on a `zk-dtypes` too old for the binary-field dtypes.

## Setup

No submodules and nothing to clone by hand — both pinned deps are fetched by the
build:

| dep | how |
|---|---|
| **flock** — the reference prover + byte-compare oracle | a cargo **git rev dep** (`flock-core` / `flock-prover` in [`Cargo.toml`](https://github.com/fractalyze/flock-zorch/blob/main/Cargo.toml)); `cargo build` fetches it at the pinned rev, and `examples/dump_*.rs` drive it to dump the golden fixtures |
| **zorch** — the scheme-agnostic spine (`zorch.hash.sha256`, the device Fiat-Shamir transcript, the `Round`/`Bridge`/`Stage` chain roles, `pcs.ligerito`) | a bazel **`git_override`** in [`MODULE.bazel`](https://github.com/fractalyze/flock-zorch/blob/main/MODULE.bazel); bazel fetches it |

**Prerequisites** — an NVIDIA GPU (CUDA; RTX 5090 / sm_120 reference), a Rust
toolchain (`flock-core` is edition 2024), Python 3.11. For the GPU fast path, a **CUDA 13.3
`ptxas`** at `~/.local/cuda13/bin`: with it on `PATH` the pinned frx wheel's
compiler emits the hardware `clmad` GF(2¹²⁸) multiply; without it, the software
`binary_field_ghash` multiply — same output, just slower.

```bash
git clone https://github.com/fractalyze/flock-zorch.git && cd flock-zorch
```

Reproduction has three tiers with independent deps: a **Rust toolchain**
regenerates the golden fixtures by driving the pinned flock (no GPU, no Python);
the **CPU byte-match** checks the frx port against them under **Bazel** (deps from
the pip lock, zorch from the git_override — no venv); the **GPU byte-match** runs
the port on-device from a **venv**. Build the venv once (the other two tiers need
nothing installed):

```bash
python3.11 -m venv .venv
.venv/bin/pip install -r requirements.in --extra-index-url https://fractalyze.github.io/pypi/simple/
```

### Bumping the pins

- **flock** — bump the `rev` on the `flock-core` / `flock-prover` git deps in
  [`Cargo.toml`](https://github.com/fractalyze/flock-zorch/blob/main/Cargo.toml); cargo re-fetches on the next build.
- **zorch** — bump the `git_override` commit in [`MODULE.bazel`](https://github.com/fractalyze/flock-zorch/blob/main/MODULE.bazel),
  and move `requirements.in`'s `frx` / `frxlib` / `frx-cuda12` wheels to the SAME
  version as zorch's own `requirements.in` — the binary-field GPU kernels must
  match, and CPU-only CI can't catch a desync.

Then re-verify before pushing:

```bash
scripts/dump_goldens.sh core && bazel test //python:all
```

## Reproduce

The oracle is the pinned flock itself: `examples/dump_*.rs` dump fixtures from
`flock-core`, and the `*_oracle_test.py` gates byte-compare the FRX port's
serialized proofs against them. The gates are **proof-level**: every field of a
full serialized proof is compared, which transitively pins every layer under it
(FS framing, NTT, Merkle/octopus, zerocheck, lincheck, ring-switch — one
diverging byte anywhere flips every Fiat-Shamir draw after it). Primitives are
covered by python-native tests (no goldens); the retired per-layer golden gates
live in git history.

### Bazel tests (CPU)

Run under bazel — deps from the pip lock, `zorch` from the `MODULE.bazel`
`git_override`, goldens from `//artifacts` runfiles. One byte-match gate (the
full `LigeritoProof` — flock's fused prove has no config below m=22, so the e2e
gate can't come down to CPU) plus the native tests:

```bash
scripts/dump_goldens.sh core              # goldens the gates byte-compare against
bazel test //python:all                   # (JAX_PLATFORMS=cpu + x64 pinned in .bazelrc)
bazel test //python:ligerito_oracle_test  # the CPU byte-match anchor alone
```

### Proof gates (GPU, venv)

The full-prove gates — the identity e2e and the hash-circuit provers
(keccak/sha2/blake3, hundreds-of-MB goldens) — are **not** bazel targets (the
CUDA wheels aren't hermetic). Run them on the venv, resolving the same
git_override'd zorch via `scripts/zorch_pythonpath.sh`:

```bash
export JAX_PLATFORMS=cuda
export XLA_PYTHON_CLIENT_PREALLOCATE=false   # don't grab ~75% of VRAM up front
export PYTHONPATH="python:$(scripts/zorch_pythonpath.sh)"
export PATH="$HOME/.local/cuda13/bin:$PATH"  # CUDA 13.3 ptxas -> compiler emits clmad
VENV=.venv/bin/python
scripts/dump_goldens.sh all                  # + the real hash circuits
$VENV python/flock_zorch/testing/e2e_ligerito_oracle_test.py    # fused prove (identity R1CS)
$VENV python/flock_zorch/testing/keccak3_ligerito_oracle_test.py # Keccak full prove (Ligerito)
$VENV python/flock_zorch/testing/blake3_ligerito_oracle_test.py
```

The full proof-gate list is the `*_oracle_test.py` set under
`python/flock_zorch/testing/`. `artifacts/` is gitignored (regenerable, and
`blake3_golden.bin` alone is ~118 MB); `scripts/dump_goldens.sh [core|all]`
rebuilds it from the pinned flock.

### One benchmark point (SHA-256, m=26)

```bash
VENV=.venv/bin/python                                                                    # the venv from Setup
cargo run --release --example dump_sha2_ligerito -- 2048 artifacts/sha2_ligerito_golden.bin  # real R1CS, m=26
cargo build --release --example bench_sha2_ligerito_cpu                                   # CPU anchor
export JAX_PLATFORMS=cuda XLA_PYTHON_CLIENT_PREALLOCATE=false
export PYTHONPATH="python:$(scripts/zorch_pythonpath.sh)"
export PATH="$HOME/.local/cuda13/bin:$PATH"
CPU=$(target/release/examples/bench_sha2_ligerito_cpu 2048 | grep -oE '[0-9.]+ ms' | head -1)
$VENV python/flock_zorch/testing/prove_phase_bench.py sha2 --cpu-ms "${CPU%% ms}"         # GPU vs CPU
```

`prove_phase_bench.py` also splits the prove into commit / zerocheck / lincheck /
open and reports hashes/second, and refuses to print absolute numbers when
another process is using the GPU — a neighbour saturating the SMs inflates a warm
prove ~28× here, which is enough to invent a result. Swap `sha2` for `blake3` or
`keccak3`; `--golden` points it at an m-variant dump.

## Benchmark

Apple-to-apple: **unmodified flock CPU vs flock-zorch GPU on the same idle
machine** (RTX 5090, Ryzen 9 9950X), same-instance both sides. The golden is
dumped from flock-core, the CPU bench (`bench_*_cpu`, thin-LTO /
`codegen-units=1` / `target-cpu=native` — flock's honest x86 best) proves it, and
the GPU bench ingests the same golden. GPU uses the hardware `clmad` multiply;
timing is warm best-of-3 (JIT compile excluded), GPU verified idle. Every
instance is a real flock hash-circuit R1CS at flock's shipped size, swept over
the witness size m to locate the GPU/CPU crossover. The CPU baseline is x86
**scalar** (flock's NEON paths are aarch64-gated), so Apple silicon would shift
the crossover right. Measured with zorch `650b1cf` and FRX
`dev20260720085939` on 2026-07-21.

### Keccak3 (Ligerito) — crossover ≈ m=24

| m   | n_keccaks | flock CPU (ms) | GPU (ms) | speedup    |
| --- | --------- | -------------- | -------- | ---------- |
| 22  | 49        | 25.8           | 48.0     | 0.54×      |
| 24  | 384       | 70.9           | 56.7     | **1.25×**  |
| 26  | 1536      | 266.4          | 76.1     | **3.50×**  |
| 28  | 6144      | 1,123.7        | 123.7    | **9.08×**  |
| 30† | 24576     | 4,706.1        | 316.7    | **14.86×** |
| 31† | 49152     | 9,724.2        | 586.4    | **16.58×** |

† m≥30 uses `XLA_PYTHON_CLIENT_ALLOCATOR=cuda_async`; the default BFC arena
fragments on the large proof phases (#131).

The Ligerito open runs device-resident — zorch's recursive open compiles to one
device program (#479) and query positions are sampled on-device (#104) — while
the packed-byte zerocheck fold avoids expanding the retained witness. GPU wins
from m=24 and reaches 16.58× at m=31.

### BLAKE3 (Ligerito)

| m   | n_comp | flock CPU (ms) | GPU (ms) | speedup    |
| --- | ------ | -------------- | -------- | ---------- |
| 26  | 4096   | 316.5          | 66.8     | **4.73×**  |
| 31† | 131072 | 10,724.9       | 621.1    | **17.27×** |

BLAKE3 uses the generic sparse CSC lincheck rather than Keccak3's procedural
walker. The same packed zerocheck path keeps its high-end curve nearly identical:
the GPU proof grows 9.3× while the batch grows 32× from m=26 to m=31.

**Reading the numbers.** flock's prover is a sequential SHA-256 Fiat-Shamir
chain; at small m the per-round data-parallel work (NTT / URM / recursive fold)
is too small to amortize GPU launch overhead, so the CPU wins. The bulk work
grows with m and the GPU overtakes at m≈24, and the advantage keeps growing
above the crossover (16–17× by m=31). Reproduce any point with the
[SHA-256 recipe above](#one-benchmark-point-sha-256-m26) (swap `dump_sha2_ligerito` /
`bench_sha2_ligerito_cpu` and the `sha2` argument for the `blake3` / `keccak3`
variants).

## Acknowledgments

The proving scheme and the reference implementation are
[**flock**](https://github.com/succinctlabs/flock) by Succinct Labs — the
[flock paper](https://eprint.iacr.org/2026/1329) (eprint 2026/1329). flock-zorch
is an independent GPU implementation of that scheme on the zorch stack; the
unmodified `succinctlabs/flock` prover is pinned as the `flock-core` /
`flock-prover` git rev dep and is the byte-compare oracle every gate checks
against. All credit for the scheme and the R1CS PIOP design is theirs.
