mirror of
https://github.com/RustCrypto/hashes.git
synced 2026-01-25 04:18:20 +00:00
k12: add Kt256; rename KangarooTwelve to Kt128 (#756)
This implement KT256 as specified in RFC 9861: https://www.rfc-editor.org/rfc/rfc9861.html Also, rename existing types `KangarooTwelve*` to `Kt128*` (e.g. `KangarooTwelveReader` to `Kt128Reader`). This is because the KangarooTwelve instance is specified as the KT128 instance in RFC 9861.[1] NOTE: For compatibility reasons, the existing types are defined as deprecated aliases for `Kt128*`. [1]: https://www.rfc-editor.org/rfc/rfc9861.html#section-1-3
This commit is contained in:
@@ -5,10 +5,19 @@ use digest::bench_update;
|
||||
use test::Bencher;
|
||||
|
||||
bench_update!(
|
||||
k12::KangarooTwelve::default();
|
||||
k12_10 10;
|
||||
k12_100 100;
|
||||
k12::Kt128::default();
|
||||
kt128_10 10;
|
||||
kt128_100 100;
|
||||
// the bigger sizes result in OOM
|
||||
// k12_1000 1000;
|
||||
// k12_10000 10000;
|
||||
// kt128_1000 1000;
|
||||
// kt128_10000 10000;
|
||||
);
|
||||
|
||||
bench_update!(
|
||||
k12::Kt256::default();
|
||||
kt256_10 10;
|
||||
kt256_100 100;
|
||||
// the bigger sizes result in OOM
|
||||
// kt256_1000 1000;
|
||||
// kt256_10000 10000;
|
||||
);
|
||||
|
||||
@@ -5,207 +5,250 @@ use digest::{
|
||||
AlgorithmName, Block, BlockSizeUser, Buffer, BufferKindUser, Eager, ExtendableOutputCore,
|
||||
UpdateCore, XofReaderCore,
|
||||
},
|
||||
consts::{U128, U168},
|
||||
consts::{U128, U136, U168},
|
||||
};
|
||||
use sha3::{TurboShake128, TurboShake128Reader};
|
||||
use sha3::{TurboShake128, TurboShake128Reader, TurboShake256, TurboShake256Reader};
|
||||
|
||||
const CHUNK_SIZE: usize = 8192;
|
||||
const CHAINING_VALUE_SIZE: usize = 32;
|
||||
const LENGTH_ENCODE_SIZE: usize = 255;
|
||||
|
||||
/// Core [`KangarooTwelve`] hasher state.
|
||||
#[derive(Clone)]
|
||||
#[allow(non_camel_case_types)]
|
||||
pub struct KangarooTwelveCore<'cs> {
|
||||
customization: &'cs [u8],
|
||||
buffer: [u8; CHUNK_SIZE],
|
||||
bufpos: usize,
|
||||
final_tshk: TurboShake128<0x06>,
|
||||
chain_tshk: TurboShake128<0x0B>,
|
||||
chain_length: usize,
|
||||
}
|
||||
|
||||
impl<'cs> KangarooTwelveCore<'cs> {
|
||||
/// Creates a new KangarooTwelve instance with the given customization.
|
||||
pub fn new(customization: &'cs [u8]) -> Self {
|
||||
Self {
|
||||
customization,
|
||||
buffer: [0u8; CHUNK_SIZE],
|
||||
bufpos: 0usize,
|
||||
final_tshk: Default::default(),
|
||||
chain_tshk: Default::default(),
|
||||
chain_length: 0usize,
|
||||
}
|
||||
}
|
||||
|
||||
fn process_chunk(&mut self) {
|
||||
debug_assert!(self.bufpos == CHUNK_SIZE);
|
||||
if self.chain_length == 0 {
|
||||
self.final_tshk.update(&self.buffer);
|
||||
} else {
|
||||
self.process_chaining_chunk();
|
||||
macro_rules! impl_k12_core {
|
||||
(
|
||||
$name:ident, $reader_name:ident, $ts_name:ident, $ts_reader_name:ident, $cv_size:literal,
|
||||
$alg_name:literal,
|
||||
) => {
|
||||
#[doc = "Core"]
|
||||
#[doc = $alg_name]
|
||||
#[doc = "hasher state."]
|
||||
#[derive(Clone)]
|
||||
#[allow(non_camel_case_types)]
|
||||
pub struct $name<'cs> {
|
||||
customization: &'cs [u8],
|
||||
buffer: [u8; CHUNK_SIZE],
|
||||
bufpos: usize,
|
||||
final_tshk: $ts_name<0x06>,
|
||||
chain_tshk: $ts_name<0x0B>,
|
||||
chain_length: usize,
|
||||
}
|
||||
|
||||
self.chain_length += 1;
|
||||
self.buffer = [0u8; CHUNK_SIZE];
|
||||
self.bufpos = 0;
|
||||
}
|
||||
impl<'cs> $name<'cs> {
|
||||
const CHAINING_VALUE_SIZE: usize = $cv_size;
|
||||
|
||||
fn process_chaining_chunk(&mut self) {
|
||||
debug_assert!(self.bufpos != 0);
|
||||
if self.chain_length == 1 {
|
||||
self.final_tshk
|
||||
.update(&[0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
|
||||
}
|
||||
|
||||
let mut result = [0u8; CHAINING_VALUE_SIZE];
|
||||
self.chain_tshk.update(&self.buffer[..self.bufpos]);
|
||||
self.chain_tshk.finalize_xof_reset_into(&mut result);
|
||||
self.final_tshk.update(&result);
|
||||
}
|
||||
}
|
||||
|
||||
impl HashMarker for KangarooTwelveCore<'_> {}
|
||||
|
||||
impl BlockSizeUser for KangarooTwelveCore<'_> {
|
||||
type BlockSize = U128;
|
||||
}
|
||||
|
||||
impl BufferKindUser for KangarooTwelveCore<'_> {
|
||||
type BufferKind = Eager;
|
||||
}
|
||||
|
||||
impl UpdateCore for KangarooTwelveCore<'_> {
|
||||
#[inline]
|
||||
fn update_blocks(&mut self, blocks: &[Block<Self>]) {
|
||||
for block in blocks {
|
||||
if self.bufpos == CHUNK_SIZE {
|
||||
self.process_chunk();
|
||||
#[doc = "Creates a new"]
|
||||
#[doc = $alg_name]
|
||||
#[doc = "instance with the given customization."]
|
||||
pub fn new(customization: &'cs [u8]) -> Self {
|
||||
Self {
|
||||
customization,
|
||||
buffer: [0u8; CHUNK_SIZE],
|
||||
bufpos: 0usize,
|
||||
final_tshk: Default::default(),
|
||||
chain_tshk: Default::default(),
|
||||
chain_length: 0usize,
|
||||
}
|
||||
}
|
||||
|
||||
self.buffer[self.bufpos..self.bufpos + 128].clone_from_slice(block);
|
||||
self.bufpos += 128;
|
||||
}
|
||||
}
|
||||
}
|
||||
fn process_chunk(&mut self) {
|
||||
debug_assert!(self.bufpos == CHUNK_SIZE);
|
||||
if self.chain_length == 0 {
|
||||
self.final_tshk.update(&self.buffer);
|
||||
} else {
|
||||
self.process_chaining_chunk();
|
||||
}
|
||||
|
||||
impl ExtendableOutputCore for KangarooTwelveCore<'_> {
|
||||
type ReaderCore = KangarooTwelveReaderCore;
|
||||
self.chain_length += 1;
|
||||
self.buffer = [0u8; CHUNK_SIZE];
|
||||
self.bufpos = 0;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn finalize_xof_core(&mut self, buffer: &mut Buffer<Self>) -> Self::ReaderCore {
|
||||
let mut lenbuf = [0u8; LENGTH_ENCODE_SIZE];
|
||||
fn process_chaining_chunk(&mut self) {
|
||||
debug_assert!(self.bufpos != 0);
|
||||
if self.chain_length == 1 {
|
||||
self.final_tshk
|
||||
.update(&[0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
|
||||
}
|
||||
|
||||
// Digest customization
|
||||
buffer.digest_blocks(self.customization, |block| self.update_blocks(block));
|
||||
buffer.digest_blocks(
|
||||
length_encode(self.customization.len(), &mut lenbuf),
|
||||
|block| self.update_blocks(block),
|
||||
);
|
||||
|
||||
if self.bufpos == CHUNK_SIZE && buffer.get_pos() != 0 {
|
||||
self.process_chunk();
|
||||
let mut result = [0u8; Self::CHAINING_VALUE_SIZE];
|
||||
self.chain_tshk.update(&self.buffer[..self.bufpos]);
|
||||
self.chain_tshk.finalize_xof_reset_into(&mut result);
|
||||
self.final_tshk.update(&result);
|
||||
}
|
||||
}
|
||||
|
||||
// Read leftover data from buffer
|
||||
self.buffer[self.bufpos..(self.bufpos + buffer.get_pos())]
|
||||
.copy_from_slice(buffer.get_data());
|
||||
self.bufpos += buffer.get_pos();
|
||||
impl HashMarker for $name<'_> {}
|
||||
|
||||
// Calculate final node
|
||||
if self.chain_length == 0 {
|
||||
// Input did not exceed a single chaining value
|
||||
let tshk = TurboShake128::<0x07>::default()
|
||||
.chain(&self.buffer[..self.bufpos])
|
||||
.finalize_xof_reset();
|
||||
return KangarooTwelveReaderCore { tshk };
|
||||
impl BlockSizeUser for $name<'_> {
|
||||
type BlockSize = U128;
|
||||
}
|
||||
|
||||
// Calculate last chaining value
|
||||
self.process_chaining_chunk();
|
||||
|
||||
// Pad final node calculation
|
||||
self.final_tshk
|
||||
.update(length_encode(self.chain_length, &mut lenbuf));
|
||||
self.final_tshk.update(&[0xff, 0xff]);
|
||||
|
||||
KangarooTwelveReaderCore {
|
||||
tshk: self.final_tshk.finalize_xof_reset(),
|
||||
impl BufferKindUser for $name<'_> {
|
||||
type BufferKind = Eager;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for KangarooTwelveCore<'_> {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
customization: &[],
|
||||
buffer: [0u8; CHUNK_SIZE],
|
||||
bufpos: 0usize,
|
||||
final_tshk: Default::default(),
|
||||
chain_tshk: Default::default(),
|
||||
chain_length: 0usize,
|
||||
impl UpdateCore for $name<'_> {
|
||||
#[inline]
|
||||
fn update_blocks(&mut self, blocks: &[Block<Self>]) {
|
||||
for block in blocks {
|
||||
if self.bufpos == CHUNK_SIZE {
|
||||
self.process_chunk();
|
||||
}
|
||||
|
||||
self.buffer[self.bufpos..self.bufpos + 128].clone_from_slice(block);
|
||||
self.bufpos += 128;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Reset for KangarooTwelveCore<'_> {
|
||||
#[inline]
|
||||
fn reset(&mut self) {
|
||||
*self = Self::new(self.customization);
|
||||
}
|
||||
}
|
||||
impl ExtendableOutputCore for $name<'_> {
|
||||
type ReaderCore = $reader_name;
|
||||
|
||||
impl AlgorithmName for KangarooTwelveCore<'_> {
|
||||
fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str(stringify!(KangarooTwelve))
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
fn finalize_xof_core(&mut self, buffer: &mut Buffer<Self>) -> Self::ReaderCore {
|
||||
let mut lenbuf = [0u8; LENGTH_ENCODE_SIZE];
|
||||
|
||||
impl fmt::Debug for KangarooTwelveCore<'_> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str(concat!(stringify!(KangarooTwelveCore), " { ... }"))
|
||||
}
|
||||
}
|
||||
// Digest customization
|
||||
buffer.digest_blocks(self.customization, |block| self.update_blocks(block));
|
||||
buffer.digest_blocks(
|
||||
length_encode(self.customization.len(), &mut lenbuf),
|
||||
|block| self.update_blocks(block),
|
||||
);
|
||||
|
||||
if self.bufpos == CHUNK_SIZE && buffer.get_pos() != 0 {
|
||||
self.process_chunk();
|
||||
}
|
||||
|
||||
// Read leftover data from buffer
|
||||
self.buffer[self.bufpos..(self.bufpos + buffer.get_pos())]
|
||||
.copy_from_slice(buffer.get_data());
|
||||
self.bufpos += buffer.get_pos();
|
||||
|
||||
// Calculate final node
|
||||
if self.chain_length == 0 {
|
||||
// Input did not exceed a single chaining value
|
||||
let tshk = $ts_name::<0x07>::default()
|
||||
.chain(&self.buffer[..self.bufpos])
|
||||
.finalize_xof_reset();
|
||||
return $reader_name { tshk };
|
||||
}
|
||||
|
||||
// Calculate last chaining value
|
||||
self.process_chaining_chunk();
|
||||
|
||||
// Pad final node calculation
|
||||
self.final_tshk
|
||||
.update(length_encode(self.chain_length, &mut lenbuf));
|
||||
self.final_tshk.update(&[0xff, 0xff]);
|
||||
|
||||
$reader_name {
|
||||
tshk: self.final_tshk.finalize_xof_reset(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for $name<'_> {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
customization: &[],
|
||||
buffer: [0u8; CHUNK_SIZE],
|
||||
bufpos: 0usize,
|
||||
final_tshk: Default::default(),
|
||||
chain_tshk: Default::default(),
|
||||
chain_length: 0usize,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Reset for $name<'_> {
|
||||
#[inline]
|
||||
fn reset(&mut self) {
|
||||
*self = Self::new(self.customization);
|
||||
}
|
||||
}
|
||||
|
||||
impl AlgorithmName for $name<'_> {
|
||||
fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str($alg_name)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for $name<'_> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str(concat!(stringify!($name), " { ... }"))
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for $name<'_> {
|
||||
fn drop(&mut self) {
|
||||
#[cfg(feature = "zeroize")]
|
||||
{
|
||||
use digest::zeroize::Zeroize;
|
||||
self.buffer.zeroize();
|
||||
self.bufpos.zeroize();
|
||||
self.chain_length.zeroize();
|
||||
// final_tshk and chain_tshk zeroized by their Drop impl
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for KangarooTwelveCore<'_> {
|
||||
fn drop(&mut self) {
|
||||
#[cfg(feature = "zeroize")]
|
||||
{
|
||||
use digest::zeroize::Zeroize;
|
||||
self.buffer.zeroize();
|
||||
self.bufpos.zeroize();
|
||||
self.chain_length.zeroize();
|
||||
// final_tshk and chain_tshk zeroized by their Drop impl
|
||||
impl digest::zeroize::ZeroizeOnDrop for $name<'_> {}
|
||||
|
||||
#[doc = "Core"]
|
||||
#[doc = $alg_name]
|
||||
#[doc = "reader state."]
|
||||
#[derive(Clone)]
|
||||
pub struct $reader_name {
|
||||
tshk: $ts_reader_name,
|
||||
}
|
||||
}
|
||||
|
||||
impl XofReaderCore for $reader_name {
|
||||
#[inline]
|
||||
fn read_block(&mut self) -> Block<Self> {
|
||||
let mut block = Block::<Self>::default();
|
||||
self.tshk.read(&mut block);
|
||||
block
|
||||
}
|
||||
}
|
||||
|
||||
// `Sha3ReaderCore` and the wrapper are zeroized by their Drop impls
|
||||
#[cfg(feature = "zeroize")]
|
||||
impl digest::zeroize::ZeroizeOnDrop for $reader_name {}
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "zeroize")]
|
||||
impl digest::zeroize::ZeroizeOnDrop for KangarooTwelveCore<'_> {}
|
||||
impl_k12_core!(
|
||||
Kt128Core,
|
||||
Kt128ReaderCore,
|
||||
TurboShake128,
|
||||
TurboShake128Reader,
|
||||
32,
|
||||
"KT128",
|
||||
);
|
||||
impl_k12_core!(
|
||||
Kt256Core,
|
||||
Kt256ReaderCore,
|
||||
TurboShake256,
|
||||
TurboShake256Reader,
|
||||
64,
|
||||
"KT256",
|
||||
);
|
||||
|
||||
/// Core [`KangarooTwelve`] reader state.
|
||||
#[derive(Clone)]
|
||||
pub struct KangarooTwelveReaderCore {
|
||||
tshk: TurboShake128Reader,
|
||||
}
|
||||
|
||||
impl BlockSizeUser for KangarooTwelveReaderCore {
|
||||
impl BlockSizeUser for Kt128ReaderCore {
|
||||
type BlockSize = U168; // TurboSHAKE128 block size
|
||||
}
|
||||
|
||||
impl XofReaderCore for KangarooTwelveReaderCore {
|
||||
#[inline]
|
||||
fn read_block(&mut self) -> Block<Self> {
|
||||
let mut block = Block::<Self>::default();
|
||||
self.tshk.read(&mut block);
|
||||
block
|
||||
}
|
||||
impl BlockSizeUser for Kt256ReaderCore {
|
||||
type BlockSize = U136; // TurboSHAKE256 block size
|
||||
}
|
||||
|
||||
// `TurboShake128ReaderCore` and the wrapper are zeroized by their Drop impls
|
||||
#[cfg(feature = "zeroize")]
|
||||
impl digest::zeroize::ZeroizeOnDrop for KangarooTwelveReaderCore {}
|
||||
/// Core KT128 hasher state.
|
||||
#[deprecated(since = "0.4.0-pre", note = "use `Kt128Core` instead")]
|
||||
pub type KangarooTwelveCore<'cs> = Kt128Core<'cs>;
|
||||
|
||||
/// Core KT128 reader state.
|
||||
#[deprecated(since = "0.4.0-pre", note = "use `Kt128ReaderCore` instead")]
|
||||
pub type KangarooTwelveReaderCore = Kt128ReaderCore;
|
||||
|
||||
fn length_encode(mut length: usize, buffer: &mut [u8; LENGTH_ENCODE_SIZE]) -> &mut [u8] {
|
||||
let mut bufpos = 0usize;
|
||||
|
||||
203
k12/src/lib.rs
203
k12/src/lib.rs
@@ -18,97 +18,138 @@ use digest::{
|
||||
CollisionResistance, ExtendableOutput, HashMarker, Reset, Update, XofReader,
|
||||
block_api::{AlgorithmName, BlockSizeUser, ExtendableOutputCore, UpdateCore, XofReaderCore},
|
||||
block_buffer::{BlockBuffer, Eager, ReadBuffer},
|
||||
consts::{U16, U128, U168},
|
||||
consts::{U16, U32, U128, U136, U168},
|
||||
};
|
||||
|
||||
/// `KangarooTwelve` hasher.
|
||||
#[derive(Default, Clone)]
|
||||
pub struct KangarooTwelve<'cs> {
|
||||
core: block_api::KangarooTwelveCore<'cs>,
|
||||
buffer: BlockBuffer<U128, Eager>,
|
||||
}
|
||||
|
||||
impl<'cs> KangarooTwelve<'cs> {
|
||||
/// Creates a new KangarooTwelve instance with the given customization.
|
||||
pub fn new(customization: &'cs [u8]) -> Self {
|
||||
Self {
|
||||
core: block_api::KangarooTwelveCore::new(customization),
|
||||
buffer: Default::default(),
|
||||
macro_rules! impl_k12 {
|
||||
(
|
||||
$name:ident, $reader_name:ident, $core_name:ident, $reader_core_name:ident, $rate:ty,
|
||||
$alg_name:literal,
|
||||
) => {
|
||||
#[doc = $alg_name]
|
||||
#[doc = "hasher."]
|
||||
#[derive(Default, Clone)]
|
||||
pub struct $name<'cs> {
|
||||
core: block_api::$core_name<'cs>,
|
||||
buffer: BlockBuffer<U128, Eager>,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for KangarooTwelve<'_> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
|
||||
f.write_str("KangarooTwelve { .. }")
|
||||
}
|
||||
}
|
||||
|
||||
impl AlgorithmName for KangarooTwelve<'_> {
|
||||
fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str("KangarooTwelve")
|
||||
}
|
||||
}
|
||||
|
||||
impl HashMarker for KangarooTwelve<'_> {}
|
||||
|
||||
impl BlockSizeUser for KangarooTwelve<'_> {
|
||||
type BlockSize = U128;
|
||||
}
|
||||
|
||||
impl Update for KangarooTwelve<'_> {
|
||||
fn update(&mut self, data: &[u8]) {
|
||||
let Self { core, buffer } = self;
|
||||
buffer.digest_blocks(data, |blocks| core.update_blocks(blocks));
|
||||
}
|
||||
}
|
||||
|
||||
impl Reset for KangarooTwelve<'_> {
|
||||
fn reset(&mut self) {
|
||||
self.core.reset();
|
||||
self.buffer.reset();
|
||||
}
|
||||
}
|
||||
|
||||
impl ExtendableOutput for KangarooTwelve<'_> {
|
||||
type Reader = KangarooTwelveReader;
|
||||
|
||||
#[inline]
|
||||
fn finalize_xof(mut self) -> Self::Reader {
|
||||
Self::Reader {
|
||||
core: self.core.finalize_xof_core(&mut self.buffer),
|
||||
buffer: Default::default(),
|
||||
impl<'cs> $name<'cs> {
|
||||
#[doc = "Creates a new"]
|
||||
#[doc = $alg_name]
|
||||
#[doc = "instance with the given customization."]
|
||||
pub fn new(customization: &'cs [u8]) -> Self {
|
||||
Self {
|
||||
core: block_api::$core_name::new(customization),
|
||||
buffer: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for $name<'_> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
|
||||
f.write_str(concat!(stringify!($name), " { .. }"))
|
||||
}
|
||||
}
|
||||
|
||||
impl AlgorithmName for $name<'_> {
|
||||
fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str($alg_name)
|
||||
}
|
||||
}
|
||||
|
||||
impl HashMarker for $name<'_> {}
|
||||
|
||||
impl BlockSizeUser for $name<'_> {
|
||||
type BlockSize = U128;
|
||||
}
|
||||
|
||||
impl Update for $name<'_> {
|
||||
fn update(&mut self, data: &[u8]) {
|
||||
let Self { core, buffer } = self;
|
||||
buffer.digest_blocks(data, |blocks| core.update_blocks(blocks));
|
||||
}
|
||||
}
|
||||
|
||||
impl Reset for $name<'_> {
|
||||
fn reset(&mut self) {
|
||||
self.core.reset();
|
||||
self.buffer.reset();
|
||||
}
|
||||
}
|
||||
|
||||
impl ExtendableOutput for $name<'_> {
|
||||
type Reader = $reader_name;
|
||||
|
||||
#[inline]
|
||||
fn finalize_xof(mut self) -> Self::Reader {
|
||||
Self::Reader {
|
||||
core: self.core.finalize_xof_core(&mut self.buffer),
|
||||
buffer: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "zeroize")]
|
||||
impl digest::zeroize::ZeroizeOnDrop for $name<'_> {}
|
||||
|
||||
#[doc = $alg_name]
|
||||
#[doc = "XOF reader."]
|
||||
pub struct $reader_name {
|
||||
core: block_api::$reader_core_name,
|
||||
buffer: ReadBuffer<$rate>,
|
||||
}
|
||||
|
||||
impl fmt::Debug for $reader_name {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
|
||||
f.write_str(concat!(stringify!($reader_name), " { .. }"))
|
||||
}
|
||||
}
|
||||
|
||||
impl XofReader for $reader_name {
|
||||
#[inline]
|
||||
fn read(&mut self, buffer: &mut [u8]) {
|
||||
let Self { core, buffer: buf } = self;
|
||||
buf.read(buffer, |block| *block = core.read_block());
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "zeroize")]
|
||||
impl digest::zeroize::ZeroizeOnDrop for $reader_name {}
|
||||
};
|
||||
}
|
||||
|
||||
impl CollisionResistance for KangarooTwelve<'_> {
|
||||
// https://www.ietf.org/archive/id/draft-irtf-cfrg-kangarootwelve-17.html#section-7-7
|
||||
impl_k12!(
|
||||
Kt128,
|
||||
Kt128Reader,
|
||||
Kt128Core,
|
||||
Kt128ReaderCore,
|
||||
U168,
|
||||
"KT128",
|
||||
);
|
||||
impl_k12!(
|
||||
Kt256,
|
||||
Kt256Reader,
|
||||
Kt256Core,
|
||||
Kt256ReaderCore,
|
||||
U136,
|
||||
"KT256",
|
||||
);
|
||||
|
||||
impl CollisionResistance for Kt128<'_> {
|
||||
// https://www.rfc-editor.org/rfc/rfc9861.html#section-7-7
|
||||
type CollisionResistance = U16;
|
||||
}
|
||||
|
||||
#[cfg(feature = "zeroize")]
|
||||
impl digest::zeroize::ZeroizeOnDrop for KangarooTwelve<'_> {}
|
||||
|
||||
/// `KangarooTwelve` XOF reader.
|
||||
pub struct KangarooTwelveReader {
|
||||
core: block_api::KangarooTwelveReaderCore,
|
||||
buffer: ReadBuffer<U168>,
|
||||
impl CollisionResistance for Kt256<'_> {
|
||||
// https://www.rfc-editor.org/rfc/rfc9861.html#section-7-8
|
||||
type CollisionResistance = U32;
|
||||
}
|
||||
|
||||
impl fmt::Debug for KangarooTwelveReader {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
|
||||
f.write_str("KangarooTwelveReader { .. }")
|
||||
}
|
||||
}
|
||||
/// KT128 hasher.
|
||||
#[deprecated(since = "0.4.0-pre", note = "use `Kt128` instead")]
|
||||
pub type KangarooTwelve<'cs> = Kt128<'cs>;
|
||||
|
||||
impl XofReader for KangarooTwelveReader {
|
||||
#[inline]
|
||||
fn read(&mut self, buffer: &mut [u8]) {
|
||||
let Self { core, buffer: buf } = self;
|
||||
buf.read(buffer, |block| *block = core.read_block());
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "zeroize")]
|
||||
impl digest::zeroize::ZeroizeOnDrop for KangarooTwelveReader {}
|
||||
/// KT128 XOF reader.
|
||||
#[deprecated(since = "0.4.0-pre", note = "use `Kt128Reader` instead")]
|
||||
pub type KangarooTwelveReader = Kt128Reader;
|
||||
|
||||
146
k12/tests/mod.rs
146
k12/tests/mod.rs
@@ -1,26 +1,34 @@
|
||||
use core::iter;
|
||||
use hex_literal::hex;
|
||||
use k12::{
|
||||
KangarooTwelve,
|
||||
Kt128, Kt256,
|
||||
digest::{ExtendableOutput, Update},
|
||||
};
|
||||
|
||||
fn digest_and_box(data: &[u8], n: usize) -> Box<[u8]> {
|
||||
let mut h = KangarooTwelve::default();
|
||||
h.update(data);
|
||||
h.finalize_boxed(n)
|
||||
macro_rules! digest_and_box {
|
||||
($name:ident, $hasher:ty) => {
|
||||
fn $name(data: &[u8], n: usize) -> Box<[u8]> {
|
||||
let mut h = <$hasher>::default();
|
||||
h.update(data);
|
||||
h.finalize_boxed(n)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
digest_and_box!(kt128_digest_and_box, Kt128);
|
||||
digest_and_box!(kt256_digest_and_box, Kt256);
|
||||
|
||||
// Source: <https://www.rfc-editor.org/rfc/rfc9861.html#section-5>
|
||||
|
||||
#[test]
|
||||
fn empty() {
|
||||
// Source: reference paper
|
||||
fn kt128_empty() {
|
||||
assert_eq!(
|
||||
digest_and_box(b"", 32)[..],
|
||||
kt128_digest_and_box(b"", 32)[..],
|
||||
hex!("1ac2d450fc3b4205d19da7bfca1b37513c0803577ac7167f06fe2ce1f0ef39e5")[..]
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
digest_and_box(b"", 64)[..],
|
||||
kt128_digest_and_box(b"", 64)[..],
|
||||
hex!(
|
||||
"1ac2d450fc3b4205d19da7bfca1b37513c0803577ac7167f06fe2ce1f0ef39e5"
|
||||
"4269c056b8c82e48276038b6d292966cc07a3d4645272e31ff38508139eb0a71"
|
||||
@@ -28,13 +36,42 @@ fn empty() {
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
digest_and_box(b"", 10032)[10000..],
|
||||
kt128_digest_and_box(b"", 10032)[10000..],
|
||||
hex!("e8dc563642f7228c84684c898405d3a834799158c079b12880277a1d28e2ff6d")[..]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pat_m() {
|
||||
fn kt256_empty() {
|
||||
assert_eq!(
|
||||
kt256_digest_and_box(b"", 64)[..],
|
||||
hex!(
|
||||
"b23d2e9cea9f4904e02bec06817fc10ce38ce8e93ef4c89e6537076af8646404"
|
||||
"e3e8b68107b8833a5d30490aa33482353fd4adc7148ecb782855003aaebde4a9"
|
||||
)[..],
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
kt256_digest_and_box(b"", 128)[..],
|
||||
hex!(
|
||||
"b23d2e9cea9f4904e02bec06817fc10ce38ce8e93ef4c89e6537076af8646404"
|
||||
"e3e8b68107b8833a5d30490aa33482353fd4adc7148ecb782855003aaebde4a9"
|
||||
"b0925319d8ea1e121a609821ec19efea89e6d08daee1662b69c840289f188ba8"
|
||||
"60f55760b61f82114c030c97e5178449608ccd2cd2d919fc7829ff69931ac4d0"
|
||||
)[..],
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
kt256_digest_and_box(b"", 10064)[10000..],
|
||||
hex!(
|
||||
"ad4a1d718cf950506709a4c33396139b4449041fc79a05d68da35f1e453522e0"
|
||||
"56c64fe94958e7085f2964888259b9932752f3ccd855288efee5fcbb8b563069"
|
||||
)[..],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn kt128_pat_m() {
|
||||
let expected = [
|
||||
hex!("2bda92450e8b147f8a7cb629e784a058efca7cf7d8218e02d345dfaa65244a1f"),
|
||||
hex!("6bf75fa2239198db4772e36478f8e19b0f371205f6a9a93a273f51df37122888"),
|
||||
@@ -49,13 +86,55 @@ fn pat_m() {
|
||||
{
|
||||
let len = 17usize.pow(i);
|
||||
let m: Vec<u8> = (0..len).map(|j| (j % 251) as u8).collect();
|
||||
let result = digest_and_box(&m, 32);
|
||||
let result = kt128_digest_and_box(&m, 32);
|
||||
assert_eq!(result[..], expected[i as usize][..]);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pat_c() {
|
||||
fn kt256_pat_m() {
|
||||
let expected = [
|
||||
hex!(
|
||||
"0d005a194085360217128cf17f91e1f71314efa5564539d444912e3437efa17f"
|
||||
"82db6f6ffe76e781eaa068bce01f2bbf81eacb983d7230f2fb02834a21b1ddd0"
|
||||
),
|
||||
hex!(
|
||||
"1ba3c02b1fc514474f06c8979978a9056c8483f4a1b63d0dccefe3a28a2f323e"
|
||||
"1cdcca40ebf006ac76ef0397152346837b1277d3e7faa9c9653b19075098527b"
|
||||
),
|
||||
hex!(
|
||||
"de8ccbc63e0f133ebb4416814d4c66f691bbf8b6a61ec0a7700f836b086cb029"
|
||||
"d54f12ac7159472c72db118c35b4e6aa213c6562caaa9dcc518959e69b10f3ba"
|
||||
),
|
||||
hex!(
|
||||
"647efb49fe9d717500171b41e7f11bd491544443209997ce1c2530d15eb1ffbb"
|
||||
"598935ef954528ffc152b1e4d731ee2683680674365cd191d562bae753b84aa5"
|
||||
),
|
||||
hex!(
|
||||
"b06275d284cd1cf205bcbe57dccd3ec1ff6686e3ed15776383e1f2fa3c6ac8f0"
|
||||
"8bf8a162829db1a44b2a43ff83dd89c3cf1ceb61ede659766d5ccf817a62ba8d"
|
||||
),
|
||||
hex!(
|
||||
"9473831d76a4c7bf77ace45b59f1458b1673d64bcd877a7c66b2664aa6dd149e"
|
||||
"60eab71b5c2bab858c074ded81ddce2b4022b5215935c0d4d19bf511aeeb0772"
|
||||
),
|
||||
hex!(
|
||||
"0652b740d78c5e1f7c8dcc1777097382768b7ff38f9a7a20f29f413bb1b3045b"
|
||||
"31a5578f568f911e09cf44746da84224a5266e96a4a535e871324e4f9c7004da"
|
||||
),
|
||||
];
|
||||
for i in 0..5
|
||||
/*NOTE: can be up to 7 but is slow*/
|
||||
{
|
||||
let len = 17usize.pow(i);
|
||||
let m: Vec<u8> = (0..len).map(|j| (j % 251) as u8).collect();
|
||||
let result = kt256_digest_and_box(&m, 64);
|
||||
assert_eq!(result[..], expected[i as usize][..]);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn kt128_pat_c() {
|
||||
let expected = [
|
||||
hex!("fab658db63e94a246188bf7af69a133045f46ee984c56e3c3328caaf1aa1a583"),
|
||||
hex!("d848c5068ced736f4462159b9867fd4c20b808acc3d5bc48e0b06ba0a3762ec4"),
|
||||
@@ -66,7 +145,7 @@ fn pat_c() {
|
||||
let m: Vec<u8> = iter::repeat_n(0xFF, 2usize.pow(i) - 1).collect();
|
||||
let len = 41usize.pow(i);
|
||||
let c: Vec<u8> = (0..len).map(|j| (j % 251) as u8).collect();
|
||||
let mut h = KangarooTwelve::new(&c);
|
||||
let mut h = Kt128::new(&c);
|
||||
h.update(&m);
|
||||
let result = h.finalize_boxed(32);
|
||||
assert_eq!(result[..], expected[i as usize][..]);
|
||||
@@ -74,7 +153,38 @@ fn pat_c() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn input_multiple_of_chunk_size_minus_one() {
|
||||
fn kt256_pat_c() {
|
||||
let expected = [
|
||||
hex!(
|
||||
"9280f5cc39b54a5a594ec63de0bb99371e4609d44bf845c2f5b8c316d72b1598"
|
||||
"11f748f23e3fabbe5c3226ec96c62186df2d33e9df74c5069ceecbb4dd10eff6"
|
||||
),
|
||||
hex!(
|
||||
"47ef96dd616f200937aa7847e34ec2feae8087e3761dc0f8c1a154f51dc9ccf8"
|
||||
"45d7adbce57ff64b639722c6a1672e3bf5372d87e00aff89be97240756998853"
|
||||
),
|
||||
hex!(
|
||||
"3b48667a5051c5966c53c5d42b95de451e05584e7806e2fb765eda959074172c"
|
||||
"b438a9e91dde337c98e9c41bed94c4e0aef431d0b64ef2324f7932caa6f54969"
|
||||
),
|
||||
hex!(
|
||||
"e0911cc00025e1540831e266d94add9b98712142b80d2629e643aac4efaf5a3a"
|
||||
"30a88cbf4ac2a91a2432743054fbcc9897670e86ba8cec2fc2ace9c966369724"
|
||||
),
|
||||
];
|
||||
for i in 0..4 {
|
||||
let m: Vec<u8> = iter::repeat_n(0xFF, 2usize.pow(i) - 1).collect();
|
||||
let len = 41usize.pow(i);
|
||||
let c: Vec<u8> = (0..len).map(|j| (j % 251) as u8).collect();
|
||||
let mut h = Kt256::new(&c);
|
||||
h.update(&m);
|
||||
let result = h.finalize_boxed(64);
|
||||
assert_eq!(result[..], expected[i as usize][..]);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn kt128_input_multiple_of_chunk_size_minus_one() {
|
||||
// generated with reference python implementation
|
||||
let expected = [
|
||||
hex!("1b577636f723643e990cc7d6a659837436fd6a103626600eb8301cd1dbe553d6"),
|
||||
@@ -85,13 +195,13 @@ fn input_multiple_of_chunk_size_minus_one() {
|
||||
for (i, exp_res) in expected.iter().enumerate() {
|
||||
let len = 8192 * (i + 1) - 1;
|
||||
let m: Vec<u8> = (0..len).map(|j| (j % 251) as u8).collect();
|
||||
let result = digest_and_box(&m, 32);
|
||||
let result = kt128_digest_and_box(&m, 32);
|
||||
assert_eq!(result[..], exp_res[..]);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn input_multiple_of_chunk_size() {
|
||||
fn kt128_input_multiple_of_chunk_size() {
|
||||
// generated with reference python implementation
|
||||
let expected = [
|
||||
hex!("48f256f6772f9edfb6a8b661ec92dc93b95ebd05a08a17b39ae3490870c926c3"),
|
||||
@@ -102,7 +212,7 @@ fn input_multiple_of_chunk_size() {
|
||||
for (i, exp_res) in expected.iter().enumerate() {
|
||||
let len = 8192 * (i + 1);
|
||||
let m: Vec<u8> = (0..len).map(|j| (j % 251) as u8).collect();
|
||||
let result = digest_and_box(&m, 32);
|
||||
let result = kt128_digest_and_box(&m, 32);
|
||||
assert_eq!(result[..], exp_res[..]);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user