Skip to main content

zorch

SNARK = Σ IOP Round

FRX-native building blocks for Modern SNARKs. 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.

A Modern SNARK is IOP + PCS. The way deep learning stacks Layers, zorch stacks Rounds — the one composable unit the rest is threaded through.

Installation

Python 3.11 on Linux x86_64. frxlib publishes a single cp311-cp311-manylinux_2_27_x86_64 wheel, so although its metadata says >=3.11, on 3.12 or on macOS pip finds nothing to install.

Install as pyzorch, import as zorch — the zorch name on PyPI belongs to an unrelated project.

CPU

pip install pyzorch frx frxlib

frx is not a declared dependency of the wheel, deliberately: it is a GPU-correctness-sensitive, continuously bumped build that the consuming workspace has to pin exactly, so pinning it here would fight that.

GPU (CUDA 12)

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

The extra index is required, and only for the GPU tier. frx[cuda12] pulls frx-cuda12-plugin, which depends on frx-cuda12-pjrt — 129 MB against PyPI's 100 MiB per-file limit, so PyPI carries only a 0.0.0 name-reservation stub and the real wheel is served from the Fractalyze index. A limit increase has been requested; when it lands this tier collapses into the CPU command above and the extra index goes away. Everything else in the chain (nvidia-cublas-cu12 and friends) already comes from PyPI.

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; if it prints CpuDevice with a warning that a CUDA-enabled jaxlib is missing, the GPU tier did not take effect.

Design Philosophy

  • Proving-scheme-agnostic. The blocks capture every proving scheme, not a single one. Round / Fiat-Shamir / Polynomial / PCS / fold / zero-check compose into FRI, sumcheck, GKR, STARK, Basefold, WHIR, …; pairing-based schemes plug in by swapping the PCS block (e.g. a KZG-style commitment).
  • Implementation-agnostic. zorch targets 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 each commit/open, each absorb/squeeze, each fold step, and a hash permutation's internal rounds — must lower to a single fused kernel. We get there by construction, not by a per-primitive pattern-matcher in the compiler.
  • Easy to assemble. These are building blocks; the API optimizes for snapping them together.

Building blocks

The one unit is the Round — a prover↔verifier interaction of an IOP: a message observed into the Fiat-Shamir transcript, a challenge sampled back (observesample, via __call__). Rounds nest — a single per-variable step is a Round, and a whole sumcheck (its per-variable Rounds bundled) is itself a Round. This is what SNARK = Σ IOP Round says literally: a Fiat-Shamir-compiled IOP is a tree of these rounds, Σ flattening it to the leaf interactions.

Grouping Rounds gives either a bigger Round (a sumcheck, from its per-variable rounds) or — when the group is a top-level phase — a Stage. Two roles organize the composition; both are Rounds, since a chain is itself one:

  • A Stage is a Round that is one phase of the scheme's prove_chain — the sequence of Stages the scheme is (trace-commit, logup-gkr, zero-check, a PCS opening).
  • A Bridge is a transcript-only Round for soundness or security work — a grind (buys security bits), a framed observe or domain separator (closes a Fiat-Shamir soundness gap), a sampled-and-discarded challenge (matches the reference's schedule). It usually sits inside a Stage; a scheme may also place one directly in the prove_chain between two stages (an RLC batching their claims).

So the shape is recursive — the prove_chain is Stages (with the occasional Bridge between them); a Stage chains Rounds and Bridges; a Round may itself chain Rounds, down to the leaf interaction:

prove()  —  the prove_chain is Stages; a Stage holds Rounds and Bridges
──────────────────────────────────────────────────────────────────────

  Stage   trace-commit          commit the witness columns
  Stage   logup-gkr             the interaction argument:
    Bridge  grind                 a PoW inside the stage (buys security bits)
    Round   layer L                one layer — itself a Round of Rounds:
      Round   bind x₀                a leaf: one observe → sample
      Round   bind x₁
    Round   layer L-1
  Stage   zero-check            the constraint sumcheck:
    Bridge  observe(framing)      bind the transcript first (soundness)
    Round   bind x₀                a leaf: one observe → sample
    Round   bind x₁
  Stage   jagged-evals          the PCS opening
Round Stage Bridge
Is a prover↔verifier interaction; nests a sequence of Rounds that is one prove_chain phase a transcript-only connective Round
Does observesample at the leaf witness + real compute (an inner sumcheck, an open) a transcript op soundness/security needs
Example a sumcheck round, or a whole sumcheck trace-commit, logup-gkr, zero-check, jagged-evals a grind, a framed observe, a discarded sample

Stage and Bridge are the same Round interface — that is how chains nest and how the verifier mirrors the prover round-for-round — but the roles are what a reader navigates by.

Where the boundaries fall. A leaf Round is each prover↔verifier interaction (observesample); Rounds bundle into a bigger Round or, at a prove_chain phase, a Stage; a Bridge sits wherever the reference's soundness argument needs a transcript op — inside a stage, or between two in the prove_chain. The full carry-and-seam contract is docs/composition/stage-composition.md.

Where the classic pieces fit. A ZK reader expects Fiat-Shamir, Polynomial, PCS, and sumcheck as top-level "blocks." In this picture they are not peers of the Round:

  • Fiat-Shamir, Polynomial, and fold are the materials a Round body computes with — the transcript it threads, the polynomials it evaluates, the fold (2-to-1 reduction, one challenge per round) it applies each step.
  • A PCS opening and a zero-check are Stages — each a distinct phase: a zero-check reduces to a sumcheck, while a PCS opening runs its commitment-opening and evaluation checks (the jagged-evals stage above).

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.

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

pyzorch-0.1.1.tar.gz (284.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pyzorch-0.1.1-py3-none-any.whl (372.8 kB view details)

Uploaded Python 3

File details

Details for the file pyzorch-0.1.1.tar.gz.

File metadata

  • Download URL: pyzorch-0.1.1.tar.gz
  • Upload date:
  • Size: 284.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for pyzorch-0.1.1.tar.gz
Algorithm Hash digest
SHA256 8d31cf6e8b62649255c4574b7d85f3b34f5ef05a35a0b4f7ab78719df9baa56f
MD5 2dcd79441d3b917371e0efdeae637780
BLAKE2b-256 361c5bc4ae075d0b0f7907647536095913047f691218cb15173171a36a401781

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyzorch-0.1.1.tar.gz:

Publisher: release.yml on fractalyze/zorch

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyzorch-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: pyzorch-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 372.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for pyzorch-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 c640252bf6393b9c2625c1f944a1fe2fa9c12500b074e879b88299edd316f806
MD5 dfa8108e11efd0f7a2b777924964cc24
BLAKE2b-256 16d2e0822727fbd91ef0f0a16db08947269321e35cc9dbfd425f06e569952c9a

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyzorch-0.1.1-py3-none-any.whl:

Publisher: release.yml on fractalyze/zorch

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.2.0

2 files

0.1.2

2 files

This release

0.1.1 This release

2 files

0.1.0

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page