Skip to content

Commit

Permalink
polyfill: Rewrite as_chunks/as_chunks_mut/flatten/flatten_mut.
Browse files Browse the repository at this point in the history
Define new types `AsChunks<T,N>` & `AsChunksMut<T,N>` that act
like `&[[T; N]]` and `&mut [[T; N]]`, respectively. Although
there is a ton of boilerplate to do this, the advantage is we
eliminate the `unsafe` in the implementations of `as_chunks` and
`as_chunks_mut`, respectively.

It turns out we only have `flatten`/`flatten_mut` to undo the
effects of `as_chunks`/`as_chunks_mut`. The new polyfills have a
very natural implementation of flattening: just return the inner
slice. Thus, we eliminate the prior use of `unsafe` in
flattening easily.

`core` renamed `flatten` and `flatten_mut` to `as_flattened` and
`as_flattened_mut`, respectively. Use the new naming.

Move `as_chunks` and related machinery into its own file, and do
the same for `as_chunks_mut`. Then we can more easily compare
the two implementations for (in)consistency.

```
diff src/polyfill/slice/as_chunks.rs \
     src/polyfill/slice/as_chunks_mut.rs
```
  • Loading branch information
briansmith committed Jan 25, 2025
1 parent 0db51a8 commit 63dc1e5
Show file tree
Hide file tree
Showing 18 changed files with 223 additions and 105 deletions.
18 changes: 9 additions & 9 deletions src/aead/aes_gcm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,9 +176,9 @@ pub(super) fn seal(
unreachable!()
}
};
let (whole, remainder) = slice::as_chunks_mut(ramaining);
aes_key.ctr32_encrypt_within(slice::flatten_mut(whole).into(), &mut ctr);
auth.update_blocks(whole);
let (mut whole, remainder) = slice::as_chunks_mut(ramaining);
aes_key.ctr32_encrypt_within(whole.as_flattened_mut().into(), &mut ctr);
auth.update_blocks(whole.into());
let remainder = OverlappingPartialBlock::new(remainder.into())
.unwrap_or_else(|InputTooLongError { .. }| unreachable!());
seal_finish(aes_key, auth, remainder, ctr, tag_iv)
Expand All @@ -190,7 +190,7 @@ pub(super) fn seal(

let mut auth = gcm::Context::new(gcm_key, aad, in_out.len())?;

let (whole, remainder) = slice::as_chunks_mut(in_out);
let (mut whole, remainder) = slice::as_chunks_mut(in_out);
let whole_block_bits = auth.in_out_whole_block_bits();
let whole_block_bits_u64: BitLength<u64> = whole_block_bits.into();
if let Ok(whole_block_bits) = whole_block_bits_u64.try_into() {
Expand Down Expand Up @@ -264,11 +264,11 @@ fn seal_strided<A: aes::EncryptBlock + aes::EncryptCtr32, G: gcm::UpdateBlocks +
) -> Result<Tag, error::Unspecified> {
let mut auth = gcm::Context::new(gcm_key, aad, in_out.len())?;

let (whole, remainder) = slice::as_chunks_mut(in_out);
let (mut whole, remainder) = slice::as_chunks_mut(in_out);

for chunk in whole.chunks_mut(CHUNK_BLOCKS) {
aes_key.ctr32_encrypt_within(slice::flatten_mut(chunk).into(), &mut ctr);
auth.update_blocks(chunk);
for mut chunk in whole.chunks_mut::<CHUNK_BLOCKS>() {
aes_key.ctr32_encrypt_within(chunk.as_flattened_mut().into(), &mut ctr);
auth.update_blocks(chunk.into());
}

let remainder = OverlappingPartialBlock::new(remainder.into())
Expand Down Expand Up @@ -361,7 +361,7 @@ pub(super) fn open(
let (whole, _) = slice::as_chunks(in_out.input());
auth.update_blocks(whole);

let whole_len = slice::flatten(whole).len();
let whole_len = whole.as_flattened().len();

// Decrypt any remaining whole blocks.
let whole = Overlapping::new(&mut in_out_slice[..(src.start + whole_len)], src.clone())
Expand Down
6 changes: 3 additions & 3 deletions src/aead/gcm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use super::{aes_gcm, Aad};
use crate::{
bits::{BitLength, FromByteLen as _},
error::{self, InputTooLongError},
polyfill::{sliceutil::overwrite_at_start, NotSend},
polyfill::{slice::AsChunks, sliceutil::overwrite_at_start, NotSend},
};
use cfg_if::cfg_if;

Expand Down Expand Up @@ -120,7 +120,7 @@ impl Context<'_, clmulavxmovbe::Key> {

impl<K: UpdateBlocks> Context<'_, K> {
#[inline(always)]
pub fn update_blocks(&mut self, input: &[[u8; BLOCK_LEN]]) {
pub fn update_blocks(&mut self, input: AsChunks<u8, BLOCK_LEN>) {
self.key.update_blocks(&mut self.Xi, input);
}
}
Expand Down Expand Up @@ -150,5 +150,5 @@ pub(super) trait Gmult {
}

pub(super) trait UpdateBlocks {
fn update_blocks(&self, xi: &mut Xi, input: &[[u8; BLOCK_LEN]]);
fn update_blocks(&self, xi: &mut Xi, input: AsChunks<u8, BLOCK_LEN>);
}
6 changes: 5 additions & 1 deletion src/aead/gcm/clmul.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,11 @@ impl Gmult for Key {

#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
impl super::UpdateBlocks for Key {
fn update_blocks(&self, xi: &mut Xi, input: &[[u8; super::BLOCK_LEN]]) {
fn update_blocks(
&self,
xi: &mut Xi,
input: crate::polyfill::slice::AsChunks<u8, { super::BLOCK_LEN }>,
) {
let _: cpu::Features = cpu::features();
unsafe { ghash!(gcm_ghash_clmul, xi, &self.h_table, input) }
}
Expand Down
4 changes: 2 additions & 2 deletions src/aead/gcm/clmulavxmovbe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
#![cfg(target_arch = "x86_64")]

use super::{clmul, Gmult, HTable, KeyValue, UpdateBlocks, Xi, BLOCK_LEN};
use crate::cpu;
use crate::{cpu, polyfill::slice::AsChunks};

pub(in super::super) type RequiredCpuFeatures = (
clmul::RequiredCpuFeatures,
Expand Down Expand Up @@ -47,7 +47,7 @@ impl Gmult for Key {
}

impl UpdateBlocks for Key {
fn update_blocks(&self, xi: &mut Xi, input: &[[u8; BLOCK_LEN]]) {
fn update_blocks(&self, xi: &mut Xi, input: AsChunks<u8, BLOCK_LEN>) {
unsafe { ghash!(gcm_ghash_avx, xi, &self.inner.inner(), input) }
}
}
8 changes: 4 additions & 4 deletions src/aead/gcm/fallback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
// Unlike the BearSSL notes, we use u128 in the 64-bit implementation.

use super::{ffi::U128, Gmult, KeyValue, UpdateBlocks, Xi, BLOCK_LEN};
use crate::polyfill::ArraySplitMap as _;
use crate::polyfill::{slice::AsChunks, ArraySplitMap as _};

#[derive(Clone)]
pub struct Key {
Expand All @@ -43,7 +43,7 @@ impl Gmult for Key {
}

impl UpdateBlocks for Key {
fn update_blocks(&self, xi: &mut Xi, input: &[[u8; BLOCK_LEN]]) {
fn update_blocks(&self, xi: &mut Xi, input: AsChunks<u8, BLOCK_LEN>) {
ghash(xi, self.h, input);
}
}
Expand Down Expand Up @@ -248,9 +248,9 @@ fn gmult(xi: &mut Xi, h: U128) {
})
}

fn ghash(xi: &mut Xi, h: U128, input: &[[u8; BLOCK_LEN]]) {
fn ghash(xi: &mut Xi, h: U128, input: AsChunks<u8, BLOCK_LEN>) {
with_swapped_xi(xi, |swapped| {
input.iter().for_each(|&input| {
input.into_iter().for_each(|&input| {
let input = input.array_split_map(u64::from_be_bytes);
swapped[0] ^= input[1];
swapped[1] ^= input[0];
Expand Down
10 changes: 6 additions & 4 deletions src/aead/gcm/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

use crate::{constant_time, polyfill::ArraySplitMap};
use crate::{
constant_time,
polyfill::{slice::AsChunks, ArraySplitMap},
};

pub(in super::super) const BLOCK_LEN: usize = 16;
pub(in super::super) type Block = [u8; BLOCK_LEN];
Expand Down Expand Up @@ -125,12 +128,11 @@ impl HTable {
len: crate::c::NonZero_size_t,
),
xi: &mut Xi,
input: &[[u8; BLOCK_LEN]],
input: AsChunks<u8, BLOCK_LEN>,
) {
use crate::polyfill::slice;
use core::num::NonZeroUsize;

let input = slice::flatten(input);
let input = input.as_flattened();

let input_len = match NonZeroUsize::new(input.len()) {
Some(len) => len,
Expand Down
4 changes: 2 additions & 2 deletions src/aead/gcm/neon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
))]

use super::{Gmult, HTable, KeyValue, UpdateBlocks, Xi, BLOCK_LEN};
use crate::cpu;
use crate::{cpu, polyfill::slice::AsChunks};

pub(in super::super) type RequiredCpuFeatures = cpu::arm::Neon;

Expand All @@ -42,7 +42,7 @@ impl Gmult for Key {
}

impl UpdateBlocks for Key {
fn update_blocks(&self, xi: &mut Xi, input: &[[u8; BLOCK_LEN]]) {
fn update_blocks(&self, xi: &mut Xi, input: AsChunks<u8, BLOCK_LEN>) {
unsafe { ghash!(gcm_ghash_neon, xi, &self.h_table, input) }
}
}
9 changes: 4 additions & 5 deletions src/aead/poly1305.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@
use super::{Tag, TAG_LEN};
#[cfg(all(target_arch = "arm", target_endian = "little"))]
use crate::cpu::GetFeature as _;
use crate::{cpu, polyfill::slice};
use core::array;
use crate::{cpu, polyfill::slice::AsChunks};

mod ffi_arm_neon;
mod ffi_fallback;
Expand Down Expand Up @@ -64,11 +63,11 @@ impl Context {
}

pub fn update_block(&mut self, input: [u8; BLOCK_LEN]) {
self.update(array::from_ref(&input))
self.update(AsChunks::from_ref(&input))
}

pub fn update(&mut self, input: &[[u8; BLOCK_LEN]]) {
self.update_internal(slice::flatten(input));
pub fn update(&mut self, input: AsChunks<u8, BLOCK_LEN>) {
self.update_internal(input.as_flattened());
}

fn update_internal(&mut self, input: &[u8]) {
Expand Down
2 changes: 1 addition & 1 deletion src/digest/dynstate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ pub(super) fn sha1_block_data_order<'d>(

let (full_blocks, leftover) = slice::as_chunks(data);
sha1::sha1_block_data_order(state, full_blocks);
(full_blocks.len() * sha1::BLOCK_LEN.into(), leftover)
(full_blocks.as_flattened().len(), leftover)
}

pub(super) fn sha256_block_data_order<'d>(
Expand Down
10 changes: 5 additions & 5 deletions src/digest/sha1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ use super::{
},
BlockLen, OutputLen,
};
use crate::polyfill::slice;
use core::num::Wrapping;
use crate::polyfill::slice::{self, AsChunks};
use core::{mem::size_of, num::Wrapping};

pub(super) const BLOCK_LEN: BlockLen = BlockLen::_512;
pub const CHAINING_LEN: usize = 160 / 8;
Expand All @@ -39,7 +39,7 @@ fn parity(x: W32, y: W32, z: W32) -> W32 {
type State = [W32; CHAINING_WORDS];
const ROUNDS: usize = 80;

pub fn sha1_block_data_order(state: &mut State32, data: &[[u8; BLOCK_LEN.into()]]) {
pub fn sha1_block_data_order(state: &mut State32, data: AsChunks<u8, { BLOCK_LEN.into() }>) {
// The unwrap won't fail because `CHAINING_WORDS` is smaller than the
// length.
let state: &mut State = (&mut state[..CHAINING_WORDS]).try_into().unwrap();
Expand All @@ -52,11 +52,11 @@ pub fn sha1_block_data_order(state: &mut State32, data: &[[u8; BLOCK_LEN.into()]
#[rustfmt::skip]
fn block_data_order(
mut H: [W32; CHAINING_WORDS],
M: &[[u8; BLOCK_LEN.into()]],
M: AsChunks<u8, { BLOCK_LEN.into() }>,
) -> [W32; CHAINING_WORDS]
{
for M in M {
let (M, remainder): (&[<W32 as Word>::InputBytes], &[u8]) = slice::as_chunks(M);
let (M, remainder): (AsChunks<u8, {size_of::<W32>()}>, &[u8]) = slice::as_chunks(M);
debug_assert!(remainder.is_empty());

// FIPS 180-4 6.1.2 Step 1
Expand Down
6 changes: 3 additions & 3 deletions src/digest/sha2/fallback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

use super::CHAINING_WORDS;
use crate::polyfill::slice;
use crate::polyfill::slice::{self, AsChunks};
use core::{
num::Wrapping,
ops::{Add, AddAssign, BitAnd, BitOr, BitXor, Not, Shr},
Expand All @@ -30,13 +30,13 @@ use core::{
#[inline]
pub(super) fn block_data_order<S: Sha2, const BLOCK_LEN: usize, const BYTES_LEN: usize>(
mut H: [S; CHAINING_WORDS],
M: &[[u8; BLOCK_LEN]],
M: AsChunks<u8, BLOCK_LEN>,
) -> [S; CHAINING_WORDS]
where
for<'a> &'a S::InputBytes: From<&'a [u8; BYTES_LEN]>,
{
for M in M {
let (M, remainder): (&[[u8; BYTES_LEN]], &[u8]) = slice::as_chunks(M);
let (M, remainder): (AsChunks<u8, BYTES_LEN>, &[u8]) = slice::as_chunks(M);
debug_assert!(remainder.is_empty());

// FIPS 180-4 {6.2.2, 6.4.2} Step 1
Expand Down
3 changes: 2 additions & 1 deletion src/digest/sha2/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

use super::CHAINING_WORDS;
use crate::polyfill::slice::AsChunks;
use core::num::{NonZeroUsize, Wrapping};

/// `unsafe { T => f }` means it is safe to call `f` iff we can construct
Expand Down Expand Up @@ -49,7 +50,7 @@ macro_rules! sha2_64_ffi {

pub(super) unsafe fn sha2_ffi<U, Cpu, const BLOCK_LEN: usize>(
state: &mut [Wrapping<U>; CHAINING_WORDS],
data: &[[u8; BLOCK_LEN]],
data: AsChunks<u8, BLOCK_LEN>,
cpu: Cpu,
f: unsafe extern "C" fn(
&mut [Wrapping<U>; CHAINING_WORDS],
Expand Down
4 changes: 2 additions & 2 deletions src/digest/sha2/sha2_32.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

use super::{BlockLen, CHAINING_WORDS};
use crate::cpu;
use crate::{cpu, polyfill::slice::AsChunks};
use cfg_if::cfg_if;
use core::num::Wrapping;

Expand All @@ -23,7 +23,7 @@ pub type State32 = [Wrapping<u32>; CHAINING_WORDS];

pub(crate) fn block_data_order_32(
state: &mut State32,
data: &[[u8; SHA256_BLOCK_LEN.into()]],
data: AsChunks<u8, { SHA256_BLOCK_LEN.into() }>,
cpu: cpu::Features,
) {
cfg_if! {
Expand Down
4 changes: 2 additions & 2 deletions src/digest/sha2/sha2_64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

use super::{BlockLen, CHAINING_WORDS};
use crate::cpu;
use crate::{cpu, polyfill::slice::AsChunks};
use cfg_if::cfg_if;
use core::num::Wrapping;

Expand All @@ -23,7 +23,7 @@ pub type State64 = [Wrapping<u64>; CHAINING_WORDS];

pub(crate) fn block_data_order_64(
state: &mut State64,
data: &[[u8; SHA512_BLOCK_LEN.into()]],
data: AsChunks<u8, { SHA512_BLOCK_LEN.into() }>,
cpu: cpu::Features,
) {
cfg_if! {
Expand Down
9 changes: 7 additions & 2 deletions src/ec/curve25519/scalar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

use crate::{arithmetic::limbs_from_hex, digest, error, limb, polyfill::slice};
use crate::{
arithmetic::limbs_from_hex,
digest, error, limb,
polyfill::slice::{self, AsChunks},
};
use core::array;

#[repr(transparent)]
Expand All @@ -28,7 +32,8 @@ impl Scalar {
limbs_from_hex("1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed");
let order = ORDER.map(limb::Limb::from);

let (limbs_as_bytes, _empty): (&[[u8; limb::LIMB_BYTES]], _) = slice::as_chunks(&bytes);
let (limbs_as_bytes, _empty): (AsChunks<u8, { limb::LIMB_BYTES }>, _) =
slice::as_chunks(&bytes);
debug_assert!(_empty.is_empty());
let limbs: [limb::Limb; SCALAR_LEN / limb::LIMB_BYTES] =
array::from_fn(|i| limb::Limb::from_le_bytes(limbs_as_bytes[i]));
Expand Down
Loading

0 comments on commit 63dc1e5

Please sign in to comment.