Skip to content

Instantly share code, notes, and snippets.

@adria0
Created June 10, 2019 07:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save adria0/07e47c7f7506f826c56f999c32a62c14 to your computer and use it in GitHub Desktop.
Save adria0/07e47c7f7506f826c56f999c32a62c14 to your computer and use it in GitHub Desktop.
websnarks.rs
use num_bigint::{BigInt, BigUint};
use circom2_parser::ast::SignalType;
use circom2_compiler::algebra::{LC, QEQ};
use circom2_compiler::storage::{Constraints, Signals,Result};
use byteorder::{BigEndian, WriteBytesExt};
use std::fs::File;
use std::io::{Seek, SeekFrom, Write};
use num_traits::identities::One;
use rand::thread_rng;
use num_traits::Num;
use std::str::FromStr;
use ff::PrimeField;
use num_traits::cast::ToPrimitive;
use pairing::bn256::Bn256;
use pairing::Engine;
use pairing::CurveAffine;
use bellman::groth16::{
create_random_proof, generate_random_parameters, prepare_verifying_key, verify_proof,
Parameters, Proof, VerifyingKey,
};
use bellman::{Circuit, ConstraintSystem, LinearCombination, SynthesisError};
pub fn export_pkey<S:Signals,C:Constraints>(path: &str, signals : &S, constraints : &C, params: Parameters<Bn256>) -> Result<()> {
println!("Scanning constraints...");
let mut public_signal_count = 0;
let mut private_signal_count = 0;
for n in 0..signals.len()? {
let s = signals.get_by_id(n)?.unwrap();
let component_len = s.full_name.0.chars().filter(|ch| *ch == '.').count();
if component_len == 1 {
match s.xtype {
SignalType::Output | SignalType::PublicInput => public_signal_count += 1,
SignalType::PrivateInput => private_signal_count += 1,
_ => {}
}
}
}
println!("public_signal_count = {}",public_signal_count);
println!("private_signal_count = {}",private_signal_count);
let input_signals_count = public_signal_count + private_signal_count;
println!("Writing websnarks proving key {}...",path);
let mut file = File::create(&path)?;
let current_offset = |f:&mut File| {
f.seek(SeekFrom::Current(0)).unwrap() as u32
};
let to_montgomery_q = |n:&BigUint| {
let q = BigUint::from_str("21888242871839275222246405745257275088696311157297823662689037894645226208583").unwrap();
(n * (BigUint::one() << 256)) % q
};
let to_montgomery_r = |n:&BigUint| {
let r = BigUint::from_str("21888242871839275222246405745257275088548364400416034343698204186575808495617").unwrap();
(n * (BigUint::one() << 256)) % r
};
let reserve_u32 = |f:&mut File| {
let offset = f.seek(SeekFrom::Current(0)).unwrap();
f.write_u32::<BigEndian>(0).unwrap();
offset as u32
};
let write_u32 = |f:&mut File, value:u32| {
f.write_u32::<BigEndian>(value).unwrap();
};
let write_u32_offset = |f:&mut File, offset:u32, value:u32| {
f.seek(SeekFrom::Start(offset as u64)).unwrap();
f.write_u32::<BigEndian>(value).unwrap();
f.seek(SeekFrom::End(0)).unwrap();
};
let write_g1 = |f:&mut File, g1 : &<pairing::bn256::Bn256 as Engine>::G1Affine| {
let mut k = g1.into_compressed();
f.write_all(k.as_mut())
};
let write_g2 = |f:&mut File, g2 : &<pairing::bn256::Bn256 as Engine>::G2Affine| {
let mut k = g2.into_compressed();
f.write_all(k.as_mut())
};
let write_bigint = |f:&mut File, v:&BigUint| {
let bits32mask = BigUint::from_str_radix("FFFFFFFF", 16).unwrap();
for i in 0..8 {
let vv = (v >> (i*32)) & &bits32mask;
write_u32(f, vv.to_u32().unwrap());
}
};
let write_transformed_polynomials = |f:&mut File, lc: &Fn(QEQ) -> LC| {
for signal_id in 0..signals.len().unwrap() {
let offset_count = reserve_u32(f);
let mut count = 0;
for constraint_no in 0..constraints.len().unwrap() {
let constraint = constraints.get(constraint_no).unwrap();
if let Some((s,v)) = lc(constraint).0.iter().find(|(s,v)| *s == signal_id) {
write_u32(f, constraint_no as u32);
write_bigint(f, &to_montgomery_r(&v.0));
count += 1;
}
}
write_u32_offset(f,offset_count,count)
}
};
let write_point_g1 = |f:&mut File, point : &<pairing::bn256::Bn256 as Engine>::G1Affine| {
let (x,y) = parse::parse_g1(point);
vec![x,y]
.iter()
.for_each(
|v|
write_bigint(f, &to_montgomery_q(&BigUint::from_str(&v).unwrap()))
);
};
let write_point_g2 = |f:&mut File, point : &<pairing::bn256::Bn256 as Engine>::G2Affine| {
let (x1,x0,y1,y0) = parse::parse_g2(point);
vec![x0,y0,x1,y1]
.iter()
.for_each(
|v|
write_bigint(f, &to_montgomery_q(&BigUint::from_str(&v).unwrap()))
);
};
// NSignals
write_u32(&mut file,signals.len()? as u32);
// NPublic
write_u32(&mut file,input_signals_count as u32);
// DomainSize (2 multiple) // TODO!
write_u32(&mut file,0);
// reserve offsets
let offset_pols_a = reserve_u32(&mut file);
let offset_pols_b = reserve_u32(&mut file);
let offset_points_a = reserve_u32(&mut file);
let offset_points_b1 = reserve_u32(&mut file);
let offset_points_b2 = reserve_u32(&mut file);
let offset_points_c = reserve_u32(&mut file);
let offset_points_hexps = reserve_u32(&mut file);
// alpha, beta, delta
write_g1(&mut file,&params.vk.alpha_g1)?;
write_g1(&mut file,&params.vk.beta_g1)?;
write_g1(&mut file,&params.vk.delta_g1)?;
write_g2(&mut file,&params.vk.beta_g2)?;
write_g2(&mut file,&params.vk.delta_g2)?;
// A & B polinomials
let offset = current_offset(&mut file);
write_u32_offset(&mut file,offset_pols_a,offset);
write_transformed_polynomials(&mut file,&|qeq:QEQ| qeq.a);
let offset = current_offset(&mut file);
write_u32_offset(&mut file,offset_pols_b,offset);
write_transformed_polynomials(&mut file,&|qeq:QEQ| qeq.b);
// check https://github.com/matter-labs/pairing/blob/master/src/bn256/mod.rs
// a
let offset = current_offset(&mut file);
write_u32_offset(&mut file,offset_points_a,offset);
for point in params.a.iter() {
write_point_g1(&mut file, point);
}
// b1
let offset = current_offset(&mut file);
write_u32_offset(&mut file,offset_points_b1,offset);
for point in params.b_g1.iter() {
write_point_g1(&mut file, point);
}
// b2
let offset = current_offset(&mut file);
write_u32_offset(&mut file,offset_points_b1,offset);
for point in params.b_g2.iter() {
write_point_g2(&mut file, point);
}
// c
let offset = current_offset(&mut file);
write_u32_offset(&mut file,offset_points_b1,offset);
for point in params.l.iter() {
write_point_g1(&mut file, point);
}
Ok(())
}
// Taken from Zokrates, G1.{x,y} and G2.{x0,y0,x1,y1} are not available,
// https://github.com/Zokrates/ZoKrates/blob/master/zokrates_core/src/proof_system/bn128/utils/bellman.rs
mod parse {
use lazy_static::lazy_static;
use super::*;
use regex::Regex;
lazy_static! {
static ref G2_REGEX: Regex = Regex::new(r"G2\(x=Fq2\(Fq\((?P<x0>0[xX][0-9a-fA-F]{64})\) \+ Fq\((?P<x1>0[xX][0-9a-fA-F]{64})\) \* u\), y=Fq2\(Fq\((?P<y0>0[xX][0-9a-fA-F]{64})\) \+ Fq\((?P<y1>0[xX][0-9a-fA-F]{64})\) \* u\)\)").unwrap();
}
lazy_static! {
static ref G1_REGEX: Regex = Regex::new(
r"G1\(x=Fq\((?P<x>0[xX][0-9a-fA-F]{64})\), y=Fq\((?P<y>0[xX][0-9a-fA-F]{64})\)\)"
)
.unwrap();
}
lazy_static! {
static ref FR_REGEX: Regex = Regex::new(r"Fr\((?P<x>0[xX][0-9a-fA-F]{64})\)").unwrap();
}
pub fn parse_g1(e: &<Bn256 as bellman::pairing::Engine>::G1Affine) -> (String, String) {
let raw_e = e.to_string();
let captures = G1_REGEX.captures(&raw_e).unwrap();
(
captures.name(&"x").unwrap().as_str().to_string(),
captures.name(&"y").unwrap().as_str().to_string(),
)
}
pub fn parse_g2(
e: &<Bn256 as bellman::pairing::Engine>::G2Affine,
) -> (String, String, String, String) {
let raw_e = e.to_string();
let captures = G2_REGEX.captures(&raw_e).unwrap();
(
captures.name(&"x1").unwrap().as_str().to_string(),
captures.name(&"x0").unwrap().as_str().to_string(),
captures.name(&"y1").unwrap().as_str().to_string(),
captures.name(&"y0").unwrap().as_str().to_string(),
)
}
/*
pub fn parse_fr(e: &Fr) -> String {
let raw_e = e.to_string();
let captures = FR_REGEX.captures(&raw_e).unwrap();
captures.name(&"x").unwrap().as_str().to_string()
}
pub fn parse_g1_json(e: &<Bn256 as bellman::pairing::Engine>::G1Affine) -> String {
let parsed = parse_g1(e);
format!("[\"{}\", \"{}\"]", parsed.0, parsed.1)
}
pub fn parse_g2_json(e: &<Bn256 as bellman::pairing::Engine>::G2Affine) -> String {
let parsed = parse_g2(e);
format!(
"[[\"{}\", \"{}\"], [\"{}\", \"{}\"]]",
parsed.0, parsed.1, parsed.2, parsed.3,
)
}
pub fn parse_fr_json(e: &Fr) -> String {
let parsed = parse_fr(e);
format!("\"{}\"", parsed)
}
pub fn parse_g1_hex(e: &<Bn256 as bellman::pairing::Engine>::G1Affine) -> String {
let parsed = parse_g1(e);
format!("{}, {}", parsed.0, parsed.1)
}
pub fn parse_g2_hex(e: &<Bn256 as bellman::pairing::Engine>::G2Affine) -> String {
let parsed = parse_g2(e);
format!("[{}, {}], [{}, {}]", parsed.0, parsed.1, parsed.2, parsed.3,)
}
*/
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment