arnaucube
arnaucube/circomPublic Self-hosted repository
for loops
Jordi Baylina jordi@baylina.cat
Thu, 28 Nov 2019 15:10:59 +0100
commit

93330f065b5cd4d8548cc37af4c4078a7f8d92a6

parent

66291a0efe01e4b95fb1bc7c35a23b0bf6437c18

M .gitignore → .gitignore

@@ -61,3 +61,6 @@ # next.js build output

.next tmp + +.DS_Store +
A Project.sublime-project

@@ -0,0 +1,24 @@

+ { + "folders": [ + { + "path": ".", + } + ], + "settings": { + "SublimeAnarchyDebug": { + "debug": { + "executable": "${project_path}/test/circuits/add", + "params": [ + "addin.json", + "out.bin", + ], + "path": [ + ], + "environment": [ + ], + "working_dir": "${project_path}" + } + } + } + } +
A Project.sublime-workspace

@@ -0,0 +1,878 @@

+{ + "auto_complete": + { + "selected_items": + [ + [ + "ins", + "instantiateConstant" + ], + [ + "c", + "circuit" + ], + [ + "type", + "typeof" + ], + [ + "b", + "bName" + ], + [ + "e", + "eOut" + ], + [ + "sym", + "symbols" + ], + [ + "res", + "resStr" + ], + [ + "base", + "baseName" + ], + [ + "a", + "async" + ], + [ + "out", + "outFile" + ], + [ + "addS", + "addSymbolArray" + ], + [ + "of", + "offset" + ], + [ + "si", + "signal" + ], + [ + "s", + "signals" + ], + [ + "dir", + "dirName" + ], + [ + "main", + "mainComponent" + ], + [ + "ci", + "circomFile" + ], + [ + "pc", + "pcV1" + ], + [ + "re", + "require" + ], + [ + "buildC", + "buildCircuit" + ], + [ + "Ti", + "Ticker" + ], + [ + "Ma", + "MaxBandwith" + ], + [ + "Bl", + "BlackList" + ], + [ + "Max", + "MaxConnections" + ], + [ + "uint", + "uint64" + ], + [ + "he", + "helloLen" + ], + [ + "Pr", + "Printf" + ], + [ + "n", + "nil" + ], + [ + "ne", + "newBuff" + ], + [ + "new", + "newBuff" + ], + [ + "H", + "HiddenDomain" + ], + [ + "Hidden", + "hiddenDomain" + ], + [ + "ex", + "extensionLen" + ], + [ + "sess", + "sessionLen" + ], + [ + "ses", + "sessionId" + ], + [ + "exte", + "extensionLen" + ], + [ + "se", + "sessionLen" + ], + [ + "by", + "byte" + ], + [ + "clie", + "clientKS" + ], + [ + "de", + "decrypter" + ], + [ + "buf", + "buftype" + ], + [ + "set", + "setSignal" + ], + [ + "ha", + "handle_error" + ], + [ + "in", + "infilename" + ], + [ + "wri", + "writeOut" + ], + [ + "str", + "string" + ], + [ + "it", + "itFunc" + ], + [ + "iter", + "iterateArr" + ], + [ + "idx", + "idxInput" + ], + [ + "NS", + "NSignals" + ], + [ + "en", + "entryPos" + ], + [ + "h", + "hIdx" + ], + [ + "nS", + "NSignals" + ], + [ + "inc", + "include" + ], + [ + "bui", + "buildOutArray" + ], + [ + "N", + "NVars" + ], + [ + "pC", + "pCurrent" + ], + [ + "acc", + "account2" + ], + [ + "tim", + "timestamp" + ], + [ + "not", + "notAvTxs" + ], + [ + "con", + "continue" + ], + [ + "on", + "onChainTxs" + ], + [ + "ge", + "getOperatorFee" + ], + [ + "use", + "userFee" + ], + [ + "no", + "normalizedFee" + ], + [ + "fi", + "firstNonce" + ], + [ + "am", + "amountF" + ], + [ + "cal", + "calcSlots" + ], + [ + "tx", + "txPool" + ], + [ + "non", + "nonExecutableSlots" + ], + [ + "max", + "maxSlots" + ], + [ + "slo", + "slotKeys" + ], + [ + "Tx", + "TXPool" + ], + [ + "cla", + "_classifyTxs" + ], + [ + "remo", + "removed" + ], + [ + "u", + "updateSlotsPending" + ], + [ + "txs", + "txsByCoin" + ], + [ + "forged", + "forgedTxs" + ], + [ + "removed", + "removedCoins" + ], + [ + "bestN", + "bestNTx" + ], + [ + "av", + "avTxs" + ], + [ + "ad", + "adjustedFee" + ], + [ + "M", + "MaxCoins" + ], + [ + "norm", + "normalizedFee" + ], + [ + "us", + "userFeeF" + ], + [ + "from", + "idxFrom" + ], + [ + "eq", + "equal" + ], + [ + "fee", + "feePlanCoins" + ], + [ + "as", + "async" + ], + [ + "ke", + "key" + ], + [ + "pro", + "promises" + ], + [ + "DB", + "DB_Master" + ], + [ + "va", + "value" + ], + [ + "add", + "addSizes" + ], + [ + "labe", + "labelSize" + ], + [ + "las", + "last_column" + ], + [ + "stat", + "statements" + ], + [ + "firs", + "first_column" + ], + [ + "f", + "first_line" + ], + [ + "tmp", + "tmpNames" + ], + [ + "su", + "suggestedName" + ], + [ + "fn", + "fnvHash" + ], + [ + "def", + "definedHashTables" + ], + [ + "le", + "length" + ], + [ + "la", + "labelName" + ], + [ + "size", + "sizes" + ], + [ + "code", + "codeFooter" + ], + [ + "sc", + "scopes" + ], + [ + "rN", + "rName" + ], + [ + "genGet", + "genGetSignal" + ], + [ + "label", + "labelName" + ], + [ + "instan", + "instantiateRef" + ], + [ + "v", + "vOffset" + ], + [ + "BIGIN", + "BIGINT" + ], + [ + "st", + "stack" + ], + [ + "SI", + "SIZES" + ], + [ + "newS", + "newStackVar" + ], + [ + "sco", + "scopes" + ], + [ + "cons", + "constant" + ], + [ + "val", + "value" + ], + [ + "com", + "components" + ], + [ + "calc", + "calcAcc" + ], + [ + "ca", + "calcStr" + ], + [ + "to", + "toJSNumber" + ], + [ + "get", + "getTmpName" + ], + [ + "cS", + "cSourceDone" + ], + [ + "r1", + "r1csDone" + ], + [ + "B", + "Buffer" + ] + ] + }, + "buffers": + [ + ], + "build_system": "", + "build_system_choices": + [ + ], + "build_varint": "", + "command_palette": + { + "height": 0.0, + "last_filter": "", + "selected_items": + [ + [ + "in", + "Package Control: Install Package" + ], + [ + "ins", + "Package Control: Install Package" + ], + [ + "", + "Arithmetic" + ], + [ + "Package Control: ", + "Package Control: Disable Package" + ], + [ + "install", + "Package Control: Install Package" + ] + ], + "width": 0.0 + }, + "console": + { + "height": 210.0, + "history": + [ + ] + }, + "distraction_free": + { + "menu_visible": true, + "show_minimap": false, + "show_open_files": false, + "show_tabs": false, + "side_bar_visible": false, + "status_bar_visible": false + }, + "file_history": + [ + "/Users/jbaylina/git/iden3/circom/cli.js", + "/Users/jbaylina/git/iden3/circom/src/c_build.js", + "/Users/jbaylina/git/iden3/circom/src/c_gen.js", + "/Users/jbaylina/git/iden3/circom/test/circuits/add.circom", + "/Users/jbaylina/git/iden3/circom/src/c_tester.js", + "/Users/jbaylina/git/iden3/circom/test/basiccases.js", + "/Users/jbaylina/git/iden3/circom/test/inout.js", + "/Users/jbaylina/git/iden3/circom/c/main.cpp", + "/Users/jbaylina/git/iden3/circom/src/utils.js", + "/Users/jbaylina/git/iden3/circom/src/zqfield.js", + "/Users/jbaylina/git/iden3/circom/src/compiler.js", + "/Users/jbaylina/git/iden3/circom/c/calcwit.h", + "/Users/jbaylina/git/iden3/circom/c/zqfield.cpp", + "/Users/jbaylina/git/iden3/circom/c/circom.h", + "/Users/jbaylina/git/iden3/circom/test/circuits/add.cpp", + "/Users/jbaylina/git/iden3/circom/c/zqfield.h", + "/Users/jbaylina/git/iden3/circom/c/calcwit.cpp", + "/Users/jbaylina/git/iden3/circom/src/ctx.js", + "/Users/jbaylina/git/iden3/circom/index.js", + "/Users/jbaylina/git/iden3/circom/test/circuits/inout.cpp", + "/Users/jbaylina/git/iden3/circom/src/tester.js", + "/Users/jbaylina/git/iden3/rollup/doc/rollup_tx.txt", + "/Users/jbaylina/git/personal/tls-tris/_dev/GOROOT/darwin_amd64/src/crypto/tls/conn.go", + "/Users/jbaylina/git/personal/tls-tris/_dev/GOROOT/darwin_amd64/src/crypto/tls/handshake_client.go", + "/Users/jbaylina/git/personal/tls-tris/_dev/GOROOT/darwin_amd64/src/crypto/tls/alert.go", + "/Users/jbaylina/git/personal/tls-tris/13.go", + "/Users/jbaylina/git/personal/tls-tris/tls_test.go", + "/Users/jbaylina/git/personal/tls-tris/conn.go", + "/Users/jbaylina/git/personal/tls-tris/_dev/GOROOT/darwin_amd64/src/crypto/x509/verify.go", + "/Users/jbaylina/git/personal/tls-tris/handshake_client.go", + "/Users/jbaylina/git/personal/testimg/dosfilter.go", + "/Users/jbaylina/git/personal/testimg/main.go", + "/Users/jbaylina/git/personal/hiddenproxy/hiddenproxy/main.go", + "/Users/jbaylina/git/personal/tls-tris/cipher_suites.go", + "/Users/jbaylina/git/personal/hiddenproxy.old/proxy.go", + "/Users/jbaylina/git/personal/hiddenproxy/hiddenproxy/proxy.go", + "/Users/jbaylina/git/personal/hiddenproxy/client-test/client-test", + "/Users/jbaylina/git/personal/hiddenproxy/client-test/main.go", + "/Users/jbaylina/git/personal/tls-tris/key_agreement.go", + "/Users/jbaylina/git/personal/tls-tris/common.go", + "/Users/jbaylina/git/personal/testesni/testesni.go", + "/Users/jbaylina/git/personal/hiddenproxy/main.go", + "/Users/jbaylina/git/personal/testesni2/testesni2.go", + "/Users/jbaylina/git/personal/hiddenproxy/proxy.go", + "/Users/jbaylina/git/personal/hiddenproxy/testenc/main.go", + "/Users/jbaylina/git/personal/tls-tris/_dev/GOROOT/darwin_amd64/src/crypto/blake2b/blake2b_amd64.go", + "/Users/jbaylina/git/personal/tls-tris/_dev/GOROOT/darwin_amd64/src/crypto/blake2b/blake2b.go", + "/Users/jbaylina/git/personal/tls-tris/esni.go", + "/Users/jbaylina/git/personal/tls-tris/_dev/tris-testclient/esni_query.go", + "/Users/jbaylina/git/personal/tls-tris/_dev/tris-testclient/client.go", + "/Users/jbaylina/git/personal/tls-tris/_dev/tris-localserver/server.go", + "/Users/jbaylina/git/personal/tls-tris/_dev/GOROOT/darwin_amd64/src/crypto/tls/esni.go", + "/Users/jbaylina/git/personal/tls-tris/_dev/GOROOT/darwin_amd64/src/crypto/tls/common.go", + "/Users/jbaylina/git/iden3/circom/src/exec.js", + "/Users/jbaylina/git/personal/tls-tris/_dev/GOROOT/darwin_amd64/src/net/tcpsock_plan9.go", + "/Users/jbaylina/git/personal/tls-tris/tls.go", + "/Users/jbaylina/git/personal/tls-tris/hiddenproxy.go", + "/Users/jbaylina/git/personal/tls-tris/_dev/GOROOT/darwin_amd64/src/net/tcpsock.go", + "/Users/jbaylina/git/personal/tls-tris/_dev/GOROOT/darwin_amd64/src/net/tcpsock_posix.go", + "/Users/jbaylina/git/personal/tls-tris/_dev/GOROOT/darwin_amd64/src/net/ipsock_plan9.go", + "/Users/jbaylina/git/iden3/circom/src/gen_c.js", + "/Users/jbaylina/git/iden3/circom/test/circuits/inout.circom", + "/Users/jbaylina/git/iden3/circom/c/utils.cpp", + "/Users/jbaylina/git/iden3/circom/c/utils.h", + "/Users/jbaylina/git/iden3/circom/c/mainjson.cpp", + "/Users/jbaylina/git/iden3/circom/c/mainjson", + "/Users/jbaylina/git/iden3/circom/doc/r1cs_bin_format.md", + "/Users/jbaylina/git/iden3/circom/c/circom.cpp", + "/Users/jbaylina/git/iden3/circomlib/src/eddsa.js", + "/Users/jbaylina/git/iden3/rollup/js/utils.js", + "/Users/jbaylina/git/iden3/rollup/js/rollupaccount.js", + "/Users/jbaylina/git/iden3/rollup/js/txpool.js", + "/Users/jbaylina/git/iden3/rollup/test/txpool.js", + "/Users/jbaylina/git/iden3/rollup/js/tmpstate.js", + "/Users/jbaylina/git/iden3/rollup/js/rollupdb.js", + "/Users/jbaylina/git/iden3/rollup/circuits/balancesupdater.circom", + "/Users/jbaylina/git/iden3/rollup/test/feeselector.js", + "/Users/jbaylina/git/iden3/rollup/test/circuits/rollup_test.circom", + "/Users/jbaylina/git/iden3/rollup/js/batchbuilder.js", + "/Users/jbaylina/git/iden3/rollup/test/rollup_circuit.js", + "/Users/jbaylina/git/iden3/rollup/circuits/rollup.circom", + "/Users/jbaylina/git/iden3/rollup/circuits/rolluptx.circom", + "/Users/jbaylina/git/iden3/rollup/circuits/feeselector.circom", + "/Users/jbaylina/git/iden3/rollup/circuits/feeplandecoder.circom", + "/Users/jbaylina/git/iden3/rollup/test.txt", + "/Users/jbaylina/git/iden3/rollup/package.json", + "/Users/jbaylina/git/iden3/rollup/circuits/rolluptxstates.circom", + "/Users/jbaylina/git/iden3/rollup/js/constants.js", + "/Users/jbaylina/git/iden3/rollup/.gitignore", + "/Users/jbaylina/git/iden3/rollup/test/helpers/checkbatch.js", + "/Users/jbaylina/git/iden3/circomlib/package.json", + "/Users/jbaylina/git/iden3/snarkjs/src/bn128.js", + "/Users/jbaylina/git/iden3/circomlib/test/smtverifier.js", + "/Users/jbaylina/git/iden3/circomlib/test/smtverifier_adria.js", + "/Users/jbaylina/git/iden3/circomlib/src/smt_memdb.js", + "/Users/jbaylina/git/iden3/rollup/js/smttmpdb.js", + "/Users/jbaylina/git/iden3/rollup/js/blockbuilder.js", + "/Users/jbaylina/git/iden3/circom/src/buildc.js", + "/Users/jbaylina/git/iden3/circom/package.json", + "/Users/jbaylina/git/iden3/circom/test/cases.js", + "/Users/jbaylina/git/iden3/circom/src/lcalgebra.js", + "/Users/jbaylina/git/iden3/rollup/circuits/decodetx.circom", + "/Users/jbaylina/git/personal/semaphore/semaphorejs/snark/test.circom", + "/Users/jbaylina/git/iden3/circom/src/gencode.js", + "/Users/jbaylina/git/iden3/circom/src/buildwasm.js", + "/Users/jbaylina/git/iden3/rollup/circuits/statepacker.circom", + "/Users/jbaylina/git/personal/semaphore/semaphorejs/snark/circuit.json", + "/Users/jbaylina/git/iden3/circomlib/test/eddsaposeidon.js", + "/Users/jbaylina/git/iden3/rollup/.eslintrc.js", + "/Users/jbaylina/git/iden3/rollup/.eslintrc", + "/Users/jbaylina/git/iden3/circomlib/index.js", + "/Users/jbaylina/git/iden3/snarkjs/src/calculateWitness.js", + "/Users/jbaylina/git/iden3/circomlib/src/smt.js", + "/Users/jbaylina/git/iden3/snarkjs/src/bigint.js", + "/Users/jbaylina/git/iden3/rollup/circuits/requiredtxverifier.circom", + "/Users/jbaylina/git/codereview/rattack/deploy_withdraw.js", + "/Users/jbaylina/git/iden3/circomlib/src/poseidon.js", + "/Users/jbaylina/git/iden3/rollup/test/rollupaccount.js", + "/Users/jbaylina/git/iden3/rollup/test/circuits/input.json", + "/Users/jbaylina/git/iden3/rollup/js/tmpdb.js", + "/Users/jbaylina/git/iden3/circomlib/circuits/eddsaposeidon.circom", + "/Users/jbaylina/git/iden3/rollup/circuits/decodefloat.circom", + "/Users/jbaylina/git/iden3/circomlib/circuits/escalarmulany.circom", + "/Users/jbaylina/git/iden3/circomlib/circuits/escalarmulfix.circom", + "/Users/jbaylina/git/iden3/rollup/test/decodefloat.js", + "/Users/jbaylina/git/iden3/circomlib/test/sha256.js", + "/Users/jbaylina/git/iden3/circomlib/test/circuits/sha256_test448.circom", + "/Users/jbaylina/git/iden3/circomlib/test/circuits/sha256_test512.circom" + ], + "find": + { + "height": 40.0 + }, + "find_in_files": + { + "height": 313.0, + "where_history": + [ + ] + }, + "find_state": + { + "case_sensitive": true, + "find_history": + [ + "genSignalAssignConstrain", + "mpz_impo", + "instantiateConstant", + "genVariable", + "instantiateConstant", + "error", + "used", + "instantiateRef", + "newRef", + "used", + "main", + "components", + "execDeclareSignal", + ".e", + "execSignalAssign", + "execSignalAssignConstrain", + "buildWit2Sig", + "__P__", + "genConstraint", + "checkConstraint", + "genConstraint", + "genConstrain", + "setS", + "asse", + "genConstrain", + "codeHeader", + "ht_InOut", + "addSizes", + "codes_sizes", + "definedSizes", + "getTmpName", + "getTmpNames", + "getTmp", + "getTmpName", + "utils", + "buildWit2Sig", + "buildMapIsInput", + "globalNames", + "buildInit", + "ctx", + "buildInit", + "genHe" + ], + "highlight": true, + "in_selection": false, + "preserve_case": false, + "regex": false, + "replace_history": + [ + ], + "reverse": false, + "show_context": true, + "use_buffer2": true, + "whole_word": false, + "wrap": true + }, + "groups": + [ + { + "sheets": + [ + ] + } + ], + "incremental_find": + { + "height": 28.0 + }, + "input": + { + "height": 107.0 + }, + "layout": + { + "cells": + [ + [ + 0, + 0, + 1, + 1 + ] + ], + "cols": + [ + 0.0, + 1.0 + ], + "rows": + [ + 0.0, + 1.0 + ] + }, + "menu_visible": true, + "output.SublimeLinter": + { + "height": 0.0 + }, + "output.SublimeLinter Messages": + { + "height": 246.0 + }, + "output.find_results": + { + "height": 0.0 + }, + "pinned_build_system": "", + "project": "Project.sublime-project", + "replace": + { + "height": 52.0 + }, + "save_all_on_build": true, + "select_file": + { + "height": 0.0, + "last_filter": "", + "selected_items": + [ + [ + "", + "iden3/circom/src/exec.js" + ] + ], + "width": 0.0 + }, + "select_project": + { + "height": 0.0, + "last_filter": "", + "selected_items": + [ + ], + "width": 0.0 + }, + "select_symbol": + { + "height": 0.0, + "last_filter": "", + "selected_items": + [ + ], + "width": 0.0 + }, + "selected_group": 0, + "settings": + { + }, + "show_minimap": true, + "show_open_files": false, + "show_tabs": true, + "side_bar_visible": true, + "side_bar_width": 300.0, + "status_bar_visible": true, + "template_settings": + { + } +}
M c/calcwit.cpp → c/calcwit.cpp

