Browse Source

Add circom test w/ circuit for CircomVerifierProof

Add circom test with circuit for CircomVerifierProofs, which allows to
automatically check that the data generated from arbo matches the circom
circuit of a SMTVerifierProof.
Added also GHA workflow to test the circuits with the output of arbo
code.
master
arnaucube 2 years ago
parent
commit
a8c7ea9808
10 changed files with 2257 additions and 0 deletions
  1. +24
    -0
      .github/workflows/circomtest.yml
  2. +3
    -0
      testvectors/circom/.gitignore
  3. +56
    -0
      testvectors/circom/go-data-generator/generator_test.go
  4. +1950
    -0
      testvectors/circom/package-lock.json
  5. +32
    -0
      testvectors/circom/package.json
  6. +28
    -0
      testvectors/circom/test/circuits/smt-proof-processor_test.circom
  7. +27
    -0
      testvectors/circom/test/circuits/smt-proof-verifier_test.circom
  8. +94
    -0
      testvectors/circom/test/smt.test.ts
  9. +19
    -0
      testvectors/circom/tsconfig.json
  10. +24
    -0
      testvectors/circom/tslint.json

+ 24
- 0
.github/workflows/circomtest.yml

@ -0,0 +1,24 @@
name: CircomTest
on: [ push, pull_request ]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [14.x]
go-version: [1.16.x]
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- name: Install Go
uses: actions/setup-go@v1
with:
go-version: ${{ matrix.go-version }}
- name: run circom tests
run: |
cd testvectors/circom
npm install
npm run test

+ 3
- 0
testvectors/circom/.gitignore

@ -0,0 +1,3 @@
node_modules
dist
go-data-generator/*.json

+ 56
- 0
testvectors/circom/go-data-generator/generator_test.go

@ -0,0 +1,56 @@
package main
import (
"encoding/json"
"io/ioutil"
"math/big"
"testing"
qt "github.com/frankban/quicktest"
"github.com/vocdoni/arbo"
"go.vocdoni.io/dvote/db"
)
func TestGenerator(t *testing.T) {
c := qt.New(t)
database, err := db.NewBadgerDB(c.TempDir())
c.Assert(err, qt.IsNil)
tree, err := arbo.NewTree(database, 4, arbo.HashFunctionPoseidon)
c.Assert(err, qt.IsNil)
bLen := tree.HashFunction().Len()
testVector := [][]int64{
{1, 11},
{2, 22},
{3, 33},
{4, 44},
}
for i := 0; i < len(testVector); i++ {
k := arbo.BigIntToBytes(bLen, big.NewInt(testVector[i][0]))
v := arbo.BigIntToBytes(bLen, big.NewInt(testVector[i][1]))
if err := tree.Add(k, v); err != nil {
t.Fatal(err)
}
}
// proof of existence
k := arbo.BigIntToBytes(bLen, big.NewInt(int64(2)))
cvp, err := tree.GenerateCircomVerifierProof(k)
c.Assert(err, qt.IsNil)
jCvp, err := json.Marshal(cvp)
c.Assert(err, qt.IsNil)
// store the data into a file that will be used at the circom test
err = ioutil.WriteFile("go-smt-verifier-inputs.json", jCvp, 0600)
c.Assert(err, qt.IsNil)
// proof of non-existence
k = arbo.BigIntToBytes(bLen, big.NewInt(int64(5)))
cvp, err = tree.GenerateCircomVerifierProof(k)
c.Assert(err, qt.IsNil)
jCvp, err = json.Marshal(cvp)
c.Assert(err, qt.IsNil)
// store the data into a file that will be used at the circom test
err = ioutil.WriteFile("go-smt-verifier-non-existence-inputs.json", jCvp, 0600)
c.Assert(err, qt.IsNil)
}

+ 1950
- 0
testvectors/circom/package-lock.json
File diff suppressed because it is too large
View File


+ 32
- 0
testvectors/circom/package.json

@ -0,0 +1,32 @@
{
"name": "arbo-testvectors-circom",
"version": "0.0.1",
"description": "",
"main": "index.js",
"directories": {
"test": "test"
},
"scripts": {
"build": "npm run clean && ./node_modules/.bin/tsc",
"clean": "rimraf dist",
"pretest": "cd go-data-generator && go test",
"test": "npm run build && ./node_modules/.bin/mocha -r ts-node/register test/**/*.ts"
},
"author": "",
"license": "GPL-3.0",
"dependencies": {
"chai": "^4.2.0",
"circom": "0.5.45",
"circomlib": "^0.5.0",
"ffjavascript": "0.2.33"
},
"devDependencies": {
"@types/chai": "^4.2.14",
"@types/mocha": "^8.2.0",
"@types/node": "^14.14.25",
"mocha": "^8.0.1",
"ts-node": "^9.1.1",
"tslint": "^6.1.3",
"typescript": "^4.1.3"
}
}

+ 28
- 0
testvectors/circom/test/circuits/smt-proof-processor_test.circom

