Getting Started
The @pcd/gpc
package allows you to prove and verify using GPCs. This guide will walk you through how to get started with POD development. The examples below assuming you’re using TypeScript, but the same steps will work from JavaScript as well.
You can find full information about the types and functions used here in the API Reference. If you prefer to read complete working code, check out the tutorial example.
Installation
To get started with GPCs, you will need to install the @pcd/pod
package, using your preferred package manager:
The package is available in CJS or ESM format, and will work either in browser or in a server. The example code makes use of bigint literals, so requries a target of at least ES2020.
Packaging for a browser requires polyfill for some Node modules, including buffer
and constants
, so watch for that if you see any dependency issues.
There is a known issue with a dependency fastfile
which can be resolved by polyfilling constants
as you can see in this example.
Imports
Next, import the types and functions you need from the package. See the API Reference for everything which is available, and import what you need as you write your code. Here’s an example covering the first few samples below:
Prove or verify?
The GPC library allows you to create and verify zero knowledge proofs about PODs. Depending on your use case, your app may need to prove, or verify, or both. You may need to so either client-side (in browser) or server-side.
If you intend to integrate with Zupass, you can use the Z-API to query the user’s PODs, and request proofs about them without using the GPC library directly. In that case, you can skip ahead to the verification section of this guide.
This remainder of this guide walks through the steps to both prove and verify in your own app in a browser.
Preparing Inputs
PODs
In order to make a proof, you first need some PODs. The examples below will work with the example POD signed in POD Tutorial. Check out that page first to learn how to work with PODs.
Artifacts
Proving and verifying also requires binary files called artifacts, which are tailored to a specific GPC circuit. The prover and verifier need to use the same artifacts for proofs to be valid. Artifacts released separately from the code since they’re large enough not to be packaged with your app bundle. You can obtain artifacts from NPM or direct download.
See the Circuit Artifacts page for full details about how to manage artifacts. For this example, we’ll fetch them from a CDN backed by NPM.
Proof Configuration
To make a proof, you first have to say what you want to prove. A GPCProofConfiguration
specifies the POD entries you want to prove, and the constraints you want to apply to them. The Proof Configuration page has full details, but let’s start with a simple configuration. This will prove that the ID POD has a birthdate earlier than Nov 11 2003, and reveal the holder’s name.
Make a proof
With all the preparation in place you can format the inputs to make your first ZK proof! The proofInputs
argument lets you match up real PODs with the names used in the configuration.
The result of proving includes 3 types of data:
proof
is the cryptrographic proof of correctness. These are opaque numbers which can be used to verify the correctness of the rest.boundConfig
is the same as the configuration you passed in, except it now contains the identifier of the specific circuit which was auto-selected for the proof.revealedClaims
contains the information revealed in this proof. In this case, it includes thename
entry, as well as the public key of the ID card’s signer.
Transmit the proof as JSON
Usually the prover and verifier won’t be the same app (otherwise there would be no need for a proof). The results of gpcProve()
are precisely the values which need to be sent to the verifier.
You can send these objects across the network using JSON. However, they contain non-JSON-compatible types such as bigint
so they need to be converted before transmission.
The verifier can reverse the conversion to recover the original objects. The conversion also fully validates the structure of the objects, and will throw an error if they are malformed.
Verify the proof
Finally the verifier can confirm that the proof is valid using gpcVerify()
. This needs all three parts of the proof result, as well as the same artifact download URL used by the prover.
Check assumptions
If gpcVerify()
returns true, you know you have a valid proof of something, but it’s still important to confirm it’s the right proof. The logic inside gpcVerify()
ensures that all the contents of the config and revealed claims properly correspond to each other, but it can’t decide whether they match your app’s expectations.
To avoid being fooled by cheating provers, should check:
- The signer’s public key is the one you expect. Trusted issuers, such as Zupass should publish their public keys.
- The configuration reflects what you wanted to prove.
Finally you should remember to examine the revealed entries. In this case the user’s name was revealed, so it could be used to record their admittance to an event.