@@ -25,8 +25,12 @@

// Initialize remaining signals for (int i=1; i<circuit->NSignals; i++) mpz_init2(signalValues[i], 256); - reset(); + BigInt p; + mpz_init_set_str(p, circuit->P, 10); + field = new ZqField(&p); + mpz_clear(p); + reset(); } void Circom_CalcWit::reset() {

@@ -43,6 +47,8 @@ }

Circom_CalcWit::~Circom_CalcWit() { + delete field; + #ifdef SANITY_CHECK delete signalAssigned; #endif
M c/calcwit.h → c/calcwit.h

@@ -2,6 +2,7 @@ #ifndef CIRCOM_CALCWIT_H

#define CIRCOM_CALCWIT_H #include "circom.h" +#include "zqfield.h" class Circom_CalcWit {

@@ -18,13 +19,12 @@ BigInt *signalValues;

Circom_Circuit *circuit; - - void triggerComponent(int newCIdx); void calculateWitness(void *input, void *output); public: + ZqField *field; int cIdx; // Functions called by the circuit Circom_CalcWit(Circom_Circuit *aCircuit);
M c/circom.h → c/circom.h

@@ -48,6 +48,7 @@ int NVars;

int *wit2sig; Circom_Component *components; u32 *mapIsInput; + const char *P; }; #define BITMAP_ISSET(m, b) (m[b>>5] & (1 << (b&0x1F)))
A c/zqfield.cpp

@@ -0,0 +1,30 @@

+#include "zqfield.h" + +ZqField::ZqField(PBigInt ap) { + mpz_init_set(p, *ap); + mpz_init_set_ui(zero, 0); + mpz_init_set_ui(one, 1); +} + + +void ZqField::add(PBigInt r, PBigInt a, PBigInt b) { + mpz_add(*r,*a,*b); + mpz_fdiv_r(*r, *r, p); +} + +void ZqField::lt(PBigInt r, PBigInt a, PBigInt b) { + int c = mpz_cmp(*a, *b); + if (c<0) { + mpz_set(*r, one); + } else { + mpz_set(*r, zero); + } +} + +int ZqField::isTrue(PBigInt a) { + return mpz_sgn(*a); +} + +void ZqField::copy(PBigInt a, PBigInt b) { + return mpz_set(*a, *b); +}
A c/zqfield.h

@@ -0,0 +1,20 @@

+#ifndef ZQFIELD_H +#define ZQFIELD_H + +#include "circom.h" + +class ZqField { + +public: + BigInt p; + BigInt one; + BigInt zero; + ZqField(PBigInt ap); + + void copy(PBigInt a, PBigInt b); + void add(PBigInt r,PBigInt a, PBigInt b); + void lt(PBigInt r, PBigInt a, PBigInt b); + int isTrue(PBigInt a); +}; + +#endif // ZQFIELD_H
M src/c_build.js → src/c_build.js

