mirror of
https://github.com/rosenpass/rosenpass.git
synced 2026-02-27 22:13:12 -08:00
dev(ciphers): add implementation of shake256
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -1838,6 +1838,7 @@ dependencies = [
|
|||||||
"blake2",
|
"blake2",
|
||||||
"chacha20poly1305",
|
"chacha20poly1305",
|
||||||
"libcrux",
|
"libcrux",
|
||||||
|
"rosenpass-cipher-traits",
|
||||||
"rosenpass-constant-time",
|
"rosenpass-constant-time",
|
||||||
"rosenpass-oqs",
|
"rosenpass-oqs",
|
||||||
"rosenpass-secret-memory",
|
"rosenpass-secret-memory",
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ rosenpass-constant-time = { workspace = true }
|
|||||||
rosenpass-secret-memory = { workspace = true }
|
rosenpass-secret-memory = { workspace = true }
|
||||||
rosenpass-oqs = { workspace = true }
|
rosenpass-oqs = { workspace = true }
|
||||||
rosenpass-util = { workspace = true }
|
rosenpass-util = { workspace = true }
|
||||||
|
rosenpass-cipher-traits = { workspace = true }
|
||||||
static_assertions = { workspace = true }
|
static_assertions = { workspace = true }
|
||||||
zeroize = { workspace = true }
|
zeroize = { workspace = true }
|
||||||
chacha20poly1305 = { workspace = true }
|
chacha20poly1305 = { workspace = true }
|
||||||
|
|||||||
65
ciphers/src/subtle/hash_functions/keyed_shake256.rs
Normal file
65
ciphers/src/subtle/hash_functions/keyed_shake256.rs
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
use anyhow::ensure;
|
||||||
|
use sha3::digest::{ExtendableOutput, Update, XofReader};
|
||||||
|
use sha3::Shake256;
|
||||||
|
use rosenpass_cipher_traits::KeyedHash;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub struct SHAKE256Core<const KEY_LEN: usize, const HASH_LEN: usize>;
|
||||||
|
|
||||||
|
impl<const KEY_LEN: usize, const HASH_LEN: usize> KeyedHash<KEY_LEN, HASH_LEN> for SHAKE256Core<KEY_LEN, HASH_LEN> {
|
||||||
|
type Error = anyhow::Error;
|
||||||
|
|
||||||
|
/// TODO: Rework test
|
||||||
|
/// Provides a keyed hash function based on SHAKE256. To work for the protocol, the output length
|
||||||
|
/// and key length are fixed to 32 bytes (also see [KEY_LEN] and [HASH_LEN]).
|
||||||
|
///
|
||||||
|
/// Note that the SHAKE256 is designed for 64 bytes output length, which we truncate to 32 bytes
|
||||||
|
/// to work well with the overall protocol. Referring to Table 4 of FIPS 202, this offers the
|
||||||
|
/// same collision resistance as SHAKE128, but 256 bits of preimage resistance. We therefore
|
||||||
|
/// prefer a truncated SHAKE256 over SHAKE128.
|
||||||
|
///
|
||||||
|
/// TODO: Example/Test
|
||||||
|
/// #Examples
|
||||||
|
/// ```rust
|
||||||
|
/// # use rosenpass_ciphers::subtle::keyed_shake256::SHAKE256Core;
|
||||||
|
/// use rosenpass_cipher_traits::KeyedHash;
|
||||||
|
/// const KEY_LEN: usize = 32;
|
||||||
|
/// const HASH_LEN: usize = 32;
|
||||||
|
/// let key: [u8; 32] = [0; KEY_LEN];
|
||||||
|
/// let data: [u8; 32] = [255; 32]; // arbitrary data, could also be longer
|
||||||
|
/// // buffer for the hash output
|
||||||
|
/// let mut hash_data: [u8; 32] = [0u8; HASH_LEN];
|
||||||
|
///
|
||||||
|
/// assert!(SHAKE256Core::<32, 32>::keyed_hash(&key, &data, &mut hash_data).is_ok(), "Hashing has to return OK result");
|
||||||
|
/// # let expected_hash: &[u8] = &[44, 102, 248, 251, 141, 145, 55, 194, 165, 228, 156, 42, 220,
|
||||||
|
/// 108, 50, 224, 48, 19, 197, 253, 105, 136, 95, 34, 95, 203, 149, 192, 124, 223, 243, 87];
|
||||||
|
/// # assert_eq!(hash_data, expected_hash);
|
||||||
|
/// ```
|
||||||
|
fn keyed_hash(key: &[u8; KEY_LEN], data: &[u8], out: &mut [u8; HASH_LEN]) -> Result<(), Self::Error> {
|
||||||
|
// Since SHAKE256 is a XOF, we fix the output length manually to what is required for the
|
||||||
|
// protocol.
|
||||||
|
ensure!(out.len() == HASH_LEN);
|
||||||
|
// Not bothering with padding; the implementation
|
||||||
|
// uses appropriately sized keys.
|
||||||
|
ensure!(key.len() == KEY_LEN);
|
||||||
|
let mut shake256 = Shake256::default();
|
||||||
|
shake256.update(key);
|
||||||
|
shake256.update(data);
|
||||||
|
|
||||||
|
// Following the NIST recommendations in Section A.2 of the FIPS 202 standard,
|
||||||
|
// (pages 24/25, i.e., 32/33 in the PDF) we append the length of the input to the end of
|
||||||
|
// the input. This prevents that if the same input is used with two different output lengths,
|
||||||
|
// the shorter output is a prefix of the longer output. See the Section A.2 of the FIPS 202
|
||||||
|
// standard for more details.
|
||||||
|
// TODO: Explain why we do not include the length here
|
||||||
|
// shake256.update(&((HASH_LEN as u8).to_le_bytes()));
|
||||||
|
shake256.finalize_xof().read(out);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const KEY_LEN: usize, const HASH_LEN: usize> SHAKE256Core<KEY_LEN, HASH_LEN> {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self
|
||||||
|
}
|
||||||
|
}
|
||||||
1
ciphers/src/subtle/hash_functions/mod.rs
Normal file
1
ciphers/src/subtle/hash_functions/mod.rs
Normal file
@@ -0,0 +1 @@
|
|||||||
|
pub mod keyed_shake256;
|
||||||
@@ -11,3 +11,6 @@ pub mod chacha20poly1305_ietf;
|
|||||||
pub mod chacha20poly1305_ietf_libcrux;
|
pub mod chacha20poly1305_ietf_libcrux;
|
||||||
pub mod incorrect_hmac_blake2b;
|
pub mod incorrect_hmac_blake2b;
|
||||||
pub mod xchacha20poly1305_ietf;
|
pub mod xchacha20poly1305_ietf;
|
||||||
|
pub mod hash_functions;
|
||||||
|
|
||||||
|
pub use hash_functions::{keyed_shake256};
|
||||||
Reference in New Issue
Block a user