arnaucube
arnaucube/circomPublic Self-hosted repository
sha256 done
Jordi Baylina jordi@baylina.cat
Fri, 14 Sep 2018 07:09:58 +0200
commit

431a6919630f82ed007c4fda4ff5ffb23d6c4d2c

parent

2ebd68be6f8c704b6c58d04b70307110265addaf

M circuits/sha256/rotate.circom → circuits/sha256/rotate.circom

@@ -4,7 +4,7 @@ template RotR(n, r) {

signal input in[n]; signal output out[n]; - for (i=0; i<n; i++) { + for (var i=0; i<n; i++) { out[i] <== in[ (i+r)%n ]; } }
M circuits/sha256/sha256_2.circom → circuits/sha256/sha256_2.circom

@@ -8,36 +8,41 @@ signal input b;

signal output out; component bits2num = Bits2Num(216); - component num2bits[2] = Num2Bits(216); + component num2bits[2]; - num2bits[0].inp <== a; - num2bits[1].inp <== b; + num2bits[0] = Num2Bits(216); + num2bits[1] = Num2Bits(216); + + num2bits[0].in <== a; + num2bits[1].in <== b; component sha256compression = Sha256compression() ; var i; for (i=0; i<216; i++) { - sha256compression.inp[i] <== num2bits[0].out[i]; - sha256compression.inp[i+216] <== num2bits[1].out[i]; + sha256compression.inp[i] <== num2bits[0].out[215-i]; + sha256compression.inp[i+216] <== num2bits[1].out[215-i]; } - for (i=432; i<247; i++) { + sha256compression.inp[432] <== 1; + + for (i=433; i<503; i++) { sha256compression.inp[i] <== 0; } - sha256compression.inp[247] <== 1; - sha256compression.inp[248] <== 1; - sha256compression.inp[249] <== 0; - sha256compression.inp[250] <== 1; - sha256compression.inp[251] <== 1; - sha256compression.inp[252] <== 0; - sha256compression.inp[253] <== 0; - sha256compression.inp[254] <== 0; - sha256compression.inp[255] <== 0; + sha256compression.inp[503] <== 1; + sha256compression.inp[504] <== 1; + sha256compression.inp[505] <== 0; + sha256compression.inp[506] <== 1; + sha256compression.inp[507] <== 1; + sha256compression.inp[508] <== 0; + sha256compression.inp[509] <== 0; + sha256compression.inp[510] <== 0; + sha256compression.inp[511] <== 0; for (i=0; i<216; i++) { - bits2num.inp[i] <== sha256compression.out[i]; + bits2num.in[i] <== sha256compression.out[255-i]; } out <== bits2num.out;
M circuits/sha256/sha256compression.circom → circuits/sha256/sha256compression.circom

@@ -8,38 +8,47 @@

template Sha256compression() { signal input inp[512]; signal output out[256]; - signal a[64][32]; - signal b[64][32]; - signal c[64][32]; - signal d[64][32]; - signal e[64][32]; - signal f[64][32]; - signal g[64][32]; - signal h[64][32]; + signal a[65][32]; + signal b[65][32]; + signal c[65][32]; + signal d[65][32]; + signal e[65][32]; + signal f[65][32]; + signal g[65][32]; + signal h[65][32]; signal w[64][32]; var i; - component sigmaPlus[48] = SigmaPlus(); + component sigmaPlus[48]; + for (i=0; i<48; i++) sigmaPlus[i] = SigmaPlus(); component ct_k[64]; for (i=0; i<64; i++) ct_k[i] = K(i); - component ha0 = H0(0); - component hb0 = H0(1); - component hc0 = H0(2); - component hd0 = H0(3); - component he0 = H0(4); - component hf0 = H0(5); - component hg0 = H0(6); - component hh0 = H0(7); + component ha0 = H(0); + component hb0 = H(1); + component hc0 = H(2); + component hd0 = H(3); + component he0 = H(4); + component hf0 = H(5); + component hg0 = H(6); + component hh0 = H(7); + + component t1[64]; + for (i=0; i<64; i++) t1[i] = T1(); + + component t2[64]; + for (i=0; i<64; i++) t2[i] = T2(); + + component suma[64]; + for (i=0; i<64; i++) suma[i] = BinSum(32, 2); - component t1[64] = T1(); - component t2[64] = T2(); + component sume[64]; + for (i=0; i<64; i++) sume[i] = BinSum(32, 2); - component suma[64] = Sum(32, 2); - component sume[64] = Sum(32, 2); - component fsum[8] = Sum(32, 2); + component fsum[8]; + for (i=0; i<8; i++) fsum[i] = BinSum(32, 2); var k; var t;

@@ -47,12 +56,12 @@

for (t=0; t<64; t++) { if (t<16) { for (k=0; k<32; k++) { - w[t][k] <== inp[t*32+k]; + w[t][k] <== inp[t*32+31-k]; } } else { for (k=0; k<32; k++) { sigmaPlus[t-16].in2[k] <== w[t-2][k]; - sigmaPlus[t-16].in7[k] <== w[t-2][k]; + sigmaPlus[t-16].in7[k] <== w[t-7][k]; sigmaPlus[t-16].in15[k] <== w[t-15][k]; sigmaPlus[t-16].in16[k] <== w[t-16][k]; w[t][k] <== sigmaPlus[t-16].out[k];

@@ -71,37 +80,37 @@ g[0][k] <== hg0.out[k]

h[0][k] <== hh0.out[k] } - for (t = 0; t<63; t++) { + for (t = 0; t<64; t++) { for (k=0; k<32; k++) { - t1[t].h[k] <== h[k]; - t1[t].e[k] <== e[k]; - t1[t].f[k] <== f[k]; - t1[t].g[k] <== g[k]; - t1[t].k[k] <== ct_K[t].out[k]; + t1[t].h[k] <== h[t][k]; + t1[t].e[k] <== e[t][k]; + t1[t].f[k] <== f[t][k]; + t1[t].g[k] <== g[t][k]; + t1[t].k[k] <== ct_k[t].out[k]; t1[t].w[k] <== w[t][k]; - t2[t].a[k] <== a[k]; - t2[t].b[k] <== b[k]; - t2[t].c[k] <== c[k]; + t2[t].a[k] <== a[t][k]; + t2[t].b[k] <== b[t][k]; + t2[t].c[k] <== c[t][k]; } for (k=0; k<32; k++) { - sume[t].a[k] <== d[k]; - sume[t].b[k] <== t1[t].out[k]; + sume[t].in[0][k] <== d[t][k]; + sume[t].in[1][k] <== t1[t].out[k]; - suma[t].a[k] <== t1[t].out[k]; - suma[t].b[k] <== t2[t].out[k]; + suma[t].in[0][k] <== t1[t].out[k]; + suma[t].in[1][k] <== t2[t].out[k]; } for (k=0; k<32; k++) { - h[t+1] <== g[t]; - g[t+1] <== f[t]; - f[t+1] <== e[t]; - e[t+1] <== sume[t].out[k]; - d[t+1] <== c[t]; - c[t+1] <== b[t]; - b[t+1] <== a[t]; - a[t+1] <== suma[t].out[k]; + h[t+1][k] <== g[t][k]; + g[t+1][k] <== f[t][k]; + f[t+1][k] <== e[t][k]; + e[t+1][k] <== sume[t].out[k]; + d[t+1][k] <== c[t][k]; + c[t+1][k] <== b[t][k]; + b[t+1][k] <== a[t][k]; + a[t+1][k] <== suma[t].out[k]; } }

@@ -125,13 +134,13 @@ fsum[7].in[1][k] <== h[64][k];

} for (k=0; k<32; k++) { - out[k] <== fsum[0].out[k]; - out[32+k] <== fsum[1].out[k]; - out[64+k] <== fsum[2].out[k]; - out[96+k] <== fsum[3].out[k]; - out[128+k] <== fsum[4].out[k]; - out[160+k] <== fsum[5].out[k]; - out[192+k] <== fsum[6].out[k]; - out[224+k] <== fsum[7].out[k]; + out[31-k] <== fsum[0].out[k]; + out[32+31-k] <== fsum[1].out[k]; + out[64+31-k] <== fsum[2].out[k]; + out[96+31-k] <== fsum[3].out[k]; + out[128+31-k] <== fsum[4].out[k]; + out[160+31-k] <== fsum[5].out[k]; + out[192+31-k] <== fsum[6].out[k]; + out[224+31-k] <== fsum[7].out[k]; } }
A circuits/sha256/shift.circom

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

+ +template ShR(n, r) { + signal input in[n]; + signal output out[n]; + + for (var i=0; i<n; i++) { + if (i+r >= n) { + out[i] <== 0; + } else { + out[i] <== in[ i+r ]; + } + } +} +
M circuits/sha256/sigma.circom → circuits/sha256/sigma.circom

@@ -1,9 +1,33 @@

include "xor3.circom"; include "rotate.circom"; +include "shift.circom"; -template Sigma(ra, rb, rc) { +template SmallSigma(ra, rb, rc) { signal input in[32]; - signal output out; + signal output out[32]; + + component xor3 = Xor3(32); + + component rota = RotR(32, ra); + component rotb = RotR(32, rb); + component shrc = ShR(32, rc); + + for (var k=0; k<32; k++) { + rota.in[k] <== in[k]; + rotb.in[k] <== in[k]; + shrc.in[k] <== in[k]; + + xor3.a[k] <== rota.out[k]; + xor3.b[k] <== rotb.out[k]; + xor3.c[k] <== shrc.out[k]; + + out[k] <== xor3.out[k]; + } +} + +template BigSigma(ra, rb, rc) { + signal input in[32]; + signal output out[32]; component xor3 = Xor3(32);
M circuits/sha256/sigmaplus.circom → circuits/sha256/sigmaplus.circom

@@ -8,9 +8,9 @@ signal input in15[32];

signal input in16[32]; signal output out[32]; - component sum = Sum(32, 4); - component sigma1 = Sigma(17,19,10); - component sigma0 = Sigma(7, 18, 3); + component sum = BinSum(32, 4); + component sigma1 = SmallSigma(17,19,10); + component sigma0 = SmallSigma(7, 18, 3); for (var k=0; k<32; k++) { sigma1.in[k] <== in2[k];
M circuits/sha256/t1.circom → circuits/sha256/t1.circom

@@ -11,23 +11,23 @@ signal input k[32];

signal input w[32]; signal output out[32]; - component sum = Sum(32, 5); + component sum = BinSum(32, 5); component ch = Ch(32); - component bigsigma1 = Sigma(6, 11, 25); + component bigsigma1 = BigSigma(6, 11, 25); - for (var k=0; k<32; k++) { - bigsigma1.in[k] <== e[k]; - ch.a[k] <== e[k]; - ch.b[k] <== f[k]; - ch.c[k] <== g[k] + for (var ki=0; ki<32; ki++) { + bigsigma1.in[ki] <== e[ki]; + ch.a[ki] <== e[ki]; + ch.b[ki] <== f[ki]; + ch.c[ki] <== g[ki] - sum.in[0][k] <== h[k]; - sum.in[1][k] <== bigsigma1.out[k]; - sum.in[2][k] <== ch.out[k]; - sum.in[3][k] <== k[k]; - sum.in[4][k] <== w[k]; + sum.in[0][ki] <== h[ki]; + sum.in[1][ki] <== bigsigma1.out[ki]; + sum.in[2][ki] <== ch.out[ki]; + sum.in[3][ki] <== k[ki]; + sum.in[4][ki] <== w[ki]; - out[k] <== sum.out[k]; + out[ki] <== sum.out[ki]; } }
M circuits/sha256/t2.circom → circuits/sha256/t2.circom

@@ -8,9 +8,9 @@ signal input b[32];

signal input c[32]; signal output out[32]; - component sum = Sum(32, 2); + component sum = BinSum(32, 2); - component bigsigma0 = Sigma(2, 13, 22); + component bigsigma0 = BigSigma(2, 13, 22); component maj = Maj(32); for (var k=0; k<32; k++) {
M package.json → package.json

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

{ "name": "circom", - "version": "0.0.5", + "version": "0.0.6", "description": "Language to generate logic circuits", "main": "index.js", "directories": {

@@ -37,6 +37,6 @@ "chai": "^4.1.2",

"eslint": "^5.0.1", "eslint-plugin-mocha": "^5.0.0", "jison": "^0.4.18", - "zksnark": "0.0.5" + "zksnark": "0.0.6" } }
M src/exec.js → src/exec.js

@@ -3,14 +3,14 @@ Copyright 2018 0KIMS association.

This file is part of jaz (Zero Knowledge Circuit Compiler). - jaz is a free software: you can redistribute it and/or modify it + jaz 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. - jaz 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 + jaz 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

@@ -72,6 +72,8 @@ } else if (ast.op == "UMINUS") {

return execUMinus(ctx, ast); } else if (ast.op == "*") { return execMul(ctx, ast); + } else if (ast.op == "%") { + return execMod(ctx, ast); } else if (ast.op == "PLUSPLUSRIGHT") { return execPlusPlusRight(ctx, ast); } else if (ast.op == "PLUSPLUSLEFT") {

@@ -86,6 +88,12 @@ } else if (ast.op == ">>") {

return execShr(ctx, ast); } else if (ast.op == "<") { return execLt(ctx, ast); + } else if (ast.op == ">") { + return execGt(ctx, ast); + } else if (ast.op == "<=") { + return execLte(ctx, ast); + } else if (ast.op == ">=") { + return execGte(ctx, ast); } else if (ast.op == "==") { return execEq(ctx, ast); } else if (ast.op == "?") {

@@ -113,6 +121,8 @@ } else if (ast.type == "FOR") {

return execFor(ctx, ast); } else if (ast.type == "WHILE") { return execWhile(ctx, ast); + } else if (ast.type == "IF") { + return execIf(ctx, ast); } else if (ast.type == "RETURN") { return execReturn(ctx, ast); } else if (ast.type == "TEMPLATEDEF") {

@@ -310,6 +320,8 @@ }

if (template.params.length != paramValues.length) error(ctx, fn, "Invalid Number of parameters"); const vv = getScope(ctx, componentName, vr.selectors); + + if (!vv) return error(ctx, vr, "Component not defined"+ componentName); instantiateComponent(vv);

@@ -486,7 +498,12 @@ };

} function execVariable(ctx, ast) { - const v = getScope(ctx, ast.name, ast.selectors); + let v; + try { + v = getScope(ctx, ast.name, ast.selectors); + } catch(err) { + console.log(JSON.stringify(ast, null,1)); + } if (ctx.error) return; if (!v) return error(ctx, ast, "Variable not defined");

@@ -547,6 +564,19 @@ if (ctx.error) return;

} } +function execIf(ctx, ast) { + let v = exec(ctx, ast.condition); + if (ctx.error) return; + + if ((v.value.neq(0))&&(!ctx.returnValue)) { + exec(ctx, ast.then); + if (ctx.error) return; + } else { + exec(ctx, ast.else); + if (ctx.error) return; + } +} + function execVarAssignement(ctx, ast) { let v;

@@ -559,7 +589,7 @@ }

const num = getScope(ctx, v.name, v.selectors); if (ctx.error) return; - if (typeof(num) != "object") return error(ctx, ast, "Variable not defined"); + if ((typeof(num) != "object")||(num == null)) return error(ctx, ast, "Variable not defined"); if (num.type == "COMPONENT") return execInstantiateComponet(ctx, v, ast.values[1]);

@@ -585,6 +615,49 @@ value: a.value.lt(b.value) ? bigInt(1) : bigInt(0)

}; } +function execGt(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.gt(b.value) ? bigInt(1) : bigInt(0) + }; +} + +function execLte(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.lesserOrEquals(b.value) ? bigInt(1) : bigInt(0) + }; +} + +function execGte(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.greaterOrEquals(b.value) ? bigInt(1) : bigInt(0) + }; +} + + function execEq(ctx, ast) { const a = exec(ctx, ast.values[0]); if (ctx.error) return;

@@ -644,6 +717,21 @@ value: a.value.shiftRight(v).and(__MASK__)

}; } +function execMod(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.mod(b.value) + }; +} + + function execExp(ctx, ast) { const a = exec(ctx, ast.values[0]); if (ctx.error) return;

@@ -703,6 +791,7 @@ if (res.type == "ERROR") return error(ctx, ast, res.errStr);

return res; } + function execVarAddAssignement(ctx, ast) { const res = execAdd(ctx,{ values: [ast.values[0], ast.values[1]] } );
M src/gencode.js → src/gencode.js

@@ -3,14 +3,14 @@ Copyright 2018 0KIMS association.

This file is part of jaz (Zero Knowledge Circuit Compiler). - jaz is a free software: you can redistribute it and/or modify it + jaz 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. - jaz 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 + jaz 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

@@ -57,6 +57,8 @@ } else if (ast.op == "UMINUS") {

return genUMinus(ctx, ast); } else if (ast.op == "*") { return genMul(ctx, ast); + } else if (ast.op == "%") { + return genMod(ctx, ast); } else if (ast.op == "PLUSPLUSRIGHT") { return genPlusPlusRight(ctx, ast); } else if (ast.op == "PLUSPLUSLEFT") {

@@ -71,6 +73,12 @@ } else if (ast.op == ">>") {

return genShr(ctx, ast); } else if (ast.op == "<") { return genLt(ctx, ast); + } else if (ast.op == ">") { + return genGt(ctx, ast); + } else if (ast.op == "<=") { + return genLte(ctx, ast); + } else if (ast.op == ">=") { + return genGte(ctx, ast); } else if (ast.op == "==") { return genEq(ctx, ast); } else if (ast.op == "?") {

@@ -98,6 +106,8 @@ } else if (ast.type == "FOR") {

return genFor(ctx, ast); } else if (ast.type == "WHILE") { return genWhile(ctx, ast); + } else if (ast.type == "IF") { + return genIf(ctx, ast); } else if (ast.type == "RETURN") { return genReturn(ctx, ast); } else if (ast.type == "TEMPLATEDEF") {

@@ -218,7 +228,7 @@ const step = gen(ctx, ast.step);

if (ctx.error) return; const body = gen(ctx, ast.body); if (ctx.error) return; - return `for (${init};${condition};${step})\n${body}`; + return `for (${init};${condition};${step}) { \n${body}\n }\n`; } function genWhile(ctx, ast) {

@@ -226,8 +236,19 @@ const condition = gen(ctx, ast.condition);

if (ctx.error) return; const body = gen(ctx, ast.body); if (ctx.error) return; - return `while (${condition})\n${body}`; + return `while (${condition}) {\n${body}\n}\n`; +} + +function genIf(ctx, ast) { + const condition = gen(ctx, ast.condition); + if (ctx.error) return; + const thenBody = gen(ctx, ast.then); + if (ctx.error) return; + const elseBody = gen(ctx, ast.else); + if (ctx.error) return; + return `if (${condition}) {\n${thenBody}\n} else {\n${elseBody}\n}\n`; } + function genReturn(ctx, ast) { const value = gen(ctx, ast.value);

@@ -449,12 +470,44 @@ 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 genLt(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}).lt(bigInt(${b})) ? 1 : 0`; +} + +function genGt(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}).gt(bigInt(${b})) ? 1 : 0`; +} + +function genLte(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}).lesserOrEquals(bigInt(${b})) ? 1 : 0`; +} + +function genGte(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}).greaterOrEquals(bigInt(${b})) ? 1 : 0`; } function genEq(ctx, ast) {
M test/circuits/sha256_2_test.circom → test/circuits/sha256_2_test.circom

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

component sha256_2 = Sha256_2(); sha256_2.a <== a; - sha256_2.b <== a; + sha256_2.b <== b; out <== sha256_2.out; }
A test/helpers/sha256.js

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

