rvm-types 0.1.1

Core types for the RVM coherence-native microhypervisor (ADR-132)
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
//! Witness record types for the audit subsystem.
//!
//! Every privileged action in RVM emits a compact, immutable audit record.
//! This is a core invariant (INV-3): **no witness, no mutation**.
//!
//! The witness record is exactly 64 bytes, cache-line aligned, with FNV-1a
//! hash chaining for tamper evidence. See ADR-134 for the full specification.

/// A single witness record. Exactly 64 bytes, cache-line aligned.
///
/// All fields are little-endian. The record is `#[repr(C, align(64))]` to
/// guarantee layout and alignment on all target architectures (`AArch64`,
/// RISC-V, x86-64).
///
/// # Layout
///
/// | Offset | Size | Field                | Description |
/// |--------|------|----------------------|-------------|
/// | 0      | 8    | `sequence`           | Monotonic sequence number |
/// | 8      | 8    | `timestamp_ns`       | Nanosecond timestamp |
/// | 16     | 1    | `action_kind`        | Privileged action discriminant |
/// | 17     | 1    | `proof_tier`         | Proof tier (1, 2, or 3) |
/// | 18     | 1    | `flags`              | Action-specific flags |
/// | 19     | 1    | `_reserved`          | Reserved (must be zero) |
/// | 20     | 4    | `actor_partition_id` | Actor partition |
/// | 24     | 8    | `target_object_id`   | Target object |
/// | 32     | 4    | `capability_hash`    | Truncated cap hash |
/// | 36     | 8    | `payload`            | Action-specific data |
/// | 44     | 4    | `prev_hash`          | FNV-1a chain link |
/// | 48     | 4    | `record_hash`        | FNV-1a self-integrity |
/// | 52     | 8    | `aux`                | Secondary payload / TEE sig |
/// | 60     | 4    | `_pad`               | Padding to 64 bytes |
#[derive(Debug, Clone, Copy)]
#[repr(C, align(64))]
pub struct WitnessRecord {
    /// Monotonic sequence number. Provides global ordering of all privileged actions.
    pub sequence: u64,
    /// Nanosecond timestamp from the system timer (`CNTVCT_EL0` / `rdtsc`).
    pub timestamp_ns: u64,
    /// Which privileged action was performed (see [`ActionKind`]).
    pub action_kind: u8,
    /// Which proof tier authorized this action (1 = P1, 2 = P2, 3 = P3).
    pub proof_tier: u8,
    /// Action-specific flags (interpretation varies by `action_kind`).
    pub flags: u8,
    /// Reserved for future use. Must be zero.
    reserved: u8,
    /// Partition that performed the action.
    pub actor_partition_id: u32,
    /// Object acted upon: partition, region, capability, etc.
    pub target_object_id: u64,
    /// Truncated FNV-1a hash of the capability used (not the full token).
    pub capability_hash: u32,
    /// Action-specific data, packed by kind.
    ///
    /// Examples:
    /// - `PartitionSplit`: `new_id_a` in bytes \[0..4\], `new_id_b` in bytes \[4..8\].
    /// - `RegionTransfer`: `from_partition` in bytes \[0..4\], `to_partition` in bytes \[4..8\].
    pub payload: [u8; 8],
    /// FNV-1a hash of the previous record (chain link for tamper evidence).
    pub prev_hash: u32,
    /// FNV-1a hash of bytes \[0..44\] of this record (self-integrity).
    pub record_hash: u32,
    /// Secondary payload or TEE signature fragment.
    pub aux: [u8; 8],
    /// Padding to guarantee 64-byte total size.
    pad: [u8; 4],
}

// Compile-time size assertion: the record MUST be exactly 64 bytes.
const _: () = {
    assert!(core::mem::size_of::<WitnessRecord>() == 64);
};

impl WitnessRecord {
    /// Create a zeroed witness record (genesis / placeholder).
    #[must_use]
    pub const fn zeroed() -> Self {
        Self {
            sequence: 0,
            timestamp_ns: 0,
            action_kind: 0,
            proof_tier: 0,
            flags: 0,
            reserved: 0,
            actor_partition_id: 0,
            target_object_id: 0,
            capability_hash: 0,
            payload: [0; 8],
            prev_hash: 0,
            record_hash: 0,
            aux: [0; 8],
            pad: [0; 4],
        }
    }
}

