2026年9月2日 12 分で読めます 投稿者:Remco Bloemen, World Foundation

ProveKit: Privacy for the real world

Today we’re excited to share ProveKit, a production-ready zero-knowledge proving toolkit that lets users generate proofs on their own devices. ProveKit is built into World ID and powers the privacy-preserving features that make proof of human useful for enterprises, consumer platforms, and developers.

The open-source codebase is available at github.com/worldfnd/provekit, with documentation and benchmarks at provekit.org.

We are excited to release what we believe is a big milestone in real-world privacy. A thank you goes out to the dozens of people who have helped make this possible!

Try ProveKit with your own Noir circuits. Follow the Quick Start Guide or run cargo install provekit-cli.

Introduction

World’s mission is to establish proof of human at planetary scale — verifying that you’re a unique human without revealing who you are. As World enters its third year, the question is no longer just “can we prove humanness?” but “can we make that proof useful?” A bar checking your age, a social platform filtering bots, a government service confirming residency, all of these need to verify something about you without seeing all of the underlying data on your ID card.

World ID Credentials enable individuals to optionally store information from their physical chip-enabled ID cards like NFC-enabled passports in World App on their device. Importantly, it does this with none of the data stored off their device or accessible to World Foundation, Tools for Humanity or any third party. A user can then use their World ID to prove things like age, nationality and unique document ownership without revealing their real identity. In fact, a user can prove that they are above a minimum age without disclosing anything more about their actual age. This feat is possible in World ID thanks to modern zero-knowledge cryptography.

To preserve privacy, it is critical that the user can do this by themselves on their own devices, and to work at World’s scale, this needs to run on all phones (not just the latest flagship phones), in browser tabs, and on hardware that costs as little as $40. We also require it to meet the highest security bar: 128 bits post-quantum security and minimal trust assumptions. Here’s how ProveKit meets these requirements:

  1. Maximally private: Proofs are generated entirely on the user’s device. Private data never leaves the user's device. The verifier only learns the claim that has been proven (e.g. the user has a valid identity document meeting the minimum age requirement).
  2. Minimal trust: Based on the WHIR hash-based commitment scheme, there is no trusted setup and there are no elliptic curve or lattice assumptions. The implementation is open source and independently audited by Least Authority.
  3. Developer-friendly: Developers can write provable claims in Noir, a Rust-inspired language developed by Aztec with a large ecosystem of reusable components. New provable claims can be downloaded and don’t need to be part of the app bundle.
  4. User-friendly: It runs in a matter of seconds, has a small download size, requires little memory, works offline and on very constrained devices. The main targets are users’ phones and browsers.

To our knowledge, no existing solution meets all these requirements. ProveKit is the first to offer post-quantum security, a developer-friendly language, and mobile-first client-side proving in a single stack.

Performance

We will compare ProveKit v1 against two popular alternative client-side provers with a developer-friendly language. The benchmarks are deliberately challenging, but this reflects the needs of real-world use cases.

Provers

  • Noir + Barretenberg: Released by Aztec in 2021, this is the default proving stack for Noir. Unlike ProveKit, proving is a two-step process: first a so-called witness needs to be generated using Noir ACVM, then this witness is proven using Barrettenberg.
  • Rapidsnark / snarkjs: Circom (2018) is the first popular developer-friendly language for provable claims. For witness generation we use the Circom-generated WASM one, running in wasmi on mobile devices. We cannot use the native compiled witness generator as mobile apps cannot link in code from outside the app bundle. For the second step we use Rapidsnark on mobile and snarkjs in the browser as these performed the best.

Platforms

  • Mid-tier phone: iPhone SE 3. Released in 2022 with 4GB RAM and an Apple A15 CPU.
  • Low-end phone: We picked a Motorola Moto E15. A relatively new phone released in 2025, it stands out by having only 2GB RAM and running the 32-bit Android 14. So despite having a 64-bit capable Helio G81 (2x A76 @2GHz, 6x A55 @ 1.7GHz), apps only have 32-bit instructions.
  • Browser: This runs in WebAssembly in Chrome on an M4 Max MacBook Pro laptop. The implementations are allowed to use multiple threads with shared memory.

Provable claims

  • Passport: Verifies that a passport is valid, unexpired, and belongs to a holder older than a specified minimum age, without revealing the passport data or which trusted document signing key was used. The main proving costs are the SHA-256 hashing and RSA-4096 verification.
    See the [Noir] and [Circom] implementations.
  • WebAuthn: Verifies that a valid WebAuthn assertion authorizes a challenge for a specified website and passkey. The main proving costs are SHA-256 hashing and P-256 ECDSA verification. The latter is particularly challenging for Circom due to lack of lookup tables.
    See the [Noir] and [Circom] implementations.
  • OPRF: An anonymous proof of credential ownership with an action-bound nullifier from an OPRF service. This allows the holder to anonymously prove it is authorized to do some action it has not done before. The main proving costs here are zk-friendly hashes and elliptic curve operations. This claim is designed to be fast to prove.
    See the [Noir] and [Circom] implementations.

