@ -0,0 +1,43 @@ |
|||||
|
|
||||
|
|
||||
|
|
||||
|
template AND() { |
||||
|
signal input a; |
||||
|
signal input b; |
||||
|
signal output c; |
||||
|
|
||||
|
c <== a*b; |
||||
|
} |
||||
|
|
||||
|
template AND3() { |
||||
|
signal input in1; |
||||
|
signal input in2; |
||||
|
signal input in3; |
||||
|
signal output out; |
||||
|
|
||||
|
component and1 = AND(); |
||||
|
component and2 = AND(); |
||||
|
|
||||
|
in1 ==> and1.a; |
||||
|
in2 ==> and1.b; |
||||
|
in3 ==> and2.a; |
||||
|
and1.c ==> and2.b; |
||||
|
and2.c ==> out; |
||||
|
} |
||||
|
|
||||
|
template ToBin() { |
||||
|
signal input in; |
||||
|
signal output out[32]; |
||||
|
|
||||
|
var lc = 0; |
||||
|
|
||||
|
for (var i=0; i<32; i++) { |
||||
|
out[i] <-- (in >> i) & 1; |
||||
|
lc = lc + out[i] * 2**i; |
||||
|
out[i]*(out[i]-1) === 0; |
||||
|
} |
||||
|
|
||||
|
lc === in; |
||||
|
} |
||||
|
|
||||
|
component main = ToBin(); |
@ -0,0 +1,18 @@ |
|||||
|
include "constants.jaz" |
||||
|
|
||||
|
template A() { |
||||
|
signal input in; |
||||
|
component h0; |
||||
|
h0 = K(8); |
||||
|
|
||||
|
var lc = 0; |
||||
|
var e = 1; |
||||
|
for (var i=0; i<32; i++) { |
||||
|
lc = lc + e*h0.out[i]; |
||||
|
e *= 2; |
||||
|
} |
||||
|
|
||||
|
lc === in; |
||||
|
} |
||||
|
|
||||
|
component main = A(); |
@ -0,0 +1,290 @@ |
|||||
|
{ |
||||
|
"mainCode": "{\n {\n }\n}\n", |
||||
|
"signalName2Idx": { |
||||
|
"one": 0, |
||||
|
"main.in": 1, |
||||
|
"main.h0.out[0]": 2, |
||||
|
"main.h0.out[1]": 3, |
||||
|
"main.h0.out[2]": 4, |
||||
|
"main.h0.out[3]": 5, |
||||
|
"main.h0.out[4]": 6, |
||||
|
"main.h0.out[5]": 7, |
||||
|
"main.h0.out[6]": 8, |
||||
|
"main.h0.out[7]": 9, |
||||
|
"main.h0.out[8]": 10, |
||||
|
"main.h0.out[9]": 11, |
||||
|
"main.h0.out[10]": 12, |
||||
|
"main.h0.out[11]": 13, |
||||
|
"main.h0.out[12]": 14, |
||||
|
"main.h0.out[13]": 15, |
||||
|
"main.h0.out[14]": 16, |
||||
|
"main.h0.out[15]": 17, |
||||
|
"main.h0.out[16]": 18, |
||||
|
"main.h0.out[17]": 19, |
||||
|
"main.h0.out[18]": 20, |
||||
|
"main.h0.out[19]": 21, |
||||
|
"main.h0.out[20]": 22, |
||||
|
"main.h0.out[21]": 23, |
||||
|
"main.h0.out[22]": 24, |
||||
|
"main.h0.out[23]": 25, |
||||
|
"main.h0.out[24]": 26, |
||||
|
"main.h0.out[25]": 27, |
||||
|
"main.h0.out[26]": 28, |
||||
|
"main.h0.out[27]": 29, |
||||
|
"main.h0.out[28]": 30, |
||||
|
"main.h0.out[29]": 31, |
||||
|
"main.h0.out[30]": 32, |
||||
|
"main.h0.out[31]": 33 |
||||
|
}, |
||||
|
"components": [ |
||||
|
{ |
||||
|
"name": "main", |
||||
|
"params": {}, |
||||
|
"template": "A", |
||||
|
"inputSignals": 1 |
||||
|
}, |
||||
|
{ |
||||
|
"name": "main.h0", |
||||
|
"params": { |
||||
|
"x": "8" |
||||
|
}, |
||||
|
"template": "K", |
||||
|
"inputSignals": 0 |
||||
|
} |
||||
|
], |
||||
|
"componentName2Idx": { |
||||
|
"main": 0, |
||||
|
"main.h0": 1 |
||||
|
}, |
||||
|
"signals": [ |
||||
|
{ |
||||
|
"names": [ |
||||
|
"one" |
||||
|
], |
||||
|
"triggerComponents": [] |
||||
|
}, |
||||
|
{ |
||||
|
"names": [ |
||||
|
"main.in" |
||||
|
], |
||||
|
"triggerComponents": [ |
||||
|
0 |
||||
|
] |
||||
|
}, |
||||
|
{ |
||||
|
"names": [ |
||||
|
"main.h0.out[0]" |
||||
|
], |
||||
|
"triggerComponents": [] |
||||
|
}, |
||||
|
{ |
||||
|
"names": [ |
||||
|
"main.h0.out[1]" |
||||
|
], |
||||
|
"triggerComponents": [] |
||||
|
}, |
||||
|
{ |
||||
|
"names": [ |
||||
|
"main.h0.out[2]" |
||||
|
], |
||||
|
"triggerComponents": [] |
||||
|
}, |
||||
|
{ |
||||
|
"names": [ |
||||
|
"main.h0.out[3]" |
||||
|
], |
||||
|
"triggerComponents": [] |
||||
|
}, |
||||
|
{ |
||||
|
"names": [ |
||||
|
"main.h0.out[4]" |
||||
|
], |
||||
|
"triggerComponents": [] |
||||
|
}, |
||||
|
{ |
||||
|
"names": [ |
||||
|
"main.h0.out[5]" |
||||
|
], |
||||
|
"triggerComponents": [] |
||||
|
}, |
||||
|
{ |
||||
|
"names": [ |
||||
|
"main.h0.out[6]" |
||||
|
], |
||||
|
"triggerComponents": [] |
||||
|
}, |
||||
|
{ |
||||
|
"names": [ |
||||
|
"main.h0.out[7]" |
||||
|
], |
||||
|
"triggerComponents": [] |
||||
|
}, |
||||
|
{ |
||||
|
"names": [ |
||||
|
"main.h0.out[8]" |
||||
|
], |
||||
|
"triggerComponents": [] |
||||
|
}, |
||||
|
{ |
||||
|
"names": [ |
||||
|
"main.h0.out[9]" |
||||
|
], |
||||
|
"triggerComponents": [] |
||||
|
}, |
||||
|
{ |
||||
|
"names": [ |
||||
|
"main.h0.out[10]" |
||||
|
], |
||||
|
"triggerComponents": [] |
||||
|
}, |
||||
|
{ |
||||
|
"names": [ |
||||
|
"main.h0.out[11]" |
||||
|
], |
||||
|
"triggerComponents": [] |
||||
|
}, |
||||
|
{ |
||||
|
"names": [ |
||||
|
"main.h0.out[12]" |
||||
|
], |
||||
|
"triggerComponents": [] |
||||
|
}, |
||||
|
{ |
||||
|
"names": [ |
||||
|
"main.h0.out[13]" |
||||
|
], |
||||
|
"triggerComponents": [] |
||||
|
}, |
||||
|
{ |
||||
|
"names": [ |
||||
|
"main.h0.out[14]" |
||||
|
], |
||||
|
"triggerComponents": [] |
||||
|
}, |
||||
|
{ |
||||
|
"names": [ |
||||
|
"main.h0.out[15]" |
||||
|
], |
||||
|
"triggerComponents": [] |
||||
|
}, |
||||
|
{ |
||||
|
"names": [ |
||||
|
"main.h0.out[16]" |
||||
|
], |
||||
|
"triggerComponents": [] |
||||
|
}, |
||||
|
{ |
||||
|
"names": [ |
||||
|
"main.h0.out[17]" |
||||
|
], |
||||
|
"triggerComponents": [] |
||||
|
}, |
||||
|
{ |
||||
|
"names": [ |
||||
|
"main.h0.out[18]" |
||||
|
], |
||||
|
"triggerComponents": [] |
||||
|
}, |
||||
|
{ |
||||
|
"names": [ |
||||
|
"main.h0.out[19]" |
||||
|
], |
||||
|
"triggerComponents": [] |
||||
|
}, |
||||
|
{ |
||||
|
"names": [ |
||||
|
"main.h0.out[20]" |
||||
|
], |
||||
|
"triggerComponents": [] |
||||
|
}, |
||||
|
{ |
||||
|
"names": [ |
||||
|
"main.h0.out[21]" |
||||
|
], |
||||
|
"triggerComponents": [] |
||||
|
}, |
||||
|
{ |
||||
|
"names": [ |
||||
|
"main.h0.out[22]" |
||||
|
], |
||||
|
"triggerComponents": [] |
||||
|
}, |
||||
|
{ |
||||
|
"names": [ |
||||
|
"main.h0.out[23]" |
||||
|
], |
||||
|
"triggerComponents": [] |
||||
|
}, |
||||
|
{ |
||||
|
"names": [ |
||||
|
"main.h0.out[24]" |
||||
|
], |
||||
|
"triggerComponents": [] |
||||
|
}, |
||||
|
{ |
||||
|
"names": [ |
||||
|
"main.h0.out[25]" |
||||
|
], |
||||
|
"triggerComponents": [] |
||||
|
}, |
||||
|
{ |
||||
|
"names": [ |
||||
|
"main.h0.out[26]" |
||||
|
], |
||||
|
"triggerComponents": [] |
||||
|
}, |
||||
|
{ |
||||
|
"names": [ |
||||
|
"main.h0.out[27]" |
||||
|
], |
||||
|
"triggerComponents": [] |
||||
|
}, |
||||
|
{ |
||||
|
"names": [ |
||||
|
"main.h0.out[28]" |
||||
|
], |
||||
|
"triggerComponents": [] |
||||
|
}, |
||||
|
{ |
||||
|
"names": [ |
||||
|
"main.h0.out[29]" |
||||
|
], |
||||
|
"triggerComponents": [] |
||||
|
}, |
||||
|
{ |
||||
|
"names": [ |
||||
|
"main.h0.out[30]" |
||||
|
], |
||||
|
"triggerComponents": [] |
||||
|
}, |
||||
|
{ |
||||
|
"names": [ |
||||
|
"main.h0.out[31]" |
||||
|
], |
||||
|
"triggerComponents": [] |
||||
|
} |
||||
|
], |
||||
|
"constrains": [ |
||||
|
[ |
||||
|
{}, |
||||
|
{}, |
||||
|
{ |
||||
|
"0": "21888242871839275222246405745257275088548364400416034343698204186572184114537", |
||||
|
"1": "1" |
||||
|
} |
||||
|
] |
||||
|
], |
||||
|
"templates": { |
||||
|
"H": "function(ctx) {\n ctx.setVar(\"c\", [], [\"1779033703\",\"3144134277\",\"1013904242\",\"2773480762\",\"1359893119\",\"2600822924\",\"528734635\",\"1541459225\"]);\n for (ctx.setVar(\"i\", [], \"0\");bigInt(ctx.getVar(\"i\",[])).lt(bigInt(\"32\")) ? 1 : 0;(ctx.setVar(\"i\", [], bigInt(ctx.getVar(\"i\",[])).add(bigInt(\"1\")).mod(__P__))).add(__P__).sub(bigInt(1)).mod(__P__))\n {\n ctx.setSignal(\"out\", [ctx.getVar(\"i\",[])], bigInt(bigInt(ctx.getVar(\"i\",[])).greater(bigInt(256)) ? 0 : bigInt(ctx.getVar(\"c\",[ctx.getVar(\"x\",[])])).shr(bigInt(ctx.getVar(\"i\",[]))).and(__MASK__)).and(bigInt(\"1\")).and(__MASK__));\n ctx.assert(ctx.getSignal(\"out\", [ctx.getVar(\"i\",[])]), bigInt(bigInt(ctx.getVar(\"i\",[])).greater(bigInt(256)) ? 0 : bigInt(ctx.getVar(\"c\",[ctx.getVar(\"x\",[])])).shr(bigInt(ctx.getVar(\"i\",[]))).and(__MASK__)).and(bigInt(\"1\")).and(__MASK__));\n }\n}\n", |
||||
|
"K": "function(ctx) {\n ctx.setVar(\"c\", [], [\"1116352408\",\"1899447441\",\"3049323471\",\"3921009573\",\"961987163\",\"1508970993\",\"2453635748\",\"2870763221\",\"3624381080\",\"310598401\",\"607225278\",\"1426881987\",\"1925078388\",\"2162078206\",\"2614888103\",\"3248222580\",\"3835390401\",\"4022224774\",\"264347078\",\"604807628\",\"770255983\",\"1249150122\",\"1555081692\",\"1996064986\",\"2554220882\",\"2821834349\",\"2952996808\",\"3210313671\",\"3336571891\",\"3584528711\",\"113926993\",\"338241895\",\"666307205\",\"773529912\",\"1294757372\",\"1396182291\",\"1695183700\",\"1986661051\",\"2177026350\",\"2456956037\",\"2730485921\",\"2820302411\",\"3259730800\",\"3345764771\",\"3516065817\",\"3600352804\",\"4094571909\",\"275423344\",\"430227734\",\"506948616\",\"659060556\",\"883997877\",\"958139571\",\"1322822218\",\"1537002063\",\"1747873779\",\"1955562222\",\"2024104815\",\"2227730452\",\"2361852424\",\"2428436474\",\"2756734187\",\"3204031479\",\"3329325298\"]);\n for (ctx.setVar(\"i\", [], \"0\");bigInt(ctx.getVar(\"i\",[])).lt(bigInt(\"32\")) ? 1 : 0;(ctx.setVar(\"i\", [], bigInt(ctx.getVar(\"i\",[])).add(bigInt(\"1\")).mod(__P__))).add(__P__).sub(bigInt(1)).mod(__P__))\n {\n ctx.setSignal(\"out\", [ctx.getVar(\"i\",[])], bigInt(bigInt(ctx.getVar(\"i\",[])).greater(bigInt(256)) ? 0 : bigInt(ctx.getVar(\"c\",[ctx.getVar(\"x\",[])])).shr(bigInt(ctx.getVar(\"i\",[]))).and(__MASK__)).and(bigInt(\"1\")).and(__MASK__));\n ctx.assert(ctx.getSignal(\"out\", [ctx.getVar(\"i\",[])]), bigInt(bigInt(ctx.getVar(\"i\",[])).greater(bigInt(256)) ? 0 : bigInt(ctx.getVar(\"c\",[ctx.getVar(\"x\",[])])).shr(bigInt(ctx.getVar(\"i\",[]))).and(__MASK__)).and(bigInt(\"1\")).and(__MASK__));\n }\n}\n", |
||||
|
"A": "function(ctx) {\n ctx.setVar(\"lc\", [], \"0\");\n ctx.setVar(\"e\", [], \"1\");\n for (ctx.setVar(\"i\", [], \"0\");bigInt(ctx.getVar(\"i\",[])).lt(bigInt(\"32\")) ? 1 : 0;(ctx.setVar(\"i\", [], bigInt(ctx.getVar(\"i\",[])).add(bigInt(\"1\")).mod(__P__))).add(__P__).sub(bigInt(1)).mod(__P__))\n {\n ctx.setVar(\"lc\", [], bigInt(ctx.getVar(\"lc\",[])).add(bigInt(bigInt(ctx.getVar(\"e\",[])).mul(bigInt(ctx.getPin(\"h0\", [], \"out\", [ctx.getVar(\"i\",[])]))).mod(__P__))).mod(__P__));\n ctx.setVar(\"e\", [], bigInt(ctx.getVar(\"e\",[])).mul(bigInt(\"2\")).mod(__P__));\n }\n ctx.assert(ctx.getVar(\"lc\",[]), ctx.getSignal(\"in\", []));\n}\n" |
||||
|
}, |
||||
|
"functions": {}, |
||||
|
"nPrvInputs": 0, |
||||
|
"nPubInputs": 1, |
||||
|
"nInputs": 1, |
||||
|
"nOutputs": 0, |
||||
|
"nVars": 2, |
||||
|
"nConstants": 32, |
||||
|
"nSignals": 34 |
||||
|
} |
@ -0,0 +1 @@ |
|||||
|
module.exports = require("./src/compiler.js"); |
@ -0,0 +1,3 @@ |
|||||
|
{ |
||||
|
"in": "10" |
||||
|
} |
@ -0,0 +1 @@ |
|||||
|
["1","10","0","1","0","1","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0"] |
@ -1,209 +0,0 @@ |
|||||
const bigInt = require("big-integer"); |
|
||||
|
|
||||
module.exports = calculateWitness; |
|
||||
|
|
||||
function calculateWitness(circuit, inputSignals) { |
|
||||
const ctx = new RTCtx(circuit); |
|
||||
|
|
||||
function iterateSelector(values, sels, cb) { |
|
||||
if (!Array.isArray(values)) { |
|
||||
return cb(sels, values); |
|
||||
} |
|
||||
for (let i=0; i<values.length; i++) { |
|
||||
sels.push(i); |
|
||||
iterateSelector(values[i], sels, cb); |
|
||||
sels.pop(i); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
ctx.setSignal("one", [], bigInt(1)); |
|
||||
|
|
||||
for (let c in ctx.notInitSignals) { |
|
||||
if (ctx.notInitSignals[c] == 0) ctx.triggerComponent(c); |
|
||||
} |
|
||||
|
|
||||
for (let s in inputSignals) { |
|
||||
ctx.currentComponent = "main"; |
|
||||
iterateSelector(inputSignals[s], [], function(selector, value) { |
|
||||
ctx.setSignal(s, selector, bigInt(value)); |
|
||||
}); |
|
||||
} |
|
||||
|
|
||||
for (let i=0; i<ctx.witness.length; i++) { |
|
||||
if (typeof(ctx.witness[i]) == "undefined") { |
|
||||
throw("Signal not assigned: " + ctx.circuit.witnessNames[i].join(", ")); |
|
||||
} |
|
||||
console.log(ctx.circuit.witnessNames[i].join(",") + " --> " + ctx.witness[i].toString()); |
|
||||
} |
|
||||
return ctx.witness; |
|
||||
} |
|
||||
|
|
||||
class RTCtx { |
|
||||
constructor(circuit) { |
|
||||
this.scopes = []; |
|
||||
this.circuit = circuit; |
|
||||
this.witness = []; |
|
||||
this.notInitSignals = {}; |
|
||||
for (let c in this.circuit.components) { |
|
||||
this.notInitSignals[c] = this.circuit.components[c].inputSignals; |
|
||||
if (this.notInitSignals == 0) { |
|
||||
this.currentComponent = c; |
|
||||
this.components.calc(this); |
|
||||
this.currentComponent = null; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
_sels2str(sels) { |
|
||||
let res = ""; |
|
||||
for (let i=0; i<sels.length; i++) { |
|
||||
res += `[${sels[i]}]`; |
|
||||
} |
|
||||
return res; |
|
||||
} |
|
||||
|
|
||||
setPin(componentName, componentSels, signalName, signalSels, value) { |
|
||||
let fullName = componentName=="one" ? "one" : this.currentComponent + "." + componentName; |
|
||||
fullName += this._sels2str(componentSels) + |
|
||||
"."+ |
|
||||
signalName+ |
|
||||
this._sels2str(signalSels); |
|
||||
this.setSignalFullName(fullName, value); |
|
||||
} |
|
||||
|
|
||||
setSignal(name, sels, value) { |
|
||||
let fullName = this.currentComponent ? this.currentComponent + "." + name : name; |
|
||||
fullName += this._sels2str(sels); |
|
||||
this.setSignalFullName(fullName, value); |
|
||||
} |
|
||||
|
|
||||
triggerComponent(c) { |
|
||||
console.log("Component Treiggered: " + c); |
|
||||
|
|
||||
// Set notInitSignals to -1 to not initialize again
|
|
||||
this.notInitSignals[c] --; |
|
||||
const oldComponent = this.currentComponent; |
|
||||
this.currentComponent = c; |
|
||||
const template = this.circuit.components[c].template; |
|
||||
|
|
||||
const newScope = {}; |
|
||||
for (let p in this.circuit.components[c].params) { |
|
||||
newScope[p] = this.circuit.components[c].params[p]; |
|
||||
} |
|
||||
|
|
||||
const oldScope = this.scopes; |
|
||||
this.scopes = [ this.scopes[0], newScope ]; |
|
||||
|
|
||||
// TODO set params.
|
|
||||
|
|
||||
this.circuit.templates[template](this); |
|
||||
this.scopes = oldScope; |
|
||||
this.currentComponent = oldComponent; |
|
||||
} |
|
||||
|
|
||||
callFunction(functionName, params) { |
|
||||
|
|
||||
const newScope = {}; |
|
||||
for (let p=0; p<this.circuit.functionParams[functionName].length; p++) { |
|
||||
const paramName = this.circuit.functionParams[functionName][p]; |
|
||||
newScope[paramName] = params[p]; |
|
||||
} |
|
||||
|
|
||||
const oldScope = this.scopes; |
|
||||
this.scopes = [ this.scopes[0], newScope ]; |
|
||||
|
|
||||
// TODO set params.
|
|
||||
|
|
||||
const res = this.circuit.functions[functionName](this); |
|
||||
this.scopes = oldScope; |
|
||||
|
|
||||
return res; |
|
||||
} |
|
||||
|
|
||||
setSignalFullName(fullName, value) { |
|
||||
console.log("set " + fullName + " <-- " + value.toString()); |
|
||||
const sId = this.circuit.signals[fullName].id; |
|
||||
let firstInit =false; |
|
||||
if (!this.witness[sId]) { |
|
||||
firstInit = true; |
|
||||
} |
|
||||
this.witness[sId] = value; |
|
||||
const callComponents = []; |
|
||||
for (let i=0; i<this.circuit.witnessNames[sId].length; i++) { |
|
||||
const ss = this.circuit.witnessNames[sId][i]; |
|
||||
if (this.circuit.signals[ss].direction == "IN") { |
|
||||
if (firstInit) this.notInitSignals[ this.circuit.signals[ss].component] --; |
|
||||
callComponents.push(this.circuit.signals[ss].component); |
|
||||
} |
|
||||
} |
|
||||
for (let i in callComponents) { |
|
||||
const c= callComponents[i]; |
|
||||
if (this.notInitSignals[c] == 0) this.triggerComponent(c); |
|
||||
} |
|
||||
return value; |
|
||||
} |
|
||||
|
|
||||
setVar(name, sels, value) { |
|
||||
function setVarArray(a, sels2, value) { |
|
||||
if (sels2.length == 1) { |
|
||||
a[sels2[0]] = value; |
|
||||
} else { |
|
||||
if (typeof(a[sels2[0]]) == "undefined") a[sels2[0]] = []; |
|
||||
setVarArray(a[sels2[0]], sels2.slice(1), value); |
|
||||
} |
|
||||
} |
|
||||
const scope = this.scopes[this.scopes.length-1]; |
|
||||
if (sels.length == 0) { |
|
||||
scope[name] = value; |
|
||||
} else { |
|
||||
if (typeof(scope[name]) == "undefined") scope[name] = []; |
|
||||
setVarArray(scope[name], sels, value); |
|
||||
} |
|
||||
return value; |
|
||||
} |
|
||||
|
|
||||
getVar(name, sels) { |
|
||||
function select(a, sels2) { |
|
||||
return (sels2.length == 0) ? a : select(a[sels2[0]], sels2.slice(1)); |
|
||||
} |
|
||||
for (let i=this.scopes.length-1; i>=0; i--) { |
|
||||
if (typeof(this.scopes[i][name]) != "undefined") return select(this.scopes[i][name], sels); |
|
||||
} |
|
||||
throw new Error("Variable not defined: " + name); |
|
||||
} |
|
||||
|
|
||||
getSignal(name, sels) { |
|
||||
let fullName = name=="one" ? "one" : this.currentComponent + "." + name; |
|
||||
fullName += this._sels2str(sels); |
|
||||
return this.getSignalFullName(fullName); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
getPin(componentName, componentSels, signalName, signalSels) { |
|
||||
let fullName = componentName=="one" ? "one" : this.currentComponent + "." + componentName; |
|
||||
fullName += this._sels2str(componentSels) + |
|
||||
"."+ |
|
||||
signalName+ |
|
||||
this._sels2str(signalSels); |
|
||||
return this.getSignalFullName(fullName); |
|
||||
} |
|
||||
|
|
||||
getSignalFullName(fullName) { |
|
||||
const sId = this.circuit.signals[fullName].id; |
|
||||
if (typeof(this.witness[sId]) == "undefined") { |
|
||||
throw new Error("Signal not initialized: "+fullName); |
|
||||
} |
|
||||
console.log("get --->" + fullName + " = " + this.witness[sId].toString() ); |
|
||||
return this.witness[sId]; |
|
||||
} |
|
||||
|
|
||||
assert(a,b) { |
|
||||
const ba = bigInt(a); |
|
||||
const bb = bigInt(b); |
|
||||
if (!ba.equals(bb)) { |
|
||||
throw new Error("Constrain doesn't match: " + ba.toString() + " != " + bb.toString()); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
|
|
||||
} |
|
@ -1,156 +0,0 @@ |
|||||
|
|
||||
const fs = require("fs"); |
|
||||
const path = require("path"); |
|
||||
const bigInt = require("big-integer"); |
|
||||
const __P__ = new bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617"); |
|
||||
const __MASK__ = new bigInt(2).pow(253).minus(1); |
|
||||
const assert = require("assert"); |
|
||||
const gen = require("./gencode"); |
|
||||
const exec = require("./exec"); |
|
||||
const lc = require("./lcalgebra"); |
|
||||
|
|
||||
|
|
||||
const argv = require("optimist") |
|
||||
.alias("c", "circuit") |
|
||||
.alias("o", "output") |
|
||||
.alias("w", "witnes") |
|
||||
.argv; |
|
||||
|
|
||||
const parser = require("../jaz.js").parser; |
|
||||
|
|
||||
const fullFileName = path.resolve(process.cwd(), argv.circuit); |
|
||||
const fullFilePath = path.dirname(fullFileName); |
|
||||
|
|
||||
const src = fs.readFileSync(fullFileName, "utf8"); |
|
||||
const ast = parser.parse(src); |
|
||||
|
|
||||
assert(ast.type == "BLOCK"); |
|
||||
|
|
||||
const ctx = { |
|
||||
scopes: [{}], |
|
||||
signals: { |
|
||||
one: { |
|
||||
fullName: "one", |
|
||||
value: bigInt(1), |
|
||||
equivalence: "", |
|
||||
direction: "" |
|
||||
} |
|
||||
}, |
|
||||
currentComponent: "", |
|
||||
constrains: [], |
|
||||
components: {}, |
|
||||
templates: {}, |
|
||||
functions: {}, |
|
||||
functionParams: {}, |
|
||||
filePath: fullFilePath, |
|
||||
fileName: fullFileName |
|
||||
}; |
|
||||
|
|
||||
exec(ctx, ast); |
|
||||
|
|
||||
reduceConstrains(ctx); |
|
||||
generateWitnessNames(ctx); |
|
||||
generateWitnessConstrains(ctx); |
|
||||
|
|
||||
if (ctx.error) { |
|
||||
console.log(`ERROR at ${ctx.error.errFile}:${ctx.error.pos.first_line},${ctx.error.pos.first_column}-${ctx.error.pos.last_line},${ctx.error.pos.last_column} ${ctx.error.errStr}`); |
|
||||
console.log(JSON.stringify(ctx.error.ast, null, 1)); |
|
||||
process.exit(1); |
|
||||
} |
|
||||
|
|
||||
/* |
|
||||
console.log("SIGNALS"); |
|
||||
console.log("=========="); |
|
||||
for (let key in ctx.signals) { |
|
||||
const signal = ctx.signals[key]; |
|
||||
console.log(signal.fullName); |
|
||||
} |
|
||||
|
|
||||
console.log("CONSTRAINS"); |
|
||||
console.log("=========="); |
|
||||
for (let i=0; i<ctx.constrains.length; i++) { |
|
||||
console.log(lc.toString(ctx.constrains[i], ctx) + " === 0"); |
|
||||
} |
|
||||
*/ |
|
||||
ctx.scopes = [{}]; |
|
||||
|
|
||||
const mainCode = gen(ctx,ast); |
|
||||
if (ctx.error) { |
|
||||
console.log(`ERROR at ${ctx.error.pos.first_line},${ctx.error.pos.first_column}-${ctx.error.pos.last_line},${ctx.error.pos.last_column} ${ctx.error.errStr}`); |
|
||||
console.log(JSON.stringify(ctx.error.ast, null, 1)); |
|
||||
process.exit(1); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
let outCode = ""; |
|
||||
outCode += "const bigInt = require(\"big-integer\");\n"; |
|
||||
outCode += "const __P__ = new bigInt(\"21888242871839275222246405745257275088696311157297823662689037894645226208583\");\n"; |
|
||||
outCode += "const __MASK__ = new bigInt(2).pow(253).minus(1);\n"; |
|
||||
outCode += "const circuit = {};\n"; |
|
||||
outCode += "module.exports = circuit;\n\n"; |
|
||||
outCode += `circuit.signals=${JSON.stringify(ctx.signals, null, 1)};\n\n`; |
|
||||
outCode += `circuit.components=${JSON.stringify(ctx.components, null, 1)};\n\n`; |
|
||||
outCode += `circuit.signalConstrains=${JSON.stringify(ctx.constrains, null, 1)};\n\n`; |
|
||||
outCode += `circuit.witnessNames=${JSON.stringify(ctx.witnessNames, null, 1)};\n\n`; |
|
||||
outCode += mainCode; |
|
||||
outCode += "\ncircuit.templates = {};\n"; |
|
||||
for (let t in ctx.templates) { |
|
||||
outCode += `\ncircuit.templates["${t}"] = ${ctx.templates[t]};\n`; |
|
||||
} |
|
||||
outCode += `circuit.functionParams=${JSON.stringify(ctx.functionParams, null, 1)};\n\n`; |
|
||||
outCode += "\ncircuit.functions = {};\n"; |
|
||||
for (let f in ctx.functions) { |
|
||||
outCode += `\ncircuit.functions["${f}"] = ${ctx.functions[f]};\n`; |
|
||||
} |
|
||||
|
|
||||
/* |
|
||||
console.log("CODE"); |
|
||||
console.log("===="); |
|
||||
console.log(outCode); |
|
||||
*/ |
|
||||
|
|
||||
|
|
||||
console.log("#Constrains:" +ctx.constrains.length); |
|
||||
|
|
||||
fs.writeFileSync(argv.output, outCode, "utf8"); |
|
||||
|
|
||||
function generateWitnessNames(ctx) { |
|
||||
ctx.witnessNames = []; |
|
||||
for (let c in ctx.components) { |
|
||||
ctx.components[c].inputSignals = 0; |
|
||||
} |
|
||||
for (let s in ctx.signals) { |
|
||||
const signal = ctx.signals[s]; |
|
||||
let lSignal = signal; |
|
||||
while (lSignal.equivalence) { |
|
||||
lSignal = ctx.signals[lSignal.equivalence]; |
|
||||
} |
|
||||
if ( typeof(lSignal.id) === "undefined" ) { |
|
||||
lSignal.id = ctx.witnessNames.length; |
|
||||
ctx.witnessNames.push([]); |
|
||||
} |
|
||||
if (signal.direction == "IN") { |
|
||||
ctx.components[signal.component].inputSignals++; |
|
||||
} |
|
||||
|
|
||||
signal.id = lSignal.id; |
|
||||
ctx.witnessNames[signal.id].push(signal.fullName); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
function reduceConstrains(ctx) { |
|
||||
const newConstrains = []; |
|
||||
for (let i=0; i<ctx.constrains.length; i++) { |
|
||||
const c = lc.canonize(ctx, ctx.constrains[i]); |
|
||||
if (!lc.isZero(c)) { |
|
||||
newConstrains.push(c); |
|
||||
} |
|
||||
} |
|
||||
ctx.constrains = newConstrains; |
|
||||
} |
|
||||
|
|
||||
function generateWitnessConstrains(ctx) { |
|
||||
|
|
||||
} |
|
||||
|
|
||||
|
|
@ -0,0 +1,27 @@ |
|||||
|
/* eslint-disable no-console */ |
||||
|
|
||||
|
const fs = require("fs"); |
||||
|
const path = require("path"); |
||||
|
|
||||
|
const compiler = require("./compiler"); |
||||
|
|
||||
|
const argv = require("yargs") |
||||
|
.usage("jaz -s [input source circuit file] -o [output definition circuit file]") |
||||
|
.alias("s", "source") |
||||
|
.alias("o", "output") |
||||
|
.require(["s","o"]) |
||||
|
.argv; |
||||
|
|
||||
|
const fullFileName = path.resolve(process.cwd(), argv.source); |
||||
|
|
||||
|
compiler(fullFileName).then( (cir) => { |
||||
|
fs.writeFileSync(argv.output, JSON.stringify(cir, null, 1), "utf8"); |
||||
|
}, (err) => { |
||||
|
console.error(`ERROR at ${err.errFile}:${err.pos.first_line},${err.pos.first_column}-${err.pos.last_line},${err.pos.last_column} ${err.errStr}`); |
||||
|
console.error(JSON.stringify(err.ast, null, 1)); |
||||
|
process.exit(1); |
||||
|
}); |
||||
|
|
||||
|
|
||||
|
|
||||
|
|
@ -0,0 +1,279 @@ |
|||||
|
|
||||
|
const fs = require("fs"); |
||||
|
const path = require("path"); |
||||
|
const bigInt = require("big-integer"); |
||||
|
const __P__ = new bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617"); |
||||
|
const __MASK__ = new bigInt(2).pow(253).minus(1); |
||||
|
const assert = require("assert"); |
||||
|
const gen = require("./gencode"); |
||||
|
const exec = require("./exec"); |
||||
|
const lc = require("./lcalgebra"); |
||||
|
|
||||
|
module.exports = compile; |
||||
|
|
||||
|
const parser = require("../jaz.js").parser; |
||||
|
|
||||
|
function compile(srcFile) { |
||||
|
|
||||
|
return new Promise ((resolve, reject) => { |
||||
|
const fullFileName = srcFile; |
||||
|
const fullFilePath = path.dirname(fullFileName); |
||||
|
|
||||
|
const src = fs.readFileSync(fullFileName, "utf8"); |
||||
|
const ast = parser.parse(src); |
||||
|
|
||||
|
assert(ast.type == "BLOCK"); |
||||
|
|
||||
|
const ctx = { |
||||
|
scopes: [{}], |
||||
|
signals: { |
||||
|
one: { |
||||
|
fullName: "one", |
||||
|
value: bigInt(1), |
||||
|
equivalence: "", |
||||
|
direction: "" |
||||
|
} |
||||
|
}, |
||||
|
currentComponent: "", |
||||
|
constrains: [], |
||||
|
components: {}, |
||||
|
templates: {}, |
||||
|
functions: {}, |
||||
|
functionParams: {}, |
||||
|
filePath: fullFilePath, |
||||
|
fileName: fullFileName |
||||
|
}; |
||||
|
|
||||
|
exec(ctx, ast); |
||||
|
|
||||
|
reduceConstrains(ctx); |
||||
|
generateWitnessNames(ctx); |
||||
|
|
||||
|
if (ctx.error) { |
||||
|
reject(ctx.error); |
||||
|
} |
||||
|
|
||||
|
ctx.scopes = [{}]; |
||||
|
|
||||
|
const mainCode = gen(ctx,ast); |
||||
|
if (ctx.error) reject(ctx.error); |
||||
|
|
||||
|
const def = buildCircuitDef(ctx, mainCode); |
||||
|
|
||||
|
resolve(def); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
function generateWitnessNames(ctx) { |
||||
|
|
||||
|
const totals = { |
||||
|
"output": 0, |
||||
|
"pubInput": 0, |
||||
|
"one": 0, |
||||
|
"prvInput": 0, |
||||
|
"internal": 0, |
||||
|
"constant": 0, |
||||
|
}; |
||||
|
const ids = {}; |
||||
|
|
||||
|
function priorize(t1, t2) { |
||||
|
if ((t1 == "error") || (t2=="error")) return "error"; |
||||
|
if (t1 == "internal") { |
||||
|
return t2; |
||||
|
} else if (t2=="internal") { |
||||
|
return t1; |
||||
|
} |
||||
|
if ((t1 == "one") || (t2 == "one")) return "one"; |
||||
|
if ((t1 == "constant") || (t2 == "constant")) return "constant"; |
||||
|
if (t1!=t2) return "error"; |
||||
|
return t1; |
||||
|
} |
||||
|
|
||||
|
// First classify the signals
|
||||
|
for (let s in ctx.signals) { |
||||
|
const signal = ctx.signals[s]; |
||||
|
let tAll = "internal"; |
||||
|
let lSignal = signal; |
||||
|
let end = false; |
||||
|
while (!end) { |
||||
|
let t = lSignal.category || "internal"; |
||||
|
if (s == "one") { |
||||
|
t = "one"; |
||||
|
} else if (lSignal.value) { |
||||
|
t = "constant"; |
||||
|
} else if (lSignal.component=="main") { |
||||
|
if (lSignal.direction == "IN") { |
||||
|
if (lSignal.private) { |
||||
|
t = "prvInput"; |
||||
|
} else { |
||||
|
t = "pubInput"; |
||||
|
} |
||||
|
} else if (lSignal.direction == "OUT") { |
||||
|
t = "output"; |
||||
|
} |
||||
|
} |
||||
|
tAll = priorize(t,tAll); |
||||
|
if (lSignal.equivalence) { |
||||
|
lSignal = ctx.signals[lSignal.equivalence]; |
||||
|
} else { |
||||
|
end=true; |
||||
|
} |
||||
|
} |
||||
|
if (tAll == "error") { |
||||
|
throw new Error("Incompatible types in signal: " + s); |
||||
|
} |
||||
|
if (lSignal.category) totals[lSignal.category]--; |
||||
|
lSignal.category = tAll; |
||||
|
totals[lSignal.category] ++; |
||||
|
} |
||||
|
|
||||
|
ids["one"] = 0; |
||||
|
ids["output"] = 1; |
||||
|
ids["pubInput"] = ids["output"] + totals["output"]; |
||||
|
ids["prvInput"] = ids["pubInput"] + totals["pubInput"]; |
||||
|
ids["internal"] = ids["prvInput"] + totals["prvInput"]; |
||||
|
ids["constant"] = ids["internal"] + totals["internal"]; |
||||
|
const nSignals = ids["constant"] + totals["constant"]; |
||||
|
|
||||
|
ctx.signalNames = new Array(nSignals); |
||||
|
for (let i=0; i< nSignals; i++) ctx.signalNames[i] = []; |
||||
|
ctx.signalName2Idx = {}; |
||||
|
|
||||
|
for (let s in ctx.signals) { |
||||
|
const signal = ctx.signals[s]; |
||||
|
let lSignal = signal; |
||||
|
while (lSignal.equivalence) { |
||||
|
lSignal = ctx.signals[lSignal.equivalence]; |
||||
|
} |
||||
|
if ( typeof(lSignal.id) === "undefined" ) { |
||||
|
lSignal.id = ids[lSignal.category] ++; |
||||
|
} |
||||
|
|
||||
|
signal.id = lSignal.id; |
||||
|
ctx.signalNames[signal.id].push(signal.fullName); |
||||
|
ctx.signalName2Idx[signal.fullName] = signal.id; |
||||
|
} |
||||
|
|
||||
|
ctx.totals = totals; |
||||
|
} |
||||
|
|
||||
|
function reduceConstrains(ctx) { |
||||
|
const newConstrains = []; |
||||
|
for (let i=0; i<ctx.constrains.length; i++) { |
||||
|
const c = lc.canonize(ctx, ctx.constrains[i]); |
||||
|
if (!lc.isZero(c)) { |
||||
|
newConstrains.push(c); |
||||
|
} |
||||
|
} |
||||
|
ctx.constrains = newConstrains; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
function buildCircuitDef(ctx, mainCode) { |
||||
|
const res = { |
||||
|
mainCode: mainCode |
||||
|
}; |
||||
|
res.signalName2Idx = ctx.signalName2Idx; |
||||
|
|
||||
|
res.components = []; |
||||
|
res.componentName2Idx = {}; |
||||
|
for (let c in ctx.components) { |
||||
|
const idCoponent = res.components.length; |
||||
|
res.components.push({ |
||||
|
name: c, |
||||
|
params: ctx.components[c].params, |
||||
|
template: ctx.components[c].template, |
||||
|
inputSignals: 0 |
||||
|
}); |
||||
|
res.componentName2Idx[c] = idCoponent; |
||||
|
} |
||||
|
|
||||
|
res.signals = new Array(ctx.signalNames.length); |
||||
|
for (let i=0; i<ctx.signalNames.length; i++) { |
||||
|
res.signals[i] = { |
||||
|
names: ctx.signalNames[i], |
||||
|
triggerComponents: [] |
||||
|
}; |
||||
|
ctx.signalNames[i].map( (fullName) => { |
||||
|
const idComponet = res.componentName2Idx[ctx.signals[fullName].component]; |
||||
|
if (ctx.signals[fullName].direction == "IN") { |
||||
|
res.signals[i].triggerComponents.push(idComponet); |
||||
|
res.components[idComponet].inputSignals++; |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
res.constrains = buildConstrains(ctx); |
||||
|
|
||||
|
res.templates = ctx.templates; |
||||
|
|
||||
|
res.functions = {}; |
||||
|
for (let f in ctx.functions) { |
||||
|
res.functions[f] = { |
||||
|
params: ctx.functionParams[f], |
||||
|
func: ctx.functions[f] |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
res.nPrvInputs = ctx.totals.prvInput; |
||||
|
res.nPubInputs = ctx.totals.pubInput; |
||||
|
res.nInputs = res.nPrvInputs + res.nPubInputs; |
||||
|
res.nOutputs = ctx.totals.output; |
||||
|
res.nVars = res.nInputs + res.nOutputs + ctx.totals.one + ctx.totals.internal; |
||||
|
res.nConstants = ctx.totals.constant; |
||||
|
res.nSignals = res.nVars + res.nConstants; |
||||
|
|
||||
|
return res; |
||||
|
} |
||||
|
|
||||
|
/* |
||||
|
Build constrains |
||||
|
|
||||
|
A constrain like this |
||||
|
|
||||
|
[s1 + 2*s2 + 3*s3] * [ s2 + 5*s4] - [s0 ] = 0 |
||||
|
[ 5*s2 + 6*s3] * [ s2 + ] - [s0 + 2* s2] = 0 |
||||
|
[s1 + s3] * [ s2 + 5*s3] - [s4 ] = 0 |
||||
|
|
||||
|
is converted to |
||||
|
|
||||
|
[ |
||||
|
[{"1":"1","2":"2","3":"3"} , {"2":"1","4":"5"} , {"0":"1" }], |
||||
|
[{ "2":"5","3":"6"} , {"2":"1" } , {"0":"1", "2":"2"}], |
||||
|
[{"1":"1", "3":"1"} , {"2":"1","3":"5"} , {"4":"1" }] |
||||
|
] |
||||
|
^ ^ ^ |
||||
|
| | | |
||||
|
A B C |
||||
|
|
||||
|
*/ |
||||
|
|
||||
|
function buildConstrains(ctx) { |
||||
|
const res = []; |
||||
|
|
||||
|
function fillLC(dst, src) { |
||||
|
for (let s in src.values) { |
||||
|
const v = src.values[s].toString(); |
||||
|
const id = ctx.signalName2Idx[s]; |
||||
|
dst[id] = v; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
for (let i=0; i<ctx.constrains.length; i++) { |
||||
|
const A = {}; |
||||
|
const B = {}; |
||||
|
const C = {}; |
||||
|
|
||||
|
fillLC(A, ctx.constrains[i].a); |
||||
|
fillLC(B, ctx.constrains[i].b); |
||||
|
fillLC(C, lc.negate(ctx.constrains[i].c)); |
||||
|
|
||||
|
res.push([A,B,C]); |
||||
|
} |
||||
|
|
||||
|
return res; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
@ -0,0 +1,18 @@ |
|||||
|
include "../../circuits/sha256/constants.jaz" |
||||
|
|
||||
|
template A() { |
||||
|
signal input in; |
||||
|
component h0; |
||||
|
h0 = K(8); |
||||
|
|
||||
|
var lc = 0; |
||||
|
var e = 1; |
||||
|
for (var i=0; i<32; i++) { |
||||
|
lc = lc + e*h0.out[i]; |
||||
|
e *= 2; |
||||
|
} |
||||
|
|
||||
|
lc === in; |
||||
|
} |
||||
|
|
||||
|
component main = A(); |
@ -0,0 +1,14 @@ |
|||||
|
const chai = require("chai"); |
||||
|
const path = require("path"); |
||||
|
|
||||
|
const compiler = require("../index.js"); |
||||
|
|
||||
|
const assert = chai.assert; |
||||
|
|
||||
|
describe("SHA256 test", () => { |
||||
|
it("Should create a constant circuit", async () => { |
||||
|
|
||||
|
const cir = await compiler(path.join(__dirname, "circuits", "constants_test.jaz")); |
||||
|
assert.equal(cir.nVars, 2); |
||||
|
}); |
||||
|
}); |