Skip to content

Commit 071bb85

Browse files
authored
Add BoxedUint::conditional_select (#329)
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.
1 parent f07de91 commit 071bb85

File tree

1 file changed

+33
-1
lines changed

1 file changed

+33
-1
lines changed

src/uint/boxed.rs

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ mod sub_mod;
1414
use crate::{Limb, Uint, Word, Zero, U128, U64};
1515
use alloc::{boxed::Box, vec, vec::Vec};
1616
use core::fmt;
17-
use subtle::Choice;
17+
use subtle::{Choice, ConditionallySelectable};
1818

1919
#[cfg(feature = "zeroize")]
2020
use zeroize::Zeroize;
@@ -151,6 +151,23 @@ impl BoxedUint {
151151
self.limbs.len()
152152
}
153153

154+
/// Conditionally select `a` or `b` in constant time depending on [`Choice`].
155+
///
156+
/// NOTE: can't impl `subtle`'s [`ConditionallySelectable`] trait due to its `Copy` bound, so
157+
/// this is an inherent function instead.
158+
///
159+
/// Panics if `a` and `b` don't have the same precision.
160+
pub fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
161+
debug_assert_eq!(a.nlimbs(), b.nlimbs());
162+
let mut limbs = vec![Limb::ZERO; a.nlimbs()].into_boxed_slice();
163+
164+
for i in 0..a.nlimbs() {
165+
limbs[i] = Limb::conditional_select(&a.limbs[i], &b.limbs[i], choice);
166+
}
167+
168+
Self { limbs }
169+
}
170+
154171
/// Perform a carry chain-like operation over the limbs of the inputs,
155172
/// constructing a result from the returned limbs and carry which is
156173
/// widened to the same width as the widest input.
@@ -300,3 +317,18 @@ impl Zeroize for BoxedUint {
300317
self.limbs.zeroize();
301318
}
302319
}
320+
321+
#[cfg(test)]
322+
mod tests {
323+
use super::BoxedUint;
324+
use subtle::Choice;
325+
326+
#[test]
327+
fn conditional_select() {
328+
let a = BoxedUint::zero_with_precision(128);
329+
let b = BoxedUint::max(128);
330+
331+
assert_eq!(a, BoxedUint::conditional_select(&a, &b, Choice::from(0)));
332+
assert_eq!(b, BoxedUint::conditional_select(&a, &b, Choice::from(1)));
333+
}
334+
}

0 commit comments

Comments
 (0)