1use crate::{CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, Choice, CtEq, CtOption, CtSelect};
4use core::ops::{Add, Div, Mul, Sub};
5
6#[cfg(feature = "serde")]
7use serdect::serde::{Deserialize, Deserializer, Serialize, Serializer};
8
9#[derive(Copy, Clone, Debug)]
14pub struct Checked<T>(pub CtOption<T>);
15
16impl<T> Checked<T> {
17 pub const fn new(val: T) -> Self {
19 Self(CtOption::some(val))
20 }
21
22 #[cfg(test)]
24 pub(crate) fn none() -> Self
25 where
26 T: Default,
27 {
28 Self(CtOption::none())
29 }
30}
31
32impl<T> Add<Self> for Checked<T>
33where
34 T: CheckedAdd + CtSelect + Default,
35{
36 type Output = Checked<T>;
37
38 #[inline]
39 fn add(self, rhs: Self) -> Self::Output {
40 Checked(
41 self.0
42 .as_ref()
43 .and_then(|lhs| rhs.0.as_ref().and_then(|rhs| lhs.checked_add(rhs))),
44 )
45 }
46}
47
48impl<T> Add<&Self> for Checked<T>
49where
50 T: CheckedAdd + CtSelect + Default,
51{
52 type Output = Checked<T>;
53
54 #[inline]
55 fn add(self, rhs: &Self) -> Self::Output {
56 Checked(
57 self.0
58 .as_ref()
59 .and_then(|lhs| rhs.0.as_ref().and_then(|rhs| lhs.checked_add(rhs))),
60 )
61 }
62}
63
64impl<T> Add<Checked<T>> for &Checked<T>
65where
66 T: CheckedAdd + CtSelect + Default,
67{
68 type Output = Checked<T>;
69
70 #[inline]
71 fn add(self, rhs: Checked<T>) -> Self::Output {
72 Checked(
73 self.0
74 .as_ref()
75 .and_then(|lhs| rhs.0.as_ref().and_then(|rhs| lhs.checked_add(rhs))),
76 )
77 }
78}
79
80impl<T> Add<&Checked<T>> for &Checked<T>
81where
82 T: CheckedAdd + CtSelect + Default,
83{
84 type Output = Checked<T>;
85
86 #[inline]
87 fn add(self, rhs: &Checked<T>) -> Self::Output {
88 Checked(
89 self.0
90 .as_ref()
91 .and_then(|lhs| rhs.0.as_ref().and_then(|rhs| lhs.checked_add(rhs))),
92 )
93 }
94}
95
96impl<T> Sub<Self> for Checked<T>
97where
98 T: CheckedSub + CtSelect + Default,
99{
100 type Output = Checked<T>;
101
102 #[inline]
103 fn sub(self, rhs: Self) -> Self::Output {
104 Checked(
105 self.0
106 .as_ref()
107 .and_then(|lhs| rhs.0.as_ref().and_then(|rhs| lhs.checked_sub(rhs))),
108 )
109 }
110}
111
112impl<T> Sub<&Self> for Checked<T>
113where
114 T: CheckedSub + CtSelect + Default,
115{
116 type Output = Checked<T>;
117
118 #[inline]
119 fn sub(self, rhs: &Self) -> Self::Output {
120 Checked(
121 self.0
122 .as_ref()
123 .and_then(|lhs| rhs.0.as_ref().and_then(|rhs| lhs.checked_sub(rhs))),
124 )
125 }
126}
127
128impl<T> Sub<Checked<T>> for &Checked<T>
129where
130 T: CheckedSub + CtSelect + Default,
131{
132 type Output = Checked<T>;
133
134 #[inline]
135 fn sub(self, rhs: Checked<T>) -> Self::Output {
136 Checked(
137 self.0
138 .as_ref()
139 .and_then(|lhs| rhs.0.as_ref().and_then(|rhs| lhs.checked_sub(rhs))),
140 )
141 }
142}
143
144impl<T> Sub<&Checked<T>> for &Checked<T>
145where
146 T: CheckedSub + CtSelect + Default,
147{
148 type Output = Checked<T>;
149
150 #[inline]
151 fn sub(self, rhs: &Checked<T>) -> Self::Output {
152 Checked(
153 self.0
154 .as_ref()
155 .and_then(|lhs| rhs.0.as_ref().and_then(|rhs| lhs.checked_sub(rhs))),
156 )
157 }
158}
159
160impl<T> Mul<Self> for Checked<T>
161where
162 T: CheckedMul + CtSelect + Default,
163{
164 type Output = Checked<T>;
165
166 #[inline]
167 fn mul(self, rhs: Self) -> Self::Output {
168 Checked(
169 self.0
170 .as_ref()
171 .and_then(|lhs| rhs.0.as_ref().and_then(|rhs| lhs.checked_mul(rhs))),
172 )
173 }
174}
175
176impl<T> Mul<&Self> for Checked<T>
177where
178 T: CheckedMul + CtSelect + Default,
179{
180 type Output = Checked<T>;
181
182 #[inline]
183 fn mul(self, rhs: &Self) -> Self::Output {
184 Checked(
185 self.0
186 .as_ref()
187 .and_then(|lhs| rhs.0.as_ref().and_then(|rhs| lhs.checked_mul(rhs))),
188 )
189 }
190}
191
192impl<T> Mul<Checked<T>> for &Checked<T>
193where
194 T: CheckedMul + CtSelect + Default,
195{
196 type Output = Checked<T>;
197
198 #[inline]
199 fn mul(self, rhs: Checked<T>) -> Self::Output {
200 Checked(
201 self.0
202 .as_ref()
203 .and_then(|lhs| rhs.0.as_ref().and_then(|rhs| lhs.checked_mul(rhs))),
204 )
205 }
206}
207
208impl<T> Mul<&Checked<T>> for &Checked<T>
209where
210 T: CheckedMul + CtSelect + Default,
211{
212 type Output = Checked<T>;
213
214 #[inline]
215 fn mul(self, rhs: &Checked<T>) -> Self::Output {
216 Checked(
217 self.0
218 .as_ref()
219 .and_then(|lhs| rhs.0.as_ref().and_then(|rhs| lhs.checked_mul(rhs))),
220 )
221 }
222}
223
224impl<T> Div<Self> for Checked<T>
225where
226 T: CheckedDiv + CtSelect + Default,
227{
228 type Output = Checked<T>;
229
230 #[inline]
231 fn div(self, rhs: Self) -> Self::Output {
232 Checked(
233 self.0
234 .as_ref()
235 .and_then(|lhs| rhs.0.as_ref().and_then(|rhs| lhs.checked_div(rhs))),
236 )
237 }
238}
239
240impl<T> Div<&Self> for Checked<T>
241where
242 T: CheckedDiv + CtSelect + Default,
243{
244 type Output = Checked<T>;
245
246 #[inline]
247 fn div(self, rhs: &Self) -> Self::Output {
248 Checked(
249 self.0
250 .as_ref()
251 .and_then(|lhs| rhs.0.as_ref().and_then(|rhs| lhs.checked_div(rhs))),
252 )
253 }
254}
255
256impl<T> Div<Checked<T>> for &Checked<T>
257where
258 T: CheckedDiv + CtSelect + Default,
259{
260 type Output = Checked<T>;
261
262 #[inline]
263 fn div(self, rhs: Checked<T>) -> Self::Output {
264 Checked(
265 self.0
266 .as_ref()
267 .and_then(|lhs| rhs.0.as_ref().and_then(|rhs| lhs.checked_div(rhs))),
268 )
269 }
270}
271
272impl<T> Div<&Checked<T>> for &Checked<T>
273where
274 T: CheckedDiv + CtSelect + Default,
275{
276 type Output = Checked<T>;
277
278 #[inline]
279 fn div(self, rhs: &Checked<T>) -> Self::Output {
280 Checked(
281 self.0
282 .as_ref()
283 .and_then(|lhs| rhs.0.as_ref().and_then(|rhs| lhs.checked_div(rhs))),
284 )
285 }
286}
287
288impl<T> CtEq for Checked<T>
289where
290 T: CtEq,
291{
292 #[inline]
293 fn ct_eq(&self, other: &Self) -> Choice {
294 self.0.ct_eq(&other.0)
295 }
296}
297
298impl<T> CtSelect for Checked<T>
299where
300 T: CtSelect,
301{
302 #[inline]
303 fn ct_select(&self, other: &Self, choice: Choice) -> Self {
304 Self(self.0.ct_select(&other.0, choice))
305 }
306}
307
308impl<T> Default for Checked<T>
309where
310 T: Default,
311{
312 fn default() -> Self {
313 Self::new(T::default())
314 }
315}
316
317impl<T> From<Checked<T>> for CtOption<T> {
318 fn from(checked: Checked<T>) -> CtOption<T> {
319 checked.0
320 }
321}
322
323impl<T> From<CtOption<T>> for Checked<T> {
324 fn from(ct_option: CtOption<T>) -> Checked<T> {
325 Checked(ct_option)
326 }
327}
328
329impl<T> From<Checked<T>> for Option<T> {
330 fn from(checked: Checked<T>) -> Option<T> {
331 checked.0.into()
332 }
333}
334
335#[cfg(feature = "serde")]
336impl<'de, T: Default + Deserialize<'de>> Deserialize<'de> for Checked<T> {
337 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
338 where
339 D: Deserializer<'de>,
340 {
341 let value = Option::<T>::deserialize(deserializer)?;
342 let choice = Choice::from_u8_lsb(value.is_some().into());
343 Ok(Self(CtOption::new(value.unwrap_or_default(), choice)))
344 }
345}
346
347#[cfg(feature = "serde")]
348impl<T: Copy + Serialize> Serialize for Checked<T> {
349 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
350 where
351 S: Serializer,
352 {
353 self.0.into_option().serialize(serializer)
354 }
355}
356
357#[cfg(feature = "subtle")]
358impl<T> subtle::ConditionallySelectable for Checked<T>
359where
360 T: Copy,
361 Self: CtSelect,
362{
363 #[inline]
364 fn conditional_select(a: &Self, b: &Self, choice: subtle::Choice) -> Self {
365 a.ct_select(b, choice.into())
366 }
367}
368
369#[cfg(feature = "subtle")]
370impl<T> subtle::ConstantTimeEq for Checked<T>
371where
372 Self: CtEq,
373{
374 #[inline]
375 fn ct_eq(&self, rhs: &Self) -> subtle::Choice {
376 CtEq::ct_eq(self, rhs).into()
377 }
378}
379
380#[cfg(test)]
381mod tests {
382 use super::Checked;
383 use crate::{
384 CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, Choice, CtEq, CtOption, CtSelect, Limb,
385 };
386
387 const INPUTS: &[(Limb, Limb)] = &[
389 (Limb::ZERO, Limb::ZERO),
390 (Limb::ZERO, Limb::ONE),
391 (Limb::ZERO, Limb::MAX),
392 (Limb::ONE, Limb::ZERO),
393 (Limb::ONE, Limb::ONE),
394 (Limb::ONE, Limb::MAX),
395 (Limb::MAX, Limb::ZERO),
396 (Limb::MAX, Limb::ONE),
397 (Limb::MAX, Limb::MAX),
398 ];
399
400 #[test]
401 fn checked_new() {
402 assert_eq!(
403 Checked::<Limb>::default().0.into_option(),
404 Some(Limb::default())
405 );
406 for (a, _b) in INPUTS {
407 assert_eq!(Checked::<Limb>::new(*a).0.into_option(), Some(*a));
408 }
409 }
410
411 #[test]
412 fn checked_eq_select() {
413 let pairs: &[(Checked<Limb>, Checked<Limb>, bool)] = &[
414 (Checked::none(), Checked::none(), true),
415 (Checked::none(), Checked::new(Limb::ZERO), false),
416 (Checked::new(Limb::ZERO), Checked::none(), false),
417 (Checked::new(Limb::ZERO), Checked::new(Limb::ZERO), true),
418 (Checked::new(Limb::ZERO), Checked::new(Limb::ONE), false),
419 ];
420
421 for (a, b, eq) in pairs {
422 assert_eq!(a.ct_eq(b).to_bool(), *eq);
423 assert!(a.ct_select(b, Choice::FALSE).ct_eq(a).to_bool());
424 assert!(a.ct_select(b, Choice::TRUE).ct_eq(b).to_bool());
425 #[cfg(feature = "subtle")]
426 assert_eq!(bool::from(subtle::ConstantTimeEq::ct_eq(a, b)), *eq);
427 #[cfg(feature = "subtle")]
428 assert!(
429 subtle::ConditionallySelectable::conditional_select(
430 a,
431 b,
432 subtle::Choice::from(0u8)
433 )
434 .ct_eq(a)
435 .to_bool()
436 );
437 #[cfg(feature = "subtle")]
438 assert!(
439 subtle::ConditionallySelectable::conditional_select(
440 a,
441 b,
442 subtle::Choice::from(1u8)
443 )
444 .ct_eq(b)
445 .to_bool()
446 );
447 }
448 }
449
450 #[test]
451 fn checked_from() {
452 assert_eq!(Checked::<Limb>(CtOption::none()).0.into_option(), None);
453 assert_eq!(
454 Checked::<Limb>::default().0.into_option(),
455 Checked::<Limb>::from(CtOption::<Limb>::some(Limb::default()))
456 .0
457 .into_option(),
458 );
459 assert_eq!(
460 Checked::<Limb>::default().0.into_option(),
461 Into::<Option<Limb>>::into(Checked::<Limb>::default())
462 );
463 assert_eq!(
464 Checked::<Limb>::default().0.into_option(),
465 Into::<CtOption<Limb>>::into(Checked::<Limb>::default()).into_option()
466 );
467 }
468
469 #[allow(clippy::op_ref)]
470 #[test]
471 fn checked_add() {
472 for (a, b) in INPUTS {
473 let expect = a.checked_add(b).into_option();
474 assert_eq!(
475 (Checked::new(*a) + Checked::new(*b)).0.into_option(),
476 expect
477 );
478 assert_eq!(
479 (&Checked::new(*a) + Checked::new(*b)).0.into_option(),
480 expect
481 );
482 assert_eq!(
483 (Checked::new(*a) + &Checked::new(*b)).0.into_option(),
484 expect
485 );
486 assert_eq!(
487 (&Checked::new(*a) + &Checked::new(*b)).0.into_option(),
488 expect
489 );
490 }
491 }
492
493 #[allow(clippy::op_ref)]
494 #[test]
495 fn checked_sub() {
496 for (a, b) in INPUTS {
497 let expect = a.checked_sub(b).into_option();
498 assert_eq!(
499 (Checked::new(*a) - Checked::new(*b)).0.into_option(),
500 expect
501 );
502 assert_eq!(
503 (&Checked::new(*a) - Checked::new(*b)).0.into_option(),
504 expect
505 );
506 assert_eq!(
507 (Checked::new(*a) - &Checked::new(*b)).0.into_option(),
508 expect
509 );
510 assert_eq!(
511 (&Checked::new(*a) - &Checked::new(*b)).0.into_option(),
512 expect
513 );
514 }
515 }
516
517 #[allow(clippy::op_ref)]
518 #[test]
519 fn checked_mul() {
520 for (a, b) in INPUTS {
521 let expect = a.checked_mul(b).into_option();
522 assert_eq!(
523 (Checked::new(*a) * Checked::new(*b)).0.into_option(),
524 expect
525 );
526 assert_eq!(
527 (&Checked::new(*a) * Checked::new(*b)).0.into_option(),
528 expect
529 );
530 assert_eq!(
531 (Checked::new(*a) * &Checked::new(*b)).0.into_option(),
532 expect
533 );
534 assert_eq!(
535 (&Checked::new(*a) * &Checked::new(*b)).0.into_option(),
536 expect
537 );
538 }
539 }
540
541 #[allow(clippy::op_ref)]
542 #[test]
543 fn checked_div() {
544 for (a, b) in INPUTS {
545 let expect = a.checked_div(b).into_option();
546 assert_eq!(
547 (Checked::new(*a) / Checked::new(*b)).0.into_option(),
548 expect
549 );
550 assert_eq!(
551 (&Checked::new(*a) / Checked::new(*b)).0.into_option(),
552 expect
553 );
554 assert_eq!(
555 (Checked::new(*a) / &Checked::new(*b)).0.into_option(),
556 expect
557 );
558 assert_eq!(
559 (&Checked::new(*a) / &Checked::new(*b)).0.into_option(),
560 expect
561 );
562 }
563 }
564}