Hey
,
My PhD dissertation happens to be on the topic of fault injection (simulation, and also fault model inference), so I know the subject somewhat
.
I'd say you can't do fault-injection resistant code (Rust, or anything else) in a vacuum. The state of the art is that multiple fault injections are possible, with various fault models that have sometimes non-local and unpredictable consequences (eg you can access "phantom instructions" on variable-width instruction sets because some fault models makes the target offset its interpretation of instructions by a fraction of one instruction...). You need a hardware target that your code will run on (and be compiled for), a fault model (what happens when I throw an EM pulse at this position on the component? Instruction skip? Instruction change? Data change?) and an attacker model (how likely is the attacker to be able to perform 1 fault on the component. 2 faults? more? How much time, equipment and expertise has the attacker?). Blindly double-checking every conditional is not going to work if the fault model allows you to NOP 10-40 instructions.
With these targets being set, the Rust compiler will be your first enemy in making fault-resistant code. I'm personally convinced that if we are to be serious about fault injection countermeasures at scale, we need to add the capability built-in to the compiler. An approach is described in the 3rd part of the blog post you linked, btw.
If I were to implement something like this, I would add some countermeasure_xxx lang items to the compiler (eg countermeasure_double_check), then implement them as custom LLVM attributes that can drive code generation to add the countermeasure (and inhibit any optimization that would annihilate the countermeasure, which is probably the hard part I guess). You'd also need to make sure the rust compiler doesn't already performs optimization before lowering to LLVM, and disable them here too.
In the absence of such a tool, I guess your best bet is directly writing assembly for the parts of the code that need to be fault-resistant. You need to do so to be side-channel resistant anyway, due to similar reasons (a compiler extension to add "branch_balanced" attributes would be similarly interesting).