sponges/bash-f/src/lib.rs
2025-10-24 01:26:08 +03:00

127 lines
3.8 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#![no_std]
#![doc = include_str!("../README.md")]
#![doc(
html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg",
html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg"
)]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![warn(missing_docs)]
/// Number of 64-bit words in the [`bash-f`][bash_f] state.
pub const STATE_WORDS: usize = 24;
/// `bash-s` transformation defined in Section 6.1 of STB 34.101.77-2020.
fn bash_s(
mut w0: u64,
mut w1: u64,
mut w2: u64,
m1: u32,
n1: u32,
m2: u32,
n2: u32,
) -> (u64, u64, u64) {
// 1. T0 ← RotHi^m1(W0)
let t0 = w0.rotate_left(m1);
// 2. W0 ← W0 ⊕ W1 ⊕ W2
w0 ^= w1 ^ w2;
// 3. T1 ← W1 ⊕ RotHi^n1(W0)
let t1 = w1 ^ w0.rotate_left(n1);
// 4. W1 ← T0 ⊕ T1
w1 = t0 ^ t1;
// 5. W2 ← W2 ⊕ RotHi^m2(W2) ⊕ RotHi^n2(T1)
w2 ^= w2.rotate_left(m2) ^ t1.rotate_left(n2);
// 6. T0 ← ¬W2
let t0 = !w2;
// 7. T1 ← W0 W2
let t1 = w0 | w2;
// 8. T2 ← W0 ∧ W1
let t2 = w0 & w1;
// 9. T0 ← T0 W1
let t0 = t0 | w1;
// 10. W1 ← W1 ⊕ T1
w1 ^= t1;
// 11. W2 ← W2 ⊕ T2
w2 ^= t2;
// 12. W0 ← W0 ⊕ T0
w0 ^= t0;
// 13. Return (W0, W1, W2)
(w0, w1, w2)
}
/// `bash-f` sponge permutation defined in Section 6.2 of STB 34.101.77-2020.
pub fn bash_f(state: &mut [u64; STATE_WORDS]) {
// 1. Split S into words (S0, S1, ..., S23)
// 2. C ← B194BAC80A08F53B (initialize round constant, swapped to little-endian)
let mut c: u64 = 0x3BF5080AC8BA94B1;
// 3. For i = 1, 2, ..., 24 perform 24 rounds
for _ in 0..STATE_WORDS {
// 3.1. Apply S-box layer with varying rotation parameters
// (m1, n1, m2, n2) ← (8, 53, 14, 1)
let (mut m1, mut n1, mut m2, mut n2) = (8, 53, 14, 1);
// 3.2. For j = 0, 1, ..., 7 apply bash-s to each of 8 columns
for j in 0..8 {
// 3.2.a. (Sj, S8+j, S16+j) ← bash-s(Sj, S8+j, S16+j, m1, n1, m2, n2)
let (s0, s1, s2) = bash_s(state[j], state[8 + j], state[16 + j], m1, n1, m2, n2);
state[j] = s0;
state[8 + j] = s1;
state[16 + j] = s2;
// 3.2.b. (m1, n1, m2, n2) ← (7·m1 mod 64, 7·n1 mod 64, 7·m2 mod 64, 7·n2 mod 64)
(m1, n1, m2, n2) = ((7 * m1) % 64, (7 * n1) % 64, (7 * m2) % 64, (7 * n2) % 64);
}
// 3.3. Apply word permutation
// S ← S15 ‖ S10 ‖ S9 ‖ S12 ‖ S11 ‖ S14 ‖ S13 ‖ S8 ‖
// S17 ‖ S16 ‖ S19 ‖ S18 ‖ S21 ‖ S20 ‖ S23 ‖ S22 ‖
// S6 ‖ S3 ‖ S0 ‖ S5 ‖ S2 ‖ S7 ‖ S4 ‖ S1
const INDEXES: [usize; STATE_WORDS] = [
15, 10, 9, 12, 11, 14, 13, 8, 17, 16, 19, 18, 21, 20, 23, 22, 6, 3, 0, 5, 2, 7, 4, 1,
];
*state = INDEXES.map(|i| state[i]);
// 3.4. S23 ← S23 ⊕ C (add round constant)
state[23] ^= c;
// 3.5. Update LFSR (Galois configuration)
// if ⌊C⌉ is even, then C ← ShLo(C)
// else C ← ShLo(C) ⊕ AED8E07F99E12BDC
if c & 1 == 0 {
c >>= 1;
} else {
c = (c >> 1) ^ 0xDC2BE1997FE0D8AE;
}
}
// 4. Return S - state is modified in place
}
/// Test vector from Table A.1 of STB 34.101.77-2020.
#[test]
fn test_bash_s() {
// Note that constants in the spec are provided using the LE order (see Section 4.2.2).
let w0 = 0xB194BAC80A08F53Bu64.swap_bytes();
let w1 = 0xE12BDC1AE28257ECu64.swap_bytes();
let w2 = 0xE9DEE72C8F0C0FA6u64.swap_bytes();
let (w0_out, w1_out, w2_out) = bash_s(w0, w1, w2, 8, 53, 14, 1);
assert_eq!(w0_out, 0x479E76129979DC5Fu64.swap_bytes());
assert_eq!(w1_out, 0x0F2B2C93ED128EDDu64.swap_bytes());
assert_eq!(w2_out, 0x41009B1B112DFEF3u64.swap_bytes());
}