Skip to content

Commit

Permalink
arithmetic internals: Iterate over slice in Rust for even/zero checks.
Browse files Browse the repository at this point in the history
(We still need `LIMBS_are_zero` because it is used from C code.
Rewrite it to use the same algorithm as the Rust equivalent.)

This eliminates a pair of calls to pointer-taking C functions.
  • Loading branch information
briansmith committed Jan 24, 2025
1 parent 3c5946f commit 5bc94d2
Show file tree
Hide file tree
Showing 4 changed files with 19 additions and 31 deletions.
2 changes: 1 addition & 1 deletion build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -865,8 +865,8 @@ fn prefix_all_symbols(pp: char, prefix_prefix: &str, prefix: &str) -> String {
"ChaCha20_ctr32_nohw",
"ChaCha20_ctr32_ssse3",
"ChaCha20_ctr32_ssse3_4x",
"LIMB_is_zero",
"LIMBS_add_mod",
"LIMBS_are_even",
"LIMBS_are_zero",
"LIMBS_equal",
"LIMBS_equal_limb",
Expand Down
24 changes: 8 additions & 16 deletions crypto/limbs/limbs.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,19 @@
* but we haven't verified that assumption. TODO: Fix it so we don't need to
* make that assumption. */

/* Returns 0xfff..f if |a| is zero, and zero otherwise. */
Limb LIMB_is_zero(const Limb a) {
return constant_time_is_zero_w(a);
}

/* Returns 0xfff..f if |a| is all zero limbs, and zero otherwise. |num_limbs|
* may be zero. */
Limb LIMBS_are_zero(const Limb a[], size_t num_limbs) {
Limb is_zero = CONSTTIME_TRUE_W;
Limb all = 0;
for (size_t i = 0; i < num_limbs; ++i) {
is_zero = constant_time_select_w(is_zero, constant_time_is_zero_w(a[i]),
is_zero);
all |= a[i];
}
return is_zero;
return LIMB_is_zero(all);
}

/* Returns 0xffff..f if |a == b|, and zero otherwise. |num_limbs| may be zero. */
Expand All @@ -54,18 +58,6 @@ Limb LIMBS_equal_limb(const Limb a[], Limb b, size_t num_limbs) {
return constant_time_select_w(lo_equal, hi_zero, 0);
}

/* Returns 0xfff..f if |a| is all zero limbs, and zero otherwise.
* |num_limbs| may be zero. */
Limb LIMBS_are_even(const Limb a[], size_t num_limbs) {
Limb lo;
if (num_limbs == 0) {
lo = 0;
} else {
lo = a[0];
}
return constant_time_is_zero_w(lo & 1);
}

/* Returns 0xffff...f if |a| is less than |b|, and zero otherwise. */
Limb LIMBS_less_than(const Limb a[], const Limb b[], size_t num_limbs) {
debug_assert_nonsecret(num_limbs >= 1);
Expand Down
1 change: 0 additions & 1 deletion crypto/limbs/limbs.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ typedef crypto_word_t Limb;


Limb LIMBS_are_zero(const Limb a[], size_t num_limbs);
Limb LIMBS_are_even(const Limb a[], size_t num_limbs);
Limb LIMBS_equal(const Limb a[], const Limb b[], size_t num_limbs);
Limb LIMBS_equal_limb(const Limb a[], Limb b, size_t num_limbs);
void LIMBS_reduce_once(Limb r[], const Limb m[], size_t num_limbs);
Expand Down
23 changes: 10 additions & 13 deletions src/limb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ pub fn limbs_equal_limbs_consttime(a: &[Limb], b: &[Limb]) -> LimbMask {
prefixed_extern! {
fn LIMBS_equal(a: *const Limb, b: *const Limb, num_limbs: c::size_t) -> LimbMask;
}

assert_eq!(a.len(), b.len());
unsafe { LIMBS_equal(a.as_ptr(), b.as_ptr(), a.len()) }
}
Expand Down Expand Up @@ -89,27 +88,25 @@ pub fn limbs_less_than_limbs_vartime(a: &[Limb], b: &[Limb]) -> Result<bool, Len
}

#[inline]
pub fn limbs_are_zero_constant_time(limbs: &[Limb]) -> LimbMask {
fn limb_is_zero_constant_time(limb: Limb) -> LimbMask {
prefixed_extern! {
fn LIMBS_are_zero(a: *const Limb, num_limbs: c::size_t) -> LimbMask;
fn LIMB_is_zero(limb: Limb) -> LimbMask;
}
unsafe { LIMBS_are_zero(limbs.as_ptr(), limbs.len()) }
unsafe { LIMB_is_zero(limb) }
}

#[inline]
pub fn limbs_are_zero_constant_time(limbs: &[Limb]) -> LimbMask {
limb_is_zero_constant_time(limbs.iter().fold(0, |a, b| a | b))
}

/// Leaks one bit of information (other than the lengths of the inputs):
/// Whether the given limbs are even.
#[cfg(any(test, feature = "alloc"))]
#[inline]
pub fn limbs_reject_even_leak_bit(limbs: &[Limb]) -> Result<(), error::Unspecified> {
prefixed_extern! {
fn LIMBS_are_even(a: *const Limb, num_limbs: c::NonZero_size_t) -> LimbMask;
}
let len = NonZeroUsize::new(limbs.len()).ok_or(error::Unspecified)?;
let r = unsafe { LIMBS_are_even(limbs.as_ptr(), len) };
if r.leak() {
return Err(error::Unspecified);
}
Ok(())
let bottom = *limbs.first().ok_or(error::Unspecified)?;
limb_is_zero_constant_time(bottom & 1)
}

#[cfg(any(test, feature = "alloc"))]
Expand Down

0 comments on commit 5bc94d2

Please sign in to comment.