SECURITY: fix timing variability in backend/serial/u32/scalar.rs (#661)

Similar security fix to #659, but for the 32-bit backend. See that PR
for more information about the problem. Relevant compiler outputs (thanks to @tarcieri):

Without fix
https://godbolt.org/z/zvaWxzvqv
Notice the `jns` ("jump if not sign") instruction on line 106.

With fix
https://godbolt.org/z/jc9j7eb8E
This commit is contained in:
Tony Arcieri 2024-06-18 13:02:37 -06:00 committed by GitHub
parent 415892acf1
commit b4f9e4df92
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -185,6 +185,14 @@ impl Scalar29 {
/// Compute `a - b` (mod l).
pub fn sub(a: &Scalar29, b: &Scalar29) -> Scalar29 {
// Optimization barrier to prevent compiler from inserting branch instructions
// TODO(tarcieri): find a better home (or abstraction) for this
fn black_box(value: u32) -> u32 {
// SAFETY: `u32` is a simple integer `Copy` type and `value` lives on the stack so
// a pointer to it will be valid.
unsafe { core::ptr::read_volatile(&value) }
}
let mut difference = Scalar29::ZERO;
let mask = (1u32 << 29) - 1;
@ -199,7 +207,7 @@ impl Scalar29 {
let underflow_mask = ((borrow >> 31) ^ 1).wrapping_sub(1);
let mut carry: u32 = 0;
for i in 0..9 {
carry = (carry >> 29) + difference[i] + (constants::L[i] & underflow_mask);
carry = (carry >> 29) + difference[i] + (constants::L[i] & black_box(underflow_mask));
difference[i] = carry & mask;
}