edgesentry_rs/
integrity.rs1use thiserror::Error;
8
9use crate::record::AuditRecord;
10
11pub fn compute_payload_hash(payload: &[u8]) -> [u8; 32] {
13 *blake3::hash(payload).as_bytes()
14}
15
16#[derive(Debug, Error, PartialEq, Eq)]
18pub enum ChainError {
19 #[error("invalid previous hash at index {index}")]
20 InvalidPrevHash { index: usize },
21 #[error("invalid sequence at index {index}: expected {expected}, actual {actual}")]
22 InvalidSequence {
23 index: usize,
24 expected: u64,
25 actual: u64,
26 },
27}
28
29pub fn verify_chain(records: &[AuditRecord]) -> Result<(), ChainError> {
36 if records.is_empty() {
37 return Ok(());
38 }
39
40 for (index, record) in records.iter().enumerate() {
41 if index == 0 {
42 if record.prev_record_hash != AuditRecord::zero_hash() {
43 return Err(ChainError::InvalidPrevHash { index });
44 }
45 continue;
46 }
47
48 let previous = &records[index - 1];
49 if record.prev_record_hash != previous.hash() {
50 return Err(ChainError::InvalidPrevHash { index });
51 }
52
53 let expected_sequence = previous.sequence + 1;
54 if record.sequence != expected_sequence {
55 return Err(ChainError::InvalidSequence {
56 index,
57 expected: expected_sequence,
58 actual: record.sequence,
59 });
60 }
61 }
62
63 Ok(())
64}