1use crate::{CheckedAdd, CheckedDiv, CheckedMul, CheckedSub};
4use core::ops::{Add, Div, Mul, Sub};
5use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
6
7#[cfg(feature = "serde")]
8use serdect::serde::{Deserialize, Deserializer, Serialize, Serializer};
9
10#[derive(Copy, Clone, Debug)]
15pub struct Checked<T>(pub CtOption<T>);
16
17impl<T> Checked<T> {
18 pub fn new(val: T) -> Self {
20 Self(CtOption::new(val, Choice::from(1)))
21 }
22}
23
24impl<T> Add<Self> for Checked<T>
25where
26 T: CheckedAdd + ConditionallySelectable + Default,
27{
28 type Output = Checked<T>;
29
30 #[inline]
31 fn add(self, rhs: Self) -> Self::Output {
32 Checked(
33 self.0
34 .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_add(&rhs))),
35 )
36 }
37}
38
39impl<T> Add<&Self> for Checked<T>
40where
41 T: CheckedAdd + ConditionallySelectable + Default,
42{
43 type Output = Checked<T>;
44
45 #[inline]
46 fn add(self, rhs: &Self) -> Self::Output {
47 Checked(
48 self.0
49 .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_add(&rhs))),
50 )
51 }
52}
53
54impl<T> Add<Checked<T>> for &Checked<T>
55where
56 T: CheckedAdd + ConditionallySelectable + Default,
57{
58 type Output = Checked<T>;
59
60 #[inline]
61 fn add(self, rhs: Checked<T>) -> Self::Output {
62 Checked(
63 self.0
64 .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_add(&rhs))),
65 )
66 }
67}
68
69impl<T> Add<&Checked<T>> for &Checked<T>
70where
71 T: CheckedAdd + ConditionallySelectable + Default,
72{
73 type Output = Checked<T>;
74
75 #[inline]
76 fn add(self, rhs: &Checked<T>) -> Self::Output {
77 Checked(
78 self.0
79 .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_add(&rhs))),
80 )
81 }
82}
83
84impl<T> Sub<Self> for Checked<T>
85where
86 T: CheckedSub + ConditionallySelectable + Default,
87{
88 type Output = Checked<T>;
89
90 #[inline]
91 fn sub(self, rhs: Self) -> Self::Output {
92 Checked(
93 self.0
94 .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_sub(&rhs))),
95 )
96 }
97}
98
99impl<T> Sub<&Self> for Checked<T>
100where
101 T: CheckedSub + ConditionallySelectable + Default,
102{
103 type Output = Checked<T>;
104
105 #[inline]
106 fn sub(self, rhs: &Self) -> Self::Output {
107 Checked(
108 self.0
109 .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_sub(&rhs))),
110 )
111 }
112}
113
114impl<T> Sub<Checked<T>> for &Checked<T>
115where
116 T: CheckedSub + ConditionallySelectable + Default,
117{
118 type Output = Checked<T>;
119
120 #[inline]
121 fn sub(self, rhs: Checked<T>) -> Self::Output {
122 Checked(
123 self.0
124 .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_sub(&rhs))),
125 )
126 }
127}
128
129impl<T> Sub<&Checked<T>> for &Checked<T>
130where
131 T: CheckedSub + ConditionallySelectable + Default,
132{
133 type Output = Checked<T>;
134
135 #[inline]
136 fn sub(self, rhs: &Checked<T>) -> Self::Output {
137 Checked(
138 self.0
139 .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_sub(&rhs))),
140 )
141 }
142}
143
144impl<T> Mul<Self> for Checked<T>
145where
146 T: CheckedMul + ConditionallySelectable + Default,
147{
148 type Output = Checked<T>;
149
150 #[inline]
151 fn mul(self, rhs: Self) -> Self::Output {
152 Checked(
153 self.0
154 .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_mul(&rhs))),
155 )
156 }
157}
158
159impl<T> Mul<&Self> for Checked<T>
160where
161 T: CheckedMul + ConditionallySelectable + Default,
162{
163 type Output = Checked<T>;
164
165 #[inline]
166 fn mul(self, rhs: &Self) -> Self::Output {
167 Checked(
168 self.0
169 .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_mul(&rhs))),
170 )
171 }
172}
173
174impl<T> Mul<Checked<T>> for &Checked<T>
175where
176 T: CheckedMul + ConditionallySelectable + Default,
177{
178 type Output = Checked<T>;
179
180 #[inline]
181 fn mul(self, rhs: Checked<T>) -> Self::Output {
182 Checked(
183 self.0
184 .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_mul(&rhs))),
185 )
186 }
187}
188
189impl<T> Mul<&Checked<T>> for &Checked<T>
190where
191 T: CheckedMul + ConditionallySelectable + Default,
192{
193 type Output = Checked<T>;
194
195 #[inline]
196 fn mul(self, rhs: &Checked<T>) -> Self::Output {
197 Checked(
198 self.0
199 .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_mul(&rhs))),
200 )
201 }
202}
203
204impl<T> Div<Self> for Checked<T>
205where
206 T: CheckedDiv + ConditionallySelectable + Default,
207{
208 type Output = Checked<T>;
209
210 #[inline]
211 fn div(self, rhs: Self) -> Self::Output {
212 Checked(
213 self.0
214 .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_div(&rhs))),
215 )
216 }
217}
218
219impl<T> Div<&Self> for Checked<T>
220where
221 T: CheckedDiv + ConditionallySelectable + Default,
222{
223 type Output = Checked<T>;
224
225 #[inline]
226 fn div(self, rhs: &Self) -> Self::Output {
227 Checked(
228 self.0
229 .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_div(&rhs))),
230 )
231 }
232}
233
234impl<T> Div<Checked<T>> for &Checked<T>
235where
236 T: CheckedDiv + ConditionallySelectable + Default,
237{
238 type Output = Checked<T>;
239
240 #[inline]
241 fn div(self, rhs: Checked<T>) -> Self::Output {
242 Checked(
243 self.0
244 .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_div(&rhs))),
245 )
246 }
247}
248
249impl<T> Div<&Checked<T>> for &Checked<T>
250where
251 T: CheckedDiv + ConditionallySelectable + Default,
252{
253 type Output = Checked<T>;
254
255 #[inline]
256 fn div(self, rhs: &Checked<T>) -> Self::Output {
257 Checked(
258 self.0
259 .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_div(&rhs))),
260 )
261 }
262}
263
264impl<T: ConditionallySelectable> ConditionallySelectable for Checked<T> {
265 #[inline]
266 fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
267 Self(CtOption::conditional_select(&a.0, &b.0, choice))
268 }
269}
270
271impl<T: ConstantTimeEq> ConstantTimeEq for Checked<T> {
272 #[inline]
273 fn ct_eq(&self, rhs: &Self) -> Choice {
274 self.0.ct_eq(&rhs.0)
275 }
276}
277
278impl<T> Default for Checked<T>
279where
280 T: Default,
281{
282 fn default() -> Self {
283 Self::new(T::default())
284 }
285}
286
287impl<T> From<Checked<T>> for CtOption<T> {
288 fn from(checked: Checked<T>) -> CtOption<T> {
289 checked.0
290 }
291}
292
293impl<T> From<CtOption<T>> for Checked<T> {
294 fn from(ct_option: CtOption<T>) -> Checked<T> {
295 Checked(ct_option)
296 }
297}
298
299impl<T> From<Checked<T>> for Option<T> {
300 fn from(checked: Checked<T>) -> Option<T> {
301 checked.0.into()
302 }
303}
304
305#[cfg(feature = "serde")]
306impl<'de, T: Default + Deserialize<'de>> Deserialize<'de> for Checked<T> {
307 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
308 where
309 D: Deserializer<'de>,
310 {
311 let value = Option::<T>::deserialize(deserializer)?;
312 let choice = Choice::from(value.is_some() as u8);
313 Ok(Self(CtOption::new(value.unwrap_or_default(), choice)))
314 }
315}
316
317#[cfg(feature = "serde")]
318impl<T: Copy + Serialize> Serialize for Checked<T> {
319 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
320 where
321 S: Serializer,
322 {
323 Option::<T>::from(self.0).serialize(serializer)
324 }
325}
326
327#[cfg(all(test, feature = "serde"))]
328#[allow(clippy::unwrap_used)]
329mod tests {
330
331 use crate::{Checked, U64};
332 use subtle::{Choice, ConstantTimeEq, CtOption};
333
334 #[test]
335 fn serde() {
336 let test = Checked::new(U64::from_u64(0x0011223344556677));
337
338 let serialized = bincode::serialize(&test).unwrap();
339 let deserialized: Checked<U64> = bincode::deserialize(&serialized).unwrap();
340
341 assert!(bool::from(test.ct_eq(&deserialized)));
342
343 let test = Checked::new(U64::ZERO) - Checked::new(U64::ONE);
344 assert!(bool::from(
345 test.ct_eq(&Checked(CtOption::new(U64::ZERO, Choice::from(0))))
346 ));
347
348 let serialized = bincode::serialize(&test).unwrap();
349 let deserialized: Checked<U64> = bincode::deserialize(&serialized).unwrap();
350
351 assert!(bool::from(test.ct_eq(&deserialized)));
352 }
353
354 #[test]
355 fn serde_owned() {
356 let test = Checked::new(U64::from_u64(0x0011223344556677));
357
358 let serialized = bincode::serialize(&test).unwrap();
359 let deserialized: Checked<U64> = bincode::deserialize_from(serialized.as_slice()).unwrap();
360
361 assert!(bool::from(test.ct_eq(&deserialized)));
362
363 let test = Checked::new(U64::ZERO) - Checked::new(U64::ONE);
364 assert!(bool::from(
365 test.ct_eq(&Checked(CtOption::new(U64::ZERO, Choice::from(0))))
366 ));
367
368 let serialized = bincode::serialize(&test).unwrap();
369 let deserialized: Checked<U64> = bincode::deserialize_from(serialized.as_slice()).unwrap();
370
371 assert!(bool::from(test.ct_eq(&deserialized)));
372 }
373}