+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +/* SHA-256 (FIPS 180-4) implementation in JavaScript (c) Chris Veness 2002-2017 */ +/* MIT Licence */ +/* www.movable-type.co.uk/scripts/sha256.html */ +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +'use strict'; + + +/** + * SHA-256 hash function reference implementation. + * + * This is an annotated direct implementation of FIPS 180-4, without any optimisations. It is + * intended to aid understanding of the algorithm rather than for production use. + * + * While it could be used where performance is not critical, I would recommend using the ‘Web + * Cryptography API’ (developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest) for the browser, + * or the ‘crypto’ library (nodejs.org/api/crypto.html#crypto_class_hash) in Node.js. + * + * See csrc.nist.gov/groups/ST/toolkit/secure_hashing.html + * csrc.nist.gov/groups/ST/toolkit/examples.html + */ +class Sha256 { + + /** + * Generates SHA-256 hash of string. + * + * @param {string} msg - (Unicode) string to be hashed. + * @param {Object} [options] + * @param {string} [options.msgFormat=string] - Message format: 'string' for JavaScript string + * (gets converted to UTF-8 for hashing); 'hex-bytes' for string of hex bytes ('616263' ≡ 'abc') . + * @param {string} [options.outFormat=hex] - Output format: 'hex' for string of contiguous + * hex bytes; 'hex-w' for grouping hex bytes into groups of (4 byte / 8 character) words. + * @returns {string} Hash of msg as hex character string. + */ + static hash(msg, options) { + const defaults = { msgFormat: 'string', outFormat: 'hex' }; + const opt = Object.assign(defaults, options); + + // note use throughout this routine of 'n >>> 0' to coerce Number 'n' to unsigned 32-bit integer + + switch (opt.msgFormat) { + default: // default is to convert string to UTF-8, as SHA only deals with byte-streams + case 'string': msg = utf8Encode(msg); break; + case 'hex-bytes':msg = hexBytesToString(msg); break; // mostly for running tests + } + + // constants [§4.2.2] + const K = [ + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 ]; + + // initial hash value [§5.3.3] + const H = [ + 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 ]; + + // PREPROCESSING [§6.2.1] + + msg += String.fromCharCode(0x80); // add trailing '1' bit (+ 0's padding) to string [§5.1.1] + + // convert string msg into 512-bit blocks (array of 16 32-bit integers) [§5.2.1] + const l = msg.length/4 + 2; // length (in 32-bit integers) of msg + ‘1’ + appended length + const N = Math.ceil(l/16); // number of 16-integer (512-bit) blocks required to hold 'l' ints + const M = new Array(N); // message M is N×16 array of 32-bit integers + + for (let i=0; i<N; i++) { + M[i] = new Array(16); + for (let j=0; j<16; j++) { // encode 4 chars per integer (64 per block), big-endian encoding + M[i][j] = (msg.charCodeAt(i*64+j*4+0)<<24) | (msg.charCodeAt(i*64+j*4+1)<<16) + | (msg.charCodeAt(i*64+j*4+2)<< 8) | (msg.charCodeAt(i*64+j*4+3)<< 0); + } // note running off the end of msg is ok 'cos bitwise ops on NaN return 0 + } + // add length (in bits) into final pair of 32-bit integers (big-endian) [§5.1.1] + // note: most significant word would be (len-1)*8 >>> 32, but since JS converts + // bitwise-op args to 32 bits, we need to simulate this by arithmetic operators + const lenHi = ((msg.length-1)*8) / Math.pow(2, 32); + const lenLo = ((msg.length-1)*8) >>> 0; + M[N-1][14] = Math.floor(lenHi); + M[N-1][15] = lenLo; + + // HASH COMPUTATION [§6.2.2] + + for (let i=0; i<N; i++) { + const W = new Array(64); + + // 1 - prepare message schedule 'W' + for (let t=0; t<16; t++) W[t] = M[i][t]; + for (let t=16; t<64; t++) { + W[t] = (Sha256.σ1(W[t-2]) + W[t-7] + Sha256.σ0(W[t-15]) + W[t-16]) >>> 0; + } + + // 2 - initialise working variables a, b, c, d, e, f, g, h with previous hash value + let a = H[0], b = H[1], c = H[2], d = H[3], e = H[4], f = H[5], g = H[6], h = H[7]; + + // 3 - main loop (note '>>> 0' for 'addition modulo 2^32') + for (let t=0; t<64; t++) { + const T1 = h + Sha256.Σ1(e) + Sha256.Ch(e, f, g) + K[t] + W[t]; + const T2 = Sha256.Σ0(a) + Sha256.Maj(a, b, c); + h = g; + g = f; + f = e; + e = (d + T1) >>> 0; + d = c; + c = b; + b = a; + a = (T1 + T2) >>> 0; + } + + // 4 - compute the new intermediate hash value (note '>>> 0' for 'addition modulo 2^32') + H[0] = (H[0]+a) >>> 0; + H[1] = (H[1]+b) >>> 0; + H[2] = (H[2]+c) >>> 0; + H[3] = (H[3]+d) >>> 0; + H[4] = (H[4]+e) >>> 0; + H[5] = (H[5]+f) >>> 0; + H[6] = (H[6]+g) >>> 0; + H[7] = (H[7]+h) >>> 0; + } + + // convert H0..H7 to hex strings (with leading zeros) + for (let h=0; h<H.length; h++) H[h] = ('00000000'+H[h].toString(16)).slice(-8); + + // concatenate H0..H7, with separator if required + const separator = opt.outFormat=='hex-w' ? ' ' : ''; + + return H.join(separator); + + /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + + function utf8Encode(str) { + try { + return new TextEncoder().encode(str, 'utf-8').reduce((prev, curr) => prev + String.fromCharCode(curr), ''); + } catch (e) { // no TextEncoder available? + return unescape(encodeURIComponent(str)); // monsur.hossa.in/2012/07/20/utf-8-in-javascript.html + } + } + + function hexBytesToString(hexStr) { // convert string of hex numbers to a string of chars (eg '616263' -> 'abc'). + const str = hexStr.replace(' ', ''); // allow space-separated groups + return str=='' ? '' : str.match(/.{2}/g).map(byte => String.fromCharCode(parseInt(byte, 16))).join(''); + } + } + + + + /** + * Rotates right (circular right shift) value x by n positions [§3.2.4]. + * @private + */ + static ROTR(n, x) { + return (x >>> n) | (x << (32-n)); + } + + + /** + * Logical functions [§4.1.2]. + * @private + */ + static Σ0(x) { return Sha256.ROTR(2, x) ^ Sha256.ROTR(13, x) ^ Sha256.ROTR(22, x); } + static Σ1(x) { return Sha256.ROTR(6, x) ^ Sha256.ROTR(11, x) ^ Sha256.ROTR(25, x); } + static σ0(x) { return Sha256.ROTR(7, x) ^ Sha256.ROTR(18, x) ^ (x>>>3); } + static σ1(x) { return Sha256.ROTR(17, x) ^ Sha256.ROTR(19, x) ^ (x>>>10); } + static Ch(x, y, z) { return (x & y) ^ (~x & z); } // 'choice' + static Maj(x, y, z) { return (x & y) ^ (x & z) ^ (y & z); } // 'majority' + +} + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +if (typeof module != 'undefined' && module.exports) module.exports = Sha256; // ≡ export default Sha256 +
M test/sha256.js → test/sha256.js

@@ -7,6 +7,27 @@ 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); +} + describe("SHA256 test", () => { it("Should create a constant circuit", async () => {

@@ -38,17 +59,21 @@ const circuit = new zkSnark.Circuit(cirDef);

const witness = circuit.calculateWitness({ "a": "1", "b": "2" }); - const b = new Buffer.alloc(432); - b[115] = 1; - b[431] = 2; + const b = new Buffer.alloc(54); + b[26] = 1; + b[53] = 2; const hash = crypto.createHash("sha256") .update(b) .digest("hex"); - const r = "0x" + hash.slice(40); + const r = "0x" + hash.slice(10); + + const hash2 = sha256.hash(b.toString("hex"), {msgFormat: "hex-bytes"}); + + assert.equal(hash, hash2); assert(witness[1].equals(zkSnark.bigInt(r))); - }); + }).timeout(1000000); });
D test_old/commandline.js

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

