@ -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); |
|||
}); |
|||
}); |