jisp_sha2/
preprocessing.rs

1//! Functions for performing the standard preprocessing steps before applying the SHA-2 algorithm
2
3use crypto_bigint::{Uint, U1024, U512};
4use crate::conversions;
5
6pub fn string_to_encoding(s: &str) -> Vec<u8> {
7    s.as_bytes().into()
8}
9
10pub fn sha256_preprocessing(s: &str) -> Vec<U512> {
11    standard_preprocessing::<8, 1>(s)
12}
13
14pub fn sha512_preprocessing(s: &str) -> Vec<U1024> {
15    standard_preprocessing::<16, 2>(s)
16}
17
18pub fn standard_preprocessing<const BLOCK: usize, const SUFFIX: usize>(s: &str) -> Vec<Uint<BLOCK>> {
19    let bytes = string_to_encoding(s);
20    let l = 8 * bytes.len();
21    let mut l_vec = [0 as u64; SUFFIX];
22    l_vec[SUFFIX - 1] = l as u64;
23
24    let words = byte_padding(&bytes);
25    word_padding(&words, l_vec)
26}
27
28pub fn custom_preprocessing<const BLOCK: usize, const SUFFIX: usize>(bytes: Vec<u8>, suffix:[u64;SUFFIX]) -> Vec<Uint<BLOCK>> {
29    let words = byte_padding(&bytes);
30    word_padding(&words, suffix)
31}
32
33/// Packs 64 bit words into 512 bit blocks by padding the message with 0s and adding the suffix l (usually the length of the message) at the end of the final block.
34/// # Examples
35/// The word padding function completely trusts you that the length you give was the original length of the message
36/// ```
37/// use jisp_sha2::preprocessing::word_padding;
38/// use crypto_bigint::{U512, CheckedAdd};
39///
40/// let v = vec![1];
41/// let len = (v.len()*8) as u64;
42///
43/// let res = word_padding::<8,1>(&v, [len]);
44/// let expected = U512::ONE.shl(448).checked_add(&U512::from(8u8)).unwrap();
45///
46/// assert_eq!(res, vec![expected])
47/// ```
48pub fn word_padding<const BSIZE: usize, const SUFFIX: usize>(
49    v: &Vec<u64>,
50    l: [u64; SUFFIX],
51) -> Vec<Uint<BSIZE>> {
52    let mut blocks = Vec::new();
53    let mut block = [0u64; BSIZE];
54    let mut block_index = 0;
55
56    if SUFFIX > BSIZE {
57        panic!(
58            "Size SUFFIX:{} is larger than block size BSIZE: {}",
59            SUFFIX, BSIZE
60        );
61    }
62
63    for word in v.iter() {
64        block[block_index] = *word;
65        block_index += 1;
66        if block_index == BSIZE {
67            block_index = 0;
68            blocks.push(conversions::from_u64_words(&mut block));
69        }
70    }
71
72    let mut i = BSIZE - SUFFIX;
73    //check if length fits in remaining block space
74    if i < block_index {
75        blocks.push(conversions::from_u64_words(&mut block));
76    }
77
78    //append l to the end of the final block and push
79    for l_elem in l {
80        block[i] = l_elem;
81        i += 1;
82    }
83    blocks.push(conversions::from_u64_words(&mut block));
84
85    return blocks;
86}
87/// Merges groups of 8 bytes into 64 bit words
88/// We extend the length of the list of bytes by adding a 1 bit at the end and enough 0s such that we have a multiple of 64 bits
89///  # Example
90/// ```
91/// use jisp_sha2::preprocessing::byte_padding;
92///
93/// let mut v = vec![1,2,3];
94///
95/// let res = byte_padding(&v);
96/// let expected = 0x0102_0380_0000_0000u64;
97///
98/// assert_eq!(res, vec![expected])
99/// ```
100///
101///
102/// the 1 packing at the end means we add an extra u64 if your message is already a multiple of 8 bytes
103/// ```
104/// use jisp_sha2::preprocessing::byte_padding;
105///
106/// let mut v = vec![0;8];
107/// v[7] = 5;
108///
109/// let res = byte_padding(&v);
110///
111/// assert_eq!(res,vec![5, 1 << 63])
112/// ```
113pub fn byte_padding(v: &Vec<u8>) -> Vec<u64> {
114    let mut words = Vec::new();
115    let mut word = [0; 8];
116    let mut byte_i = 0;
117    for u in v.iter() {
118        word[byte_i] = *u;
119        byte_i += 1;
120        if byte_i == 8 {
121            byte_i = 0;
122            words.push(bytes_to_u64(word));
123            word = [0; 8];
124        }
125    }
126    //We do not know if we completed the last word when we ended
127    //add 1000 0000 to the result we have
128    word[byte_i] = 0x80u8;
129    words.push(bytes_to_u64(word));
130
131    return words;
132}
133
134pub fn bytes_to_u64(v: [u8; 8]) -> u64 {
135    let mut res: u64 = 0;
136    for i in v.iter() {
137        res = res << 8;
138        res += *i as u64;
139    }
140    res
141}