/// A 256-bit witness commitment hash.
///
/// Used to anchor state transitions in the RVM witness trail. This is
/// a fixed-size value type suitable for embedding in `no_std` contexts
/// without heap allocation.
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct WitnessHash {
    bytes: [u8; 32],
}

impl WitnessHash {
    /// The zero hash, used as a sentinel for the genesis state.
    pub const ZERO: Self = Self { bytes: [0u8; 32] };

    /// Create a witness hash from raw bytes.
    #[must_use]
    pub const fn from_bytes(bytes: [u8; 32]) -> Self {
        Self { bytes }
    }

    /// Return the raw byte representation.
    #[must_use]
    pub const fn as_bytes(&self) -> &[u8; 32] {
        &self.bytes
    }

    /// Check whether this is the zero (genesis) hash.
    #[must_use]
    pub const fn is_zero(&self) -> bool {
        let mut i = 0;
        while i < 32 {
            if self.bytes[i] != 0 {
                return false;
            }
            i += 1;
        }
        true
    }
}

impl core::fmt::Debug for WitnessHash {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        write!(f, "WitnessHash(")?;
        for byte in &self.bytes[..4] {
            write!(f, "{byte:02x}")?;
        }
        write!(f, "..)")
    }
}

impl core::fmt::Display for WitnessHash {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        for byte in &self.bytes {
            write!(f, "{byte:02x}")?;
        }
        Ok(())
    }
}

/// Privileged actions that produce witness records (ADR-134, Section 2).
///
/// Organized by subsystem. Hex values allow easy filtering by prefix in
/// audit queries (0x0_ = partition, 0x1_ = capability, 0x2_ = memory, etc.).
///
/// If a privileged action exists without a corresponding kind, the system
/// has an audit gap.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
pub enum ActionKind {
    // --- Partition lifecycle (0x01-0x0F) ---
    /// A new partition was created.
    PartitionCreate = 0x01,
    /// A partition was destroyed and its resources freed.
    PartitionDestroy = 0x02,
    /// A partition was suspended (tasks paused).
    PartitionSuspend = 0x03,
    /// A suspended partition was resumed.
    PartitionResume = 0x04,
    /// A partition was split along a mincut boundary.
    PartitionSplit = 0x05,
    /// Two partitions were merged into one.
    PartitionMerge = 0x06,
    /// A partition was hibernated to dormant/cold storage.
    PartitionHibernate = 0x07,
    /// A hibernated partition was reconstructed from its receipt.
    PartitionReconstruct = 0x08,
    /// A partition was migrated to another node.
    PartitionMigrate = 0x09,

    // --- Capability operations (0x10-0x1F) ---
    /// A capability was granted (copied) to another partition.
    CapabilityGrant = 0x10,
    /// A capability was revoked.
    CapabilityRevoke = 0x11,
    /// A capability was delegated (with depth decrement).
    CapabilityDelegate = 0x12,
    /// Delegation depth was increased (escalation).
    CapabilityEscalate = 0x13,
    /// Capability was attenuated during a partition split (DC-8).
    CapabilityAttenuated = 0x14,

    // --- Memory operations (0x20-0x2F) ---
    /// A memory region was created.
    RegionCreate = 0x20,
    /// A memory region was destroyed.
    RegionDestroy = 0x21,
    /// A memory region was transferred to another partition.
    RegionTransfer = 0x22,
    /// A memory region was shared (read-only) with another partition.
    RegionShare = 0x23,
    /// A shared memory region was unshared.
    RegionUnshare = 0x24,
    /// A memory region was promoted to a warmer tier.
    RegionPromote = 0x25,
    /// A memory region was demoted to a colder tier.
    RegionDemote = 0x26,
    /// A stage-2 mapping was added for a memory region.
    RegionMap = 0x27,
    /// A stage-2 mapping was removed for a memory region.
    RegionUnmap = 0x28,

