Making My Rust Program Space-Flight Ready — Walter van der Giessen
Skip to content
2026-07-13
Making My Rust Program Space-Flight Ready
Walter van der Giessen
Yesterday someone published a crate called hugebool. It has one export, a type called Booléan, and the docs describe it as "The strongest, radiation-hardened Booléan (16-bytes wide)". A normal Rust bool is one byte. This one is sixteen, which makes it sixteen times as much boolean, and I hear you thinking: why on earth would anyone need that? I'd argue that's exactly the point. Nobody on earth does.
Or so I thought.
In 2003 an electronic voting machine in Schaerbeek, Belgium gave a candidate 4,096 extra preference votes. That number is 2^12 exactly, the official explanation is a single flipped bit, and the error was only caught because she ended up with more votes than were mathematically possible in her district. ECC memory exists because this happens often enough to matter. My laptop doesn't have ECC. My programs have been running unprotected this whole time, at sea level, like fools.
A boolean with a safety margin
The entire crate is one enum:
#[repr(u128)]<br>pub enum Booléan {<br>falsé = 0x0,<br>trué = 0x55aa55aa55aa55aa55aa55,<br>The accents are there for a reason. bool, true and false are keywords, so the radiation-hardened versions needed names of their own, and the author went with French.
The bit pattern is where I stopped laughing and started taking notes. 0x55 is 01010101 and 0xAA is 10101010, the same alternating patterns memory testers have been writing into RAM for decades. falsé is 128 zeroes. trué has 44 ones spread across the low 11 bytes (the top 5 bytes are zero, which I can only assume is headroom). For radiation to silently turn one valid value into the other, it has to flip exactly those 44 bits and no others. Compare that to a normal bool, where a single hit turns true into false instantly and with total confidence. There's no wreckage to investigate afterwards, because the wreckage is a perfectly valid boolean.
Booléan also derefs to bool, so if *launch_ready works and every if statement it touches is now aerospace grade.
Reads that repair
hugebool makes corruption detectable, since 2^128 minus two of all possible values are invalid. I wanted it repairable too. If a value isn't exactly trué or falsé, count how many bits separate it from each and pick the closer one:
const TRUÉ: u128 = 0x55aa55aa55aa55aa55aa55;
fn decode(raw: u128) -> Booléan {<br>let flips_from_falsé = raw.count_ones();<br>let flips_from_trué = (raw ^ TRUÉ).count_ones();<br>if flips_from_trué flips_from_falsé {<br>Booléan::trué<br>} else {<br>Booléan::falsé<br>This is nearest-match decoding, the same idea ECC memory is built on, implemented with two calls to count_ones(). Since the valid values differ in 44 bits, any corruption of up to 21 bits decodes back to the original. At exactly 22 flips in the wrong places the value sits equidistant between the two, and my decoder returns falsé, because if we genuinely can't tell anymore I'd rather the engines not fire.
Why stop at booleans
Real spacecraft apply redundancy to whole computers, and the classic trick is triple modular redundancy: run three copies, compare, and go with the majority. The Space Shuttle flew four flight computers voting against each other, plus a fifth running independently written software in case the bug was in the software itself. I don't have a Space Shuttle budget, but I do have generics.
pub struct RadT> {<br>copies: [T; 3],
implT: Eq + Copy> RadT> {<br>pub fn new(value: T) -> Self {<br>Rad { copies: [value; 3] }
pub fn read(&mut self) -> T {<br>let [a, b, c] = self.copies;<br>let winner = if a == b || a == c { a } else { b };<br>self.copies = [winner; 3]; // scrub: heal the outvoted copy<br>winner<br>Note that read takes &mut self, because reading also repairs, and Rust makes you admit that in the signature. The repair step is called scrubbing and real systems do it too: satellite memory controllers walk through RAM in the background rewriting anything ECC flags, so single-bit errors never get the time to accumulate into something unvotable.
Nothing in Rad cares that the payload is a boolean. Anything Eq + Copy votes the same way, so the rest of my imaginary flight state gets hardened with the same eight lines:
#[derive(Clone, Copy, PartialEq, Eq)]<br>enum FlightMode { Prelaunch, Ascent, Coast, Reentry }
let mut mode = Rad::new(FlightMode::Ascent);<br>let mut altitude_m = Rad::new(31_547u32);<br>let mut retries_left = Rad::new(3u8);<br>Integers actually need this more than my Booléan does. Every one of a u32's four billion values is valid, so a bit flip in a plain altitude_m just produces a different altitude, and there's nothing to detect after the fact. Schaerbeek was exactly this: a counter, one flipped bit, and a result that looked fine until someone did the math by hand. Majority voting doesn't need invalid values to exist, because it only compares the three copies against each other, so it covers types where the hugebool...