1#![no_std]
2#![doc = include_str!("../README.md")]
3#![doc(
4 html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg",
5 html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg"
6)]
7#![cfg_attr(docsrs, feature(doc_cfg))]
8#![forbid(unsafe_code)]
9#![warn(missing_docs, missing_debug_implementations)]
10#![warn(unreachable_pub)]
11
12pub use digest::{self, Digest};
13
14use core::fmt;
15use digest::{
16 FixedOutput, FixedOutputReset, HashMarker, Output, OutputSizeUser, Reset, Update,
17 common::{
18 AlgorithmName, BlockSizeUser,
19 hazmat::{DeserializeStateError, SerializableState, SerializedState},
20 },
21 consts::{U28, U32, U48, U64, U72, U104, U136, U144, U200, U201},
22 typenum::Unsigned,
23};
24use keccak::{Keccak, State1600};
25
26#[cfg(feature = "oid")]
27mod oids;
28mod utils;
29
30macro_rules! impl_sha3_variants {
31 ($(
32 $(#[$attr:meta])*
33 $name:ident($rate_ty:ty, $out_len:ty, $pad:expr);
34 )*) => {$(
35 $(#[$attr])*
36 #[derive(Clone, Default)]
37 pub struct $name {
38 state: State1600,
39 cursor: sponge_cursor::SpongeCursor<{ <$rate_ty>::USIZE }>,
40 keccak: Keccak,
41 }
42
43 impl Reset for $name {
44 #[inline]
45 fn reset(&mut self) {
46 self.state = Default::default();
47 self.cursor = Default::default();
48 }
49 }
50
51 impl HashMarker for $name {}
52
53 impl Update for $name {
54 #[inline]
55 fn update(&mut self, data: &[u8]) {
56 self.keccak.with_f1600(|f1600| {
57 self.cursor.absorb_u64_le(&mut self.state, f1600, data);
58 });
59 }
60 }
61
62 impl BlockSizeUser for $name {
63 type BlockSize = $rate_ty;
64 }
65
66 impl OutputSizeUser for $name {
67 type OutputSize = $out_len;
68 }
69
70 impl FixedOutput for $name {
71 fn finalize_into(mut self, dst: &mut Output<Self>) {
72 utils::pad::<$pad, { <$rate_ty>::USIZE }>(&mut self.state, &self.cursor);
73 self.keccak.with_f1600(|f1600| {
74 f1600(&mut self.state);
75 utils::read_state(&mut self.state, dst);
76 });
77 }
78 }
79
80 impl FixedOutputReset for $name {
81 fn finalize_into_reset(&mut self, dst: &mut Output<Self>) {
82 utils::pad::<$pad, { <$rate_ty>::USIZE }>(&mut self.state, &self.cursor);
83 self.keccak.with_f1600(|f1600| {
84 f1600(&mut self.state);
85 utils::read_state(&mut self.state, dst);
86 });
87 Reset::reset(self);
88 }
89 }
90
91 impl AlgorithmName for $name {
92 #[inline]
93 fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
94 f.write_str(stringify!($name))
95 }
96 }
97
98 impl SerializableState for $name {
99 type SerializedStateSize = U201;
100
101 fn serialize(&self) -> SerializedState<Self> {
102 utils::serialize(&self.state, &self.cursor).into()
103 }
104
105 fn deserialize(
106 serialized_state: &SerializedState<Self>,
107 ) -> Result<Self, DeserializeStateError> {
108 utils::deserialize(serialized_state.into())
109 .ok_or(DeserializeStateError)
110 .map(|(state, cursor)| Self {
111 state,
112 cursor,
113 keccak: Keccak::new(),
114 })
115 }
116 }
117
118 impl fmt::Debug for $name {
119 #[inline]
120 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
121 f.write_str(concat!(stringify!($name), " { ... }"))
122 }
123 }
124
125 impl Drop for $name {
126 #[inline]
127 fn drop(&mut self) {
128 #[cfg(feature = "zeroize")]
129 {
130 use digest::zeroize::Zeroize;
131 self.state.zeroize();
132 self.cursor.zeroize();
133 }
134 }
135 }
136
137 #[cfg(feature = "zeroize")]
138 impl digest::zeroize::ZeroizeOnDrop for $name {}
139 )*};
140}
141
142const KECCAK_PAD: u8 = 0x01;
143const SHA3_PAD: u8 = 0x06;
144
145impl_sha3_variants!(
146 Sha3_224(U144, U28, SHA3_PAD);
148 Sha3_256(U136, U32, SHA3_PAD);
150 Sha3_384(U104, U48, SHA3_PAD);
152 Sha3_512(U72, U64, SHA3_PAD);
154
155 Keccak224(U144, U28, KECCAK_PAD);
157 Keccak256(U136, U32, KECCAK_PAD);
159 Keccak384(U104, U48, KECCAK_PAD);
161 Keccak512(U72, U64, KECCAK_PAD);
163
164 Keccak256Full(U136, U200, KECCAK_PAD);
166);