Skip to main content

libcrux_sha3/
lib.rs

1//! # SHA3
2//!
3//! A SHA3 implementation with optional simd optimisations.
4
5#![no_std]
6#![forbid(unsafe_code)]
7#![deny(missing_docs)]
8
9mod simd;
10
11mod generic_keccak;
12
13#[cfg(not(any(hax, eurydice)))]
14mod impl_digest_trait;
15#[cfg(not(any(hax, eurydice)))]
16pub use impl_digest_trait::*;
17
18#[cfg(hax)]
19use hax_lib::int::*;
20
21mod traits;
22
23/// Size in bytes of a SHA3 224 digest.
24pub const SHA3_224_DIGEST_SIZE: usize = 28;
25/// Size in bytes of a SHA3 256 digest.
26pub const SHA3_256_DIGEST_SIZE: usize = 32;
27/// Size in bytes of a SHA3 2384 digest.
28pub const SHA3_384_DIGEST_SIZE: usize = 48;
29/// Size in bytes of a SHA3 512 digest.
30pub const SHA3_512_DIGEST_SIZE: usize = 64;
31
32/// F* verification helper
33#[cfg(hax)]
34pub(crate) mod proof_utils;
35
36/// The Digest Algorithm.
37#[cfg_attr(not(eurydice), derive(Debug, PartialEq))]
38#[derive(Clone, Copy)]
39#[repr(u32)]
40pub enum Algorithm {
41    /// SHA3 224
42    Sha224 = 1,
43
44    /// SHA3 256
45    Sha256 = 2,
46
47    /// SHA3 384
48    Sha384 = 3,
49
50    /// SHA3 512
51    Sha512 = 4,
52}
53
54// Verification fails because of the panic
55#[cfg(not(any(hax, eurydice)))]
56impl From<u32> for Algorithm {
57    fn from(v: u32) -> Algorithm {
58        match v {
59            1 => Algorithm::Sha224,
60            2 => Algorithm::Sha256,
61            3 => Algorithm::Sha384,
62            4 => Algorithm::Sha512,
63            _ => panic!("Invalid SHA3 Algorithm code"),
64        }
65    }
66}
67
68impl From<Algorithm> for u32 {
69    fn from(v: Algorithm) -> u32 {
70        match v {
71            Algorithm::Sha224 => 1,
72            Algorithm::Sha256 => 2,
73            Algorithm::Sha384 => 3,
74            Algorithm::Sha512 => 4,
75        }
76    }
77}
78
79/// Returns the output size of a digest.
80pub const fn digest_size(mode: Algorithm) -> usize {
81    match mode {
82        Algorithm::Sha224 => SHA3_224_DIGEST_SIZE,
83        Algorithm::Sha256 => SHA3_256_DIGEST_SIZE,
84        Algorithm::Sha384 => SHA3_384_DIGEST_SIZE,
85        Algorithm::Sha512 => SHA3_512_DIGEST_SIZE,
86    }
87}
88
89/// SHA3
90#[hax_lib::fstar::options("--split_queries always")]
91#[hax_lib::requires(
92    payload.len().to_int() <= u32::MAX.to_int() &&
93    digest_size(algorithm) == LEN
94)]
95pub fn hash<const LEN: usize>(algorithm: Algorithm, payload: &[u8]) -> [u8; LEN] {
96    debug_assert!(payload.len() <= u32::MAX as usize);
97    debug_assert_eq!(digest_size(algorithm), LEN);
98
99    let mut out = [0u8; LEN];
100    match algorithm {
101        Algorithm::Sha224 => portable::sha224(&mut out, payload),
102        Algorithm::Sha256 => portable::sha256(&mut out, payload),
103        Algorithm::Sha384 => portable::sha384(&mut out, payload),
104        Algorithm::Sha512 => portable::sha512(&mut out, payload),
105    }
106    out
107}
108
109/// SHA3
110pub use hash as sha3;
111
112/// SHA3 224
113#[cfg_attr(not(eurydice), inline(always))]
114#[hax_lib::requires(
115    data.len().to_int() <= u32::MAX.to_int()
116)]
117pub fn sha224(data: &[u8]) -> [u8; SHA3_224_DIGEST_SIZE] {
118    let mut out = [0u8; SHA3_224_DIGEST_SIZE];
119    sha224_ema(&mut out, data);
120    out
121}
122
123/// SHA3 224
124///
125/// Preconditions:
126/// - `digest.len() == 28`
127#[cfg_attr(not(eurydice), inline(always))]
128#[hax_lib::requires(
129    payload.len().to_int() <= u32::MAX.to_int() &&
130    digest.len().to_int() == int!(28)
131)]
132pub fn sha224_ema(digest: &mut [u8], payload: &[u8]) {
133    debug_assert!(payload.len() <= u32::MAX as usize);
134    debug_assert!(digest.len() == 28);
135
136    portable::sha224(digest, payload)
137}
138
139/// SHA3 256
140#[cfg_attr(not(eurydice), inline(always))]
141#[hax_lib::requires(
142    data.len().to_int() <= u32::MAX.to_int()
143)]
144pub fn sha256(data: &[u8]) -> [u8; SHA3_256_DIGEST_SIZE] {
145    let mut out = [0u8; SHA3_256_DIGEST_SIZE];
146    sha256_ema(&mut out, data);
147    out
148}
149
150/// SHA3 256
151#[cfg_attr(not(eurydice), inline(always))]
152#[hax_lib::requires(
153    payload.len().to_int() <= u32::MAX.to_int() &&
154    digest.len().to_int() == int!(32)
155)]
156pub fn sha256_ema(digest: &mut [u8], payload: &[u8]) {
157    debug_assert!(payload.len() <= u32::MAX as usize);
158    debug_assert!(digest.len() == 32);
159
160    portable::sha256(digest, payload)
161}
162
163/// SHA3 384
164#[cfg_attr(not(eurydice), inline(always))]
165#[hax_lib::requires(
166    data.len().to_int() <= u32::MAX.to_int()
167)]
168pub fn sha384(data: &[u8]) -> [u8; SHA3_384_DIGEST_SIZE] {
169    let mut out = [0u8; SHA3_384_DIGEST_SIZE];
170    sha384_ema(&mut out, data);
171    out
172}
173
174/// SHA3 384
175#[cfg_attr(not(eurydice), inline(always))]
176#[hax_lib::requires(
177    payload.len().to_int() <= u32::MAX.to_int() &&
178    digest.len().to_int() == int!(48)
179)]
180pub fn sha384_ema(digest: &mut [u8], payload: &[u8]) {
181    debug_assert!(payload.len() <= u32::MAX as usize);
182    debug_assert!(digest.len() == 48);
183
184    portable::sha384(digest, payload)
185}
186
187/// SHA3 512
188#[cfg_attr(not(eurydice), inline(always))]
189#[hax_lib::requires(
190    data.len().to_int() <= u32::MAX.to_int()
191)]
192pub fn sha512(data: &[u8]) -> [u8; SHA3_512_DIGEST_SIZE] {
193    let mut out = [0u8; SHA3_512_DIGEST_SIZE];
194    sha512_ema(&mut out, data);
195    out
196}
197
198/// SHA3 512
199#[cfg_attr(not(eurydice), inline(always))]
200#[hax_lib::requires(
201    payload.len().to_int() <= u32::MAX.to_int() &&
202    digest.len().to_int() == int!(64)
203)]
204pub fn sha512_ema(digest: &mut [u8], payload: &[u8]) {
205    debug_assert!(payload.len() <= u32::MAX as usize);
206    debug_assert!(digest.len() == 64);
207
208    portable::sha512(digest, payload)
209}
210
211/// SHAKE 128
212///
213/// Note that the output length `BYTES` must fit into 32 bit. If it is longer,
214/// the output will only return `u32::MAX` bytes.
215#[cfg_attr(not(eurydice), inline(always))]
216pub fn shake128<const BYTES: usize>(data: &[u8]) -> [u8; BYTES] {
217    let mut out = [0u8; BYTES];
218    portable::shake128(&mut out, data);
219    out
220}
221
222/// SHAKE 128
223///
224/// Writes `out.len()` bytes.
225#[cfg_attr(not(eurydice), inline(always))]
226pub fn shake128_ema(out: &mut [u8], data: &[u8]) {
227    portable::shake128(out, data);
228}
229
230/// SHAKE 256
231///
232/// Note that the output length `BYTES` must fit into 32 bit. If it is longer,
233/// the output will only return `u32::MAX` bytes.
234#[cfg_attr(not(eurydice), inline(always))]
235pub fn shake256<const BYTES: usize>(data: &[u8]) -> [u8; BYTES] {
236    let mut out = [0u8; BYTES];
237    portable::shake256(&mut out, data);
238    out
239}
240
241/// SHAKE 256
242///
243/// Writes `out.len()` bytes.
244#[cfg_attr(not(eurydice), inline(always))]
245pub fn shake256_ema(out: &mut [u8], data: &[u8]) {
246    portable::shake256(out, data);
247}
248
249//  === Instantiation === //
250
251/// A portable SHA3 implementation without platform dependent optimisations.
252pub mod portable;
253
254/// A neon optimised implementation.
255///
256/// When this is compiled for non-neon architectures, the functions panic.
257/// The caller must make sure to check for hardware feature before calling these
258/// functions and compile them in.
259///
260/// Feature `simd128` enables the implementations in this module.
261#[cfg(feature = "simd128")]
262pub mod neon;
263
264/// An AVX2 optimised implementation.
265///
266/// When this is compiled for non-neon architectures, the functions panic.
267/// The caller must make sure to check for hardware feature before calling these
268/// functions and compile them in.
269///
270/// Feature `simd256` enables the implementations in this module.
271#[cfg(feature = "simd256")]
272pub mod avx2;