Prover time

For a good end-user experience, the most important factor is fast proving times. In fact, the user experience changes a lot with proving time: for times up to a few seconds we need a spinner, up 15 seconds, a progress bar, and after that we need a background worker as users will switch apps. Anything beyond a few minutes is basically a battery-draining pocket warmer that will not be used. ProveKit v1 completes each proof in a couple of seconds on a typical phone, and under half a minute on the worst phone we could find.

The other big challenge is the very limited memory. Mobile phones can have as little as 2 GB RAM, and the OS aggressively limits what an app can use, hence our design goal is less than 1GB of memory. Circom WebAuthn exceeds this, allocating a 1.73GB buffer for the proving key alone which causes Moto E15 to randomly fail with an Out of Memory (OOM) error.

Proving times were measured from inputs to a valid proof object (i.e. witness generation time is included). We measured both cold and warm times, and took the median of five samples. The cold overhead is shaded light in the graph.

Bandwidth

Bandwidth is not as commonly available as the 5G rollout in major tech hubs may suggest, and for many users every megabyte counts. This is where the design of ProveKit shows its strength: since there is no trusted setup, there is no large key material to download. Circom requires new key material for each circuit and must download gigabytes to complete the proofs. Barettenberg only requires 80 megabytes as the key material is mostly shared between proofs (shaded lighter). ProveKit is worse in proof size, as is typical of post-quantum cryptography, but still within our 1 MB target.

Circom has a per-circuit trusted setup which means each circuit has its own large download (i.e. for all three you need to add the download sizes). Barretenberg has a universal setup, after you download a fixed ~70MB file (shaded lighter) it can be reused for each circuit.

Try ProveKit with your own Noir circuits. Follow the Quick Start Guide or run cargo install provekit-cli.

How ProveKit Works

ProveKit takes a provable claim written in Noir and transforms it step by step into simpler claims. Each claim implies the one before it and, ultimately, the original claim.

  • Noir: The starting point is a Noir program that defines the claim to be proven. When generating a proof, the user supplies private input evidence accepted by the program, for example a valid identity document.
  • ACIR: The program is compiled to a simpler representation containing algebraic relations and table lookups. The private input transforms into a large set of numbers that satisfies these relations.
  • LogUp: The LogUp protocol turns the table lookups into algebraic relations.
  • R1CS: Now that everything is reduced to algebraic relations, these can be transformed into a rank-1 constraint system (R1CS), a simple bilinear relation on a vector.
  • WHIR: The private input, now transformed into a vector known as the witness, is committed using WHIR. This allows the user to prove things about it without revealing it.
  • Spartan: The Spartan protocol is used to prove that the witness satisfies the R1CS relation.

This way, the user proves that they know a witness that satisfies the R1CS relation. And by following the reductions in reverse, this means they know an accepting input to the Noir program we started with. Importantly, the verifier learns nothing about this witness and hence nothing about the private input.
The rest of this section explains each step in more detail. Readers interested mainly in using ProveKit can safely skip ahead to “What’s Next.”

Front-end

Developers write circuits in Noir, a high-level DSL developed by Aztec. It has a Rust-inspired syntax and rich language features to make development easy. An anonymous proof of age in Noir could look like:

Noir compiles to a simpler intermediate language called ACIR. It is analogous to assembly language for Noir circuits and a small fragment looks like

It is this simpler language that ProveKit compiles to split-witness R1CS. A rank-1 constraint system (R1CS) represents a circuit using three (sparse) matrices A,B,C\mathrm{A}, \mathrm{B}, \mathrm{C}. The prover needs to show it knows a vector w\mathbf{w} such that

(Aw)(Bw)=Cw.(\mathrm A \cdot \mathbf w) \,\odot\, (\mathrm B \cdot \mathbf w) = \mathrm C \cdot \mathbf w.

where we further require w0=1w_0 = 1 to prevent the all-zeros solution, and we require the public inputs pub\mathbf{pub} to be at fixed positions in w\mathbf{w}. Although remarkably simple, this model can express any computation.

We can make this model more expressive by using a split witness. Instead of committing to the entire witness at once, the prover first commits to the initial witness w1\mathbf{w}_1. Then Fiat-Shamir is applied to derive challenge values θ\boldsymbol{\theta}, after which the prover computes and commits to the second witness w2\mathbf{w}_2. The complete witness is then assembled from the parts as

