1 | // Copyright 2015-2023 Brian Smith. |
2 | // |
3 | // Permission to use, copy, modify, and/or distribute this software for any |
4 | // purpose with or without fee is hereby granted, provided that the above |
5 | // copyright notice and this permission notice appear in all copies. |
6 | // |
7 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES |
8 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
9 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY |
10 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
11 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
12 | // OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
13 | // CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
14 | |
15 | use super::Modulus; |
16 | use crate::{ |
17 | error, |
18 | limb::{self, Limb, LimbMask, LIMB_BYTES}, |
19 | }; |
20 | use alloc::{boxed::Box, vec}; |
21 | use core::{ |
22 | marker::PhantomData, |
23 | ops::{Deref, DerefMut}, |
24 | }; |
25 | |
26 | /// All `BoxedLimbs<M>` are stored in the same number of limbs. |
27 | pub(super) struct BoxedLimbs<M> { |
28 | limbs: Box<[Limb]>, |
29 | |
30 | /// The modulus *m* that determines the size of `limbx`. |
31 | m: PhantomData<M>, |
32 | } |
33 | |
34 | impl<M> Deref for BoxedLimbs<M> { |
35 | type Target = [Limb]; |
36 | #[inline ] |
37 | fn deref(&self) -> &Self::Target { |
38 | &self.limbs |
39 | } |
40 | } |
41 | |
42 | impl<M> DerefMut for BoxedLimbs<M> { |
43 | #[inline ] |
44 | fn deref_mut(&mut self) -> &mut Self::Target { |
45 | &mut self.limbs |
46 | } |
47 | } |
48 | |
49 | // TODO: `derive(Clone)` after https://github.com/rust-lang/rust/issues/26925 |
50 | // is resolved or restrict `M: Clone`. |
51 | impl<M> Clone for BoxedLimbs<M> { |
52 | fn clone(&self) -> Self { |
53 | Self { |
54 | limbs: self.limbs.clone(), |
55 | m: self.m, |
56 | } |
57 | } |
58 | } |
59 | |
60 | impl<M> BoxedLimbs<M> { |
61 | // The caller must ensure that `limbs.len()` is the same width as the |
62 | // modulus. |
63 | pub(super) fn new_unchecked(limbs: Box<[Limb]>) -> Self { |
64 | Self { |
65 | limbs, |
66 | m: PhantomData, |
67 | } |
68 | } |
69 | |
70 | pub(super) fn positive_minimal_width_from_be_bytes( |
71 | input: untrusted::Input, |
72 | ) -> Result<Self, error::KeyRejected> { |
73 | // Reject leading zeros. Also reject the value zero ([0]) because zero |
74 | // isn't positive. |
75 | if untrusted::Reader::new(input).peek(0) { |
76 | return Err(error::KeyRejected::invalid_encoding()); |
77 | } |
78 | let num_limbs = (input.len() + LIMB_BYTES - 1) / LIMB_BYTES; |
79 | let mut r = Self::zero(num_limbs); |
80 | limb::parse_big_endian_and_pad_consttime(input, &mut r) |
81 | .map_err(|error::Unspecified| error::KeyRejected::unexpected_error())?; |
82 | Ok(r) |
83 | } |
84 | |
85 | pub(super) fn from_be_bytes_padded_less_than( |
86 | input: untrusted::Input, |
87 | m: &Modulus<M>, |
88 | ) -> Result<Self, error::Unspecified> { |
89 | let mut r = Self::zero(m.limbs().len()); |
90 | limb::parse_big_endian_and_pad_consttime(input, &mut r)?; |
91 | if limb::limbs_less_than_limbs_consttime(&r, m.limbs()) != LimbMask::True { |
92 | return Err(error::Unspecified); |
93 | } |
94 | Ok(r) |
95 | } |
96 | |
97 | #[inline ] |
98 | pub(super) fn is_zero(&self) -> bool { |
99 | limb::limbs_are_zero_constant_time(&self.limbs) == LimbMask::True |
100 | } |
101 | |
102 | pub(super) fn zero(len: usize) -> Self { |
103 | Self { |
104 | limbs: vec![0; len].into_boxed_slice(), |
105 | m: PhantomData, |
106 | } |
107 | } |
108 | |
109 | pub(super) fn into_limbs(self) -> Box<[Limb]> { |
110 | self.limbs |
111 | } |
112 | } |
113 | |