jisp_sha2/
sha256.rs

1//! This is the SHA-256 Algorithm. 
2//! You can use the standard implementations of [sha_256] and [sha_224] or you can use custom constants and initial hash values with [sha256_internal]
3
4
5use std::ops::{BitXor, BitAnd};
6
7use crypto_bigint::{U512,U256};
8use crate::conversions;
9use crate::constants::{Constants, Sha256, Sha224};
10
11
12/// The SHA-256 Algorithm, only use this after having [preprocessed](crate::preprocessing::sha256_preprocessing) your data into message blocks
13pub fn sha_256(m:Vec<U512>) -> U256 {
14    sha256_internal::<Sha256>(m)
15}
16
17/// The SHA-224 Algorithm, only use this after having [preprocessed](crate::preprocessing::sha256_preprocessing) your data into message blocks
18/// Note that this is essentially the [SHA-256](sha_256) algorithm, except with different constants and a truncated result.
19pub fn sha_224(m:Vec<U512>) -> [u32;7] {
20    let hash = sha256_internal::<Sha224>(m);
21    let words = conversions::to_u32_words(hash);
22    let mut truncated_words = [0u32; 7];
23    for i in 0..7 {
24        truncated_words[i] = words[i];
25    } 
26    return truncated_words;
27}
28
29
30/// The internal loop of the SHA-256 algorithm, 
31/// you can use different initial hash and constant values by implementing the [Constants](crate::constants::Constants) trait on a new object
32pub fn sha256_internal<C:Constants<64,u32>>(msg:Vec<U512>) -> U256 {
33    let mut hash = C::initial_hash();
34    for block in msg {
35        let registers = sha256_compression::<C>(&hash, block);
36        for i in 0..8 {
37            hash[i] = hash[i].wrapping_add(registers[i]);
38        }
39    }
40    conversions::from_u32_words(&hash.to_vec())
41    
42}
43
44fn sha256_compression<C:Constants<64,u32>>(intermediate_hash:&[u32;8], msg:U512) -> [u32;8] {
45    let [mut a, mut b, mut c, mut d, mut e, mut f, mut g, mut h] = intermediate_hash.clone();
46    let constants_k = C::constant_words();
47    let expanded_blocks = sha256_message_schedule(msg);
48
49    for j in 0..64 {
50        let T1 = wrapping_sum(vec![
51            h, sigma_l1(e), ch(e,f,g), constants_k[j], expanded_blocks[j] 
52        ]);
53        let T2 = sigma_l0(a).wrapping_add(maj(a,b,c));
54
55        h = g;
56        g = f;
57        f = e;
58        e = d.wrapping_add(T1);
59        d = c;
60        c = b;
61        b = a;
62        a = T1.wrapping_add(T2);
63    }
64
65    [a, b, c, d, e, f, g, h]
66}
67
68// ------ Six Logical Functions -------
69
70fn ch(x:u32, y:u32, z:u32) -> u32 {
71    let x_and_y = x.bitand(y);
72    let x_and_z = inv(x).bitand(z);
73    return x_and_y.bitxor(x_and_z);
74}
75
76fn maj(x:u32, y:u32, z:u32) -> u32 {
77    let x_and_y = x.bitand(y);
78    let y_and_z = y.bitand(z);
79    let x_and_z = x.bitand(z);
80    return x_and_y.bitxor(y_and_z).bitxor(x_and_z);
81}
82
83fn sigma_l0(x:u32) -> u32 {
84    let s2 = x.rotate_right(2);
85    let s13 = x.rotate_right(13);
86    let s22 = x.rotate_right(22);
87    return s2.bitxor(s13).bitxor(s22);
88}
89
90fn sigma_l1(x:u32) -> u32 {
91    let s6 = x.rotate_right(6);
92    let s11 = x.rotate_right(11);
93    let s25 = x.rotate_right(25);
94    return s6.bitxor(s11).bitxor(s25);
95
96}
97
98fn sigma_s0(x:u32) -> u32 {
99    let s7 = x.rotate_right(7);
100    let s18 = x.rotate_right(18);
101    let r3 = x >> 3;
102    return s7.bitxor(s18).bitxor(r3);
103}
104
105fn sigma_s1(x:u32) -> u32 {
106    let s17 = x.rotate_right(17);
107    let s19 = x.rotate_right(19);
108    let r10 = x >> 10;
109    return s17.bitxor(s19).bitxor(r10);
110}
111
112// --------- addendum -------------
113fn inv(x:u32) -> u32 {
114    x.bitxor(u32::MAX)
115}
116
117fn xor_sum(v:Vec<u32>) -> u32 {
118    let mut res = 0u32;
119    for u in v {
120        res = res.bitxor(u);
121    }
122    return res;
123}
124
125fn wrapping_sum(v:Vec<u32>) -> u32 {
126    let mut res = 0u32;
127    for u in v {
128        res = res.wrapping_add(u);
129    }
130    return res;
131}
132
133
134// ------------------ Message Schedule ----------------
135
136fn sha256_message_schedule(m:U512) -> [u32;64] {
137    //word vector of length 16
138    let m = conversions::to_u32_words(m); 
139    let mut w = [0u32; 64];
140    for i in 0..16 {
141        w[i] = m[i];
142    }
143
144    for i in 16..64 {
145        let mut w_i = sigma_s1(w[i - 2]);
146        w_i = w_i.wrapping_add(w[i - 7]);
147        w_i = w_i.wrapping_add(sigma_s0(w[i - 15]));
148        w_i = w_i.wrapping_add(w[i - 16]);
149        w[i] = w_i;
150    }
151
152    return w;
153}
154
155#[cfg(test)]
156mod tests {
157    use super::*;
158    #[test]
159    fn simple_sigma_s0() {
160        let y = sigma_s0(1);
161        let expected = (1 << 25) + (1 << 14);
162        assert_eq!(y, expected);
163    }
164
165    #[test]
166    fn simple_sigma_s1() {
167        let y = sigma_s1(1 << 31);
168        let expected = 0b00000000_00100000_01010000_00000000;
169        assert_eq!(y,expected);
170    }
171}