Skip to main content

taceo_circom_types/
witness.rs

1//! This module defines the [`Witness`] struct that implements deserialization of Circom witness files via [`Witness::from_reader`].
2
3use std::io;
4
5use ark_serialize::{Read, SerializationError};
6use byteorder::{LittleEndian, ReadBytesExt};
7use thiserror::Error;
8
9use ark_ff::{BigInteger, PrimeField};
10
11use crate::reader_utils::{self, InvalidHeaderError};
12
13type Result<T> = std::result::Result<T, WitnessParserError>;
14const WITNESS_HEADER: &str = "wtns";
15const MAX_VERSION: u32 = 2;
16const N_SECTIONS: u32 = 2;
17
18/// Error type describing errors during parsing witness files
19#[derive(Debug, Error)]
20pub enum WitnessParserError {
21    /// Error during IO operations (reading/opening file, etc.)
22    #[error(transparent)]
23    IoError(#[from] io::Error),
24    /// Error during serialization
25    #[error(transparent)]
26    SerializationError(#[from] SerializationError),
27    /// Error describing that the version of the file is not supported for parsing
28    #[error("Max supported version is {0}, but got {1}")]
29    VersionNotSupported(u32, u32),
30    /// Error describing that the number of sections in the file is invalid
31    #[error("Wrong number of sections is {0}, but got {1}")]
32    InvalidSectionNumber(u32, u32),
33    /// Error describing that the ScalarField from curve does not match in witness file
34    #[error("ScalarField from curve does not match in witness file")]
35    WrongScalarField,
36    /// Error during reading Circom file header
37    #[error(transparent)]
38    WrongHeader(#[from] InvalidHeaderError),
39}
40
41/// Represents a witness in the format defined by Circom. Implements [`Witness::from_reader`] to deserialize a witness from a reader.
42#[derive(Debug, Clone, Eq, PartialEq)]
43pub struct Witness<F> {
44    /// The values of the witness.
45    pub values: Vec<F>,
46}
47
48impl<F: PrimeField> Witness<F> {
49    /// Deserializes a [`Witness`] from a reader.
50    pub fn from_reader<R: Read>(mut reader: R) -> Result<Self> {
51        tracing::trace!("trying to read witness");
52        reader_utils::read_header(&mut reader, WITNESS_HEADER)?;
53        let version = reader.read_u32::<LittleEndian>()?;
54        if version > MAX_VERSION {
55            return Err(WitnessParserError::VersionNotSupported(
56                MAX_VERSION,
57                version,
58            ));
59        }
60
61        let n_sections = reader.read_u32::<LittleEndian>()?;
62        if n_sections > N_SECTIONS {
63            return Err(WitnessParserError::InvalidSectionNumber(
64                N_SECTIONS, n_sections,
65            ));
66        }
67        //this is the section id and length
68        //don't know if we need them, maybe at least log them later
69        let _ = reader.read_u32::<LittleEndian>()?;
70        let _ = reader.read_u64::<LittleEndian>()?;
71        let n8 = reader.read_u32::<LittleEndian>()?;
72        let n8 = usize::try_from(n8).expect("u32 fits into usize");
73        let mut buf = vec![0; n8];
74        reader.read_exact(buf.as_mut_slice())?;
75        if F::MODULUS.to_bytes_le() != buf {
76            tracing::trace!("wrong scalar field");
77            return Err(WitnessParserError::WrongScalarField);
78        }
79        let n_witness = reader.read_u32::<LittleEndian>()?;
80        //this is the section id and length
81        //don't know if we need them, maybe at least log them later
82        let _ = reader.read_u32::<LittleEndian>()?;
83        let _ = reader.read_u64::<LittleEndian>()?;
84        Ok(Self {
85            values: (0..n_witness)
86                .map(|_| {
87                    reader_utils::prime_field_from_reader(&mut reader, n8)
88                        .map_err(WitnessParserError::from)
89                })
90                .collect::<Result<Vec<F>>>()?,
91        })
92    }
93}
94
95#[cfg(test)]
96#[cfg(feature = "bn254")]
97mod bn254_tests {
98    use std::fs::File;
99
100    use crate::tests::groth16_bn254_kats;
101
102    use super::Witness;
103
104    #[test]
105    fn can_deser_witness_bn254() {
106        let groth16_bn254_kats = groth16_bn254_kats();
107        let witness = File::open(groth16_bn254_kats.join("witness.wtns")).unwrap();
108        let is_witness = Witness::<ark_bn254::Fr>::from_reader(witness).unwrap();
109        assert_eq!(
110            is_witness,
111            Witness {
112                values: vec![
113                    ark_bn254::Fr::from(1),
114                    ark_bn254::Fr::from(33),
115                    ark_bn254::Fr::from(3),
116                    ark_bn254::Fr::from(11),
117                ],
118            }
119        );
120    }
121}
122
123#[cfg(test)]
124#[cfg(feature = "bls12-381")]
125mod bls12_381_tests {
126    use std::fs::File;
127
128    use crate::tests::groth16_bls12_381_kats;
129
130    use super::Witness;
131
132    #[test]
133    fn can_deser_witness_bls12381() {
134        let groth16_bls12_381_kats = groth16_bls12_381_kats();
135        let witness = File::open(groth16_bls12_381_kats.join("witness.wtns")).unwrap();
136        let is_witness = Witness::<ark_bls12_381::Fr>::from_reader(witness).unwrap();
137        assert_eq!(
138            is_witness,
139            Witness {
140                values: vec![
141                    ark_bls12_381::Fr::from(1),
142                    ark_bls12_381::Fr::from(33),
143                    ark_bls12_381::Fr::from(3),
144                    ark_bls12_381::Fr::from(11),
145                ],
146            }
147        );
148    }
149}