mirror of
https://github.com/tornadocash/snarkjs.git
synced 2024-07-01 06:11:52 +02:00
398 lines
10 KiB
Markdown
398 lines
10 KiB
Markdown
# snarkjs: JavaScript implementation of zkSNARKs.
|
||
|
||
This is a JavaScript and Pure Web Assembly implementation of zkSNARK schemes. It uses the Groth16 Protocol (3 point only and 3 pairings)
|
||
|
||
This library includes all the tools required to perform trusted setup multi-party ceremonies: including the universal "powers of tau" ceremony, and the second phase circuit specific ceremonies.
|
||
|
||
The formats used in this library for the multi-party computation are compatible with the ones used in [Semaphore's Perpetual Powers of Tau](https://github.com/weijiekoh/perpetualpowersoftau) and [other implementations](https://github.com/kobigurk/phase2-bn254).
|
||
|
||
This library uses the compiled circuits generated by the [circom](https://github.com/iden3/circom) compiler.
|
||
|
||
The library works in `node.js` as well as directly in the browser.
|
||
|
||
It's an [ES module](https://hacks.mozilla.org/2018/03/es-modules-a-cartoon-deep-dive/), so it can be directly imported into bigger projects using [Rollup](https://rollupjs.org/guide/en/) or [Webpack](https://webpack.js.org/).
|
||
|
||
The low-level cryptography is performed directly in wasm, and uses worker threads to parallelize the computations. The result is a high performance library with benchmarks comparable to host implementations.
|
||
|
||
## Preliminaries
|
||
|
||
### Install node v14
|
||
First off, make sure you have a recent version of `Node.js` installed. While any version after `v12` should work fine, we recommend you install `v14` or later.
|
||
|
||
If you’re not sure which version of Node you have installed, you can run:
|
||
|
||
```sh
|
||
node -v
|
||
```
|
||
|
||
To download the latest version of Node, see [here](https://nodejs.org/en/download/).
|
||
|
||
### Install snarkjs and circom
|
||
|
||
To install `circom` and `snarkjs`, run:
|
||
|
||
```sh
|
||
npm install -g circom@latest
|
||
npm install -g snarkjs@latest
|
||
```
|
||
|
||
If you're seeing an error, try prefixing both commands with `sudo`.
|
||
|
||
### Understand the Help command
|
||
|
||
To see a list of all `snarkjs` commands, as well as descriptions about their inputs and outputs, run:
|
||
|
||
```sh
|
||
snarkjs --help
|
||
```
|
||
|
||
|
||
The help for specific command:
|
||
|
||
Example
|
||
```sh
|
||
snarkjs groth16 prove --help
|
||
```
|
||
|
||
Most of the commands have a short alias.
|
||
|
||
For example, the previous command can also be invoked as:
|
||
|
||
```sh
|
||
snarkjs g16p --help
|
||
```
|
||
|
||
### Debugging tip
|
||
|
||
If you a feel a command is taking longer than it should, re-run it with a `-v` or `--verbose` option to see more details about how it's progressing and where it's getting blocked. For example:
|
||
|
||
|
||
```sh
|
||
snarkjs g16p -v
|
||
```
|
||
|
||
|
||
## Tutorial
|
||
|
||
### 0. Create a new directory
|
||
|
||
```sh
|
||
mkdir snarkjs_example
|
||
cd snarkjs_example
|
||
```
|
||
|
||
### 1. Start a new ceremony.
|
||
|
||
```sh
|
||
snarkjs powersoftau new bn128 12 pot12_0000.ptau
|
||
```
|
||
|
||
The first parameter after `new` refers to the type of curve you wish to use. At the moment, we support both `bn128` and `bls12-381`.
|
||
|
||
The second parameter, in this case `12`, is the power of two of the maximum number of contraints that the ceremony can accept.
|
||
|
||
In this case, the maximum number of constraints is `2^12 = 4096`.
|
||
|
||
### 2. Contribute to the ceremony
|
||
```sh
|
||
snarkjs powersoftau contribute pot12_0000.ptau pot12_0001.ptau --name="Example Name" -v
|
||
```
|
||
|
||
The name is a random name and it's include for reference. It's printed in the verification.
|
||
|
||
### 3. Provide a second contribution
|
||
```sh
|
||
snarkjs powersoftau contribute pot12_0001.ptau pot12_0002.ptau --name="Second contribution Name" -v -e="some random text"
|
||
```
|
||
|
||
the -e parameter allows the comman to be non interactive and use this text as an extra source of entropy for the random generation.
|
||
|
||
|
||
### 4. Verify the file
|
||
```sh
|
||
snarkjs powersoftau verify pot12_0002.ptau
|
||
```
|
||
|
||
This command checks all the contributions of the Multiparty Computation (MPC) and list the hashes of the
|
||
intermediary results.
|
||
|
||
### Contribute using third party software
|
||
|
||
```sh
|
||
snarkjs powersoftau export challange pot12_0002.ptau challange_0003
|
||
snarkjs powersoftau challange contribute bn128 challange_0003 response_0003
|
||
snarkjs powersoftau import response pot12_0002.ptau response_0003 pot12_0003.ptau -n="Third contribution name"
|
||
```
|
||
|
||
|
||
### Add a beacon
|
||
```sh
|
||
snarkjs powersoftau beacon pot12_0003.ptau pot12_beacon.ptau 0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f 10 -n="Final Beacon"
|
||
```
|
||
|
||
### Prepare phase2
|
||
```sh
|
||
snarkjs powersoftau prepare phase2 pot12_beacon.ptau pot12_final.ptau -v
|
||
```
|
||
|
||
### Verify the last file
|
||
```sh
|
||
snarkjs powersoftau verify pot12_final.ptau
|
||
```
|
||
|
||
### Create a circuit
|
||
```sh
|
||
cat <<EOT > circuit.circom
|
||
template Multiplier(n) {
|
||
signal private input a;
|
||
signal private input b;
|
||
signal output c;
|
||
|
||
signal int[n];
|
||
|
||
int[0] <== a*a + b;
|
||
for (var i=1; i<n; i++) {
|
||
int[i] <== int[i-1]*int[i-1] + b;
|
||
}
|
||
|
||
c <== int[n-1];
|
||
}
|
||
|
||
component main = Multiplier(1000);
|
||
EOT
|
||
```
|
||
|
||
This is an example circom fille that allows to test the system with different number of contraints.
|
||
|
||
In this case 1000, but it can be changed to any nomber of constraints.
|
||
|
||
### compile the circuit
|
||
```sh
|
||
circom circuit.circom -r -w -s -v
|
||
```
|
||
|
||
-r to generate the .r1cs file
|
||
-w to generate the .wasm file that computes the witness from an input.
|
||
-s to generate the .sym file that contains the human readable names of all signals. (Important to debug the circuit)
|
||
-v Verbose. To see the progress of the compilation.
|
||
|
||
### info of a circuit
|
||
```sh
|
||
snarkjs r1cs info circuit.r1cs
|
||
```
|
||
|
||
### Print the constraints
|
||
```sh
|
||
snarkjs r1cs print circuit.r1cs
|
||
```
|
||
|
||
### export r1cs to json
|
||
```sh
|
||
snarkjs r1cs export json circuit.r1cs circuit.r1cs.json
|
||
cat circuit.r1cs.json
|
||
```
|
||
|
||
|
||
### Generate the reference zKey without contributions from the circuit.
|
||
```sh
|
||
snarkjs zkey new circuit.r1cs pot12_final.ptau circuit_0000.zkey
|
||
```
|
||
|
||
circuit_0000.zkey does not include any contribution yet, so it cannot be used in a final circuit.
|
||
|
||
### Contribute in the phase2 ceremony
|
||
```sh
|
||
snarkjs zkey contribute circuit_0000.zkey circuit_0001.zkey --name="1st Contributor Name" -v
|
||
```
|
||
|
||
### Do a second phase2 contribution
|
||
```sh
|
||
snarkjs zkey contribute circuit_0001.zkey circuit_0002.zkey --name="Second contribution Name" -v -e="Another random entropy"
|
||
```
|
||
|
||
|
||
### Verify the zkey file
|
||
```sh
|
||
snarkjs zkey verify circuit.r1cs pot12_final.ptau circuit_0002.zkey
|
||
```
|
||
|
||
|
||
### Contribute using third party software.
|
||
|
||
```sh
|
||
snarkjs zkey export bellman circuit_0002.zkey challange_phase2_0003
|
||
snarkjs zkey bellman contribute bn128 challange_phase2_0003 response_phase2_0003
|
||
snarkjs zkey import bellman circuit_0002.zkey response_phase2_0003 circuit_0003.zkey -n="Third contribution name"
|
||
```
|
||
|
||
|
||
### Add a beacon
|
||
```sh
|
||
snarkjs zkey beacon circuit_0003.zkey circuit_final.zkey 0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f 10 -n="Final Beacon phase2"
|
||
```
|
||
|
||
### Verify the final file
|
||
```sh
|
||
snarkjs zkey verify circuit.r1cs pot12_final.ptau circuit_final.zkey
|
||
```
|
||
|
||
### Export the verification key
|
||
```sh
|
||
snarkjs zkey export verificationkey circuit_final.zkey verification_key.json
|
||
```
|
||
|
||
### Calculat witess
|
||
```sh
|
||
cat <<EOT > input.json
|
||
{"a": 3, "b": 11}
|
||
EOT
|
||
snarkjs wtns calculate circuit.wasm input.json witness.wtns
|
||
```
|
||
|
||
|
||
### Debug witness calculation
|
||
|
||
In general, when you are developing a new circuit you will want to check for some errors in the witness calculation process.
|
||
|
||
You can do it by doing
|
||
```sh
|
||
snarkjs wtns debug circuit.wasm input.json witness.wtns circuit.sym --trigger --get --set
|
||
```
|
||
|
||
This will log every time a new component is started/ended ( --trigger ) when a signal is set (--set) and when it's get (--get)
|
||
|
||
|
||
### Proof calculation
|
||
```sh
|
||
snarkjs groth16 prove circuit_final.zkey witness.wtns proof.json public.json
|
||
```
|
||
|
||
It is possible also to do the calculate witness and the prove calculation in the same command:
|
||
```sh
|
||
snarkjs groth16 fullprove input.json circuit.wasm circuit_final.zkey proof.json public.json
|
||
```
|
||
|
||
|
||
### Verify
|
||
```sh
|
||
snarkjs groth16 verify verification_key.json public.json proof.json
|
||
```
|
||
|
||
### Export Solidity Verifier
|
||
```sh
|
||
snarkjs zkey export solidityverifier circuit_final.zkey verifier.sol
|
||
```
|
||
|
||
You can deploy th "Verifier" smartcontract using remix for example.
|
||
|
||
In order to simulate a verification call, you can do:
|
||
|
||
```sh
|
||
snarkjs zkey export soliditycalldata public.json proof.json
|
||
```
|
||
|
||
And cut and paste the resolt directlly in the "verifyProof" field in the deployed smart contract.
|
||
|
||
This call will return true if the proof and the public data is valid.
|
||
|
||
|
||
## Use in node
|
||
|
||
```sh
|
||
npm init
|
||
npm install snarkjs
|
||
```
|
||
|
||
```js
|
||
const snarkjs = require("snarkjs");
|
||
const fs = require("fs");
|
||
|
||
async function run() {
|
||
const { proof, publicSignals } = await snarkjs.groth16.fullProve({a: 10, b: 21}, "circuit.wasm", "circuit_final.zkey");
|
||
|
||
console.log("Proof: ");
|
||
console.log(JSON.stringify(proof, null, 1));
|
||
|
||
const vKey = JSON.parse(fs.readFileSync("verification_key.json"));
|
||
|
||
const res = await snarkjs.groth16.verify(vKey, publicSignals, proof);
|
||
|
||
if (res === true) {
|
||
console.log("Verification OK");
|
||
} else {
|
||
console.log("Invalid proof");
|
||
}
|
||
|
||
}
|
||
|
||
run().then(() => {
|
||
process.exit(0);
|
||
});
|
||
```
|
||
|
||
## Use in the web
|
||
|
||
load snarkjs.min.js and start using it normally.
|
||
|
||
```
|
||
cp node_modules/snarkjs/build/snarkjs.min.js .
|
||
```
|
||
|
||
|
||
```html
|
||
<!doctype html>
|
||
<html>
|
||
<head>
|
||
<title>Snarkjs client example</title>
|
||
</head>
|
||
<body>
|
||
|
||
<h1>Snarkjs client example</h1>
|
||
<button id="bGenProof"> Create proof </button>
|
||
|
||
<!-- JS-generated output will be added here. -->
|
||
<pre class="proof"> Proof: <code id="proof"></code></pre>
|
||
|
||
<pre class="proof"> Result: <code id="result"></code></pre>
|
||
|
||
|
||
<script src="snarkjs.min.js"> </script>
|
||
|
||
|
||
<!-- This is the bundle generated by rollup.js -->
|
||
<script>
|
||
|
||
const proofCompnent = document.getElementById('proof');
|
||
const resultComponent = document.getElementById('result');
|
||
const bGenProof = document.getElementById("bGenProof");
|
||
|
||
bGenProof.addEventListener("click", calculateProof);
|
||
|
||
async function calculateProof() {
|
||
|
||
const { proof, publicSignals } =
|
||
await snarkjs.groth16.fullProve( { a: 3, b: 11}, "circuit.wasm", "circuit_final.zkey");
|
||
|
||
proofCompnent.innerHTML = JSON.stringify(proof, null, 1);
|
||
|
||
|
||
const vkey = await fetch("verification_key.json").then( function(res) {
|
||
return res.json();
|
||
});
|
||
|
||
const res = await snarkjs.groth16.verify(vkey, publicSignals, proof);
|
||
|
||
resultComponent.innerHTML = res;
|
||
}
|
||
|
||
</script>
|
||
|
||
</body>
|
||
</html>
|
||
```
|
||
|
||
|
||
## License
|
||
|
||
snarkjs is part of the iden3 project copyright 2018 0KIMS association and published with GPL-3 license. Please check the COPYING file for more details.
|