88*/
99
1010#include " SHA1.hpp"
11+ #include < algorithm>
12+
13+ /* ==================================================================*/
1114
15+ #if __has_include(<bit>)
1216#include < bit>
13- #include < algorithm>
17+ #endif
18+
19+ static constexpr std::uint32_t rotl (std::uint32_t value, std::uint32_t rotation) noexcept {
20+ #if __has_include(<bit>)
21+ return std::rotl (value, rotation);
22+ #else
23+ return (value << rotation) | (value >> (32 - rotation));
24+ #endif
25+ }
1426
1527/* ==================================================================*/
1628
1729static constexpr std::uint32_t block_mix (std::uint32_t * block, std::size_t i) noexcept {
18- return std:: rotl (
30+ return rotl (
1931 block[(i + 0xD ) & 0xF ] ^
2032 block[(i + 0x8 ) & 0xF ] ^
2133 block[(i + 0x2 ) & 0xF ] ^
@@ -31,8 +43,8 @@ static constexpr void R0(
3143 std::uint32_t v, std::uint32_t & w, std::uint32_t x,
3244 std::uint32_t y, std::uint32_t & z, std::size_t i
3345) noexcept {
34- z += ((w & (x ^ y)) ^ y) + block[i] + 0x5A827999 + std:: rotl (v, 5 );
35- w = std:: rotl (w, 30 );
46+ z += ((w & (x ^ y)) ^ y) + block[i] + 0x5A827999 + rotl (v, 5 );
47+ w = rotl (w, 30 );
3648}
3749
3850static constexpr void R1 (
@@ -41,8 +53,8 @@ static constexpr void R1(
4153 std::uint32_t y, std::uint32_t & z, std::size_t i
4254) noexcept {
4355 block[i] = block_mix (block, i);
44- z += ((w & (x ^ y)) ^ y) + block[i] + 0x5A827999 + std:: rotl (v, 5 );
45- w = std:: rotl (w, 30 );
56+ z += ((w & (x ^ y)) ^ y) + block[i] + 0x5A827999 + rotl (v, 5 );
57+ w = rotl (w, 30 );
4658}
4759
4860static constexpr void R2 (
@@ -51,8 +63,8 @@ static constexpr void R2(
5163 std::uint32_t y, std::uint32_t & z, std::size_t i
5264) noexcept {
5365 block[i] = block_mix (block, i);
54- z += (w ^ x ^ y) + block[i] + 0x6ED9EBA1 + std:: rotl (v, 5 );
55- w = std:: rotl (w, 30 );
66+ z += (w ^ x ^ y) + block[i] + 0x6ED9EBA1 + rotl (v, 5 );
67+ w = rotl (w, 30 );
5668}
5769
5870static constexpr void R3 (
@@ -61,8 +73,8 @@ static constexpr void R3(
6173 std::uint32_t y, std::uint32_t & z, std::size_t i
6274) noexcept {
6375 block[i] = block_mix (block, i);
64- z += (((w | x) & y) | (w & x)) + block[i] + 0x8F1BBCDC + std:: rotl (v, 5 );
65- w = std:: rotl (w, 30 );
76+ z += (((w | x) & y) | (w & x)) + block[i] + 0x8F1BBCDC + rotl (v, 5 );
77+ w = rotl (w, 30 );
6678}
6779
6880static constexpr void R4 (
@@ -71,8 +83,8 @@ static constexpr void R4(
7183 std::uint32_t y, std::uint32_t & z, std::size_t i
7284) noexcept {
7385 block[i] = block_mix (block, i);
74- z += (w ^ x ^ y) + block[i] + 0xCA62C1D6 + std:: rotl (v, 5 );
75- w = std:: rotl (w, 30 );
86+ z += (w ^ x ^ y) + block[i] + 0xCA62C1D6 + rotl (v, 5 );
87+ w = rotl (w, 30 );
7688}
7789
7890/* ==================================================================*/
@@ -118,15 +130,13 @@ constexpr void SHA1::transform(std::uint32_t* block) noexcept {
118130 ++m_transforms;
119131}
120132
121- // Hash a single 512-bit block
122- constexpr void SHA1::buffer_to_block (std::uint32_t * block) noexcept {
123-
124- // convert the string (byte buffer) to a u32 array (MSB)
133+ constexpr void SHA1::bytes_to_block (std::uint32_t * block, const char * src) noexcept {
134+ // read bytes as byteswapped ints
125135 for (auto i = 0u ; i < c_block_size; ++i) {
126- block[i] = (m_buffer [4 * i + 3 ] & 0xFF )
127- | (m_buffer [4 * i + 2 ] & 0xFF ) << 8
128- | (m_buffer [4 * i + 1 ] & 0xFF ) << 16
129- | (m_buffer [4 * i + 0 ] & 0xFF ) << 24 ;
136+ block[i] = (src [4 * i + 3 ] & 0xFF )
137+ | (src [4 * i + 2 ] & 0xFF ) << 8
138+ | (src [4 * i + 1 ] & 0xFF ) << 16
139+ | (src [4 * i + 0 ] & 0xFF ) << 24 ;
130140 }
131141}
132142
@@ -137,49 +147,62 @@ void SHA1::reset() noexcept {
137147 m_digest[3 ] = 0x10325476u ;
138148 m_digest[4 ] = 0xC3D2E1F0u ;
139149
140- m_buffer. fill ( ' \0 ' );
141- m_transforms = m_buf_offset = 0 ;
150+ std::fill_n (m_buffer, c_buffer_size, ' \x00 ' );
151+ m_transforms = m_tail_size = 0 ;
142152}
143153
144154void SHA1::update (const char * data_pointer, std::size_t byte_count) noexcept {
145- while (byte_count > 0 ) {
155+ // if the buffer is partially filled, top it up first
156+ if (m_tail_size > 0 ) {
146157 const auto chunk_size = std::uint32_t (std::min (
147- c_block_bytes - m_buf_offset , byte_count));
158+ c_block_bytes - m_tail_size , byte_count));
148159
149160 std::copy (data_pointer, data_pointer + chunk_size,
150- m_buffer. data () + m_buf_offset );
161+ m_buffer + m_tail_size );
151162
152- m_buf_offset += chunk_size;
163+ m_tail_size += chunk_size;
153164 data_pointer += chunk_size;
154165 byte_count -= chunk_size;
155166
156- if (m_buf_offset == c_block_bytes) {
157- std::uint32_t block_array[c_block_size]{} ;
158- buffer_to_block (block_array);
167+ if (m_tail_size == c_block_bytes) {
168+ std::uint32_t block_array[c_block_size];
169+ bytes_to_block (block_array, m_buffer );
159170 transform (block_array);
160- m_buf_offset = 0 ;
171+ m_tail_size = 0 ;
161172 }
162173 }
174+
175+ // process full blocks directly from the input — no copy
176+ while (byte_count >= c_block_bytes) {
177+ std::uint32_t block_array[c_block_size];
178+ bytes_to_block (block_array, data_pointer);
179+ transform (block_array);
180+ data_pointer += c_block_bytes;
181+ byte_count -= c_block_bytes;
182+ }
183+
184+ // stash any remaining partial block in the buffer
185+ if (byte_count > 0 ) {
186+ std::copy (data_pointer, data_pointer + byte_count, m_buffer);
187+ m_tail_size = std::uint32_t (byte_count);
188+ }
163189}
164190
165191std::string SHA1::final () noexcept {
166192 const auto total_hashed_bits =
167- 8 * (m_transforms * c_block_bytes + m_buf_offset );
193+ 8 * (m_transforms * c_block_bytes + m_tail_size );
168194
169- // insert message end bit, then pad with
170- // zeroes until the end of the block
171- m_buffer[m_buf_offset++] = ' \x80 ' ;
172- const auto buffer_size = m_buf_offset;
195+ // insert message end bit, then pad to end of block with zeroes
196+ m_buffer[m_tail_size++] = ' \x80 ' ;
173197
174- while (m_buf_offset < c_block_bytes) {
175- m_buffer[m_buf_offset++] = ' \x00 ' ;
176- }
198+ std::fill (m_buffer + m_tail_size,
199+ m_buffer + c_buffer_size, ' \x00 ' );
177200
178201 // process the final block
179- std::uint32_t block_array[c_block_size]{} ;
180- buffer_to_block (block_array);
202+ std::uint32_t block_array[c_block_size];
203+ bytes_to_block (block_array, m_buffer );
181204
182- if (buffer_size > c_block_bytes - 8 ) {
205+ if (m_tail_size > c_block_bytes - 8 ) {
183206 transform (block_array);
184207 for (auto i = 0u ; i < c_block_size - 2 ; ++i) {
185208 block_array[i] = 0 ;
@@ -192,9 +215,9 @@ std::string SHA1::final() noexcept {
192215 transform (block_array);
193216
194217 // convert digest[] to a string
195- std::string result (40 , ' \0 ' );
218+ std::string result (40 , ' \x00 ' );
196219 constexpr auto c_hex = " 0123456789abcdef" ;
197- for (auto i = 0u ; i < std::size (m_digest) ; ++i) {
220+ for (auto i = 0u ; i < c_digest_size ; ++i) {
198221 for (auto j = 0u ; j < 8 ; ++j) {
199222 result[i * 8 + j] = c_hex[(m_digest[i] >> (28 - j * 4 )) & 0xF ];
200223 }
0 commit comments