Skip to main content

AuditRecord

Struct AuditRecord 

Source
pub struct AuditRecord {
    pub device_id: String,
    pub sequence: u64,
    pub timestamp_ms: u64,
    pub payload_hash: Hash32,
    pub signature: Signature64,
    pub prev_record_hash: Hash32,
    pub object_ref: String,
}

Fields§

§device_id: String§sequence: u64§timestamp_ms: u64§payload_hash: Hash32§signature: Signature64§prev_record_hash: Hash32§object_ref: String

Implementations§

Source§

impl AuditRecord

Source

pub fn hash(&self) -> Hash32

Examples found in repository?
examples/lift_inspection_flow.rs (line 40)
7fn main() {
8    let device_id = "lift-01";
9    let signing_key = SigningKey::from_bytes(&[1u8; 32]);
10    let verifying_key = signing_key.verifying_key();
11
12    let mut service = IngestService::new(
13        IngestState::default(),
14        InMemoryRawDataStore::default(),
15        InMemoryAuditLedger::default(),
16        InMemoryOperationLog::default(),
17    );
18    service.register_device(device_id, verifying_key);
19
20    let payloads = [
21        b"check=door,status=ok" as &[u8],
22        b"check=vibration,status=ok",
23        b"check=emergency_brake,status=ok",
24    ];
25
26    let mut prev_hash = AuditRecord::zero_hash();
27    let mut records = Vec::new();
28
29    for (index, payload) in payloads.iter().enumerate() {
30        let sequence = (index as u64) + 1;
31        let record = build_signed_record(
32            device_id,
33            sequence,
34            1_700_000_000_000 + sequence,
35            payload,
36            prev_hash,
37            format!("s3://bucket/{device_id}/inspection-{sequence}.bin"),
38            &signing_key,
39        );
40        prev_hash = record.hash();
41        records.push(record);
42    }
43
44    for record in &records {
45        service
46            .ingest(record.clone(), payloads[record.sequence as usize - 1])
47            .expect("ingest should succeed");
48    }
49
50    println!("Stored {} audit records", service.audit_ledger().records().len());
51
52    let tampered_payload = b"tampered";
53    let tampered_record = build_signed_record(
54        device_id,
55        4,
56        1_700_000_000_004,
57        tampered_payload,
58        prev_hash,
59        "s3://bucket/lift-01/inspection-4.bin",
60        &signing_key,
61    );
62    let mut tampered = tampered_record;
63    tampered.payload_hash[0] ^= 0x01;
64
65    let result = service.ingest(tampered, tampered_payload);
66    assert!(result.is_err(), "tampered record should be rejected");
67    println!("Tampered record rejected: {:?}", result.unwrap_err());
68
69    println!("Operation log entries: {}", service.operation_log().entries().len());
70    for entry in service.operation_log().entries() {
71        println!("  {:?} device={} seq={} msg={}", entry.decision, entry.device_id, entry.sequence, entry.message);
72    }
73}
Source

pub fn zero_hash() -> Hash32

Examples found in repository?
examples/lift_inspection_flow.rs (line 26)
7fn main() {
8    let device_id = "lift-01";
9    let signing_key = SigningKey::from_bytes(&[1u8; 32]);
10    let verifying_key = signing_key.verifying_key();
11
12    let mut service = IngestService::new(
13        IngestState::default(),
14        InMemoryRawDataStore::default(),
15        InMemoryAuditLedger::default(),
16        InMemoryOperationLog::default(),
17    );
18    service.register_device(device_id, verifying_key);
19
20    let payloads = [
21        b"check=door,status=ok" as &[u8],
22        b"check=vibration,status=ok",
23        b"check=emergency_brake,status=ok",
24    ];
25
26    let mut prev_hash = AuditRecord::zero_hash();
27    let mut records = Vec::new();
28
29    for (index, payload) in payloads.iter().enumerate() {
30        let sequence = (index as u64) + 1;
31        let record = build_signed_record(
32            device_id,
33            sequence,
34            1_700_000_000_000 + sequence,
35            payload,
36            prev_hash,
37            format!("s3://bucket/{device_id}/inspection-{sequence}.bin"),
38            &signing_key,
39        );
40        prev_hash = record.hash();
41        records.push(record);
42    }
43
44    for record in &records {
45        service
46            .ingest(record.clone(), payloads[record.sequence as usize - 1])
47            .expect("ingest should succeed");
48    }
49
50    println!("Stored {} audit records", service.audit_ledger().records().len());
51
52    let tampered_payload = b"tampered";
53    let tampered_record = build_signed_record(
54        device_id,
55        4,
56        1_700_000_000_004,
57        tampered_payload,
58        prev_hash,
59        "s3://bucket/lift-01/inspection-4.bin",
60        &signing_key,
61    );
62    let mut tampered = tampered_record;
63    tampered.payload_hash[0] ^= 0x01;
64
65    let result = service.ingest(tampered, tampered_payload);
66    assert!(result.is_err(), "tampered record should be rejected");
67    println!("Tampered record rejected: {:?}", result.unwrap_err());
68
69    println!("Operation log entries: {}", service.operation_log().entries().len());
70    for entry in service.operation_log().entries() {
71        println!("  {:?} device={} seq={} msg={}", entry.decision, entry.device_id, entry.sequence, entry.message);
72    }
73}

Trait Implementations§

Source§

impl Clone for AuditRecord

Source§

fn clone(&self) -> AuditRecord

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for AuditRecord

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<'de> Deserialize<'de> for AuditRecord

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl PartialEq for AuditRecord

Source§

fn eq(&self, other: &AuditRecord) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl Serialize for AuditRecord

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more
Source§

impl Eq for AuditRecord

Source§

impl StructuralPartialEq for AuditRecord

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,