1use std::collections::BTreeMap;
17use std::collections::HashMap;
18use std::fs::File;
19use std::fs::OpenOptions;
20use std::io::BufReader;
21use std::io::Read;
22use std::io::Seek;
23use std::io::SeekFrom;
24use std::path::Path;
25
26use byteorder::LittleEndian;
27use byteorder::ReadBytesExt;
28use crypto_bigint::U256;
29use ff::PrimeField;
30use itertools::Itertools;
31use serde::Deserialize;
32use serde::Serialize;
33
34use crate::error::Error;
35use crate::error::Result;
36use crate::r1cs::Constraint;
37use crate::r1cs::R1CS;
38
39#[derive(Serialize, Deserialize)]
42pub(crate) struct CircuitJson {
43 constraints: Vec<Vec<BTreeMap<String, String>>>,
44 #[serde(rename = "nPubInputs")]
45 num_inputs: usize,
46 #[serde(rename = "nOutputs")]
47 num_outputs: usize,
48 #[serde(rename = "nVars")]
49 num_variables: usize,
50}
51
52#[allow(dead_code)]
55#[derive(Debug, Default)]
56struct Header {
57 field_size: u32,
58 prime_size: Vec<u8>,
59 n_wires: u32,
60 n_pub_out: u32,
61 n_pub_in: u32,
62 n_prv_in: u32,
63 n_labels: u64,
64 n_constraints: u32,
65}
66
67#[allow(dead_code)]
70#[derive(Debug, Default)]
71pub struct R1CSFile<F: PrimeField> {
72 version: u32,
73 header: Header,
74 constraints: Vec<Constraint<F>>,
75 wire_mapping: Vec<u64>,
76}
77
78pub fn load_witness_from_file<Fr: PrimeField>(filename: impl AsRef<Path>) -> Vec<Fr> {
80 if filename.as_ref().ends_with("json") {
81 load_witness_from_json_file::<Fr>(filename)
82 } else {
83 load_witness_from_bin_file::<Fr>(filename)
84 }
85}
86
87pub fn load_witness_from_bin_file<Fr: PrimeField>(filename: impl AsRef<Path>) -> Vec<Fr> {
89 let reader = OpenOptions::new()
90 .read(true)
91 .open(filename)
92 .expect("unable to open.");
93 load_witness_from_bin_reader::<Fr, BufReader<File>>(BufReader::new(reader))
94 .expect("read witness failed")
95}
96
97pub fn load_witness_from_bin_reader<Fr: PrimeField, R: Read>(mut reader: R) -> Result<Vec<Fr>> {
99 let mut wtns_header = [0u8; 4];
100 reader.read_exact(&mut wtns_header)?;
101 if wtns_header != [119, 116, 110, 115] {
102 return Err(Error::LoadR1CS("invalid file header".to_string()));
104 }
105 let version = reader.read_u32::<LittleEndian>()?;
106 if version > 2 {
108 return Err(Error::LoadR1CS("unsupported file version".to_string()));
109 }
110 let num_sections = reader.read_u32::<LittleEndian>()?;
111 if num_sections != 2 {
112 return Err(Error::LoadR1CS("invalid num sections".to_string()));
113 }
114 let sec_type = reader.read_u32::<LittleEndian>()?;
116 if sec_type != 1 {
117 return Err(Error::LoadR1CS("invalid section type".to_string()));
118 }
119 let sec_size = reader.read_u64::<LittleEndian>()?;
120 if sec_size != 4 + 32 + 4 {
121 return Err(Error::LoadR1CS("invalid section len".to_string()));
122 }
123 let field_size = reader.read_u32::<LittleEndian>()?;
124 if field_size != 32 {
125 return Err(Error::LoadR1CS("invalid field byte size".to_string()));
126 }
127 let mut prime = vec![0u8; field_size as usize];
128 reader.read_exact(&mut prime)?;
129 let witness_len = reader.read_u32::<LittleEndian>()?;
133 let sec_type = reader.read_u32::<LittleEndian>()?;
135 if sec_type != 2 {
136 return Err(Error::LoadR1CS("invalid section type".to_string()));
137 }
138 let sec_size = reader.read_u64::<LittleEndian>()?;
139 if sec_size != u64::from(witness_len * field_size) {
140 return Err(Error::LoadR1CS(format!(
141 "invalid witness section size {}",
142 sec_size
143 )));
144 }
145 let mut result = Vec::with_capacity(witness_len as usize);
146 for _ in 0..witness_len {
147 result.push(read_field::<&mut R, Fr>(&mut reader)?);
148 }
149 Ok(result)
150}
151
152pub fn load_witness_from_json_file<Fr: PrimeField>(filename: impl AsRef<Path>) -> Vec<Fr> {
154 let reader = OpenOptions::new()
155 .read(true)
156 .open(filename)
157 .expect("unable to open.");
158 load_witness_from_json::<Fr, BufReader<File>>(BufReader::new(reader))
159}
160
161pub fn load_witness_from_json<Fr: PrimeField, R: Read>(reader: R) -> Vec<Fr> {
163 let witness: Vec<String> = serde_json::from_reader(reader).expect("unable to read.");
164 witness
165 .into_iter()
166 .map(|x| Fr::from_str_vartime(&x).unwrap())
167 .collect::<Vec<Fr>>()
168}
169
170pub fn load_r1cs_from_bin_file<F: PrimeField>(filename: impl AsRef<Path>) -> R1CS<F> {
172 let reader = OpenOptions::new()
173 .read(true)
174 .open(filename.as_ref())
175 .unwrap_or_else(|_| panic!("unable to open {:?}", filename.as_ref()));
176 load_r1cs_from_bin(BufReader::new(reader))
177}
178
179fn read_field<R: Read, Fr: PrimeField>(mut reader: R) -> Result<Fr> {
180 let mut repr = Fr::ZERO.to_repr();
181 for digit in repr.as_mut().iter_mut() {
182 *digit = reader.read_u8()?;
184 }
185 let fr = Fr::from_repr(repr).unwrap();
186 Ok(fr)
187}
188
189fn read_header<R: Read>(mut reader: R, size: u64, expected_prime: &str) -> Result<Header> {
190 let field_size = reader.read_u32::<LittleEndian>()?;
191
192 if size != 32 + u64::from(field_size) {
193 return Err(Error::InvalidDataWhenReadingR1CS(
194 "Invalid header section size".to_string(),
195 ));
196 }
197
198 let mut prime_size = vec![0u8; field_size as usize];
199 reader.read_exact(&mut prime_size)?;
200 let prime = U256::from_le_slice(&prime_size);
201 let prime = &prime.to_string().to_ascii_lowercase();
202
203 if prime != &expected_prime[2..] {
204 return Err(Error::InvalidDataWhenReadingR1CS(format!("Mismatched prime field. Expected {expected_prime}, read {prime} in the header instead.")));
206 }
207
208 Ok(Header {
209 field_size,
210 prime_size,
211 n_wires: reader.read_u32::<LittleEndian>()?,
212 n_pub_out: reader.read_u32::<LittleEndian>()?,
213 n_pub_in: reader.read_u32::<LittleEndian>()?,
214 n_prv_in: reader.read_u32::<LittleEndian>()?,
215 n_labels: reader.read_u64::<LittleEndian>()?,
216 n_constraints: reader.read_u32::<LittleEndian>()?,
217 })
218}
219
220fn read_constraint_vec<R: Read, Fr: PrimeField>(
221 mut reader: R,
222 _header: &Header,
223) -> Result<Vec<(usize, Fr)>> {
224 let n_vec = reader.read_u32::<LittleEndian>()? as usize;
225 let mut vec = Vec::with_capacity(n_vec);
226 for _ in 0..n_vec {
227 vec.push((
228 reader.read_u32::<LittleEndian>()? as usize,
229 read_field::<&mut R, Fr>(&mut reader)?,
230 ));
231 }
232 Ok(vec)
233}
234
235fn read_constraints<R: Read, Fr: PrimeField>(
236 mut reader: R,
237 _size: u64,
238 header: &Header,
239) -> Result<Vec<Constraint<Fr>>> {
240 let mut vec = Vec::with_capacity(header.n_constraints as usize);
242 for _ in 0..header.n_constraints {
243 vec.push((
244 read_constraint_vec::<&mut R, Fr>(&mut reader, header)?,
245 read_constraint_vec::<&mut R, Fr>(&mut reader, header)?,
246 read_constraint_vec::<&mut R, Fr>(&mut reader, header)?,
247 ));
248 }
249 Ok(vec)
250}
251
252fn read_map<R: Read>(mut reader: R, size: u64, header: &Header) -> Result<Vec<u64>> {
253 if size != u64::from(header.n_wires) * 8 {
254 return Err(Error::InvalidDataWhenReadingR1CS(
255 "Invalid map section size".to_string(),
256 ));
257 }
258 let mut vec = Vec::with_capacity(header.n_wires as usize);
259 for _ in 0..header.n_wires {
260 vec.push(reader.read_u64::<LittleEndian>()?);
261 }
262 if vec[0] != 0 {
263 return Err(Error::InvalidDataWhenReadingR1CS(
264 "Wire 0 should always be mapped to 0".to_string(),
265 ));
266 }
267 Ok(vec)
268}
269
270fn from_reader<Fr: PrimeField, R: Read + Seek>(mut reader: R) -> Result<R1CSFile<Fr>> {
271 let mut magic = [0u8; 4];
272 reader.read_exact(&mut magic)?;
273 if magic != [0x72, 0x31, 0x63, 0x73] {
274 return Err(Error::InvalidDataWhenReadingR1CS(
276 "Invalid magic number".to_string(),
277 ));
278 }
279
280 let version = reader.read_u32::<LittleEndian>()?;
281 if version != 1 {
282 return Err(Error::InvalidDataWhenReadingR1CS(
283 "Unsupported version".to_string(),
284 ));
285 }
286
287 let num_sections = reader.read_u32::<LittleEndian>()?;
288
289 let mut section_offsets = HashMap::<u32, u64>::new();
291 let mut section_sizes = HashMap::<u32, u64>::new();
292
293 for _ in 0..num_sections {
295 let section_type = reader.read_u32::<LittleEndian>()?;
296 let section_size = reader.read_u64::<LittleEndian>()?;
297 let offset = reader.stream_position()?;
298 section_offsets.insert(section_type, offset);
299 section_sizes.insert(section_type, section_size);
300 reader.seek(SeekFrom::Current(section_size as i64))?;
301 }
302
303 let header_type = 1;
304 let constraint_type = 2;
305 let wire2label_type = 3;
306
307 reader.seek(SeekFrom::Start(*section_offsets.get(&header_type).unwrap()))?;
308 let header = read_header(
309 &mut reader,
310 *section_sizes.get(&header_type).unwrap(),
311 Fr::MODULUS,
312 )?;
313 if header.field_size != 32 {
314 return Err(Error::InvalidDataWhenReadingR1CS(
315 "This parser only supports 32-byte fields".to_string(),
316 ));
317 }
318 reader.seek(SeekFrom::Start(
323 *section_offsets.get(&constraint_type).unwrap(),
324 ))?;
325 let constraints = read_constraints::<&mut R, Fr>(
326 &mut reader,
327 *section_sizes.get(&constraint_type).unwrap(),
328 &header,
329 )?;
330
331 reader.seek(SeekFrom::Start(
332 *section_offsets.get(&wire2label_type).unwrap(),
333 ))?;
334 let wire_mapping = read_map(
335 &mut reader,
336 *section_sizes.get(&wire2label_type).unwrap(),
337 &header,
338 )?;
339
340 Ok(R1CSFile {
341 version,
342 header,
343 constraints,
344 wire_mapping,
345 })
346}
347
348pub fn load_r1cs_from_bin<Fr: PrimeField, R: Read + Seek>(reader: R) -> R1CS<Fr> {
350 let file = from_reader(reader).expect("unable to read.");
351 let num_inputs = (1 + file.header.n_pub_in + file.header.n_pub_out) as usize;
352 let num_variables = file.header.n_wires as usize;
353 let num_aux = num_variables - num_inputs;
354 R1CS {
355 num_aux,
356 num_inputs,
357 num_variables,
358 constraints: file.constraints,
359 }
360}
361
362pub fn load_r1cs<Fr: PrimeField>(filename: impl AsRef<Path>) -> R1CS<Fr> {
364 if filename.as_ref().ends_with("json") {
365 load_r1cs_from_json_file(filename)
366 } else {
367 load_r1cs_from_bin_file(filename)
368 }
369}
370
371pub fn load_r1cs_from_json_file<Fr: PrimeField>(filename: impl AsRef<Path>) -> R1CS<Fr> {
373 let reader = OpenOptions::new()
374 .read(true)
375 .open(filename)
376 .expect("unable to open.");
377 load_r1cs_from_json(BufReader::new(reader))
378}
379
380pub fn load_r1cs_from_json<Fr: PrimeField, R: Read>(reader: R) -> R1CS<Fr> {
382 let circuit_json: CircuitJson = serde_json::from_reader(reader).expect("unable to read.");
383
384 let num_inputs = circuit_json.num_inputs + circuit_json.num_outputs + 1;
385 let num_aux = circuit_json.num_variables - num_inputs;
386
387 let convert_constraint = |lc: &BTreeMap<String, String>| {
388 lc.iter()
389 .map(|(index, coeff)| (index.parse().unwrap(), Fr::from_str_vartime(coeff).unwrap()))
390 .collect_vec()
391 };
392
393 let constraints = circuit_json
394 .constraints
395 .iter()
396 .map(|c| {
397 (
398 convert_constraint(&c[0]),
399 convert_constraint(&c[1]),
400 convert_constraint(&c[2]),
401 )
402 })
403 .collect_vec();
404
405 R1CS {
406 num_inputs,
407 num_aux,
408 num_variables: circuit_json.num_variables,
409 constraints,
410 }
411}