ring/arithmetic/limbs512/storage.rs
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 AUTHOR DISCLAIMS ALL WARRANTIES
8// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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 crate::{
16 error::LenMismatchError,
17 limb::{Limb, LIMB_BITS},
18 polyfill::slice::{self, AsChunksMut},
19};
20use 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))]
30pub struct AlignedStorage<const N: usize>([Limb; N]);
31
32const _LIMB_SIZE_DIVIDES_ALIGNMENT: () =
33 assert!(align_of::<AlignedStorage<1>>() % size_of::<Limb>() == 0);
34
35pub const LIMBS_PER_CHUNK: usize = 512 / LIMB_BITS;
36
37impl<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 = num_entries * chunks_per_entry * LIMBS_PER_CHUNK;
50 let len = self.0.len();
51 let flattened = self
52 .0
53 .get_mut(..total_limbs)
54 .ok_or_else(|| LenMismatchError::new(len))?;
55 match slice::as_chunks_mut(flattened) {
56 (chunks, []) => Ok(chunks),
57 (_, r) => Err(LenMismatchError::new(r.len())),
58 }
59 }
60}