-const path = require("path"); -const fs = require("fs"); -const cmd=require("node-cmd"); -const util = require("util"); -const assert = require("assert"); - -const claimUtils = require("../src/claimUtils.js"); - -cmd.get[util.promisify.custom] = (c) => { - return new Promise((resolve, reject) => { - cmd.get(c, (err, data, stderr) => { - if (err) { - reject(err); - } else { - resolve([data, stderr]); - } - }); - }); -}; - -const getAsync = util.promisify(cmd.get); -const mkdir = util.promisify(fs.mkdir); -const writeFile = util.promisify(fs.writeFile); - -describe("command line", () => { - - let tmpPath; - before(async () => { - tmpPath = path.join(__dirname, "..", "tmp"); - if (!fs.existsSync(tmpPath)) { - await mkdir(tmpPath, 0o744); - } - process.chdir(tmpPath); - }); - - it("Should create a tree from a claim files", async () => { - - let i; - let claims = []; - for (i=0; i<100; i++) { - const b = Buffer.from([ i / 256, i % 256 ]); - claims[i] = claimUtils.buildClaim("0x01", "0x02", "0x03", b).toString("hex"); - } - - claims = claims.sort(); - const claimsFile = path.join(tmpPath, "claims100.hex"); - const dbFile = path.join(tmpPath, "claims100.db"); - await writeFile(claimsFile, claims.join("\n"), "utf8"); - - await getAsync(`${path.join("..", "cli.js")} -d ${dbFile} add ${claimsFile} `); - - const data = await getAsync(`${path.join("..", "cli.js")} -d ${dbFile} export`); - let claims2 = data[0].split("\n"); - - claims2 = claims2.filter(function(n){ return n.length>0; }); - claims2 = claims2.sort(); - - assert.equal(claims2.join("\n"), claims.join("\n")); - - }).timeout(20000); -});
D test_old/jorge.prg

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

