1use ark_ff::PrimeField;
5use byteorder::{LittleEndian, ReadBytesExt};
6use std::io::{Error, ErrorKind};
7
8use ark_serialize::{SerializationError, SerializationError::IoError};
9use ark_std::io::{Read, Seek, SeekFrom};
10
11use std::collections::HashMap;
12
13type IoResult<T> = Result<T, SerializationError>;
14
15use super::{ConstraintVec, Constraints};
16
17#[derive(Clone, Debug)]
18pub struct R1CS<F> {
19 pub num_inputs: usize,
20 pub num_aux: usize,
21 pub num_variables: usize,
22 pub constraints: Vec<Constraints<F>>,
23 pub wire_mapping: Option<Vec<usize>>,
24}
25
26impl<F: PrimeField> From<R1CSFile<F>> for R1CS<F> {
27 fn from(file: R1CSFile<F>) -> Self {
28 let num_inputs = (1 + file.header.n_pub_in + file.header.n_pub_out) as usize;
29 let num_variables = file.header.n_wires as usize;
30 let num_aux = num_variables - num_inputs;
31 R1CS {
32 num_aux,
33 num_inputs,
34 num_variables,
35 constraints: file.constraints,
36 wire_mapping: Some(file.wire_mapping.iter().map(|e| *e as usize).collect()),
37 }
38 }
39}
40
41pub struct R1CSFile<F: PrimeField> {
42 pub version: u32,
43 pub header: Header,
44 pub constraints: Vec<Constraints<F>>,
45 pub wire_mapping: Vec<u64>,
46}
47
48impl<F: PrimeField> R1CSFile<F> {
49 pub fn new<R: Read + Seek>(mut reader: R) -> IoResult<R1CSFile<F>> {
55 let mut magic = [0u8; 4];
56 reader.read_exact(&mut magic)?;
57 if magic != [0x72, 0x31, 0x63, 0x73] {
58 return Err(IoError(Error::new(
59 ErrorKind::InvalidData,
60 "Invalid magic number",
61 )));
62 }
63
64 let version = reader.read_u32::<LittleEndian>()?;
65 if version != 1 {
66 return Err(IoError(Error::new(
67 ErrorKind::InvalidData,
68 "Unsupported version",
69 )));
70 }
71
72 let num_sections = reader.read_u32::<LittleEndian>()?;
73
74 let mut sec_offsets = HashMap::<u32, u64>::new();
77 let mut sec_sizes = HashMap::<u32, u64>::new();
78
79 for _ in 0..num_sections {
81 let sec_type = reader.read_u32::<LittleEndian>()?;
82 let sec_size = reader.read_u64::<LittleEndian>()?;
83 let offset = reader.stream_position()?;
84 sec_offsets.insert(sec_type, offset);
85 sec_sizes.insert(sec_type, sec_size);
86 reader.seek(SeekFrom::Current(sec_size as i64))?;
87 }
88
89 let header_type = 1;
90 let constraint_type = 2;
91 let wire2label_type = 3;
92
93 let header_offset = sec_offsets.get(&header_type).ok_or_else(|| {
94 Error::new(
95 ErrorKind::InvalidData,
96 "No section offset for header type found",
97 )
98 });
99
100 reader.seek(SeekFrom::Start(*header_offset?))?;
101
102 let header_size = sec_sizes.get(&header_type).ok_or_else(|| {
103 Error::new(
104 ErrorKind::InvalidData,
105 "No section size for header type found",
106 )
107 });
108
109 let header = Header::new(&mut reader, *header_size?)?;
110
111 let constraint_offset = sec_offsets.get(&constraint_type).ok_or_else(|| {
112 Error::new(
113 ErrorKind::InvalidData,
114 "No section offset for constraint type found",
115 )
116 });
117
118 reader.seek(SeekFrom::Start(*constraint_offset?))?;
119
120 let constraints = read_constraints::<&mut R, F>(&mut reader, &header)?;
121
122 let wire2label_offset = sec_offsets.get(&wire2label_type).ok_or_else(|| {
123 Error::new(
124 ErrorKind::InvalidData,
125 "No section offset for wire2label type found",
126 )
127 });
128
129 reader.seek(SeekFrom::Start(*wire2label_offset?))?;
130
131 let wire2label_size = sec_sizes.get(&wire2label_type).ok_or_else(|| {
132 Error::new(
133 ErrorKind::InvalidData,
134 "No section size for wire2label type found",
135 )
136 });
137
138 let wire_mapping = read_map(&mut reader, *wire2label_size?, &header)?;
139
140 Ok(R1CSFile {
141 version,
142 header,
143 constraints,
144 wire_mapping,
145 })
146 }
147}
148
149pub struct Header {
150 pub field_size: u32,
151 pub prime_size: Vec<u8>,
152 pub n_wires: u32,
153 pub n_pub_out: u32,
154 pub n_pub_in: u32,
155 pub n_prv_in: u32,
156 pub n_labels: u64,
157 pub n_constraints: u32,
158}
159
160impl Header {
161 fn new<R: Read>(mut reader: R, size: u64) -> IoResult<Header> {
162 let field_size = reader.read_u32::<LittleEndian>()?;
163 if field_size != 32 {
164 return Err(IoError(Error::new(
165 ErrorKind::InvalidData,
166 "This parser only supports 32-byte fields",
167 )));
168 }
169
170 if size != 32 + field_size as u64 {
171 return Err(IoError(Error::new(
172 ErrorKind::InvalidData,
173 "Invalid header section size",
174 )));
175 }
176
177 let mut prime_size = vec![0u8; field_size as usize];
178 reader.read_exact(&mut prime_size)?;
179
180 if prime_size
181 != hex::decode("010000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430")
182 .unwrap()
183 {
184 return Err(IoError(Error::new(
185 ErrorKind::InvalidData,
186 "This parser only supports bn256",
187 )));
188 }
189
190 Ok(Header {
191 field_size,
192 prime_size,
193 n_wires: reader.read_u32::<LittleEndian>()?,
194 n_pub_out: reader.read_u32::<LittleEndian>()?,
195 n_pub_in: reader.read_u32::<LittleEndian>()?,
196 n_prv_in: reader.read_u32::<LittleEndian>()?,
197 n_labels: reader.read_u64::<LittleEndian>()?,
198 n_constraints: reader.read_u32::<LittleEndian>()?,
199 })
200 }
201}
202
203fn read_constraint_vec<R: Read, F: PrimeField>(mut reader: R) -> IoResult<ConstraintVec<F>> {
204 let n_vec = reader.read_u32::<LittleEndian>()? as usize;
205 let mut vec = Vec::with_capacity(n_vec);
206 for _ in 0..n_vec {
207 vec.push((
208 reader.read_u32::<LittleEndian>()? as usize,
209 F::deserialize_uncompressed(&mut reader)?,
210 ));
211 }
212 Ok(vec)
213}
214
215fn read_constraints<R: Read, F: PrimeField>(
216 mut reader: R,
217 header: &Header,
218) -> IoResult<Vec<Constraints<F>>> {
219 let mut vec = Vec::with_capacity(header.n_constraints as usize);
221 for _ in 0..header.n_constraints {
222 vec.push((
223 read_constraint_vec::<&mut R, F>(&mut reader)?,
224 read_constraint_vec::<&mut R, F>(&mut reader)?,
225 read_constraint_vec::<&mut R, F>(&mut reader)?,
226 ));
227 }
228 Ok(vec)
229}
230
231fn read_map<R: Read>(mut reader: R, size: u64, header: &Header) -> IoResult<Vec<u64>> {
232 if size != header.n_wires as u64 * 8 {
233 return Err(IoError(Error::new(
234 ErrorKind::InvalidData,
235 "Invalid map section size",
236 )));
237 }
238 let mut vec = Vec::with_capacity(header.n_wires as usize);
239 for _ in 0..header.n_wires {
240 vec.push(reader.read_u64::<LittleEndian>()?);
241 }
242 if vec[0] != 0 {
243 return Err(IoError(Error::new(
244 ErrorKind::InvalidData,
245 "Wire 0 should always be mapped to 0",
246 )));
247 }
248 Ok(vec)
249}
250
251#[cfg(test)]
252mod tests {
253 use super::*;
254 use ark_bn254::Fr;
255 use ark_std::io::{BufReader, Cursor};
256
257 #[test]
258 fn sample() {
259 let data = hex_literal::hex!(
260 "
261 72316373
262 01000000
263 03000000
264 01000000 40000000 00000000
265 20000000
266 010000f0 93f5e143 9170b979 48e83328 5d588181 b64550b8 29a031e1 724e6430
267 07000000
268 01000000
269 02000000
270 03000000
271 e8030000 00000000
272 03000000
273 02000000 88020000 00000000
274 02000000
275 05000000 03000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
276 06000000 08000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
277 03000000
278 00000000 02000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
279 02000000 14000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
280 03000000 0C000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
281 02000000
282 00000000 05000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
283 02000000 07000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
284 03000000
285 01000000 04000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
286 04000000 08000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
287 05000000 03000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
288 02000000
289 03000000 2C000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
290 06000000 06000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
291 00000000
292 01000000
293 06000000 04000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
294 03000000
295 00000000 06000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
296 02000000 0B000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
297 03000000 05000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
298 01000000
299 06000000 58020000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
300 03000000 38000000 00000000
301 00000000 00000000
302 03000000 00000000
303 0a000000 00000000
304 0b000000 00000000
305 0c000000 00000000
306 0f000000 00000000
307 44010000 00000000
308 "
309 );
310
311 let reader = BufReader::new(Cursor::new(&data[..]));
312 let file = R1CSFile::<Fr>::new(reader).unwrap();
313 assert_eq!(file.version, 1);
314
315 assert_eq!(file.header.field_size, 32);
316 assert_eq!(
317 file.header.prime_size,
318 hex::decode("010000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430")
319 .unwrap(),
320 );
321 assert_eq!(file.header.n_wires, 7);
322 assert_eq!(file.header.n_pub_out, 1);
323 assert_eq!(file.header.n_pub_in, 2);
324 assert_eq!(file.header.n_prv_in, 3);
325 assert_eq!(file.header.n_labels, 0x03e8);
326 assert_eq!(file.header.n_constraints, 3);
327
328 assert_eq!(file.constraints.len(), 3);
329 assert_eq!(file.constraints[0].0.len(), 2);
330 assert_eq!(file.constraints[0].0[0].0, 5);
331 assert_eq!(file.constraints[0].0[0].1, Fr::from(3));
332 assert_eq!(file.constraints[2].1[0].0, 0);
333 assert_eq!(file.constraints[2].1[0].1, Fr::from(6));
334 assert_eq!(file.constraints[1].2.len(), 0);
335
336 assert_eq!(file.wire_mapping.len(), 7);
337 assert_eq!(file.wire_mapping[1], 3);
338 }
339}