1#![allow(unused_variables, dead_code)]
3
4use crate::circom::circuit::Constraint;
5use byteorder::{LittleEndian, ReadBytesExt};
6use ff::PrimeField;
7use hex_literal::hex;
8use nova_snark::traits::Group;
9use std::{
10 collections::HashMap,
11 io::{Error, ErrorKind, Read, Result, Seek, SeekFrom},
12};
13
14#[derive(Debug, Default)]
16pub struct Header {
17 pub field_size: u32,
18 pub prime_size: Vec<u8>,
19 pub n_wires: u32,
20 pub n_pub_out: u32,
21 pub n_pub_in: u32,
22 pub n_prv_in: u32,
23 pub n_labels: u64,
24 pub n_constraints: u32,
25}
26
27#[derive(Debug, Default)]
29pub struct R1CSFile<Fr: PrimeField> {
30 pub version: u32,
31 pub header: Header,
32 pub constraints: Vec<Constraint<Fr>>,
33 pub wire_mapping: Vec<u64>,
34}
35
36pub(crate) fn read_field<R: Read, Fr: PrimeField>(mut reader: R) -> Result<Fr> {
37 let mut repr = Fr::ZERO.to_repr();
38 for digit in repr.as_mut().iter_mut() {
39 *digit = reader.read_u8()?;
41 }
42 let fr = Fr::from_repr(repr).unwrap();
43 Ok(fr)
44}
45
46fn read_header<R: Read>(mut reader: R, size: u64) -> Result<Header> {
47 let field_size = reader.read_u32::<LittleEndian>()?;
48 let mut prime_size = vec![0u8; field_size as usize];
49 reader.read_exact(&mut prime_size)?;
50 if size != 32 + field_size as u64 {
51 return Err(Error::new(
52 ErrorKind::InvalidData,
53 "Invalid header section size",
54 ));
55 }
56
57 Ok(Header {
58 field_size,
59 prime_size,
60 n_wires: reader.read_u32::<LittleEndian>()?,
61 n_pub_out: reader.read_u32::<LittleEndian>()?,
62 n_pub_in: reader.read_u32::<LittleEndian>()?,
63 n_prv_in: reader.read_u32::<LittleEndian>()?,
64 n_labels: reader.read_u64::<LittleEndian>()?,
65 n_constraints: reader.read_u32::<LittleEndian>()?,
66 })
67}
68
69fn read_constraint_vec<R: Read, Fr: PrimeField>(
70 mut reader: R,
71 header: &Header,
72) -> Result<Vec<(usize, Fr)>> {
73 let n_vec = reader.read_u32::<LittleEndian>()? as usize;
74 let mut vec = Vec::with_capacity(n_vec);
75 for _ in 0..n_vec {
76 vec.push((
77 reader.read_u32::<LittleEndian>()? as usize,
78 read_field::<&mut R, Fr>(&mut reader)?,
79 ));
80 }
81 Ok(vec)
82}
83
84fn read_constraints<R: Read, Fr: PrimeField>(
85 mut reader: R,
86 size: u64,
87 header: &Header,
88) -> Result<Vec<Constraint<Fr>>> {
89 let mut vec = Vec::with_capacity(header.n_constraints as usize);
91 for _ in 0..header.n_constraints {
92 vec.push((
93 read_constraint_vec::<&mut R, Fr>(&mut reader, header)?,
94 read_constraint_vec::<&mut R, Fr>(&mut reader, header)?,
95 read_constraint_vec::<&mut R, Fr>(&mut reader, header)?,
96 ));
97 }
98 Ok(vec)
99}
100
101fn read_map<R: Read>(mut reader: R, size: u64, header: &Header) -> Result<Vec<u64>> {
102 if size != header.n_wires as u64 * 8 {
103 return Err(Error::new(
104 ErrorKind::InvalidData,
105 "Invalid map section size",
106 ));
107 }
108 let mut vec = Vec::with_capacity(header.n_wires as usize);
109 for _ in 0..header.n_wires {
110 vec.push(reader.read_u64::<LittleEndian>()?);
111 }
112 if vec[0] != 0 {
113 return Err(Error::new(
114 ErrorKind::InvalidData,
115 "Wire 0 should always be mapped to 0",
116 ));
117 }
118 Ok(vec)
119}
120
121pub fn from_reader<R: Read + Seek, G1, G2>(mut reader: R) -> Result<R1CSFile<<G1 as Group>::Scalar>>
122where
123 G1: Group<Base = <G2 as Group>::Scalar>,
124 G2: Group<Base = <G1 as Group>::Scalar>,
125{
126 let mut magic = [0u8; 4];
127 reader.read_exact(&mut magic)?;
128 if magic != [0x72, 0x31, 0x63, 0x73] {
129 return Err(Error::new(ErrorKind::InvalidData, "Invalid magic number"));
131 }
132
133 let version = reader.read_u32::<LittleEndian>()?;
134 if version != 1 {
135 return Err(Error::new(ErrorKind::InvalidData, "Unsupported version"));
136 }
137
138 let num_sections = reader.read_u32::<LittleEndian>()?;
139
140 let mut section_offsets = HashMap::<u32, u64>::new();
142 let mut section_sizes = HashMap::<u32, u64>::new();
143
144 for _ in 0..num_sections {
146 let section_type = reader.read_u32::<LittleEndian>()?;
147 let section_size = reader.read_u64::<LittleEndian>()?;
148 let offset = reader.seek(SeekFrom::Current(0))?;
149 section_offsets.insert(section_type, offset);
150 section_sizes.insert(section_type, section_size);
151 reader.seek(SeekFrom::Current(section_size as i64))?;
152 }
153
154 let header_type = 1;
155 let constraint_type = 2;
156 let wire2label_type = 3;
157
158 reader.seek(SeekFrom::Start(*section_offsets.get(&header_type).unwrap()))?;
159 let header = read_header(&mut reader, *section_sizes.get(&header_type).unwrap())?;
160 if header.field_size != 32 {
161 return Err(Error::new(
162 ErrorKind::InvalidData,
163 "This parser only supports 32-byte fields",
164 ));
165 }
166
167 reader.seek(SeekFrom::Start(
177 *section_offsets.get(&constraint_type).unwrap(),
178 ))?;
179 let constraints = read_constraints::<&mut R, <G1 as Group>::Scalar>(
180 &mut reader,
181 *section_sizes.get(&constraint_type).unwrap(),
182 &header,
183 )?;
184
185 reader.seek(SeekFrom::Start(
186 *section_offsets.get(&wire2label_type).unwrap(),
187 ))?;
188 let wire_mapping = read_map(
189 &mut reader,
190 *section_sizes.get(&wire2label_type).unwrap(),
191 &header,
192 )?;
193
194 Ok(R1CSFile {
195 version,
196 header,
197 constraints,
198 wire_mapping,
199 })
200}
201
202mod tests {
203 #[test]
204 fn sample() {
205 use super::*;
206 use hex_literal::hex;
207 use std::io::{BufReader, Cursor};
208
209 let data = hex!(
210 "
211 72316373
212 01000000
213 03000000
214 01000000 40000000 00000000
215 20000000
216 010000f0 93f5e143 9170b979 48e83328 5d588181 b64550b8 29a031e1 724e6430
217 07000000
218 01000000
219 02000000
220 03000000
221 e8030000 00000000
222 03000000
223 02000000 88020000 00000000
224 02000000
225 05000000 03000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
226 06000000 08000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
227 03000000
228 00000000 02000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
229 02000000 14000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
230 03000000 0C000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
231 02000000
232 00000000 05000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
233 02000000 07000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
234 03000000
235 01000000 04000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
236 04000000 08000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
237 05000000 03000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
238 02000000
239 03000000 2C000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
240 06000000 06000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
241 00000000
242 01000000
243 06000000 04000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
244 03000000
245 00000000 06000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
246 02000000 0B000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
247 03000000 05000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
248 01000000
249 06000000 58020000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
250 03000000 38000000 00000000
251 00000000 00000000
252 03000000 00000000
253 0a000000 00000000
254 0b000000 00000000
255 0c000000 00000000
256 0f000000 00000000
257 44010000 00000000
258 "
259 );
260
261 type G1 = pasta_curves::pallas::Point;
262 type G2 = pasta_curves::vesta::Point;
263
264 let reader = BufReader::new(Cursor::new(&data[..]));
265 let file = from_reader::<_, G1, G2>(reader).unwrap();
266 assert_eq!(file.version, 1);
267
268 assert_eq!(file.header.field_size, 32);
269 assert_eq!(
270 file.header.prime_size,
271 &hex!("010000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430")
272 );
273 assert_eq!(file.header.n_wires, 7);
274 assert_eq!(file.header.n_pub_out, 1);
275 assert_eq!(file.header.n_pub_in, 2);
276 assert_eq!(file.header.n_prv_in, 3);
277 assert_eq!(file.header.n_labels, 0x03e8);
278 assert_eq!(file.header.n_constraints, 3);
279
280 assert_eq!(file.constraints.len(), 3);
281 assert_eq!(file.constraints[0].0.len(), 2);
282 assert_eq!(file.constraints[0].0[0].0, 5);
283 assert_eq!(file.constraints[2].1[0].0, 0);
285 assert_eq!(file.constraints[1].2.len(), 0);
287
288 assert_eq!(file.wire_mapping.len(), 7);
289 assert_eq!(file.wire_mapping[1], 3);
290 }
291
292 #[test]
293 fn test_reader_size_fail() {
294 use super::*;
295
296 let mut buf: Vec<u8> = 32_u32.to_le_bytes().to_vec();
298 buf.resize(4 + 32, 0);
299 let err = read_header(&mut buf.as_slice(), 32).err().unwrap();
300 assert_eq!(err.kind(), ErrorKind::InvalidData)
301 }
302}