    // --- Communication (0x30-0x3F) ---
    /// A communication edge was created between two partitions.
    CommEdgeCreate = 0x30,
    /// A communication edge was destroyed.
    CommEdgeDestroy = 0x31,
    /// An IPC message was sent.
    IpcSend = 0x32,
    /// An IPC message was received.
    IpcReceive = 0x33,
    /// A zero-copy memory share was established.
    ZeroCopyShare = 0x34,
    /// A notification signal was sent.
    NotificationSignal = 0x35,

    // --- Device operations (0x40-0x4F) ---
    /// A device lease was granted.
    DeviceLeaseGrant = 0x40,
    /// A device lease was revoked.
    DeviceLeaseRevoke = 0x41,
    /// A device lease expired (time-bounded).
    DeviceLeaseExpire = 0x42,
    /// A device lease was renewed.
    DeviceLeaseRenew = 0x43,

    // --- Proof verification (0x50-0x5F) ---
    /// A P1 capability check passed.
    ProofVerifiedP1 = 0x50,
    /// A P2 policy validation passed.
    ProofVerifiedP2 = 0x51,
    /// A P3 deep proof passed.
    ProofVerifiedP3 = 0x52,
    /// A proof was rejected.
    ProofRejected = 0x53,
    /// A proof was escalated to a higher tier.
    ProofEscalated = 0x54,

    // --- Scheduler decisions (0x60-0x6F) ---
    /// Scheduler epoch boundary (bulk switch summary per DC-10).
    SchedulerEpoch = 0x60,
    /// Scheduler mode switched (Reflex / Flow / Recovery).
    SchedulerModeSwitch = 0x61,
    /// A task was spawned within a partition.
    TaskSpawn = 0x62,
    /// A task was terminated.
    TaskTerminate = 0x63,
    /// Scheduler triggered a structural split.
    StructuralSplit = 0x64,
    /// Scheduler triggered a structural merge.
    StructuralMerge = 0x65,

    // --- Recovery actions (0x70-0x7F) ---
    /// System entered recovery mode.
    RecoveryEnter = 0x70,
    /// System exited recovery mode.
    RecoveryExit = 0x71,
    /// A recovery checkpoint was created.
    CheckpointCreated = 0x72,
    /// A recovery checkpoint was restored.
    CheckpointRestored = 0x73,
    /// Mincut budget was exceeded, stale cut used (DC-2 fallback).
    MinCutBudgetExceeded = 0x74,
    /// System entered degraded mode (DC-6).
    DegradedModeEntered = 0x75,
    /// System exited degraded mode.
    DegradedModeExited = 0x76,

    // --- Boot and attestation (0x80-0x8F) ---
    /// Boot attestation record (genesis witness).
    BootAttestation = 0x80,
    /// Boot sequence completed successfully.
    BootComplete = 0x81,
    /// TEE-backed attestation record.
    TeeAttestation = 0x82,

    // --- Vector/Graph mutations (0x90-0x9F) ---
    /// A vector was inserted into the coherence graph.
    VectorPut = 0x90,
    /// A vector was deleted from the coherence graph.
    VectorDelete = 0x91,
    /// A graph mutation occurred.
    GraphMutation = 0x92,
    /// Coherence scores were recomputed.
    CoherenceRecomputed = 0x93,

    // --- VMID management (0xA0-0xAF) ---
    /// A physical VMID was reclaimed from a hibernated partition (DC-12).
    VmidReclaim = 0xA0,
    /// Migration timed out and was aborted (DC-7).
    MigrationTimeout = 0xA1,

    // --- External anchoring (0xB0-0xBF) ---
    /// A commitment to an external, service-side record (e.g. a ruflo
    /// ADR-322C evaluation receipt) was anchored into the witness chain
    /// after independent verification (ADR-156).
    ///
    /// Anchoring records provenance only: the anchored record keeps the
    /// assurance level it was produced under and does not acquire the
    /// witness chain's guarantees (ADR-285 discipline).
    AnchorExternalReceipt = 0xB0,

