use blake2::Blake2b512; use digest::Digest; /// Database of fixed-length records, packed as a `cells_per_record × n_records` /// column-major matrix of mod-p cells (p = 256, so one byte = one cell). pub struct Database { /// Row-major: data[i * n_records + j] = record j's byte i. data: Vec, n_records: usize, record_bytes: usize, } impl Database { /// Pack `records` (each padded/truncated to `record_bytes`) into a query-ready matrix. pub fn new(records: &[&[u8]], record_bytes: usize) -> Self { let n_records = records.len(); let cells = record_bytes; let mut data = vec![0u32; cells * n_records]; for (j, rec) in records.iter().enumerate() { let len = rec.len().min(record_bytes); for i in 0..len { data[i * n_records + j] = rec[i] as u32; } } Database { data, n_records, record_bytes } } pub fn data(&self) -> &[u32] { &self.data } pub fn n_records(&self) -> usize { self.n_records } pub fn record_bytes(&self) -> usize { self.record_bytes } pub fn cells_per_record(&self) -> usize { self.record_bytes } /// BLAKE2b-256 commitment over (n_records, record_bytes, all packed cells). pub fn version(&self) -> [u8; 32] { let mut h = Blake2b512::new(); h.update((self.n_records as u64).to_le_bytes()); h.update((self.record_bytes as u64).to_le_bytes()); for &val in &self.data { h.update(val.to_le_bytes()); } let digest = h.finalize(); let mut v = [0u8; 32]; v.copy_from_slice(&digest[..32]); v } }