zorch
SNARK = Σ IOP Round
FRX-native building blocks for proof systems. zorch sits between FRX —
Fractalyze's fork of JAX — and the proof systems
that consume it: FRX provides tracing and codegen, lowered through Fractalyze
XLA, its fork of stock XLA that adds native
field and elliptic-curve types. zorch provides the reusable pieces a proof
system is assembled from.
The banner is a mnemonic for where the work is, not a definition: repeated IOP rounds are the core interactive computation, and a non-interactive argument adds its relation, a Fiat–Shamir transform, and commitment machinery around them. Folding and other families reuse the same pieces without fitting the equation literally. So zorch's two units are the round — one step of a repeated recurrence — and the stage — one claim reduction with paired prover and verifier roles.
Installation
Python 3.11 on Linux x86_64, or macOS on Apple Silicon. (frxlib ships a
cp311 wheel for those two platforms only — not 3.12/3.13, not Intel Macs.)
Install as pyzorch, import as zorch — the zorch name on PyPI belongs to an
unrelated project.
CPU
pip install pyzorch
GPU (CUDA 12)
pip install pyzorch '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
python -c "import frx, zorch; print(frx.devices()); print(zorch.__version__)"
[CpuDevice(id=0)] means the CPU tier; a CUDA install prints the GPU devices.
Design Philosophy
- Proving-scheme-agnostic. The blocks are reusable across proving schemes,
rather than encoding a single one.
Round, Fiat-Shamir,Polynomial,PCS, fold, and zero-check compose into FRI, sumcheck, GKR, STARK, Basefold, WHIR, …; pairing-based schemes plug in by swapping thePCSblock (e.g. a KZG-style commitment). - Implementation-agnostic.
zorchtargets the proving scheme, not any one downstream implementation — a zkVM, a zkML prover, a zkTLS prover. Each plugs in as a consumer; nothing implementation-specific leaks into a block. - Fusion-first. Each
Round— and eachcommit/open, eachabsorb/squeeze, each fold step, and a hash permutation's internal rounds — must lower to one replayable device unit. We get there by construction, not by a per-primitive pattern-matcher in the compiler. The fusion north star is where that unit is defined and measured. - Easy to assemble. These are building blocks; the API optimizes for snapping them together.
Building blocks
The two units differ in kind, not size. A round is directional and repeated: one step of a homogeneous recurrence, driven in a loop. A stage is paired and whole: a claim reduction with a prover role and a verifier role that can be deployed separately. A whole sumcheck stage may be cheaper than one GKR round — repetition versus pairing decides, never scale.
ProverRound: (carry, transcript) -> (carry, transcript, message)
VerifierRound: (carry, transcript, message) -> (carry, transcript, ok)
ProverStage.prove(claim, witness, transcript) -> ProveResult
VerifierStage.verify(claim, reduction_proof, ...) -> VerifyResult
The claim is the public assertion entering the stage; the witness is the prover's private evidence. Both roles derive the same reduced claim, and the reduction proof does not establish it — it establishes the source claim conditional on it:
reduced claim is true => source claim is true
That conditional is what lets stages chain: each one's reduced claim is the
next one's source claim, so a proof system is a sequence of reductions ending at
TrivialClaim, which holds by construction and leaves nothing left to prove. An
argument of knowledge is exactly a reduction to the trivial claim, and a PCS
opening is the usual terminal one.
Dense sumcheck is the smallest complete stage, entire:
@dataclass(frozen=True)
class SumClaim: # public: this polynomial sums to `value` over the cube
value: Array
rounds: int
@dataclass(frozen=True)
class EvaluationClaim: # reduced: ...provided it evaluates to `value` at `point`
point: Array
value: Array
class SumcheckProver(ProverStage[SumClaim, SumcheckWitness, EvaluationClaim, Array]):
def prove(self, claim, witness, transcript):
pre = transcript
# the rounds live inside the stage — one per variable, driven in a loop
_, _, messages = fold_rounds(
self.prover_round, witness.state, transcript, claim.rounds
)
reduction_proof = fnp.stack(messages)
# The prover's carry is the folded tables: each round squeezes its
# challenge, folds with it, and drops it. The point and running value
# accumulate in the verifier's carry instead, so replaying is how the
# prover obtains a reduced claim it never built. The transcript comes
# back with it and matches the one fold_rounds discarded.
point, value, replayed, _ = verify(
self.verifier_round, claim.value, reduction_proof, pre
)
return ProveResult(EvaluationClaim(point, value), reduction_proof, replayed)
SumcheckVerifier.verify is that same replay against the proof alone. Nothing
here knows where the sum came from: zerocheck, lincheck and LogUp-GKR each
configure this stage and export their own claim type.
A proof system is those reductions chained until the claim is trivial.
SpartanProver / SpartanVerifier are the worked composite — four stages, a
transcript-only batching step, and prover data that skips to the opening — in
docs/schemes/spartan.md.
Contracts, ownership rules, the round-vs-stage-vs-committer decision table, and
reuse guidance:
docs/composition/stage-composition.md.
Development
zorch is pure Python on FRX, run against its GPU plugin. A virtualenv with
the pinned toolchain:
python3.11 -m venv .venv && . .venv/bin/activate
pip install -r requirements.in \
--extra-index-url https://fractalyze.github.io/pypi/simple/
Install the git hooks with both stages named. Plain pre-commit install wires
only the pre-commit stage, which leaves the commit-message linter inactive —
formatting hooks fire while a malformed commit message sails through to CI:
pre-commit install --install-hooks --hook-type pre-commit --hook-type commit-msg
Commit messages follow Conventional Commits:
a valid type, a lowercase summary with no trailing period, a header of at most
80 characters, and a body on everything but docs. The same linter runs in CI
over every commit in a pull request and over the PR title, which matters here
because this repo squash-merges with the title as the subject.
The dev loop — per-workspace venvs, developing against a local Fractalyze XLA
build, the FRX compile-cache rule — lives in docs/reference/development.md.
Documentation
- Task-indexed docs hub:
docs/README.md— indexes every design doc by what you're trying to do.
Agent skill
skills/using-zorch packages this guide for AI coding
agents — install commands, block import paths, field-dtype rules, and the
consumer boundary — so an agent writing code against zorch in your repo has
them on hand. Install with any agent via skills.sh:
npx skills add fractalyze/zorch
or as a Claude Code plugin:
/plugin marketplace add fractalyze/zorch
/plugin install zorch@zorch
License
Licensed under the Apache License, Version 2.0 (see LICENSE).
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pyzorch-0.2.0.tar.gz.
File metadata
- Download URL: pyzorch-0.2.0.tar.gz
- Upload date:
- Size: 304.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e19e4abaa2a87484bcc5f13b4b52c5d2ddabb4f8253e882266bee22777e40e55
|
|
| MD5 |
c694d29ceccdf31ad4ccdeedf99b8256
|
|
| BLAKE2b-256 |
c2228e1bfec1a536439f34bd31dd6ee6821ee96a17697bc64e5b744178cc198e
|
Provenance
The following attestation bundles were made for pyzorch-0.2.0.tar.gz:
Publisher:
release.yml on fractalyze/zorch
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pyzorch-0.2.0.tar.gz -
Subject digest:
e19e4abaa2a87484bcc5f13b4b52c5d2ddabb4f8253e882266bee22777e40e55 - Sigstore transparency entry: 2333184930
- Sigstore integration time:
-
Permalink:
fractalyze/zorch@be2178d34ded0a1dcad00580ef912f067724927a -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/fractalyze
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@be2178d34ded0a1dcad00580ef912f067724927a -
Trigger Event:
release
-
Statement type:
File details
Details for the file pyzorch-0.2.0-py3-none-any.whl.
File metadata
- Download URL: pyzorch-0.2.0-py3-none-any.whl
- Upload date:
- Size: 396.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
aeaffc37759d0e9099f49457e687888585e08c451a3a90bad9e10d3b112d0ec3
|
|
| MD5 |
26ae20f30c47a592434427a5937df948
|
|
| BLAKE2b-256 |
3e7e1e701e90f13a9c38614f4651b647ef79b72b2e61b7de449bf76415cfeb54
|
Provenance
The following attestation bundles were made for pyzorch-0.2.0-py3-none-any.whl:
Publisher:
release.yml on fractalyze/zorch
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pyzorch-0.2.0-py3-none-any.whl -
Subject digest:
aeaffc37759d0e9099f49457e687888585e08c451a3a90bad9e10d3b112d0ec3 - Sigstore transparency entry: 2333184970
- Sigstore integration time:
-
Permalink:
fractalyze/zorch@be2178d34ded0a1dcad00580ef912f067724927a -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/fractalyze
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@be2178d34ded0a1dcad00580ef912f067724927a -
Trigger Event:
release
-
Statement type: