Construction phase redone

This commit is contained in:
Jordi Baylina
2019-12-23 19:34:52 +01:00
parent b564201170
commit da969a5e16
15 changed files with 1722 additions and 1981 deletions

View File

@@ -87,7 +87,7 @@ function instantiateConstant(ctx, value) {
function createRefs(ctx, ast) {
const scopeLabels = [];
iterateAST(ast, (ast, level) => {
while ((scopeLabels.length>0)&&(!scopeLabels[scopeLabels.length-1].startsWith(level))) {
while ((scopeLabels.length>0)&&(!level.startsWith(scopeLabels[scopeLabels.length-1]))) {
ctx.scopes.pop();
scopeLabels.pop();
}
@@ -329,7 +329,7 @@ function genDeclareVariable(ctx, ast) {
}
sizes = utils.accSizes(sizes);
} else {
sizes = null; // If not sizes, the sized are defined in the first assignement.
sizes = [1,0];
}
if ((!v.sizes)&&(sizes)) {

View File

@@ -17,26 +17,18 @@
along with circom. If not, see <https://www.gnu.org/licenses/>.
*/
const fs = require("fs");
const path = require("path");
const bigInt = require("big-integer");
const __P__ = new bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
const sONE = 0;
const assert = require("assert");
const buildC = require("./c_build");
const exec = require("./exec");
const lc = require("./lcalgebra");
const constructionPhase = require("./construction_phase");
const Ctx = require("./ctx");
const ZqField = require("./zqfield");
const ZqField = require("fflib").ZqField;
const utils = require("./utils");
const buildR1cs = require("./r1csfile").buildR1cs;
module.exports = compile;
const parser = require("../parser/jaz.js").parser;
const timeout = ms => new Promise(res => setTimeout(res, ms));
async function compile(srcFile, options) {
options.p = options.p || __P__;
if (!options) {
@@ -45,26 +37,15 @@ async function compile(srcFile, options) {
if (typeof options.reduceConstraints === "undefined") {
options.reduceConstraints = true;
}
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 = new Ctx();
ctx.field = new ZqField(options.p);
ctx.mainComponent = options.mainComponent || "main";
ctx.filePath= fullFilePath;
ctx.fileName= fullFileName;
ctx.includedFiles = {};
ctx.includedFiles[fullFileName] = src.split("\n");
ctx.verbose= options.verbose || false;
ctx.mainComponent = options.mainComponent || "main";
exec(ctx, ast);
constructionPhase(ctx, srcFile);
console.log("NConstraints Before: "+ctx.constraints.length);
if (ctx.error) {
throw(ctx.error);
@@ -91,6 +72,8 @@ async function compile(srcFile, options) {
}
}
console.log("NConstraints After: "+ctx.constraints.length);
generateWitnessNames(ctx);
if (ctx.error) {
@@ -235,8 +218,8 @@ function reduceConstants(ctx) {
const newConstraints = [];
for (let i=0; i<ctx.constraints.length; i++) {
if ((ctx.verbose)&&(i%10000 == 0)) console.log("reducing constants: ", i);
const c = lc.canonize(ctx, ctx.constraints[i]);
if (!lc.isZero(c)) {
const c = ctx.lc.canonize(ctx, ctx.constraints[i]);
if (!ctx.lc.isZero(c)) {
newConstraints.push(c);
}
delete ctx.constraints[i];
@@ -265,19 +248,19 @@ function reduceConstrains(ctx) {
// Mov to C if possible.
if (isConstant(c.a)) {
const ct = {type: "NUMBER", value: c.a.values[sONE]};
c.c = lc.add(lc.mul(c.b, ct), c.c);
c.a = { type: "LINEARCOMBINATION", values: {} };
c.b = { type: "LINEARCOMBINATION", values: {} };
const ct = {t: "N", v: c.a.coefs[sONE]};
c.c = ctx.lc.add(ctx.lc.mul(c.b, ct), c.c);
c.a = { t: "LC", coefs: {} };
c.b = { t: "LC", coefs: {} };
}
if (isConstant(c.b)) {
const ct = {type: "NUMBER", value: c.b.values[sONE]};
c.c = lc.add(lc.mul(c.a, ct), c.c);
c.a = { type: "LINEARCOMBINATION", values: {} };
c.b = { type: "LINEARCOMBINATION", values: {} };
const ct = {t: "N", v: c.b.coefs[sONE]};
c.c = ctx.lc.add(ctx.lc.mul(c.a, ct), c.c);
c.a = { t: "LC", coefs: {} };
c.b = { t: "LC", coefs: {} };
}
if (lc.isZero(c.a) || lc.isZero(c.b)) {
if (ctx.lc.isZero(c.a) || ctx.lc.isZero(c.b)) {
const isolatedSignal = getFirstInternalSignal(ctx, c.c);
if (isolatedSignal) {
@@ -288,22 +271,22 @@ function reduceConstrains(ctx) {
const isolatedSignalEquivalence = {
type: "LINEARCOMBINATION",
values: {}
t: "LC",
coefs: {}
};
const invCoef = c.c.values[isolatedSignal].modInv(__P__);
for (const s in c.c.values) {
const invCoef = c.c.coefs[isolatedSignal].modInv(__P__);
for (const s in c.c.coefs) {
if (s != isolatedSignal) {
const v = __P__.minus(c.c.values[s]).times(invCoef).mod(__P__);
const v = __P__.minus(c.c.coefs[s]).times(invCoef).mod(__P__);
if (!v.isZero()) {
isolatedSignalEquivalence.values[s] = v;
isolatedSignalEquivalence.coefs[s] = v;
}
}
}
for (let j in lSignal.inConstraints) {
if ((j!=i)&&(ctx.constraints[j])) {
ctx.constraints[j] = lc.substitute(ctx.constraints[j], isolatedSignal, isolatedSignalEquivalence);
ctx.constraints[j] = ctx.lc.substitute(ctx.constraints[j], isolatedSignal, isolatedSignalEquivalence);
linkSignalsConstraint(j);
if (j<i) {
nextPossibleConstraints[j] = true;
@@ -315,7 +298,7 @@ function reduceConstrains(ctx) {
lSignal.c = ctx.stDISCARDED;
} else {
if (lc.isZero(c.c)) ctx.constraints[i] = null;
if (ctx.lc.isZero(c.c)) ctx.constraints[i] = null;
}
}
}
@@ -341,9 +324,9 @@ function reduceConstrains(ctx) {
function linkSignalsConstraint(cidx) {
const ct = ctx.constraints[cidx];
for (let k in ct.a.values) linkSignal(k, cidx);
for (let k in ct.b.values) linkSignal(k, cidx);
for (let k in ct.c.values) linkSignal(k, cidx);
for (let k in ct.a.coefs) linkSignal(k, cidx);
for (let k in ct.b.coefs) linkSignal(k, cidx);
for (let k in ct.c.coefs) linkSignal(k, cidx);
}
function unindexVariables() {
@@ -378,7 +361,7 @@ function reduceConstrains(ctx) {
}
function getFirstInternalSignal(ctx, l) {
for (let k in l.values) {
for (let k in l.coefs) {
const signal = ctx.signals[k];
if (signal.c == ctx.stINTERNAL) return k;
}
@@ -386,10 +369,10 @@ function reduceConstrains(ctx) {
}
function isConstant(l) {
for (let k in l.values) {
if ((k != sONE) && (!l.values[k].isZero())) return false;
for (let k in l.coefs) {
if ((k != sONE) && (!l.coefs[k].isZero())) return false;
}
if (!l.values[sONE] || l.values[sONE].isZero()) return false;
if (!l.coefs[sONE] || l.coefs[sONE].isZero()) return false;
return true;
}
@@ -483,9 +466,9 @@ function buildConstraints(ctx) {
const res = [];
function fillLC(dst, src) {
if (src.type != "LINEARCOMBINATION") throw new Error("Constraint is not a LINEARCOMBINATION");
for (let s in src.values) {
const v = src.values[s].toString();
if (src.t != "LC") throw new Error("Constraint is not a LINEARCOMBINATION");
for (let s in src.coefs) {
const v = src.coefs[s].toString();
const id = ctx.signalName2Idx[s];
dst[id] = v;
}
@@ -498,7 +481,7 @@ function buildConstraints(ctx) {
fillLC(A, ctx.constraints[i].a);
fillLC(B, ctx.constraints[i].b);
fillLC(C, lc.negate(ctx.constraints[i].c));
fillLC(C, ctx.lc.negate(ctx.constraints[i].c));
res.push([A,B,C]);
}

1070
src/construction_phase.js Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -61,6 +61,12 @@ function iterateAST(ast, fn, _pfx) {
iterateAST(ast.value, fn, getPfx());
} else if (ast.type == "ARRAY") {
iterate(ast.values);
} else if ((ast.type == "TEMPLATEDEF")) {
//
} else if ((ast.type == "FUNCTIONDEF")) {
//
} else if ((ast.type == "INCLUDE")) {
//
} else {
assert(false, "GEN -> Invalid AST iteration: " + ast.type);
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,6 @@
const fs = require("fs");
const assert = require("assert");
const lc = require("./lcalgebra");
const bigInt = require("big-integer");
module.exports.buildR1cs = buildR1cs;
@@ -262,19 +261,19 @@ async function buildR1cs(ctx, fileName) {
async function writeConstraint(c) {
await writeLC(c.a);
await writeLC(c.b);
await writeLC(lc.negate(c.c));
await writeLC(ctx.lc.neg(c.c));
}
async function writeLC(lc) {
const idxs = Object.keys(lc.values);
const idxs = Object.keys(lc.coefs);
await writeU32(idxs.length);
for (let s in lc.values) {
for (let s in lc.coefs) {
let lSignal = ctx.signals[s];
while (lSignal.e >=0 ) lSignal = ctx.signals[lSignal.e];
await writeU32(lSignal.id);
await writeBigInt(lc.values[s]);
await writeBigInt(lc.coefs[s]);
}
}

View File

@@ -124,3 +124,4 @@ function accSizes2Str(sizes) {

View File

@@ -1,118 +0,0 @@
const bigInt = require("big-integer");
const assert = require("assert");
module.exports = class ZqField {
constructor(p) {
this.one = bigInt.one;
this.zero = bigInt.zero;
this.p = p;
this.bitLength = p.bitLength();
this.mask = bigInt.one.shiftLeft(this.bitLength - 1).minus(bigInt.one);
}
add(a, b) {
let res = a.add(b);
if (res.geq(this.p)) {
res = res.minus(this.p);
}
return res;
}
sub(a, b) {
if (a.geq(b)) {
return a.minus(b);
} else {
return this.p.minus(b.minus(a));
}
}
neg(a) {
if (a.isZero()) return a;
return this.p.minus(a);
}
mul(a, b) {
return a.times(b).mod(this.p);
}
lt(a, b) {
return a.lt(b) ? bigInt(1) : bigInt(0);
}
eq(a, b) {
return a.eq(b) ? bigInt(1) : bigInt(0);
}
gt(a, b) {
return a.gt(b) ? bigInt(1) : bigInt(0);
}
leq(a, b) {
return a.leq(b) ? bigInt(1) : bigInt(0);
}
geq(a, b) {
return a.geq(b) ? bigInt(1) : bigInt(0);
}
neq(a, b) {
return a.neq(b) ? bigInt(1) : bigInt(0);
}
div(a, b) {
assert(!b.isZero(), "Division by zero");
return a.times(b.modInv(this.p)).mod(this.p);
}
idiv(a, b) {
assert(!b.isZero(), "Division by zero");
return a.divide(b);
}
mod(a, b) {
return a.mod(b);
}
pow(a, b) {
return a.modPow(b, this.p);
}
band(a, b) {
return a.and(b).and(this.mask);
}
bor(a, b) {
return a.or(b).and(this.mask);
}
bxor(a, b) {
return a.xor(b).and(this.mask);
}
bnot(a) {
return a.xor(this.mask).and(this.mask);
}
shl(a, b) {
if (b.geq(this.bitLength)) return bigInt.zero;
return a.shiftLeft(b).and(this.mask);
}
shr(a, b) {
if (b.geq(this.bitLength)) return bigInt.zero;
return a.shiftRight(b).and(this.mask);
}
land(a, b) {
return (a.isZero() || b.isZero) ? bigInt.zero : bigInt.one;
}
lor(a, b) {
return (a.isZero() && b.isZero) ? bigInt.zero : bigInt.one;
}
lnot(a) {
return a.isZero() ? bigInt.one : bigInt.zero;
}
};