Created
June 10, 2019 07:22
-
-
Save adria0/07e47c7f7506f826c56f999c32a62c14 to your computer and use it in GitHub Desktop.
websnarks.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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,¶ms.vk.alpha_g1)?; | |
write_g1(&mut file,¶ms.vk.beta_g1)?; | |
write_g1(&mut file,¶ms.vk.delta_g1)?; | |
write_g2(&mut file,¶ms.vk.beta_g2)?; | |
write_g2(&mut file,¶ms.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