-1 * 2 * 3 -* 4
D test_old/mainTest.js

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

-const assert = require("assert"); - -const StaticMerkle = require("../src/StaticMerkle.js"); -const MemDB = require("../src/dbMem.js"); -const hash = require("../src/hashKeccak.js"); -const buffUtils = require("../src/buffUtils.js"); -const claimUtils = require("../src/claimUtils.js"); - -describe("static merkle", () => { - before(async () => { - - }); - - it("Create an empty tring of 0 levels", async () => { - const dbPrv0 = await MemDB(); - const SM0 = await StaticMerkle(hash, dbPrv0, 0); - const empty = SM0.root; - assert.equal(buffUtils.toHex(empty), "0x0000000000000000000000000000000000000000000000000000000000000000"); - }); - - it("create an empty", async () => { - const dbPrv = await MemDB(); - const SM140 = await StaticMerkle(hash, dbPrv, 140); - const empty = SM140.root; - assert.equal(buffUtils.toHex(empty), "0x0000000000000000000000000000000000000000000000000000000000000000"); - }); - - it("should add and remove a claim", async() => { - const dbPrv = await MemDB(); - const SM140 = await StaticMerkle(hash, dbPrv, 140); - const empty = SM140.root; - const claim = claimUtils.buildClaim("0x01", "0x02", "0x03", "0x04"); - await SM140.addClaim(claim); - assert.equal(buffUtils.toHex(SM140.root), "0xd3d9ad5e3c0b38c4e3eb411e9e3114b5ed8fb5c4bc69158329feb1a62743cda1"); - await SM140.removeClaim(claim); - assert.equal(buffUtils.toHex(SM140.root), buffUtils.toHex(empty)); - - assert.equal(SM140.tx.inserts.length, 0); - - }); - - it("should add two claims in different order and should be the same", async () => { - const dbPrv_1 = await MemDB(); - const SM140_1 = await StaticMerkle(hash, dbPrv_1, 140); - const dbPrv_2 = await MemDB(); - const SM140_2 = await StaticMerkle(hash, dbPrv_2, 140); - const empty = SM140_1.root; - const claim1 = claimUtils.buildClaim("0x01", "0x02", "0x03", "0x04"); - const claim2 = claimUtils.buildClaim("0x01", "0x02", "0x03", "0x05"); - - await SM140_1.addClaim(claim1); - await SM140_1.addClaim(claim2); - - await SM140_2.addClaim(claim2); - await SM140_2.addClaim(claim1); - - assert.equal(buffUtils.toHex(SM140_1.root), buffUtils.toHex(SM140_2.root)); - - await SM140_1.removeClaim(claim1); - await SM140_1.removeClaim(claim2); - assert.equal(buffUtils.toHex(SM140_1.root), buffUtils.toHex(empty)); - - await SM140_2.removeClaim(claim2); - await SM140_2.removeClaim(claim1); - assert.equal(buffUtils.toHex(SM140_2.root), buffUtils.toHex(empty)); - - }); - - it("should add 10 claims and remove them in different order", async () => { - const dbPrv = await MemDB(); - const SM140 = await StaticMerkle(hash, dbPrv, 140); - const empty = SM140.root; - const claims = []; - let i; - for (i=0; i<10; i++) { - const b = Buffer.from([ i / 256, i % 256 ]); - claims[i] = claimUtils.buildClaim("0x01", "0x02", "0x03", b); - } - - for (i=0;i<claims.length; i++) { - await SM140.addClaim(claims[i]); - } - - assert.equal(buffUtils.toHex(SM140.root), "0xb57c288d5c018c56610a3fb783062c9b199221734c8c5617795b57cbdbd4347f"); - - for (i=0;i<claims.length; i++) { - await SM140.removeClaim(claims[i]); - } - - assert.equal(buffUtils.toHex(SM140.root), buffUtils.toHex(empty)); - assert.equal(SM140.tx.inserts.length, 0); - }); - - it("Should give the same root when added a repeated claim", async () => { - const dbPrv = await MemDB(); - const SM140 = await StaticMerkle(hash, dbPrv, 140); - const empty = SM140.root; - const claims = []; - let i; - for (i=0; i<100; i++) { - const b = Buffer.from([ i % 10 ]); - claims[i] = claimUtils.buildClaim("0x01", "0x02", "0x03", b); - } - - for (i=0;i<claims.length; i++) { - await SM140.addClaim(claims[i]); - } - - assert.equal(buffUtils.toHex(SM140.root), "0xb57c288d5c018c56610a3fb783062c9b199221734c8c5617795b57cbdbd4347f"); - - for (i=0;i<claims.length; i++) { - await SM140.removeClaim(claims[i]); - } - - assert.equal(buffUtils.toHex(SM140.root), buffUtils.toHex(empty)); - assert.equal(SM140.tx.inserts.length, 0); - }).timeout(20000); - - it("Should create a merkle proof and verify it ok", async () => { - const dbPrv = await MemDB(); - const SM140 = await StaticMerkle(hash, dbPrv, 140); - const empty = SM140.root; - const claim1 = claimUtils.buildClaim("0x01", "0x02", "0x03", "0x04"); - const claim2 = claimUtils.buildClaim("0x01", "0x02", "0x03", "0x05"); - - await SM140.addClaim(claim1); - await SM140.addClaim(claim2); - - const mp = await SM140.getMerkeProof(claim1); - - assert.equal(SM140.checkClaim(SM140.root, claim1, mp), true); - assert.equal(SM140.checkClaim(empty, claim1, mp), false); - assert.equal(SM140.checkClaim(empty, claim2, mp), false); - - const mp1 = await SM140.getMerkeProof(claim1); - assert.equal(SM140.checkClaim(SM140.root, claim1, mp1), true); - const mp2 = await SM140.getMerkeProof(claim2); - assert.equal(SM140.checkClaim(SM140.root, claim2, mp2), true); - }); - -});
D test_old/test1.jaz

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

