| 1 | // Copyright 2025 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 crate::{ |
| 16 | error::LenMismatchError, |
| 17 | limb::{Limb, LIMB_BITS}, |
| 18 | polyfill::slice::{self, AsChunksMut}, |
| 19 | }; |
| 20 | use core::mem::{align_of, size_of}; |
| 21 | |
| 22 | // Some x86_64 assembly is written under the assumption that some of its |
| 23 | // input data and/or temporary storage is aligned to `MOD_EXP_CTIME_ALIGN` |
| 24 | // bytes, which was/is 64 in OpenSSL. |
| 25 | // |
| 26 | // We use this in the non-X86-64 implementation of exponentiation as well, |
| 27 | // with the hope of converging th two implementations into one. |
| 28 | |
| 29 | #[repr (C, align(64))] |
| 30 | pub struct AlignedStorage<const N: usize>([Limb; N]); |
| 31 | |
| 32 | const _LIMB_SIZE_DIVIDES_ALIGNMENT: () = |
| 33 | assert!(align_of::<AlignedStorage<1>>() % size_of::<Limb>() == 0); |
| 34 | |
| 35 | pub const LIMBS_PER_CHUNK: usize = 512 / LIMB_BITS; |
| 36 | |
| 37 | impl<const N: usize> AlignedStorage<N> { |
| 38 | pub fn zeroed() -> Self { |
| 39 | assert_eq!(N % LIMBS_PER_CHUNK, 0); // TODO: const. |
| 40 | Self([0; N]) |
| 41 | } |
| 42 | |
| 43 | // The result will have every chunk aligned on a 64 byte boundary. |
| 44 | pub fn aligned_chunks_mut( |
| 45 | &mut self, |
| 46 | num_entries: usize, |
| 47 | chunks_per_entry: usize, |
| 48 | ) -> Result<AsChunksMut<Limb, LIMBS_PER_CHUNK>, LenMismatchError> { |
| 49 | let total_limbs: usize = num_entries * chunks_per_entry * LIMBS_PER_CHUNK; |
| 50 | let len: usize = self.0.len(); |
| 51 | let flattened: &mut [u64] = self |
| 52 | .0 |
| 53 | .get_mut(..total_limbs) |
| 54 | .ok_or_else(|| LenMismatchError::new(len))?; |
| 55 | match slice::as_chunks_mut(slice:flattened) { |
| 56 | (chunks: AsChunksMut<'_, u64, 8>, []) => Ok(chunks), |
| 57 | (_, r: &mut [u64]) => Err(LenMismatchError::new(r.len())), |
| 58 | } |
| 59 | } |
| 60 | } |
| 61 | |