Remove ArrayEncoding
usage from Digest
and delete ArrayEncoding
.
Note: I originally tried an alternative implementation using `flat_map` that ended up being materially slower. To fix that performance regression I had to make the following change: ``` let mut output = Output([0; MAX_OUTPUT_LEN]); output .0 - .iter_mut() - .zip(input.iter().copied().flat_map(|Wrapping(w)| f(w))) + .chunks_mut(N) + .zip(input.iter().copied().map(|Wrapping(w)| f(w))) .for_each(|(o, i)| { - *o = i; + o.copy_from_slice(&i); }); output } ``` I verified that this generates the same assembly code as the original code on x86-64 using Rust 1.74.0, except that there are two additional 128-bit moves in `sha256_formta_output` to zero out the latter half of `Output`, which was intended.
This commit is contained in:
parent
ff0ed4ca9d
commit
57fc4860d0
@ -24,11 +24,7 @@
|
|||||||
// The goal for this implementation is to drive the overhead as close to zero
|
// The goal for this implementation is to drive the overhead as close to zero
|
||||||
// as possible.
|
// as possible.
|
||||||
|
|
||||||
use crate::{
|
use crate::{c, cpu, debug, polyfill};
|
||||||
c, cpu, debug,
|
|
||||||
endian::{ArrayEncoding, BigEndian},
|
|
||||||
polyfill,
|
|
||||||
};
|
|
||||||
use core::num::Wrapping;
|
use core::num::Wrapping;
|
||||||
|
|
||||||
mod sha1;
|
mod sha1;
|
||||||
@ -248,8 +244,7 @@ impl Digest {
|
|||||||
impl AsRef<[u8]> for Digest {
|
impl AsRef<[u8]> for Digest {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn as_ref(&self) -> &[u8] {
|
fn as_ref(&self) -> &[u8] {
|
||||||
let as64 = unsafe { &self.value.as64 };
|
&self.value.0[..self.algorithm.output_len]
|
||||||
&as64.as_byte_array()[..self.algorithm.output_len]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -456,10 +451,7 @@ union State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
union Output {
|
struct Output([u8; MAX_OUTPUT_LEN]);
|
||||||
as64: [BigEndian<u64>; 512 / 8 / core::mem::size_of::<BigEndian<u64>>()],
|
|
||||||
as32: [BigEndian<u32>; 256 / 8 / core::mem::size_of::<BigEndian<u32>>()],
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The maximum block length ([`Algorithm::block_len()`]) of all the algorithms
|
/// The maximum block length ([`Algorithm::block_len()`]) of all the algorithms
|
||||||
/// in this module.
|
/// in this module.
|
||||||
@ -474,17 +466,30 @@ pub const MAX_OUTPUT_LEN: usize = 512 / 8;
|
|||||||
pub const MAX_CHAINING_LEN: usize = MAX_OUTPUT_LEN;
|
pub const MAX_CHAINING_LEN: usize = MAX_OUTPUT_LEN;
|
||||||
|
|
||||||
fn sha256_format_output(input: State) -> Output {
|
fn sha256_format_output(input: State) -> Output {
|
||||||
let input = unsafe { &input.as32 };
|
let input = unsafe { input.as32 };
|
||||||
Output {
|
format_output::<_, _, { core::mem::size_of::<u32>() }>(input, u32::to_be_bytes)
|
||||||
as32: input.map(BigEndian::from),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sha512_format_output(input: State) -> Output {
|
fn sha512_format_output(input: State) -> Output {
|
||||||
let input = unsafe { &input.as64 };
|
let input = unsafe { input.as64 };
|
||||||
Output {
|
format_output::<_, _, { core::mem::size_of::<u64>() }>(input, u64::to_be_bytes)
|
||||||
as64: input.map(BigEndian::from),
|
}
|
||||||
}
|
|
||||||
|
#[inline]
|
||||||
|
fn format_output<T, F, const N: usize>(input: [Wrapping<T>; sha2::CHAINING_WORDS], f: F) -> Output
|
||||||
|
where
|
||||||
|
F: Fn(T) -> [u8; N],
|
||||||
|
T: Copy,
|
||||||
|
{
|
||||||
|
let mut output = Output([0; MAX_OUTPUT_LEN]);
|
||||||
|
output
|
||||||
|
.0
|
||||||
|
.chunks_mut(N)
|
||||||
|
.zip(input.iter().copied().map(|Wrapping(w)| f(w)))
|
||||||
|
.for_each(|(o, i)| {
|
||||||
|
o.copy_from_slice(&i);
|
||||||
|
});
|
||||||
|
output
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The length of the output of SHA-1, in bytes.
|
/// The length of the output of SHA-1, in bytes.
|
||||||
|
@ -11,12 +11,6 @@ where
|
|||||||
const ZERO: Self;
|
const ZERO: Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Work around the inability to implement `AsRef` for arrays of `Encoding`s
|
|
||||||
/// due to the coherence rules.
|
|
||||||
pub trait ArrayEncoding<T> {
|
|
||||||
fn as_byte_array(&self) -> &T;
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! define_endian {
|
macro_rules! define_endian {
|
||||||
($endian:ident) => {
|
($endian:ident) => {
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
@ -25,22 +19,6 @@ macro_rules! define_endian {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! impl_array_encoding {
|
|
||||||
($endian:ident, $base:ident, $elems:expr) => {
|
|
||||||
impl ArrayEncoding<[u8; $elems * core::mem::size_of::<$base>()]>
|
|
||||||
for [$endian<$base>; $elems]
|
|
||||||
{
|
|
||||||
#[inline]
|
|
||||||
fn as_byte_array(&self) -> &[u8; $elems * core::mem::size_of::<$base>()] {
|
|
||||||
let as_bytes_ptr = self
|
|
||||||
.as_ptr()
|
|
||||||
.cast::<[u8; $elems * core::mem::size_of::<$base>()]>();
|
|
||||||
unsafe { &*as_bytes_ptr }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! impl_endian {
|
macro_rules! impl_endian {
|
||||||
($endian:ident, $base:ident, $to_endian:ident, $from_endian:ident, $size:expr) => {
|
($endian:ident, $base:ident, $to_endian:ident, $from_endian:ident, $size:expr) => {
|
||||||
impl Encoding<$base> for $endian<$base> {
|
impl Encoding<$base> for $endian<$base> {
|
||||||
@ -81,18 +59,11 @@ macro_rules! impl_endian {
|
|||||||
$base::$from_endian(value)
|
$base::$from_endian(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_array_encoding!($endian, $base, 1);
|
|
||||||
impl_array_encoding!($endian, $base, 2);
|
|
||||||
impl_array_encoding!($endian, $base, 3);
|
|
||||||
impl_array_encoding!($endian, $base, 4);
|
|
||||||
impl_array_encoding!($endian, $base, 8);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
define_endian!(BigEndian);
|
define_endian!(BigEndian);
|
||||||
impl_endian!(BigEndian, u32, to_be, from_be, 4);
|
impl_endian!(BigEndian, u32, to_be, from_be, 4);
|
||||||
impl_endian!(BigEndian, u64, to_be, from_be, 8);
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user