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 | |