Skip to content

Commit 82c36a4

Browse files
authored
sha2: add soft-compact backend (backport of #686) (#687)
This PR is a slightly modified backport of [#686]. Instead of the configuration flag it introduces the `force-soft-compact` crate feature. [#686]: #686
1 parent c1e85ae commit 82c36a4

File tree

7 files changed

+150
-4
lines changed

7 files changed

+150
-4
lines changed

Cargo.lock

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

sha2/CHANGELOG.md

+7
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## 0.10.9 (2025-04-30)
9+
### Added
10+
- `force-soft-compact` crate feature to enable compact software backend (backport of [#686]) [#687]
11+
12+
[#686]: https://github.com/RustCrypto/hashes/pull/686
13+
[#687]: https://github.com/RustCrypto/hashes/pull/687
14+
815
## 0.10.8 (2023-09-26)
916
### Added
1017
- `asm!`-based backend for LoongArch64 targets gated behind `loongarch64_asm` feature [#507]

sha2/Cargo.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "sha2"
3-
version = "0.10.8"
3+
version = "0.10.9"
44
description = """
55
Pure Rust implementation of the SHA-2 hash function family
66
including SHA-224, SHA-256, SHA-384, and SHA-512.
@@ -36,6 +36,7 @@ asm = ["sha2-asm"] # WARNING: this feature SHOULD NOT be enabled by library crat
3636
loongarch64_asm = []
3737
compress = [] # Expose compress functions
3838
force-soft = [] # Force software implementation
39+
force-soft-compact = [] # Force compact software implementation
3940
asm-aarch64 = ["asm"] # DEPRECATED: use `asm` instead
4041

4142
[package.metadata.docs.rs]

sha2/src/sha256.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
use digest::{generic_array::GenericArray, typenum::U64};
22

33
cfg_if::cfg_if! {
4-
if #[cfg(feature = "force-soft")] {
4+
if #[cfg(feature = "force-soft-compact")] {
5+
mod soft_compact;
6+
use soft_compact::compress;
7+
} else if #[cfg(feature = "force-soft")] {
58
mod soft;
69
use soft::compress;
710
} else if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {

sha2/src/sha256/soft_compact.rs

+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
use crate::consts::K32;
2+
3+
fn to_u32s(block: &[u8; 64]) -> [u32; 16] {
4+
use core::convert::TryInto;
5+
let mut res = [0u32; 16];
6+
for i in 0..16 {
7+
let chunk = block[4 * i..][..4].try_into().unwrap();
8+
res[i] = u32::from_be_bytes(chunk);
9+
}
10+
res
11+
}
12+
13+
fn compress_u32(state: &mut [u32; 8], block: [u32; 16]) {
14+
let [mut a, mut b, mut c, mut d, mut e, mut f, mut g, mut h] = *state;
15+
16+
let mut w = [0; 64];
17+
w[..16].copy_from_slice(&block);
18+
19+
for i in 16..64 {
20+
let w15 = w[i - 15];
21+
let s0 = (w15.rotate_right(7)) ^ (w15.rotate_right(18)) ^ (w15 >> 3);
22+
let w2 = w[i - 2];
23+
let s1 = (w2.rotate_right(17)) ^ (w2.rotate_right(19)) ^ (w2 >> 10);
24+
w[i] = w[i - 16]
25+
.wrapping_add(s0)
26+
.wrapping_add(w[i - 7])
27+
.wrapping_add(s1);
28+
}
29+
30+
for i in 0..64 {
31+
let s1 = e.rotate_right(6) ^ e.rotate_right(11) ^ e.rotate_right(25);
32+
let ch = (e & f) ^ ((!e) & g);
33+
let t1 = s1
34+
.wrapping_add(ch)
35+
.wrapping_add(K32[i])
36+
.wrapping_add(w[i])
37+
.wrapping_add(h);
38+
let s0 = a.rotate_right(2) ^ a.rotate_right(13) ^ a.rotate_right(22);
39+
let maj = (a & b) ^ (a & c) ^ (b & c);
40+
let t2 = s0.wrapping_add(maj);
41+
42+
h = g;
43+
g = f;
44+
f = e;
45+
e = d.wrapping_add(t1);
46+
d = c;
47+
c = b;
48+
b = a;
49+
a = t1.wrapping_add(t2);
50+
}
51+
52+
state[0] = state[0].wrapping_add(a);
53+
state[1] = state[1].wrapping_add(b);
54+
state[2] = state[2].wrapping_add(c);
55+
state[3] = state[3].wrapping_add(d);
56+
state[4] = state[4].wrapping_add(e);
57+
state[5] = state[5].wrapping_add(f);
58+
state[6] = state[6].wrapping_add(g);
59+
state[7] = state[7].wrapping_add(h);
60+
}
61+
62+
pub fn compress(state: &mut [u32; 8], blocks: &[[u8; 64]]) {
63+
for block in blocks.iter() {
64+
compress_u32(state, to_u32s(block));
65+
}
66+
}

sha2/src/sha512.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
use digest::{generic_array::GenericArray, typenum::U128};
22

33
cfg_if::cfg_if! {
4-
if #[cfg(feature = "force-soft")] {
4+
if #[cfg(feature = "force-soft-compact")] {
5+
mod soft_compact;
6+
use soft_compact::compress;
7+
} else if #[cfg(feature = "force-soft")] {
58
mod soft;
69
use soft::compress;
710
} else if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {

sha2/src/sha512/soft_compact.rs

+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
use crate::consts::K64;
2+
3+
fn to_u64s(block: &[u8; 128]) -> [u64; 16] {
4+
use core::convert::TryInto;
5+
let mut res = [0u64; 16];
6+
for i in 0..16 {
7+
let chunk = block[8 * i..][..8].try_into().unwrap();
8+
res[i] = u64::from_be_bytes(chunk);
9+
}
10+
res
11+
}
12+
13+
fn compress_u64(state: &mut [u64; 8], block: [u64; 16]) {
14+
let [mut a, mut b, mut c, mut d, mut e, mut f, mut g, mut h] = *state;
15+
16+
let mut w = [0; 80];
17+
w[..16].copy_from_slice(&block);
18+
19+
for i in 16..80 {
20+
let w15 = w[i - 15];
21+
let s0 = (w15.rotate_right(1)) ^ (w15.rotate_right(8)) ^ (w15 >> 7);
22+
let w2 = w[i - 2];
23+
let s1 = (w2.rotate_right(19)) ^ (w2.rotate_right(61)) ^ (w2 >> 6);
24+
w[i] = w[i - 16]
25+
.wrapping_add(s0)
26+
.wrapping_add(w[i - 7])
27+
.wrapping_add(s1);
28+
}
29+
30+
for i in 0..80 {
31+
let s1 = e.rotate_right(14) ^ e.rotate_right(18) ^ e.rotate_right(41);
32+
let ch = (e & f) ^ ((!e) & g);
33+
let t1 = s1
34+
.wrapping_add(ch)
35+
.wrapping_add(K64[i])
36+
.wrapping_add(w[i])
37+
.wrapping_add(h);
38+
let s0 = a.rotate_right(28) ^ a.rotate_right(34) ^ a.rotate_right(39);
39+
let maj = (a & b) ^ (a & c) ^ (b & c);
40+
let t2 = s0.wrapping_add(maj);
41+
42+
h = g;
43+
g = f;
44+
f = e;
45+
e = d.wrapping_add(t1);
46+
d = c;
47+
c = b;
48+
b = a;
49+
a = t1.wrapping_add(t2);
50+
}
51+
52+
state[0] = state[0].wrapping_add(a);
53+
state[1] = state[1].wrapping_add(b);
54+
state[2] = state[2].wrapping_add(c);
55+
state[3] = state[3].wrapping_add(d);
56+
state[4] = state[4].wrapping_add(e);
57+
state[5] = state[5].wrapping_add(f);
58+
state[6] = state[6].wrapping_add(g);
59+
state[7] = state[7].wrapping_add(h);
60+
}
61+
62+
pub fn compress(state: &mut [u64; 8], blocks: &[[u8; 128]]) {
63+
for block in blocks.iter() {
64+
compress_u64(state, to_u64s(block));
65+
}
66+
}

0 commit comments

Comments
 (0)