mirror of
https://github.com/arnaucube/arbo.git
synced 2026-01-11 16:11:29 +01:00
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.
This commit is contained in:
24
.github/workflows/circomtest.yml
vendored
Normal file
24
.github/workflows/circomtest.yml
vendored
Normal file
@@ -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
testvectors/circom/.gitignore
vendored
Normal file
3
testvectors/circom/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
node_modules
|
||||||
|
dist
|
||||||
|
go-data-generator/*.json
|
||||||
56
testvectors/circom/go-data-generator/generator_test.go
Normal file
56
testvectors/circom/go-data-generator/generator_test.go
Normal file
@@ -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
testvectors/circom/package-lock.json
generated
Normal file
1950
testvectors/circom/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
32
testvectors/circom/package.json
Normal file
32
testvectors/circom/package.json
Normal file
@@ -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"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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
testvectors/circom/test/smt.test.ts
Normal file
94
testvectors/circom/test/smt.test.ts
Normal file
@@ -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
testvectors/circom/tsconfig.json
Normal file
19
testvectors/circom/tsconfig.json
Normal file
@@ -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
testvectors/circom/tslint.json
Normal file
24
testvectors/circom/tslint.json
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"defaultSeverity": "error",
|
||||||
|
"extends": [
|
||||||
|
"tslint:recommended"
|
||||||
|
],
|
||||||
|
"jsRules": {},
|
||||||
|
"rules": {
|
||||||
|
"indent": [
|
||||||
|
true,
|
||||||
|
"spaces",
|
||||||
|
4
|
||||||
|
],
|
||||||
|
"semicolon": [
|
||||||
|
false,
|
||||||
|
"always"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"rulesDirectory": [],
|
||||||
|
"linterOptions": {
|
||||||
|
"exclude": [
|
||||||
|
"node_modules/**"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user