Skip to content

Latest commit

 

History

History
218 lines (166 loc) · 5.83 KB

zkdb-rollup.md

File metadata and controls

218 lines (166 loc) · 5.83 KB

zkDB Rollup Tutorial

zkJSON is still under active development, and neither the circuits nor the contracts have been audited. Please use it for only experimental purposes.

Install zkjson Package

Make sure you have Circom and Hardhat installed globally.

git clone https://github.com/weavedb/zkjson.git
cd zkjson
yarn

Generate Powers of Tau

For the db circuit,

yarn ceremony --power 16

For the rollup circuit,

yarn ceremony --power 20

Beware that power 20 takes hours.

Compile Circuits

We need to compile 2 circuits.

yarn compile --power 16 --circuit db
yarn compile --power 20 --circuit rollup

Create Solidity Project with Hardhat

cd ..
mkdir myrollup
cd myrollup
npx hardhat init
yarn add zkjson

Copy Verifier Contracts

cp ../zkjson/circom/build/circuit/db/verifier.sol contracts/verifier_db.sol
cp ../zkjson/circom/build/circuit/rollup/verifier.sol contracts/verifier_rollup.sol

Rename the contract name to Groth16VerifierJSON as we will have multiple verifiers with the same name.

Open myrollup/contracts/verifier_db.sol and rename

contract Groth16Verifier {

to

contract Groth16VerifierDB {

Then open myrollup/contracts/verifier_rollup.sol and rename

contract Groth16Verifier {

to

contract Groth16VerifierRU {

Write Solidity Contract

myrollup/contracts/MyRollup.sol

// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.7.0 <0.9.0;
import "../node_modules/zkrjson/contracts/ZKRollup.sol";

interface VerifierDB {
  function verifyProof(uint[2] calldata _pA, uint[2][2] calldata _pB, uint[2] calldata _pC, uint[14] calldata _pubSignals) view external returns (bool);
}

contract MyRollup is ZKRollup {
  uint constant SIZE_PATH = 5;
  uint constant SIZE_VAL = 5;
  address public verifierDB;

  constructor (address _verifierRU, address _verifierDB, address _committer){
    verifierRU = _verifierRU;
    verifierDB = _verifierDB;
    committer = _committer;
  }
  
  function validateQuery(uint[] memory path, uint[] memory zkp) private view returns(uint[] memory){
    verify(zkp, VerifierDB.verifyProof.selector, verifierDB);
    return _validateQueryRU(path, zkp, SIZE_PATH, SIZE_VAL);    
  }

  function qInt (uint[] memory path, uint[] memory zkp) public view returns (int) {
    uint[] memory value = validateQuery(path, zkp);
    return _qInt(value);
  }

  function qFloat (uint[] memory path, uint[] memory zkp) public view returns (uint[3] memory) {
    uint[] memory value = validateQuery(path, zkp);
    return _qFloat(value);
  }

  function qRaw (uint[] memory path, uint[] memory zkp) public view returns (uint[] memory) {
    uint[] memory value = validateQuery(path, zkp);
    return _qRaw(value);
  }
  
  function qString (uint[] memory path, uint[] memory zkp) public view returns (string memory) {
    uint[] memory value = validateQuery(path, zkp);
    return _qString(value);
  }

  function qBool (uint[] memory path, uint[] memory zkp) public view returns (bool) {
    uint[] memory value = validateQuery(path, zkp);
    return _qBool(value);
  }
  
  function qNull (uint[] memory path, uint[] memory zkp) public view returns (bool) {
    uint[] memory value = validateQuery(path, zkp);
    return _qNull(value);
  }
}

Write Tests

myrollup/test/MyRollup.js

const { loadFixture } = require("@nomicfoundation/hardhat-network-helpers")
const { toIndex, path, DB } = require("zkjson")
const { resolve } = require("path")
const { expect } = require("chai")

async function deploy() {
  const [committer] = await ethers.getSigners()
  const VerifierRU = await ethers.getContractFactory("Groth16VerifierRU")
  const verifierRU = await VerifierRU.deploy()
  const VerifierDB = await ethers.getContractFactory("Groth16VerifierDB")
  const verifierDB = await VerifierDB.deploy()

  const MyRU = await ethers.getContractFactory("MyRollup")
  const myru = await MyRU.deploy( verifierRU.address, verifierDB.address, committer.address )
  return { myru, committer }
}

describe("MyRollup", function () {
  let myru, committer, db, col_id, ru
  this.timeout(0)

  beforeEach(async () => {
    const dep = await loadFixture(deploy)
    myru = dep.myru
    committer = dep.committer
  })

  it("should verify rollup transactions", async function () {
    db = new DB({
      level: 100,
      size_path: 5,
      size_val: 5,
      size_json: 256,
      size_txs: 10,
      level_col: 8,
      wasmRU: resolve(  __dirname, "../../zkjson/circom/build/circuits/rollup/index_js/index.wasm" ),
      zkeyRU: resolve(  __dirname, "../../zkjson/circom/build/circuits/rollup/index_0001.zkey" ),
      wasm: resolve(  __dirname, "../../zkjson/circom/build/circuits/db/index_js/index.wasm" ),
      zkey: resolve( __dirname, "../../zkjson/circom/build/circuits/db/index_0001.zkey" ),
    })
    await db.init()
    col_id = await db.addCollection()
    const people = [
      { name: "Bob", age: 10 },
      { name: "Alice", age: 20 },
      { name: "Mike", age: 30 },
      { name: "Beth", age: 40 },
    ]
    let txs = people.map(v => { return [col_id, v.name, v] })
	
    // batch commit write queries
    const zkp = await db.genRollupProof(txs)
    await myru.commit(zkp)

    // query Bob's age
    const zkp2 = await db.genProof({ json: people[0], col_id, path: "age", id: "Bob" })
    expect((await myru.qInt([col_id, toIndex("Bob"), ...path("age")], zkp2)).toNumber()).to.eql(10)
	
    // query Beth's name
    const zkp3 = await db.genProof({ json: people[3], col_id, path: "name", id: "Beth" })
    expect(await myru.qString([col_id, toIndex("Beth"), ...path("name")], zkp3)).to.eql("Beth")
  })
})

Then run the tests.

yarn hardhat test test/MyRollup.js