-11+12; 13; -14; 15; -/* Multi Line - comment */ -/*** / * /* **/ -// Single line comment /* sss */ -16; 0x1f; 0xAa; -12; id1; A; B; A+B; -A*B+A*B+3; -4/2; -4/3; -4/3*3; -8/2; -0/2; -2/1; -8 % 5; --1; +--1; -(3+4)*(5*2); -0xFF & 0x12; -1 << 8; --1 >> 257; --1 << 257; --1 >> 256; --1 << 256; --1 >> 250; --1 << 250; -33 == 33; -33 == 34; -3>3; -3>=3; -3<=3; -3<3; -3 && 0; -0 && 3; -3 && 3; -0 && 0; -!3; -!0; -!!8; -2**3; -(-1)**(-1); -a[3]; -a[3][b] + b[4][c][d]; -func() + func(a) + func(a,b); -3*4==6+6 && 2+1==3 ? 3+3*2 : (3+2)*6
D test_old/test10.jaz

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

-f(1,2)
D test_old/test11.jaz

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

-a+b*c -(a+b)*c -var c + a[1].b[2] + c -f(1,2) -component f(4) d; - -a++ + b++; - ---a;
D test_old/test12.jaz

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

-var a; -var b; -var c; -a+b*b[3+a][2]; -a<<2<=2>>a
D test_old/test13.jaz

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

