Skip to content

Commit

Permalink
Refactor the SHA-1 implementation.
Browse files Browse the repository at this point in the history
Address review comments after
briansmith#156 (comment).
  • Loading branch information
SimonSapin authored and briansmith committed Mar 28, 2016
1 parent fc99d30 commit c5fc35f
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 46 deletions.
36 changes: 27 additions & 9 deletions src/digest/digest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@
use core;
use super::{c, polyfill};

pub use self::sha1::SHA1;

// XXX: endian-specific.
// XXX: Replace with `const fn` when `const fn` is stable:
// https://github.com/rust-lang/rust/issues/24111
Expand Down Expand Up @@ -114,7 +112,7 @@ impl Context {
&data[..to_copy]);

unsafe {
(self.algorithm.block_data_order)(self.state.as_mut_ptr(),
(self.algorithm.block_data_order)(&mut self.state,
self.pending.as_ptr(), 1);
}
self.completed_data_blocks =
Expand All @@ -128,7 +126,7 @@ impl Context {
let num_to_save_for_later = remaining.len() % self.algorithm.block_len;
if num_blocks > 0 {
unsafe {
(self.algorithm.block_data_order)(self.state.as_mut_ptr(),
(self.algorithm.block_data_order)(&mut self.state,
remaining.as_ptr(),
num_blocks);
}
Expand Down Expand Up @@ -161,7 +159,7 @@ impl Context {
polyfill::slice::fill(
&mut self.pending[padding_pos..self.algorithm.block_len], 0);
unsafe {
(self.algorithm.block_data_order)(self.state.as_mut_ptr(),
(self.algorithm.block_data_order)(&mut self.state,
self.pending.as_ptr(), 1);
}
// We don't increase |self.completed_data_blocks| because the
Expand All @@ -185,7 +183,7 @@ impl Context {
completed_data_bits /= 0x100;
}
unsafe {
(self.algorithm.block_data_order)(self.state.as_mut_ptr(),
(self.algorithm.block_data_order)(&mut self.state,
self.pending.as_ptr(), 1);
}

Expand Down Expand Up @@ -283,7 +281,7 @@ pub struct Algorithm {
/// The length of the length in the padding.
len_len: usize,

block_data_order: unsafe extern fn(state: *mut u64, data: *const u8,
block_data_order: unsafe extern fn(state: &mut [u64; MAX_CHAINING_LEN / 8], data: *const u8,
num: c::size_t),
format_output: fn (input: &[u64; MAX_CHAINING_LEN / 8]) ->
[u64; MAX_OUTPUT_LEN / 8],
Expand All @@ -296,6 +294,26 @@ pub struct Algorithm {
pub nid: c::int,
}

/// SHA-1 as specified in [FIPS
/// 180-4](http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf).
///
/// SHA-1 is deprecated.
pub static SHA1: Algorithm = Algorithm {
output_len: 160 / 8,
chaining_len: sha1::CHAINING_LEN,
block_len: sha1::BLOCK_LEN,
len_len: 64 / 8,
block_data_order: sha1::block_data_order,
format_output: sha256_format_output,
initial_state: [
u32x2!(0x67452301u32, 0xefcdab89u32),
u32x2!(0x98badcfeu32, 0x10325476u32),
u32x2!(0xc3d2e1f0u32, 0u32),
0, 0, 0, 0, 0,
],
nid: 64, // NID_sha1
};

/// SHA-256 as specified in [FIPS
/// 180-4](http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf).
pub static SHA256: Algorithm = Algorithm {
Expand Down Expand Up @@ -435,8 +453,8 @@ pub extern fn SHA512_4(out: *mut u8, out_len: c::size_t,
}

extern {
fn sha256_block_data_order(state: *mut u64, data: *const u8, num: c::size_t);
fn sha512_block_data_order(state: *mut u64, data: *const u8, num: c::size_t);
fn sha256_block_data_order(state: &mut [u64; MAX_CHAINING_LEN / 8], data: *const u8, num: c::size_t);
fn sha512_block_data_order(state: &mut [u64; MAX_CHAINING_LEN / 8], data: *const u8, num: c::size_t);
}

#[cfg(test)]
Expand Down
56 changes: 24 additions & 32 deletions src/digest/sha1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,51 +17,43 @@ use core;
use core::num::Wrapping;
use c;
use polyfill;
use super::{Algorithm, sha256_format_output, MAX_CHAINING_LEN};
use super::MAX_CHAINING_LEN;

/// SHA-1 as specified in [FIPS
/// 180-4](http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf).
///
/// SHA-1 is deprecated in *ring*.
/// The main purpose in retaining it is to support legacy protocols and OCSP,
/// none of which need a fast SHA-1 implementation.
/// This implementation therfore favors size and simplicity over speed.
/// Unlike SHA-256, SHA-384, and SHA-512, there is no assembly language implementation.
pub static SHA1: Algorithm = Algorithm {
output_len: 160 / 8,
chaining_len: 160 / 8,
block_len: 512 / 8,
len_len: 64 / 8,
block_data_order: sha1_block_data_order,
format_output: sha256_format_output,
initial_state: [
u32x2!(0x67452301u32, 0xefcdab89u32),
u32x2!(0x98badcfeu32, 0x10325476u32),
u32x2!(0xc3d2e1f0u32, 0u32),
0, 0, 0, 0, 0,
],
nid: 64, // NID_sha1
};
pub const BLOCK_LEN: usize = 512 / 8;
pub const CHAINING_LEN: usize = 160 / 8;
const CHAINING_WORDS: usize = CHAINING_LEN / 4;

type W32 = Wrapping<u32>;

#[inline] fn ch(x: W32, y: W32, z: W32) -> W32 { (x & y) | (!x & z) }
#[inline] fn parity(x: W32, y: W32, z: W32) -> W32 { x ^ y ^ z }
#[inline] fn maj(x: W32, y: W32, z: W32) -> W32 { (x & y) | (x & z) | (y & z) }

unsafe extern fn sha1_block_data_order(state: *mut u64, mut data: *const u8,
num: c::size_t) {
let state = core::slice::from_raw_parts_mut(state, MAX_CHAINING_LEN / 8);
/// The main purpose in retaining this is to support legacy protocols and OCSP,
/// none of which need a fast SHA-1 implementation.
/// This implementation therefore favors size and simplicity over speed.
/// Unlike SHA-256, SHA-384, and SHA-512,
/// there is no assembly language implementation.
pub unsafe extern fn block_data_order(state: &mut [u64; MAX_CHAINING_LEN / 8],
data: *const u8,
num: c::size_t) {
let data = data as *const [u8; BLOCK_LEN];
let blocks = core::slice::from_raw_parts(data, num);
block_data_order_safe(state, blocks)
}

fn block_data_order_safe(state: &mut [u64; MAX_CHAINING_LEN / 8],
blocks: &[[u8; BLOCK_LEN]]) {
let state = polyfill::slice::u64_as_u32_mut(state);
let state = polyfill::slice::as_wrapping_mut(state);
let state = &mut state[..CHAINING_WORDS];
let state = slice_as_array_ref_mut!(state, CHAINING_WORDS).unwrap();

let mut w: [W32; 80] = [Wrapping(0); 80];
for _ in 0..num {
let block = core::slice::from_raw_parts(data, 512 / 8);
data = data.offset(512 / 8);

for block in blocks {
for t in 0..16 {
w[t] = Wrapping(polyfill::slice::u32_from_be_u8_at(block, t * 4))
let word = slice_as_array_ref!(&block[t * 4..][..4], 4).unwrap();
w[t] = Wrapping(polyfill::slice::u32_from_be_u8(word))
}
for t in 16..80 {
let wt = w[t - 3] ^ w[t - 8] ^ w[t - 14] ^ w[t - 16];
Expand Down
10 changes: 5 additions & 5 deletions src/polyfill.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,11 @@ pub mod slice {
use core;

#[inline(always)]
pub fn u32_from_be_u8_at(buffer: &[u8], at: usize) -> u32 {
u32::from(buffer[at]) << 24 |
u32::from(buffer[at + 1]) << 16 |
u32::from(buffer[at + 2]) << 8 |
u32::from(buffer[at + 3])
pub fn u32_from_be_u8(buffer: &[u8; 4]) -> u32 {
u32::from(buffer[0]) << 24 |
u32::from(buffer[1]) << 16 |
u32::from(buffer[2]) << 8 |
u32::from(buffer[3])
}

// https://github.com/rust-lang/rust/issues/27750
Expand Down

0 comments on commit c5fc35f

Please sign in to comment.