w=[1pubw1θw2]\mathbf w = \begin{bmatrix} 1 & \mathbf {pub} & \mathbf w_1 & \boldsymbol{\theta} & \mathbf w_2 \end{bmatrix}

This extra challenge value that binds to w1\mathbf{w}_1 and is input to w2\mathbf{w}_2 is very powerful; it allows the R1CS to directly encode one-round public-coin interactive protocols in the constraint system. We use this to encode LogUp, giving us efficient lookup arguments and an order of magnitude performance improvement over plain R1CS.

When you run provekit prepare it will take the Noir project, compile it to ACIR, then lower it to the R1CS A,B,C\mathrm{A}, \mathrm{B}, \mathrm{C} matrices and store these in a ProveKit Prover file (.pkp). This file is all the user needs to start producing proofs for that circuit. No trusted setup or large proving-key download is required.

Prover

Given a prover file and satisfying inputs (e.g. a valid passport document above 18) we can compute a proof of the split-witness R1CS relation. For this we use WHIR for commitments and a variant of Spartan-NIZK for the constraints.

To prove the R1CS relation we use the zero-check from Spartan. Let the equality vector ex\mathbf{e}_{\mathbf x} be given by (ex)i=eq(x,b(i))(\mathbf{e}_{\mathbf x})_i = \mathrm{eq}(\mathbf x, \mathbf b(i)) where eq\mathrm{eq} is the multilinear equality polynomial and b(i)\mathbf{b}(i) is the binary expansion of ii. Then a~(x)=exAw\widetilde{a}(\mathbf x) = \mathbf{e}_{\mathbf x} \cdot \mathrm{A} \cdot \mathbf{w} is the multilinear extension of Aw\mathrm{A} \cdot \mathbf{w}, similarly define b~\widetilde{b} and c~\widetilde{c}. Then the prover receives a challenge τ\boldsymbol{\tau} and proves the sumcheck relation

x{0,1}keq(τ,x)(a~(x)b~(x)c~(x))=0.\sum_{\mathbf x \in \{ 0, 1 \}^k} \mathrm{eq}(\boldsymbol{\tau}, \mathbf x) \cdot \left( \widetilde {a}(\mathbf x) \cdot \widetilde {b}(\mathbf x) - \widetilde {c}(\mathbf x) \right) = 0.

This reduces the zero-check claim to the final evaluation, for some hh and challenge r\mathbf{r},

eq(τ,r)(a~(r)b~(r)c~(r))=h.\mathrm{eq}(\boldsymbol{\tau}, \mathbf r) \cdot \left(\widetilde {a}(\mathbf r) \cdot \widetilde {b}(\mathbf r) - \widetilde {c}(\mathbf r) \right) = h.

The prover provides the evaluations

a=a~(r)b=b~(r)c=c~(r)\begin{align*} a &= \widetilde {a}(\mathbf r) & b &= \widetilde {b}(\mathbf r) & c &= \widetilde {c}(\mathbf r) \end{align*}

which allows the verifier to reduce the claim to three inner product claims on the witness:

(erA)w=a(erB)w=b(erC)w=c\begin{align*} (\mathbf{e}_{\mathbf r}\cdot \mathrm{A} )\cdot \mathbf{w} &= a \\ (\mathbf{e}_{\mathbf r}\cdot \mathrm{B} )\cdot \mathbf{w} &= b \\ (\mathbf{e}_{\mathbf r}\cdot \mathrm{C} )\cdot \mathbf{w} &= c \\ \end{align*}

We use WHIR batch inner product openings to prove these. The only remaining work is for the verifier to check

