legogroth16/circom/
r1cs_reader.rs

1//! Parser for .r1cs file generated by Circom compiler.
2//! Largely copied from <https://github.com/gakonst/ark-circom/blob/master/src/circom/r1cs_reader.rs>
3//! Spec: <https://github.com/iden3/r1csfile/blob/master/doc/r1cs_bin_format.md>
4
5use ark_ec::pairing::Pairing;
6use ark_serialize::CanonicalDeserialize;
7use ark_std::{collections::BTreeMap, format, io::Read, marker::PhantomData, vec, vec::Vec};
8use std::io::{Seek, SeekFrom};
9
10use crate::circom::{
11    error::CircomError,
12    r1cs::{Constraint, Header, R1CSFile, LC},
13    witness::check_subgroup_order,
14};
15
16impl<E: Pairing> R1CSFile<E> {
17    pub fn new_from_file(path: impl AsRef<std::path::Path>) -> Result<Self, CircomError> {
18        let reader = std::fs::File::open(path).map_err(|err| {
19            log::error!("Encountered error while opening R1CS file: {:?}", err);
20            CircomError::UnableToOpenR1CSFile(format!(
21                "Encountered error while opening R1CS file: {:?}",
22                err
23            ))
24        })?;
25        Self::new(reader)
26    }
27
28    /// reader must implement the Seek trait, for example with a Cursor
29    ///
30    /// ```rust,ignore
31    /// let reader = BufReader::new(Cursor::new(&data[..]));
32    /// ```
33    pub fn new<R: Read + Seek>(mut reader: R) -> Result<Self, CircomError> {
34        let mut magic = [0u8; 4];
35        read_exact(&mut reader, &mut magic)?;
36        if magic != [0x72, 0x31, 0x63, 0x73] {
37            // magic = "r1cs"
38            return Err(CircomError::R1CSFileParsing(
39                "Invalid magic number".to_string(),
40            ));
41        }
42
43        let version = read_u32(&mut reader)?;
44        if version != 1 {
45            return Err(CircomError::R1CSFileParsing(
46                "Unsupported version".to_string(),
47            ));
48        }
49
50        let num_sections = read_u32(&mut reader)?;
51
52        // todo: handle sec_size correctly
53        // section type -> file offset
54        let mut sec_offsets = BTreeMap::<u32, u64>::new();
55        let mut sec_sizes = BTreeMap::<u32, u64>::new();
56
57        // get file offset of each section
58        for _ in 0..num_sections {
59            let sec_type = read_u32(&mut reader)?;
60            let sec_size = read_u64(&mut reader)?;
61            let offset = seek(&mut reader, SeekFrom::Current(0))?;
62            sec_offsets.insert(sec_type, offset);
63            sec_sizes.insert(sec_type, sec_size);
64            seek(&mut reader, SeekFrom::Current(sec_size as i64))?;
65        }
66
67        let header_type = 1;
68        let constraint_type = 2;
69        let wire2label_type = 3;
70
71        let header_offset = sec_offsets.get(&header_type).ok_or_else(|| {
72            CircomError::R1CSFileParsing("No section offset for header type found".to_string())
73        })?;
74
75        seek(&mut reader, SeekFrom::Start(*header_offset))?;
76
77        let header_size = sec_sizes.get(&header_type).ok_or_else(|| {
78            CircomError::R1CSFileParsing("No section size for header type found".to_string())
79        })?;
80
81        let header = Header::new(&mut reader, *header_size)?;
82
83        let constraint_offset = sec_offsets.get(&constraint_type).ok_or_else(|| {
84            CircomError::R1CSFileParsing("No section offset for constraint type found".to_string())
85        })?;
86
87        seek(&mut reader, SeekFrom::Start(*constraint_offset))?;
88
89        let constraints = read_constraints::<&mut R, E>(&mut reader, &header)?;
90
91        let wire2label_offset = sec_offsets.get(&wire2label_type).ok_or_else(|| {
92            CircomError::R1CSFileParsing("No section offset for wire2label type found".to_string())
93        })?;
94
95        seek(&mut reader, SeekFrom::Start(*wire2label_offset))?;
96
97        let wire2label_size = sec_sizes.get(&wire2label_type).ok_or_else(|| {
98            CircomError::R1CSFileParsing("No section size for wire2label type found".to_string())
99        })?;
100
101        let wire_mapping = read_map(&mut reader, *wire2label_size, &header)?;
102
103        Ok(R1CSFile {
104            version,
105            header,
106            constraints,
107            wire_mapping,
108        })
109    }
110}
111
112impl<E: Pairing> Header<E> {
113    fn new<R: Read>(mut reader: R, size: u64) -> Result<Header<E>, CircomError> {
114        let field_size = read_u32(&mut reader)?;
115        if field_size != 32 {
116            return Err(CircomError::R1CSFileParsing(
117                "This parser only supports 32-byte fields".to_string(),
118            ));
119        }
120
121        if size != 32 + field_size as u64 {
122            return Err(CircomError::R1CSFileParsing(
123                "Invalid header section size".to_string(),
124            ));
125        }
126
127        // Subgroup order is encoded in little endian bytes
128        let mut subgroup_order_bytes = vec![0u8; field_size as usize];
129        read_exact(&mut reader, &mut subgroup_order_bytes)?;
130        let curve = check_subgroup_order::<E>(&subgroup_order_bytes)?;
131
132        Ok(Header {
133            field_size,
134            subgroup_order: subgroup_order_bytes,
135            curve,
136            n_wires: read_u32(&mut reader)?,
137            n_pub_out: read_u32(&mut reader)?,
138            n_pub_in: read_u32(&mut reader)?,
139            n_prv_in: read_u32(&mut reader)?,
140            n_labels: read_u64(&mut reader)?,
141            n_constraints: read_u32(&mut reader)?,
142            phantom: PhantomData,
143        })
144    }
145}
146
147fn read_u32<R: Read>(reader: R) -> Result<u32, CircomError> {
148    let mut buf = [0; 4];
149    read_exact(reader, &mut buf)?;
150    Ok(u32::from_le_bytes(buf))
151}
152
153fn read_u64<R: Read>(reader: R) -> Result<u64, CircomError> {
154    let mut buf = [0; 8];
155    read_exact(reader, &mut buf)?;
156    Ok(u64::from_le_bytes(buf))
157}
158
159fn read_exact<R: Read>(mut reader: R, buf: &mut [u8]) -> Result<(), CircomError> {
160    reader.read_exact(buf).map_err(|err| {
161        log::error!("Encountered error while parsing R1CS file: {:?}", err);
162        CircomError::R1CSFileParsing(format!(
163            "Encountered error while parsing R1CS file: {:?}",
164            err
165        ))
166    })
167}
168
169fn seek<R: Read + Seek>(mut reader: R, pos: SeekFrom) -> Result<u64, CircomError> {
170    reader.seek(pos).map_err(|err| {
171        log::error!("Encountered error while parsing R1CS file: {:?}", err);
172        CircomError::R1CSFileParsing(format!(
173            "Encountered error while parsing R1CS file: {:?}",
174            err
175        ))
176    })
177}
178
179/// Read a linear combination
180fn read_lc<R: Read, E: Pairing>(mut reader: R) -> Result<LC<E>, CircomError> {
181    let num_terms = read_u32(&mut reader)? as usize;
182    let mut terms = Vec::with_capacity(num_terms);
183    for _ in 0..num_terms {
184        terms.push((
185            read_u32(&mut reader)? as usize, // wire_id
186            E::ScalarField::deserialize_uncompressed(&mut reader) // coefficient
187                .map_err(|err| {
188                    log::error!("Encountered error while parsing R1CS file: {:?}", err);
189                    CircomError::R1CSFileParsing(format!(
190                        "Encountered error while parsing R1CS file: {:?}",
191                        err
192                    ))
193                })?,
194        ));
195    }
196    Ok(LC(terms))
197}
198
199/// Read all the constraints where each constraint is a 3-tuple of linear combinations
200fn read_constraints<R: Read, E: Pairing>(
201    mut reader: R,
202    header: &Header<E>,
203) -> Result<Vec<Constraint<E>>, CircomError> {
204    // todo check section size
205    let mut vec = Vec::with_capacity(header.n_constraints as usize);
206    for _ in 0..header.n_constraints {
207        vec.push({
208            let a = read_lc::<&mut R, E>(&mut reader)?;
209            let b = read_lc::<&mut R, E>(&mut reader)?;
210            let c = read_lc::<&mut R, E>(&mut reader)?;
211            Constraint { a, b, c }
212        });
213    }
214    Ok(vec)
215}
216
217/// Read the wire to label map. The labels not part of constraints because they were
218/// optimized out are not part of this map.
219fn read_map<R: Read, E: Pairing>(
220    mut reader: R,
221    size: u64,
222    header: &Header<E>,
223) -> Result<Vec<u64>, CircomError> {
224    if size != header.n_wires as u64 * 8 {
225        return Err(CircomError::R1CSFileParsing(
226            "Invalid map section size".to_string(),
227        ));
228    }
229    let mut vec = Vec::with_capacity(header.n_wires as usize);
230    for _ in 0..header.n_wires {
231        vec.push(read_u64(&mut reader)?);
232    }
233    if vec[0] != 0 {
234        return Err(CircomError::R1CSFileParsing(
235            "Wire 0 should always be mapped to 0".to_string(),
236        ));
237    }
238    Ok(vec)
239}
240
241#[cfg(test)]
242mod tests {
243    use super::*;
244    use crate::circom::{r1cs::Curve, tests::abs_path};
245    use ark_bls12_381::Bls12_381;
246    use ark_bn254::{Bn254, Fr as BnFr};
247    use ark_std::io::{BufReader, Cursor};
248    use num_bigint::BigUint;
249    use std::str::FromStr;
250
251    /// Some basic checks that should be true for all supported circuits
252    fn basic_checks<E: Pairing>(file: &R1CSFile<E>, curve_type: Curve) {
253        assert_eq!(file.version, 1);
254        assert_eq!(file.header.field_size, 32);
255        assert_eq!(file.header.curve, curve_type);
256
257        if curve_type == Curve::Bn128 {
258            assert_eq!(
259                file.header.subgroup_order,
260                BigUint::from_str(
261                    "21888242871839275222246405745257275088548364400416034343698204186575808495617"
262                )
263                .unwrap()
264                .to_bytes_le(),
265            );
266        }
267
268        if curve_type == Curve::Bls12_381 {
269            assert_eq!(
270                file.header.subgroup_order,
271                BigUint::from_str(
272                    "52435875175126190479447740508185965837690552500527637822603658699938581184513"
273                )
274                .unwrap()
275                .to_bytes_le(),
276            );
277        }
278
279        assert!(file.header.n_labels >= file.header.n_wires as u64);
280        assert_eq!(file.wire_mapping.len() as u32, file.header.n_wires);
281    }
282
283    #[test]
284    fn bn_254() {
285        let data = hex_literal::hex!(
286            "
287        72316373
288        01000000
289        03000000
290        01000000 40000000 00000000
291        20000000
292        010000f0 93f5e143 9170b979 48e83328 5d588181 b64550b8 29a031e1 724e6430
293        07000000
294        01000000
295        02000000
296        03000000
297        e8030000 00000000
298        03000000
299        02000000 88020000 00000000
300        02000000
301        05000000 03000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
302        06000000 08000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
303        03000000
304        00000000 02000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
305        02000000 14000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
306        03000000 0C000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
307        02000000
308        00000000 05000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
309        02000000 07000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
310        03000000
311        01000000 04000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
312        04000000 08000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
313        05000000 03000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
314        02000000
315        03000000 2C000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
316        06000000 06000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
317        00000000
318        01000000
319        06000000 04000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
320        03000000
321        00000000 06000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
322        02000000 0B000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
323        03000000 05000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
324        01000000
325        06000000 58020000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
326        03000000 38000000 00000000
327        00000000 00000000
328        03000000 00000000
329        0a000000 00000000
330        0b000000 00000000
331        0c000000 00000000
332        0f000000 00000000
333        44010000 00000000
334    "
335        );
336
337        let reader = BufReader::new(Cursor::new(&data[..]));
338        let file = R1CSFile::<Bn254>::new(reader).unwrap();
339        basic_checks(&file, Curve::Bn128);
340        assert_eq!(file.header.n_wires, 7);
341        assert_eq!(file.header.n_pub_out, 1);
342        assert_eq!(file.header.n_pub_in, 2);
343        assert_eq!(file.header.n_prv_in, 3);
344        assert_eq!(file.header.n_labels, 0x03e8);
345        assert_eq!(file.header.n_constraints, 3);
346
347        assert_eq!(file.constraints.len(), 3);
348        assert_eq!(file.constraints[0].a.len(), 2);
349        assert_eq!(file.constraints[0].a.0[0].0, 5);
350        assert_eq!(file.constraints[0].a.0[0].1, BnFr::from(3));
351        assert_eq!(file.constraints[2].b.0[0].0, 0);
352        assert_eq!(file.constraints[2].b.0[0].1, BnFr::from(6));
353        assert_eq!(file.constraints[1].c.len(), 0);
354
355        assert_eq!(file.wire_mapping.len(), 7);
356        assert_eq!(file.wire_mapping[1], 3);
357    }
358
359    #[test]
360    fn input_validation() {
361        assert_eq!(
362            R1CSFile::<Bn254>::new_from_file(abs_path("test-vectors/bls12-381/multiply2.r1cs"))
363                .unwrap_err(),
364            CircomError::IncompatibleWithCurve
365        );
366        assert_eq!(
367            R1CSFile::<Bls12_381>::new_from_file(abs_path("test-vectors/bn128/multiply2.r1cs"))
368                .unwrap_err(),
369            CircomError::IncompatibleWithCurve
370        );
371
372        // The `multiply2_goldilocks` files are generated by passing flag `-p=goldilocks` to the Circom compiler
373        assert_eq!(
374            R1CSFile::<Bn254>::new_from_file(abs_path("test-vectors/multiply2_goldilocks.r1cs"))
375                .unwrap_err(),
376            CircomError::R1CSFileParsing("This parser only supports 32-byte fields".to_string())
377        );
378        assert_eq!(
379            R1CSFile::<Bls12_381>::new_from_file(abs_path(
380                "test-vectors/multiply2_goldilocks.r1cs"
381            ))
382            .unwrap_err(),
383            CircomError::R1CSFileParsing("This parser only supports 32-byte fields".to_string())
384        );
385    }
386
387    #[test]
388    fn multiply2() {
389        fn check<E: Pairing>(file: &R1CSFile<E>, curve_type: Curve) {
390            basic_checks(&file, curve_type);
391            // 4 wires, 1st wire for constant 1, 2nd for input a, 3rd for input b and 4th for input c.
392            assert_eq!(file.header.n_wires, 4);
393            assert_eq!(file.header.n_labels, 4);
394            assert_eq!(file.header.n_pub_out, 1);
395            assert_eq!(file.header.n_pub_in, 0);
396            assert_eq!(file.header.n_prv_in, 2);
397            assert_eq!(file.header.n_constraints, 1);
398
399            assert_eq!(file.constraints.len(), 1);
400            assert_eq!(file.constraints[0].a.len(), 1);
401            assert_eq!(file.constraints[0].b.len(), 1);
402            assert_eq!(file.constraints[0].c.len(), 1);
403
404            assert_eq!(file.wire_mapping, vec![0, 1, 2, 3]);
405        }
406        check(
407            &R1CSFile::<Bn254>::new_from_file(abs_path("test-vectors/bn128/multiply2.r1cs"))
408                .unwrap(),
409            Curve::Bn128,
410        );
411        check(
412            &R1CSFile::<Bls12_381>::new_from_file(abs_path(
413                "test-vectors/bls12-381/multiply2.r1cs",
414            ))
415            .unwrap(),
416            Curve::Bls12_381,
417        );
418    }
419
420    #[test]
421    fn test_1() {
422        fn check<E: Pairing>(file: &R1CSFile<E>, curve_type: Curve) {
423            basic_checks(&file, curve_type);
424            assert_eq!(file.header.n_wires, 4);
425            assert_eq!(file.header.n_labels, 5);
426            assert_eq!(file.header.n_pub_out, 1);
427            assert_eq!(file.header.n_pub_in, 0);
428            assert_eq!(file.header.n_prv_in, 1);
429            assert_eq!(file.header.n_constraints, 2);
430
431            assert_eq!(file.constraints.len(), 2);
432            assert_eq!(file.constraints[0].a.len(), 1);
433            assert_eq!(file.constraints[0].b.len(), 1);
434            assert_eq!(file.constraints[0].c.len(), 1);
435            assert_eq!(file.constraints[1].a.len(), 1);
436            assert_eq!(file.constraints[1].b.len(), 1);
437            assert_eq!(file.constraints[1].c.len(), 3);
438
439            assert_eq!(file.wire_mapping, vec![0, 1, 2, 3]);
440        }
441
442        check(
443            &R1CSFile::<Bn254>::new_from_file(abs_path("test-vectors/bn128/test1.r1cs")).unwrap(),
444            Curve::Bn128,
445        );
446        check(
447            &R1CSFile::<Bls12_381>::new_from_file(abs_path("test-vectors/bls12-381/test1.r1cs"))
448                .unwrap(),
449            Curve::Bls12_381,
450        );
451    }
452
453    #[test]
454    fn test_2() {
455        fn check<E: Pairing>(file: &R1CSFile<E>, curve_type: Curve) {
456            basic_checks(&file, curve_type);
457            assert_eq!(file.header.n_wires, 6);
458            assert_eq!(file.header.n_labels, 7);
459            assert_eq!(file.header.n_pub_out, 1);
460            assert_eq!(file.header.n_pub_in, 0);
461            assert_eq!(file.header.n_prv_in, 2);
462            assert_eq!(file.header.n_constraints, 3);
463
464            assert_eq!(file.constraints.len(), 3);
465            assert_eq!(file.constraints[0].a.len(), 1);
466            assert_eq!(file.constraints[0].b.len(), 1);
467            assert_eq!(file.constraints[0].c.len(), 1);
468            assert_eq!(file.constraints[1].a.len(), 1);
469            assert_eq!(file.constraints[1].b.len(), 1);
470            assert_eq!(file.constraints[1].c.len(), 1);
471            assert_eq!(file.constraints[2].a.len(), 1);
472            assert_eq!(file.constraints[2].b.len(), 1);
473            assert_eq!(file.constraints[2].c.len(), 5);
474
475            assert_eq!(file.wire_mapping, vec![0, 1, 2, 3, 4, 5]);
476        }
477
478        check(
479            &R1CSFile::<Bn254>::new_from_file(abs_path("test-vectors/bn128/test2.r1cs")).unwrap(),
480            Curve::Bn128,
481        );
482        check(
483            &R1CSFile::<Bls12_381>::new_from_file(abs_path("test-vectors/bls12-381/test2.r1cs"))
484                .unwrap(),
485            Curve::Bls12_381,
486        );
487    }
488
489    #[test]
490    fn test_3() {
491        fn check<E: Pairing>(file: &R1CSFile<E>, curve_type: Curve) {
492            basic_checks(&file, curve_type);
493            assert_eq!(file.header.n_wires, 12);
494            assert_eq!(file.header.n_labels, 14);
495            assert_eq!(file.header.n_pub_out, 2);
496            assert_eq!(file.header.n_pub_in, 2);
497            assert_eq!(file.header.n_prv_in, 4);
498            assert_eq!(file.header.n_constraints, 5);
499
500            assert_eq!(file.constraints.len(), 5);
501            assert_eq!(file.constraints[0].a.len(), 1);
502            assert_eq!(file.constraints[0].b.len(), 1);
503            assert_eq!(file.constraints[0].c.len(), 1);
504            assert_eq!(file.constraints[1].a.len(), 1);
505            assert_eq!(file.constraints[1].b.len(), 1);
506            assert_eq!(file.constraints[1].c.len(), 1);
507            assert_eq!(file.constraints[2].a.len(), 1);
508            assert_eq!(file.constraints[2].b.len(), 1);
509            assert_eq!(file.constraints[2].c.len(), 3);
510            assert_eq!(file.constraints[3].a.len(), 1);
511            assert_eq!(file.constraints[3].b.len(), 1);
512            assert_eq!(file.constraints[3].c.len(), 1);
513            assert_eq!(file.constraints[4].a.len(), 1);
514            assert_eq!(file.constraints[4].b.len(), 1);
515            assert_eq!(file.constraints[4].c.len(), 2);
516        }
517
518        check(
519            &R1CSFile::<Bn254>::new_from_file(abs_path("test-vectors/bn128/test3.r1cs")).unwrap(),
520            Curve::Bn128,
521        );
522        check(
523            &R1CSFile::<Bls12_381>::new_from_file(abs_path("test-vectors/bls12-381/test3.r1cs"))
524                .unwrap(),
525            Curve::Bls12_381,
526        );
527    }
528
529    #[test]
530    fn test_4() {
531        fn check<E: Pairing>(file: &R1CSFile<E>, curve_type: Curve) {
532            basic_checks(&file, curve_type);
533            assert_eq!(file.header.n_wires, 40);
534            assert_eq!(file.header.n_labels, 42);
535            assert_eq!(file.header.n_pub_out, 2);
536            assert_eq!(file.header.n_pub_in, 4);
537            assert_eq!(file.header.n_prv_in, 4);
538            assert_eq!(file.header.n_constraints, 31);
539        }
540
541        check(
542            &R1CSFile::<Bn254>::new_from_file(abs_path("test-vectors/bn128/test4.r1cs")).unwrap(),
543            Curve::Bn128,
544        );
545        check(
546            &R1CSFile::<Bls12_381>::new_from_file(abs_path("test-vectors/bls12-381/test4.r1cs"))
547                .unwrap(),
548            Curve::Bls12_381,
549        );
550    }
551
552    #[test]
553    fn multiply_n() {
554        fn check<E: Pairing>(file: &R1CSFile<E>, curve_type: Curve) {
555            basic_checks(&file, curve_type);
556            assert_eq!(file.header.n_wires, 600);
557            assert_eq!(file.header.n_labels, 602);
558            assert_eq!(file.header.n_pub_out, 1);
559            assert_eq!(file.header.n_pub_in, 0);
560            assert_eq!(file.header.n_prv_in, 300);
561            assert_eq!(file.header.n_constraints, 299);
562
563            assert_eq!(file.constraints.len(), 299);
564            for i in 0..299 {
565                assert_eq!(file.constraints[i].a.len(), 1);
566                assert_eq!(file.constraints[i].b.len(), 1);
567                assert_eq!(file.constraints[i].c.len(), 1);
568            }
569
570            for i in 0..=301 {
571                assert_eq!(file.wire_mapping[i], i as u64);
572            }
573            for i in 302..=599 {
574                assert_eq!(file.wire_mapping[i], i as u64 + 1);
575            }
576        }
577
578        check(
579            &R1CSFile::<Bn254>::new_from_file(abs_path("test-vectors/bn128/multiply_n.r1cs"))
580                .unwrap(),
581            Curve::Bn128,
582        );
583        check(
584            &R1CSFile::<Bls12_381>::new_from_file(abs_path(
585                "test-vectors/bls12-381/multiply_n.r1cs",
586            ))
587            .unwrap(),
588            Curve::Bls12_381,
589        );
590    }
591
592    #[test]
593    fn nconstraints() {
594        fn check<E: Pairing>(file: &R1CSFile<E>, curve_type: Curve) {
595            basic_checks(&file, curve_type);
596            assert_eq!(file.header.n_pub_out, 1);
597            assert_eq!(file.header.n_pub_in, 0);
598            assert_eq!(file.header.n_prv_in, 1);
599            assert_eq!(file.header.n_constraints, 2499);
600
601            assert_eq!(file.constraints.len(), 2499);
602            for i in 0..2499 {
603                assert_eq!(file.constraints[i].a.len(), 1);
604                assert_eq!(file.constraints[i].b.len(), 1);
605                assert_eq!(file.constraints[i].c.len(), 2);
606            }
607        }
608        check(
609            &R1CSFile::<Bn254>::new_from_file(abs_path("test-vectors/bn128/nconstraints.r1cs"))
610                .unwrap(),
611            Curve::Bn128,
612        );
613        check(
614            &R1CSFile::<Bls12_381>::new_from_file(abs_path(
615                "test-vectors/bls12-381/nconstraints.r1cs",
616            ))
617            .unwrap(),
618            Curve::Bls12_381,
619        );
620    }
621
622    #[test]
623    fn multiply2_bounded() {
624        basic_checks(
625            &R1CSFile::<Bn254>::new_from_file(abs_path(
626                "test-vectors/bn128/multiply2_bounded.r1cs",
627            ))
628            .unwrap(),
629            Curve::Bn128,
630        );
631        basic_checks(
632            &R1CSFile::<Bls12_381>::new_from_file(abs_path(
633                "test-vectors/bls12-381/multiply2_bounded.r1cs",
634            ))
635            .unwrap(),
636            Curve::Bls12_381,
637        );
638    }
639
640    #[test]
641    fn mimc() {
642        basic_checks(
643            &R1CSFile::<Bn254>::new_from_file(abs_path("test-vectors/bn128/mimc_bn128.r1cs"))
644                .unwrap(),
645            Curve::Bn128,
646        );
647        basic_checks(
648            &R1CSFile::<Bls12_381>::new_from_file(abs_path(
649                "test-vectors/bls12-381/mimc_bls12_381.r1cs",
650            ))
651            .unwrap(),
652            Curve::Bls12_381,
653        );
654    }
655
656    #[test]
657    fn mimcsponge() {
658        basic_checks(
659            &R1CSFile::<Bn254>::new_from_file(abs_path("test-vectors/bn128/mimcsponge_bn128.r1cs"))
660                .unwrap(),
661            Curve::Bn128,
662        );
663        basic_checks(
664            &R1CSFile::<Bls12_381>::new_from_file(abs_path(
665                "test-vectors/bls12-381/mimcsponge_bls12_381.r1cs",
666            ))
667            .unwrap(),
668            Curve::Bls12_381,
669        );
670    }
671
672    #[test]
673    fn poseidon() {
674        basic_checks(
675            &R1CSFile::<Bn254>::new_from_file(abs_path("test-vectors/bn128/poseidon_bn128.r1cs"))
676                .unwrap(),
677            Curve::Bn128,
678        );
679    }
680
681    #[test]
682    fn less_than_32_bits() {
683        basic_checks(
684            &R1CSFile::<Bn254>::new_from_file(abs_path("test-vectors/bn128/less_than_32.r1cs"))
685                .unwrap(),
686            Curve::Bn128,
687        );
688        basic_checks(
689            &R1CSFile::<Bls12_381>::new_from_file(abs_path(
690                "test-vectors/bls12-381/less_than_32.r1cs",
691            ))
692            .unwrap(),
693            Curve::Bls12_381,
694        );
695    }
696
697    #[test]
698    fn less_than_public_64_bits() {
699        basic_checks(
700            &R1CSFile::<Bn254>::new_from_file(abs_path(
701                "test-vectors/bn128/less_than_public_64.r1cs",
702            ))
703            .unwrap(),
704            Curve::Bn128,
705        );
706        basic_checks(
707            &R1CSFile::<Bls12_381>::new_from_file(abs_path(
708                "test-vectors/bls12-381/less_than_public_64.r1cs",
709            ))
710            .unwrap(),
711            Curve::Bls12_381,
712        );
713    }
714
715    #[test]
716    fn all_different_10() {
717        basic_checks(
718            &R1CSFile::<Bn254>::new_from_file(abs_path("test-vectors/bn128/all_different_10.r1cs"))
719                .unwrap(),
720            Curve::Bn128,
721        );
722        basic_checks(
723            &R1CSFile::<Bls12_381>::new_from_file(abs_path(
724                "test-vectors/bls12-381/all_different_10.r1cs",
725            ))
726            .unwrap(),
727            Curve::Bls12_381,
728        );
729    }
730}