@@ -17,15 +17,18 @@ You should have received a copy of the GNU General Public License

along with circom. If not, see <https://www.gnu.org/licenses/>. */ -const utils = require("./utils"); const assert = require("assert"); -const gen = require("./c_gen"); +const bigInt = require("big-integer"); +const utils = require("./utils"); +const gen = require("./c_gen").gen; +const newRef = require("./c_gen").newRef; module.exports = buildC; function buildC(ctx) { ctx.code = ""; + ctx.conditionalCodeHeader = ""; ctx.tmpNames = {}; ctx.getTmpName = getTmpName; ctx.codes_sizes = [];

@@ -158,6 +161,7 @@

const scope = {_prefix : ""}; ctx.scopes = [scope]; + ctx.conditionalCode = false; ctx.nScopes = 0; ctx.code = ""; ctx.codeHeader = "// Header\n";

@@ -165,7 +169,7 @@ ctx.codeFooter = "// Footer\n";

ctx.tmpNames = Object.assign({},globalNames); for (let p in ctx.components[i].params) { - newRef(ctx, "BIGINT", p, ctx.components[i].params[p]); + newRef(ctx, "BIGINT", p, bigInt(ctx.components[i].params[p])); } gen(ctx, ctx.templates[ctx.components[i].template].block);

