Skip to content

Repository files navigation

Plonky2 streaming proof verifier — host + Ledger Flex

Prove two small computations with Plonky2, then verify the resulting proofs as a byte stream — either locally on a host, or on a Ledger Flex, which checks the ~298-310 KB proof on a device with 36 KB of RAM without ever holding the whole thing in memory.

Two fixed circuits are supported, each with its own example, artifacts, and verifier key:

  • display — a 32-step xorshift image generator. Verifying it yields a 32x32 picture.
  • sha256 — proof of knowledge of a SHA-256 preimage. Verifying it yields the digest.

This repository is a fork of 0xPolygonZero/plonky2. The Plonky2 library itself is kept (the prover and verifier both need it); a handful of internal functions were made public so the streaming verifier can reuse Plonky2's exact verification logic. See Changes to Plonky2.

What you can do here

  1. Prove the good computation of display and sha256 (the Plonky2 examples).
  2. Verify and interpret proofs locally — on the host, both by reconstructing the proof and by true streaming, rendering the image or printing the digest.
  3. Build, install and manage the Ledger app — stream proofs to it, run its test suite, measure its RAM/timing. See ledger-app/README.md.

Repository layout

Path What it is
plonky2/ Fork of the Plonky2 prover/verifier library. The examples examples/display.rs and examples/sha256.rs build the two circuits, prove them, and write artifacts in the "Solution-B" streaming layout; examples/shared/streaming_artifacts.rs is the shared serializer.
field/, util/, maybe_rayon/ Plonky2's supporting crates (dependencies of plonky2), upstream.
stream_verifier/ no_std core that verifies a Solution-B proof in one forward-only pass, with a working set that does not grow with the proof size. Shared verbatim by the host CLI and the Ledger app.
verifier/ Host CLI. Two binaries: verify_b (reconstructs the proof, then runs the stock verifier) and stream_verifier (true bounded-memory streaming). Both interpret the verified outputs — render the image / print the digest.
ledger-app/ The Ledger Flex app. Verifies a streamed proof on-device and shows the result. Its own Cargo workspace (BOLOS cross-compile).
verify.sh Convenience wrapper that builds and runs the host verifier (verify_b).

Generated files — target/, display_artifacts/, sha_artifacts/, and bitmaps/ — are git-ignored; the commands below (re)create them.

Prerequisites

Plonky2 needs a nightly toolchain; rust-toolchain already pins nightly, so cargo picks it up automatically. Building/loading the Ledger app has its own prerequisites (Docker, ledgerblue) documented in ledger-app/README.md.

1. Prove

Each example builds its circuit, proves it, and writes three files into its artifacts directory (display_artifacts/ or sha_artifacts/): the verifier key (verifier_circuit_data.bin), the proof in the streaming layout (proof_with_public_inputs.bin), and a convenience copy of the public outputs (output.bin).

# display: optional seed as decimal or 0x-hex (defaults to 0x12345678)
cargo run --release -p plonky2 --example display
cargo run --release -p plonky2 --example display -- 0xdeadbeef

# sha256: the preimage whose digest is proven
cargo run --release -p plonky2 --example sha256 -- "hello world"

2. Verify and interpret locally

The quickest path is verify.sh, which builds verify_b and runs it against a program's artifacts. For display it renders the verified image into ./bitmaps/; for sha256 it prints the verified digest.

./verify.sh                 # display (default): display_artifacts/ -> bitmaps/
./verify.sh sha256          # sha256: verify sha_artifacts/ and print the digest

To exercise the bounded-memory streaming verifier — the host twin of what the Ledger app runs, delivering the proof in small packets drained through a tiny fixed buffer — run the stream_verifier binary:

cargo run --release -p verifier --bin stream_verifier                    # display
cargo run --release -p verifier --bin stream_verifier -- --program sha256

Both verifiers cross-check output.bin against the proof's public inputs, but that check is a convenience only: the outputs are part of the proof and are covered by the Fiat-Shamir transcript.

3. The Ledger app

Everything about building, sideloading, streaming proofs to, testing, and measuring the Ledger Flex app lives in ledger-app/README.md. In short:

# Both verifier keys are compiled into the app, so both artifact sets must exist first.
cargo run --release -p plonky2 --example display
cargo run --release -p plonky2 --example sha256 -- "hello world"

ledger-app/build.sh                       # build the ELF + installable .apdu (needs Docker)
ledger-app/run_speculos.sh                # run under the emulator
python3 ledger-app/tools/send_proof.py    # stream a proof and show the result
python3 ledger-app/tools/run_tests.py     # the acceptance/rejection test suite

How the streaming works

The proof is stored in the "Solution-B" layout: a small header (~10% of the bytes) followed by the FRI query rounds (~90%). Every Fiat-Shamir challenge can be derived from the header alone, so a verifier reads the header, fixes the challenges, and then checks the query rounds one at a time — each read, verified against the already-fixed challenges, and dropped before the next arrives. Peak memory is reached while processing the header and does not grow with the number of query rounds.

Only the byte order of the file differs from Plonky2's canonical format; the transcript order — and therefore the proof's validity — is unchanged, so this is exactly as sound as verifying a whole proof. The crate-level docs of stream_verifier explain the verification order, the memory model, and the soundness argument in detail.

Changes to Plonky2

The custom crates reuse Plonky2's own verification code rather than reimplementing any cryptography. To make that possible, the fork only widens visibility and splits one function (no logic changes):

  • plonk::get_challenges::get_challenges is made pub — derives every challenge from the header, before any query round.
  • plonk::verifier: the PLONK-identity check is split out into a public verify_plonk_identity (the non-FRI half of verify_with_challenges), so it can run as soon as the openings arrive.
  • fri::verifier: fri_verifier_query_round (plus compute_evaluation, fri_combine_initial, fri_verify_proof_of_work, PrecomputedReducedOpenings) are made pub, and query-round verification takes the commit-phase caps and final polynomial directly instead of a whole FriProof, so rounds can be checked as they stream in.
  • plonk::proof::OpeningSet::to_fri_openings and plonk::circuit_data::CommonCircuitData::get_fri_instance are made pub.
  • plonky2/Cargo.toml: adds plonky2_u32, sha2, and hex as dev-dependencies, used only by the sha256 example.
  • Cargo.toml: adds the custom crates as workspace members and patches crates-io's plonky2 to this workspace's local crate (so a single copy is used everywhere, including transitively via plonky2_u32).

License

As a fork of Plonky2, this repository is licensed under either of

at your option.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages