provekit-common 1.0.0

Common types and utilities for the ProveKit proving system
Documentation
mod bin;
mod buf_ext;
mod counting_writer;
mod json;

use {
    self::{
        bin::{deserialize_from_bytes, read_bin, serialize_to_bytes, write_bin, Compression},
        buf_ext::BufExt,
        counting_writer::CountingWriter,
        json::{read_json, write_json},
    },
    crate::{NoirProof, NoirProofScheme, Prover, Verifier},
    anyhow::Result,
    serde::{Deserialize, Serialize},
    std::{ffi::OsStr, path::Path},
    tracing::instrument,
};

/// Trait for structures that can be serialized to and deserialized from files.
pub trait FileFormat: Serialize + for<'a> Deserialize<'a> {
    const FORMAT: [u8; 8];
    const EXTENSION: &'static str;
    const VERSION: (u16, u16);
    const COMPRESSION: Compression;
}

impl FileFormat for NoirProofScheme {
    const FORMAT: [u8; 8] = *b"NrProScm";
    const EXTENSION: &'static str = "nps";
    const VERSION: (u16, u16) = (1, 1);
    const COMPRESSION: Compression = Compression::Zstd;
}

impl FileFormat for Prover {
    const FORMAT: [u8; 8] = *b"PrvKitPr";
    const EXTENSION: &'static str = "pkp";
    const VERSION: (u16, u16) = (1, 1);
    const COMPRESSION: Compression = Compression::Xz;
}

impl FileFormat for Verifier {
    const FORMAT: [u8; 8] = *b"PrvKitVr";
    const EXTENSION: &'static str = "pkv";
    const VERSION: (u16, u16) = (1, 2);
    const COMPRESSION: Compression = Compression::Zstd;
}

impl FileFormat for NoirProof {
    const FORMAT: [u8; 8] = *b"NPSProof";
    const EXTENSION: &'static str = "np";
    const VERSION: (u16, u16) = (1, 0);
    const COMPRESSION: Compression = Compression::Zstd;
}

/// Write a file with format determined from extension.
#[instrument(skip(value))]
pub fn write<T: FileFormat>(value: &T, path: &Path) -> Result<()> {
    match path.extension().and_then(OsStr::to_str) {
        Some("json") => write_json(value, path),
        Some(ext) if ext == T::EXTENSION => {
            write_bin(value, path, T::FORMAT, T::VERSION, T::COMPRESSION)
        }
        _ => Err(anyhow::anyhow!(
            "Unsupported file extension, please specify .{} or .json",
            T::EXTENSION
        )),
    }
}

/// Read a file with format determined from extension.
#[instrument()]
pub fn read<T: FileFormat>(path: &Path) -> Result<T> {
    match path.extension().and_then(OsStr::to_str) {
        Some("json") => read_json(path),
        Some(ext) if ext == T::EXTENSION => read_bin(path, T::FORMAT, T::VERSION),
        _ => Err(anyhow::anyhow!(
            "Unsupported file extension, please specify .{} or .json",
            T::EXTENSION
        )),
    }
}

/// Serialize a value to bytes using the binary format.
pub fn serialize<T: FileFormat>(value: &T) -> Result<Vec<u8>> {
    serialize_to_bytes(value, T::FORMAT, T::VERSION, T::COMPRESSION)
}

/// Deserialize a value from bytes in the binary format.
pub fn deserialize<T: FileFormat>(data: &[u8]) -> Result<T> {
    deserialize_from_bytes(data, T::FORMAT, T::VERSION)
}