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
2727namespace libbitcoin {
2828namespace system {
@@ -33,30 +33,57 @@ namespace sha {
3333
3434TEMPLATE
3535INLINE 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
6188TEMPLATE
6289template <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
85112TEMPLATE
@@ -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
111134TEMPLATE
@@ -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
136174TEMPLATE
@@ -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
160213TEMPLATE
@@ -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