-a <== b === c -r = a ? c ? 5 : 6 : b ? 3 : 4 -c = sqrt(a**2+b**2)
D test_old/test14.jaz

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

-(a + bb) + c; -include "filename.ext" -include "secondfile" -include "therdfile"; -include "4th file" -{ - include "fifthfile" -}
D test_old/test2.jaz

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

-{ - 3+3 - 4+4 - 5+5 -} -6 -7 -a <-- 3 -3 --> a; -signal input b <== 4; -4 ==> signal b; -c === d; -
D test_old/test3.jaz

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

-signal input b <== 3; -signal o[44] <-- 2; -a[1][2].b[3] <== 4 -function f(a,b) { - c=a+b; -} - -component b(b1,b2) { - b1 <== b2[3].pin[4] -}
D test_old/test4.jaz

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

-if (a) b; else c; -if (a) { - 1 -} else { - 2 -} -if (1) if(0) 1; else 2;
D test_old/test5.jaz

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

-var a=0; -for (i=0; i<10; i=i+1) { - a=a+1; -}
D test_old/test6.jaz

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

-++a; -a++; -b--; ---b; -a -- > 0; -0 < ++ b; -
D test_old/test7.jaz

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

-a=3 -a+=3 -a-=3 -a*=3 -a/=3 -a%=3 -a>>=3 -a<<=3 -a&=3 -a|=3 -a^=3
D test_old/test8.jaz

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

-while (1) { - a -} -do { - xx; -} while (1)
D test_old/test9.jaz

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

-function f() { - return 3; -} - -function ff(a) { - return 4; -} - -component c = s(a);