From ece851c0928f9fc2445a966bffb0f86ca6ca96fe Mon Sep 17 00:00:00 2001 From: Jack Lloyd Date: Sat, 19 Oct 2024 11:31:16 -0400 Subject: [PATCH] Reduce risk of compiler value range propogation in FrodoKEM sampling No compiler has been found to perform optimizations that introduce a side channel here, but the construct as written was somewhat risky. --- .../frodokem/frodokem_common/frodo_matrix.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/lib/pubkey/frodokem/frodokem_common/frodo_matrix.cpp b/src/lib/pubkey/frodokem/frodokem_common/frodo_matrix.cpp index f15490654c8..dc1a3b51e35 100644 --- a/src/lib/pubkey/frodokem/frodokem_common/frodo_matrix.cpp +++ b/src/lib/pubkey/frodokem/frodokem_common/frodo_matrix.cpp @@ -78,10 +78,11 @@ FrodoMatrix FrodoMatrix::sample(const FrodoKEMConstants& constants, load_le(elements.data(), r.data(), n); - for(size_t i = 0; i < n; ++i) { - uint32_t sample = 0; // Avoid integral promotion - const uint16_t prnd = elements.at(i) >> 1; // Drop the least significant bit - const uint16_t sign = elements.at(i) & 0x1; // Pick the least significant bit + for(auto& elem : elements) { + const uint16_t prnd = CT::value_barrier(elem >> 1); // Drop the least significant bit + const auto sign = CT::Mask::expand_bit(elem, 0); // Pick the least significant bit + + uint32_t sample = 0; // Avoid integral promotion // No need to compare with the last value. for(size_t j = 0; j < constants.cdf_table_len() - 1; ++j) { @@ -89,7 +90,9 @@ FrodoMatrix FrodoMatrix::sample(const FrodoKEMConstants& constants, sample += CT::Mask::is_lt(constants.cdf_table_at(j), prnd).if_set_return(1); } // Assuming that sign is either 0 or 1, flips sample iff sign = 1 - elements.at(i) = static_cast((-sign) ^ sample) + sign; + const uint16_t sample_u16 = static_cast(sample); + + elem = sign.select(~sample_u16, sample_u16) + (sign.value() & 1); } return FrodoMatrix(dimensions, std::move(elements));