Skip to content

Commit

Permalink
Add BoxedUint::conditional_select (#329)
Browse files Browse the repository at this point in the history
This is an inherent function with the same type signature as
`subtle::ConditionallySelectable::conditional_select`, however we can't
impl the upstream trait because it has a `Copy` bound.

See dalek-cryptography/subtle#94.
  • Loading branch information
tarcieri authored Nov 27, 2023
1 parent f07de91 commit 071bb85
Showing 1 changed file with 33 additions and 1 deletion.
34 changes: 33 additions & 1 deletion src/uint/boxed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ mod sub_mod;
use crate::{Limb, Uint, Word, Zero, U128, U64};
use alloc::{boxed::Box, vec, vec::Vec};
use core::fmt;
use subtle::Choice;
use subtle::{Choice, ConditionallySelectable};

#[cfg(feature = "zeroize")]
use zeroize::Zeroize;
Expand Down Expand Up @@ -151,6 +151,23 @@ impl BoxedUint {
self.limbs.len()
}

/// Conditionally select `a` or `b` in constant time depending on [`Choice`].
///
/// NOTE: can't impl `subtle`'s [`ConditionallySelectable`] trait due to its `Copy` bound, so
/// this is an inherent function instead.
///
/// Panics if `a` and `b` don't have the same precision.
pub fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
debug_assert_eq!(a.nlimbs(), b.nlimbs());
let mut limbs = vec![Limb::ZERO; a.nlimbs()].into_boxed_slice();

for i in 0..a.nlimbs() {
limbs[i] = Limb::conditional_select(&a.limbs[i], &b.limbs[i], choice);
}

Self { limbs }
}

/// Perform a carry chain-like operation over the limbs of the inputs,
/// constructing a result from the returned limbs and carry which is
/// widened to the same width as the widest input.
Expand Down Expand Up @@ -300,3 +317,18 @@ impl Zeroize for BoxedUint {
self.limbs.zeroize();
}
}

#[cfg(test)]
mod tests {
use super::BoxedUint;
use subtle::Choice;

#[test]
fn conditional_select() {
let a = BoxedUint::zero_with_precision(128);
let b = BoxedUint::max(128);

assert_eq!(a, BoxedUint::conditional_select(&a, &b, Choice::from(0)));
assert_eq!(b, BoxedUint::conditional_select(&a, &b, Choice::from(1)));
}
}

0 comments on commit 071bb85

Please sign in to comment.