Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ This is a helper library to read r1cs binary files defined [here](doc/r1cs_bin_f
## Usage

```
const loadR1cs = require("r1csfile").load
const loadR1cs = require("r1csfile").readR1cs

loadR1cs("myfile.r1cs").then((r1cs) => {
console.log(r1cs);
Expand Down
54 changes: 27 additions & 27 deletions doc/r1cs_bin_format.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@

## Simple Summary

This standard defines a standard format for a binery representation of a r1cs constraint system.
This standard defines a standard format for a binary representation of a r1cs constraint system.

## Abstract


## Motivation

The zero knowledge primitives, requires the definition of a statment that wants to be proved. This statment can be expressed as a deterministric program or an algebraic circuit. Lots of primitives like zkSnarks, bulletProofs or aurora, requires to convert this statment to a rank-one constraint system.
The zero knowledge primitives, requires the definition of a statement that wants to be proved. This statement can be expressed as a deterministic program or an algebraic circuit. Lots of primitives like zkSnarks, bulletProofs or aurora, requires to convert this statement to a rank-one constraint system.

This standard specifies a format for a r1cs and allows the to connect a set of tools that compiles a program or a circuit to r1cs that can be used for the zksnarks or bulletproofs primitives.

Expand All @@ -20,9 +20,9 @@ This standard specifies a format for a r1cs and allows the to connect a set of t
The standard extension is `.r1cs`


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}
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
This file defines a map between $l_{i}$ -> $w_{j}$ and defines a series a R1CS of the form

$$
\left\{ \begin{array}{rclclcl}
Expand Down Expand Up @@ -82,7 +82,7 @@ Wire 0 must be always mapped to label 0 and it's an input forced to value "1" im

#### Magic Number

Size: 4 bytes
Size: 4 bytes
The file start with a constant 4 bytes (magic number) "r1cs"

```
Expand All @@ -91,7 +91,7 @@ The file start with a constant 4 bytes (magic number) "r1cs"

#### Version

Size: 4 bytes
Size: 4 bytes
Format: Little-Endian

For this standard it's fixed to
Expand All @@ -102,14 +102,14 @@ For this standard it's fixed to

#### Number of Sections

Size: 4 bytes
Size: 4 bytes
Format: Little-Endian

Number of sections contained in the file

#### SectionType

Size: 4 bytes
Size: 4 bytes
Format: Little-Endian

Type of the section.
Expand All @@ -133,7 +133,7 @@ Example:

#### SectionSize

Size: `ws` bytes
Size: 8 bytes
Format: Little-Endian

Size in bytes of the section
Expand All @@ -146,7 +146,7 @@ Section Type: 0x01
┃ 4 │ 20 00 00 00 ┃ Field Size in bytes (fs)
┗━━━━┻━━━━━━━━━━━━━━━━━┛
┏━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ fs │ 010000f0 93f5e143 9170b979 48e83328 5d588181 b64550b8 29a031e1 724e6430 ┃ Prime size
┃ fs │ 010000f0 93f5e143 9170b979 48e83328 5d588181 b64550b8 29a031e1 724e6430 ┃ Prime
┗━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
┏━━━━┳━━━━━━━━━━━━━━━━━┓
┃ 32 │ 01 00 00 00 ┃ nWires
Copy link
Copy Markdown

@mratsim mratsim Dec 28, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another issue is that the field size field uses bytes as unit, while nWires and the rest use bits in the diagram.

Expand All @@ -170,9 +170,9 @@ Section Type: 0x01

````

#### field Size (fs)
#### Field Size (fs)

Size: 4 bytes
Size: 4 bytes
Format: Little-Endian

Size in bytes of a field element. Must be a multiple of 8.
Expand All @@ -193,42 +193,42 @@ Example:

#### Number of wires

Size: 4 bytes
Size: 4 bytes
Format: Little-Endian

Total Number of wires including ONE signal (Index 0).
Total Number of wires including the ONE signal (Index 0).

#### Number of public outputs

Size: 4 bytes
Size: 4 bytes
Format: Little-Endian

Total Number of wires public output wires. They should be starting at idx 1
Total Number of public output wires. They should be starting at idx 1

#### Number of public inputs

Size: 4 bytes
Size: 4 bytes
Format: Little-Endian

Total Number of wires public input wires. They should be starting just after the public output
Total Number of public input wires. They should be starting just after the public outputs

#### Number of private inputs

Size: 4 bytes
Size: 4 bytes
Format: Little-Endian

Total Number of wires private input wires. They should be starting just after the public inputs
Total Number of private input wires. They should be starting just after the public inputs

#### Number of Labels

Size: 8 bytes
Size: 8 bytes
Format: Little-Endian

Total Number of wires private input wires. They should be starting just after the public inputs
Total Number of wires including the public outputs and inputs, private inputs and the ONE signal.

#### Number of constraints (m)

Size: 4 bytes
Size: 4 bytes
Format: Little-Endian

Total Number of constraints
Expand Down Expand Up @@ -370,7 +370,7 @@ $$

#### Number of nonZero Factors

Size: 4 bytes
Size: 4 bytes
Format: Little-Endian

Total number of non Zero factors in the linear combination.
Expand All @@ -383,7 +383,7 @@ For each factor we have the index of the factor and the value of the factor.

#### WireId of the factor

Size: 4 bytes
Size: 4 bytes
Format: Little-Endian

WireId of the nonZero Factor
Expand Down Expand Up @@ -506,9 +506,9 @@ Variable size for field elements allows to shrink the size of the file and allow

Version allows to update the format.

Have a very good comprasion ratio for sparse r1cs as it's the normal case.
Have a very good comparison ratio for sparse r1cs as it's the normal case.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Have a very good comparison ratio for sparse r1cs as it's the normal case.
Have a very good compression 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.
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 generated by the circuit.


## Backward Compatibility
Expand Down
11 changes: 7 additions & 4 deletions src/r1csfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export const R1CS_FILE_WIRE2LABELID_SECTION = 3;
export const R1CS_FILE_CUSTOM_GATES_LIST_SECTION = 4;
export const R1CS_FILE_CUSTOM_GATES_USES_SECTION = 5;

export async function readR1csHeader(fd,sections,singleThread) {
export async function readR1csHeader(fd, sections, singleThread) {
let options;
if (typeof singleThread === "object") {
options = singleThread;
Expand All @@ -24,7 +24,9 @@ export async function readR1csHeader(fd,sections,singleThread) {

const res = {};
await binFileUtils.startReadUniqueSection(fd, sections, 1);

// Read Header
// n8 is the byte size of a field element
res.n8 = await fd.readULE32();
res.prime = await binFileUtils.readBigInt(fd, res.n8);

Expand Down Expand Up @@ -59,7 +61,7 @@ export async function readR1csHeader(fd,sections,singleThread) {
return res;
}

export async function readConstraints(fd,sections, r1cs, logger, loggerCtx) {
export async function readConstraints(fd, sections, r1cs, logger, loggerCtx) {
let options;
if (typeof logger === "object") {
options = logger;
Expand All @@ -75,7 +77,7 @@ export async function readConstraints(fd,sections, r1cs, logger, loggerCtx) {
const bR1cs = await binFileUtils.readSection(fd, sections, 2);
let bR1csPos = 0;
let constraints;
if (r1cs.nConstraints>1<<20) {
if (r1cs.nConstraints > 1<<20) {
constraints = new BigArray();
} else {
constraints = [];
Expand All @@ -102,8 +104,9 @@ export async function readConstraints(fd,sections, r1cs, logger, loggerCtx) {
const buffUL32 = bR1cs.slice(bR1csPos, bR1csPos+4);
bR1csPos += 4;
const buffUL32V = new DataView(buffUL32.buffer);
// Number of non-zero terms in the LC
const nIdx = buffUL32V.getUint32(0, true);

const buff = bR1cs.slice(bR1csPos, bR1csPos + (4+r1cs.n8)*nIdx );
bR1csPos += (4+r1cs.n8)*nIdx;
const buffV = new DataView(buff.buffer);
Expand Down