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
15use super::{limb, BoxedLimbs, Limb, LimbMask, Modulus};
16use crate::error;
17use alloc::boxed::Box;
18
19pub struct PrivateExponent {
20 limbs: Box<[Limb]>,
21}
22
23impl PrivateExponent {
24 // `p` is the modulus for which the exponent is in the interval [1, `p` - 1).
25 pub fn from_be_bytes_padded<M>(
26 input: untrusted::Input,
27 p: &Modulus<M>,
28 ) -> Result<Self, error::Unspecified> {
29 let dP = BoxedLimbs::from_be_bytes_padded_less_than(input, p)?;
30
31 // Proof that `dP < p - 1`:
32 //
33 // If `dP < p` then either `dP == p - 1` or `dP < p - 1`. Since `p` is
34 // odd, `p - 1` is even. `d` is odd, and an odd number modulo an even
35 // number is odd. Therefore `dP` must be odd. But then it cannot be
36 // `p - 1` and so we know `dP < p - 1`.
37 //
38 // Further we know `dP != 0` because `dP` is not even.
39 if limb::limbs_are_even_constant_time(&dP) != LimbMask::False {
40 return Err(error::Unspecified);
41 }
42
43 Ok(Self {
44 limbs: dP.into_limbs(),
45 })
46 }
47
48 #[cfg(test)]
49 pub fn from_be_bytes_for_test_only<M>(
50 input: untrusted::Input,
51 p: &Modulus<M>,
52 ) -> Result<Self, error::Unspecified> {
53 // Do exactly what `from_be_bytes_padded` does for any inputs it accepts.
54 if let r @ Ok(_) = Self::from_be_bytes_padded(input, p) {
55 return r;
56 }
57
58 let dP = BoxedLimbs::<M>::positive_minimal_width_from_be_bytes(input)?;
59
60 Ok(Self {
61 limbs: dP.into_limbs(),
62 })
63 }
64
65 #[inline]
66 pub(super) fn limbs(&self) -> &[Limb] {
67 &self.limbs
68 }
69}
70