@@ -212,6 +216,7 @@ `#define NComponents ${ctx.components.length}\n` +

`#define NInputs ${ctx.components[ ctx.getComponentIdx("main") ].nInSignals}\n`+ `#define NOutputs ${ctx.totals[ ctx.stOUTPUT ]}\n`+ `#define NVars ${ctx.totals[ctx.stONE] + ctx.totals[ctx.stOUTPUT] + ctx.totals[ctx.stPUBINPUT] + ctx.totals[ctx.stPRVINPUT] + ctx.totals[ctx.stINTERNAL]}\n` + + `#define __P__ "${ctx.field.p.toString()}"\n` + "\n"; }

@@ -310,7 +315,8 @@ " NOutputs,\n"+

" NVars,\n"+ " _wit2sig,\n"+ " _components,\n"+ - " _mapIsInput\n"+ + " _mapIsInput,\n"+ + " __P__\n" + "};\n"; }
M src/c_gen.js → src/c_gen.js

@@ -1,8 +1,9 @@

const bigInt = require("big-integer"); const utils = require("./utils"); +const assert = require("assert"); -module.exports = gen; - +module.exports.gen = gen; +module.exports.newRef = newRef; function newRef(ctx, type, _name, value, _sizes) { const isValue = ((typeof(value) != "undefined")&&(value != null));

@@ -28,7 +29,7 @@ sizes = newSizes(ctx, []);

} const scope = ctx.scopes[ctx.scopes.length-1]; - if (scope[name]) return error("Variable already exists: " + name); + if (scope[name]) return error(ctx, null, "Variable already exists: " + name); const label = scope._prefix + name; scope[name] = {

@@ -64,9 +65,9 @@ return name;

} -function instantiateRef(ctx, name) { +function instantiateRef(ctx, name, initValue) { const v = getScope(ctx, name); - if (!v.stack) return error("Using a non existing var: " + name); + if (!v.stack) return error(ctx, null, "Using a non existing var: " + name); if (v.used) return; if (v.type=="BIGINT") {

@@ -76,7 +77,12 @@

if (iSize.used) { const labelSize = iSize.label; ctx.codeHeader += `PBigInt ${v.label};\n`; - ctx.code += `${v.label} = ctx->allocBigInts(${labelSize});\n`; + const c = `${v.label} = ctx->allocBigInts(${labelSize});\n`; + if (ctx.conditionalCode) { + ctx.conditionalCodeHeader += c; + } else { + ctx.code += c; + } ctx.codeFooter += `ctx->freeBigInts(${v.label}, ${labelSize});\n`; } else if (iSize.value) { const labelSize = ctx.addSizes(iSize.value);

@@ -92,6 +98,30 @@ } else if (v.type=="SIZES") {

ctx.codeHeader += `Circom_Sizes ${v.label};\n`; } v.used = true; + if ((typeof initValue!= "undefined")&&(initValue != null)) { + const flatedValue = utils.flatArray(initValue); + for (let i=0; i<flatedValue.length; i++) { + const c = `mpz_set_str(${v.label}[${i}], "${flatedValue[i].toString(10)}", 10);\n`; + if (ctx.conditionalCode) { + ctx.conditionalCodeHeader += c; + } else { + ctx.code += c; + } + } + } +} + +function instantiateConstant(ctx, value) { + const labelSize = ctx.addSizes(utils.extractSizes(value)); + const flatedValue = utils.flatArray(value); + const res = ctx.getTmpName("_const"); + ctx.codeHeader += `PBigInt ${res};\n`; + ctx.codeHeader += `${res} = ctx->allocBigInts(${labelSize});\n`; + for (let i=0; i<flatedValue.length; i++) { + ctx.codeHeader += `mpz_set_str(${res}[${i}], "${flatedValue[i].toString(10)}", 10);\n`; + } + ctx.codeFooter += `ctx->freeBigInts(${res}, ${labelSize});\n`; + return res; }

@@ -140,7 +170,7 @@ return genVarAddAssignement(ctx, ast);

} else if (ast.op == "*=") { return genVarMulAssignement(ctx, ast); } else if (ast.op == "+") { - return genAdd(ctx, ast); + return genBinaryOp(ctx, ast, "add"); } else if (ast.op == "-") { return genSub(ctx, ast); } else if (ast.op == "UMINUS") {

@@ -174,7 +204,7 @@ return genShl(ctx, ast);

} else if (ast.op == ">>") { return genShr(ctx, ast); } else if (ast.op == "<") { - return genLt(ctx, ast); + return genBinaryOp(ctx, ast, "lt"); } else if (ast.op == ">") { return genGt(ctx, ast); } else if (ast.op == "<=") {

@@ -226,6 +256,7 @@ }

} function genBlock(ctx, ast) { + ctx.scopes.push({_prefix : ""}); const oldCode = ctx.code; let res = null; ctx.code = "";

@@ -236,26 +267,35 @@ }

