use std::{
io::{Cursor, Read},
marker::PhantomData,
};
use ark_ec::pairing::Pairing;
use ark_serialize::SerializationError;
use byteorder::{LittleEndian, ReadBytesExt};
use thiserror::Error;
use crate::traits::CircomArkworksPairingBridge;
pub(crate) type ZkeyParserResult<T> = std::result::Result<T, ZkeyParserError>;
#[derive(Debug, Error)]
pub enum ZkeyParserError {
#[error(transparent)]
SerializationError(#[from] SerializationError),
#[error("invalid modulus found in header for chosen curve")]
InvalidPrimeInHeader,
#[error("Unexpected field size for curve in header. Expected {0} but got {1}")]
UnexpectedByteSize(u32, u32),
#[error(transparent)]
IoError(#[from] std::io::Error),
#[error("bin file corrupted: \"{0}\"")]
CorruptedBinFile(String),
}
#[derive(Debug)]
pub(crate) struct BinFile<P: Pairing + CircomArkworksPairingBridge> {
#[expect(dead_code)]
ftype: String,
#[expect(dead_code)]
version: u32,
sections: Vec<Vec<u8>>,
phantom_data: PhantomData<P>,
}
impl<P: Pairing + CircomArkworksPairingBridge> BinFile<P> {
pub(crate) fn new<R: Read>(reader: &mut R) -> ZkeyParserResult<Self> {
tracing::debug!("reading bin file");
let mut magic = [0u8; 4];
reader.read_exact(&mut magic)?;
let ftype = std::str::from_utf8(&magic[..])
.map_err(|_| ZkeyParserError::CorruptedBinFile("cannot parse magic number".to_owned()))?
.to_string();
tracing::debug!("file type for binfile: \"{ftype}\"");
let version = reader.read_u32::<LittleEndian>()?;
tracing::debug!("binfile version {}", version);
let num_sections: usize = reader
.read_u32::<LittleEndian>()?
.try_into()
.expect("u32 fits into usize");
tracing::debug!("we got {} sections in binfile", num_sections);
let mut sections = vec![vec![]; num_sections];
for _ in 0..num_sections {
let section_id: usize = reader
.read_u32::<LittleEndian>()?
.try_into()
.expect("u32 fits into usize");
let section_length: usize = reader
.read_u64::<LittleEndian>()?
.try_into()
.expect("u64 fits into usize");
let section = &mut sections[section_id - 1];
if !section.is_empty() {
return Err(ZkeyParserError::CorruptedBinFile(
"sections are empty!".to_owned(),
));
}
section.resize(section_length, 0);
reader.read_exact(section)?;
}
tracing::debug!("successfully read bin file!");
Ok(Self {
ftype,
version,
sections,
phantom_data: PhantomData::<P>,
})
}
pub(crate) fn take_section(&mut self, id: usize) -> Cursor<Vec<u8>> {
Cursor::new(std::mem::take(&mut self.sections[id - 1]))
}
#[cfg(feature = "plonk")]
pub(crate) fn take_section_raw(&mut self, id: usize) -> Vec<u8> {
std::mem::take(&mut self.sections[id - 1])
}
}