The hello world app of ZK: prove you know a non-trivial factorization of an integer without revealing the factors.
This repo serves as a guide to show how to plug a ZK Haskell program into existing proving software. In this case we want to build a browser based proving application with an Ethereum smart contract verifier, and we will make use of the snarkjs proving library. There are similar integrations for arkworks, the nova folding scheme and more to come.
You must have nix installed and ideally direnv. The haskell builds are managed by different nix shells depending on the directory because we require both the normal and WASM GHC.
All other builds/tools are managed via npm. To get started, run
> npm install
You should have a local ethereum node with an unlocked default account and the web3 api running on the default port 8545
. E.g. use hardhat or cliquebait:
> docker run --rm -it -p 8545:8545 foamspace/cliquebait:latest
A ZK program written in a Haskell DSL that expresses a factorization of a public input n
into a product of secret inputs a
and b
. The factorization must be non-trivial, i.e. a /= 1 && b /= 1
.
You can produce a circom compatible r1cs
file for this program by running
> cabal run factors -- compile --r1cs trusted-setup/circuit.r1cs --constraints trusted-setup/circuit.bin
You should see the artifacts
trusted-setup
├── circuit.bin
├── circuit.r1cs
└ ...
The circuit.r1cs
file is the R1CS that is expected by snarkjs for proving/verification key generation. The circuit.bin
is the binary serialization of the constraints represented by the compiled circuit. This file is required in order to evaluate the circuit, i.e. generate a witness.
A constraint solver applied to the factors
program. You can produce a circom compatible WASM binary for this solver by running
> cd wasm-solver
> ./build-wasm
You should see an artifact www/circuit.wasm
.
Assuming you have run the above, you should see a circuit.r1cs
file in the trusted-setup
directory. To produce a final proving key and solidity verifier:
> npx snarkjs groth16 setup trusted-setup/circuit.r1cs trusted-setup/pot14_final.ptau trusted-setup/circuit_final.zkey
> npx snarkjs zkey export solidityverifier trusted-setup/circuit_final.zkey contracts/Groth16Verifier.sol
You can verify your proving key:
> npx snarkjs zkey verify trusted-setup/circuit.r1cs trusted-setup/pot14_final.ptau trusted-setup/circuit_final.zkey
NOTE: It is also possible to generate a witness, construct a proof and verify it using the standard snarkjs
cli commands with the artifacts we have created.
You can comple the contracts, build the purescript ffi, and deploy this smart contract via
> npm run chanterelle-build
> npm run chanterelle-deploy
Assuming you have done the previous steps, copy the proving key and the compiled circuit to the www
folder
> cp trusted-setup/circuit_final.zkey trusted-setup/circuit.bin www
You should see the circuit.wasm
solver binary is already there. Assuming you have deployed the verifying contract, you can start the frontend:
> npm run build
> export VERIFIER_ADDRESS=$(jq -r '.networks."420123".address' build/contracts/Groth16Verifier.json) && npm run parcel
NOTE: I used cliquebaite to write this readme, which has networkId/chainId 420123
. If you have a different chainId, you will need to subsitute it in the above command or just find the address in the artifact manually.
You should see a form load to test the application