Skip to content

Commit 2a8b0b1

Browse files
authored
ctutils: core::num::NonZero<T> support (#1368)
Adds initial support for the following aliases of `NonZero<T>`: - NonZeroI8 - NonZeroI16 - NonZeroI32 - NonZeroI64 - NonZeroI128 - NonZeroU8 - NonZeroU16 - NonZeroU32 - NonZeroU64 - NonZeroU128 (We can't yet implement things generically because `NonZero` bounds on `T: ZeroablePrimitive` which is unstable) The following traits are impl'd for all of the above: - `CtAssign` - `CtEq` - `CtNeg` - `CtSelect` The following are impl'd for the unsigned `NonZeroU*` types: - `CtGt` - `CtLt`
1 parent 8e9e528 commit 2a8b0b1

7 files changed

Lines changed: 176 additions & 7 deletions

File tree

ctutils/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
clippy::panic_in_result_fn,
1818
clippy::std_instead_of_alloc,
1919
clippy::std_instead_of_core,
20+
clippy::undocumented_unsafe_blocks,
21+
clippy::unnecessary_safety_comment,
2022
missing_copy_implementations,
2123
missing_debug_implementations,
2224
missing_docs,

ctutils/src/traits/ct_assign.rs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
use crate::{Choice, CtSelect};
22
use cmov::Cmov;
3-
use core::cmp;
3+
use core::{
4+
cmp,
5+
num::{
6+
NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI128, NonZeroU8, NonZeroU16,
7+
NonZeroU32, NonZeroU64, NonZeroU128,
8+
},
9+
};
410

511
#[cfg(feature = "alloc")]
612
use alloc::{boxed::Box, vec::Vec};
@@ -29,7 +35,19 @@ macro_rules! impl_ct_assign_with_ct_select {
2935
};
3036
}
3137

32-
impl_ct_assign_with_ct_select!(cmp::Ordering);
38+
impl_ct_assign_with_ct_select!(
39+
cmp::Ordering,
40+
NonZeroI8,
41+
NonZeroI16,
42+
NonZeroI32,
43+
NonZeroI64,
44+
NonZeroI128,
45+
NonZeroU8,
46+
NonZeroU16,
47+
NonZeroU32,
48+
NonZeroU64,
49+
NonZeroU128
50+
);
3351

3452
/// Impl `CtAssign` using the `cmov::Cmov` trait
3553
macro_rules! impl_ct_assign_with_cmov {

ctutils/src/traits/ct_eq.rs

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
use crate::Choice;
22
use cmov::CmovEq;
3-
use core::cmp;
3+
use core::{
4+
cmp,
5+
num::{
6+
NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI128, NonZeroU8, NonZeroU16,
7+
NonZeroU32, NonZeroU64, NonZeroU128,
8+
},
9+
};
410

511
#[cfg(feature = "subtle")]
612
use crate::CtOption;
@@ -24,7 +30,7 @@ where
2430
}
2531
}
2632

