1use rhdl::prelude::*;
10
11pub const HASH_BYTES: usize = 32;
13
14pub const SHA_BLOCK_BYTES: usize = 64;
16
17pub const HASH_INPUT_BITS: u32 = 256;
19
20pub const PRF_INPUT_BITS: u32 = 280;
22
23pub const SECRET_INPUT_BITS: u32 = 512;
25
26pub const ENDPOINT_STREAM_BYTES: usize = 2_144;
28
29pub const ENDPOINT_STREAM_BITS: u32 = 17_152;
31
32pub type HashBytes = [b8; HASH_BYTES];
34
35pub type ShaBlock = [b32; 16];
37
38pub type HashWords = [b32; 8];
40
41#[derive(Clone, Copy, Debug, Default, Digital, Eq, PartialEq)]
43pub struct PrfBlockInput {
44 pub seed: HashBytes,
46 pub index: b16,
48}
49
50#[derive(Clone, Copy, Debug, Default, Digital, Eq, PartialEq)]
52pub struct SecretDataInput {
53 pub function_key: HashBytes,
55 pub secret_prf: HashBytes,
57}
58
59#[derive(Clone, Copy, Debug, Default, Digital, Eq, PartialEq)]
61pub struct ChainBlockInput {
62 pub state: HashBytes,
64 pub mask: HashBytes,
66}
67
68#[derive(Clone, Copy, Debug, Default, Digital, Eq, PartialEq)]
70pub struct EndpointPairInput {
71 pub first: HashBytes,
73 pub second: HashBytes,
75}
76
77#[allow(clippy::needless_range_loop)] #[kernel]
80pub fn bytes_to_words_be_kernel(bytes: [b8; SHA_BLOCK_BYTES]) -> ShaBlock {
81 let mut words = [b32(0); 16];
82 for word in 0..16 {
83 let byte = word * 4;
84 let byte_zero: b32 = bytes[byte].resize();
85 let byte_one: b32 = bytes[byte + 1].resize();
86 let byte_two: b32 = bytes[byte + 2].resize();
87 let byte_three: b32 = bytes[byte + 3].resize();
88 words[word] = (byte_zero << 24) | (byte_one << 16) | (byte_two << 8) | byte_three;
89 }
90 words
91}
92
93#[kernel]
99pub fn hash_words_to_bytes_kernel(words: HashWords) -> HashBytes {
100 let mut bytes = [b8(0); HASH_BYTES];
101 for word in 0..8 {
102 bytes[word * 4] = (words[word] >> 24).resize();
103 bytes[word * 4 + 1] = (words[word] >> 16).resize();
104 bytes[word * 4 + 2] = (words[word] >> 8).resize();
105 bytes[word * 4 + 3] = words[word].resize();
106 }
107 bytes
108}
109
110#[kernel]
115#[allow(clippy::used_underscore_binding)] pub fn initial_state_words_kernel(_dummy: b1) -> HashWords {
117 [
118 b32(0x6a09_e667),
119 b32(0xbb67_ae85),
120 b32(0x3c6e_f372),
121 b32(0xa54f_f53a),
122 b32(0x510e_527f),
123 b32(0x9b05_688c),
124 b32(0x1f83_d9ab),
125 b32(0x5be0_cd19),
126 ]
127}
128
129#[kernel]
131pub fn sha256_32_byte_block_kernel(input: HashBytes) -> ShaBlock {
132 let mut bytes = [b8(0); SHA_BLOCK_BYTES];
133 for index in 0..HASH_BYTES {
134 bytes[index] = input[index];
135 }
136 bytes[HASH_BYTES] = b8(0x80);
137 bytes[62] = b8(0x01);
138 bytes[63] = b8(0x00);
139 bytes_to_words_be_kernel(bytes)
140}
141
142#[kernel]
147pub fn private_seed_block_kernel(private_seed: HashBytes) -> ShaBlock {
148 sha256_32_byte_block_kernel(private_seed)
149}
150
151#[kernel]
153pub fn prf_block_kernel(input: PrfBlockInput) -> ShaBlock {
154 let mut bytes = [b8(0); SHA_BLOCK_BYTES];
155 bytes[0] = b8(0x03);
156 for index in 0..HASH_BYTES {
157 bytes[index + 1] = input.seed[index];
158 }
159 bytes[33] = (input.index >> 8).resize();
160 bytes[34] = input.index.resize();
161 bytes[35] = b8(0x80);
162 bytes[62] = b8(0x01);
163 bytes[63] = b8(0x18);
164 bytes_to_words_be_kernel(bytes)
165}
166
167#[kernel]
169pub fn secret_data_block_kernel(input: SecretDataInput) -> ShaBlock {
170 let mut bytes = [b8(0); SHA_BLOCK_BYTES];
171 for index in 0..HASH_BYTES {
172 bytes[index] = input.function_key[index];
173 bytes[index + HASH_BYTES] = input.secret_prf[index];
174 }
175 bytes_to_words_be_kernel(bytes)
176}
177
178#[kernel]
183#[allow(clippy::used_underscore_binding)] pub fn secret_padding_block_kernel(_dummy: b1) -> ShaBlock {
185 let mut words = [b32(0); 16];
186 words[0] = b32(0x8000_0000);
187 words[15] = b32(512);
188 words
189}
190
191#[allow(clippy::needless_range_loop)] #[kernel]
194pub fn chain_block_kernel(input: ChainBlockInput) -> ShaBlock {
195 let mut preimage = [b8(0); HASH_BYTES];
196 for index in 0..HASH_BYTES {
197 preimage[index] = input.state[index] ^ input.mask[index];
198 }
199 sha256_32_byte_block_kernel(preimage)
200}
201
202#[kernel]
206pub fn endpoint_pair_block_kernel(input: EndpointPairInput) -> ShaBlock {
207 let mut bytes = [b8(0); SHA_BLOCK_BYTES];
208 for index in 0..HASH_BYTES {
209 bytes[index] = input.first[index];
210 bytes[index + HASH_BYTES] = input.second[index];
211 }
212 bytes_to_words_be_kernel(bytes)
213}
214
215#[kernel]
217pub fn endpoint_final_block_kernel(endpoint_66: HashBytes) -> ShaBlock {
218 let mut bytes = [b8(0); SHA_BLOCK_BYTES];
219 for index in 0..HASH_BYTES {
220 bytes[index] = endpoint_66[index];
221 }
222 bytes[HASH_BYTES] = b8(0x80);
223 bytes[62] = b8(0x43);
224 bytes[63] = b8(0x00);
225 bytes_to_words_be_kernel(bytes)
226}
227
228#[must_use]
234pub fn software_padded_block(message: &[u8], block_index: usize) -> Option<[u32; 16]> {
235 let bit_length = u64::try_from(message.len()).ok()?.checked_mul(8)?;
236 let complete_blocks = message.len() / SHA_BLOCK_BYTES;
237 let remainder = message.len() % SHA_BLOCK_BYTES;
238 let block_count = complete_blocks + if remainder <= 55 { 1 } else { 2 };
239 if block_index >= block_count {
240 return None;
241 }
242
243 let mut bytes = [0_u8; SHA_BLOCK_BYTES];
244 let stream_offset = block_index.checked_mul(SHA_BLOCK_BYTES)?;
245 let length_offset = block_count.checked_mul(SHA_BLOCK_BYTES)?.checked_sub(8)?;
246 for (offset, output) in bytes.iter_mut().enumerate() {
247 let absolute = stream_offset + offset;
248 *output = if absolute < message.len() {
249 message[absolute]
250 } else if absolute == message.len() {
251 0x80
252 } else if absolute >= length_offset {
253 bit_length.to_be_bytes()[absolute - length_offset]
254 } else {
255 0
256 };
257 }
258 Some(software_words_from_bytes(bytes))
259}
260
261#[must_use]
263pub fn software_words_from_bytes(bytes: [u8; SHA_BLOCK_BYTES]) -> [u32; 16] {
264 core::array::from_fn(|word| {
265 let offset = word * 4;
266 u32::from_be_bytes([
267 bytes[offset],
268 bytes[offset + 1],
269 bytes[offset + 2],
270 bytes[offset + 3],
271 ])
272 })
273}
274
275const _: () = {
276 assert!(HASH_INPUT_BITS == 256);
277 assert!(PRF_INPUT_BITS == 35 * 8);
278 assert!(SECRET_INPUT_BITS == 512);
279 assert!(ENDPOINT_STREAM_BYTES == 67 * HASH_BYTES);
280 assert!(ENDPOINT_STREAM_BITS == 17_152);
281};