@ -0,0 +1,28 @@
include "../../node_modules/circomlib/circuits/comparators.circom";
include "../../node_modules/circomlib/circuits/poseidon.circom";
include "../../node_modules/circomlib/circuits/smt/smtprocessor.circom";
template SMTProcessorTest(nLevels) {
signal input newKey;
signal input newValue;
signal private input oldKey;
signal private input oldValue;
signal private input isOld0;
signal private input siblings[nLevels];
signal input oldRoot;
signal input newRoot;
component smtProcessor = SMTProcessor(nLevels);
smtProcessor.oldRoot <== oldRoot;
smtProcessor.newRoot <== newRoot;
for (var i=0; i<nLevels; i++) {
smtProcessor.siblings[i] <== siblings[i];
}
smtProcessor.oldKey <== oldKey;
smtProcessor.oldValue <== oldValue;
smtProcessor.isOld0 <== isOld0;
smtProcessor.newKey <== newKey;
smtProcessor.newValue <== newValue;
smtProcessor.fnc[0] <== 1;
smtProcessor.fnc[1] <== 0;
}

+ 27
- 0
testvectors/circom/test/circuits/smt-proof-verifier_test.circom

@ -0,0 +1,27 @@
include "../../node_modules/circomlib/circuits/comparators.circom";
include "../../node_modules/circomlib/circuits/poseidon.circom";
include "../../node_modules/circomlib/circuits/smt/smtverifier.circom";
template SMTVerifierTest(nLevels) {
signal input key;
signal input value;
signal input fnc;
signal private input oldKey;
signal private input oldValue;
signal private input isOld0;
signal private input siblings[nLevels];
signal input root;
component smtV = SMTVerifier(nLevels);
smtV.enabled <== 1;
smtV.fnc <== fnc;
smtV.root <== root;
for (var i=0; i<nLevels; i++) {
smtV.siblings[i] <== siblings[i];
}
smtV.oldKey <== oldKey;
smtV.oldValue <== oldValue;
smtV.isOld0 <== isOld0;
smtV.key <== key;
smtV.value <== value;
}

+ 94
- 0
testvectors/circom/test/smt.test.ts

@ -0,0 +1,94 @@
const fs = require("fs");
const path = require("path");
const tester = require("circom").tester;
const assert = require('assert');
const circomlib = require("circomlib");
const smt = require("circomlib").smt;
describe("merkletreetree circom-proof-verifier", function () {
this.timeout(0);
const nLevels = 4;
let circuit;
let circuitPath = path.join(__dirname, "circuits", "mt-proof-verifier-main.test.circom");
before( async() => {
const circuitCode = `
include "smt-proof-verifier_test.circom";
component main = SMTVerifierTest(4);
`;
fs.writeFileSync(circuitPath, circuitCode, "utf8");
circuit = await tester(circuitPath, {reduceConstraints:false});
await circuit.loadConstraints();
console.log("Constraints: " + circuit.constraints.length + "\n");
});
after( async() => {
fs.unlinkSync(circuitPath);
});
let inputsVerifier, inputsVerifierNonExistence;
before("generate smt-verifier js inputs", async () => {
let tree = await smt.newMemEmptyTrie();
await tree.insert(1, 11);
await tree.insert(2, 22);
await tree.insert(3, 33);
await tree.insert(4, 44);
const res = await tree.find(2);
assert(res.found);
let root = tree.root;
let siblings = res.siblings;
while (siblings.length < nLevels) {
siblings.push("0");
};
inputsVerifier = {
"fnc": 0,
"key": 2,
"value": 22,
"siblings": siblings,
"root": root,
};
const res2 = await tree.find(5);
assert(!res2.found);
let siblings2 = res2.siblings;
while (siblings2.length < nLevels) {
siblings2.push("0");
};
inputsVerifierNonExistence = {
"fnc": 1,
"oldKey": 1,
"oldValue": 11,
"key": 5,
"value": 11,
"siblings": siblings2,
"root": root,
};
});
it("Test smt-verifier proof of existence go inputs", async () => {
// fromGo is a json CircomVerifierProof generated from Go code using
// https://github.com/vocdoni/arbo
let rawdata = fs.readFileSync('go-data-generator/go-smt-verifier-inputs.json');
let fromGo = JSON.parse(rawdata);
inputsVerifier=fromGo;
// console.log("smtverifier js inputs:\n", inputsVerifier);
const witness = await circuit.calculateWitness(inputsVerifier);
await circuit.checkConstraints(witness);
});
it("Test smt-verifier proof of non-existence go inputs", async () => {
// fromGo is a json CircomVerifierProof generated from Go code using
// https://github.com/vocdoni/arbo
let rawdata = fs.readFileSync('go-data-generator/go-smt-verifier-non-existence-inputs.json');
let fromGo = JSON.parse(rawdata);
inputsVerifierNonExistence=fromGo;
// console.log("smtverifier js inputs:\n", inputsVerifierNonExistence);
const witness = await circuit.calculateWitness(inputsVerifierNonExistence);
await circuit.checkConstraints(witness);
});
});

+ 19
- 0
testvectors/circom/tsconfig.json

@ -0,0 +1,19 @@
{
"compilerOptions": {
"module": "commonjs",
"moduleResolution": "node",
"resolveJsonModule": true,
"pretty": true,
"declaration": true,
"sourceMap": true,
"target": "es2017",
"outDir": "dist",
"baseUrl": "src"
},
"include": [
"test/**/*.ts"
],
"exclude": [
"node_modules"
]
}

+ 24
- 0
testvectors/circom/tslint.json

@ -0,0 +1,24 @@
{
"defaultSeverity": "error",
"extends": [
"tslint:recommended"
],
"jsRules": {},
"rules": {
"indent": [
true,
"spaces",
4
],
"semicolon": [
false,
"always"
]
},
"rulesDirectory": [],
"linterOptions": {
"exclude": [
"node_modules/**"
]
}
}

Loading…
Cancel
Save