27-
// Impl `CtEq` using the `cmov::CmovEq` trait
33+
/// Impl `CtEq` using the `cmov::CmovEq` trait
2834
macro_rules! impl_ct_eq_with_cmov_eq {
2935
( $($ty:ty),+ ) => {
3036
$(
@@ -42,6 +48,33 @@ macro_rules! impl_ct_eq_with_cmov_eq {
4248

4349
impl_ct_eq_with_cmov_eq!(i8, i16, i32, i64, i128, u8, u16, u32, u64, u128);
4450

51+
/// Impl `CtEq` for `NonZero<T>` by calling `NonZero::get`.
52+
macro_rules! impl_ct_eq_for_nonzero_integer {
53+
( $($ty:ty),+ ) => {
54+
$(
55+
impl CtEq for $ty {
56+
#[inline]
57+
fn ct_eq(&self, other: &Self) -> Choice {
58+
self.get().ct_eq(&other.get())
59+
}
60+
}
61+
)+
62+
};
63+
}
64+
65+
impl_ct_eq_for_nonzero_integer!(
66+
NonZeroI8,
67+
NonZeroI16,
68+
NonZeroI32,
69+
NonZeroI64,
70+
NonZeroI128,
71+
NonZeroU8,
72+
NonZeroU16,
73+
NonZeroU32,
74+
NonZeroU64,
75+
NonZeroU128
76+
);
77+
4578
#[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
4679
impl CtEq for isize {
4780
#[cfg(target_pointer_width = "32")]

ctutils/src/traits/ct_gt.rs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
use crate::Choice;
2-
use core::cmp;
2+
use core::{
3+
cmp,
4+
num::{NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128},
5+
};
36

47
/// Constant time greater than.
58
pub trait CtGt {
@@ -24,6 +27,22 @@ macro_rules! impl_unsigned_ct_gt {
2427

2528
impl_unsigned_ct_gt!(u8, u16, u32, u64, u128);
2629

30+
/// Impl `CtGt` for `NonZero<T>` by calling `NonZero::get`.
31+
macro_rules! impl_ct_gt_for_nonzero_integer {
32+
( $($ty:ty),+ ) => {
33+
$(
34+
impl CtGt for $ty {
35+
#[inline]
36+
fn ct_gt(&self, other: &Self) -> Choice {
37+
self.get().ct_gt(&other.get())
38+
}
39+
}
40+
)+
41+
};
42+
}
43+
44+
impl_ct_gt_for_nonzero_integer!(NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128);
45+
2746
impl CtGt for cmp::Ordering {
2847
#[inline]
2948
fn ct_gt(&self, other: &Self) -> Choice {

ctutils/src/traits/ct_lt.rs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
use crate::Choice;
2-
use core::cmp;
2+
use core::{
3+
cmp,
4+
num::{NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128},
5+
};
36

47
/// Constant time less than.
58
pub trait CtLt {
@@ -24,6 +27,22 @@ macro_rules! impl_unsigned_ct_lt {
2427

2528
impl_unsigned_ct_lt!(u8, u16, u32, u64, u128);
2629

30+
/// Impl `CtLt` for `NonZero<T>` by calling `NonZero::get`.
31+
macro_rules! impl_ct_lt_for_nonzero_integer {
32+
( $($ty:ty),+ ) => {
33+
$(
34+
impl CtLt for $ty {
35+
#[inline]
36+
fn ct_lt(&self, other: &Self) -> Choice {
37+
self.get().ct_lt(&other.get())
38+
}
39+
}
40+
)+
41+
};
42+
}
43+
44+
impl_ct_lt_for_nonzero_integer!(NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128);
45+
2746
impl CtLt for cmp::Ordering {
2847
#[inline]
2948
fn ct_lt(&self, other: &Self) -> Choice {

ctutils/src/traits/ct_neg.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
use crate::{Choice, CtAssign, CtSelect};
2+
use core::num::{
3+
NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI128, NonZeroU8, NonZeroU16, NonZeroU32,
4+
NonZeroU64, NonZeroU128,
5+
};
26

37
/// Constant-time conditional negation: negates a value when `choice` is [`Choice::TRUE`].
48
pub trait CtNeg: Sized {
@@ -58,6 +62,42 @@ macro_rules! impl_unsigned_ct_neg {
5862
impl_signed_ct_neg!(i8, i16, i32, i64, i128);
5963
impl_unsigned_ct_neg!(u8, u16, u32, u64, u128);
6064

65+
/// Impl `CtNeg` for `NonZero<T>` by calling the `CtNeg` impl for `T`.
66+
macro_rules! impl_ct_neg_for_nonzero_integer {
67+
( $($nzint:ident),+ ) => {
68+
$(
69+
impl CtNeg for $nzint {
70+
#[inline]
71+
fn ct_neg(&self, choice: Choice) -> Self {
72+
let n = self.get().ct_neg(choice);
73+
74+
// SAFETY: we are constructing `NonZero` from a value we obtained from
75+
// `NonZero::get`, which ensures it's non-zero, and the negation of a non-zero
76+
// integer will always be non-zero:
77+
//
78+
// - signed: `{i*}::MIN` and `{i*}::MAX` are each other's negations
79+
// - unsigned: `1` and `{u*}::MAX` are each other's negations
80+
#[allow(unsafe_code)]
81+
unsafe { $nzint::new_unchecked(n) }
82+
}
83+
}
84+
)+
85+
};
86+
}
87+
88+
impl_ct_neg_for_nonzero_integer!(
89+
NonZeroI8,
90+
NonZeroI16,
91+
NonZeroI32,
92+
NonZeroI64,
93+
NonZeroI128,
94+
NonZeroU8,
95+
NonZeroU16,
96+
NonZeroU32,
97+
NonZeroU64,
98+
NonZeroU128
99+
);
100+
61101
#[cfg(test)]
62102
mod tests {
63103
/// Test `CtNeg` impl on `i*`

ctutils/src/traits/ct_select.rs

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
use crate::{Choice, CtAssign};
2-
use core::cmp;
2+
use core::{
3+
cmp,
4+
num::{
5+
NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI128, NonZeroU8, NonZeroU16,
6+
NonZeroU32, NonZeroU64, NonZeroU128,
7+
},
8+
};
39

410
#[cfg(feature = "subtle")]
511
use crate::CtOption;
@@ -47,6 +53,38 @@ macro_rules! impl_ct_select_with_ct_assign {
4753

4854
impl_ct_select_with_ct_assign!(i8, i16, i32, i64, i128, u8, u16, u32, u64, u128);
4955

56+
/// Impl `CtSelect` for `NonZero<T>` by calling the `CtSelect` impl for `T`.
57+
macro_rules! impl_ct_select_for_nonzero_integer {
58+
( $($nzint:ident),+ ) => {
59+
$(
60+
impl CtSelect for $nzint {
61+
#[inline]
62+
fn ct_select(&self, rhs: &Self, choice: Choice) -> Self {
63+
let n = self.get().ct_select(&rhs.get(), choice);
64+
65+
// SAFETY: we are constructing `NonZero` from a value we obtained from
66+
// `NonZero::get`, which ensures it's non-zero.
67+
#[allow(unsafe_code)]
68+
unsafe { $nzint::new_unchecked(n) }
69+
}
70+
}
71+
)+
72+
};
73+
}
74+
75+
impl_ct_select_for_nonzero_integer!(
76+
NonZeroI8,
77+
NonZeroI16,
78+
NonZeroI32,
79+
NonZeroI64,
80+
NonZeroI128,
81+
NonZeroU8,
82+
NonZeroU16,
83+
NonZeroU32,
84+
NonZeroU64,
85+
NonZeroU128
86+
);
87+
5088
#[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
5189
impl CtSelect for isize {
5290
#[cfg(target_pointer_width = "32")]

0 commit comments

Comments
 (0)