From 14158e96d7723727bbe51e1368561c5250a2de79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2=20=5BArtyom=20Pavlov=5D?= Date: Wed, 21 Aug 2024 17:43:43 +0300 Subject: [PATCH] Add compact versions --- .github/workflows/sha2.yml | 6 ++ sha2/Cargo.toml | 6 +- sha2/src/lib.rs | 5 +- sha2/src/sha256.rs | 6 ++ sha2/src/sha256/riscv_zknh.rs | 17 ++-- sha2/src/sha256/riscv_zknh_compact.rs | 79 +++++++++++++++++++ sha2/src/sha512.rs | 6 ++ sha2/src/sha512/riscv_zknh_compact.rs | 107 ++++++++++++++++++++++++++ 8 files changed, 220 insertions(+), 12 deletions(-) create mode 100644 sha2/src/sha256/riscv_zknh_compact.rs create mode 100644 sha2/src/sha512/riscv_zknh_compact.rs diff --git a/.github/workflows/sha2.yml b/.github/workflows/sha2.yml index a8038f8a..981228ab 100644 --- a/.github/workflows/sha2.yml +++ b/.github/workflows/sha2.yml @@ -162,6 +162,9 @@ jobs: - run: cross test --package sha2 --target riscv64gc-unknown-linux-gnu env: RUSTFLAGS: '-Dwarnings --cfg sha2_backend="riscv-zknh" -C target-feature=+zknh' + - run: cross test --package sha2 --target riscv64gc-unknown-linux-gnu + env: + RUSTFLAGS: '-Dwarnings --cfg sha2_backend="riscv-zknh-compact" -C target-feature=+zknh' riscv32-zknh: runs-on: ubuntu-latest @@ -175,6 +178,9 @@ jobs: - run: cargo build --target riscv32gc-unknown-linux-gnu -Z build-std env: RUSTFLAGS: '-Dwarnings --cfg sha2_backend="riscv-zknh" -C target-feature=+zknh' + - run: cargo build --target riscv32gc-unknown-linux-gnu -Z build-std + env: + RUSTFLAGS: '-Dwarnings --cfg sha2_backend="riscv-zknh-compact" -C target-feature=+zknh' minimal-versions: uses: RustCrypto/actions/.github/workflows/minimal-versions.yml@master diff --git a/sha2/Cargo.toml b/sha2/Cargo.toml index 1f2e8952..3bc42abd 100644 --- a/sha2/Cargo.toml +++ b/sha2/Cargo.toml @@ -30,13 +30,13 @@ base16ct = { version = "0.2", features = ["alloc"] } [features] default = ["oid", "std"] std = ["digest/std"] -oid = ["digest/oid"] # Enable OID support +oid = ["digest/oid"] # Enable OID support zeroize = ["digest/zeroize"] -force-soft = [] # Force software implementation +force-soft = [] # Force software implementation [lints.rust.unexpected_cfgs] level = "warn" -check-cfg = ['cfg(sha2_backend, values("riscv-zknh"))'] +check-cfg = ['cfg(sha2_backend, values("riscv-zknh", "riscv-zknh-compact"))'] [package.metadata.docs.rs] all-features = true diff --git a/sha2/src/lib.rs b/sha2/src/lib.rs index 623ada2b..0c757e42 100644 --- a/sha2/src/lib.rs +++ b/sha2/src/lib.rs @@ -6,7 +6,10 @@ )] #![cfg_attr(docsrs, feature(doc_auto_cfg))] #![warn(missing_docs, rust_2018_idioms)] -#![cfg_attr(sha2_backend = "riscv-zknh", feature(riscv_ext_intrinsics))] +#![cfg_attr( + any(sha2_backend = "riscv-zknh", sha2_backend = "riscv-zknh-compact"), + feature(riscv_ext_intrinsics) +)] pub use digest::{self, Digest}; diff --git a/sha2/src/sha256.rs b/sha2/src/sha256.rs index d1473375..61309fb9 100644 --- a/sha2/src/sha256.rs +++ b/sha2/src/sha256.rs @@ -12,6 +12,12 @@ cfg_if::cfg_if! { ))] { mod riscv_zknh; use riscv_zknh::compress; + } else if #[cfg(all( + any(target_arch = "riscv32", target_arch = "riscv64"), + sha2_backend = "riscv-zknh-compact" + ))] { + mod riscv_zknh_compact; + use riscv_zknh_compact::compress; } else if #[cfg(target_arch = "aarch64")] { mod soft; mod aarch64; diff --git a/sha2/src/sha256/riscv_zknh.rs b/sha2/src/sha256/riscv_zknh.rs index 2a5a95f4..5f527a2f 100644 --- a/sha2/src/sha256/riscv_zknh.rs +++ b/sha2/src/sha256/riscv_zknh.rs @@ -19,14 +19,15 @@ fn maj(x: u32, y: u32, z: u32) -> u32 { } fn round(state: &mut [u32; 8], block: &[u32; 16]) { - let a = (K32.len() - R) % 8; - let b = (K32.len() - R + 1) % 8; - let c = (K32.len() - R + 2) % 8; - let d = (K32.len() - R + 3) % 8; - let e = (K32.len() - R + 4) % 8; - let f = (K32.len() - R + 5) % 8; - let g = (K32.len() - R + 6) % 8; - let h = (K32.len() - R + 7) % 8; + let n = K32.len() - R; + let a = n % 8; + let b = (n + 1) % 8; + let c = (n + 2) % 8; + let d = (n + 3) % 8; + let e = (n + 4) % 8; + let f = (n + 5) % 8; + let g = (n + 6) % 8; + let h = (n + 7) % 8; state[h] = state[h] .wrapping_add(unsafe { sha256sum1(state[e]) }) diff --git a/sha2/src/sha256/riscv_zknh_compact.rs b/sha2/src/sha256/riscv_zknh_compact.rs new file mode 100644 index 00000000..8c3e17d9 --- /dev/null +++ b/sha2/src/sha256/riscv_zknh_compact.rs @@ -0,0 +1,79 @@ +use crate::consts::K32; + +#[cfg(target_arch = "riscv32")] +use core::arch::riscv32::*; +#[cfg(target_arch = "riscv64")] +use core::arch::riscv64::*; + +#[cfg(not(target_feature = "zknh"))] +compile_error!("riscv-zknh backend requires enabled zknh target feature"); + +#[inline(always)] +fn ch(x: u32, y: u32, z: u32) -> u32 { + (x & y) ^ (!x & z) +} + +#[inline(always)] +fn maj(x: u32, y: u32, z: u32) -> u32 { + (x & y) ^ (x & z) ^ (y & z) +} + +#[inline(always)] +fn round(state: &mut [u32; 8], block: &[u32; 16], r: usize) { + let n = K32.len() - r; + let a = (n + 0) % 8; + let b = (n + 1) % 8; + let c = (n + 2) % 8; + let d = (n + 3) % 8; + let e = (n + 4) % 8; + let f = (n + 5) % 8; + let g = (n + 6) % 8; + let h = (n + 7) % 8; + + state[h] = state[h] + .wrapping_add(unsafe { sha256sum1(state[e]) }) + .wrapping_add(ch(state[e], state[f], state[g])) + .wrapping_add(K32[r]) + .wrapping_add(block[r % 16]); + state[d] = state[d].wrapping_add(state[h]); + state[h] = state[h] + .wrapping_add(unsafe { sha256sum0(state[a]) }) + .wrapping_add(maj(state[a], state[b], state[c])) +} + +#[inline(always)] +fn round_schedule(state: &mut [u32; 8], block: &mut [u32; 16], r: usize) { + round(state, block, r); + + block[r % 16] = block[r % 16] + .wrapping_add(unsafe { sha256sig1(block[(r + 14) % 16]) }) + .wrapping_add(block[(r + 9) % 16]) + .wrapping_add(unsafe { sha256sig0(block[(r + 1) % 16]) }); +} + +#[inline(always)] +fn compress_block(state: &mut [u32; 8], mut block: [u32; 16]) { + let s = &mut state.clone(); + let b = &mut block; + + for i in 0..48 { + round_schedule(s, b, i); + } + for i in 48..64 { + round(s, b, i); + } + + for i in 0..8 { + state[i] = state[i].wrapping_add(s[i]); + } +} + +pub fn compress(state: &mut [u32; 8], blocks: &[[u8; 64]]) { + for block_u8 in blocks { + let mut block = [0u32; 16]; + for (dst, src) in block.iter_mut().zip(block_u8.chunks_exact(4)) { + *dst = u32::from_be_bytes(src.try_into().unwrap()); + } + compress_block(state, block); + } +} diff --git a/sha2/src/sha512.rs b/sha2/src/sha512.rs index f7323f7c..45790865 100644 --- a/sha2/src/sha512.rs +++ b/sha2/src/sha512.rs @@ -12,6 +12,12 @@ cfg_if::cfg_if! { ))] { mod riscv_zknh; use riscv_zknh::compress; + } else if #[cfg(all( + any(target_arch = "riscv32", target_arch = "riscv64"), + sha2_backend = "riscv-zknh-compact" + ))] { + mod riscv_zknh_compact; + use riscv_zknh_compact::compress; } else if #[cfg(target_arch = "aarch64")] { mod soft; mod aarch64; diff --git a/sha2/src/sha512/riscv_zknh_compact.rs b/sha2/src/sha512/riscv_zknh_compact.rs new file mode 100644 index 00000000..0d3c5e5b --- /dev/null +++ b/sha2/src/sha512/riscv_zknh_compact.rs @@ -0,0 +1,107 @@ +use crate::consts::K64; + +#[cfg(target_arch = "riscv32")] +use core::arch::riscv32::*; +#[cfg(target_arch = "riscv64")] +use core::arch::riscv64::*; + +#[cfg(not(target_feature = "zknh"))] +compile_error!("riscv-zknh backend requires enabled zknh target feature"); + +#[cfg(target_arch = "riscv32")] +unsafe fn sha512sum0(x: u64) -> u64 { + let a = sha512sum0r((x >> 32) as u32, x as u32); + let b = sha512sum0r(x as u32, (x >> 32) as u32); + ((a as u64) << 32) | (b as u64) +} + +#[cfg(target_arch = "riscv32")] +unsafe fn sha512sum1(x: u64) -> u64 { + let a = sha512sum1r((x >> 32) as u32, x as u32); + let b = sha512sum1r(x as u32, (x >> 32) as u32); + ((a as u64) << 32) | (b as u64) +} + +#[cfg(target_arch = "riscv32")] +unsafe fn sha512sig0(x: u64) -> u64 { + let a = sha512sig0h((x >> 32) as u32, x as u32); + let b = sha512sig0l(x as u32, (x >> 32) as u32); + ((a as u64) << 32) | (b as u64) +} + +#[cfg(target_arch = "riscv32")] +unsafe fn sha512sig1(x: u64) -> u64 { + let a = sha512sig1h((x >> 32) as u32, x as u32); + let b = sha512sig1l(x as u32, (x >> 32) as u32); + ((a as u64) << 32) | (b as u64) +} + +#[inline(always)] +fn ch(x: u64, y: u64, z: u64) -> u64 { + (x & y) ^ (!x & z) +} + +#[inline(always)] +fn maj(x: u64, y: u64, z: u64) -> u64 { + (x & y) ^ (x & z) ^ (y & z) +} + +#[inline(always)] +fn round(state: &mut [u64; 8], block: &[u64; 16], r: usize) { + let n = K64.len() - r; + let a = (n + 0) % 8; + let b = (n + 1) % 8; + let c = (n + 2) % 8; + let d = (n + 3) % 8; + let e = (n + 4) % 8; + let f = (n + 5) % 8; + let g = (n + 6) % 8; + let h = (n + 7) % 8; + + state[h] = state[h] + .wrapping_add(unsafe { sha512sum1(state[e]) }) + .wrapping_add(ch(state[e], state[f], state[g])) + .wrapping_add(K64[r]) + .wrapping_add(block[r % 16]); + state[d] = state[d].wrapping_add(state[h]); + state[h] = state[h] + .wrapping_add(unsafe { sha512sum0(state[a]) }) + .wrapping_add(maj(state[a], state[b], state[c])) +} + +#[inline(always)] +fn round_schedule(state: &mut [u64; 8], block: &mut [u64; 16], r: usize) { + round(state, block, r); + + block[r % 16] = block[r % 16] + .wrapping_add(unsafe { sha512sig1(block[(r + 14) % 16]) }) + .wrapping_add(block[(r + 9) % 16]) + .wrapping_add(unsafe { sha512sig0(block[(r + 1) % 16]) }); +} + +#[inline(always)] +fn compress_block(state: &mut [u64; 8], mut block: [u64; 16]) { + let s = &mut state.clone(); + let b = &mut block; + + for i in 0..64 { + round_schedule(s, b, i); + } + for i in 64..80 { + round(s, b, i); + } + + for i in 0..8 { + state[i] = state[i].wrapping_add(s[i]); + } +} + +pub fn compress(state: &mut [u64; 8], blocks: &[[u8; 128]]) { + for block_u8 in blocks { + let mut block = [0u64; 16]; + for (dst, src) in block.iter_mut().zip(block_u8.chunks_exact(8)) { + *dst = u64::from_be_bytes(src.try_into().unwrap()); + } + compress_block(state, block); + } +}