1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
//! # Internal Utilities
//!
//! This module provides low‑level helper functions used throughout the SHA‑512,
//! HMAC, and HKDF implementations. It is not intended for public consumption;
//! however, it is marked `pub` because other modules in the crate need to access
//! these utilities.
//!
//! ## Contents
//!
//! - **Constants**: `BLOCKBYTES` and `BYTES` – the SHA‑512 block size (128 bytes)
//! and digest size (64 bytes).
//! - **Endianness helpers**: `load_be` and `store_be` – convert between `u64` and
//! big‑endian byte arrays.
//! - **Constant‑time comparison**: `verify` – compares two byte slices in
//! constant time to prevent timing side‑channel attacks.
//!
//! ## Security Notes
//!
//! - The `verify` function is designed to be resistant to timing attacks.
//! - All functions are marked `#[inline(always)]` where appropriate to ensure
//! optimal performance.
/// SHA‑512 block size in bytes.
///
/// This is the size of a single message block processed by the compression
/// function. It is `128` bytes (1024 bits).
pub const BLOCKBYTES: usize = 128;
/// SHA‑512 output size in bytes.
///
/// This is the length of the final digest: `64` bytes (512 bits).
pub const BYTES: usize = 64;
/// Loads a 64‑bit integer from a big‑endian byte slice at a given offset.
///
/// This function reads 8 bytes starting at `offset` from `base` and interprets
/// them as a big‑endian `u64`. It is used to parse message words and initial
/// vectors.
///
/// # Arguments
/// * `base` – The byte slice to read from. Must have at least `offset + 8`
/// bytes.
/// * `offset` – The starting index (in bytes) to read from.
///
/// # Returns
/// The `u64` value represented by the 8 bytes in big‑endian order.
///
/// # Panics
/// This function will panic if the slice is too short. It is the caller's
/// responsibility to ensure bounds are valid.
///
/// # Example
/// ```
/// use libvctrl_sha512::utils::load_be;
/// let bytes = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08];
/// let value = load_be(&bytes, 0);
/// assert_eq!(value, 0x0102030405060708);
/// ```
/// Stores a 64‑bit integer as big‑endian bytes at a given offset.
///
/// This function writes the 8 bytes of `x` (in big‑endian order) into `base`
/// starting at `offset`. It is used to produce final digests and intermediate
/// values.
///
/// # Arguments
/// * `base` – The mutable byte slice to write to. Must have at least
/// `offset + 8` bytes.
/// * `offset` – The starting index (in bytes) to write to.
/// * `x` – The 64‑bit value to store.
///
/// # Panics
/// This function will panic if the slice is too short.
///
/// # Example
/// ```
/// use libvctrl_sha512::utils::store_be;
/// let mut bytes = [0u8; 8];
/// store_be(&mut bytes, 0, 0x0102030405060708);
/// assert_eq!(bytes, [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]);
/// ```
/// Compares two byte slices in **constant time**.
///
/// This function is designed to prevent timing side‑channel attacks that could
/// leak information about the compared values. It uses a bitwise XOR reduction
/// and a volatile read to ensure the comparison runs in O(n) with data‑
/// independent timing.
///
/// # Security
///
/// - The loop iterates over all bytes of the shorter slice (if lengths differ,
/// it returns `false` early, which is a length leak but unavoidable and
/// typically acceptable).
/// - For equal lengths, every byte pair is XORed and ORed into a single
/// accumulator; the loop always runs for the full length.
/// - A volatile read is used to prevent the compiler from optimising away the
/// comparison.
///
/// # Arguments
/// * `x` – First byte slice.
/// * `y` – Second byte slice.
///
/// # Returns
/// `true` if both slices have the same length and contain identical bytes,
/// `false` otherwise.
///
/// # Example
/// ```
/// use libvctrl_sha512::utils::verify;
/// let a = [1, 2, 3];
/// let b = [1, 2, 3];
/// let c = [1, 2, 4];
/// assert!(verify(&a, &b));
/// assert!(!verify(&a, &c));
/// assert!(!verify(&a, &[1, 2])); // different lengths
/// ```
///
/// # Note
/// On WebAssembly (`wasm32`/`wasm64`), an additional mixing step is performed
/// to provide extra protection against certain timing variations.