Skip to content

Commit 90936dc

Browse files
authored
ctutils: deprecate Choice::new (#1312)
It panics if given a value which isn't `0` or `1`. Instead we can use `Choice::from_u8_lsb` for clear, non-panicking semantics instead.
1 parent 7746d38 commit 90936dc

File tree

4 files changed

+35
-49
lines changed

4 files changed

+35
-49
lines changed

ctutils/src/choice.rs

Lines changed: 30 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ macro_rules! bitnz {
3636
/// the only line of defense.
3737
// TODO(tarcieri): remove `Eq`/`PartialEq` when `crypto-bigint` is updated
3838
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
39-
pub struct Choice(u8);
39+
pub struct Choice(pub(crate) u8);
4040

4141
impl Choice {
4242
/// Equivalent of [`false`].
@@ -45,28 +45,11 @@ impl Choice {
4545
/// Equivalent of [`true`].
4646
pub const TRUE: Self = Self(1);
4747

48-
/// Create a new [`Choice`] from the given `u8` value, which MUST be either `0` or `1`.
49-
///
50-
/// <div class="warning">
51-
/// <b>Potential panics and other misbehavior!</b>
52-
///
53-
/// This constructor panics in debug builds if the given value is not 0 or 1.
54-
///
55-
/// It mainly exists as a convenience for migrating code which previously used `subtle`, but
56-
/// we may deprecate it in future releases.
57-
///
58-
/// Consider using a more specific non-panicking constructor, like [`Choice::from_u8_lsb`].
59-
/// </div>
60-
///
61-
/// # Panics
62-
/// - in `debug` builds, panics if the value is anything other than `0` or `1`.
63-
// TODO(tarcieri): deprecate this in favor of non-panicking constructors?
48+
/// DEPRECATED: legacy alias for [`Choice::from_u8_lsb`].
49+
#[deprecated(since = "0.2.3", note = "use `Choice::from_u8_lsb` instead")]
6450
#[inline]
6551
pub const fn new(value: u8) -> Self {
66-
// Compare to what should be the non-secret upper bits of the value, which should always be
67-
// zero, and thus avoid branching on the bit that carries a potential secret
68-
debug_assert!(value & 0xFE == 0, "Choice::new accepts only 0 or 1");
69-
Self(value)
52+
Self::from_u8_lsb(value)
7053
}
7154

7255
/// Convert `Choice` into a `bool`.
@@ -472,14 +455,17 @@ impl CtSelect for Choice {
472455
}
473456
}
474457

475-
/// Create a new [`Choice`] from the given `u8` value, which MUST be either `0` or `1`.
458+
/// DEPRECATED: this exists to aid migrating code from `subtle`. Use `Choice::from_u8_lsb` instead.
476459
///
477-
/// # Panics
478-
/// - in `debug` builds, panics if the value is anything other than `0` or `1`.
479-
// TODO(tarcieri): deprecate this in favor of non-panicking constructors?
460+
/// <div class="warning">
461+
/// <b>Note</b>
462+
///
463+
/// Rust doesn't actually let us deprecate an impl block, however this comment is here to
464+
/// discourage future use and warn that this will be removed in a future release.
465+
/// </div>
480466
impl From<u8> for Choice {
481467
fn from(value: u8) -> Self {
482-
Choice::new(value)
468+
Choice::from_u8_lsb(value)
483469
}
484470
}
485471

@@ -576,44 +562,44 @@ mod tests {
576562

577563
#[test]
578564
fn to_bool() {
579-
assert!(!Choice::new(0).to_bool());
580-
assert!(Choice::new(1).to_bool());
565+
assert!(!Choice::FALSE.to_bool());
566+
assert!(Choice::TRUE.to_bool());
581567
}
582568

583569
#[test]
584570
fn to_u8() {
585-
assert_eq!(Choice::new(0).to_u8(), 0);
586-
assert_eq!(Choice::new(1).to_u8(), 1);
571+
assert_eq!(Choice::FALSE.to_u8(), 0);
572+
assert_eq!(Choice::TRUE.to_u8(), 1);
587573
}
588574

589575
#[test]
590576
fn and() {
591-
assert_eq!((Choice::new(0) & Choice::new(0)).to_u8(), 0);
592-
assert_eq!((Choice::new(1) & Choice::new(0)).to_u8(), 0);
593-
assert_eq!((Choice::new(0) & Choice::new(1)).to_u8(), 0);
594-
assert_eq!((Choice::new(1) & Choice::new(1)).to_u8(), 1);
577+
assert_eq!((Choice::FALSE & Choice::FALSE).to_u8(), 0);
578+
assert_eq!((Choice::TRUE & Choice::FALSE).to_u8(), 0);
579+
assert_eq!((Choice::FALSE & Choice::TRUE).to_u8(), 0);
580+
assert_eq!((Choice::TRUE & Choice::TRUE).to_u8(), 1);
595581
}
596582

597583
#[test]
598584
fn or() {
599-
assert_eq!((Choice::new(0) | Choice::new(0)).to_u8(), 0);
600-
assert_eq!((Choice::new(1) | Choice::new(0)).to_u8(), 1);
601-
assert_eq!((Choice::new(0) | Choice::new(1)).to_u8(), 1);
602-
assert_eq!((Choice::new(1) | Choice::new(1)).to_u8(), 1);
585+
assert_eq!((Choice::FALSE | Choice::FALSE).to_u8(), 0);
586+
assert_eq!((Choice::TRUE | Choice::FALSE).to_u8(), 1);
587+
assert_eq!((Choice::FALSE | Choice::TRUE).to_u8(), 1);
588+
assert_eq!((Choice::TRUE | Choice::TRUE).to_u8(), 1);
603589
}
604590

605591
#[test]
606592
fn xor() {
607-
assert_eq!((Choice::new(0) ^ Choice::new(0)).to_u8(), 0);
608-
assert_eq!((Choice::new(1) ^ Choice::new(0)).to_u8(), 1);
609-
assert_eq!((Choice::new(0) ^ Choice::new(1)).to_u8(), 1);
610-
assert_eq!((Choice::new(1) ^ Choice::new(1)).to_u8(), 0);
593+
assert_eq!((Choice::FALSE ^ Choice::FALSE).to_u8(), 0);
594+
assert_eq!((Choice::TRUE ^ Choice::FALSE).to_u8(), 1);
595+
assert_eq!((Choice::FALSE ^ Choice::TRUE).to_u8(), 1);
596+
assert_eq!((Choice::TRUE ^ Choice::TRUE).to_u8(), 0);
611597
}
612598

613599
#[test]
614600
fn not() {
615-
assert_eq!(Choice::new(0).not().to_u8(), 1);
616-
assert_eq!(Choice::new(1).not().to_u8(), 0);
601+
assert_eq!(Choice::FALSE.not().to_u8(), 1);
602+
assert_eq!(Choice::TRUE.not().to_u8(), 0);
617603
}
618604

619605
#[test]

ctutils/src/traits/ct_eq.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@ macro_rules! impl_ct_eq_with_cmov_eq {
2929
impl CtEq for $ty {
3030
#[inline]
3131
fn ct_eq(&self, other: &Self) -> Choice {
32-
let mut ret = 0;
33-
self.cmoveq(other, 1, &mut ret);
34-
Choice::new(ret)
32+
let mut ret = Choice::FALSE;
33+
self.cmoveq(other, 1, &mut ret.0);
34+
ret
3535
}
3636
}
3737
)+

ctutils/src/traits/ct_gt.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ macro_rules! impl_unsigned_ct_gt {
1515
#[inline]
1616
fn ct_gt(&self, other: &Self) -> Choice {
1717
let (_, overflow) = other.overflowing_sub(*self);
18-
Choice::new(overflow.into())
18+
Choice(overflow.into())
1919
}
2020
}
2121
)+

ctutils/src/traits/ct_lt.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ macro_rules! impl_unsigned_ct_lt {
1515
#[inline]
1616
fn ct_lt(&self, other: &Self) -> Choice {
1717
let (_, overflow) = self.overflowing_sub(*other);
18-
Choice::new(overflow.into())
18+
Choice(overflow.into())
1919
}
2020
}
2121
)+

0 commit comments

Comments
 (0)