sha2/
core_api.rs

1use crate::{consts, sha256::compress256, sha512::compress512};
2use core::{fmt, slice::from_ref};
3use digest::{
4    block_buffer::Eager,
5    core_api::{
6        AlgorithmName, Block, BlockSizeUser, Buffer, BufferKindUser, OutputSizeUser, TruncSide,
7        UpdateCore, VariableOutputCore,
8    },
9    typenum::{Unsigned, U128, U32, U64},
10    HashMarker, InvalidOutputSize, Output,
11};
12
13/// Core block-level SHA-256 hasher with variable output size.
14///
15/// Supports initialization only for 28 and 32 byte output sizes,
16/// i.e. 224 and 256 bits respectively.
17#[derive(Clone)]
18pub struct Sha256VarCore {
19    state: consts::State256,
20    block_len: u64,
21}
22
23impl HashMarker for Sha256VarCore {}
24
25impl BlockSizeUser for Sha256VarCore {
26    type BlockSize = U64;
27}
28
29impl BufferKindUser for Sha256VarCore {
30    type BufferKind = Eager;
31}
32
33impl UpdateCore for Sha256VarCore {
34    #[inline]
35    fn update_blocks(&mut self, blocks: &[Block<Self>]) {
36        self.block_len += blocks.len() as u64;
37        compress256(&mut self.state, blocks);
38    }
39}
40
41impl OutputSizeUser for Sha256VarCore {
42    type OutputSize = U32;
43}
44
45impl VariableOutputCore for Sha256VarCore {
46    const TRUNC_SIDE: TruncSide = TruncSide::Left;
47
48    #[inline]
49    fn new(output_size: usize) -> Result<Self, InvalidOutputSize> {
50        let state = match output_size {
51            28 => consts::H256_224,
52            32 => consts::H256_256,
53            _ => return Err(InvalidOutputSize),
54        };
55        let block_len = 0;
56        Ok(Self { state, block_len })
57    }
58
59    #[inline]
60    fn finalize_variable_core(&mut self, buffer: &mut Buffer<Self>, out: &mut Output<Self>) {
61        let bs = Self::BlockSize::U64;
62        let bit_len = 8 * (buffer.get_pos() as u64 + bs * self.block_len);
63        buffer.len64_padding_be(bit_len, |b| compress256(&mut self.state, from_ref(b)));
64
65        for (chunk, v) in out.chunks_exact_mut(4).zip(self.state.iter()) {
66            chunk.copy_from_slice(&v.to_be_bytes());
67        }
68    }
69}
70
71impl AlgorithmName for Sha256VarCore {
72    #[inline]
73    fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
74        f.write_str("Sha256")
75    }
76}
77
78impl fmt::Debug for Sha256VarCore {
79    #[inline]
80    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
81        f.write_str("Sha256VarCore { ... }")
82    }
83}
84
85/// Core block-level SHA-512 hasher with variable output size.
86///
87/// Supports initialization only for 28, 32, 48, and 64 byte output sizes,
88/// i.e. 224, 256, 384, and 512 bits respectively.
89#[derive(Clone)]
90pub struct Sha512VarCore {
91    state: consts::State512,
92    block_len: u128,
93}
94
95impl HashMarker for Sha512VarCore {}
96
97impl BlockSizeUser for Sha512VarCore {
98    type BlockSize = U128;
99}
100
101impl BufferKindUser for Sha512VarCore {
102    type BufferKind = Eager;
103}
104
105impl UpdateCore for Sha512VarCore {
106    #[inline]
107    fn update_blocks(&mut self, blocks: &[Block<Self>]) {
108        self.block_len += blocks.len() as u128;
109        compress512(&mut self.state, blocks);
110    }
111}
112
113impl OutputSizeUser for Sha512VarCore {
114    type OutputSize = U64;
115}
116
117impl VariableOutputCore for Sha512VarCore {
118    const TRUNC_SIDE: TruncSide = TruncSide::Left;
119
120    #[inline]
121    fn new(output_size: usize) -> Result<Self, InvalidOutputSize> {
122        let state = match output_size {
123            28 => consts::H512_224,
124            32 => consts::H512_256,
125            48 => consts::H512_384,
126            64 => consts::H512_512,
127            _ => return Err(InvalidOutputSize),
128        };
129        let block_len = 0;
130        Ok(Self { state, block_len })
131    }
132
133    #[inline]
134    fn finalize_variable_core(&mut self, buffer: &mut Buffer<Self>, out: &mut Output<Self>) {
135        let bs = Self::BlockSize::U64 as u128;
136        let bit_len = 8 * (buffer.get_pos() as u128 + bs * self.block_len);
137        buffer.len128_padding_be(bit_len, |b| compress512(&mut self.state, from_ref(b)));
138
139        for (chunk, v) in out.chunks_exact_mut(8).zip(self.state.iter()) {
140            chunk.copy_from_slice(&v.to_be_bytes());
141        }
142    }
143}
144
145impl AlgorithmName for Sha512VarCore {
146    #[inline]
147    fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
148        f.write_str("Sha512")
149    }
150}
151
152impl fmt::Debug for Sha512VarCore {
153    #[inline]
154    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
155        f.write_str("Sha512VarCore { ... }")
156    }
157}