vole-document 0.1.0-alpha.1

Byte-exact procedural document storage: deterministic reconstruction state, typed residuals, and entropy-coded channels that materialize the exact original document bytes.
Documentation
//! Deterministic materialization.
//!
//! The materializer is deliberately boring: it evaluates a bounded program,
//! checks the reconstructed length, and checks the archival digest. It never
//! searches, guesses, optimizes, or invokes external tools.

use crate::container::{Descriptor, ParsedDescriptor};
use crate::error::{Error, Result};
use crate::integrity::{sha256, to_hex};
use crate::limits::Limits;

/// Materialize the exact source bytes for a parsed descriptor.
///
/// Enforces, in order: program bounds (via `eval`), reconstructed length, and
/// whole-source SHA-256.
pub fn materialize(parsed: &ParsedDescriptor, limits: Limits) -> Result<Vec<u8>> {
    let d = &parsed.descriptor;
    let out = d.program.eval(&d.objects, limits)?;
    if out.len() as u64 != d.source_len {
        return Err(Error::reconstruction_mismatch(format!(
            "materialized {} bytes but {} were declared",
            out.len(),
            d.source_len
        )));
    }
    let digest = sha256(&out);
    if digest != d.source_sha256 {
        return Err(Error::integrity_mismatch(format!(
            "materialized SHA-256 {} != declared {}",
            to_hex(&digest),
            to_hex(&d.source_sha256)
        )));
    }
    Ok(out)
}

/// Parse and materialize in one step.
pub fn decode_to_bytes(bytes: &[u8], limits: Limits) -> Result<(Vec<u8>, ParsedDescriptor)> {
    let parsed = Descriptor::parse(bytes, limits)?;
    let out = materialize(&parsed, limits)?;
    Ok((out, parsed))
}

/// The result of a deep verification.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct VerifyReport {
    /// Reconstructed source length.
    pub source_len: u64,
    /// Lower-case hex SHA-256 of the reconstructed source.
    pub sha256_hex: String,
    /// Number of raw byte objects in the descriptor.
    pub object_count: usize,
    /// Number of DRA instructions in the reconstruction program.
    pub graph_ops: usize,
}

/// Deep verification: parse, materialize, and check the archival digest.
pub fn verify(bytes: &[u8], limits: Limits) -> Result<VerifyReport> {
    let (out, parsed) = decode_to_bytes(bytes, limits)?;
    Ok(VerifyReport {
        source_len: out.len() as u64,
        sha256_hex: to_hex(&sha256(&out)),
        object_count: parsed.descriptor.objects.len(),
        graph_ops: parsed.descriptor.program.ops.len(),
    })
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::dra::Op;
    use crate::{EXACTNESS_PROFILE_EXACT_BYTES, SOURCE_FORMAT_OPAQUE};

    fn descriptor_for(source: &[u8]) -> Descriptor {
        Descriptor {
            universe: crate::container::UNIVERSE_V1.to_string(),
            source_format: SOURCE_FORMAT_OPAQUE,
            format_basis: "opaque:test".to_string(),
            objects: vec![source.to_vec()],
            program: crate::dra::Program::new(vec![Op::EmitObject { object_id: 0 }]),
            source_sha256: sha256(source),
            source_len: source.len() as u64,
        }
    }

    #[test]
    fn exact_roundtrip() {
        let source = b"exact bytes must survive";
        let d = descriptor_for(source);
        let (bytes, _) = d.serialize().unwrap();
        let (out, _) = decode_to_bytes(&bytes, Limits::DEFAULT).unwrap();
        assert_eq!(out, source);
        let _ = EXACTNESS_PROFILE_EXACT_BYTES;
    }

    #[test]
    fn detects_digest_mismatch() {
        let source = b"abcdef";
        let mut d = descriptor_for(source);
        d.source_sha256[0] ^= 0xFF;
        let (bytes, _) = d.serialize().unwrap();
        let e = decode_to_bytes(&bytes, Limits::DEFAULT).unwrap_err();
        assert_eq!(e.class(), crate::ErrorClass::IntegrityMismatch);
    }
}