res = gen(ctx, ast.statements[i]); if (ctx.error) return; } - if (ctx.scopes.length>1) { - ctx.code = oldCode + `{\n${utils.ident(ctx.code)}}\n`; - } else { - ctx.code = oldCode + ctx.code; - } + ctx.code = oldCode + ctx.code; + ctx.scopes.pop(); return res; } -function genSrcComment(ctx, ast) { +function getSource(ctx, ast) { let codes = []; const fl= ast.first_line-1; const ll = ast.last_line-1; - const fc = ast.first_column-1; + const fc = ast.first_column; const lc = ast.last_column; for (let i=fl; i<=ll; i++) { const p1 = i==fl ? fc : 0; const p2 = i==ll ? lc : -1; codes.push(ctx.includedFiles[ctx.fileName][i].slice(p1, p2>=0 ? p2 : undefined)); } - ctx.code += "\n/* "+codes.join("\n")+"*/\n"; + return codes.join("\n"); +} + +function genSrcComment(ctx, ast) { + const code = getSource(ctx, ast); + ctx.code += "\n/* "+code+" */\n"; +} + +function genForSrcComment(ctx, ast) { + const init = getSource(ctx, ast.init); + const condition = getSource(ctx, ast.condition); + const step = getSource(ctx, ast.step); + ctx.code += `\n/* for (${init},${condition},${step}) */\n`; }

@@ -297,7 +337,7 @@ const varName = ast.name.name;

const labelName = scope._prefix + ast.name.name; if (ast.name.type != "VARIABLE") return error(ctx, ast, "Invalid component name"); - if (ctx.scope[varName]) return error(ctx, ast, "Name already exists: "+varName); + if (typeof scope[varName] != "undefined") return error(ctx, ast, "Name already exists: "+varName); const sizes=[]; let instantiate = false;

@@ -329,16 +369,17 @@ } else {

iSizes.value = sizes; } - const res = ctx.scope[varName] = { + const res = scope[varName] = { stack: true, type: "BIGINT", sizes: vSizes, - label: labelName + label: labelName, + used: false, }; scope[varName] = res; - return res; + return varName; } function genNumber(ctx, ast) {

@@ -432,17 +473,23 @@ return genGetSignal(ctx, "ctx->cIdx", vOffset);

} else if (v.type == "BIGINT") { const vOffset = genGetOffset(ctx, 0, v.sizes, ast.sels ); + const offset = getScope(ctx, vOffset); if (v.used) { - if (vOffset == 0) { - return ast.name; - } else { + if (offset.used) { const res = newRef(ctx, "BIGINT", "_v"); instantiateRef(ctx, res); ctx.code += `${res} = ${ast.name} + ${vOffset};\n`; return res; + } else if (offset.value) { + const res = newRef(ctx, "BIGINT", "_v"); + instantiateRef(ctx, res); + ctx.code += `${res} = ${ast.name} + ${vOffset.value};\n`; + return res; + } else { + return ast.name; } } else { - if (typeof(vOffset) == "string") { + if (offset.used) { instantiateRef(ctx, ast.name); const vConstant = instantiateConstant(ctx, v.value); const res = newRef(ctx, "BIGINT", "_v");

@@ -475,17 +522,6 @@ error(ctx, ast, "Invalid Variable type");

} } -function instantiateConstant(ctx, value) { - const flatedValue = utils.flatArray(value); - const res = ctx.getTmpName("_const"); - ctx.codeHeader += `PBigInt ${res};\n`; - ctx.code += `${res.label} = ctx->allocBigInts(${flatedValue.length});\n`; - for (let i=0; i<flatedValue.length; i++) { - ctx.code += `mpz_init_set_str(${res.label}[${i}], ${flatedValue[i].toString(16)}, 16);\n`; - } - ctx.codeFooter += `ctx->freeBigInts(${res.label});\n`; - return res; -} function genPin(ctx, ast) { let vcIdx;

@@ -546,7 +582,12 @@ return vSizes;

} function genSetSignal(ctx, cIdx, sIdx, value) { + const v = getScope(ctx, value); + if (!v.used) { + value = instantiateConstant(ctx, v.value); + } ctx.code += `ctx->setSignal(${cIdx}, ${sIdx}, ${value});\n`; + return value; }

@@ -604,6 +645,10 @@

const left = getScope(ctx, lName); if (!left) return error(ctx, ast, "Variable does not exists: "+ast.values[0].name); + if (ctx.conditionalCode && !left.used) { + instantiateRef(ctx, lName, left.value); + } + // Component instantiation is already done. if (left.type == "COMPONENT") { ctx.last = lName;

@@ -626,36 +671,29 @@ vsIdx = genGetSigalOffset(ctx, "ctx->cIdx", lName);

} return genSetSignal(ctx, "ctx->cIdx", vsIdx, rName); - } else if (left.type == "VAR") { + } else if (left.type == "BIGINT") { if (left.used) { if (!right.used) { instantiateRef(ctx, rName); } - ctx.code += `BigInt_copy(${left.label}, ${right.label});\n`; - return lName; + ctx.code += `ctx->field->copy(${left.label}, ${right.label});\n`; } else { if (right.used) { instantiateRef(ctx, lName); - ctx.code += `BigInt_copy(${left.label}, ${right.label});\n`; - return lName; + ctx.code += `ctx->field->copy(${left.label}, ${right.label});\n`; } else { - if (!left.value) { - left.value = right.value; + if (ctx.conditionalCode) { + instantiateRef(ctx, lName); + ctx.code += `ctx->field->copy(${left.label}, ${right.label});\n`; } else { - if (!left.value.equals(right.value)) { - if (ctx.scopes.length > 1) { - instantiateRef(ctx, lName); - ctx.code += `BigInt_copy(${left.label}, ${right.label});\n`; - } else { - left.value = right.value; - } - } + left.value = right.value; } } } } else { return error(ctx, ast, "Assigning to invalid"); } + return lName; } function genConstraint(ctx, ast) {

@@ -690,18 +728,103 @@

return `ctx.callFunction("${ast.name}", ${S})`; } +function enterConditionalCode(ctx) { + if (!ctx.conditionalCode) { + ctx.conditionalCode = 1; + ctx.conditionalCodeHeader = ""; + ctx.code += "__CONDITIONAL_CODE_HEADER__"; + } else { + ctx.conditionalCode ++; + } +} + +function leaveConditionalCode(ctx) { + assert(ctx.conditionalCode, "Leaving conditional code too many times"); + ctx.conditionalCode --; + if (!ctx.conditionalCode) { + ctx.code = ctx.code.replace("__CONDITIONAL_CODE_HEADER__", + "// Conditional Code Header\n" + + ctx.conditionalCodeHeader+ + "\n"); + delete ctx.conditionalCodeHeader; + delete ctx.conditionalCode; + } +} + function genFor(ctx, ast) { - ctx.scopes.push({}); - const init = gen(ctx, ast.init); + genForSrcComment(ctx, ast); + let inLoop = false; + ctx.scopes.push({_prefix : ""}); + gen(ctx, ast.init); if (ctx.error) return; - const condition = gen(ctx, ast.condition); - if (ctx.error) return; - const step = gen(ctx, ast.step); - if (ctx.error) return; - const body = gen(ctx, ast.body); - if (ctx.error) return; + + let end=false; + let condVar; + + + const condName = gen(ctx, ast.condition); + const cond = getScope(ctx, condName); + if (cond.used) { + inLoop = true; + enterConditionalCode(ctx); + condVar = newRef(ctx, "INT", "_cond"); + instantiateRef(ctx, condVar); + + ctx.code += + `${condVar} = ctx->field->isTrue(${condName});\n` + + `while (${condVar}) {\n`; + } else { + if ((typeof cond.value == "undefined")||(cond.value == null)) return error(ctx, ast, "condition value not assigned"); + if (cond.value.isZero()) end=true; + } + + + while (!end) { + + const oldCode = ctx.code; + ctx.code = ""; + + if (ast.body.type != "BLOCK") genSrcComment(ctx, ast.body); + gen(ctx, ast.body); + if (ctx.error) return; + + gen(ctx, ast.step); + if (ctx.error) return; + + const condName2 = gen(ctx, ast.condition); + const cond2 = getScope(ctx, condName2); + + if (!inLoop) { + if (cond2.used) { + ctx.code = oldCode + ctx.code; + inLoop = true; + enterConditionalCode(ctx); + condVar = newRef(ctx, "INT", "_cond"); + instantiateRef(ctx, condVar); + + ctx.code = + oldCode + + ctx.code + + `${condVar} = ctx->field->isTrue(${condName2});\n` + + `while (${condVar}) {\n`; + } else { + ctx.code = oldCode + ctx.code; + if (cond2.value.isZero()) end=true; + } + } else { + ctx.code = + oldCode + + utils.ident( + ctx.code + + `${condVar} = ctx->field->isTrue(${condName2});\n`); + end=true; + } + } + if (inLoop) { + ctx.code += "}\n"; + leaveConditionalCode(ctx); + } ctx.scopes.pop(); - return `for (${init};bigInt(${condition}).neq(bigInt(0));${step}) { \n${body}\n }\n`; } function genWhile(ctx, ast) {

@@ -743,9 +866,9 @@

function genSignalAssignConstrain(ctx, ast) { const res = genVarAssignement(ctx, ast); - genConstraint(ctx, ast); + // genConstraint(ctx, ast); return res; -// return genVarAssignement(ctx, ast); + // return genVarAssignement(ctx, ast); } function genVarAddAssignement(ctx, ast) {

@@ -772,12 +895,34 @@ function genMinusMinusLeft(ctx, ast) {

return genVarAssignement(ctx, {values: [ast.values[0], {type: "OP", op: "-", values: [ast.values[0], {type: "NUMBER", value: bigInt(1)}]}]}); } -function genAdd(ctx, ast) { - const a = gen(ctx, ast.values[0]); +function genBinaryOp(ctx, ast, op) { + let aName = gen(ctx, ast.values[0]); if (ctx.error) return; - const b = gen(ctx, ast.values[1]); + const a = getScope(ctx, aName); + + let bName = gen(ctx, ast.values[1]); if (ctx.error) return; - return `bigInt(${a}).add(bigInt(${b})).mod(__P__)`; + const b = getScope(ctx, bName); + + if ((!a.used)&&(typeof a.value == "undefined")) return error(ctx, ast, "Using a not assigned varialble: "+aName); + if ((!b.used)&&(typeof b.value == "undefined")) return error(ctx, ast, "Using a not assigned varialble: "+bName); + + let rName; + if (a.used || b.used) { + if (!a.used) { + aName = instantiateConstant(ctx, a.value); + } + if (!b.used) { + bName = instantiateConstant(ctx, b.value); + } + + rName = newRef(ctx, "BIGINT", "_tmp"); + instantiateRef(ctx, rName); + ctx.code += `ctx->field->${op}(${rName},${aName}, ${bName});\n`; + } else { + rName = newRef(ctx, "BIGINT", "_tmp", ctx.field[op](a.value, b.value)); + } + return rName; } function genMul(ctx, ast) {
M src/c_tester.js → src/c_tester.js

@@ -8,8 +8,8 @@ const compiler = require("./compiler");

const util = require("util"); const exec = util.promisify(require("child_process").exec); -const stringifyBigInts = require("snarkjs").stringifyBigInts; -const unstringifyBigInts = require("snarkjs").unstringifyBigInts; +const stringifyBigInts = require("./utils").stringifyBigInts; +const unstringifyBigInts = require("./utils").unstringifyBigInts; const bigInt = require("snarkjs").bigInt; module.exports = c_tester;

@@ -35,12 +35,13 @@ ` ${path.join(dir.path, baseName + ".cpp")} ` +

` ${path.join(cdir, "main.cpp")}` + ` ${path.join(cdir, "calcwit.cpp")}` + ` ${path.join(cdir, "utils.cpp")}` + + ` ${path.join(cdir, "zqfield.cpp")}` + ` -o ${path.join(dir.path, baseName)}` + ` -I ${cdir}` + " -lgmp -std=c++11 -DSANITY_CHECK" ); - console.log(dir.path); + // console.log(dir.path); return new CTester(dir, baseName, mainComponent); }

@@ -102,7 +103,7 @@ if (Array.isArray(eOut)) {

for (let i=0; i<eOut.length; i++) { checkObject(prefix + "["+i+"]", eOut[i]); } - } else if (typeof eOut == "object") { + } else if ((typeof eOut == "object")&&(eOut.constructor.name == "Object")) { for (let k in eOut) { checkObject(prefix + "."+k, eOut[k]); }
M src/compiler.js → src/compiler.js

@@ -28,6 +28,7 @@ const buildC = require("./c_build");

const exec = require("./exec"); const lc = require("./lcalgebra"); const Ctx = require("./ctx"); +const ZqField = require("./zqfield"); module.exports = compile;

@@ -36,6 +37,7 @@

const timeout = ms => new Promise(res => setTimeout(res, ms)); async function compile(srcFile, options) { + options.p = options.p || __P__; if (!options) { options = {}; }

@@ -51,6 +53,7 @@

assert(ast.type == "BLOCK"); const ctx = new Ctx(); + ctx.field = new ZqField(options.p); ctx.mainComponent = options.mainComponent || "main"; ctx.filePath= fullFilePath; ctx.fileName= fullFileName;
M src/exec.js → src/exec.js

@@ -1143,7 +1143,7 @@ if (!lc.isZero(res)) {

ctx.constraints.push(lc.toQEQ(res)); } - if (ctx.constraints.length % 10000 == 0) console.log("Constraints: " + ctx.constraints.length); + if ((ctx.constraints.length % 10000 == 0)&&(ctx.constraints.length>0)) console.log("Constraints: " + ctx.constraints.length); return res; }
M src/utils.js → src/utils.js

@@ -1,12 +1,16 @@

const fnv = require("fnv-plus"); +const bigInt = require("big-integer"); module.exports.ident =ident; module.exports.extractSizes =extractSizes; +module.exports.flatArray = flatArray; module.exports.csArr = csArr; module.exports.subArray = subArray; module.exports.accSizes = accSizes; module.exports.fnvHash = fnvHash; +module.exports.stringifyBigInts = stringifyBigInts; +module.exports.unstringifyBigInts = unstringifyBigInts; function ident(text) { let lines = text.split("\n");

@@ -17,10 +21,26 @@ return lines.join("\n");

} function extractSizes (o) { - if (! Array.isArray(o)) return [1, 0]; + if (! Array.isArray(o)) return []; return [o.length, ...extractSizes(o[0])]; } +function flatArray(a) { + var res = []; + fillArray(res, a); + return res; + + function fillArray(res, a) { + if (Array.isArray(a)) { + for (let i=0; i<a.length; i++) { + fillArray(res, a[i]); + } + } else { + res.push(a); + } + } +} + // Input [1,2,3] // Returns " ,1 ,2, 3" function csArr(_arr) {

@@ -53,3 +73,37 @@ }

+function stringifyBigInts(o) { + if ((typeof(o) == "bigint") || o.isZero !== undefined) { + return o.toString(10); + } else if (Array.isArray(o)) { + return o.map(stringifyBigInts); + } else if (typeof o == "object") { + const res = {}; + for (let k in o) { + res[k] = stringifyBigInts(o[k]); + } + return res; + } else { + return o; + } +} + +function unstringifyBigInts(o) { + if ((typeof(o) == "string") && (/^[0-9]+$/.test(o) )) { + return bigInt(o); + } else if (Array.isArray(o)) { + return o.map(unstringifyBigInts); + } else if (typeof o == "object") { + const res = {}; + for (let k in o) { + res[k] = unstringifyBigInts(o[k]); + } + return res; + } else { + return o; + } +} + + +
A src/zqfield.js

@@ -0,0 +1,17 @@

+const bigInt = require("big-integer"); + +module.exports = class ZqField { + constructor(p) { + this.p = p; + } + + add(a, b) { + return a.add(b).mod(this.p); + } + + lt(a, b) { + return a.lt(b) ? bigInt(1) : bigInt(0); + } + +}; +
A test/basiccases.js

@@ -0,0 +1,62 @@

+const path = require("path"); + +const bigInt = require("big-integer"); +const c_tester = require("../index.js").c_tester; + +const __P__ = new bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617"); + + +async function doTest(circuit, testVectors) { + const cir = await c_tester(path.join(__dirname, "circuits", circuit)); + + for (let i=0; i<testVectors.length; i++) { + const w = await cir.calculateWitness(testVectors[i][0]); + await cir.assertOut(w, testVectors[i][1] ); + } + + await cir.release(); +} + +describe("basic cases", function () { + this.timeout(100000); + it("add", async () => { + await doTest( + "add.circom", + [ + [{in: [0,0]}, {out: 0}], + [{in: [0,1]}, {out: 1}], + [{in: [1,2]}, {out: 3}], + [{in: [__P__.minus(1),1]}, {out: 0}], + ] + ); + }); + it("add constant", async () => { + await doTest( + "addconst1.circom", + [ + [{in: 0}, {out: 15}], + [{in: 10}, {out: 25}], + [{in: __P__.minus(2)}, {out: 13}], + ] + ); + }); + it("for unrolled", async () => { + await doTest( + "forunrolled.circom", + [ + [{in: 0}, {out: [0,1,2]}], + [{in: 10}, {out: [10, 11, 12]}], + [{in: __P__.minus(2)}, {out: [__P__.minus(2), __P__.minus(1), 0]}], + ] + ); + }); + it("for rolled", async () => { + await doTest( + "forrolled.circom", + [ + [{in: 0}, {out: 0}], + [{in: 10}, {out: 10}], + ] + ); + }); +});
A test/circuits/add.circom

@@ -0,0 +1,9 @@

+ +template Add() { + signal input in[2]; + signal output out; + + out <== in[0] + in[1]; +} + +component main = Add();
A test/circuits/addconst1.circom

@@ -0,0 +1,16 @@

+ + +template AddConst(c) { + signal input in; + signal output out; + var a = 2; + var b = 3; + a=a+b; + a=a+4; + a=a+c; + + out <== 5 + a + in; +} + +// It should out <== in + 1+2+3+4+5 = in + 15 +component main = AddConst(1);
A test/circuits/addin.json

@@ -0,0 +1,1 @@

+{"in":[1,2]}
A test/circuits/forrolled.circom

@@ -0,0 +1,14 @@

+template ForRolled() { + signal input in; + signal output out; + + var acc = 0; + + for (var i=0; i<in; i = i+1) { + acc = acc + 1; + } + + out <== acc; +} + +component main = ForRolled();
A test/circuits/forunrolled.circom

@@ -0,0 +1,10 @@

+template ForUnrolled(n) { + signal input in; + signal output out[n]; + + for (var i=0; i<n; i = i+1) { + out[i] <== in + i; + } +} + +component main = ForUnrolled(3);
M test/circuits/in.json → test/circuits/in.json

@@ -1,1 +1,1 @@

-{ "in1": 1, "in2": [2,3], "in3":[[4,5],[6,7],[8,9]] } +{"in": 0}
A test/circuits/out.json

@@ -0,0 +1,5 @@

+[ + "1" +,"0" +,"0" +]
M test/inout.js → test/inout.js

@@ -1,8 +1,7 @@

-const chai = require("chai"); const path = require("path"); const c_tester = require("../index.js").c_tester; -const stringifyBigInts = require("snarkjs").stringifyBigInts; +// const stringifyBigInts = require("snarkjs").stringifyBigInts; describe("inout test", function () {