    // --- Governed context namespace (0xC0-0xCF) ---
    /// A versionless `ruv://` name was resolved to an immutable RVF revision.
    ContextResolve = 0xC0,
    /// A progressive context representation was read.
    ContextRead = 0xC1,
    /// An authorized context search enumerated candidate results.
    ContextSearch = 0xC2,
    /// A new immutable context revision was registered.
    ContextPut = 0xC3,
    /// A versionless alias was changed with compare-and-swap.
    ContextAliasUpdate = 0xC4,
    /// A context alias was tombstoned and its payload became unreachable.
    ContextForget = 0xC5,
    /// Execution of pinned context content was authorized.
    ContextExecute = 0xC6,
    /// A cryptographic receipt sealed a context witness epoch.
    ContextEpochSeal = 0xC7,
}

impl ActionKind {
    /// Return the subsystem prefix for this action kind.
    ///
    /// Useful for filtering audit queries by subsystem:
    /// 0 = partition, 1 = capability, 2 = memory, 3 = communication,
    /// 4 = device, 5 = proof, 6 = scheduler, 7 = recovery,
    /// 8 = boot, 9 = graph, 0xA = VMID management,
    /// 0xB = external anchoring, 0xC = governed context.
    #[must_use]
    pub const fn subsystem(self) -> u8 {
        (self as u8) >> 4
    }
}

/// FNV-1a hash over a byte slice.
///
/// Chosen for speed (< 50 ns for 64 bytes), not cryptographic strength.
/// For tamper resistance against a capable adversary, use the optional
/// TEE-backed `WitnessSigner` (ADR-134, Section 9).
///
/// Unrolls the per-byte loop by 8 for inputs >= 8 bytes while preserving
/// standard FNV-1a byte-order sensitivity. The remainder is handled
/// one byte at a time.
#[inline]
#[must_use]
pub fn fnv1a_64(data: &[u8]) -> u64 {
    const FNV_OFFSET: u64 = 0xcbf2_9ce4_8422_2325;
    const FNV_PRIME: u64 = 0x0000_0100_0000_01B3;

    let mut hash: u64 = FNV_OFFSET;
    let len = data.len();
    let mut i = 0;

    // Process 8 bytes at a time (unrolled), preserving standard FNV-1a
    // per-byte XOR-then-multiply semantics for hash compatibility.
    while i + 8 <= len {
        hash ^= u64::from(data[i]);
        hash = hash.wrapping_mul(FNV_PRIME);
        hash ^= u64::from(data[i + 1]);
        hash = hash.wrapping_mul(FNV_PRIME);
        hash ^= u64::from(data[i + 2]);
        hash = hash.wrapping_mul(FNV_PRIME);
        hash ^= u64::from(data[i + 3]);
        hash = hash.wrapping_mul(FNV_PRIME);
        hash ^= u64::from(data[i + 4]);
        hash = hash.wrapping_mul(FNV_PRIME);
        hash ^= u64::from(data[i + 5]);
        hash = hash.wrapping_mul(FNV_PRIME);
        hash ^= u64::from(data[i + 6]);
        hash = hash.wrapping_mul(FNV_PRIME);
        hash ^= u64::from(data[i + 7]);
        hash = hash.wrapping_mul(FNV_PRIME);
        i += 8;
    }

    // Handle remaining bytes one at a time.
    while i < len {
        hash ^= u64::from(data[i]);
        hash = hash.wrapping_mul(FNV_PRIME);
        i += 1;
    }

    hash
}

/// FNV-1a hash truncated to 32 bits.
#[inline]
#[must_use]
#[allow(clippy::cast_possible_truncation)]
pub fn fnv1a_32(data: &[u8]) -> u32 {
    // Intentional truncation: 64-bit hash folded to 32 bits.
    fnv1a_64(data) as u32
}

/// Default witness ring buffer capacity in records.
///
/// 16 MiB / 64 bytes = 262,144 records.
/// At 100,000 privileged actions per second this gives approximately 2.6
/// seconds of hot storage before overflow drain is needed.
pub const WITNESS_RING_CAPACITY: usize = 262_144;

/// Witness record size in bytes.
pub const WITNESS_RECORD_SIZE: usize = 64;