Skip to content

Commit c6ee1c3

Browse files
committed
Tune hash algorithms
1 parent 5531d89 commit c6ee1c3

File tree

6 files changed

+167
-160
lines changed

6 files changed

+167
-160
lines changed

ref_app/src/app/benchmark/app_benchmark_hash.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
namespace
1616
{
17-
using app_benchmark_hash_type = math::checksums::hash::hash_sha1<std::uint8_t>;
17+
using app_benchmark_hash_type = math::checksums::hash::hash_sha1<std::uint16_t>;
1818

1919
app_benchmark_hash_type app_benchmark_hash_object;
2020

ref_app/src/app/benchmark/app_benchmark_hash_sha256.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
namespace
1616
{
17-
using app_benchmark_hash_type = math::checksums::hash::hash_sha256<std::uint8_t>;
17+
using app_benchmark_hash_type = math::checksums::hash::hash_sha256<std::uint_fast16_t>;
1818

1919
app_benchmark_hash_type app_benchmark_hash_object;
2020

ref_app/src/math/checksums/hash/hash_base.h

Lines changed: 94 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -15,25 +15,35 @@
1515
namespace math { namespace checksums { namespace hash {
1616

1717
template<typename CountType,
18-
const std::uint16_t MessageBufferSize>
18+
const std::uint16_t ResultBitCount,
19+
const std::uint16_t MessageBufferSize,
20+
const std::uint16_t MessageLengthTotalBitCount>
1921
class hash_base
2022
{
2123
public:
2224
using count_type = CountType;
2325

24-
static_assert( ( std::numeric_limits<count_type>::is_specialized == true)
25-
&& ( std::numeric_limits<count_type>::is_integer == true)
26-
&& ( std::numeric_limits<count_type>::is_signed == false)
27-
&& ( std::numeric_limits<count_type>::radix == 2)
28-
&& ((std::numeric_limits<count_type>::digits % 8) == 0),
29-
"Error: The count type must be an unsigned integer with radix 2, having a multiple of 8 bits");
26+
using result_type = std::array<std::uint8_t, static_cast<std::size_t>(ResultBitCount / static_cast<std::uint16_t>(UINT8_C(8)))>;
27+
28+
static_assert
29+
(
30+
std::numeric_limits<count_type>::is_specialized
31+
&& std::numeric_limits<count_type>::is_integer
32+
&& (!std::numeric_limits<count_type>::is_signed)
33+
&& (std::numeric_limits<count_type>::radix == static_cast<int>(INT8_C(2)))
34+
&& (std::numeric_limits<count_type>::digits >= static_cast<int>(INT8_C(16)))
35+
&& (static_cast<int>(std::numeric_limits<count_type>::digits % static_cast<int>(INT8_C(8))) == static_cast<int>(INT8_C(0))),
36+
"Error: The count type must be an unsigned integer with radix 2, that is 16 bits or wider, and having a multiple of 8 bits"
37+
);
3038

3139
virtual ~hash_base() = default;
3240

3341
virtual auto initialize() -> void
3442
{
3543
message_index = static_cast<std::uint_least16_t>(UINT8_C(0));
3644
message_length_total = static_cast<count_type>(UINT8_C(0));
45+
46+
message_buffer.fill(static_cast<std::uint8_t>(UINT8_C(0)));
3747
}
3848

3949
auto process(const std::uint8_t* message, const count_type count) -> void
@@ -47,13 +57,13 @@
4757
message_length_total = static_cast<count_type> (message_length_total + process_chunk_size);
4858
process_index = static_cast<count_type> (process_index + process_chunk_size);
4959

50-
if(message_index == message_buffer_static_size)
60+
if(message_index == message_buffer_static_size())
5161
{
52-
this->perform_algorithm();
62+
my_perform_algorithm();
5363
}
5464

5565
process_chunk_size = (std::min)(static_cast<count_type>(count - process_index),
56-
static_cast<count_type>(message_buffer_static_size - message_index));
66+
static_cast<count_type>(message_buffer_static_size() - message_index));
5767

5868
std::copy(message + static_cast<std::size_t>(process_index),
5969
message + static_cast<std::size_t>(process_index + process_chunk_size),
@@ -64,65 +74,66 @@
6474

6575
auto finalize() -> void
6676
{
67-
message_block_type the_last_message_block;
68-
69-
std::copy(message_buffer.cbegin(),
70-
message_buffer.cbegin() + message_index,
71-
the_last_message_block.begin());
72-
7377
// Create the padding. Begin by setting the leading padding byte to 0x80.
74-
the_last_message_block[message_index] = static_cast<std::uint8_t>(UINT8_C(0x80));
78+
message_buffer[message_index] = static_cast<std::uint8_t>(UINT8_C(0x80));
7579

7680
++message_index;
7781

78-
// Fill the rest of the padding bytes with zero.
79-
std::fill(the_last_message_block.begin() + message_index,
80-
the_last_message_block.end(),
81-
static_cast<std::uint8_t>(UINT8_C(0)));
82+
// We need an extra block because there are not enough bytes
83+
// available for storing the total bit count. So we must
84+
// transform the current block, then create and pad yet another
85+
// additional block.
8286

83-
// Do we need an extra block? If so, then transform the
84-
// current block and pad an additional block.
85-
if(message_index > static_cast<std::uint16_t>(message_buffer_static_size - 8U))
87+
if(static_cast<std::uint16_t>(message_index + static_cast<std::uint_least16_t>(message_length_total_width())) > message_buffer_static_size())
8688
{
87-
message_buffer = the_last_message_block;
88-
89-
perform_algorithm();
90-
91-
the_last_message_block.fill(static_cast<std::uint8_t>(UINT8_C(0)));
89+
my_perform_algorithm();
9290
}
9391

94-
// Encode the number of bits. Simultaneously convert the number of bytes
95-
// to the number of bits by performing a left-shift of 3 on the byte-array.
96-
// The hash_sha1 stores the 8 bytes of the bit counter in reverse order,
97-
// with the lowest byte being stored at the highest position of the buffer
98-
auto carry = static_cast<std::uint8_t>(UINT8_C(0));
99-
100-
auto local_message_length_total = static_cast<std::uint64_t>(message_length_total);
92+
// Encode the total number of bits in the final transform buffer.
93+
// Here, we can easily see the conversion of the number of bytes
94+
// to the number of bits. This is done by performing a left-shift
95+
// of 3 on the variable "message_length_total".
10196

102-
std::for_each(the_last_message_block.rbegin(),
103-
the_last_message_block.rbegin() + static_cast<std::size_t>(UINT8_C(8)),
104-
[&carry, &local_message_length_total](std::uint8_t& the_byte)
105-
{
106-
const std::uint_least16_t the_word =
107-
static_cast<std::uint_least16_t>(local_message_length_total << static_cast<unsigned>(UINT8_C(3)));
97+
auto carry = static_cast<std::uint_fast8_t>(UINT8_C(0));
10898

109-
the_byte = static_cast<std::uint8_t>(the_word | carry);
110-
111-
local_message_length_total >>= static_cast<unsigned>(UINT8_C(8));
112-
113-
carry =
114-
static_cast<std::uint8_t>
115-
(
116-
static_cast<std::uint8_t>(the_word >> static_cast<unsigned>(UINT8_C(8)))
117-
& static_cast<std::uint8_t>(UINT8_C(0x07))
118-
);
119-
});
120-
121-
message_length_total = static_cast<count_type>(local_message_length_total);
99+
for(auto ri = message_buffer.rbegin();
100+
ri != message_buffer.rbegin() + message_length_total_width();
101+
++ri)
102+
{
103+
const std::uint_least16_t the_word =
104+
static_cast<std::uint_least16_t>
105+
(
106+
static_cast<std::uint_least16_t>(message_length_total) << static_cast<unsigned>(UINT8_C(3))
107+
);
108+
109+
*ri = static_cast<std::uint8_t>(the_word | carry);
110+
111+
message_length_total =
112+
static_cast<count_type>
113+
(
114+
message_length_total >> static_cast<unsigned>(UINT8_C(8))
115+
);
116+
117+
carry =
118+
static_cast<std::uint_fast8_t>
119+
(
120+
static_cast<std::uint_fast8_t>(the_word >> static_cast<unsigned>(UINT8_C(8)))
121+
& static_cast<std::uint_fast8_t>(UINT8_C(0x07))
122+
);
123+
}
122124

123-
message_buffer = the_last_message_block;
125+
my_perform_algorithm();
126+
}
124127

125-
this->perform_algorithm();
128+
auto get_result(typename result_type::pointer result) -> void
129+
{
130+
// Extract the hash result from the message digest state.
131+
detail::convert_uint32_input_to_uint8_output_reverse
132+
(
133+
transform_context.data(),
134+
transform_context.data() + static_cast<std::size_t>(std::tuple_size<result_type>::value / sizeof(std::uint32_t)),
135+
result
136+
);
126137
}
127138

128139
auto hash(const std::uint8_t* message, const count_type count) -> void
@@ -133,13 +144,19 @@
133144
}
134145

135146
protected:
136-
static constexpr auto message_buffer_static_size = MessageBufferSize;
147+
using message_block_type = std::array<std::uint8_t, static_cast<std::size_t>(MessageBufferSize)>;
148+
149+
using context_type = std::array<std::uint32_t, static_cast<std::size_t>(std::tuple_size<result_type>::value / sizeof(std::uint32_t))>;
137150

138-
using message_block_type = std::array<std::uint8_t, static_cast<std::size_t>(message_buffer_static_size)>;
151+
static constexpr auto message_buffer_static_size() -> std::uint16_t
152+
{
153+
return static_cast<std::uint16_t>(std::tuple_size<message_block_type>::value);
154+
}
139155

140156
std::uint_least16_t message_index { };
141157
count_type message_length_total { };
142158
message_block_type message_buffer { };
159+
context_type transform_context { };
143160

144161
hash_base() = default;
145162

@@ -150,7 +167,25 @@
150167
auto operator=(hash_base&& other) noexcept -> hash_base& = default;
151168

152169
private:
170+
static constexpr auto message_length_total_width() noexcept -> std::uint16_t
171+
{
172+
return
173+
static_cast<std::uint16_t>
174+
(
175+
MessageLengthTotalBitCount / static_cast<std::uint16_t>(UINT8_C(8))
176+
);
177+
}
178+
153179
virtual auto perform_algorithm() -> void = 0;
180+
181+
auto my_perform_algorithm() -> void
182+
{
183+
this->perform_algorithm();
184+
185+
message_index = static_cast<std::uint_least16_t>(UINT8_C(0));
186+
187+
message_buffer.fill(static_cast<std::uint8_t>(UINT8_C(0)));
188+
}
154189
};
155190

156191
} } } // namespace math::checksums::hash

ref_app/src/math/checksums/hash/hash_sha1.h

Lines changed: 33 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -19,30 +19,21 @@
1919
namespace math { namespace checksums { namespace hash {
2020

2121
template<typename CountType>
22-
class hash_sha1 : public hash_base<CountType, static_cast<std::size_t>(UINT8_C(64))>
22+
class hash_sha1 : public hash_base<CountType,
23+
static_cast<std::uint16_t>(UINT8_C(160)),
24+
static_cast<std::uint16_t>(UINT8_C(64)),
25+
static_cast<std::uint16_t>(UINT8_C(64))>
2326
{
2427
private:
25-
using base_class_type = hash_base<CountType, static_cast<std::size_t>(UINT8_C(64))>;
28+
using base_class_type = hash_base<CountType,
29+
static_cast<std::uint16_t>(UINT8_C(160)),
30+
static_cast<std::uint16_t>(UINT8_C(64)),
31+
static_cast<std::uint16_t>(UINT8_C(64))>;
2632

27-
static_assert(base_class_type::message_buffer_static_size == static_cast<std::uint16_t>(UINT8_C(64)),
33+
static_assert(base_class_type::message_buffer_static_size() == static_cast<std::uint16_t>(UINT8_C(64)),
2834
"Error: The message buffer size must exactly equal 64");
2935

30-
using transform_function_type = std::uint32_t(*)(const std::uint32_t*);
31-
32-
static constexpr auto transform_functions() -> std::array<transform_function_type, static_cast<std::size_t>(UINT8_C(4))>
33-
{
34-
return
35-
{
36-
[](const std::uint32_t* p) -> std::uint32_t { return (static_cast<std::uint32_t>( p[1U] & p[2U]) | static_cast<std::uint32_t>(static_cast<std::uint32_t>(~p[1U]) & p[3U])); },
37-
[](const std::uint32_t* p) -> std::uint32_t { return static_cast<std::uint32_t>(static_cast<std::uint32_t>(p[1U] ^ p[2U]) ^ p[3U]); },
38-
[](const std::uint32_t* p) -> std::uint32_t { return static_cast<std::uint32_t>(static_cast<std::uint32_t>(p[1U] & p[2U]) | static_cast<std::uint32_t>(p[1U] & p[3U]) | static_cast<std::uint32_t>(p[2U] & p[3U])); },
39-
[](const std::uint32_t* p) -> std::uint32_t { return (static_cast<std::uint32_t>( p[1U] ^ p[2U]) ^ p[3U]); }
40-
};
41-
}
42-
4336
public:
44-
using result_type = std::array<std::uint8_t, static_cast<std::size_t>(UINT8_C(20))>;
45-
4637
hash_sha1() = default;
4738

4839
hash_sha1(const hash_sha1&) = default;
@@ -57,29 +48,14 @@
5748
{
5849
base_class_type::initialize();
5950

60-
transform_context[static_cast<std::size_t>(UINT8_C(0))] = static_cast<std::uint32_t>(UINT32_C(0x67452301));
61-
transform_context[static_cast<std::size_t>(UINT8_C(1))] = static_cast<std::uint32_t>(UINT32_C(0xEFCDAB89));
62-
transform_context[static_cast<std::size_t>(UINT8_C(2))] = static_cast<std::uint32_t>(UINT32_C(0x98BADCFE));
63-
transform_context[static_cast<std::size_t>(UINT8_C(3))] = static_cast<std::uint32_t>(UINT32_C(0x10325476));
64-
transform_context[static_cast<std::size_t>(UINT8_C(4))] = static_cast<std::uint32_t>(UINT32_C(0xC3D2E1F0));
65-
}
66-
67-
auto get_result(typename result_type::pointer result) -> void
68-
{
69-
// Extract the hash result from the message digest state.
70-
detail::convert_uint32_input_to_uint8_output_reverse
71-
(
72-
transform_context.data(),
73-
transform_context.data() + static_cast<std::size_t>(std::tuple_size<result_type>::value / sizeof(std::uint32_t)),
74-
result
75-
);
51+
base_class_type::transform_context[static_cast<std::size_t>(UINT8_C(0))] = static_cast<std::uint32_t>(UINT32_C(0x67452301));
52+
base_class_type::transform_context[static_cast<std::size_t>(UINT8_C(1))] = static_cast<std::uint32_t>(UINT32_C(0xEFCDAB89));
53+
base_class_type::transform_context[static_cast<std::size_t>(UINT8_C(2))] = static_cast<std::uint32_t>(UINT32_C(0x98BADCFE));
54+
base_class_type::transform_context[static_cast<std::size_t>(UINT8_C(3))] = static_cast<std::uint32_t>(UINT32_C(0x10325476));
55+
base_class_type::transform_context[static_cast<std::size_t>(UINT8_C(4))] = static_cast<std::uint32_t>(UINT32_C(0xC3D2E1F0));
7656
}
7757

7858
private:
79-
using context_type = std::array<std::uint32_t, static_cast<std::size_t>(std::tuple_size<result_type>::value / static_cast<std::size_t>(UINT8_C(4)))>;
80-
81-
context_type transform_context { };
82-
8359
auto perform_algorithm() -> void override;
8460
};
8561

@@ -90,7 +66,7 @@
9066

9167
using transform_constants_array_type = std::array<std::uint32_t, static_cast<std::size_t>(UINT8_C(4))>;
9268

93-
constexpr transform_constants_array_type transform_constants
69+
const transform_constants_array_type transform_constants
9470
{
9571
static_cast<std::uint32_t>(UINT32_C(0x5A827999)),
9672
static_cast<std::uint32_t>(UINT32_C(0x6ED9EBA1)),
@@ -105,11 +81,21 @@
10581
detail::convert_uint8_input_to_uint32_output_reverse
10682
(
10783
base_class_type::message_buffer.data(),
108-
base_class_type::message_buffer.data() + static_cast<std::size_t>(base_class_type::message_buffer_static_size),
84+
base_class_type::message_buffer.data() + static_cast<std::size_t>(base_class_type::message_buffer_static_size()),
10985
transform_block.data()
11086
);
11187

112-
auto hash_tmp = transform_context;
88+
using transform_function_type = std::uint32_t(*)(const std::uint32_t*);
89+
90+
const std::array<transform_function_type, static_cast<std::size_t>(UINT8_C(4))> transform_functions
91+
{
92+
[](const std::uint32_t* p) -> std::uint32_t { return (static_cast<std::uint32_t>( p[1U] & p[2U]) | static_cast<std::uint32_t>(static_cast<std::uint32_t>(~p[1U]) & p[3U])); },
93+
[](const std::uint32_t* p) -> std::uint32_t { return static_cast<std::uint32_t>(static_cast<std::uint32_t>(p[1U] ^ p[2U]) ^ p[3U]); },
94+
[](const std::uint32_t* p) -> std::uint32_t { return static_cast<std::uint32_t>(static_cast<std::uint32_t>(p[1U] & p[2U]) | static_cast<std::uint32_t>(p[1U] & p[3U]) | static_cast<std::uint32_t>(p[2U] & p[3U])); },
95+
[](const std::uint32_t* p) -> std::uint32_t { return (static_cast<std::uint32_t>( p[1U] ^ p[2U]) ^ p[3U]); }
96+
};
97+
98+
auto hash_tmp = base_class_type::transform_context;
11399

114100
auto loop_index = static_cast<std::uint8_t>(UINT8_C(0));
115101

@@ -141,7 +127,7 @@
141127
static_cast<std::uint32_t>
142128
(
143129
detail::circular_left_shift<static_cast<unsigned>(UINT8_C(5))>(hash_tmp[static_cast<std::size_t>(UINT8_C(0))])
144-
+ (transform_functions()[loop_index])(hash_tmp.data())
130+
+ (transform_functions[loop_index])(hash_tmp.data())
145131
+ hash_tmp[static_cast<std::size_t>(UINT8_C(4))]
146132
+ transform_block[static_cast<std::size_t>(loop_counter & static_cast<std::uint8_t>(UINT8_C(0x0F)))]
147133
+ transform_constants[loop_index]
@@ -155,15 +141,11 @@
155141
}
156142

157143
// Update the hash state with the transformation results.
158-
std::transform(transform_context.cbegin(),
159-
transform_context.cend (),
160-
hash_tmp.cbegin (),
161-
transform_context.begin (),
162-
std::plus<std::uint32_t>());
163-
164-
base_class_type::message_buffer.fill(static_cast<std::uint8_t>(UINT8_C(0)));
165-
166-
base_class_type::message_index = static_cast<std::uint_least16_t>(UINT8_C(0));
144+
std::transform(base_class_type::transform_context.cbegin(),
145+
base_class_type::transform_context.cend (),
146+
hash_tmp.cbegin (),
147+
base_class_type::transform_context.begin (),
148+
std::plus<std::uint32_t> ());
167149
}
168150

169151
} } } // namespace math::checksums::hash

0 commit comments

Comments
 (0)