From 1fbe4af6037fc5e70b2cfb282206fdcc8382e08e Mon Sep 17 00:00:00 2001 From: Hanting Zhang Date: Tue, 20 Feb 2024 06:09:41 +0000 Subject: [PATCH] add API for data directory --- Cargo.toml | 1 + examples/minroot.rs | 2 + src/data.rs | 110 ++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 33 +++++++++++++ src/r1cs/mod.rs | 2 +- 5 files changed, 147 insertions(+), 1 deletion(-) create mode 100644 src/data.rs diff --git a/Cargo.toml b/Cargo.toml index f1b115d41..c10e90a8a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,6 +46,7 @@ ref-cast = "1.0.20" # allocation-less conversion in multilinear polys derive_more = "0.99.17" # lightens impl macros for pasta static_assertions = "1.1.0" rayon-scan = "0.1.0" +camino = "1.1.6" [target.'cfg(any(target_arch = "x86_64", target_arch = "aarch64"))'.dependencies] # grumpkin-msm has been patched to support MSMs for the pasta curve cycle diff --git a/examples/minroot.rs b/examples/minroot.rs index e443d1b29..78f9fee17 100644 --- a/examples/minroot.rs +++ b/examples/minroot.rs @@ -195,6 +195,8 @@ fn main() { .with(EnvFilter::from_default_env()) .with(TeXRayLayer::new()); tracing::subscriber::set_global_default(subscriber).unwrap(); + arecibo::data::set_write_data(true); + type C1 = MinRootCircuit<::GE>; println!("Nova-based VDF with MinRoot delay function"); diff --git a/src/data.rs b/src/data.rs new file mode 100644 index 000000000..022074ed1 --- /dev/null +++ b/src/data.rs @@ -0,0 +1,110 @@ +//! Very minimal utilities for reading/writing general arecibo data in disk. +use camino::{Utf8Path, Utf8PathBuf}; +use once_cell::sync::OnceCell; +use serde::{de::DeserializeOwned, Serialize}; +use std::{ + collections::HashMap, + fs::{self, File, OpenOptions}, + io::{BufReader, BufWriter}, +}; + +/// Global flag for writing config. +pub static WRITE: bool = false; + +/// Path to the directory where Arecibo data will be stored. +pub static ARECIBO_DATA: &str = ".arecibo_data"; + +/// Global configuration for Arecibo data storage, including root directory and counters. +/// This configuration is initialized on first use. +pub static mut ARECIBO_CONFIG: OnceCell = OnceCell::new(); + +/// Configuration for managing Arecibo data files, including the root directory, +/// witness counter, and cross-term counter for organizing files. +#[derive(Debug, Clone)] +pub struct DataConfig { + root_dir: Utf8PathBuf, + section_counters: HashMap, + write_data: bool, +} + +/// Initializes the global configuration for Arecibo data storage, setting up the root directory +/// and initializing counters. We create the root directory if it does not already exist. +pub fn init_config() -> DataConfig { + let root_dir = Utf8PathBuf::from(ARECIBO_DATA); + if !root_dir.exists() { + fs::create_dir_all(&root_dir).expect("Failed to create arecibo data directory"); + } + + DataConfig { + root_dir, + section_counters: HashMap::new(), + write_data: WRITE, + } +} + +/// Writes Arecibo data to disk, organizing it into sections and labeling it with a unique identifier. +/// This function serializes the given payload and writes it into the appropriate section and file. +/// For now, we just increment the relevant counter to ensure uniqueness. +pub fn write_arecibo_data( + section: impl AsRef, + label: impl AsRef, + payload: &T, +) { + let _ = unsafe { ARECIBO_CONFIG.set(init_config()) }; + let config = unsafe { ARECIBO_CONFIG.get_mut().unwrap() }; + + let section_path = config.root_dir.join(section.as_ref()); + if !section_path.exists() { + fs::create_dir_all(§ion_path).expect("Failed to create section directory"); + } + + let section = section.as_ref().to_string(); + let counter = config.section_counters.entry(section).or_insert(0); + + let file_path = section_path.join(format!("{}_{:?}", label.as_ref().as_str(), counter)); + *counter += 1; + + let file = OpenOptions::new() + .read(true) + .write(true) + .truncate(true) + .create(true) + .open(file_path) + .expect("Failed to create data file"); + + let writer = BufWriter::new(&file); + bincode::serialize_into(writer, payload).expect("Failed to write data"); +} + +/// Reads and deserializes data from a specified section and label. +pub fn read_arecibo_data( + section: impl AsRef, + label: impl AsRef, +) -> T { + let config = unsafe { ARECIBO_CONFIG.get_or_init(init_config) }; + + let section_path = config.root_dir.join(section.as_ref()); + assert!(section_path.exists(), "Section directory does not exist"); + + // Assuming the label uniquely identifies the file, and ignoring the counter for simplicity + let file_path = section_path.join(label.as_ref()); + assert!(file_path.exists(), "Data file does not exist"); + + let file = File::open(file_path).expect("Failed to open data file"); + let reader = BufReader::new(file); + + bincode::deserialize_from(reader).expect("Failed to read data") +} + +/// Are we configured to write data? +pub fn write_data() -> bool { + let config = unsafe { ARECIBO_CONFIG.get_or_init(init_config) }; + config.write_data +} + +/// Set the configuration for writing data. +pub fn set_write_data(write_data: bool) { + let _ = unsafe { ARECIBO_CONFIG.set(init_config()) }; + let config = unsafe { ARECIBO_CONFIG.get_mut().unwrap() }; + config.write_data = write_data; +} diff --git a/src/lib.rs b/src/lib.rs index 01d2a9acd..0b09b7bad 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -25,6 +25,7 @@ pub mod r1cs; pub mod spartan; pub mod traits; +pub mod data; pub mod supernova; use once_cell::sync::OnceCell; @@ -37,6 +38,7 @@ use crate::{ shape_cs::ShapeCS, solver::SatisfyingAssignment, }, + data::{write_arecibo_data, write_data}, r1cs::R1CSResult, }; use abomonation::Abomonation; @@ -349,6 +351,13 @@ pub struct ResourceBuffer { T: Vec, } +/// A very simple config for [`RecursiveSNARK`] in charge of logging behavior. +/// To be fleshed out and extended in the future. +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct RecursiveSNARKConfig { + write_data: bool, +} + /// A SNARK that proves the correct execution of an incremental computation #[derive(Clone, Debug, Serialize, Deserialize)] #[serde(bound = "")] @@ -373,6 +382,8 @@ where i: usize, zi_primary: Vec, zi_secondary: Vec< as Engine>::Scalar>, + + config: RecursiveSNARKConfig, } impl RecursiveSNARK @@ -484,6 +495,10 @@ where T: r1cs::default_T::>(r1cs_secondary.num_cons), }; + let config = RecursiveSNARKConfig { + write_data: write_data(), + }; + Ok(Self { z0_primary: z0_primary.to_vec(), z0_secondary: z0_secondary.to_vec(), @@ -496,9 +511,12 @@ where buffer_primary, buffer_secondary, + i: 0, zi_primary, zi_secondary, + + config, }) } @@ -588,6 +606,21 @@ where &mut self.buffer_primary.ABC_Z_2, )?; + if self.config.write_data { + let W = l_w_primary.W; + write_arecibo_data( + format!("witness_{:?}", pp.digest()), + format!("len_{}", W.len()), + &W, + ); + let T = &self.buffer_primary.T; + write_arecibo_data( + format!("cross_term_{:?}", pp.digest()), + format!("len_{}", T.len()), + &T, + ); + } + let mut cs_secondary = SatisfyingAssignment::>::with_capacity( pp.circuit_shape_secondary.r1cs_shape.num_io + 1, pp.circuit_shape_secondary.r1cs_shape.num_vars, diff --git a/src/r1cs/mod.rs b/src/r1cs/mod.rs index caf336ecb..e5f66664a 100644 --- a/src/r1cs/mod.rs +++ b/src/r1cs/mod.rs @@ -55,7 +55,7 @@ pub struct R1CSResult { /// A type that holds a witness for a given R1CS instance #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct R1CSWitness { - W: Vec, + pub(crate) W: Vec, } /// A type that holds an R1CS instance