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, Width}; 16 use crate::{ 17 error, 18 limb::{self, Limb, LimbMask, LIMB_BYTES}, 19 }; 20 use alloc::{borrow::ToOwned, 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] deref(&self) -> &Self::Target37 fn deref(&self) -> &Self::Target { 38 &self.limbs 39 } 40 } 41 42 impl<M> DerefMut for BoxedLimbs<M> { 43 #[inline] deref_mut(&mut self) -> &mut Self::Target44 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> { clone(&self) -> Self52 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. new_unchecked(limbs: Box<[Limb]>) -> Self63 pub(super) fn new_unchecked(limbs: Box<[Limb]>) -> Self { 64 Self { 65 limbs, 66 m: PhantomData, 67 } 68 } 69 positive_minimal_width_from_be_bytes( input: untrusted::Input, ) -> Result<Self, error::KeyRejected>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(Width { 80 num_limbs, 81 m: PhantomData, 82 }); 83 limb::parse_big_endian_and_pad_consttime(input, &mut r) 84 .map_err(|error::Unspecified| error::KeyRejected::unexpected_error())?; 85 Ok(r) 86 } 87 minimal_width_from_unpadded(limbs: &[Limb]) -> Self88 pub(super) fn minimal_width_from_unpadded(limbs: &[Limb]) -> Self { 89 debug_assert_ne!(limbs.last(), Some(&0)); 90 Self { 91 limbs: limbs.to_owned().into_boxed_slice(), 92 m: PhantomData, 93 } 94 } 95 from_be_bytes_padded_less_than( input: untrusted::Input, m: &Modulus<M>, ) -> Result<Self, error::Unspecified>96 pub(super) fn from_be_bytes_padded_less_than( 97 input: untrusted::Input, 98 m: &Modulus<M>, 99 ) -> Result<Self, error::Unspecified> { 100 let mut r = Self::zero(m.width()); 101 limb::parse_big_endian_and_pad_consttime(input, &mut r)?; 102 if limb::limbs_less_than_limbs_consttime(&r, m.limbs()) != LimbMask::True { 103 return Err(error::Unspecified); 104 } 105 Ok(r) 106 } 107 108 #[inline] is_zero(&self) -> bool109 pub(super) fn is_zero(&self) -> bool { 110 limb::limbs_are_zero_constant_time(&self.limbs) == LimbMask::True 111 } 112 zero(width: Width<M>) -> Self113 pub(super) fn zero(width: Width<M>) -> Self { 114 Self { 115 limbs: vec![0; width.num_limbs].into_boxed_slice(), 116 m: PhantomData, 117 } 118 } 119 width(&self) -> Width<M>120 pub(super) fn width(&self) -> Width<M> { 121 Width { 122 num_limbs: self.limbs.len(), 123 m: PhantomData, 124 } 125 } 126 into_limbs(self) -> Box<[Limb]>127 pub(super) fn into_limbs(self) -> Box<[Limb]> { 128 self.limbs 129 } 130 } 131