Skip to main content

taceo_circom_types/
binfile.rs

1use std::{
2    io::{Cursor, Read},
3    marker::PhantomData,
4};
5
6use ark_ec::pairing::Pairing;
7use ark_serialize::SerializationError;
8use byteorder::{LittleEndian, ReadBytesExt};
9use thiserror::Error;
10
11use crate::traits::CircomArkworksPairingBridge;
12
13pub(crate) type ZkeyParserResult<T> = std::result::Result<T, ZkeyParserError>;
14
15/// Error type describing errors during parsing zkey files
16#[derive(Debug, Error)]
17pub enum ZkeyParserError {
18    /// Error during serialization
19    #[error(transparent)]
20    SerializationError(#[from] SerializationError),
21    /// Error describing that an invalid modulus was found in the header for the chosen curve
22    #[error("invalid modulus found in header for chosen curve")]
23    InvalidPrimeInHeader,
24    /// Unexpected Curve Size
25    #[error("Unexpected field size for curve in header. Expected {0} but got {1}")]
26    UnexpectedByteSize(u32, u32),
27    /// Error during IO operations (reading/opening file, etc.)
28    #[error(transparent)]
29    IoError(#[from] std::io::Error),
30    /// generic bin file error
31    #[error("bin file corrupted: \"{0}\"")]
32    CorruptedBinFile(String),
33}
34
35#[derive(Debug)]
36pub(crate) struct BinFile<P: Pairing + CircomArkworksPairingBridge> {
37    #[expect(dead_code)]
38    ftype: String,
39    #[expect(dead_code)]
40    version: u32,
41    sections: Vec<Vec<u8>>,
42    phantom_data: PhantomData<P>,
43}
44
45impl<P: Pairing + CircomArkworksPairingBridge> BinFile<P> {
46    pub(crate) fn new<R: Read>(reader: &mut R) -> ZkeyParserResult<Self> {
47        tracing::debug!("reading bin file");
48        let mut magic = [0u8; 4];
49        reader.read_exact(&mut magic)?;
50        let ftype = std::str::from_utf8(&magic[..])
51            .map_err(|_| ZkeyParserError::CorruptedBinFile("cannot parse magic number".to_owned()))?
52            .to_string();
53        tracing::debug!("file type for binfile: \"{ftype}\"");
54
55        let version = reader.read_u32::<LittleEndian>()?;
56        tracing::debug!("binfile version {}", version);
57
58        let num_sections: usize = reader
59            .read_u32::<LittleEndian>()?
60            .try_into()
61            .expect("u32 fits into usize");
62        tracing::debug!("we got {} sections in binfile", num_sections);
63        let mut sections = vec![vec![]; num_sections];
64
65        for _ in 0..num_sections {
66            let section_id: usize = reader
67                .read_u32::<LittleEndian>()?
68                .try_into()
69                .expect("u32 fits into usize");
70            let section_length: usize = reader
71                .read_u64::<LittleEndian>()?
72                .try_into()
73                .expect("u64 fits into usize");
74
75            let section = &mut sections[section_id - 1];
76            if !section.is_empty() {
77                return Err(ZkeyParserError::CorruptedBinFile(
78                    "sections are empty!".to_owned(),
79                ));
80            }
81            section.resize(section_length, 0);
82            reader.read_exact(section)?;
83        }
84        tracing::debug!("successfully read bin file!");
85        Ok(Self {
86            ftype,
87            version,
88            sections,
89            phantom_data: PhantomData::<P>,
90        })
91    }
92
93    pub(crate) fn take_section(&mut self, id: usize) -> Cursor<Vec<u8>> {
94        Cursor::new(std::mem::take(&mut self.sections[id - 1]))
95    }
96
97    #[cfg(feature = "plonk")]
98    pub(crate) fn take_section_raw(&mut self, id: usize) -> Vec<u8> {
99        std::mem::take(&mut self.sections[id - 1])
100    }
101}