From 9d0b27a7e8ee45308773d6665d874b5d3d6e59cb Mon Sep 17 00:00:00 2001 From: Jordi Baylina Date: Fri, 26 Oct 2018 17:34:02 +0200 Subject: [PATCH] Tests added and Comparators --- circuits/{sha256 => }/binsum.circom | 0 circuits/{sha256 => }/bitify.circom | 27 +++++++++ circuits/comparators.circom | 55 +++++++++++++++++ circuits/sha256/gates.circom | 67 --------------------- circuits/sha256/sha256_2.circom | 2 +- circuits/sha256/sha256compression.circom | 2 +- circuits/sha256/sigmaplus.circom | 2 +- circuits/sha256/t1.circom | 2 +- circuits/sha256/t2.circom | 2 +- src/exec.js | 16 +++++ src/gencode.js | 16 ++++- test/circuits/isequal.circom | 4 ++ test/circuits/iszero.circom | 5 ++ test/circuits/lessthan.circom | 4 ++ test/circuits/sum_test.circom | 4 +- test/comparators.js | 77 ++++++++++++++++++++++++ test/helpers/printsignal.js | 22 +++++++ test/input_sum_test.json | 4 -- test/sha256.js | 44 +------------- test/sum.js | 35 +++++++++++ 20 files changed, 268 insertions(+), 122 deletions(-) rename circuits/{sha256 => }/binsum.circom (100%) rename circuits/{sha256 => }/bitify.circom (73%) create mode 100644 circuits/comparators.circom delete mode 100644 circuits/sha256/gates.circom create mode 100644 test/circuits/isequal.circom create mode 100644 test/circuits/iszero.circom create mode 100644 test/circuits/lessthan.circom create mode 100644 test/comparators.js create mode 100644 test/helpers/printsignal.js delete mode 100644 test/input_sum_test.json create mode 100644 test/sum.js diff --git a/circuits/sha256/binsum.circom b/circuits/binsum.circom similarity index 100% rename from circuits/sha256/binsum.circom rename to circuits/binsum.circom diff --git a/circuits/sha256/bitify.circom b/circuits/bitify.circom similarity index 73% rename from circuits/sha256/bitify.circom rename to circuits/bitify.circom index b22b59d..b701f93 100644 --- a/circuits/sha256/bitify.circom +++ b/circuits/bitify.circom @@ -17,6 +17,9 @@ along with circom. If not, see . */ +include "comparators.circom"; + + template Num2Bits(n) { signal input in; signal output out[n]; @@ -43,3 +46,27 @@ template Bits2Num(n) { lc1 ==> out; } + +template Num2BitsNeg(n) { + signal input in; + signal output out[n]; + var lc1=0; + + component isZero; + + isZero = IsZero(); + + var neg = n == 0 ? 0 : 2**n - in; + + for (var i = 0; i> i) & 1; + out[i] * (out[i] -1 ) === 0; + lc1 += out[i] * 2**i; + } + + in ==> isZero.in; + + + + lc1 + isZero.out * 2**n === 2**n - in; +} diff --git a/circuits/comparators.circom b/circuits/comparators.circom new file mode 100644 index 0000000..732bd6b --- /dev/null +++ b/circuits/comparators.circom @@ -0,0 +1,55 @@ +include "bitify.circom"; +include "binsum.circom"; + +template IsZero() { + signal input in; + signal output out; + + signal inv; + + inv <-- in!=0 ? 1/in : 0; + + out <== -in*inv +1; + in*out === 0; +} + + +template IsEqual() { + signal input in[2]; + signal output out; + + component isz = IsZero(); + + in[1] - in[0] ==> isz.in; + + isz.out ==> out; +} + + +// N is the number of bits the input have. +// The MSF is the sign bit. +template LessThan(n) { + signal input in[2]; + signal output out; + + component num2Bits0; + component num2Bits1; + + component adder; + + adder = BinSum(n, 2); + + num2Bits0 = Num2Bits(n); + num2Bits1 = Num2BitsNeg(n); + + in[0] ==> num2Bits0.in; + in[1] ==> num2Bits1.in; + + var i; + for (i=0;i adder.in[0][i]; + num2Bits1.out[i] ==> adder.in[1][i]; + } + + adder.out[n-1] ==> out; +} diff --git a/circuits/sha256/gates.circom b/circuits/sha256/gates.circom deleted file mode 100644 index a1fe69a..0000000 --- a/circuits/sha256/gates.circom +++ /dev/null @@ -1,67 +0,0 @@ -/* - Copyright 2018 0KIMS association. - - This file is part of circom (Zero Knowledge Circuit Compiler). - - circom is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - circom is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with circom. If not, see . -*/ - -template XOR() { - signal input a; - signal input b; - signal output out; - - out <== a + b - 2*a*b; -} - -template AND() { - signal input a; - signal input b; - signal output out; - - out <== a*b; -} - -template OR() { - signal input a; - signal input b; - signal output out; - - out <== a + b - a*b; -} - -template NOT() { - signal input in; - signal output out; - - out <== 1 + in - 2*in; -} - -template NAND() { - signal input a; - signal input b; - signal output out; - - out <== 1 - a*b; -} - -template NOR() { - signal input a; - signal input b; - signal output out; - - out <== a*b + 1 - a - b; -} - - diff --git a/circuits/sha256/sha256_2.circom b/circuits/sha256/sha256_2.circom index c061855..93c0a63 100644 --- a/circuits/sha256/sha256_2.circom +++ b/circuits/sha256/sha256_2.circom @@ -18,7 +18,7 @@ */ include "sha256compression.circom"; -include "bitify.circom" +include "../bitify.circom" template Sha256_2() { signal input a; diff --git a/circuits/sha256/sha256compression.circom b/circuits/sha256/sha256compression.circom index 33baf1c..66e041b 100644 --- a/circuits/sha256/sha256compression.circom +++ b/circuits/sha256/sha256compression.circom @@ -20,7 +20,7 @@ include "constants.circom"; include "t1.circom"; include "t2.circom"; -include "binsum.circom"; +include "../binsum.circom"; include "sigmaplus.circom"; template Sha256compression() { diff --git a/circuits/sha256/sigmaplus.circom b/circuits/sha256/sigmaplus.circom index 9b994f0..ec5a457 100644 --- a/circuits/sha256/sigmaplus.circom +++ b/circuits/sha256/sigmaplus.circom @@ -17,7 +17,7 @@ along with circom. If not, see . */ -include "binsum.circom" +include "../binsum.circom" include "sigma.circom" template SigmaPlus() { diff --git a/circuits/sha256/t1.circom b/circuits/sha256/t1.circom index 70d881d..28caed6 100644 --- a/circuits/sha256/t1.circom +++ b/circuits/sha256/t1.circom @@ -17,7 +17,7 @@ along with circom. If not, see . */ -include "binsum.circom"; +include "../binsum.circom"; include "sigma.circom"; include "ch.circom"; diff --git a/circuits/sha256/t2.circom b/circuits/sha256/t2.circom index fb4429b..54de837 100644 --- a/circuits/sha256/t2.circom +++ b/circuits/sha256/t2.circom @@ -17,7 +17,7 @@ along with circom. If not, see . */ -include "binsum.circom"; +include "../binsum.circom"; include "sigma.circom"; include "maj.circom" diff --git a/src/exec.js b/src/exec.js index bb85621..a280a28 100644 --- a/src/exec.js +++ b/src/exec.js @@ -98,6 +98,8 @@ function exec(ctx, ast) { return execGte(ctx, ast); } else if (ast.op == "==") { return execEq(ctx, ast); + } else if (ast.op == "!=") { + return execNeq(ctx, ast); } else if (ast.op == "?") { return execTerCon(ctx, ast); } else { @@ -680,6 +682,20 @@ function execEq(ctx, ast) { }; } +function execNeq(ctx, ast) { + const a = exec(ctx, ast.values[0]); + if (ctx.error) return; + if (a.type != "NUMBER") return { type: "NUMBER" }; + const b = exec(ctx, ast.values[1]); + if (ctx.error) return; + if (b.type != "NUMBER") return { type: "NUMBER" }; + if (!a.value || !b.value) return { type: "NUMBER" }; + return { + type: "NUMBER", + value: a.value.eq(b.value) ? bigInt(0) : bigInt(1) + }; +} + function execBAnd(ctx, ast) { const a = exec(ctx, ast.values[0]); diff --git a/src/gencode.js b/src/gencode.js index 0c3b5c2..2f7214e 100644 --- a/src/gencode.js +++ b/src/gencode.js @@ -83,6 +83,8 @@ function gen(ctx, ast) { return genGte(ctx, ast); } else if (ast.op == "==") { return genEq(ctx, ast); + } else if (ast.op == "!=") { + return genNeq(ctx, ast); } else if (ast.op == "?") { return genTerCon(ctx, ast); } else { @@ -314,7 +316,9 @@ function genVariable(ctx, ast) { if (ctx.error) return; } - + if (!v) { + return error(ctx, ast, "Invalid left operand"); + } if (v.type == "VARIABLE") { return `ctx.getVar("${ast.name}",[${sels.join(",")}])`; } else if (v.type == "SIGNAL") { @@ -530,7 +534,15 @@ function genEq(ctx, ast) { if (ctx.error) return; const b = gen(ctx, ast.values[1]); if (ctx.error) return; - return `bigInt(${a}).eq(bigInt(${b})) ? 1 : 0`; + return `(bigInt(${a}).eq(bigInt(${b})) ? 1 : 0)`; +} + +function genNeq(ctx, ast) { + const a = gen(ctx, ast.values[0]); + if (ctx.error) return; + const b = gen(ctx, ast.values[1]); + if (ctx.error) return; + return `(bigInt(${a}).eq(bigInt(${b})) ? 0 : 1)`; } function genUMinus(ctx, ast) { diff --git a/test/circuits/isequal.circom b/test/circuits/isequal.circom new file mode 100644 index 0000000..c14d506 --- /dev/null +++ b/test/circuits/isequal.circom @@ -0,0 +1,4 @@ + +include "../../circuits/comparators.circom"; + +component main = IsEqual(); diff --git a/test/circuits/iszero.circom b/test/circuits/iszero.circom new file mode 100644 index 0000000..0ca0589 --- /dev/null +++ b/test/circuits/iszero.circom @@ -0,0 +1,5 @@ + + +include "../../circuits/comparators.circom"; + +component main = IsZero(); diff --git a/test/circuits/lessthan.circom b/test/circuits/lessthan.circom new file mode 100644 index 0000000..63944f2 --- /dev/null +++ b/test/circuits/lessthan.circom @@ -0,0 +1,4 @@ + +include "../../circuits/comparators.circom"; + +component main = LessThan(32); diff --git a/test/circuits/sum_test.circom b/test/circuits/sum_test.circom index 9ab2b70..a8b062b 100644 --- a/test/circuits/sum_test.circom +++ b/test/circuits/sum_test.circom @@ -1,5 +1,5 @@ -include "../../circuits/sha256/bitify.circom" -include "../../circuits/sha256/binsum.circom" +include "../../circuits/bitify.circom" +include "../../circuits/binsum.circom" template A() { signal private input a; diff --git a/test/comparators.js b/test/comparators.js new file mode 100644 index 0000000..0e6f144 --- /dev/null +++ b/test/comparators.js @@ -0,0 +1,77 @@ +const chai = require("chai"); +const path = require("path"); +const snarkjs = require("snarkjs"); +const crypto = require("crypto"); + +const compiler = require("../index.js"); + +const assert = chai.assert; + +describe("Sum test", () => { + it("Should create a iszero circuit", async() => { + const cirDef = await compiler(path.join(__dirname, "circuits", "iszero.circom")); + + const circuit = new snarkjs.Circuit(cirDef); + + let witness; + witness = circuit.calculateWitness({ "in": 111}); + assert(witness[0].equals(snarkjs.bigInt(1))); + assert(witness[1].equals(snarkjs.bigInt(0))); + + witness = circuit.calculateWitness({ "in": 0 }); + assert(witness[0].equals(snarkjs.bigInt(1))); + assert(witness[1].equals(snarkjs.bigInt(1))); + }); + it("Should create a isequal circuit", async() => { + const cirDef = await compiler(path.join(__dirname, "circuits", "isequal.circom")); + + const circuit = new snarkjs.Circuit(cirDef); + + let witness; + witness = circuit.calculateWitness({ "in[0]": "111", "in[1]": "222" }); + assert(witness[0].equals(snarkjs.bigInt(1))); + assert(witness[1].equals(snarkjs.bigInt(0))); + + witness = circuit.calculateWitness({ "in[0]": "444", "in[1]": "444" }); + assert(witness[0].equals(snarkjs.bigInt(1))); + assert(witness[1].equals(snarkjs.bigInt(1))); + }); + it("Should create a comparison", async() => { + const cirDef = await compiler(path.join(__dirname, "circuits", "lessthan.circom")); + + const circuit = new snarkjs.Circuit(cirDef); + + let witness; + witness = circuit.calculateWitness({ "in[0]": "333", "in[1]": "444" }); + assert(witness[0].equals(snarkjs.bigInt(1))); + assert(witness[1].equals(snarkjs.bigInt(1))); + + witness = circuit.calculateWitness({ "in[0]": "1", "in[1]": "1" }); + assert(witness[0].equals(snarkjs.bigInt(1))); + assert(witness[1].equals(snarkjs.bigInt(0))); + + witness = circuit.calculateWitness({ "in[0]": "661", "in[1]": "660" }); + assert(witness[0].equals(snarkjs.bigInt(1))); + assert(witness[1].equals(snarkjs.bigInt(0))); + + witness = circuit.calculateWitness({ "in[0]": "0", "in[1]": "1" }); + assert(witness[0].equals(snarkjs.bigInt(1))); + assert(witness[1].equals(snarkjs.bigInt(1))); + + witness = circuit.calculateWitness({ "in[0]": "0", "in[1]": "444" }); + assert(witness[0].equals(snarkjs.bigInt(1))); + assert(witness[1].equals(snarkjs.bigInt(1))); + + witness = circuit.calculateWitness({ "in[0]": "1", "in[1]": "0" }); + assert(witness[0].equals(snarkjs.bigInt(1))); + assert(witness[1].equals(snarkjs.bigInt(0))); + + witness = circuit.calculateWitness({ "in[0]": "555", "in[1]": "0" }); + assert(witness[0].equals(snarkjs.bigInt(1))); + assert(witness[1].equals(snarkjs.bigInt(0))); + + witness = circuit.calculateWitness({ "in[0]": "0", "in[1]": "0" }); + assert(witness[0].equals(snarkjs.bigInt(1))); + assert(witness[1].equals(snarkjs.bigInt(0))); + }); +}); diff --git a/test/helpers/printsignal.js b/test/helpers/printsignal.js new file mode 100644 index 0000000..796274d --- /dev/null +++ b/test/helpers/printsignal.js @@ -0,0 +1,22 @@ + +const snarkjs = require("snarkjs"); + +const bigInt = snarkjs.bigInt; + +module.exports = function hexBits(cir, witness, sig, nBits) { + let v = bigInt(0); + for (let i=nBits-1; i>=0; i--) { + v = v.shiftLeft(1); + const name = sig+"["+i+"]"; + const idx = cir.getSignalIdx(name); + const vbit = bigInt(witness[idx].toString()); + if (vbit.equals(bigInt(1))) { + v = v.add(bigInt(1)); + } else if (vbit.equals(bigInt(0))) { + v; + } else { + console.log("Not Binary: "+name); + } + } + return v.toString(16); +}; diff --git a/test/input_sum_test.json b/test/input_sum_test.json deleted file mode 100644 index 4709cc9..0000000 --- a/test/input_sum_test.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "a": "111", - "b": "222" -} diff --git a/test/sha256.js b/test/sha256.js index 478a792..a00f54b 100644 --- a/test/sha256.js +++ b/test/sha256.js @@ -8,51 +8,11 @@ const compiler = require("../index.js"); const assert = chai.assert; const sha256 = require("./helpers/sha256"); -const bigInt = require("big-integer"); -function hexBits(cir, witness, sig, nBits) { - let v = bigInt(0); - for (let i=nBits-1; i>=0; i--) { - v = v.shiftLeft(1); - const name = sig+"["+i+"]"; - const idx = cir.getSignalIdx(name); - const vbit = bigInt(witness[idx].toString()); - if (vbit.equals(bigInt(1))) { - v = v.add(bigInt(1)); - } else if (vbit.equals(bigInt(0))) { - v; - } else { - console.log("Not Binary: "+name); - } - } - return v.toString(16); -} +// const printSignal = require("./helpers/printsignal"); -describe("SHA256 test", () => { - it("Should create a constant circuit", async () => { - - const cirDef = await compiler(path.join(__dirname, "circuits", "constants_test.circom")); - assert.equal(cirDef.nVars, 2); - - const circuit = new snarkjs.Circuit(cirDef); - - const witness = circuit.calculateWitness({ "in": "0xd807aa98" }); - - assert(witness[0].equals(snarkjs.bigInt(1))); - assert(witness[1].equals(snarkjs.bigInt("0xd807aa98"))); - }); - it("Should create a sum circuit", async () => { - const cirDef = await compiler(path.join(__dirname, "circuits", "sum_test.circom")); - assert.equal(cirDef.nVars, 101); - - const circuit = new snarkjs.Circuit(cirDef); - - const witness = circuit.calculateWitness({ "a": "111", "b": "222" }); - - assert(witness[0].equals(snarkjs.bigInt(1))); - assert(witness[1].equals(snarkjs.bigInt("333"))); - }); +describe("SHA256 test", () => { it("Should calculate a hash", async () => { const cirDef = await compiler(path.join(__dirname, "circuits", "sha256_2_test.circom")); const circuit = new snarkjs.Circuit(cirDef); diff --git a/test/sum.js b/test/sum.js new file mode 100644 index 0000000..009f72e --- /dev/null +++ b/test/sum.js @@ -0,0 +1,35 @@ +const chai = require("chai"); +const path = require("path"); +const snarkjs = require("snarkjs"); +const crypto = require("crypto"); + +const compiler = require("../index.js"); + +const assert = chai.assert; + +describe("Sum test", () => { + it("Should create a constant circuit", async () => { + + const cirDef = await compiler(path.join(__dirname, "circuits", "constants_test.circom")); + assert.equal(cirDef.nVars, 2); + + const circuit = new snarkjs.Circuit(cirDef); + + const witness = circuit.calculateWitness({ "in": "0xd807aa98" }); + + assert(witness[0].equals(snarkjs.bigInt(1))); + assert(witness[1].equals(snarkjs.bigInt("0xd807aa98"))); + }); + it("Should create a sum circuit", async () => { + + const cirDef = await compiler(path.join(__dirname, "circuits", "sum_test.circom")); + assert.equal(cirDef.nVars, 101); + + const circuit = new snarkjs.Circuit(cirDef); + + const witness = circuit.calculateWitness({ "a": "111", "b": "222" }); + + assert(witness[0].equals(snarkjs.bigInt(1))); + assert(witness[1].equals(snarkjs.bigInt("333"))); + }); +});