All Bit and logical operators working
@@ -5,6 +5,10 @@ mpz_init2(tmp, 1024);
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 @@ mpz_sub(*r, p, tmp);
} } +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);@@ -47,6 +59,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) {@@ -100,6 +116,30 @@ if (c!=0) {
mpz_set(*r, one); } else { mpz_set(*r, zero); + } +} + +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); } }@@ -110,3 +150,42 @@
void ZqField::copyn(PBigInt a, PBigInt b, int n) { for (int i=0;i<n; i++) mpz_set(a[i], b[i]); } + +void ZqField::band(PBigInt r, PBigInt a, PBigInt b) { + mpz_and(*r, *a, *b); + mpz_and(*r, *r, mask); +} + +void ZqField::bor(PBigInt r, PBigInt a, PBigInt b) { + mpz_ior(*r, *a, *b); + mpz_and(*r, *r, mask); +} + +void ZqField::bxor(PBigInt r, PBigInt a, PBigInt b) { + mpz_xor(*r, *a, *b); + mpz_and(*r, *r, mask); +} + +void ZqField::bnot(PBigInt r, PBigInt a) { + mpz_xor(*r, *a, mask); + mpz_and(*r, *r, mask); +} + +void ZqField::shl(PBigInt r, PBigInt a, PBigInt b) { + if (mpz_cmp_ui(*b, nBits) >= 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); + } +} +
@@ -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); };
@@ -85,6 +85,7 @@ \^ { return '^'; }
\& { return '&'; } \| { return '|'; } \! { return '!'; } +\~ { return '~'; } \< { return '<'; } \> { return '>'; } \! { return '!'; }
@@ -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 24; break; -case 74: return 102; +case 75: return 102; break; -case 75: return 5; +case 76: return 5; break; -case 76: console.log("INVALID: " + yy_.yytext); return 'INVALID' +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; })();
@@ -154,15 +154,15 @@ return genVarAddAssignement(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 @@ return genOpOp(ctx, ast, "sub", "RIGHT");
} 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 @@ return resRef;
} } -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 = []; + + var anyUsed=false; + + for (let i=0; i<nOps; i++) { + const ref = gen(ctx, ast.values[i]); + if (ctx.error) return; + let v = ctx.refs[ref]; + valRefs.push(ref); + vals.push(v); - let bRef = gen(ctx, ast.values[1]); - if (ctx.error) return; - let b = ctx.refs[bRef]; + if (!utils.sameSizes(v.sizes, [1,0])) return ctx.throwError(ast, "Operation cannot be done on an array"); + if ( (!v.used) + &&( (!utils.isDefined(v.value)) + ||(!utils.isDefined(v.value[0])))) + return ctx.throwError(ast, "Using a not assigned varialble: "); - if ((!a.used)&&(!utils.isDefined(a.value))) return ctx.throwError(ast, "Using a not assigned varialble: "); - if ((!b.used)&&(!utils.isDefined(b.value))) return ctx.throwError(ast, "Using a not assigned varialble: "); - if (!utils.sameSizes(a.sizes, [1,0])) return ctx.throwError(ast, "Operation cannot be done on an array"); - if (!utils.sameSizes(b.sizes, [1,0])) return ctx.throwError(ast, "Operation cannot be done on an array"); + if (v.used) anyUsed=true; + } let rRef; - if (a.used || b.used) { - if (!a.used) { - aRef = instantiateConstant(ctx, a.value); - a = ctx.refs[aRef]; - } - if (!b.used) { - bRef = instantiateConstant(ctx, b.value); - b = ctx.refs[bRef]; + if (anyUsed) { + for (let i=0; i<nOps; i++) { + if (!vals[i].used) { + valRefs[i] = instantiateConstant(ctx, vals[i].value); + vals[i] = ctx.refs[valRefs[i]]; + } } rRef = newRef(ctx, "BIGINT", "_tmp"); instantiateRef(ctx, rRef); const r = ctx.refs[rRef]; - ctx.code += `ctx->field->${op}(${r.label},${a.label}, ${b.label});\n`; + let c = `ctx->field->${op}(${r.label}`; + for (let i=0; i<nOps; i++) { + c+=`,${vals[i].label}`; + } + c += ");\n"; + ctx.code += c; } else { - rRef = newRef(ctx, "BIGINT", "_tmp", ctx.field[op](a.value[0], b.value[0])); + const params = []; + for (let i=0; i<nOps; i++) { + params.push(vals[i].value[0]); + } + rRef = newRef(ctx, "BIGINT", "_tmp", ctx.field[op](...params)); } return rRef; } - -function genSub(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}).add(__P__).sub(bigInt(${b})).mod(__P__)`; -} - -function genDiv(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}).mul( bigInt(${b}).inverse(__P__) ).mod(__P__)`; -} - -function genIDiv(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}).div( bigInt(${b}))`; -} - -function genExp(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}).modPow(bigInt(${b}), __P__)`; -} - function genBAnd(ctx, ast) { const a = gen(ctx, ast.values[0]); if (ctx.error) return;@@ -1145,20 +1133,6 @@ if (ctx.error) return;
const b = gen(ctx, ast.values[1]); if (ctx.error) return; return `bigInt(${b}).greater(bigInt(256)) ? 0 : bigInt(${a}).shr(bigInt(${b})).and(__MASK__)`; -} - -function genMod(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}).mod(bigInt(${b}))`; -} - -function genUMinus(ctx, ast) { - const a = gen(ctx, ast.values[0]); - if (ctx.error) return; - return `__P__.sub(bigInt(${a})).mod(__P__)`; } function genTerCon(ctx, ast) {
@@ -92,10 +92,18 @@ } else if (ast.op == "**") {
return execExp(ctx, ast); } else if (ast.op == "&") { return execBAnd(ctx, ast); + } else if (ast.op == "|") { + return execBOr(ctx, ast); + } else if (ast.op == "^") { + return execBXor(ctx, ast); + } else if (ast.op == "~") { + return execBNot(ctx, ast); } else if (ast.op == "&&") { return execAnd(ctx, ast); } else if (ast.op == "||") { return execOr(ctx, ast); + } else if (ast.op == "!") { + return execLNot(ctx, ast); } else if (ast.op == "<<") { return execShl(ctx, ast); } else if (ast.op == ">>") {@@ -854,7 +862,6 @@ value: a.value.eq(b.value) ? bigInt(0) : bigInt(1)
}; } - function execBAnd(ctx, ast) { const a = exec(ctx, ast.values[0]); if (ctx.error) return;@@ -869,6 +876,51 @@ value: a.value.and(b.value).and(__MASK__)
}; } +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;@@ -896,6 +948,18 @@ type: "NUMBER",
value: (a.value.neq(0) || b.value.neq(0)) ? bigInt(1) : bigInt(0) }; } + +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]);
@@ -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 @@ return a.mul(b.modInv(this.p)).mod(this.p);
} idiv(a, b) { + assert(!b.isZero(), "Division by zero"); return a.divide(b); }@@ -53,5 +70,46 @@ mod(a, b) {
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; + } };
@@ -202,4 +202,48 @@ [{in: [ 1,-1]}, {div: -1, idiv: 0, mod: 1}],
] ); }); + 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}], + ] + ); + }); });
@@ -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();
@@ -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();
@@ -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();
@@ -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();