Skip to content

Commit 9b16970

Browse files
authored
Merge pull request #1562 from evoskuil/master
Complete shani integration.
2 parents 0cdbe08 + d7c9261 commit 9b16970

10 files changed

Lines changed: 613 additions & 286 deletions

File tree

include/bitcoin/system/hash/sha/algorithm.hpp

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,9 @@ class algorithm
113113
static void accumulate(state_t& state, iblocks_t&& blocks) NOEXCEPT;
114114
static constexpr void accumulate(state_t& state, const block_t& block) NOEXCEPT;
115115
static constexpr digest_t normalize(const state_t& state) NOEXCEPT;
116+
117+
template <size_t Blocks>
118+
static constexpr digest_t finalize(state_t& state) NOEXCEPT;
116119
static constexpr digest_t finalize(state_t& state, size_t blocks) NOEXCEPT;
117120
static constexpr digest_t finalize_second(const state_t& state) NOEXCEPT;
118121
static constexpr digest_t finalize_double(state_t& state, size_t blocks) NOEXCEPT;
@@ -166,9 +169,6 @@ class algorithm
166169
template <typename xWord, if_extended<xWord> = true>
167170
using wstate_t = std_array<xWord, sizeof(state_t) / sizeof(xWord)>;
168171

169-
////template <typename xWord, if_extended<xWord> = true>
170-
////using wblock_t = std_array<xWord, sizeof(block_t) / sizeof(xWord)>;
171-
172172
/// Other types.
173173
/// -----------------------------------------------------------------------
174174

@@ -232,8 +232,8 @@ class algorithm
232232
/// -----------------------------------------------------------------------
233233

234234
INLINE static constexpr void input(buffer_t& buffer, const block_t& block) NOEXCEPT;
235-
INLINE static constexpr void input_left(buffer_t& buffer, const half_t& half) NOEXCEPT;
236-
INLINE static constexpr void input_right(buffer_t& buffer, const half_t& half) NOEXCEPT;
235+
INLINE static constexpr void input_left(auto& buffer, const half_t& half) NOEXCEPT;
236+
INLINE static constexpr void input_right(auto& buffer, const half_t& half) NOEXCEPT;
237237
INLINE static constexpr digest_t output(const state_t& state) NOEXCEPT;
238238

239239
/// Padding.
@@ -260,7 +260,8 @@ class algorithm
260260
/// Double hashing.
261261
/// -----------------------------------------------------------------------
262262

263-
static constexpr void reinput(auto& buffer, const auto& state) NOEXCEPT;
263+
static constexpr void reinput_left(auto& buffer, const auto& left) NOEXCEPT;
264+
static constexpr void reinput_right(auto& buffer, const auto& right) NOEXCEPT;
264265

265266
/// Iteration (message scheduling vectorized for multiple blocks).
266267
/// -----------------------------------------------------------------------
@@ -385,13 +386,30 @@ class algorithm
385386
xint128_t message) NOEXCEPT;
386387

