mirror of
https://github.com/uutils/coreutils.git
synced 2026-06-10 15:48:22 -07:00
uucore: Make Shake* algorithms optionally accept a length
This commit is contained in:
committed by
Dorian Péron
parent
280abcd619
commit
690b149b4b
@@ -57,7 +57,7 @@ macro_rules! bench_shake_algorithm {
|
||||
let data = text_data::generate_by_size(100, 80);
|
||||
|
||||
bencher.bench(|| {
|
||||
let mut shake = Shake128::new();
|
||||
let mut shake = Shake128::with_output_bits(256);
|
||||
shake.hash_update(&data);
|
||||
|
||||
// SHAKE algorithms can output any length, use 256 bits (32 bytes) for meaningful comparison
|
||||
@@ -76,7 +76,7 @@ macro_rules! bench_shake_algorithm {
|
||||
let data = text_data::generate_by_size(100, 80);
|
||||
|
||||
bencher.bench(|| {
|
||||
let mut shake = Shake256::new();
|
||||
let mut shake = Shake256::with_output_bits(512);
|
||||
shake.hash_update(&data);
|
||||
|
||||
// SHAKE algorithms can output any length, use 256 bits (32 bytes) for meaningful comparison
|
||||
|
||||
@@ -100,6 +100,16 @@ fn maybe_sanitize_length(
|
||||
sanitize_sha2_sha3_length_str(algo, s_len).map(Some)
|
||||
}
|
||||
|
||||
// SHAKE128 and SHAKE256 algorithms optionally take a bit length. No
|
||||
// validation is performed on this length, any value is valid. If the
|
||||
// given length is not a multiple of 8, the last byte of the output
|
||||
// will have its extra bits set to zero.
|
||||
(Some(AlgoKind::Shake128 | AlgoKind::Shake256), Some(len)) => match len.parse::<usize>() {
|
||||
Ok(0) => Ok(None),
|
||||
Ok(l) => Ok(Some(l)),
|
||||
Err(_) => Err(ChecksumError::InvalidLength(len.into()).into()),
|
||||
},
|
||||
|
||||
// For BLAKE2b, if a length is provided, validate it.
|
||||
(Some(AlgoKind::Blake2b), Some(len)) => calculate_blake2b_length_str(len),
|
||||
|
||||
|
||||
@@ -114,6 +114,9 @@ impl AlgoKind {
|
||||
ALGORITHM_OPTIONS_SHA256 => Sha256,
|
||||
ALGORITHM_OPTIONS_SHA384 => Sha384,
|
||||
ALGORITHM_OPTIONS_SHA512 => Sha512,
|
||||
|
||||
ALGORITHM_OPTIONS_SHAKE128 => Shake128,
|
||||
ALGORITHM_OPTIONS_SHAKE256 => Shake256,
|
||||
_ => return Err(ChecksumError::UnknownAlgorithm(algo.as_ref().to_string()).into()),
|
||||
})
|
||||
}
|
||||
@@ -247,8 +250,8 @@ pub enum SizedAlgoKind {
|
||||
Sha3(ShaLength),
|
||||
// Note: we store Blake2b's length as BYTES.
|
||||
Blake2b(Option<usize>),
|
||||
Shake128(usize),
|
||||
Shake256(usize),
|
||||
Shake128(Option<usize>),
|
||||
Shake256(Option<usize>),
|
||||
}
|
||||
|
||||
impl SizedAlgoKind {
|
||||
@@ -280,8 +283,8 @@ impl SizedAlgoKind {
|
||||
(ak::Sha1, _) => Ok(Self::Sha1),
|
||||
(ak::Blake3, _) => Ok(Self::Blake3),
|
||||
|
||||
(ak::Shake128, Some(l)) => Ok(Self::Shake128(l)),
|
||||
(ak::Shake256, Some(l)) => Ok(Self::Shake256(l)),
|
||||
(ak::Shake128, l) => Ok(Self::Shake128(l)),
|
||||
(ak::Shake256, l) => Ok(Self::Shake256(l)),
|
||||
(ak::Sha2, Some(l)) => Ok(Self::Sha2(ShaLength::try_from(l)?)),
|
||||
(ak::Sha3, Some(l)) => Ok(Self::Sha3(ShaLength::try_from(l)?)),
|
||||
(algo @ (ak::Sha2 | ak::Sha3), None) => {
|
||||
@@ -298,7 +301,6 @@ impl SizedAlgoKind {
|
||||
(ak::Sha256, None) => Ok(Self::Sha2(ShaLength::Len256)),
|
||||
(ak::Sha384, None) => Ok(Self::Sha2(ShaLength::Len384)),
|
||||
(ak::Sha512, None) => Ok(Self::Sha2(ShaLength::Len512)),
|
||||
(_, None) => Err(ChecksumError::LengthRequired(kind.to_uppercase().into()).into()),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -341,27 +343,30 @@ impl SizedAlgoKind {
|
||||
Self::Blake2b(len_opt) => Box::new(Blake2b::with_output_bytes(
|
||||
len_opt.unwrap_or(Blake2b::DEFAULT_BYTE_SIZE),
|
||||
)),
|
||||
Self::Shake128(_) => Box::new(Shake128::new()),
|
||||
Self::Shake256(_) => Box::new(Shake256::new()),
|
||||
Self::Shake128(len_opt) => Box::new(Shake128::with_output_bits(
|
||||
len_opt.unwrap_or(Shake128::DEFAULT_BIT_SIZE),
|
||||
)),
|
||||
Self::Shake256(len_opt) => Box::new(Shake256::with_output_bits(
|
||||
len_opt.unwrap_or(Shake256::DEFAULT_BIT_SIZE),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bitlen(&self) -> usize {
|
||||
use SizedAlgoKind::*;
|
||||
match self {
|
||||
Sysv => 512,
|
||||
Bsd => 1024,
|
||||
Crc => 256,
|
||||
Crc32b => 32,
|
||||
Md5 => 128,
|
||||
Sm3 => 512,
|
||||
Sha1 => 160,
|
||||
Blake3 => 256,
|
||||
Sha2(len) => len.as_usize(),
|
||||
Sha3(len) => len.as_usize(),
|
||||
Blake2b(len) => len.unwrap_or(512),
|
||||
Shake128(len) => *len,
|
||||
Shake256(len) => *len,
|
||||
Self::Sysv => 512,
|
||||
Self::Bsd => 1024,
|
||||
Self::Crc => 256,
|
||||
Self::Crc32b => 32,
|
||||
Self::Md5 => 128,
|
||||
Self::Sm3 => 512,
|
||||
Self::Sha1 => 160,
|
||||
Self::Blake3 => 256,
|
||||
Self::Sha2(len) => len.as_usize(),
|
||||
Self::Sha3(len) => len.as_usize(),
|
||||
Self::Blake2b(len) => len.unwrap_or(Blake2b::DEFAULT_BYTE_SIZE * 8),
|
||||
Self::Shake128(len) => len.unwrap_or(Shake128::DEFAULT_BIT_SIZE),
|
||||
Self::Shake256(len) => len.unwrap_or(Shake256::DEFAULT_BIT_SIZE),
|
||||
}
|
||||
}
|
||||
pub fn is_legacy(&self) -> bool {
|
||||
|
||||
@@ -377,27 +377,38 @@ macro_rules! impl_digest_common {
|
||||
|
||||
// Implements the Digest trait for sha2 / sha3 algorithms with variable output
|
||||
macro_rules! impl_digest_shake {
|
||||
($algo_type: ty, $output_bits: literal) => {
|
||||
($algo_type: ty, $default_output_bits: literal) => {
|
||||
impl $algo_type {
|
||||
pub fn new() -> Self {
|
||||
Self(Default::default())
|
||||
pub const DEFAULT_BIT_SIZE: usize = $default_output_bits;
|
||||
|
||||
pub fn with_output_bits(bits: usize) -> Self {
|
||||
Self {
|
||||
digest: Default::default(),
|
||||
bit_size: bits,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Digest for $algo_type {
|
||||
fn hash_update(&mut self, input: &[u8]) {
|
||||
digest::Update::update(&mut self.0, input);
|
||||
digest::Update::update(&mut self.digest, input);
|
||||
}
|
||||
|
||||
fn hash_finalize(&mut self, out: &mut [u8]) {
|
||||
digest::ExtendableOutputReset::finalize_xof_reset_into(&mut self.0, out);
|
||||
digest::ExtendableOutputReset::finalize_xof_reset_into(&mut self.digest, out);
|
||||
|
||||
// Remove the last bits if the requested length is not a multiple of 8.
|
||||
let extra = self.output_bits() % 8;
|
||||
if extra != 0 {
|
||||
out[out.len() - 1] &= (1 << extra) - 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn reset(&mut self) {
|
||||
*self = Self::new();
|
||||
*self = Self::with_output_bits(self.bit_size);
|
||||
}
|
||||
|
||||
fn output_bits(&self) -> usize {
|
||||
$output_bits
|
||||
self.bit_size
|
||||
}
|
||||
|
||||
fn result(&mut self) -> DigestOutput {
|
||||
@@ -431,8 +442,14 @@ impl_digest_common!(Sha3_256, 256);
|
||||
impl_digest_common!(Sha3_384, 384);
|
||||
impl_digest_common!(Sha3_512, 512);
|
||||
|
||||
pub struct Shake128(sha3::Shake128);
|
||||
pub struct Shake256(sha3::Shake256);
|
||||
pub struct Shake128 {
|
||||
digest: sha3::Shake128,
|
||||
bit_size: usize,
|
||||
}
|
||||
pub struct Shake256 {
|
||||
digest: sha3::Shake256,
|
||||
bit_size: usize,
|
||||
}
|
||||
impl_digest_shake!(Shake128, 256);
|
||||
impl_digest_shake!(Shake256, 512);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user