Per-read file integrity in a no_std kernel: block-level BLAKE3 instead of re-hashing the whole file
โ Rust ๐ 2026-06-26 ๐ค surdeus ๐๏ธ 2I've been building a bare-metal no_std Rust kernel as an independent project, and I'd like feedback on its file-integrity mechanism.
Most integrity schemes (fs-verity, dm-verity, IMA) verify a file once โ at load, or when a page is first read from storage โ then trust the cached copy. That leaves a gap: if something corrupts the in-memory page after the check (a DMA-capable peripheral, a kernel bug, rowhammer), later reads return tampered bytes as authentic.
Re-hashing the whole file on every read closes the gap but scales with file size โ reading 4 bytes of a 4 MiB file re-hashes all 4 MiB, which blows a sub-millisecond budget on edge hardware.
What I did instead:
- Split each file into fixed 4 KiB blocks, each with a stored BLAKE3 leaf hash.
- A ranged read verifies only the blocks it touches, so per-read cost is
ฮ(bytes read)rather thanฮ(file size). - A lazily-recomputed Merkle root over the leaves bounds write cost (one block hash + a deferred root update, instead of a full rehash).
On real hardware (an x86-64 laptop and an ARM64 phone via Termux), block-level verification stays roughly constant โ ~2.7 ยตs on x86-64, ~3.65 ยตs on ARM64 โ across the whole 4 KiBโ4 MiB range, while whole-file verification grows into milliseconds.
Repo (kernel + benchmark harness): I'll drop the link in a reply below.
Two things I'm genuinely unsure about and would value opinions on:
- BLAKE3 SIMD in a
no_stdkernel. I'm running it in portable mode in-kernel right now. Is wiring up the SIMD path worth it on a bare-metal target, or more trouble than it's worth? - Constant-time leaf comparison. I accumulate per-byte differences without early exit to avoid a timing side channel on the verify path. Reasonable instinct here, or unnecessary?
Happy to go into the VFS hook or the lazy-Merkle update if anyone's interested.
5 posts - 4 participants
๐ท๏ธ Rust_feed