shunkakinoki / continuum

A background checker with zero knowledge proof

Home Page:

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Continuum is a background checker using Zero Knowledge proof. This project is a proof of concept to showcase how revealing your data works with zero knowledge proof.

testnet page:
mainnet page:


How it works

  • Retrieves data from github. This will be stored only locally.
  • Users can selectively reveal data from Github.
    • A commitment hash which is the combination of user's signature and data to reveal is inserted to MerkleTree.
    • It does not represent any personal data. Currently MerkleTree is stored on AWS using DynamoDB.
  • Users can mint NFT to prove the data they revealed.
    • Continuum generates MerkleProof from MerkleTree
    • On the client side, users generate a zkSNARK proof using the MerkleProof
    • Users submit the proof to the contract. Once verified, NFT will be issued.

Screen Shot 2022-05-09 at 7 13 55 AM

You can find more details on or


Call yarn install --ignore-engines at the root of the project. (ipfs contains node v16. It is used in Lambda but not required for the whole project)

Github auth


This project uses AWS. You need to setup your AWS account which has an access to at least CDK, Lambda, DynamoDB, SecretManager.


  • Rename local.env.sample to local.env and set your backend setup
  • Run yarn run dev


You can create your own Verifier Contract with different MerkleTree depth.

Step1. Seeding

  • Seed Zero hashes and group
yarn ts-node ./seedZeroHashes.ts
yarn ts-node ./seedGroups.ts

Step2. Generate input.json

We'll generate input.json from the actual input. We need values below.

Signal Detail Visibility
identityTrapdoor Generated by signature + groupId Private
identityNullifier Generated by signature + groupId Private
treePathIndices[nLevels] path indices of the leaf Private
treeSiblings[nLevels] siblings for MerkleProof Private
signalHash arbitrary byte32 value("continuum") Public
externalNullifier groupId as bigInt Public

Expected Output is root and nullifierHash which are generated by inputs above

Sample input can be found under /packages/hardhat/scripts. It is generated with the command below. Make sure to update MERKLE_TREE_DEPTH to your expected depth.

$ npx hardhat run ./scripts/generateSnarkInput.ts

Step3. Generate Verifier.sol

Go to /packages/hardhat/circuit and run the command below to generate Verifier.sol using Groth16

$ circom semaphore.circom --r1cs --wasm --sym
template instances: 144
non-linear constraints: 4582
linear constraints: 0
public inputs: 2
public outputs: 2
private inputs: 34
private outputs: 0
wires: 4603
labels: 14523

// convert r1cs to json
$ snarkjs r1cs export json semaphore.r1cs semaphore.r1cs.json

// Generate witness
$ node generate_witness.js semaphore.wasm ../input.json ../witness.wtns

// Generate final key and export Verifier.sol and verification key
$ yarn ts-node scripts/generateFinalKey.ts

// Generate the proof
$ snarkjs groth16 prove semaphore_final.zkey witness.wtns proof.json public.json

// Verify the proof
$ snarkjs groth16 verify verification_key.json public.json proof.json
[INFO]  snarkJS: OK!

// Generate Verifier
snarkjs zkey export solidityverifier semaphore_final.zkey ../contracts/Verifier.sol

// Generate call for Solidity for testing
$ snarkjs zkey export soliditycalldata public.json proof.json
["0x2078cd35aeaee98079cd034a2d5ec44e818f40c02d9218d0b279e4eb0893c7c4", "0x2d046623a90d7bcdcb174a4f7e73dae142d9fc817397334530b9d08f3bf372cd"],[["0x223a070a25bceb0ebafb063fc438338104090866e5b9e0ebc928bda6b471220e", "0x16555996336686fb6e9a528ecf16366312277e675fd162cc6a1c979e52896d43"],["0x02d3a006cd912e75789211e9f11601d2fd0d2ca287465c6fe89b35441af087ed", "0x10249bd8e3ccc341bf0cf317a2be56ee5a71c89fbcf3e49eb6714b7a2d210932"]],["0x2f4c3bd3eed7c8b7a703f46a4c719a2126536a0423095b99e28a5716c5a54d65", "0x211ca97c4f7e4e732b2e0b6ab9c88c08800906a290a7d961c2e3040d07b34987"],["0x2363beff769130fb20e6ebc044963247402b15e539a985cdd1128ff5566b9f2e","0x239bb965e269f6d79442fbaff13689546108b8e1fde2f632ed9e4b23388bd7bb","0x000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266","0x000000000000000000000000000000006af4841553646671a088d658246d9877"]

Running on Remix

After Deploying both Verifier.sol and Continuum.sol run the command below.

$ npx hardhat run ./scripts/generateSolidityInput.ts
merkleRoot: 0x2363beff769130fb20e6ebc044963247402b15e539a985cdd1128ff5566b9f2e
nullifierHash: 0x239bb965e269f6d79442fbaff13689546108b8e1fde2f632ed9e4b23388bd7bb
externalNullier: 0x6af4841553646671a088d658246d9877

Input values above to test the contract. You need to add "" to proof inputs ["0x...", "0x...", ..] or you'll get argument error



Testnet: 0x008150FD2e971857058Ee14254439691edb25490
Mainet: 0x1BBC601bF0b2C87E18561019488318C3C06daC29



ezoic increase your site revenue


A background checker with zero knowledge proof


Language:TypeScript 84.9%Language:Solidity 8.5%Language:JavaScript 6.2%Language:CSS 0.2%Language:Shell 0.1%