Skip to content

Commit

Permalink
support r1cs created by circom2 (#122)
Browse files Browse the repository at this point in the history
* support r1cs created by circom2

* upgrade version to 0.1.6

* fix

* Update package.json

Co-authored-by: HAOYUatHZ <37070449+HAOYUatHZ@users.noreply.github.com>
  • Loading branch information
lispc and 0xmountaintop authored Nov 16, 2021
1 parent ae8faa6 commit 3301dfa
Show file tree
Hide file tree
Showing 7 changed files with 46 additions and 22 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "plonkit"
version = "0.1.5"
version = "0.1.6"
authors = [ "Roman Semenov <semenov.roma@gmail.com>", "Zhuo Zhang <mycinbrin@gmail.com>", "Haoyu LIN <chris.haoyul@gmail.com>" ]
description = "Library for working with circom circuits in plonk proof system"
homepage = "https://github.com/fluidex/plonkit"
Expand Down
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
A zkSNARK toolkit to work with [circom](https://github.com/iden3/circom) zkSNARKs DSL in [plonk](https://eprint.iacr.org/2019/953) proof system. Based on [zkutil](https://github.com/poma/zkutil) and [bellman_ce](https://github.com/matter-labs/bellman).

## Prerequisites
+ https://github.com/fluidex/snarkit

1. install [circom](https://docs.circom.io/getting-started/installation/) into $PATH
2. install snarkit2 into $PATH: `npm install -g snarkit2`

## Features

Expand Down Expand Up @@ -75,7 +77,7 @@ circuit.circom input.json setup_2^20.key

# generate witness for this circuit
# another option here is use the snarkjs/circom cli like contrib/process_circom_circuit.sh
> npx snarkit check . --witness_type bin --backend wasm
> snarkit2 check . --witness_type bin --backend wasm


# Generate a snark proof using the universal setup monomial-form SRS
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "plonkit",
"version": "0.1.5",
"version": "0.1.6",
"description": "A zkSNARK toolkit to work with circom zkSNARKs DSL in plonk proof system",
"main": "index.js",
"scripts": {
Expand Down
2 changes: 1 addition & 1 deletion src/bin/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use plonkit::recursive;

/// A zkSNARK toolkit to work with circom zkSNARKs DSL in plonk proof system
#[derive(Clap)]
#[clap(version = "0.0.4")]
#[clap(version = "0.1.6")]
struct Opts {
#[clap(subcommand)]
command: SubCommand,
Expand Down
50 changes: 36 additions & 14 deletions src/r1cs_file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,13 @@ use crate::bellman_ce::pairing::{
};
use crate::circom_circuit::Constraint;
use byteorder::{LittleEndian, ReadBytesExt};
use std::io::{Error, ErrorKind, Read, Result};
use std::{
collections::HashMap,
io::{Error, ErrorKind, Read, Result, Seek, SeekFrom},
};

// R1CSFile's header
#[derive(Debug, Default)]
pub struct Header {
pub field_size: u32,
pub prime_size: Vec<u8>,
Expand All @@ -22,6 +26,7 @@ pub struct Header {
}

// R1CSFile parse result
#[derive(Debug, Default)]
pub struct R1CSFile<E: Engine> {
pub version: u32,
pub header: Header,
Expand Down Expand Up @@ -92,7 +97,7 @@ fn read_map<R: Read>(mut reader: R, size: u64, header: &Header) -> Result<Vec<u6
Ok(vec)
}

pub fn from_reader<R: Read>(mut reader: R) -> Result<R1CSFile<Bn256>> {
pub fn from_reader<R: Read + Seek>(mut reader: R) -> Result<R1CSFile<Bn256>> {
let mut magic = [0u8; 4];
reader.read_exact(&mut magic)?;
if magic != [0x72, 0x31, 0x63, 0x73] {
Expand All @@ -107,24 +112,38 @@ pub fn from_reader<R: Read>(mut reader: R) -> Result<R1CSFile<Bn256>> {

let num_sections = reader.read_u32::<LittleEndian>()?;

// todo: rewrite this to support different section order and unknown sections
// todo: handle sec_size correctly
let sec_type = reader.read_u32::<LittleEndian>()?;
let sec_size = reader.read_u64::<LittleEndian>()?;
let header = read_header(&mut reader, sec_size)?;
// section type -> file offset
let mut section_offsets = HashMap::<u32, u64>::new();
let mut section_sizes = HashMap::<u32, u64>::new();

// get file offset of each section
for _ in 0..num_sections {
let section_type = reader.read_u32::<LittleEndian>()?;
let section_size = reader.read_u64::<LittleEndian>()?;
let offset = reader.seek(SeekFrom::Current(0))?;
section_offsets.insert(section_type, offset);
section_sizes.insert(section_type, section_size);
reader.seek(SeekFrom::Current(section_size as i64))?;
}

let header_type = 1;
let constraint_type = 2;
let wire2label_type = 3;

reader.seek(SeekFrom::Start(*section_offsets.get(&header_type).unwrap()))?;
let header = read_header(&mut reader, *section_sizes.get(&header_type).unwrap())?;
if header.field_size != 32 {
return Err(Error::new(ErrorKind::InvalidData, "This parser only supports 32-byte fields"));
}
if header.prime_size != hex!("010000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430") {
return Err(Error::new(ErrorKind::InvalidData, "This parser only supports bn256"));
}
let sec_type = reader.read_u32::<LittleEndian>()?;
let sec_size = reader.read_u64::<LittleEndian>()?;
let constraints = read_constraints::<&mut R, Bn256>(&mut reader, sec_size, &header)?;

let sec_type = reader.read_u32::<LittleEndian>()?;
let sec_size = reader.read_u64::<LittleEndian>()?;
let wire_mapping = read_map(&mut reader, sec_size, &header)?;
reader.seek(SeekFrom::Start(*section_offsets.get(&constraint_type).unwrap()))?;
let constraints = read_constraints::<&mut R, Bn256>(&mut reader, *section_sizes.get(&constraint_type).unwrap(), &header)?;

reader.seek(SeekFrom::Start(*section_offsets.get(&wire2label_type).unwrap()))?;
let wire_mapping = read_map(&mut reader, *section_sizes.get(&wire2label_type).unwrap(), &header)?;

Ok(R1CSFile {
version,
Expand All @@ -136,6 +155,8 @@ pub fn from_reader<R: Read>(mut reader: R) -> Result<R1CSFile<Bn256>> {

#[cfg(test)]
mod tests {
use std::io::{BufReader, Cursor};

use super::*;

#[test]
Expand Down Expand Up @@ -193,7 +214,8 @@ mod tests {
);

use crate::bellman_ce::pairing::ff;
let file = from_reader(&data[..]).unwrap();
let reader = BufReader::new(Cursor::new(&data[..]));
let file = from_reader(reader).unwrap();
assert_eq!(file.version, 1);

assert_eq!(file.header.field_size, 32);
Expand Down
4 changes: 2 additions & 2 deletions src/reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use byteorder::{LittleEndian, ReadBytesExt};
use itertools::Itertools;
use std::collections::BTreeMap;
use std::fs::{File, OpenOptions};
use std::io::{BufRead, BufReader, Read};
use std::io::{BufRead, BufReader, Read, Seek};
use std::str;

use crate::bellman_ce::{
Expand Down Expand Up @@ -224,7 +224,7 @@ fn load_r1cs_from_bin_file(filename: &str) -> (R1CS<Bn256>, Vec<usize>) {
}

/// load r1cs from bin by a reader
fn load_r1cs_from_bin<R: Read>(reader: R) -> (R1CS<Bn256>, Vec<usize>) {
fn load_r1cs_from_bin<R: Read + Seek>(reader: R) -> (R1CS<Bn256>, Vec<usize>) {
let file = crate::r1cs_file::from_reader(reader).expect("unable to read.");
let num_inputs = (1 + file.header.n_pub_in + file.header.n_pub_out) as usize;
let num_variables = file.header.n_wires as usize;
Expand Down

0 comments on commit 3301dfa

Please sign in to comment.