zkp: a toolkit for Schnorr proofs
About two years ago, I made a proof-of-concept library called zkp
, which used Rust macros to auto-generate an implementation of proving and verification for a class of Schnorr-style discrete logarithm proof statements. However, this approach had a number of limitations and wasn’t suitable for use in real applications. Today, I published a new and completely rewritten version of the library, which is now available on crates.io.
The new implementation contains a lower-level, Bellman-inspired programmable constraint system API, which allows imperative specification of proof statements, as well as a higher-level macro, which allows declarative specification of proof statements using a DSL that resembles mathematical notation:
define_proof! {
vrf_proof, // Name of the module for generated implementation
"VRF", // Label for the proof statement
(x), // Secret variables
(A, G, H), // Public variables unique to each proof
(B) : // Public variables common between proofs
A = (x * B), // Statements to prove
G = (x * H)
}
This macro expands into a module containing an implementation of proving, verification, batch verification, and benchmarks for the proof statement. Proving uses constant-time implementations, and the proofs have a derived implementation of (memory-safe) serialization and deserialization via Serde.
The repository’s tests
directory contains examples of how to use both the higher-level and lower-level APIs:
- a specification of an “anonymous credential presentation with 10 hidden attributes” proof from CMZ’13. Thanks to the choice of group, as well as the backend optimization work I did, the generated implementation performs verification between 20 to 40 times faster than the benchmark numbers reported in that paper.
- A transcript-based signature and VRF construction with an auto-generated implementation. This includes an example of using the online interactive composition described in the Merlin blog post to provide chained signatures between two counterparties.
- An example of using the lower-level constraint system API manually.
Using the API
To experiment with the API, add the crates to Cargo.toml
:
[dependencies]
curve25519-dalek = "1"
zkp = "0.6"
then add the crates to lib.rs
(or main.rs
):
#[macro_use]
extern crate zkp;
extern crate curve25519_dalek;
The documentation on the new API can be found on doc.dalek.rs or on docs.rs. After generating an implementation with the define_proof
macro, the documentation on how to use the generated code will appear in your crates’ documentation. Here’s an example of one way to use it:
What’s next
I’m hoping to streamline the API a little bit and release 1.0 soon. If this toolkit seems like it would be useful to you, please try out the API and leave comments on the issue tracker!