387388
template <bool Swap>
388-
INLINE static void native_rounds(xint128_t& lo, xint128_t& hi,
389+
static void native_rounds(xint128_t& lo, xint128_t& hi,
389390
const block_t& block) NOEXCEPT;
390391

391-
static void native_(state_t& state, iblocks_t& blocks) NOEXCEPT;
392-
static void native_(state_t& state, const block_t& block) NOEXCEPT;
393-
INLINE static void native_preswapped(state_t& state,
394-
const words_t& block) NOEXCEPT;
392+
template <bool Swap>
393+
static void native_transform(state_t& state, const auto& block) NOEXCEPT;
394+
static void native_transform(state_t& state, iblocks_t& blocks) NOEXCEPT;
395+
396+
template <size_t Blocks>
397+
static digest_t native_finalize(state_t& state) NOEXCEPT;
398+
static digest_t native_finalize(state_t& state, size_t blocks) NOEXCEPT;
399+
static digest_t native_finalize(state_t& state, const words_t& pad) NOEXCEPT;
400+
401+
static digest_t native_finalize_second(const state_t& half) NOEXCEPT;
402+
static digest_t native_finalize_double(state_t& half, size_t blocks) NOEXCEPT;
403+
404+
////static digest_t native_hash(const block_t& block) NOEXCEPT;
405+
static digest_t native_hash(const half_t& half) NOEXCEPT;
406+
static digest_t native_hash(const half_t& left, const half_t& right) NOEXCEPT;
407+
408+
static digest_t native_double_hash(const block_t& block) NOEXCEPT;
409+
static digest_t native_double_hash(const half_t& half) NOEXCEPT;
410+
static digest_t native_double_hash(const half_t& left, const half_t& right) NOEXCEPT;
411+
412+
395413

396414
public:
397415
/// Summary public values.

include/bitcoin/system/have.hpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,6 @@
130130

131131
/// XCPU architecture intrinsics sse41, avx2, avx512f, sha-ni.
132132
/// This assumes that avx512 implies avx2 and that all imply sse41.
133-
/// All require runtime evaluation for the binary is portable across XCPUs.
134133
#if defined(HAVE_XCPU)
135134
// TODO: CLANG/GCC compile test and set -msse4 -mavx2 -mavx512f -msha.
136135
#if defined(WITH_SHANI)

include/bitcoin/system/impl/hash/sha/algorithm_double.ipp

Lines changed: 153 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
// Double hashing.
2323
// ============================================================================
2424
// No hash(state_t) optimizations for sha160 (requires chunk_t/half_t).
25-
// State input directly to buffer (reinput) eliminates two endianness calls.
25+
// State put directly to buffer (reinput) eliminates two endianness transforms.
2626

2727
namespace libbitcoin {
2828
namespace system {
@@ -33,30 +33,57 @@ namespace sha {
3333

3434
TEMPLATE
3535
INLINE constexpr void CLASS::
36-
reinput(auto& buffer, const auto& state) NOEXCEPT
36+
reinput_left(auto& buffer, const auto& left) NOEXCEPT
3737
{
38-
static_assert(SHA::strength != 160);
38+
using words = decltype(buffer);
39+
static_assert(array_count<words> >= SHA::state_words);
3940

4041
if (std::is_constant_evaluated())
4142
{
42-
buffer[0] = state[0];
43-
buffer[1] = state[1];
44-
buffer[2] = state[2];
45-
buffer[3] = state[3];
46-
buffer[4] = state[4];
47-
buffer[5] = state[5];
48-
buffer[6] = state[6];
49-
buffer[7] = state[7];
43+
buffer.at(0) = left.at(0);
44+
buffer.at(1) = left.at(1);
45+
buffer.at(2) = left.at(2);
46+
buffer.at(3) = left.at(3);
47+
buffer.at(4) = left.at(4);
48+
buffer.at(5) = left.at(5);
49+
buffer.at(6) = left.at(6);
50+
buffer.at(7) = left.at(7);
5051
}
5152
else
5253
{
53-
using word = array_element<decltype(state)>;
54-
array_cast<word, SHA::state_words>(buffer) = state;
54+
using word = array_element<words>;
55+
array_cast<word, SHA::state_words>(buffer) = left;
56+
}
57+
}
58+
59+
TEMPLATE
60+
INLINE constexpr void CLASS::
61+
reinput_right(auto& buffer, const auto& right) NOEXCEPT
62+
{
63+
using words = decltype(buffer);
64+
static_assert(array_count<words> >= SHA::state_words);
65+
66+
if (std::is_constant_evaluated())
67+
{
68+
buffer.at(8) = right.at(0);
69+
buffer.at(9) = right.at(1);
70+
buffer.at(10) = right.at(2);
71+
buffer.at(11) = right.at(3);
72+
buffer.at(12) = right.at(4);
73+
buffer.at(13) = right.at(5);
74+
buffer.at(14) = right.at(6);
75+
buffer.at(15) = right.at(7);
76+
}
77+
else
78+
{
79+
using word = array_element<words>;
80+
array_cast<word, SHA::state_words, SHA::state_words>(buffer) = right;
5581
}
5682
}
5783

5884
// public
5985
// ----------------------------------------------------------------------------
86+
// These benefit from avoiding state endian transition and reusing buffer.
6087

6188
TEMPLATE
6289
template <size_t Size>
@@ -68,18 +95,18 @@ double_hash(const ablocks_t<Size>& blocks) NOEXCEPT
6895
auto state = H::get;
6996
iterate(state, blocks);
7097

71-
buffer_t buffer{};
72-
schedule_n<Size>(buffer);
73-
compress(state, buffer);
74-
75-
// Second hash
76-
reinput(buffer, state);
77-
pad_half(buffer);
78-
schedule(buffer);
79-
state = H::get;
80-
compress(state, buffer);
81-
82-
return output(state);
98+
if (std::is_constant_evaluated())
99+
{
100+
return finalize_double(state, Size);
101+
}
102+
else if constexpr (native && SHA::strength == 256)
103+
{
104+
return native_finalize_double(state, Size);
105+
}
106+
else
107+
{
108+
return finalize_double(state, Size);
109+
}
83110
}
84111

85112
TEMPLATE
@@ -94,18 +121,14 @@ double_hash(iblocks_t&& blocks) NOEXCEPT
94121
auto state = H::get;
95122
iterate(state, blocks);
96123

97-
buffer_t buffer{};
98-
schedule_n(buffer, count);
99-
compress(state, buffer);
100-
101-
// Second hash
102-
reinput(buffer, state);
103-
pad_half(buffer);
104-
schedule(buffer);
105-
state = H::get;
106-
compress(state, buffer);
107-
108-
return output(state);
124+
if constexpr (native && SHA::strength == 256)
125+
{
126+
return native_finalize_double(state, count);
127+
}
128+
else
129+
{
130+
return finalize_double(state, count);
131+
}
109132
}
110133

111134
TEMPLATE
@@ -114,23 +137,38 @@ double_hash(const block_t& block) NOEXCEPT
114137
{
115138
static_assert(is_same_type<state_t, chunk_t>);
116139

117-
auto state = H::get;
140+
const auto hash2 = [](const block_t& block) NOEXCEPT
141+
{
142+
auto state = H::get;
143+
buffer_t buffer{};
144+
input(buffer, block);
145+
schedule(buffer);
146+
compress(state, buffer);
147+
schedule_1(buffer);
148+
compress(state, buffer);
149+
150+
// Second hash
151+
reinput_left(buffer, state);
152+
pad_half(buffer);
153+
schedule(buffer);
154+
state = H::get;
155+
compress(state, buffer);
156+
157+
return output(state);
158+
};
118159

119-
buffer_t buffer{};
120-
input(buffer, block);
121-
schedule(buffer);
122-
compress(state, buffer);
123-
schedule_1(buffer);
124-
compress(state, buffer);
125-
126-
// Second hash
127-
reinput(buffer, state);
128-
pad_half(buffer);
129-
schedule(buffer);
130-
state = H::get;
131-
compress(state, buffer);
132-
133-
return output(state);
160+
if (std::is_constant_evaluated())
161+
{
162+
return hash2(block);
163+
}
164+
else if constexpr (native && SHA::strength == 256)
165+
{
166+
return native_double_hash(block);
167+
}
168+
else
169+
{
170+
return hash2(block);
171+
}
134172
}
135173

136174
TEMPLATE
@@ -139,22 +177,37 @@ double_hash(const half_t& half) NOEXCEPT
139177
{
140178
static_assert(is_same_type<state_t, chunk_t>);
141179

142-
auto state = H::get;
143-
144-
buffer_t buffer{};
145-
input_left(buffer, half);
146-
pad_half(buffer);
147-
schedule(buffer);
148-
compress(state, buffer);
149-
150-
// Second hash
151-
reinput(buffer, state);
152-
pad_half(buffer);
153-
schedule(buffer);
154-
state = H::get;
155-
compress(state, buffer);
180+
const auto hash2 = [](const half_t& half) NOEXCEPT
181+
{
182+
auto state = H::get;
183+
buffer_t buffer{};
184+
input_left(buffer, half);
185+
pad_half(buffer);
186+
schedule(buffer);
187+
compress(state, buffer);
188+
189+
// Second hash
190+
reinput_left(buffer, state);
191+
pad_half(buffer);
192+
schedule(buffer);
193+
state = H::get;
194+
compress(state, buffer);
195+
196+
return output(state);
197+
};
156198

157-
return output(state);
199+
if (std::is_constant_evaluated())
200+
{
201+
return hash2(half);
202+
}
203+
else if constexpr (native && SHA::strength == 256)
204+
{
205+
return native_double_hash(half);
206+
}
207+
else
208+
{
209+
return hash2(half);
210+
}
158211
}
159212

160213
TEMPLATE
@@ -163,24 +216,39 @@ double_hash(const half_t& left, const half_t& right) NOEXCEPT
163216
{
164217
static_assert(is_same_type<state_t, chunk_t>);
165218

166-
auto state = H::get;
219+
const auto hash2 = [](const half_t& left, const half_t& right) NOEXCEPT
220+
{
221+
auto state = H::get;
222+
buffer_t buffer{};
223+
input_left(buffer, left);
224+
input_right(buffer, right);
225+
schedule(buffer);
226+
compress(state, buffer);
227+
schedule_1(buffer);
228+
compress(state, buffer);
229+
230+
// Second hash
231+
reinput_left(buffer, state);
232+
pad_half(buffer);
233+
schedule(buffer);
234+
state = H::get;
235+
compress(state, buffer);
236+
237+
return output(state);
238+
};
167239

168-
buffer_t buffer{};
169-
input_left(buffer, left);
170-
input_right(buffer, right);
171-
schedule(buffer);
172-
compress(state, buffer);
173-
schedule_1(buffer);
174-
compress(state, buffer);
175-
176-
// Second hash
177-
reinput(buffer, state);
178-
pad_half(buffer);
179-
schedule(buffer);
180-
state = H::get;
181-
compress(state, buffer);
182-
183-
return output(state);
240+
if (std::is_constant_evaluated())
241+
{
242+
return hash2(left, right);
243+
}
244+
else if constexpr (native && SHA::strength == 256)
245+
{
246+
return native_double_hash(left, right);
247+
}
248+
else
249+
{
250+
return hash2(left, right);
251+
}
184252
}
185253

186254
} // namespace sha

0 commit comments

Comments
 (0)