So I assume you have read the theory around Zero Knowledge already. If not, read my last post. Just to summarize: Zero Knowledge is a powerful tool to prove a statement is true without revealing anything additional on the value or reasoning.
Taking the most basic example: Suppose I want to prove my age is in a certain range without revealing my age, of course.
Following are the steps using groth16 (zk-SNARK) and circom (I will share explanations on each step):
Install circom (for creating the circuit for proving mathematically that the age lies in the given range) and snarkjs (for encrypting the truth / witness of the successful passing of circuit with input value of age and exposing a proof that can be verified by anyone). I have specified the versions that I created the proving system with.
npm install -g snarkjs@0.7.5 circom@2.0.4
In a new folder for your project (say AgeProof), create a file named age_range.circom to represent the constraints and the basic mathematical circuit for ensuring that it successfully creates a witness object only when input age is less than maxAge and more than minAge:
pragma circom 2.0.0; template AgeRangeProof() { signal input age; // Your age (private input) signal input minAge; // Minimum age in the range (public input) signal input maxAge; // Maximum age in the range (public input) // Enforce age >= minAge signal minCheck; minCheck <== age - minAge; assert(minCheck >= 0); // Enforce age <= maxAge signal maxCheck; maxCheck <== maxAge - age; assert(maxCheck >= 0); } component main = AgeRangeProof();
But where are the inputs coming from?? Well, since we need dynamic inputs, we specify them later in input.json.
Next, we use circom to generate the constraint specification (in the form of R1CS), web assembly script (the wasm script which can be run anywhere to create proof) and symbol file (for debug symbols) from the logic we put in age_range.circom in Step 2.
circom age_range.circom --r1cs --wasm --sym
Screenshot from my terminal shows the execution results and what new files got generated Next 4 steps, we create the encryption key which will be used to generate proof over (witness,input) and Powers of Tau is a powerful key generation ceremony which ensures that we build on top of randomness generated from multiple contributions across time along with our own contribution of random input. This is a one-time setup. So begin:
snarkjs powersoftau new bn128 12 pot12_0000.ptau
snarkjs powersoftau contribute pot12_0000.ptau pot12_0001.ptau
(Takes time) Next we finish setting up Powers Of Tau and begin the final phase for key generation.
snarkjs powersoftau prepare phase2 pot12_0001.ptau pot12_final.ptau
Next, lets generate the encryption key from the final constraints and Powers of Tau results:
snarkjs groth16 setup age_range.r1cs pot12_final.ptau age_range_0000.zkey

To improve the security of this key generation process, let us also contribute a random string into the key:
snarkjs zkey contribute age_range_0000.zkey age_range_final.zkey

Next, create following input.json in the same folder
{
"age": 23,
"minAge": 18,
"maxAge": 25
}
9. Now we can create the witness file for proving that inputs satisfy the constraints of the circom circuit we used :
node age_range_js/generate_witness.js age_range_js/age_range.wasm input.json witness.wtns

Now that we have a witness file, let us create the publicly shareable proof using the encryption key we generated in step 7 :
snarkjs groth16 prove age_range_final.zkey witness.wtns proof.json public.json

For someone to be able to verify that our proof was generated genuinely using the (private input age ,public inputs of minAge and maxAge), we need to share with them the verification key, so lets export it :
snarkjs zkey export verificationkey age_range_final.zkey verification_key.json

Now anyone can use the verification_key.json to verify that proof.json actually is the proof that the secret input age lies between the public inputs minAge and maxAge
snarkjs groth16 verify verification_key.json public.json proof.json
