lambdaworks_crypto/hash/sha3/
mod.rs

1use alloc::{
2    string::{String, ToString},
3    vec::Vec,
4};
5use sha3::{Digest, Sha3_256};
6
7pub struct Sha3Hasher;
8
9/// Sha3 Hasher used over fields
10/// Notice while it's generic over F, it's only generates enough randomness for fields of at most 256 bits
11impl Sha3Hasher {
12    pub const fn new() -> Self {
13        Self
14    }
15
16    pub fn expand_message(msg: &[u8], dst: &[u8], len_in_bytes: u64) -> Result<Vec<u8>, String> {
17        let b_in_bytes = Sha3_256::output_size() as u64;
18
19        let ell = len_in_bytes.div_ceil(b_in_bytes);
20        if ell > 255 {
21            return Err("Abort".to_string());
22        }
23
24        let dst_prime: Vec<u8> = [dst, &Self::i2osp(dst.len() as u64, 1)].concat();
25        let z_pad = Self::i2osp(0, 64);
26        let l_i_b_str = Self::i2osp(len_in_bytes, 2);
27        let msg_prime = [
28            z_pad,
29            msg.to_vec(),
30            l_i_b_str,
31            Self::i2osp(0, 1),
32            dst_prime.clone(),
33        ]
34        .concat();
35        let b_0: Vec<u8> = Sha3_256::digest(msg_prime).to_vec();
36        let a = [b_0.clone(), Self::i2osp(1, 1), dst_prime.clone()].concat();
37        let b_1 = Sha3_256::digest(a).to_vec();
38
39        let mut b_vals = Vec::<Vec<u8>>::with_capacity(ell as usize);
40        b_vals.push(b_1);
41        for idx in 1..ell {
42            let aux = Self::strxor(&b_0, &b_vals[idx as usize - 1]);
43            let b_i = [aux, Self::i2osp(idx, 1), dst_prime.clone()].concat();
44            b_vals.push(Sha3_256::digest(b_i).to_vec());
45        }
46
47        let mut b_vals = b_vals.concat();
48        b_vals.truncate(len_in_bytes as usize);
49
50        Ok(b_vals)
51    }
52
53    fn i2osp(x: u64, length: u64) -> Vec<u8> {
54        let mut x_aux = x;
55        let mut digits = Vec::new();
56        while x_aux != 0 {
57            digits.push((x_aux % 256) as u8);
58            x_aux /= 256;
59        }
60        digits.resize(length as usize, 0);
61        digits.reverse();
62        digits
63    }
64
65    fn strxor(a: &[u8], b: &[u8]) -> Vec<u8> {
66        a.iter().zip(b).map(|(a, b)| a ^ b).collect()
67    }
68}
69
70impl Default for Sha3Hasher {
71    fn default() -> Self {
72        Self::new()
73    }
74}