From 1f94f7f3ec771f08218a665d5424d7a4f7e6f58a Mon Sep 17 00:00:00 2001 From: Jordi Baylina Date: Sun, 8 Dec 2019 13:39:16 +0100 Subject: [PATCH] All Bit and logical operators working --- c/zqfield.cpp | 79 +++++++++++++++++++ c/zqfield.h | 18 +++++ parser/jaz.jison | 1 + parser/jaz.js | 38 ++++----- src/c_gen.js | 152 +++++++++++++++--------------------- src/exec.js | 66 +++++++++++++++- src/zqfield.js | 62 ++++++++++++++- test/basiccases.js | 44 +++++++++++ test/circuits/ops3.circom | 12 +++ test/circuits/opsbit.circom | 18 +++++ test/circuits/opscmp.circom | 18 +++++ test/circuits/opslog.circom | 12 +++ 12 files changed, 410 insertions(+), 110 deletions(-) create mode 100644 test/circuits/ops3.circom create mode 100644 test/circuits/opsbit.circom create mode 100644 test/circuits/opscmp.circom create mode 100644 test/circuits/opslog.circom diff --git a/c/zqfield.cpp b/c/zqfield.cpp index c779b23..3acf4e2 100644 --- a/c/zqfield.cpp +++ b/c/zqfield.cpp @@ -5,6 +5,10 @@ ZqField::ZqField(PBigInt ap) { mpz_init_set(p, *ap); mpz_init_set_ui(zero, 0); mpz_init_set_ui(one, 1); + nBits = mpz_sizeinbase (p, 2); + mpz_init(mask); + mpz_mul_2exp(mask, one, nBits-1); + mpz_sub(mask, mask, one); } ZqField::~ZqField() { @@ -30,6 +34,14 @@ void ZqField::sub(PBigInt r, PBigInt a, PBigInt b) { } } +void ZqField::neg(PBigInt r, PBigInt a) { + if (mpz_sgn(*a) > 0) { + mpz_sub(*r, p, *a); + } else { + mpz_set(*r, *a); + } +} + void ZqField::mul(PBigInt r, PBigInt a, PBigInt b) { mpz_mul(tmp,*a,*b); mpz_fdiv_r(*r, tmp, p); @@ -49,6 +61,10 @@ void ZqField::mod(PBigInt r, PBigInt a, PBigInt b) { mpz_fdiv_r(*r, *a, *b); } +void ZqField::pow(PBigInt r, PBigInt a, PBigInt b) { + mpz_powm(*r, *a, *b, p); +} + void ZqField::lt(PBigInt r, PBigInt a, PBigInt b) { int c = mpz_cmp(*a, *b); if (c<0) { @@ -103,6 +119,30 @@ void ZqField::neq(PBigInt r, PBigInt a, PBigInt b) { } } +void ZqField::land(PBigInt r, PBigInt a, PBigInt b) { + if (mpz_sgn(*a) && mpz_sgn(*b)) { + mpz_set(*r, one); + } else { + mpz_set(*r, zero); + } +} + +void ZqField::lor(PBigInt r, PBigInt a, PBigInt b) { + if (mpz_sgn(*a) || mpz_sgn(*b)) { + mpz_set(*r, one); + } else { + mpz_set(*r, zero); + } +} + +void ZqField::lnot(PBigInt r, PBigInt a) { + if (mpz_sgn(*a)) { + mpz_set(*r, zero); + } else { + mpz_set(*r, one); + } +} + int ZqField::isTrue(PBigInt a) { return mpz_sgn(*a); } @@ -110,3 +150,42 @@ int ZqField::isTrue(PBigInt a) { void ZqField::copyn(PBigInt a, PBigInt b, int n) { for (int i=0;i= 0) { + mpz_set(*r, zero); + } else { + mpz_mul_2exp(*r, *a, mpz_get_ui(*b)); + mpz_and(*r, *r, mask); + } +} + +void ZqField::shr(PBigInt r, PBigInt a, PBigInt b) { + if (mpz_cmp_ui(*b, nBits) >= 0) { + mpz_set(*r, zero); + } else { + mpz_tdiv_q_2exp(*r, *a, mpz_get_ui(*b)); + mpz_and(*r, *r, mask); + } +} + diff --git a/c/zqfield.h b/c/zqfield.h index ca11d0b..e80c8a5 100644 --- a/c/zqfield.h +++ b/c/zqfield.h @@ -10,22 +10,40 @@ public: BigInt p; BigInt one; BigInt zero; + size_t nBits; + BigInt mask; ZqField(PBigInt ap); ~ZqField(); void copyn(PBigInt a, PBigInt b, int n); + void add(PBigInt r,PBigInt a, PBigInt b); void sub(PBigInt r,PBigInt a, PBigInt b); + void neg(PBigInt r,PBigInt a); void mul(PBigInt r,PBigInt a, PBigInt b); void div(PBigInt r,PBigInt a, PBigInt b); void idiv(PBigInt r,PBigInt a, PBigInt b); void mod(PBigInt r,PBigInt a, PBigInt b); + void pow(PBigInt r,PBigInt a, PBigInt b); + void lt(PBigInt r, PBigInt a, PBigInt b); void eq(PBigInt r, PBigInt a, PBigInt b); void gt(PBigInt r, PBigInt a, PBigInt b); void leq(PBigInt r, PBigInt a, PBigInt b); void geq(PBigInt r, PBigInt a, PBigInt b); void neq(PBigInt r, PBigInt a, PBigInt b); + + void land(PBigInt r, PBigInt a, PBigInt b); + void lor(PBigInt r, PBigInt a, PBigInt b); + void lnot(PBigInt r, PBigInt a); + + void band(PBigInt r, PBigInt a, PBigInt b); + void bor(PBigInt r, PBigInt a, PBigInt b); + void bxor(PBigInt r, PBigInt a, PBigInt b); + void bnot(PBigInt r, PBigInt a); + void shl(PBigInt r, PBigInt a, PBigInt b); + void shr(PBigInt r, PBigInt a, PBigInt b); + int isTrue(PBigInt a); }; diff --git a/parser/jaz.jison b/parser/jaz.jison index 356c684..34e56be 100644 --- a/parser/jaz.jison +++ b/parser/jaz.jison @@ -85,6 +85,7 @@ include { return 'include'; } \& { return '&'; } \| { return '|'; } \! { return '!'; } +\~ { return '~'; } \< { return '<'; } \> { return '>'; } \! { return '!'; } diff --git a/parser/jaz.js b/parser/jaz.js index 191f36a..4c9db52 100644 --- a/parser/jaz.js +++ b/parser/jaz.js @@ -1329,42 +1329,44 @@ case 59: return 65; break; case 60: return 94; break; -case 61: return 77; +case 61: return 95; break; -case 62: return 78; +case 62: return 77; break; -case 63: return 94; +case 63: return 78; break; -case 64: return 57; +case 64: return 94; break; -case 65: return 58; +case 65: return 57; break; -case 66: return 20; +case 66: return 58; break; -case 67: return 22; +case 67: return 20; break; -case 68: return 112; +case 68: return 22; break; -case 69: return 113; +case 69: return 112; break; -case 70: return 36; +case 70: return 113; break; -case 71: return 37; +case 71: return 36; break; -case 72: return 29; +case 72: return 37; break; -case 73: return 24; +case 73: return 29; break; -case 74: return 102; +case 74: return 24; break; -case 75: return 5; +case 75: return 102; break; -case 76: console.log("INVALID: " + yy_.yytext); return 'INVALID' +case 76: return 5; +break; +case 77: console.log("INVALID: " + yy_.yytext); return 'INVALID' break; } }, -rules: [/^(?:\s+)/,/^(?:\/\*([^*]|[\r\n]|(\*+([^*\/]|[\r\n])))*\*+\/)/,/^(?:\/\/.*)/,/^(?:var\b)/,/^(?:signal\b)/,/^(?:private\b)/,/^(?:input\b)/,/^(?:output\b)/,/^(?:linearCombination\b)/,/^(?:component\b)/,/^(?:template\b)/,/^(?:function\b)/,/^(?:if\b)/,/^(?:else\b)/,/^(?:for\b)/,/^(?:while\b)/,/^(?:compute\b)/,/^(?:do\b)/,/^(?:return\b)/,/^(?:include\b)/,/^(?:0x[0-9A-Fa-f]*)/,/^(?:[0-9]+)/,/^(?:[a-zA-Z][a-zA-Z$_0-9]*)/,/^(?:"[^"]+")/,/^(?:==>)/,/^(?:<==)/,/^(?:-->)/,/^(?:<--)/,/^(?:===)/,/^(?:>>=)/,/^(?:<<=)/,/^(?:&&)/,/^(?:\|\|)/,/^(?:==)/,/^(?:<=)/,/^(?:>=)/,/^(?:!=)/,/^(?:>>)/,/^(?:<<)/,/^(?:\*\*)/,/^(?:\+\+)/,/^(?:--)/,/^(?:\+=)/,/^(?:-=)/,/^(?:\*=)/,/^(?:\/=)/,/^(?:%=)/,/^(?:\|=)/,/^(?:&=)/,/^(?:\^=)/,/^(?:=)/,/^(?:\+)/,/^(?:-)/,/^(?:\*)/,/^(?:\/)/,/^(?:\\)/,/^(?:%)/,/^(?:\^)/,/^(?:&)/,/^(?:\|)/,/^(?:!)/,/^(?:<)/,/^(?:>)/,/^(?:!)/,/^(?:\?)/,/^(?::)/,/^(?:\()/,/^(?:\))/,/^(?:\[)/,/^(?:\])/,/^(?:\{)/,/^(?:\})/,/^(?:;)/,/^(?:,)/,/^(?:\.)/,/^(?:$)/,/^(?:.)/], -conditions: {"INITIAL":{"rules":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76],"inclusive":true}} +rules: [/^(?:\s+)/,/^(?:\/\*([^*]|[\r\n]|(\*+([^*\/]|[\r\n])))*\*+\/)/,/^(?:\/\/.*)/,/^(?:var\b)/,/^(?:signal\b)/,/^(?:private\b)/,/^(?:input\b)/,/^(?:output\b)/,/^(?:linearCombination\b)/,/^(?:component\b)/,/^(?:template\b)/,/^(?:function\b)/,/^(?:if\b)/,/^(?:else\b)/,/^(?:for\b)/,/^(?:while\b)/,/^(?:compute\b)/,/^(?:do\b)/,/^(?:return\b)/,/^(?:include\b)/,/^(?:0x[0-9A-Fa-f]*)/,/^(?:[0-9]+)/,/^(?:[a-zA-Z][a-zA-Z$_0-9]*)/,/^(?:"[^"]+")/,/^(?:==>)/,/^(?:<==)/,/^(?:-->)/,/^(?:<--)/,/^(?:===)/,/^(?:>>=)/,/^(?:<<=)/,/^(?:&&)/,/^(?:\|\|)/,/^(?:==)/,/^(?:<=)/,/^(?:>=)/,/^(?:!=)/,/^(?:>>)/,/^(?:<<)/,/^(?:\*\*)/,/^(?:\+\+)/,/^(?:--)/,/^(?:\+=)/,/^(?:-=)/,/^(?:\*=)/,/^(?:\/=)/,/^(?:%=)/,/^(?:\|=)/,/^(?:&=)/,/^(?:\^=)/,/^(?:=)/,/^(?:\+)/,/^(?:-)/,/^(?:\*)/,/^(?:\/)/,/^(?:\\)/,/^(?:%)/,/^(?:\^)/,/^(?:&)/,/^(?:\|)/,/^(?:!)/,/^(?:~)/,/^(?:<)/,/^(?:>)/,/^(?:!)/,/^(?:\?)/,/^(?::)/,/^(?:\()/,/^(?:\))/,/^(?:\[)/,/^(?:\])/,/^(?:\{)/,/^(?:\})/,/^(?:;)/,/^(?:,)/,/^(?:\.)/,/^(?:$)/,/^(?:.)/], +conditions: {"INITIAL":{"rules":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77],"inclusive":true}} }); return lexer; })(); diff --git a/src/c_gen.js b/src/c_gen.js index b62e3ad..67a2755 100644 --- a/src/c_gen.js +++ b/src/c_gen.js @@ -154,15 +154,15 @@ function gen(ctx, ast) { } else if (ast.op == "*=") { return genVarMulAssignement(ctx, ast); } else if (ast.op == "+") { - return genBinaryOp(ctx, ast, "add"); + return genOp(ctx, ast, "add", 2); } else if (ast.op == "-") { - return genBinaryOp(ctx, ast, "sub"); + return genOp(ctx, ast, "sub", 2); } else if (ast.op == "UMINUS") { - return genUMinus(ctx, ast); + return genOp(ctx, ast, "neg", 1); } else if (ast.op == "*") { - return genBinaryOp(ctx, ast, "mul"); + return genOp(ctx, ast, "mul", 2); } else if (ast.op == "%") { - return genBinaryOp(ctx, ast, "mod"); + return genOp(ctx, ast, "mod", 2); } else if (ast.op == "PLUSPLUSRIGHT") { return genOpOp(ctx, ast, "add", "RIGHT"); } else if (ast.op == "PLUSPLUSLEFT") { @@ -172,33 +172,41 @@ function gen(ctx, ast) { } else if (ast.op == "MINUSMINUSLEFT") { return genOpOp(ctx, ast, "sub", "LEFT"); } else if (ast.op == "**") { - return genExp(ctx, ast); + return genOp(ctx, ast, "pow", 2); } else if (ast.op == "/") { - return genBinaryOp(ctx, ast, "div"); + return genOp(ctx, ast, "div", 2); } else if (ast.op == "\\") { - return genBinaryOp(ctx, ast, "idiv"); + return genOp(ctx, ast, "idiv", 2); } else if (ast.op == "&") { - return genBAnd(ctx, ast); + return genOp(ctx, ast, "band", 2); + } else if (ast.op == "|") { + return genOp(ctx, ast, "bor", 2); + } else if (ast.op == "^") { + return genOp(ctx, ast, "bxor", 2); + } else if (ast.op == "~") { + return genOp(ctx, ast, "bnot", 1); } else if (ast.op == "&&") { - return genAnd(ctx, ast); + return genOp(ctx, ast, "land", 2); } else if (ast.op == "||") { - return genOr(ctx, ast); + return genOp(ctx, ast, "lor", 2); + } else if (ast.op == "!") { + return genOp(ctx, ast, "lnot", 1); } else if (ast.op == "<<") { - return genShl(ctx, ast); + return genOp(ctx, ast, "shl", 2); } else if (ast.op == ">>") { - return genShr(ctx, ast); + return genOp(ctx, ast, "shr", 2); } else if (ast.op == "<") { - return genBinaryOp(ctx, ast, "lt"); + return genOp(ctx, ast, "lt", 2); } else if (ast.op == ">") { - return genBinaryOp(ctx, ast, "gt"); + return genOp(ctx, ast, "gt", 2); } else if (ast.op == "<=") { - return genBinaryOp(ctx, ast, "leq"); + return genOp(ctx, ast, "leq", 2); } else if (ast.op == ">=") { - return genBinaryOp(ctx, ast, "geq"); + return genOp(ctx, ast, "geq", 2); } else if (ast.op == "==") { - return genBinaryOp(ctx, ast, "eq"); + return genOp(ctx, ast, "eq", 2); } else if (ast.op == "!=") { - return genBinaryOp(ctx, ast, "neq"); + return genOp(ctx, ast, "neq", 2); } else if (ast.op == "?") { return genTerCon(ctx, ast); } else { @@ -1037,76 +1045,56 @@ function genOpOp(ctx, ast, op, lr) { } } -function genBinaryOp(ctx, ast, op) { - let aRef = gen(ctx, ast.values[0]); - if (ctx.error) return; - let a = ctx.refs[aRef]; +function genOp(ctx, ast, op, nOps) { + const vals = []; + const valRefs = []; - let bRef = gen(ctx, ast.values[1]); - if (ctx.error) return; - let b = ctx.refs[bRef]; + var anyUsed=false; + + for (let i=0; ifield->${op}(${r.label},${a.label}, ${b.label});\n`; + let c = `ctx->field->${op}(${r.label}`; + for (let i=0; i>") { @@ -854,7 +862,6 @@ function execNeq(ctx, ast) { }; } - function execBAnd(ctx, ast) { const a = exec(ctx, ast.values[0]); if (ctx.error) return; @@ -869,6 +876,51 @@ function execBAnd(ctx, ast) { }; } +function execBOr(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.or(b.value).and(__MASK__) + }; +} + +function execBXor(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.xor(b.value).and(__MASK__) + }; +} + +function execBNot(ctx, ast) { + const a = exec(ctx, ast.values[0]); + if (ctx.error) return; + if (a.type != "NUMBER") return { type: "NUMBER" }; + if (!a.value) return { type: "NUMBER" }; + + const res = lc.negate(a); + if (res.type == "ERROR") return error(ctx, ast, res.errStr); + + return { + type: "NUMBER", + value: a.value.xor(__MASK__).and(__MASK__) + }; +} + + + function execAnd(ctx, ast) { const a = exec(ctx, ast.values[0]); if (ctx.error) return; @@ -897,6 +949,18 @@ function execOr(ctx, ast) { }; } +function execLNot(ctx, ast) { + const a = exec(ctx, ast.values[0]); + if (ctx.error) return; + if (a.type != "NUMBER") return { type: "NUMBER" }; + if (!a.value) return { type: "NUMBER" }; + return { + type: "NUMBER", + value: (a.value.eq(0)) ? bigInt(1) : bigInt(0) + }; +} + + function execShl(ctx, ast) { const a = exec(ctx, ast.values[0]); if (ctx.error) return; diff --git a/src/zqfield.js b/src/zqfield.js index 9100791..86f64c1 100644 --- a/src/zqfield.js +++ b/src/zqfield.js @@ -1,16 +1,32 @@ const bigInt = require("big-integer"); +const assert = require("assert"); module.exports = class ZqField { constructor(p) { this.p = p; + this.bitLength = p.bitLength(); + this.mask = bigInt.one.shiftLeft(this.bitLength - 1).minus(bigInt.one); } add(a, b) { - return a.add(b).mod(this.p); + let res = a.add(b); + if (res.geq(this.p)) { + res = res.minsu(this.p); + } + return res; } sub(a, b) { - return a.minus(b).mod(this.p); + if (a.geq(b)) { + return a.minus(b); + } else { + return this.p.minus(b.minus(a)); + } + } + + neg(a) { + if (a.isZero()) return a; + return this.p.minus(a); } mul(a, b) { @@ -46,6 +62,7 @@ module.exports = class ZqField { } idiv(a, b) { + assert(!b.isZero(), "Division by zero"); return a.divide(b); } @@ -53,5 +70,46 @@ module.exports = class ZqField { return a.mod(b); } + pow(a, b) { + return a.modPow(b, this.p); + } + + band(a, b) { + return a.and(b).and(this.mask); + } + + bor(a, b) { + return a.or(b).and(this.mask); + } + + bxor(a, b) { + return a.xor(b).and(this.mask); + } + + bnot(a) { + return a.xor(this.mask).and(this.mask); + } + + shl(a, b) { + if (b.geq(this.bitLength)) return bigInt.zero; + return a.shiftLeft(b).and(this.mask); + } + + shr(a, b) { + if (b.geq(this.bitLength)) return bigInt.zero; + return a.shiftRight(b).and(this.mask); + } + + land(a, b) { + return (a.isZero() || b.isZero) ? bigInt.zero : bigInt.one; + } + + lor(a, b) { + return (a.isZero() && b.isZero) ? bigInt.zero : bigInt.one; + } + + lnot(a) { + return a.isZero() ? bigInt.one : bigInt.zero; + } }; diff --git a/test/basiccases.js b/test/basiccases.js index 0d652db..b79de94 100644 --- a/test/basiccases.js +++ b/test/basiccases.js @@ -202,4 +202,48 @@ describe("basic cases", function () { ] ); }); + it("ops3", async () => { + await doTest( + "ops3.circom", + [ + [{in: [-2, 2]}, {neg1: 2,neg2: -2, pow: 4}], + [{in: [0, 1]}, {neg1: 0, neg2: -1, pow: 0}], + [{in: [ 1,-1]}, {neg1: -1, neg2: 1, pow: 1}], + ] + ); + }); + it("Comparation ops", async () => { + await doTest( + "opscmp.circom", + [ + [{in: [ 8, 9]}, {lt: 1, leq: 1, eq:0, neq:1, geq: 0, gt:0}], + [{in: [-2,-2]}, {lt: 0, leq: 1, eq:1, neq:0, geq: 1, gt:0}], + [{in: [-1,-2]}, {lt: 0, leq: 0, eq:0, neq:1, geq: 1, gt:1}], + [{in: [ 1,-1]}, {lt: 1, leq: 1, eq:0, neq:1, geq: 0, gt:0}], // In mod, negative values are higher than positive. + ] + ); + }); + it("Bit ops", async () => { + const mask = bigInt("14474011154664524427946373126085988481658748083205070504932198000989141204991"); + const m1m = bigInt("7414231717174750794300032619171286606889616317210963838766006185586667290624"); + await doTest( + "opsbit.circom", + [ + [{in: [ 5, 3]}, {and: 1, or: 7, xor:6, not1:mask.minus(5), shl: 40, shr:0}], + [{in: [ 0, 0]}, {and: 0, or: 0, xor:0, not1:mask, shl: 0, shr:0}], + [{in: [-1, 1]}, {and: 0, or: m1m.add(bigInt.one), xor:m1m.add(bigInt.one), not1:mask.minus(m1m), shl: m1m.shiftLeft(1).and(mask), shr:__P__.shiftRight(1).and(mask)}], + ] + ); + }); + it("Logical ops", async () => { + await doTest( + "opslog.circom", + [ + [{in: [ 5, 0]}, {and: 0, or: 1, not1:0}], + [{in: [ 0, 1]}, {and: 0, or: 1, not1:1}], + [{in: [-1, 9]}, {and: 1, or: 1, not1:0}], + [{in: [ 0, 0]}, {and: 0, or: 0, not1:1}], + ] + ); + }); }); diff --git a/test/circuits/ops3.circom b/test/circuits/ops3.circom new file mode 100644 index 0000000..9b1b29e --- /dev/null +++ b/test/circuits/ops3.circom @@ -0,0 +1,12 @@ +template Ops3() { + signal input in[2]; + signal output neg1; + signal output neg2; + signal output pow; + + neg1 <-- -in[0]; + neg2 <-- -in[1]; + pow <-- in[0] ** in[1]; +} + +component main = Ops3(); diff --git a/test/circuits/opsbit.circom b/test/circuits/opsbit.circom new file mode 100644 index 0000000..190a287 --- /dev/null +++ b/test/circuits/opsbit.circom @@ -0,0 +1,18 @@ +template OpsBit() { + signal input in[2]; + signal output and; + signal output or; + signal output xor; + signal output not1; + signal output shl; + signal output shr; + + and <-- in[0] & in[1]; + or <-- in[0] | in[1]; + xor <-- in[0] ^ in[1]; + not1 <-- ~in[0]; + shl <-- in[0] << in[1]; + shr <-- in[0] >> in[1]; +} + +component main = OpsBit(); diff --git a/test/circuits/opscmp.circom b/test/circuits/opscmp.circom new file mode 100644 index 0000000..861cc40 --- /dev/null +++ b/test/circuits/opscmp.circom @@ -0,0 +1,18 @@ +template OpsCmp() { + signal input in[2]; + signal output lt; + signal output leq; + signal output eq; + signal output neq; + signal output geq; + signal output gt; + + lt <-- in[0] < in[1]; + leq <-- in[0] <= in[1]; + eq <-- in[0] == in[1]; + neq <-- in[0] != in[1]; + geq <-- in[0] >= in[1]; + gt <-- in[0] > in[1]; +} + +component main = OpsCmp(); diff --git a/test/circuits/opslog.circom b/test/circuits/opslog.circom new file mode 100644 index 0000000..36291ff --- /dev/null +++ b/test/circuits/opslog.circom @@ -0,0 +1,12 @@ +template OpsLog() { + signal input in[2]; + signal output and; + signal output or; + signal output not1; + + and <-- in[0] && in[1]; + or <-- in[0] || in[1]; + not1 <-- !in[0]; +} + +component main = OpsLog();