Skip to main content

provekit_common/file/
mod.rs

1mod bin;
2mod buf_ext;
3mod counting_writer;
4mod json;
5
6use {
7    self::{
8        bin::{deserialize_from_bytes, read_bin, serialize_to_bytes, write_bin, Compression},
9        buf_ext::BufExt,
10        counting_writer::CountingWriter,
11        json::{read_json, write_json},
12    },
13    crate::{NoirProof, NoirProofScheme, Prover, Verifier},
14    anyhow::Result,
15    serde::{Deserialize, Serialize},
16    std::{ffi::OsStr, path::Path},
17    tracing::instrument,
18};
19
20/// Trait for structures that can be serialized to and deserialized from files.
21pub trait FileFormat: Serialize + for<'a> Deserialize<'a> {
22    const FORMAT: [u8; 8];
23    const EXTENSION: &'static str;
24    const VERSION: (u16, u16);
25    const COMPRESSION: Compression;
26}
27
28impl FileFormat for NoirProofScheme {
29    const FORMAT: [u8; 8] = *b"NrProScm";
30    const EXTENSION: &'static str = "nps";
31    const VERSION: (u16, u16) = (1, 1);
32    const COMPRESSION: Compression = Compression::Zstd;
33}
34
35impl FileFormat for Prover {
36    const FORMAT: [u8; 8] = *b"PrvKitPr";
37    const EXTENSION: &'static str = "pkp";
38    const VERSION: (u16, u16) = (1, 1);
39    const COMPRESSION: Compression = Compression::Xz;
40}
41
42impl FileFormat for Verifier {
43    const FORMAT: [u8; 8] = *b"PrvKitVr";
44    const EXTENSION: &'static str = "pkv";
45    const VERSION: (u16, u16) = (1, 2);
46    const COMPRESSION: Compression = Compression::Zstd;
47}
48
49impl FileFormat for NoirProof {
50    const FORMAT: [u8; 8] = *b"NPSProof";
51    const EXTENSION: &'static str = "np";
52    const VERSION: (u16, u16) = (1, 0);
53    const COMPRESSION: Compression = Compression::Zstd;
54}
55
56/// Write a file with format determined from extension.
57#[instrument(skip(value))]
58pub fn write<T: FileFormat>(value: &T, path: &Path) -> Result<()> {
59    match path.extension().and_then(OsStr::to_str) {
60        Some("json") => write_json(value, path),
61        Some(ext) if ext == T::EXTENSION => {
62            write_bin(value, path, T::FORMAT, T::VERSION, T::COMPRESSION)
63        }
64        _ => Err(anyhow::anyhow!(
65            "Unsupported file extension, please specify .{} or .json",
66            T::EXTENSION
67        )),
68    }
69}
70
71/// Read a file with format determined from extension.
72#[instrument()]
73pub fn read<T: FileFormat>(path: &Path) -> Result<T> {
74    match path.extension().and_then(OsStr::to_str) {
75        Some("json") => read_json(path),
76        Some(ext) if ext == T::EXTENSION => read_bin(path, T::FORMAT, T::VERSION),
77        _ => Err(anyhow::anyhow!(
78            "Unsupported file extension, please specify .{} or .json",
79            T::EXTENSION
80        )),
81    }
82}
83
84/// Serialize a value to bytes using the binary format.
85pub fn serialize<T: FileFormat>(value: &T) -> Result<Vec<u8>> {
86    serialize_to_bytes(value, T::FORMAT, T::VERSION, T::COMPRESSION)
87}
88
89/// Deserialize a value from bytes in the binary format.
90pub fn deserialize<T: FileFormat>(data: &[u8]) -> Result<T> {
91    deserialize_from_bytes(data, T::FORMAT, T::VERSION)
92}