er(ρaA+ρbB+ρcC)er=h\mathbf{e}_{\mathbf r } \cdot (\rho_a \cdot \mathrm{A} + \rho_b \cdot \mathrm{B} + \rho_c \cdot \mathrm{C}) \cdot \mathbf{e}_{\mathbf r '} = h'

where hh' is the final sum value from WHIR and ρa,ρb,ρc,r\rho_a, \rho_b, \rho_c, \mathbf{r}' are challenges. This claim is still linear in the circuit size, but importantly it no longer depends on the witness. The verifier can compute this entirely on its own. This is essentially the Spartan-NIZK protocol with the linear check merged into the WHIR opening.

The resulting prover consists of just witness generation, two commitments, one degree-three sumcheck, and one batched opening. That simplicity largely explains ProveKit’s concrete performance.

There’s one trade-off: Although the proofs are sublinear in size, verification is not succinct in the formal sense. The verifier must evaluate a final matrix-dependent expression in time linear in the circuit size. Spartan’s SPARK protocol can prove this evaluation and reduce verifier work, but ProveKit deliberately omits it: minimizing work on constrained client devices is more important for our use case, while verification typically runs on well-provisioned servers.

Linear commitment scheme. ProveKit commits to witness vectors using WHIR, a transparent linear commitment scheme with efficient proofs of arbitrary linear forms. This makes it an excellent match for Spartan’s linear verification equations. In ProveKit, WHIR uses an interleaved Reed-Solomon encoding committed using a Merkle tree, then uses sumcheck to recursively fold the claim while performing periodic code-switches to maintain efficient code parameters. The result is a transparent, post-quantum linear commitment scheme with succinct proofs, fast verification, and efficient support for arbitrary linear openings.

Zero knowledge. A plain WHIR proof leaks a limited amount of linear information through its oracle queries, sumcheck messages and the final base case. Rather than masking the entire witness with a large random polynomial, ProveKit masks exactly the information that can leak, using one small masking polynomial and a logarithmic number of small blinding polynomials. As a result, the zero-knowledge transformation adds only polylogarithmic time and memory overhead.

The result is a zero-knowledge proving system with no trusted setup, sub-megabyte setup artifacts, sub-linear proof size, and prover work that is small enough to run comfortably on mobile devices.

Roads not taken

Why not delegated proving? Delegated proving comes in several forms. Generic approaches use trusted execution environments (TEEs) or multi-party computation (MPC) to offload proving to external machines. While these can protect data during computation, they still require sensitive user information to leave the user’s device. For applications such as passport verification and Proof of Human, we place a high value on keeping personal data entirely local. This simplifies privacy compliance, reduces the risk of data exposure, and puts users in control of their own information. Since ProveKit can generate proofs efficiently on commodity mobile hardware, this additional complexity and these trust assumptions are unnecessary. Dedicated delegated proving schemes can avoid trusting the server, but schemes based on secret-sharing or encoding the witness between client and prover generally require communication proportional to the witness size. For our circuits, this communication cost exceeds our bandwidth budget.

Why not a zkVM? When ProveKit development started, many ZKP teams were building zkVMs. The appeal is that existing code (e.g. Rust) can be used instead of a domain-specific language like Noir, which makes development much easier. However the leading zkVMs were designed for running on large CPU servers or GPU clusters, succinct verification, and often omitted zero-knowledge. Those architectures do not adapt easily to good performance on constrained mobile devices. Essentially, the zkVMs reflect a very different set of design priorities from ProveKit.

There are also inherent sources of overhead. A VM-based arithmetization typically produces substantially more committed witness data than a circuit compiler such as ProveKit. Every instruction must encode not only the target computation but also the execution of a general-purpose processor, including instruction decoding, the program counter, registers, and memory accesses. Commitment is the dominant cost in most provers, so the typically smaller witness sizes of split-witness R1CS have a noticeable impact on proving time and memory usage. Compiling to a low-level instruction set also discards much of the high-level structure of the original computation, preventing optimizations that a circuit compiler can perform directly.

Why not pairings/lattices? Pairing-based commitment schemes, require a large field, typically a trusted setup and large download size, and are not post-quantum at efficient parameters. This is not a great fit for our requirements. Lattice-based commitments do not have these downsides, but current implementations do not perform as well on constrained devices as code-based schemes. We chose the code-based commitment scheme because it offers excellent performance at a conservative set of security assumptions.

Among code-based commitment schemes, WHIR stood out because of its performance and flexibility. In particular it supports arbitrary linear openings and can be tuned to balance prover time, proof size, memory use, and verifier cost.

What’s Next

ProveKit v1 is production-ready and independently audited, but development is far from finished. Version 2 will migrate from Noir’s BN254 field to Goldilocks, reducing proof size, prover time, and memory usage. We are also replacing the current ACIR-based pipeline with a compiler and witness generator that lower Noir directly to optimized prover bytecode. Besides improving proving performance, this reduces .pkp artifacts from megabytes to kilobytes, making circuits much easier to distribute.

Version 2 will also introduce a Groth16 backend for applications requiring efficient on-chain verification. Developers will be able to generate Groth16 proofs directly from Noir circuits or use recursive verification to combine ProveKit’s transparent proving system with the compact verification costs of Groth16. Together, these improvements will further reduce proving costs while expanding the range of applications ProveKit can support.

We are excited to release what we believe is a big milestone in real-world privacy. A thank you goes out to the dozens of people who have helped make this possible!

Try ProveKit with your own Noir circuits. Follow the Quick Start Guide or run cargo install provekit-cli.

実在する人間のネットワークに参加しましょう。

World IDアプリを入手