This repository contains two Proof-of-Concepts (PoC) on how to implement privacy-preserving algorithms with electronic identities. It is funded by the IP-ICT 101.292 Innolink Grant on Secure and Privacy-Preserving Credentials for E-ID. You can find more information in the MS2 report.
The first PoC is created using the docknetwork/crypto library and is written in Rust. It uses Bulletproofs and BBS signatures to create the various proofs for the PoC.
The second PoC uses noir-lang to work on a fixed-size credential. The Barretenberg backend implements a UltraHONK proof which is optimized for blockchains, but still fast enough for our goals.
The third PoC uses noir-lang on Android with MoPro. You can find the code in the zkp-android repository. The benchmark results are in the table below.
According to our grant, we proposed to implement the following 4 types of proofs on the noir and docknetwork backend. It is to be noted that each circuit is measures only one proof and does not include the others. For example, the circuit c05 only includes the age verification, and does not verify the issuer signature.
- WP3 (c03) - holder binding: proving that the holder can create a signature on the challenge sent by the verifier, which can be verified by the public key stored in the credential
- WP4 (c04) - issuer signature: proving that the holder has access to a credential which has been signed by a publicly known public key
- WP5 (c05) - age verification: proving that the credential of the
holder has an
birthdatefield with a date 18 years or more in the past - WP6 (c06) - non-revocation: proving that the credential of the
holder has an
idfield which has a corresponding0bit set in the revocation list signed by a publicly known key - c09 - the concatenation of all of the proofs above to create an age proof, including holder binding and non-revocation.
In addition to these proofs for our half-project report, we added the following two circuits for the noir backend only:
- d10 - a full Swiyu JWT age proof, with issuer and holder binding, but excluding the non-revocation
- d11 - a modified proof for the SICPA identity backend, showing the possibility to easily adapt to other systems
For more details, please have a look at our [REPORT].
Here is a summary of how long the proofs and verifications take on a MacBook Pro Apple M2 Max from 2023. All times are in seconds.
| Docknetwork test | setup [s] | create_proof [s] | verify [s] | proof_size [B] |
|---|---|---|---|---|
| c03_proof_holder | 0.197 | 6.622 | 7.921 | 186429 |
| c04_proof_credential | 0.158 | 0.031 | 0.052 | 570 |
| c05_proof_predicate | 0.238 | 0.036 | 0.060 | 538 |
| c05_proof_predicate_age | 0.238 | 0.369 | 0.115 | 1952 |
| c06_proof_non_revocation | 0.160 | 0.037 | 0.098 | 760 |
| c09_proof_full | 0.172 | 7.125 | 8.515 | 189141 |
| Noir test | acir | circuit | create_vk [s] | create_proof [s] | verify [s] | proof_size [B] |
|---|---|---|---|---|---|---|
| c03_holder_binding | 2108 | 74682 | 0.25 | 0.72 | 0.01 | 14656 |
| c04_issuer_signature | 535 | 89039 | 0.38 | 0.88 | 0.01 | 14656 |
| c05_age_verification | 285 | 3227 | 0.02 | 0.10 | 0.01 | 14656 |
| c06_non_revocation | 1011 | 86305 | 0.37 | 0.85 | 0.01 | 14656 |
| c09_full_proof | 3211 | 242000 | 0.81 | 1.71 | 0.01 | 14656 |
| d10_swiyu_jwt | 92811 | 453007 | 1.55 | 3.10 | 0.01 | 14656 |
| d11_sicpa_backend | 79719 | 439405 | 1.49 | 2.97 | 0.01 | 14656 |
| d12_patrick | 95370 | 456527 | 1.56 | 2.97 | 0.01 | 14656 |
Here's the benchmarking for the proof generation on a Galaxy A54 5G. All times are in seconds.
| Noir test | Average of 100 runs [s] | Best [s] | Worst [s] |
|---|---|---|---|
| c03_holder_binding | 1.975 | 1.841 | 2.176 |
| c04_issuer_signature | 2.428 | 2.073 | 2.821 |
| c05_age_verification | 0.314 | 0.258 | 0.381 |
| c06_non_revocation | 2.645 | 2.109 | 3.016 |
| c09_full_proof | 6.483 | 5.643 | 6.940 |
| d10_swiyu_jwt | 18.419 | 16.154 | 21.013 |
For the second half of our grant, we will work together with our partners to get feedback on these PoCs. If they validate the approach, we will work on improving the proving system from Noir to tilt the balance away from long proving time to longer verification time.
You can follow the instructions for the Noir Prover or the Docknetwork Prover. TLDR:
- Install devbox
- Run
devbox run noir-allanddevbox run dock-allto run the examples on your machine
Alternatively, you can use our pre-built Docker image using the Make targets from the root of this repository:
- To build the image run:
make build- To clean the docker image run:
make clean-image- To run all docknetwork tests:
make dock-all- To run all noir tests:
make noir-all- To run all tests:
make all- To clean all build artifacts:
make clean- To clean only noir build artifacts:
make noir-clean- To spawn an interactive shell inside the container:
make debug-shellWe also provide a way to run the prover and verifier as separate services using Docker Compose.
- To start the services run:
docker-compose up- To stop the services run:
docker-compose downYou can call the prover service at http://localhost:8000/prove with a POST request containing the circuit as form data to generate a proof and verify it with the verifier service. (Available circuits: c03_holder_binding, c04_issuer_signature, c05_age_verification, c06_non_revocation, c09_full_proof).
The endpoint also takes an optional scheme parameter to specify the proving scheme to use (e.g., ultra_honk, plonk, etc.). If not provided, it will use the default scheme specified in the environment variable DEFAULT_SCHEME.
For example:
curl -X POST http://localhost:8000/prove -H "Content-Type: application/x-www-form-urlencoded" -d "circuit=c05_age_verification"You can also directly call the verifier service at http://localhost:8080/verify with a POST request containing the proof, vk, and public_inputs as form data to verify a proof. The endpoint also takes an optional scheme parameter to specify the proving scheme used for the proof. If not provided, it will use the default scheme specified in the environment variable DEFAULT_SCHEME.
For example:
curl -X POST http://localhost:8080/verify -F "proof=@path/to/proof" -F "vk=@path/to/vk" -F "public_inputs=@path/to/public_inputs"You can run time testing on the prover and verifier services by running:
make test-remoteThe results will be stored in noir/stats_remote_proof_times.csv.
If you develop some of these circuits, please add the following git-hook to your installation:
git config core.hooksPath .githooks-
2026/09/02
-
Added d12_patrick after a discussion with Patrick Amrein
-
2026/05
-
Adding d11_sicpa_backend for integration in new backend
-
Added android mobile benchmarks from zkp-android
-
2026/04
Added a d10_swiyu_jwt circuit with a full testing of a minimally modified Swiyu JWT credential: to create the signature for the holder binding, the device public key in the credential had to be updated, which needed an update of the issuer signature, which needed an update of the issuer identity...
- 2026/01/13
Patrick Amrein from Ubique suggested to use --release in the cargo test
for the docknetwork simulations.
This improved complete proving times for docknetwork by a factor of 15!
Now it is faster in all aspects than noir, which makes more sense.