diff --git a/.travis.yml b/.travis.yml index 842be429c..d1538024e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -28,6 +28,18 @@ matrix: - env: NAME=features-test rust: nightly script: ./test_features.sh + - env: NAME=test-aarch64 + arch: arm64 + rust: nightly + script: + - cd sha1 + - cargo test --verbose --release --features asm-aarch64 + - cargo bench --verbose + - cargo bench --verbose --features asm-aarch64 + - cd ../sha2 + - cargo test --verbose --release --features asm-aarch64 + - cargo bench --verbose + - cargo bench --verbose --features asm-aarch64 install: - cargo install cross || true diff --git a/sha1/Cargo.toml b/sha1/Cargo.toml index 41a941ab7..381d94463 100644 --- a/sha1/Cargo.toml +++ b/sha1/Cargo.toml @@ -18,6 +18,7 @@ block-buffer = "0.7" fake-simd = "0.1" sha1-asm = { version = "0.4", optional = true } opaque-debug = "0.2" +libc = { version = "0.2", optional = true } [dev-dependencies] digest = { version = "0.8", features = ["dev"] } @@ -28,5 +29,9 @@ default = ["std"] std = ["digest/std"] asm = ["sha1-asm"] +# TODO: Remove this feature once is_aarch64_feature_detected!() is stabilised. +# Only used on AArch64 Linux systems. +asm-aarch64 = ["asm", "libc"] + [badges] travis-ci = { repository = "RustCrypto/hashes" } diff --git a/sha1/src/aarch64.rs b/sha1/src/aarch64.rs new file mode 100644 index 000000000..d3cffecd7 --- /dev/null +++ b/sha1/src/aarch64.rs @@ -0,0 +1,9 @@ +// TODO: Import those from libc, see https://github.com/rust-lang/libc/pull/1638 +const AT_HWCAP: u64 = 16; +const HWCAP_SHA1: u64 = 32; + +#[inline(always)] +pub fn sha1_supported() -> bool { + let hwcaps: u64 = unsafe { ::libc::getauxval(AT_HWCAP) }; + (hwcaps & HWCAP_SHA1) != 0 +} diff --git a/sha1/src/consts.rs b/sha1/src/consts.rs index 7a1bb3435..628d4d6e0 100644 --- a/sha1/src/consts.rs +++ b/sha1/src/consts.rs @@ -2,16 +2,16 @@ pub const STATE_LEN: usize = 5; -#[cfg(not(feature = "asm"))] +#[cfg(any(not(feature = "asm"), feature = "asm-aarch64"))] pub const BLOCK_LEN: usize = 16; -#[cfg(not(feature = "asm"))] +#[cfg(any(not(feature = "asm"), feature = "asm-aarch64"))] pub const K0: u32 = 0x5A827999u32; -#[cfg(not(feature = "asm"))] +#[cfg(any(not(feature = "asm"), feature = "asm-aarch64"))] pub const K1: u32 = 0x6ED9EBA1u32; -#[cfg(not(feature = "asm"))] +#[cfg(any(not(feature = "asm"), feature = "asm-aarch64"))] pub const K2: u32 = 0x8F1BBCDCu32; -#[cfg(not(feature = "asm"))] +#[cfg(any(not(feature = "asm"), feature = "asm-aarch64"))] pub const K3: u32 = 0xCA62C1D6u32; pub const H: [u32; STATE_LEN] = [ diff --git a/sha1/src/lib.rs b/sha1/src/lib.rs index a1a7068a0..374c234c2 100644 --- a/sha1/src/lib.rs +++ b/sha1/src/lib.rs @@ -28,24 +28,50 @@ #![no_std] #![doc(html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo_small.png")] + +// Give relevant error messages if the user tries to enable AArch64 asm on unsupported platforms. +#[cfg(all(feature = "asm-aarch64", target_arch = "aarch64", not(target_os = "linux")))] +compile_error!("Your OS isn’t yet supported for runtime-checking of AArch64 features."); +#[cfg(all(feature = "asm-aarch64", target_os = "linux", not(target_arch = "aarch64")))] +compile_error!("Enable the \"asm\" feature instead of \"asm-aarch64\" on non-AArch64 Linux systems."); +#[cfg(all(not(feature = "asm-aarch64"), feature = "asm", target_arch = "aarch64", target_os = "linux"))] +compile_error!("Enable the \"asm-aarch64\" feature on AArch64 if you want to use asm."); + extern crate block_buffer; #[macro_use] extern crate opaque_debug; #[macro_use] pub extern crate digest; #[cfg(feature = "std")] extern crate std; -#[cfg(not(feature = "asm"))] +#[cfg(any(not(feature = "asm"), feature = "asm-aarch64"))] extern crate fake_simd as simd; +#[cfg(feature = "asm-aarch64")] +extern crate libc; #[cfg(feature = "asm")] extern crate sha1_asm; -#[cfg(feature = "asm")] +#[cfg(all(feature = "asm", not(feature = "asm-aarch64")))] #[inline(always)] fn compress(state: &mut [u32; 5], block: &GenericArray) { let block: &[u8; 64] = unsafe { core::mem::transmute(block) }; sha1_asm::compress(state, block); } +#[cfg(feature = "asm-aarch64")] +mod aarch64; +#[cfg(feature = "asm-aarch64")] +#[inline(always)] +fn compress(state: &mut [u32; 5], block: &GenericArray) { + // TODO: Replace this platform-specific call with is_aarch64_feature_detected!("sha1") once + // that macro is stabilised and https://github.com/rust-lang/rfcs/pull/2725 is implemented + // to let us use it on no_std. + if aarch64::sha1_supported() { + let block: &[u8; 64] = unsafe { core::mem::transmute(block) }; + sha1_asm::compress(state, block); + } else { + utils::compress(state, block); + } +} -#[cfg(not(feature = "asm"))] +#[cfg(any(not(feature = "asm"), feature = "asm-aarch64"))] mod utils; #[cfg(not(feature = "asm"))] use utils::compress; diff --git a/sha2/Cargo.toml b/sha2/Cargo.toml index 025a495dc..b56ce37d7 100644 --- a/sha2/Cargo.toml +++ b/sha2/Cargo.toml @@ -15,6 +15,7 @@ block-buffer = "0.7" fake-simd = "0.1" opaque-debug = "0.2" sha2-asm = { version="0.5", optional=true } +libc = { version = "0.2", optional = true } [dev-dependencies] digest = { version = "0.8", features = ["dev"] } @@ -25,5 +26,9 @@ default = ["std"] std = ["digest/std"] asm = ["sha2-asm"] +# TODO: Remove this feature once is_aarch64_feature_detected!() is stabilised. +# Only used on AArch64 Linux systems. +asm-aarch64 = ["asm", "libc"] + [badges] travis-ci = { repository = "RustCrypto/hashes" } diff --git a/sha2/src/aarch64.rs b/sha2/src/aarch64.rs new file mode 100644 index 000000000..089a8f648 --- /dev/null +++ b/sha2/src/aarch64.rs @@ -0,0 +1,9 @@ +// TODO: Import those from libc, see https://github.com/rust-lang/libc/pull/1638 +const AT_HWCAP: u64 = 16; +const HWCAP_SHA2: u64 = 64; + +#[inline(always)] +pub fn sha2_supported() -> bool { + let hwcaps: u64 = unsafe { ::libc::getauxval(AT_HWCAP) }; + (hwcaps & HWCAP_SHA2) != 0 +} diff --git a/sha2/src/lib.rs b/sha2/src/lib.rs index 9b72eb24e..2b3e93e0e 100644 --- a/sha2/src/lib.rs +++ b/sha2/src/lib.rs @@ -57,6 +57,15 @@ #![no_std] #![doc(html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo_small.png")] + +// Give relevant error messages if the user tries to enable AArch64 asm on unsupported platforms. +#[cfg(all(feature = "asm-aarch64", target_arch = "aarch64", not(target_os = "linux")))] +compile_error!("Your OS isn’t yet supported for runtime-checking of AArch64 features."); +#[cfg(all(feature = "asm-aarch64", target_os = "linux", not(target_arch = "aarch64")))] +compile_error!("Enable the \"asm\" feature instead of \"asm-aarch64\" on non-AArch64 Linux systems."); +#[cfg(all(not(feature = "asm-aarch64"), feature = "asm", target_arch = "aarch64", target_os = "linux"))] +compile_error!("Enable the \"asm-aarch64\" feature on AArch64 if you want to use asm."); + extern crate block_buffer; extern crate fake_simd as simd; #[macro_use] extern crate opaque_debug; @@ -65,12 +74,16 @@ extern crate fake_simd as simd; extern crate sha2_asm; #[cfg(feature = "std")] extern crate std; +#[cfg(feature = "asm-aarch64")] +extern crate libc; mod consts; -#[cfg(not(feature = "asm"))] +#[cfg(any(not(feature = "asm"), feature = "asm-aarch64"))] mod sha256_utils; -#[cfg(not(feature = "asm"))] +#[cfg(any(not(feature = "asm"), feature = "asm-aarch64"))] mod sha512_utils; +#[cfg(feature = "asm-aarch64")] +mod aarch64; mod sha256; mod sha512; diff --git a/sha2/src/sha256.rs b/sha2/src/sha256.rs index 95763dbfc..9dad44489 100644 --- a/sha2/src/sha256.rs +++ b/sha2/src/sha256.rs @@ -24,10 +24,24 @@ struct Engine256State { impl Engine256State { fn new(h: &[u32; STATE_LEN]) -> Engine256State { Engine256State { h: *h } } + #[cfg(not(feature = "asm-aarch64"))] pub fn process_block(&mut self, block: &Block) { let block = unsafe { &*(block.as_ptr() as *const [u8; 64]) }; compress256(&mut self.h, block); } + + #[cfg(feature = "asm-aarch64")] + pub fn process_block(&mut self, block: &Block) { + let block = unsafe { &*(block.as_ptr() as *const [u8; 64]) }; + // TODO: Replace this platform-specific call with is_aarch64_feature_detected!("sha2") once + // that macro is stabilised and https://github.com/rust-lang/rfcs/pull/2725 is implemented + // to let us use it on no_std. + if ::aarch64::sha2_supported() { + compress256(&mut self.h, block); + } else { + ::sha256_utils::compress256(&mut self.h, block); + } + } } /// A structure that keeps track of the state of the Sha-256 operation and diff --git a/sha2/src/sha512.rs b/sha2/src/sha512.rs index 6b39ae1ed..1a1c935ba 100644 --- a/sha2/src/sha512.rs +++ b/sha2/src/sha512.rs @@ -6,9 +6,9 @@ use block_buffer::byteorder::{BE, ByteOrder}; use consts::{STATE_LEN, H384, H512, H512_TRUNC_224, H512_TRUNC_256}; -#[cfg(not(feature = "asm"))] +#[cfg(any(not(feature = "asm"), feature = "asm-aarch64"))] use sha512_utils::compress512; -#[cfg(feature = "asm")] +#[cfg(all(feature = "asm", not(feature = "asm-aarch64")))] use sha2_asm::compress512; type BlockSize = U128;