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")));
+ });
+});