From 431a6919630f82ed007c4fda4ff5ffb23d6c4d2c Mon Sep 17 00:00:00 2001 From: Jordi Baylina Date: Fri, 14 Sep 2018 07:09:58 +0200 Subject: [PATCH] sha256 done --- circuits/sha256/rotate.circom | 2 +- circuits/sha256/sha256_2.circom | 37 +++-- circuits/sha256/sha256compression.circom | 115 ++++++++------- circuits/sha256/shift.circom | 14 ++ circuits/sha256/sigma.circom | 28 +++- circuits/sha256/sigmaplus.circom | 6 +- circuits/sha256/t1.circom | 26 ++-- circuits/sha256/t2.circom | 4 +- package.json | 4 +- src/exec.js | 101 ++++++++++++- src/gencode.js | 65 ++++++++- test/circuits/sha256_2_test.circom | 2 +- test/helpers/sha256.js | 178 +++++++++++++++++++++++ test/sha256.js | 35 ++++- test_old/commandline.js | 61 -------- test_old/jorge.prg | 2 - test_old/mainTest.js | 141 ------------------ test_old/test1.jaz | 45 ------ test_old/test10.jaz | 1 - test_old/test11.jaz | 9 -- test_old/test12.jaz | 5 - test_old/test13.jaz | 3 - test_old/test14.jaz | 8 - test_old/test2.jaz | 13 -- test_old/test3.jaz | 10 -- test_old/test4.jaz | 7 - test_old/test5.jaz | 4 - test_old/test6.jaz | 7 - test_old/test7.jaz | 11 -- test_old/test8.jaz | 6 - test_old/test9.jaz | 9 -- 31 files changed, 507 insertions(+), 452 deletions(-) create mode 100644 circuits/sha256/shift.circom create mode 100644 test/helpers/sha256.js delete mode 100644 test_old/commandline.js delete mode 100644 test_old/jorge.prg delete mode 100644 test_old/mainTest.js delete mode 100644 test_old/test1.jaz delete mode 100644 test_old/test10.jaz delete mode 100644 test_old/test11.jaz delete mode 100644 test_old/test12.jaz delete mode 100644 test_old/test13.jaz delete mode 100644 test_old/test14.jaz delete mode 100644 test_old/test2.jaz delete mode 100644 test_old/test3.jaz delete mode 100644 test_old/test4.jaz delete mode 100644 test_old/test5.jaz delete mode 100644 test_old/test6.jaz delete mode 100644 test_old/test7.jaz delete mode 100644 test_old/test8.jaz delete mode 100644 test_old/test9.jaz diff --git a/circuits/sha256/rotate.circom b/circuits/sha256/rotate.circom index f40b65b..567d4e9 100644 --- a/circuits/sha256/rotate.circom +++ b/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) { + out[i] <== 0; + } else { + out[i] <== in[ i+r ]; + } + } +} + diff --git a/circuits/sha256/sigma.circom b/circuits/sha256/sigma.circom index b9f2623..fcfeb4b 100644 --- a/circuits/sha256/sigma.circom +++ b/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); diff --git a/circuits/sha256/sigmaplus.circom b/circuits/sha256/sigmaplus.circom index c0d7c8b..749e220 100644 --- a/circuits/sha256/sigmaplus.circom +++ b/circuits/sha256/sigmaplus.circom @@ -8,9 +8,9 @@ template SigmaPlus() { 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]; diff --git a/circuits/sha256/t1.circom b/circuits/sha256/t1.circom index 944e81b..094edc1 100644 --- a/circuits/sha256/t1.circom +++ b/circuits/sha256/t1.circom @@ -11,23 +11,23 @@ template T1() { 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]; } } diff --git a/circuits/sha256/t2.circom b/circuits/sha256/t2.circom index 43b8aaf..02bff7b 100644 --- a/circuits/sha256/t2.circom +++ b/circuits/sha256/t2.circom @@ -8,9 +8,9 @@ template T2() { 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++) { diff --git a/package.json b/package.json index 43d0b07..35b8a06 100644 --- a/package.json +++ b/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 @@ "eslint": "^5.0.1", "eslint-plugin-mocha": "^5.0.0", "jison": "^0.4.18", - "zksnark": "0.0.5" + "zksnark": "0.0.6" } } diff --git a/src/exec.js b/src/exec.js index e573e1a..933a2a9 100644 --- a/src/exec.js +++ b/src/exec.js @@ -3,14 +3,14 @@ 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 @@ function exec(ctx, ast) { 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 @@ function exec(ctx, ast) { 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 @@ function exec(ctx, ast) { 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") { @@ -311,6 +321,8 @@ function execInstantiateComponet(ctx, vr, fn) { const vv = getScope(ctx, componentName, vr.selectors); + if (!vv) return error(ctx, vr, "Component not defined"+ componentName); + instantiateComponent(vv); function instantiateComponent(varVal) { @@ -486,7 +498,12 @@ function execDeclareVariable(ctx, ast) { } 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 @@ function execWhile(ctx, ast) { } } +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 @@ function execVarAssignement(ctx, ast) { 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 @@ function execLt(ctx, ast) { }; } +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 @@ function execShr(ctx, ast) { }; } +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; @@ -704,6 +792,7 @@ function execMul(ctx, ast) { return res; } + function execVarAddAssignement(ctx, ast) { const res = execAdd(ctx,{ values: [ast.values[0], ast.values[1]] } ); if (ctx.error) return; diff --git a/src/gencode.js b/src/gencode.js index 273a74f..4086011 100644 --- a/src/gencode.js +++ b/src/gencode.js @@ -3,14 +3,14 @@ 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 @@ function gen(ctx, ast) { 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 @@ function gen(ctx, ast) { 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 @@ function gen(ctx, ast) { 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 @@ function genFor(ctx, ast) { 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,9 +236,20 @@ function genWhile(ctx, ast) { 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); if (ctx.error) return; @@ -449,6 +470,14 @@ function genShr(ctx, ast) { 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; @@ -457,6 +486,30 @@ function genLt(ctx, ast) { 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) { const a = gen(ctx, ast.values[0]); if (ctx.error) return; diff --git a/test/circuits/sha256_2_test.circom b/test/circuits/sha256_2_test.circom index e2ac252..855423b 100644 --- a/test/circuits/sha256_2_test.circom +++ b/test/circuits/sha256_2_test.circom @@ -8,7 +8,7 @@ template Main() { component sha256_2 = Sha256_2(); sha256_2.a <== a; - sha256_2.b <== a; + sha256_2.b <== b; out <== sha256_2.out; } diff --git a/test/helpers/sha256.js b/test/helpers/sha256.js new file mode 100644 index 0000000..ec58ee1 --- /dev/null +++ b/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>> 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>> 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 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 + diff --git a/test/sha256.js b/test/sha256.js index bd1ba1f..6732127 100644 --- a/test/sha256.js +++ b/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 @@ describe("SHA256 test", () => { 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); }); diff --git a/test_old/commandline.js b/test_old/commandline.js deleted file mode 100644 index f66cea2..0000000 --- a/test_old/commandline.js +++ /dev/null @@ -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); -}); diff --git a/test_old/jorge.prg b/test_old/jorge.prg deleted file mode 100644 index 4e53322..0000000 --- a/test_old/jorge.prg +++ /dev/null @@ -1,2 +0,0 @@ -1 * 2 * 3 -* 4 diff --git a/test_old/mainTest.js b/test_old/mainTest.js deleted file mode 100644 index 26e5972..0000000 --- a/test_old/mainTest.js +++ /dev/null @@ -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 { - 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 { - 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); - }); - -}); diff --git a/test_old/test1.jaz b/test_old/test1.jaz deleted file mode 100644 index c441c84..0000000 --- a/test_old/test1.jaz +++ /dev/null @@ -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 diff --git a/test_old/test10.jaz b/test_old/test10.jaz deleted file mode 100644 index f71eac5..0000000 --- a/test_old/test10.jaz +++ /dev/null @@ -1 +0,0 @@ -f(1,2) diff --git a/test_old/test11.jaz b/test_old/test11.jaz deleted file mode 100644 index 344a216..0000000 --- a/test_old/test11.jaz +++ /dev/null @@ -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; diff --git a/test_old/test12.jaz b/test_old/test12.jaz deleted file mode 100644 index 39ff574..0000000 --- a/test_old/test12.jaz +++ /dev/null @@ -1,5 +0,0 @@ -var a; -var b; -var c; -a+b*b[3+a][2]; -a<<2<=2>>a diff --git a/test_old/test13.jaz b/test_old/test13.jaz deleted file mode 100644 index f055855..0000000 --- a/test_old/test13.jaz +++ /dev/null @@ -1,3 +0,0 @@ -a <== b === c -r = a ? c ? 5 : 6 : b ? 3 : 4 -c = sqrt(a**2+b**2) diff --git a/test_old/test14.jaz b/test_old/test14.jaz deleted file mode 100644 index 0d49333..0000000 --- a/test_old/test14.jaz +++ /dev/null @@ -1,8 +0,0 @@ -(a + bb) + c; -include "filename.ext" -include "secondfile" -include "therdfile"; -include "4th file" -{ - include "fifthfile" -} diff --git a/test_old/test2.jaz b/test_old/test2.jaz deleted file mode 100644 index e125ee0..0000000 --- a/test_old/test2.jaz +++ /dev/null @@ -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; - diff --git a/test_old/test3.jaz b/test_old/test3.jaz deleted file mode 100644 index 8dfeea5..0000000 --- a/test_old/test3.jaz +++ /dev/null @@ -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] -} diff --git a/test_old/test4.jaz b/test_old/test4.jaz deleted file mode 100644 index b5a587c..0000000 --- a/test_old/test4.jaz +++ /dev/null @@ -1,7 +0,0 @@ -if (a) b; else c; -if (a) { - 1 -} else { - 2 -} -if (1) if(0) 1; else 2; diff --git a/test_old/test5.jaz b/test_old/test5.jaz deleted file mode 100644 index d2b02ac..0000000 --- a/test_old/test5.jaz +++ /dev/null @@ -1,4 +0,0 @@ -var a=0; -for (i=0; i<10; i=i+1) { - a=a+1; -} diff --git a/test_old/test6.jaz b/test_old/test6.jaz deleted file mode 100644 index aa97ba0..0000000 --- a/test_old/test6.jaz +++ /dev/null @@ -1,7 +0,0 @@ -++a; -a++; -b--; ---b; -a -- > 0; -0 < ++ b; - diff --git a/test_old/test7.jaz b/test_old/test7.jaz deleted file mode 100644 index b17dca5..0000000 --- a/test_old/test7.jaz +++ /dev/null @@ -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 diff --git a/test_old/test8.jaz b/test_old/test8.jaz deleted file mode 100644 index c6a5bbb..0000000 --- a/test_old/test8.jaz +++ /dev/null @@ -1,6 +0,0 @@ -while (1) { - a -} -do { - xx; -} while (1) diff --git a/test_old/test9.jaz b/test_old/test9.jaz deleted file mode 100644 index 25dcaf9..0000000 --- a/test_old/test9.jaz +++ /dev/null @@ -1,9 +0,0 @@ -function f() { - return 3; -} - -function ff(a) { - return 4; -} - -component c = s(a);