Fixes and tests passed

This commit is contained in:
Jordi Baylina
2019-12-16 21:37:14 +01:00
parent ec0e7f421b
commit e62c1cdbc3
19 changed files with 956 additions and 314 deletions

View File

@@ -122,14 +122,29 @@ void Circom_CalcWit::freeBigInts(PBigInt bi, int n) {
}
void Circom_CalcWit::getSignal(int cIdx, int sIdx, PBigInt value) {
#ifdef SANITY_CHECK
if (signalAssigned[sIdx] == false) {
fprintf(stderr, "Accessing a not assigned signal: %d\n", sIdx);
assert(false);
}
#endif
mpz_set(*value, signalValues[sIdx]);
}
void Circom_CalcWit::setSignal(int cIdx, int sIdx, PBigInt value) {
#ifdef SANITY_CHECK
assert(signalAssigned[sIdx] == false);
if (signalAssigned[sIdx] == true) {
fprintf(stderr, "Signal assigned twice: %d\n", sIdx);
assert(false);
}
signalAssigned[sIdx] = true;
#endif
/*
// Log assignement
char *valueStr = mpz_get_str(0, 10, *value);
printf("%d --> %s\n", sIdx, valueStr);
free(valueStr);
*/
mpz_set(signalValues[sIdx], *value);
if ( BITMAP_ISSET(circuit->mapIsInput, sIdx) ) {
inputSignalsToTrigger[cIdx]--;
@@ -147,7 +162,7 @@ void Circom_CalcWit::checkConstraint(PBigInt value1, PBigInt value2, char const
std::string sV2 = std::string(pcV2);
free(pcV1);
free(pcV2);
throw std::runtime_error(std::string("Constraint does not match,") + err + ". " + sV1 + " != " + sV2 );
throw std::runtime_error(std::string("Constraint doesn't match, ") + err + ". " + sV1 + " != " + sV2 );
}
#endif
}
@@ -160,3 +175,10 @@ void Circom_CalcWit::triggerComponent(int newCIdx) {
cIdx = oldCIdx;
}
void Circom_CalcWit::log(PBigInt value) {
char *pcV = mpz_get_str(0, 10, *value);
printf("Log: %s\n", pcV);
free(pcV);
}

View File

@@ -43,6 +43,8 @@ public:
void checkConstraint(PBigInt value1, PBigInt value2, char const *err);
void log(PBigInt value);
// Public functions
inline void setInput(int idx, PBigInt val) {

20
cli.js
View File

@@ -67,7 +67,6 @@ if (argv._.length == 0) {
const fullFileName = path.resolve(process.cwd(), inputFile);
const fileName = path.basename(fullFileName, ".circom");
const outName = argv.output ? argv.output : fileName + ".json";
const cSourceName = typeof(argv.csource) === "string" ? argv.csource : fileName + ".cpp";
const r1csName = typeof(argv.r1cs) === "string" ? argv.r1cs : fileName + ".r1cs";
const symName = typeof(argv.sym) === "string" ? argv.sym : fileName + ".sym";
@@ -79,24 +78,15 @@ if (argv.csource) {
options.cSourceWriteStream = fs.createWriteStream(cSourceName);
}
if (argv.r1cs) {
options.r1csWriteStream = fs.createWriteStream(r1csName);
options.r1csFileName = r1csName;
}
if (argv.sym) {
options.symWriteStream = fs.createWriteStream(symName);
}
compiler(fullFileName, options).then( () => {
let r1csDone = false;
let cSourceDone = false;
let symDone = false;
if (options.r1csWriteStream) {
options.r1csWriteStream.end(() => {
r1csDone = true;
finishIfDone();
});
} else {
r1csDone = true;
}
if (options.cSourceWriteStream) {
options.cSourceWriteStream.end(() => {
cSourceDone = true;
@@ -111,11 +101,13 @@ compiler(fullFileName, options).then( () => {
finishIfDone();
});
} else {
cSourceDone = true;
symDone = true;
}
function finishIfDone() {
if ((r1csDone)&&(cSourceDone)&&(symDone)) {
process.exit(0);
if ((cSourceDone)&&(symDone)) {
setTimeout(() => {
process.exit(0);
}, 300);
}
}
}, (err) => {

View File

@@ -29,23 +29,26 @@ This standard specifies a format for a r1cs and allows the to connect a set of t
### General considerations
All integers are represented in Little Endian Fix size format
The standard extension is `.r1cs`
The constraint is in the form
A deterministic program (or circuit) is a program that generates a set of deterministic values given an input. All those values are labeled from l_{0} to l_{n_labels}
This file defines a map beween l_{i} -> w_{j} and defines a series a R1CS of the form
$$
\left\{ \begin{array}{rclclcl}
(a_{0,0}s_0 + a_{0,1}s_1 + ... + a_{0,n-1}s_{n-1}) &\cdot& (b_{0,0} s_0 + b_{0,1} s_1 + ... + b_{0,n-1} s_{n-1}) &-& (c_{0,0} s_0 + c_{0,1} s_1 + ... + c_{0,n-1}s_{n-1}) &=& 0 \\
(a_{1,0}s_0 + a_{1,1}s_1 + ... + a_{1,n-1}s_{n-1}) &\cdot& (b_{1,0} s_0 + b_{1,1} s_1 + ... + b_{1,n-1} s_{n-1}) &-& (c_{1,0} s_0 + c_{1,1}s_1 + ... + c_{1,n-1}s_{n-1}) &=& 0 \\
(a_{0,0}w_0 + a_{0,1}w_1 + ... + a_{0,n}w_{n}) &\cdot& (b_{0,0} w_0 + b_{0,1} w_1 + ... + b_{0,n} w_{n}) &-& (c_{0,0} w_0 + c_{0,1} w_1 + ... + c_{0,n}w_{n}) &=& 0 \\
(a_{1,0}w_0 + a_{1,1}w_1 + ... + a_{1,n}w_{n}) &\cdot& (b_{1,0} w_0 + b_{1,1} w_1 + ... + b_{1,n} w_{n}) &-& (c_{1,0} w_0 + c_{1,1}w_1 + ... + c_{1,n}w_{n}) &=& 0 \\
...\\
(a_{m-1,0}s_0 + a_{m-1,1}s_1 + ... + a_{m-1,n-1}s_{n-1}) &\cdot& (b_{m-1,0} s_0 + b_{m-1,1} s_1 + ... + b_{m-1,n-1} s_{n-1}) &-& (c_{m-1,0} s_0 + c_{m-1,1}s_1 + ... + c_{m-1,n-1}s_{n-1}) &=& 0
(a_{m-1,0}w_0 + a_{m-1,1}w_1 + ... + a_{m-1,n}w_{n}) &\cdot& (b_{m-1,0} w_0 + b_{m-1,1} w_1 + ... + b_{m-1,n} w_{n}) &-& (c_{m-1,0} w_0 + c_{m-1,1}w_1 + ... + c_{m-1,n}w_{n}) &=& 0
\end{array} \right.
$$
Wire 0 must be always mapped to label 0 and it's an input forced to value "1" implicitly
### Format
### Format of the file
````
@@ -55,150 +58,50 @@ $$
┏━━━━┳━━━━━━━━━━━━━━━━━┓
┃ 4 │ 01 00 00 00 ┃ Version 1
┗━━━━┻━━━━━━━━━━━━━━━━━┛
┏━━━━┳━━━━━━━━━━━━━━━━━┓
┃ 4 │ nW ┃
┃ 4 │ 03 00 00 00 ┃ Number of Sections
┗━━━━┻━━━━━━━━━━━━━━━━━┛
┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ 4 │ sectionType ┃ 8 │ SectionSize ┃
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛
┏━━━━━━━━━━━━━━━━━━━━━┓
┃ ┃
┃ ┃
┃ ┃
┃ Section Content ┃
┃ ┃
┃ ┃
┃ ┃
┗━━━━━━━━━━━━━━━━━━━━━┛
┏━━━━┳━━━━━━━━━━━━━━━━━┓
nW 01 00 00 00 nWires
┗━━━━┻━━━━━━━━━━━━━━━━━┛
┏━━━━━━━━━━━━━━━━━━━━━┓
nW │ 01 00 00 00 nPubOut
┗━━━━┻━━━━━━━━━━━━━━━━━┛
┏━━━━┳━━━━━━━━━━━━━━━━━┓
nW │ 01 00 00 00 ┃ nPubIn
┗━━━━┻━━━━━━━━━━━━━━━━━┛
┏━━━━┳━━━━━━━━━━━━━━━━━┓
nW │ 01 00 00 00 ┃ nPrvIn
┗━━━━━━━━━━━━━━━━━━━━━┛
┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━
4 sectionType ┃ 8 │ SectionSize
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━
┏━━━━━━━━━━━━━━━━━━━━━┓
┃ ┃
┃ ┃
Section Content ┃
┃ ┃
┃ ┃
┗━━━━━━━━━━━━━━━━━━━━━┛
┏━━━━┳━━━━━━━━━━━━━━━━━┓
┃ nW │m := NConstraints┃
┗━━━━┻━━━━━━━━━━━━━━━━━┛
┏━━━━┳━━━━━━━━━━━━━━━━━┓ ╲
┃ nW │ nA ┃ ╲
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ ╲
┃ nW │ idx_1 ┃ V │ a_{0,idx_1} ┃ │
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ │
┃ nW │ idx_2 ┃ V │ a_{0,idx_2} ┃ │
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │
... ... │
┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
┃ nW │ idx_nA ┃ V │ a_{0,idx_nA} ┃ │
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │
┏━━━━┳━━━━━━━━━━━━━━━━━┓ │
┃ nW │ nB ┃ │
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
┃ nW │ idx_1 ┃ V │ b_{0,idx_1} ┃ │
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ ╲
┃ nW │ idx_2 ┃ V │ b_{0,idx_2} ┃ ╲
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ Constraint_0
... ...
┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
┃ nW │ idx_nB ┃ V │ b_{0,idx_nB} ┃ │
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │
┏━━━━┳━━━━━━━━━━━━━━━━━┓ │
┃ nW │ nC ┃ │
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
┃ nW │ idx_1 ┃ V │ c_{0,idx_1} ┃ │
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ │
┃ nW │ idx_2 ┃ V │ c_{0,idx_2} ┃ │
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │
... ... │
┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
┃ nW │ idx_nB ┃ V │ c_{0,idx_nC} ┃
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛
┏━━━━┳━━━━━━━━━━━━━━━━━┓ ╲
┃ nW │ nA ┃ ╲
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ ╲
┃ nW │ idx_1 ┃ V │ a_{1,idx_1} ┃ │
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ │
┃ nW │ idx_2 ┃ V │ a_{1,idx_2} ┃ │
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │
... ... │
┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
┃ nW │ idx_nA ┃ V │ a_{1,idx_nA} ┃ │
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │
┏━━━━┳━━━━━━━━━━━━━━━━━┓ │
┃ nW │ nB ┃ │
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
┃ nW │ idx_1 ┃ V │ b_{1,idx_1} ┃ │
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ ╲
┃ nW │ idx_2 ┃ V │ b_{1,idx_2} ┃ ╲
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ Constraint_1
... ...
┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
┃ nW │ idx_nB ┃ V │ b_{1,idx_nB} ┃ │
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │
┏━━━━┳━━━━━━━━━━━━━━━━━┓ │
┃ nW │ nC ┃ │
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
┃ nW │ idx_1 ┃ V │ c_{1,idx_1} ┃ │
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ │
┃ nW │ idx_2 ┃ V │ c_{1,idx_2} ┃ │
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │
... ... │
┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
┃ nW │ idx_nB ┃ V │ c_{1,idx_nC} ┃
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛
...
...
...
┏━━━━┳━━━━━━━━━━━━━━━━━┓ ╲
┃ nW │ nA ┃ ╲
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ ╲
┃ nW │ idx_1 ┃ V │ a_{m-1,idx_1} ┃ │
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ │
┃ nW │ idx_2 ┃ V │ a_{m-1,idx_2} ┃ │
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │
... ... │
┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
┃ nW │ idx_nA ┃ V │ a_{m-1,idx_nA} ┃ │
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │
┏━━━━┳━━━━━━━━━━━━━━━━━┓ │
┃ nW │ nB ┃ │
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
┃ nW │ idx_1 ┃ V │ b_{m-1,idx_1} ┃ │
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ ╲
┃ nW │ idx_2 ┃ V │ b_{m-1,idx_2} ┃ ╲
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ Constraint_{m-1}
... ...
┏━━━━━━━━━━━━━━━━━━━━━━┳━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
┃ nW idx_nB ┃ V │ b_{m-1,idx_nB} ┃ │
┗━━━━━━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │
┏━━━━┳━━━━━━━━━━━━━━━━━┓ │
┃ nW │ nC ┃ │
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
┃ nW │ idx_1 ┃ V │ c_{m-1,idx_1} ┃ │
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ │
┃ nW │ idx_2 ┃ V │ c_{m-1,idx_2} ┃ │
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │
... ... │
┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
┃ nW │ idx_nB ┃ V │ c_{m-1,idx_nC} ┃
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛
...
...
...
````
### Magic Number
#### Magic Number
Size: 4 bytes
The file start with a constant 4 byts (magic number) "r1cs"
The file start with a constant 4 bytes (magic number) "r1cs"
```
0x72 0x31 0x63 0x73
```
### Version
#### Version
Size: 4 bytes
Format: Little-Endian
@@ -209,58 +112,277 @@ For this standard it's fixed to
0x01 0x00 0x00 0x00
```
### Word With (nW)
#### Number of Sections
Size: 4 bytes
Format: Little-Endian
This is the standard word size in bytes used to specify lenghts and indexes in the file.
Number of sections contained in the file
The format of this field is little endian.
#### SectionType
In most of the cases this will be 4 (32bit values)
Size: 4 bytes
Format: Little-Endian
Type of the section.
Currently there are 3 types of sections defined:
* 0x00000001 : Header Section
* 0x00000002 : Constraint Section
* 0x00000003 : Wire2LabelId Map Section
If the file contain other types, the format is valid, but they MUST be ignored.
Any order of the section must be accepted.
Example:
```
0x04 0x00 0x00 0x00
0x01 0x00 0x00 0x00
```
### Number of wires
#### SectionSize
Size: nW bytes
Size: `ws` bytes
Format: Little-Endian
Size in bytes of the section
### Header Section
Section Type: 0x01
````
┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ 4 │ FieldDefSize ┃ FieldDef ┃ field Id
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
┏━━━━┳━━━━━━━━━━━━━━━━━┓
┃ 4 │ 00 00 00 00 ┃ bigInt Format
┗━━━━┻━━━━━━━━━━━━━━━━━┛
┏━━━━┳━━━━━━━━━━━━━━━━━┓
┃ 4 │ is ┃ Id size ( Normally 4 (32bits))
┗━━━━┻━━━━━━━━━━━━━━━━━┛
┏━━━━┳━━━━━━━━━━━━━━━━━┓
┃ is │ 01 00 00 00 ┃ nWires
┗━━━━┻━━━━━━━━━━━━━━━━━┛
┏━━━━┳━━━━━━━━━━━━━━━━━┓
┃ is │ 01 00 00 00 ┃ nPubOut
┗━━━━┻━━━━━━━━━━━━━━━━━┛
┏━━━━┳━━━━━━━━━━━━━━━━━┓
┃ is │ 01 00 00 00 ┃ nPubIn
┗━━━━┻━━━━━━━━━━━━━━━━━┛
┏━━━━┳━━━━━━━━━━━━━━━━━┓
┃ is │ 01 00 00 00 ┃ nPrvIn
┗━━━━┻━━━━━━━━━━━━━━━━━┛
┏━━━━┳━━━━━━━━━━━━━━━━━┓
┃ is │ 01 00 00 00 ┃ nLabels
┗━━━━┻━━━━━━━━━━━━━━━━━┛
┏━━━━┳━━━━━━━━━━━━━━━━━┓
┃ is │ 01 00 00 00 ┃ mConstraints
┗━━━━┻━━━━━━━━━━━━━━━━━┛
````
#### fieldDefSize
Size: 4 bytes
Format: Little-Endian
Size of the field Definition
Example:
```
0x00 0x0 0x00 0x00
```
#### fieldDef
Field dfinition the first 4 bytes are the type in LE. 0x0000001 Ar prime fields.
For the prime fields, the next bytes are the prime in variable length LE base 256 format.
NOTE: This number is independent of the bigInt Format defined next
#### bigInt Format
Size: 4 bytes
Format: Little-Endian
0 Means that the Big Int are variable size LE.
That is the First byte indicates the size and the remaining bytes are the number in little enfian (LSB first) base 256.
Numbers from 1 to 16383 are fixed size Litle endian format base 256.
Example:
```
0x00 0x00 0x00 0x00
```
#### Id Size (is)
Size: 4 bytes
Format: Little-Endian
Size of the identifiers for wires, labels and constraints. In small circuits this is going to be 4 (32 bits)
but can be increaset to 8 for bigger circiuits.
The only possible numbers are 4 or 8
#### Number of wires
Size: `is` bytes
Format: Little-Endian
Total Number of wires including ONE signal (Index 0).
### Number of public outputs
#### Number of public outputs
Size: nW bytes
Size: `is` bytes
Format: Little-Endian
Total Number of wires public output wires. They should be starting at idx 1
### Number of public inputs
#### Number of public inputs
Size: nW bytes
Size: `is` bytes
Format: Little-Endian
Total Number of wires public input wires. They should be starting just after the public output
### Number of private inputs
#### Number of private inputs
Size: nW bytes
Size: `is` bytes
Format: Little-Endian
Total Number of wires private input wires. They should be starting just after the public inputs
### Number of constraints
#### Number of constraints (m)
Size: nW bytes
Size: `ìs` bytes
Format: Little-Endian
Total Number of constraints
### Constraints
### Constraints section
Section Type: 0x02
````
┏━━━━┳━━━━━━━━━━━━━━━━━┓ ╲
┃ is │ nA ┃ ╲
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ ╲
┃ is │ wireId_1 ┃ V │ a_{0,wireId_1} ┃ │
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ │
┃ is │ wireId_2 ┃ V │ a_{0,wireId_2} ┃ │
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │
... ... │
┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
┃ is │ wireId_nA ┃ V │ a_{0,wireId_nA} ┃ │
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │
┏━━━━┳━━━━━━━━━━━━━━━━━┓ │
┃ is │ nB ┃ │
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
┃ is │ wireId_1 ┃ V │ b_{0,wireId_1} ┃ │
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ ╲
┃ is │ wireId_2 ┃ V │ b_{0,wireId_2} ┃ ╲
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ Constraint_0
... ...
┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
┃ is │ wireId_nB ┃ V │ b_{0,wireId_nB} ┃ │
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │
┏━━━━┳━━━━━━━━━━━━━━━━━┓ │
┃ is │ nC ┃ │
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
┃ is │ wireId_1 ┃ V │ c_{0,wireId_1} ┃ │
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ │
┃ is │ wireId_2 ┃ V │ c_{0,wireId_2} ┃ │
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │
... ... │
┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
┃ is │ wireId_nC ┃ V │ c_{0,wireId_nC} ┃
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛
┏━━━━┳━━━━━━━━━━━━━━━━━┓ ╲
┃ is │ nA ┃ ╲
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ ╲
┃ is │ wireId_1 ┃ V │ a_{1,wireId_1} ┃ │
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ │
┃ is │ wireId_2 ┃ V │ a_{1,wireId_2} ┃ │
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │
... ... │
┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
┃ is │ wireId_nA ┃ V │ a_{1,wireId_nA} ┃ │
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │
┏━━━━┳━━━━━━━━━━━━━━━━━┓ │
┃ is │ nB ┃ │
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
┃ is │ wireId_1 ┃ V │ b_{1,wireId_1} ┃ │
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ ╲
┃ is │ wireId_2 ┃ V │ b_{1,wireId_2} ┃ ╲
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ Constraint_1
... ...
┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
┃ is │ wireId_nB ┃ V │ b_{1,wireId_nB} ┃ │
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │
┏━━━━┳━━━━━━━━━━━━━━━━━┓ │
┃ is │ nC ┃ │
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
┃ is │ wireId_1 ┃ V │ c_{1,wireId_1} ┃ │
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ │
┃ is │ wireId_2 ┃ V │ c_{1,wireId_2} ┃ │
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │
... ... │
┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
┃ is │ wireId_nC ┃ V │ c_{1,wireId_nC} ┃
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛
...
...
...
┏━━━━┳━━━━━━━━━━━━━━━━━┓ ╲
┃ is │ nA ┃ ╲
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ ╲
┃ is │ wireId_1 ┃ V │ a_{m-1,wireId_1} ┃ │
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ │
┃ is │ wireId_2 ┃ V │ a_{m-1,wireId_2} ┃ │
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │
... ... │
┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
┃ is │ wireId_nA ┃ V │ a_{m-1,wireId_nA} ┃ │
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │
┏━━━━┳━━━━━━━━━━━━━━━━━┓ │
┃ is │ nB ┃ │
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
┃ is │ wireId_1 ┃ V │ b_{m-1,wireId_1} ┃ │
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ ╲
┃ is │ wireId_2 ┃ V │ b_{m-1,wireId_2} ┃ ╲
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ Constraint_{m-1}
... ...
┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
┃ is │ wireId_nB ┃ V │ b_{m-1,wireId_nB} ┃ │
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │
┏━━━━┳━━━━━━━━━━━━━━━━━┓ │
┃ is │ nC ┃ │
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
┃ is │ wireId_1 ┃ V │ c_{m-1,wireId_1} ┃ │
┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ │
┃ is │ wireId_2 ┃ V │ c_{m-1,wireId_2} ┃ │
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │
... ... │
┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │
┃ is │ wireId_nC ┃ V │ c_{m-1,wireId_nC} ┃
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛
````
#### Constraints
Each constraint contains 3 linear combinations A, B, C.
@@ -269,36 +391,35 @@ The constraint is such that:
A*B-C = 0
```
### Linear combination
#### Linear combination
Each linear combination is of the form:
$$
a_{0,0}s_0 + a_{0,1}s_1 + ... + a_{0,n-1}s_{n-1}
a_{j,0}w_0 + a_{j,1}w_1 + ... + a_{j,n}w_{n}
$$
### Number of nonZero Factors
#### Number of nonZero Factors
Size: nW bytes
Size: `ìs` bytes
Format: Little-Endian
Total number of non Zero factors in the linear compination.
The factors MUST be sorted in ascending order.
### Factor
#### Factor
For each factor we have the index of the factor and the value of the factor.
### Index of the factor
#### WireId of the factor
Size: nW bytes
Size: `is` bytes
Format: Little-Endian
Index of the nonZero Factor
WireId of the nonZero Factor
### Value of the factor
#### Value of the factor
The first byte indicate the length N in bytes of the number in the upcoming bytes.
@@ -307,7 +428,7 @@ The next N bytes represent the value in Little Endian format.
For example, to represent the linear combination:
$$
5s_4 +8s_5 + 260s_886
5w_4 +8w_5 + 260w_{886}
$$
The linear combination would be represented as:
@@ -323,6 +444,18 @@ The linear combination would be represented as:
┃ 76 03 00 00 ┃ 02 04 01 ┃
┗━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━┛
````
### WireId2LabelId Map Section
Section Type: 0x03
````
┏━━┳━━━━━━━━━━━━━━━━━━━┳━━┳━━━━━━━━━━━━━━━━━━━┓ ┏━━┳━━━━━━━━━━━━━━━━━━━┓
┃is│ labelId of Wire_0 ┃is│ labelId of Wire_1 ┃ ... ┃is│ labelId of Wire_n ┃
┗━━┻━━━━━━━━━━━━━━━━━━━┻━━┻━━━━━━━━━━━━━━━━━━━┛ ┗━━┻━━━━━━━━━━━━━━━━━━━┛
````
## Rationale
Variable size for field elements allows to shrink the size of the file and allows to work with any field.
@@ -331,6 +464,8 @@ Version allows to update the format.
Have a very good comprasion ratio for sparse r1cs as it's the normal case.
The motivation of having a map between l and w is that this allows optimizers to calculate equivalent r1cs systems but keeping the original values geneated by the circuit.
## Backward Compatibility
@@ -344,37 +479,62 @@ Given this r1cs in a 256 bit Field:
$$
\left\{ \begin{array}{rclclcl}
(3s_5 + 8s_6) &\cdot& (2s_0 + 20s_2 + 12s_3) &-& (5s_0 + 7s_9) &=& 0 \\
(4s_1 + 8s_5 + 3s_9) &\cdot& (6s_6 + 44s_3) && &=& 0 \\
(4s_6) &\cdot& (6s_0 + 5s_3 + 11s_9) &-& (600s_700) &=& 0
(3w_5 + 8w_6) &\cdot& (2w_0 + 20w_2 + 12w_3) &-& (5w_0 + 7w_2) &=& 0 \\
(4w_1 + 8w_4 + 3w_5) &\cdot& (6w_6 + 44w_3) && &=& 0 \\
(4w_6) &\cdot& (6w_0 + 5w_3 + 11s_2) &-& (600w_6) &=& 0
\end{array} \right.
$$
And a Wire to label map.
$$
w_0 := l_0 \\
w_1 := l_3 \\
w_2 := l_{10} \\
w_3 := l_{11} \\
w_4 := l_{12} \\
w_5 := l_{15} \\
w_6 := l_{324} \\
$$
The format will be:
````
┏━━━━━━━━━━━━━━┓
┃ 72 31 63 77 ┃ Magic
┏━━━━━━━━━━━━━━┓
┃ 72 31 63 77 ┃ Magic
┣━━━━━━━━━━━━━━┫
┃ 01 00 00 00 ┃ Version
┣━━━━━━━━━━━━━━┫
┃ 03 00 00 00 ┃ nSections
┗━━━━━━━━━━━━━━┛
┏━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┓
┃ 01 00 00 00 ┃ 49 00 00 00 ┃ SectionType: Header
┗━━━━━━━━━━━━━━┻━━━━━━━━━━━━━┛
┏━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┓
┃ 25 00 00 00 ┃ 10 00 00 00 ┃ FieldDefSize FieldDef
┣━━━━━━━━━━━━━━┻━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ 20 010000f0 93f5e143 9170b979 48e83328 5d588181 b64550b8 29a031e1 724e6430┃
┣━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
┃ 00 00 00 00 ┃ Big Int format
┣━━━━━━━━━━━━━━┫
┃ 01 00 00 00 ┃ Version
┃ 04 00 00 00 ┃ Id Size
┣━━━━━━━━━━━━━━┫
┃ 04 00 00 00 ┃ nW
┣━━━━━━━━━━━━━━┫
┃ 04 23 45 00 ┃ # of wires
┃ 07 00 00 00 ┃ # of wires
┣━━━━━━━━━━━━━━┫
┃ 01 00 00 00 ┃ # Public Outs
┣━━━━━━━━━━━━━━┫
┃ 02 00 00 00 ┃ # Public Ins
┃ 02 00 00 00 ┃ # Public Ins
┣━━━━━━━━━━━━━━┫
┃ 05 00 00 00 ┃ # Private Ins
┃ 03 00 00 00 ┃ # Private Ins
┣━━━━━━━━━━━━━━┫
┃ e8 03 00 00 ┃ # Labels
┣━━━━━━━━━━━━━━┫
┃ 03 00 00 00 ┃ # Constraints
┗━━━━━━━━━━━━━━┛
┏━━━━━━━━━━━━━━┓
┃ 03 00 00 00 ┃ # of constraints
━━━━━━━━━━━━━━
┏━━━━━━━━━━━━━━┓ Constraint 0: (3s_5 + 8s_6) * (2s_0 + 20s_2 + 12s_3) - (5s_0 + 7s_9) = 0
┏━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┓
┃ 02 00 00 00 ┃ 8b 00 00 00 ┃ SectionType: Constraints
┗━━━━━━━━━━━━━━┻━━━━━━━━━━━━━┛
━━━━━━━━━━━━━━┓ Constraint 0: (3w_5 + 8w_6) * (2w_0 + 20w_2 + 12w_3) - (5w_0 + 7w_2) = 0
┃ 02 00 00 00 ┃
┣━━━━━━━━━━━━━━╋━━━━━━━━┓
┃ 05 00 00 00 ┃ 01 03 ┃
@@ -395,18 +555,17 @@ The format will be:
┣━━━━━━━━━━━━━━╋━━━━━━━━┓
┃ 00 00 00 00 ┃ 01 05 ┃
┣━━━━━━━━━━━━━━╋━━━━━━━━┫
┃ 09 00 00 00 ┃ 01 07 ┃
┃ 02 00 00 00 ┃ 01 07 ┃
┗━━━━━━━━━━━━━━┻━━━━━━━━┛
┏━━━━━━━━━━━━━━┓ Constraint 1: (4s_1 + 8s_5 + 3s_9) * (6s_6 + 44s_3) = 0
┏━━━━━━━━━━━━━━┓ Constraint 1: (4w_1 + 8w_4 + 3w_5) * (6w_6 + 44w_3) = 0
┃ 03 00 00 00 ┃
┣━━━━━━━━━━━━━━╋━━━━━━━━━┓
┃ 01 00 00 00 ┃ 01 04 ┃
┣━━━━━━━━━━━━━━╋━━━━━━━━━┫
┃ 05 00 00 00 ┃ 01 08 ┃
┃ 04 00 00 00 ┃ 01 08 ┃
┣━━━━━━━━━━━━━━╋━━━━━━━━━┫
┃ 09 00 00 00 ┃ 01 03 ┃
┃ 05 00 00 00 ┃ 01 03 ┃
┗━━━━━━━━━━━━━━┻━━━━━━━━━┛
┏━━━━━━━━━━━━━━┓
┃ 02 00 00 00 ┃
@@ -419,8 +578,7 @@ The format will be:
┃ 00 00 00 00 ┃
┗━━━━━━━━━━━━━━┛
┏━━━━━━━━━━━━━━┓ Constraint 2: (4s_6) * (6s_0 + 5s_3 + 11s_9) - (600s_700) = 0
┏━━━━━━━━━━━━━━┓ Constraint 2: (4w_6) * (6w_0 + 5w_3 + 11w_2) - (600w_6) = 0
┃ 01 00 00 00 ┃
┣━━━━━━━━━━━━━━╋━━━━━━━━━┓
┃ 06 00 00 00 ┃ 01 04 ┃
@@ -430,15 +588,34 @@ The format will be:
┣━━━━━━━━━━━━━━╋━━━━━━━━━┓
┃ 00 00 00 00 ┃ 01 06 ┃
┣━━━━━━━━━━━━━━╋━━━━━━━━━┫
┃ 03 00 00 00 ┃ 01 05
┃ 02 00 00 00 ┃ 01 0B
┣━━━━━━━━━━━━━━╋━━━━━━━━━┫
┃ 09 00 00 00 ┃ 01 0B
┃ 03 00 00 00 ┃ 01 05
┗━━━━━━━━━━━━━━┻━━━━━━━━━┛
┏━━━━━━━━━━━━━━┓
┃ 01 00 00 00 ┃
┣━━━━━━━━━━━━━━╋━━━━━━━━━━━━━┓
BC 02 00 00 ┃ 02 58 02 ┃
06 00 00 00 ┃ 02 58 02 ┃
┗━━━━━━━━━━━━━━┻━━━━━━━━━━━━━┛
┏━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┓
┃ 03 00 00 00 ┃ 1c 00 00 00 ┃ Wire to Label Map
┗━━━━━━━━━━━━━━┻━━━━━━━━━━━━━┛
┏━━━━━━━━━━━━━━┓
┃ 00 00 00 00 ┃
┣━━━━━━━━━━━━━━┫
┃ 03 00 00 00 ┃
┣━━━━━━━━━━━━━━┫
┃ 0a 00 00 00 ┃
┣━━━━━━━━━━━━━━┫
┃ 0b 00 00 00 ┃
┣━━━━━━━━━━━━━━┫
┃ 0c 00 00 00 ┃
┣━━━━━━━━━━━━━━┫
┃ 0f 00 00 00 ┃
┣━━━━━━━━━━━━━━┫
┃ 44 01 00 00 ┃
┗━━━━━━━━━━━━━━┛
````
And the binary representation in Hex:
@@ -446,38 +623,54 @@ And the binary representation in Hex:
````
72 31 63 77
01 00 00 00
03 00 00 00
01 00 00 00 49 00 00 00
25 00 00 00 10 00 00 00
20 010000f0 93f5e143 9170b979 48e83328 5d588181 b64550b8 29a031e1 724e6430
00 00 00 00
04 00 00 00
04 23 45 00
07 00 00 00
01 00 00 00
02 00 00 00
05 00 00 00
03 00 00 00
02 00 00 00
05 00 00 00 01 03
06 00 00 00 01 08
e8 03 00 00
03 00 00 00
00 00 00 00 01 02
02 00 00 00 01 14
03 00 00 00 01 0C
02 00 00 00 8b 00 00 00
02 00 00 00
00 00 00 00 01 05
09 00 00 00 01 07
05 00 00 00 01 03
06 00 00 00 01 08
03 00 00 00
01 00 00 00 01 04
05 00 00 00 01 08
09 00 00 00 01 03
00 00 00 00 01 02
02 00 00 00 01 14
03 00 00 00 01 0C
02 00 00 00
03 00 00 00 01 2C
06 00 00 00 01 06
00 00 00 00 01 05
02 00 00 00 01 07
03 00 00 00
01 00 00 00 01 04
04 00 00 00 01 08
05 00 00 00 01 03
02 00 00 00
03 00 00 00 01 2C
06 00 00 00 01 06
00 00 00 00
01 00 00 00
06 00 00 00 01 04
06 00 00 00 01 04
03 00 00 00
00 00 00 00 01 06
03 00 00 00 01 05
09 00 00 00 01 0B
00 00 00 00 01 06
02 00 00 00 01 0B
03 00 00 00 01 05
01 00 00 00
BC 02 00 00 02 58 02
06 00 00 00 02 58 02
03 00 00 00 1c 00 00 00
00 00 00 00
03 00 00 00
0a 00 00 00
0b 00 00 00
0c 00 00 00
0f 00 00 00
44 01 00 00
````
## Implementation
@@ -487,3 +680,4 @@ circom will output this format.
## Copyright
Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).

View File

@@ -1,2 +1,3 @@
module.exports.compiler = require("./src/compiler.js");
module.exports.c_tester = require("./src/c_tester.js");
module.exports.tester = require("./src/c_tester.js");

View File

@@ -377,6 +377,8 @@ function buildFunction(name, paramValues) {
const oldUniqueNames = ctx.uniqueNames;
const oldFileName = ctx.fileName;
const oldFilePath = ctx.oldFilePath;
const oldReturnSizes = ctx.returnSizes;
const oldReturnValue = ctx.returnValue;
ctx.scopes = [{}];
@@ -453,6 +455,8 @@ function buildFunction(name, paramValues) {
ctx.uniqueNames = oldUniqueNames;
ctx.fileName = oldFileName;
ctx.filePath = oldFilePath;
ctx.returnSizes = oldReturnSizes;
ctx.returnValue = oldReturnValue;
ctx.definedFunctions[h] = res;

View File

@@ -470,9 +470,9 @@ function genVariable(ctx, ast) {
const resRef = newRef(ctx, "BIGINT", "_v", null, v.sizes.slice(l));
const res = ctx.refs[resRef];
res.used = true;
ctx.codeHeader += `PBigInt ${res};\n`;
ctx.codeHeader += `PBigInt ${res.label};\n`;
ctx.code += `${res.label} = ${v.label} + ${offset.label};\n`;
return res;
return resRef;
} else {
// return newSubRef(ctx, ast.name, ast.selectors);
return newRef(ctx, "BIGINT", "_v", v.value.slice(offset.value[0], offset.value[0] + v.sizes[l]),v.sizes.slice(l));
@@ -574,6 +574,9 @@ function genGetSignalSizes(ctx, cIdxRef, label) {
function genSetSignal(ctx, cIdxRef, sIdxRef, valueRef) {
const v = ctx.refs[valueRef];
if (!utils.isDefined(v)) {
console.log("BREAK!!!");
}
if (!v.used) {
instantiateRef(ctx, valueRef, v.value);
}
@@ -742,8 +745,8 @@ function genConstraint(ctx, ast) {
const b = ctx.refs[bRef];
if (ctx.error) return;
const strErr = ast.fileName + ":" + ast.first_line + ":" + ast.first_column;
instantiateRef(ctx, aRef);
instantiateRef(ctx, bRef);
instantiateRef(ctx, aRef, a.value);
instantiateRef(ctx, bRef, b.value);
ctx.code += `ctx->checkConstraint(${a.label}, ${b.label}, "${strErr}");`;
}
@@ -792,6 +795,13 @@ function genArray(ctx, ast) {
function genFunctionCall(ctx, ast) {
if (ast.name == "log") {
const vRef = gen(ctx, ast.params[0]);
const val = ctx.refs[vRef];
instantiateRef(ctx, vRef, val.value);
ctx.code+=`ctx->log(${val.label});`;
return vRef;
}
const params = [];
for (let i=0; i<ast.params.length; i++) {
const pRef = gen(ctx, ast.params[i]);
@@ -913,9 +923,7 @@ function genLoop(ctx, ast) {
condVar = ctx.refs[condVarRef];
instantiateRef(ctx, condVarRef);
ctx.code =
oldCode +
ctx.code +
ctx.code +=
`${condVar.label} = ctx->field->isTrue(${cond2.label});\n` +
`while (${condVar.label}) {\n`;
} else {
@@ -972,6 +980,7 @@ function genIf(ctx, ast) {
}
ctx.code += "}\n";
leaveConditionalCode(ctx);
} else {
if (!utils.isDefined(cond.value)) return ctx.throwError(ast, "condition value not assigned");
@@ -990,7 +999,7 @@ function genReturn(ctx, ast) {
const vRef = gen(ctx, ast.value);
const v= ctx.refs[vRef];
if (ctx.returnSizes) {
if (!utils.sizesEqual(v.sizes, ctx.returnSizes)) return ctx.throwError(ast, "Diferent return sizes");
if (!utils.sameSizes(v.sizes, ctx.returnSizes)) return ctx.throwError(ast, "Diferent return sizes");
} else {
ctx.returnSizes = v.sizes;
}
@@ -1127,6 +1136,8 @@ function genTerCon(ctx, ast) {
if (ctx.error) return;
const then = ctx.refs[thenRef];
instantiateRef(ctx, thenRef, then.value);
ctx.code = oldCode + utils.ident(ctx.code);
ctx.code += `${rLabel} = ${then.label};\n`;
@@ -1139,6 +1150,8 @@ function genTerCon(ctx, ast) {
if (ctx.error) return;
const els = ctx.refs[elseRef];
instantiateRef(ctx, elseRef, els.value);
ctx.code = oldCode + utils.ident(ctx.code);
ctx.code += `${rLabel} = ${els.label};\n`;

View File

@@ -10,14 +10,16 @@ const exec = util.promisify(require("child_process").exec);
const stringifyBigInts = require("./utils").stringifyBigInts;
const unstringifyBigInts = require("./utils").unstringifyBigInts;
const bigInt = require("snarkjs").bigInt;
const bigInt = require("big-integer");
const utils = require("./utils");
const loadR1cs = require("./r1csfile").loadR1cs;
const ZqField = require("fflib").ZqField;
module.exports = c_tester;
async function c_tester(circomFile, mainComponent, _options) {
async function c_tester(circomFile, _options) {
tmp.setGracefulCleanup();
mainComponent = mainComponent || "main";
const dir = await tmp.dir({prefix: "circom_", unsafeCleanup: true });
@@ -26,31 +28,34 @@ async function c_tester(circomFile, mainComponent, _options) {
options.cSourceWriteStream = fs.createWriteStream(path.join(dir.path, baseName + ".cpp"));
options.symWriteStream = fs.createWriteStream(path.join(dir.path, baseName + ".sym"));
options.mainComponent = mainComponent;
options.r1csFileName = path.join(dir.path, baseName + ".r1cs");
await compiler(circomFile, options);
const cdir = path.join(__dirname, "..", "c");
await exec("cp" +
` ${path.join(dir.path, baseName + ".cpp")}` +
" /tmp/circuit.cpp"
);
await exec("g++" +
` ${path.join(dir.path, baseName + ".cpp")} ` +
` ${path.join(cdir, "main.cpp")}` +
` ${path.join(cdir, "calcwit.cpp")}` +
` ${path.join(cdir, "utils.cpp")}` +
` ${path.join(cdir, "zqfield.cpp")}` +
` ${path.join(dir.path, baseName + ".cpp")} ` +
` -o ${path.join(dir.path, baseName)}` +
` -I ${cdir}` +
" -lgmp -std=c++11 -DSANITY_CHECK"
);
// console.log(dir.path);
return new CTester(dir, baseName, mainComponent);
return new CTester(dir, baseName);
}
class CTester {
constructor(dir, baseName, mainComponent) {
constructor(dir, baseName) {
this.dir=dir;
this.baseName = baseName;
this.mainComponent = mainComponent;
}
async release() {
@@ -74,7 +79,8 @@ class CTester {
return res;
}
async _loadSymbols() {
async loadSymbols() {
if (this.symbols) return;
this.symbols = {};
const symsStr = await fs.promises.readFile(
path.join(this.dir.path, this.baseName + ".sym"),
@@ -91,9 +97,18 @@ class CTester {
}
}
async loadConstraints() {
const self = this;
if (this.constraints) return;
const r1cs = await loadR1cs(path.join(this.dir.path, this.baseName + ".r1cs"),true, false);
self.field = new ZqField(r1cs.prime);
self.nWires = r1cs.nWires;
self.constraints = r1cs.constraints;
}
async assertOut(actualOut, expectedOut) {
const self = this;
if (!self.symbols) await self._loadSymbols();
if (!self.symbols) await self.loadSymbols();
checkObject("main", expectedOut);
@@ -118,6 +133,51 @@ class CTester {
}
}
async getDecoratedOutput(witness) {
const self = this;
const lines = [];
if (!self.symbols) await self.loadSymbols();
for (let n in self.symbols) {
let v;
if (utils.isDefined(witness[self.symbols[n].idxWit])) {
v = witness[self.symbols[n].idxWit].toString();
} else {
v = "undefined";
}
lines.push(`${n} --> ${v}`);
}
return lines.join("\n");
}
async checkConstraints(witness) {
const self = this;
if (!self.constraints) await self.loadConstraints();
for (let i=0; i<self.constraints.length; i++) {
checkConstraint(self.constraints[i]);
}
function checkConstraint(constraint) {
const F = self.field;
const a = evalLC(constraint.a);
const b = evalLC(constraint.b);
const c = evalLC(constraint.c);
assert (F.sub(F.mul(a,b), c).isZero(), "Constraint doesn't match");
}
function evalLC(lc) {
const F = self.field;
let v = F.zero;
for (let w in lc) {
v = F.add(
v,
F.mul( lc[w], witness[w] )
);
}
return v;
}
}
}

View File

@@ -21,7 +21,6 @@ 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 sONE = 0;
const assert = require("assert");
const buildC = require("./c_build");
@@ -30,6 +29,7 @@ const lc = require("./lcalgebra");
const Ctx = require("./ctx");
const ZqField = require("./zqfield");
const utils = require("./utils");
const buildR1cs = require("./r1csfile").buildR1cs;
module.exports = compile;
@@ -85,6 +85,7 @@ async function compile(srcFile, options) {
// Repeat while reductions are performed
let oldNConstrains = -1;
while (ctx.constraints.length != oldNConstrains) {
console.log("Reducing constraints: "+ctx.constraints.length);
oldNConstrains = ctx.constraints.length;
reduceConstrains(ctx);
}
@@ -105,8 +106,8 @@ async function compile(srcFile, options) {
// const mainCode = gen(ctx,ast);
if (ctx.error) throw(ctx.error);
if (options.r1csWriteStream) {
buildR1cs(ctx, options.r1csWriteStream);
if (options.r1csFileName) {
await buildR1cs(ctx, options.r1csFileName);
}
if (options.symWriteStream) {
@@ -505,63 +506,9 @@ function buildConstraints(ctx) {
return res;
}
function buildR1cs(ctx, strm) {
strm.write(Buffer.from([0x72,0x31,0x63,0x73]));
writeU32(1);
writeU32(4);
writeU32(1 + ctx.totals.output + ctx.totals.pubInput + ctx.totals.prvInput + ctx.totals.internal);
writeU32(ctx.totals.output);
writeU32(ctx.totals.pubInput);
writeU32(ctx.totals.prvInput);
writeU32(ctx.constraints.length);
for (let i=0; i<ctx.constraints.length; i++) {
if ((ctx.verbose)&&(i%10000 == 0)) console.log("writing constraint: ", i);
writeConstraint(ctx.constraints[i]);
}
function writeU32(v) {
const b = Buffer.allocUnsafe(4);
b.writeInt32LE(v);
strm.write(b);
}
function writeConstraint(c) {
writeLC(c.a);
writeLC(c.b);
writeLC(lc.negate(c.c));
}
function writeLC(lc) {
const idxs = Object.keys(lc.values);
writeU32(idxs.length);
for (let s in lc.values) {
let lSignal = ctx.signals[s];
while (lSignal.e >=0 ) lSignal = ctx.signals[lSignal.e];
writeU32(lSignal.id);
writeBigInt(lc.values[s]);
}
}
function writeBigInt(n) {
const bytes = [];
let r = bigInt(n);
while (r.greater(bigInt.zero)) {
bytes.push(r.and(bigInt("255")).toJSNumber());
r = r.shiftRight(8);
}
assert(bytes.length<=32);
assert(bytes.length>0);
strm.write( Buffer.from([bytes.length, ...bytes ]));
}
}
function buildSyms(ctx, strm) {
let nSyms;
addSymbolsComponent(ctx.mainComponent + ".", ctx.getComponentIdx(ctx.mainComponent));
@@ -581,6 +528,8 @@ function buildSyms(ctx, strm) {
let wId = ctx.signals[s].id;
if (typeof(wId) == "undefined") wId=-1;
strm.write(`${offset},${wId},${prefix}\n`);
nSyms ++;
if ((ctx.verbose)&&(nSyms%10000 == 0)) console.log("Symbols saved: "+nSyms);
} else {
addSymbolsComponent(prefix+".", offset);
}

View File

@@ -188,7 +188,7 @@ module.exports = class Ctx {
errStr: errStr,
ast: ast,
message: errStr,
errFile: ast.fileName
errFile: this.fileName
};
} else {
return {

View File

@@ -261,7 +261,13 @@ function getScopeRef(ctx, name, selectors) {
}
for (let i=ctx.scopes.length-1; i>=0; i--) {
if (ctx.scopes[i][name]) return select(ctx.scopes[i][name].value, sels, ctx.scopes[i][name].type);
if (ctx.scopes[i][name]) {
if (ctx.scopes[i][name].type == "COMPONENT") {
return [null, sels, "COMPONENT"];
} else {
return select(ctx.scopes[i][name].value, sels, ctx.scopes[i][name].type);
}
}
}
return [null, [], ""];
}
@@ -766,6 +772,7 @@ function execVarAssignement(ctx, ast) {
} else {
v = ast.values[0];
}
const [num, sels, typ] = getScopeRef(ctx, v.name, v.selectors);
if (ctx.error) return;
@@ -1265,10 +1272,9 @@ function execConstrain(ctx, ast) {
if (!lc.isZero(res)) {
ctx.constraints.push(lc.toQEQ(res));
if ((ctx.constraints.length % 10000 == 0)&&(ctx.constraints.length>0)) console.log("Constraints: " + ctx.constraints.length);
}
if ((ctx.constraints.length % 10000 == 0)&&(ctx.constraints.length>0)) console.log("Constraints: " + ctx.constraints.length);
return res;
}

View File

@@ -61,6 +61,7 @@ QEQ QEQ ERR ERR
const bigInt = require("big-integer");
const __P__ = new bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
const sONE = 0;
const utils = require("./utils.js");
exports.add = add;
exports.mul = mul;
@@ -439,8 +440,8 @@ function canonize(ctx, a) {
for (let k in a.values) {
let s = k;
while (ctx.signals[s].e>=0) s= ctx.signals[s].e;
if ((typeof(ctx.signals[s].value) != "undefined")&&(k != sONE)) {
const v = res.values[k].times(ctx.signals[s].value).mod(__P__);
if (utils.isDefined(ctx.signals[s].v)&&(k != sONE)) {
const v = res.values[k].times(ctx.signals[s].v).mod(__P__);
if (!res.values[sONE]) {
res.values[sONE]=v;
} else {

289
src/r1csfile.js Normal file
View File

@@ -0,0 +1,289 @@
const fs = require("fs");
const assert = require("assert");
const lc = require("./lcalgebra");
const bigInt = require("big-integer");
module.exports.buildR1cs = buildR1cs;
module.exports.loadR1cs = loadR1cs;
async function loadR1cs(fileName, loadConstraints, loadMap) {
const res = {};
const fd = await fs.promises.open(fileName, "r");
const b = Buffer.allocUnsafe(4);
await fd.read(b, 0, 4, 0);
if (b.toString() != "r1cs") assert(false, "Invalid File format");
let p=4;
let v = await readU32();
if (v>1) assert(false, "Version not supported");
const nSections = await readU32();
let pHeader;
let pConstraints;
let headerSize;
let constraintsSize;
let pMap;
let mapSize;
for (let i=0; i<nSections; i++) {
let ht = await readU32();
let hl = await readU32();
if (ht == 1) {
if (typeof pHeader != "undefined") assert(false, "File has two headder sections");
pHeader = p;
headerSize = hl;
} else if (ht==2) {
if (typeof pConstraints != "undefined") assert(false, "File has two constraints sections");
pConstraints = p;
constraintsSize = hl;
} else if (ht==3) {
pMap = p;
mapSize = hl;
}
p += hl;
}
if (typeof pHeader == "undefined") assert(false, "File has two header");
// Read Header
p = pHeader;
const fieldDefSize = await readU32();
const pFieldDef = p;
const defType = await readU32();
if (defType != 1) if (typeof pConstraints != "undefined") assert(false, "Field type not supported");
res.prime = await readBigInt();
if ( p != pFieldDef + fieldDefSize) assert("Invalid fieldDef size");
const bigIntFormat = await readU32();
if (bigIntFormat != 0) assert(false, "BigInt format not supported");
const idSize = await readU32();
if (idSize != 4) assert(false, "idSize not supported. Mus be 4");
res.nWires = await readU32();
res.nPubOuts = await readU32();
res.nPubIns = await readU32();
res.nPrvIns = await readU32();
res.nLabels = await readU32();
res.nConstraints = await readU32();
if (p != pHeader + headerSize) assert(false, "Invalid header section size");
if (loadConstraints) {
// Read Constraints
p = pConstraints;
res.constraints = [];
for (let i=0; i<res.nConstraints; i++) {
const c = await readConstraint();
res.constraints.push(c);
}
if (p != pConstraints + constraintsSize) assert(false, "Invalid constraints size");
}
// Read Labels
if (loadMap) {
p = pMap;
res.map = [];
for (let i=0; i<res.nLabels; i++) {
const idx = await readU32();
res.map.push(idx);
}
if (p != pMap + mapSize) assert(false, "Invalid Map size");
}
await fd.close();
return res;
async function readU32() {
const b = Buffer.allocUnsafe(4);
await fd.read(b, 0, 4, p);
p+=4;
return b.readInt32LE(0);
}
async function readBigInt() {
const bl = Buffer.allocUnsafe(1);
await fd.read(bl, 0, 1, p);
p++;
const l = bl[0];
const b = Buffer.allocUnsafe(l);
await fd.read(b, 0, l, p);
p += l;
const arr = Uint8Array.from(b);
const arrr = new Array(arr.length);
for (let i=0; i<arr.length; i++) {
arrr[i] = arr[arr.length-1-i];
}
const n = bigInt.fromArray(arrr, 256);
return n;
}
async function readConstraint() {
const c = {};
c.a = await readLC();
c.b = await readLC();
c.c = await readLC();
return c;
}
async function readLC() {
const lc= {};
const nIdx = await readU32();
for (let i=0; i<nIdx; i++) {
const idx = await readU32();
const val = await readBigInt();
lc[idx] = val;
}
return lc;
}
}
async function buildR1cs(ctx, fileName) {
const fd = await fs.promises.open(fileName, "w");
await fd.write("r1cs"); // Magic "r1cs"
let p = 4;
await writeU32(1); // Version
await writeU32(3); // Number of Sections
// Write the header
///////////
await writeU32(1); // Header type
const pHeaderSize = p;
await writeU32(0); // Temporally set to 0 length
// Field Def
const pFieldDefSize = p;
await writeU32(0); // Temporally set to 0 length
await writeU32(1);
await writeBigInt(ctx.field.p);
const fieldDefSize = p - pFieldDefSize - 4;
await writeU32(0); // Variable bigInt format
await writeU32(4); // Id Size
const NWires =
ctx.totals[ctx.stONE] +
ctx.totals[ctx.stOUTPUT] +
ctx.totals[ctx.stPUBINPUT] +
ctx.totals[ctx.stPRVINPUT] +
ctx.totals[ctx.stINTERNAL];
await writeU32(NWires);
await writeU32(ctx.totals[ctx.stOUTPUT]);
await writeU32(ctx.totals[ctx.stPUBINPUT]);
await writeU32(ctx.totals[ctx.stPRVINPUT]);
await writeU32(ctx.signals.length);
await writeU32(ctx.constraints.length);
const headerSize = p - pHeaderSize - 4;
// Write constraints
///////////
await writeU32(2); // Constraints type
const pConstraintsSize = p;
await writeU32(0); // Temporally set to 0 length
for (let i=0; i<ctx.constraints.length; i++) {
if ((ctx.verbose)&&(i%10000 == 0)) {
if (ctx.verbose) console.log("writing constraint: ", i);
await fd.datasync();
}
await writeConstraint(ctx.constraints[i]);
}
const constraintsSize = p - pConstraintsSize - 4;
// Write map
///////////
await writeU32(3); // wires2label type
const pMapSize = p;
await writeU32(0); // Temporally set to 0 length
const arr = new Array(NWires);
for (let i=0; i<ctx.signals.length; i++) {
const outIdx = ctx.signals[i].id;
if (ctx.signals[i].e>=0) continue; // If has an alias, continue..
assert(typeof outIdx != "undefined", `Signal ${i} does not have index`);
if (outIdx>=NWires) continue; // Is a constant or a discarded variable
if (typeof arr[ctx.signals[i].id] == "undefined") {
arr[outIdx] = i;
}
}
for (let i=0; i<arr.length; i++) {
await writeU32(arr[i]);
if ((ctx.verbose)&&(i%100000)) console.log("writing label2wire map: ", i);
}
const mapSize = p - pMapSize -4;
// Write sizes
await writeU32(headerSize, pHeaderSize);
await writeU32(fieldDefSize, pFieldDefSize);
await writeU32(constraintsSize, pConstraintsSize);
await writeU32(mapSize, pMapSize);
await fd.sync();
await fd.close();
async function writeU32(v, pos) {
const b = Buffer.allocUnsafe(4);
b.writeInt32LE(v);
await fd.write(b, 0, 4, pos);
if (typeof(pos) == "undefined") p += 4;
}
async function writeConstraint(c) {
await writeLC(c.a);
await writeLC(c.b);
await writeLC(lc.negate(c.c));
}
async function writeLC(lc) {
const idxs = Object.keys(lc.values);
await writeU32(idxs.length);
for (let s in lc.values) {
let lSignal = ctx.signals[s];
while (lSignal.e >=0 ) lSignal = ctx.signals[lSignal.e];
await writeU32(lSignal.id);
await writeBigInt(lc.values[s]);
}
}
async function writeBigInt(n) {
const bytes = bigInt(n).toArray(256).value.reverse();
await fd.write(Buffer.from([bytes.length, ...bytes ]));
p += bytes.length+1;
}
}

View File

@@ -99,7 +99,7 @@ function unstringifyBigInts(o) {
}
return res;
} else {
return o;
return bigInt(o);
}
}

View File

@@ -3,6 +3,8 @@ 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);
@@ -11,7 +13,7 @@ module.exports = class ZqField {
add(a, b) {
let res = a.add(b);
if (res.geq(this.p)) {
res = res.minsu(this.p);
res = res.minus(this.p);
}
return res;
}

View File

@@ -44,7 +44,7 @@ async function doTest(circuit, testVectors) {
describe("basic cases", function () {
this.timeout(100000);
it("inout", async () => {
/* it("inout", async () => {
await doTest(
"inout.circom",
[
@@ -298,4 +298,25 @@ describe("basic cases", function () {
]
);
});
it("Constant circuit", async () => {
await doTest(
"constantcircuit.circom",
[
// 0xbb67ae85
[{}, {out: [1,0,1,0, 0,0,0,1, 0,1,1,1, 0,1,0,1, 1,1,1,0, 0,1,1,0, 1,1,0,1, 1,1,0,1]}],
]
);
}); */
it("Constant internal circuit", async () => {
await doTest(
"constantinternalcircuit.circom",
[
// 0xbb67ae85
[{in: 1}, {out: 5}],
[{in: 0}, {out: 4}],
[{in: -2}, {out: 2}],
[{in: 10}, {out: 14}]
]
);
});
});

View File

@@ -0,0 +1,17 @@
template H(x) {
signal output out[32];
var c = [0x6a09e667,
0xbb67ae85,
0x3c6ef372,
0xa54ff53a,
0x510e527f,
0x9b05688c,
0x1f83d9ab,
0x5be0cd19];
for (var i=0; i<32; i++) {
out[i] <== (c[x] >> i) & 1;
}
}
component main = H(1);

View File

@@ -0,0 +1,18 @@
template Const() {
signal output out[2];
out[0] <== 2;
out[1] <== 2;
}
template Main() {
signal input in;
signal output out;
component const = Const();
out <== const.out[0] + const.out[1] + in;
}
component main = Main();

51
utils/mergesymbols.js Normal file
View File

@@ -0,0 +1,51 @@
const fs = require("fs");
const argv = require("yargs")
.usage("mergesymbols -i [input_file] -o [output_file] -s [symbols file]")
.alias("i", "input")
.alias("o", "output")
.alias("s", "symbols")
.help("h")
.epilogue(`Copyright (C) 2018 0kims association
This program comes with ABSOLUTELY NO WARRANTY;
This is free software, and you are welcome to redistribute it
under certain conditions; see the COPYING file in the official
repo directory at https://github.com/iden3/circom `)
.demandOption(["i","o","s"])
.argv;
const inFileName = argv.input;
const outFile = argv.output;
const symbolsFile = argv.symbols;
let symbols;
async function loadSymbols() {
symbols = {};
const symsStr = await fs.promises.readFile(symbolsFile,"utf8");
const lines = symsStr.split("\n");
for (let i=0; i<lines.length; i++) {
const arr = lines[i].split(",");
if (arr.length!=3) continue;
symbols[arr[0]] = arr[2];
}
}
async function run() {
const outLines = [];
await loadSymbols();
const inStr = await fs.promises.readFile(inFileName,"utf8");
const lines = inStr.split("\n");
for (let i=0; i<lines.length; i++) {
const arr = lines[i].split(" --> ");
if (arr.length!=2) continue;
outLines.push(symbols[arr[0]] + " --> " + arr[1]);
}
await fs.promises.writeFile(outFile,outLines.join("\n"), "utf8");
}
run().then(() => {
process.exit(0);
});