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
//! Kani symbolic-verification harnesses for [`crate::Frame`] and
//! [`crate::crc32c`].
//!
//! This module is gated `#[cfg(kani)]` so the harnesses are invisible to
//! every normal `cargo build` / `cargo test` invocation. The Kani crate
//! is injected by `cargo kani` at proof time — there is no entry in
//! [`Cargo.toml`] for it, and the zero-registry-dependency invariant
//! documented in `CLAUDE.md` is preserved by construction.
//!
//! Run locally with `cargo kani -p varta-vlp`. In CI, the
//! `kani-proofs` job in `.github/workflows/ci.yml` runs the same
//! command and is a required gate on every PR that touches
//! `crates/varta-vlp/**`.
//!
//! ### Split-harness design
//!
//! Combining the CRC-table loop (28 iterations × 256-entry lookup) with
//! the full decode path explodes CBMC's state space. The proofs are
//! split so the symbolic cost stays bounded:
//!
//! * The CRC harness ([`crc_detects_bit_flip`]) proves the load-bearing
//! detection property of [`crate::crc32c::compute`] over arbitrary
//! `[u8; 28]`. Determinism / panic-freedom of `compute` are guaranteed
//! by the type system (it is `pub const fn` with no global state) and by
//! the const-asserts in `crc32c.rs`.
//! * The decode harnesses ([`decode_never_panics`],
//! [`decode_classification`]) operate on inputs constrained so the
//! CRC trailer matches the body, decoupling decode-correctness from
//! CRC-correctness.
//! * [`encode_decode_roundtrips`] and [`decode_error_precedence`]
//! exercise structural invariants over constructable frames.
//!
//! See `book/src/architecture/verification.md` for the full strategy and a
//! mapping from each harness to the protocol invariant it proves.
use crate::;
/// **M7 Step 2 — panic-freedom.**
///
/// For every possible 32-byte input, [`Frame::decode`] returns without
/// panicking. The harness is unconstrained: random bytes that fail the
/// magic / version / CRC / status / field-range gates surface as the
/// corresponding [`DecodeError`] variant; nothing inside the function
/// indexes outside `&[u8; 32]` or executes an `unwrap` on an `Err`.
/// **M7 Step 2 — classification + post-condition coverage.**
///
/// For every 32-byte input, [`Frame::decode`] returns either an [`Err`]
/// of one of the named [`DecodeError`] variants or an [`Ok(Frame)`]
/// whose fields satisfy every documented post-condition:
///
/// * `frame.magic == MAGIC`
/// * `frame.version == VERSION`
/// * `frame.status` is one of `Ok` / `Degraded` / `Critical`
/// (`Stall` is rejected by [`DecodeError::StallOnWire`]).
/// * `frame.pid >= 2` (the `BadPid(0)` / `BadPid(1)` gates fire first).
/// * `frame.timestamp != u64::MAX` (the `BadTimestamp` gate fires first).
/// * `frame.nonce != NONCE_TERMINAL` unless `frame.status == Critical`.
///
/// The harness does NOT stamp a matching CRC over `bytes[0..28]`.
/// Kani explores both CRC-valid inputs (the `Ok(frame)` arm, reachable
/// when the SMT solver picks `bytes[28..32] == compute(bytes[0..28])`)
/// and CRC-invalid inputs (the `Err(BadCrc)` arm). Stamping the CRC
/// externally introduced a second symbolic 28-iteration table-lookup
/// loop that CBMC had to prove equivalent to the one inside
/// `Frame::decode` — the same SMT-equivalence problem that forced the
/// removal of `crc_compute_is_total` (see comment below). CRC
/// detection is proved separately by [`crc_detects_bit_flip`] in
/// Step 3, so this harness needs no CRC constraint.
// `crc_compute_is_total` (CRC determinism) was removed: CBMC took >19 min on
// it because two symbolic 28-iteration table-lookup expressions over the same
// input must be proved equivalent at the SMT level. The property is already
// guaranteed by the type system — `crc32c::compute` is a `pub const fn` with
// no global state, no allocation, no FFI — and is exercised concretely by the
// const-asserts at `crc32c::tests::compute(b"") == 0x0000_0000` and the RFC
// 3720 reference vector. Totality (panic-freedom) is subsumed by
// `decode_never_panics`, which calls `compute` via the decode path.
/// **M7 Step 3 — single-bit-flip detection.**
///
/// For every 28-byte payload and every bit position in `[0, 28 * 8)`,
/// flipping that bit produces a different CRC. This is the
/// load-bearing property of CRC-32C — guaranteed by polynomial
/// construction — and is the reason the wire format uses CRC-32C
/// rather than a parity checksum.
///
/// State scope: pure CRC. No decode path, no protocol gates. CBMC
/// handles the 256-entry table lookup natively via array reads; the
/// 28-iteration loop is bounded by `default-unwind = 64` in
/// `Kani.toml`.
/// **M7 Step 4a — encode/decode round-trip (smoke test for per-PR budget).**
///
/// The buffer produced by [`Frame::encode`] on a constructable [`Frame`]
/// decodes back to a [`Frame`] with identical fields. This variant uses
/// concrete field values to stay within the per-PR CI budget (<1s);
/// the exhaustive multi-dimensional symbolic variant runs in kani-nightly.yml.
///
/// CRC computation over symbolic fields creates large SMT state
/// (even with only 2 symbolic variables, >2 min locally); smoke-testing
/// with concrete fields verifies the encode/decode path works, while
/// nightly exhaustive testing proves the invariant holds universally.
/// **M7 Step 4b — exhaustive encode/decode round-trip (nightly variant).**
///
/// For every constructable [`Frame`] whose field values satisfy the
/// documented invariants ([`Frame::decode`] docstring), the buffer
/// produced by [`Frame::encode`] decodes back to a `Frame` with
/// identical fields. The constructable subset is bounded by:
///
/// * `pid >= 2` (pid 0 = scheduler, pid 1 = init).
/// * `timestamp < u64::MAX` (reserved sentinel).
/// * `status ∈ {Ok, Degraded, Critical}` (Stall is observer-synthesised).
/// * `nonce != NONCE_TERMINAL` unless `status == Critical`.
///
/// This exhaustive multi-dimensional symbolic variant explores all status
/// values and nonce constraints, creating large SMT state via CRC
/// computation over symbolic fields. CBMC runtime is >80s locally;
/// runs in kani-nightly.yml with 6h budget.
/// **M7 Step 4c — error-gate precedence.**
///
/// For every 32-byte input that fails decode, the first gate in the
/// documented order (magic → version → CRC → status → pid →
/// timestamp → nonce) is the one whose [`DecodeError`] variant is
/// returned. This harness proves the magic and version precedences
/// universally; the remaining precedence cases are covered by
/// integration tests (`crates/varta-vlp/tests/frame.rs`) over chosen
/// counter-examples and are subsumed by [`decode_classification`] in
/// aggregate.