1 //! Checked arithmetic.
3 use subtle
::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}
;
5 #[cfg(feature = "serde")]
6 use serdect
::serde
::{Deserialize, Deserializer, Serialize, Serializer}
;
8 /// Provides intentionally-checked arithmetic on `T`.
10 /// Internally this leverages the [`CtOption`] type from the [`subtle`] crate
11 /// in order to handle overflows in constant time.
12 #[derive(Copy, Clone, Debug)]
13 pub struct Checked
<T
>(pub CtOption
<T
>);
16 /// Create a new checked arithmetic wrapper for the given value.
17 pub fn new(val
: T
) -> Self {
18 Self(CtOption
::new(val
, Choice
::from(1)))
22 impl<T
> Default
for Checked
<T
>
26 fn default() -> Self {
27 Self::new(T
::default())
31 impl<T
: ConditionallySelectable
> ConditionallySelectable
for Checked
<T
> {
33 fn conditional_select(a
: &Self, b
: &Self, choice
: Choice
) -> Self {
34 Self(CtOption
::conditional_select(&a
.0, &b
.0, choice
))
38 impl<T
: ConstantTimeEq
> ConstantTimeEq
for Checked
<T
> {
40 fn ct_eq(&self, rhs
: &Self) -> Choice
{
45 impl<T
> From
<Checked
<T
>> for CtOption
<T
> {
46 fn from(checked
: Checked
<T
>) -> CtOption
<T
> {
51 impl<T
> From
<CtOption
<T
>> for Checked
<T
> {
52 fn from(ct_option
: CtOption
<T
>) -> Checked
<T
> {
57 impl<T
> From
<Checked
<T
>> for Option
<T
> {
58 fn from(checked
: Checked
<T
>) -> Option
<T
> {
63 #[cfg(feature = "serde")]
64 #[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
65 impl<'de
, T
: Default
+ Deserialize
<'de
>> Deserialize
<'de
> for Checked
<T
> {
66 fn deserialize
<D
>(deserializer
: D
) -> Result
<Self, D
::Error
>
70 let value
= Option
::<T
>::deserialize(deserializer
)?
;
71 let choice
= Choice
::from(value
.is_some() as u8);
72 Ok(Self(CtOption
::new(value
.unwrap_or_default(), choice
)))
76 #[cfg(feature = "serde")]
77 #[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
78 impl<'de
, T
: Copy
+ Serialize
> Serialize
for Checked
<T
> {
79 fn serialize
<S
>(&self, serializer
: S
) -> Result
<S
::Ok
, S
::Error
>
83 Option
::<T
>::from(self.0).serialize(serializer
)
87 #[cfg(all(test, feature = "serde"))]
89 use crate::{Checked, U64}
;
90 use subtle
::{Choice, ConstantTimeEq, CtOption}
;
94 let test
= Checked
::new(U64
::from_u64(0x0011223344556677));
96 let serialized
= bincode
::serialize(&test
).unwrap();
97 let deserialized
: Checked
<U64
> = bincode
::deserialize(&serialized
).unwrap();
99 assert
!(bool
::from(test
.ct_eq(&deserialized
)));
101 let test
= Checked
::new(U64
::ZERO
) - Checked
::new(U64
::ONE
);
103 test
.ct_eq(&Checked(CtOption
::new(U64
::ZERO
, Choice
::from(0))))
106 let serialized
= bincode
::serialize(&test
).unwrap();
107 let deserialized
: Checked
<U64
> = bincode
::deserialize(&serialized
).unwrap();
109 assert
!(bool
::from(test
.ct_eq(&deserialized
)));
114 let test
= Checked
::new(U64
::from_u64(0x0011223344556677));
116 let serialized
= bincode
::serialize(&test
).unwrap();
117 let deserialized
: Checked
<U64
> = bincode
::deserialize_from(serialized
.as_slice()).unwrap();
119 assert
!(bool
::from(test
.ct_eq(&deserialized
)));
121 let test
= Checked
::new(U64
::ZERO
) - Checked
::new(U64
::ONE
);
123 test
.ct_eq(&Checked(CtOption
::new(U64
::ZERO
, Choice
::from(0))))
126 let serialized
= bincode
::serialize(&test
).unwrap();
127 let deserialized
: Checked
<U64
> = bincode
::deserialize_from(serialized
.as_slice()).unwrap();
129 assert
!(bool
::from(test
.ct_eq(&deserialized
)));