Skip to content

Commit

Permalink
Merge pull request #1566 from evoskuil/master
Browse files Browse the repository at this point in the history
Native hash style, comments, optimization.
  • Loading branch information
evoskuil authored Dec 12, 2024
2 parents af5a0dc + f565476 commit 6ebf3b5
Show file tree
Hide file tree
Showing 9 changed files with 59 additions and 54 deletions.
4 changes: 2 additions & 2 deletions include/bitcoin/system/hash/sha/algorithm.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -234,8 +234,8 @@ class algorithm
INLINE static constexpr void input(buffer_t& buffer, const block_t& block) NOEXCEPT;
INLINE static constexpr void input_left(auto& buffer, const half_t& half) NOEXCEPT;
INLINE static constexpr void input_right(auto& buffer, const half_t& half) NOEXCEPT;
INLINE static constexpr void reinput_left(auto& buffer, const auto& left) NOEXCEPT;
INLINE static constexpr void reinput_right(auto& buffer, const auto& right) NOEXCEPT;
INLINE static constexpr void inject_left(auto& buffer, const auto& left) NOEXCEPT;
INLINE static constexpr void inject_right(auto& buffer, const auto& right) NOEXCEPT;
INLINE static constexpr digest_t output(const state_t& state) NOEXCEPT;

/// Padding.
Expand Down
24 changes: 12 additions & 12 deletions include/bitcoin/system/impl/hash/sha/algorithm_double.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ double_hash(const block_t& block) NOEXCEPT
{
static_assert(is_same_type<state_t, chunk_t>);

const auto hash2 = [](const block_t& block) NOEXCEPT
const auto hasher = [](const block_t& block) NOEXCEPT
{
auto state = H::get;
buffer_t buffer{};
Expand All @@ -95,7 +95,7 @@ double_hash(const block_t& block) NOEXCEPT
compress(state, buffer);

// Second hash
reinput_left(buffer, state);
inject_left(buffer, state);
pad_half(buffer);
schedule(buffer);
state = H::get;
Expand All @@ -106,15 +106,15 @@ double_hash(const block_t& block) NOEXCEPT

if (std::is_constant_evaluated())
{
return hash2(block);
return hasher(block);
}
else if constexpr (native && SHA::strength == 256)
{
return native_double_hash(block);
}
else
{
return hash2(block);
return hasher(block);
}
}

Expand All @@ -124,7 +124,7 @@ double_hash(const half_t& half) NOEXCEPT
{
static_assert(is_same_type<state_t, chunk_t>);

const auto hash2 = [](const half_t& half) NOEXCEPT
const auto hasher = [](const half_t& half) NOEXCEPT
{
auto state = H::get;
buffer_t buffer{};
Expand All @@ -134,7 +134,7 @@ double_hash(const half_t& half) NOEXCEPT
compress(state, buffer);

// Second hash
reinput_left(buffer, state);
inject_left(buffer, state);
pad_half(buffer);
schedule(buffer);
state = H::get;
Expand All @@ -145,15 +145,15 @@ double_hash(const half_t& half) NOEXCEPT

if (std::is_constant_evaluated())
{
return hash2(half);
return hasher(half);
}
else if constexpr (native && SHA::strength == 256)
{
return native_double_hash(half);
}
else
{
return hash2(half);
return hasher(half);
}
}

Expand All @@ -163,7 +163,7 @@ double_hash(const half_t& left, const half_t& right) NOEXCEPT
{
static_assert(is_same_type<state_t, chunk_t>);

const auto hash2 = [](const half_t& left, const half_t& right) NOEXCEPT
const auto hasher = [](const half_t& left, const half_t& right) NOEXCEPT
{
auto state = H::get;
buffer_t buffer{};
Expand All @@ -175,7 +175,7 @@ double_hash(const half_t& left, const half_t& right) NOEXCEPT
compress(state, buffer);

// Second hash
reinput_left(buffer, state);
inject_left(buffer, state);
pad_half(buffer);
schedule(buffer);
state = H::get;
Expand All @@ -186,15 +186,15 @@ double_hash(const half_t& left, const half_t& right) NOEXCEPT

if (std::is_constant_evaluated())
{
return hash2(left, right);
return hasher(left, right);
}
else if constexpr (native && SHA::strength == 256)
{
return native_double_hash(left, right);
}
else
{
return hash2(left, right);
return hasher(left, right);
}
}

Expand Down
4 changes: 2 additions & 2 deletions include/bitcoin/system/impl/hash/sha/algorithm_functions.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LIBBITCOIN_SYSTEM_HASH_SHA_ALGORITHM_FUCNTIONS_IPP
#define LIBBITCOIN_SYSTEM_HASH_SHA_ALGORITHM_FUCNTIONS_IPP
#ifndef LIBBITCOIN_SYSTEM_HASH_SHA_ALGORITHM_FUNCTIONS_IPP
#define LIBBITCOIN_SYSTEM_HASH_SHA_ALGORITHM_FUNCTIONS_IPP

// 4.1 Functions
// ============================================================================
Expand Down
19 changes: 10 additions & 9 deletions include/bitcoin/system/impl/hash/sha/algorithm_konstant.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -252,15 +252,16 @@ TEMPLATE
INLINE constexpr void CLASS::
konstant(buffer_t& buffer) NOEXCEPT
{
if (std::is_constant_evaluated())
{
konstant_(buffer);
}
else if constexpr (vector && !with_clang)
{
vector_konstant(buffer);
}
else
// This optimization is neutral in 4/8/16 lane sha256 perf.
////if (std::is_constant_evaluated())
////{
//// konstant_(buffer);
////}
////else if constexpr (vector && !with_clang)
////{
//// vector_konstant(buffer);
////}
////else
{
konstant_(buffer);
}
Expand Down
2 changes: 1 addition & 1 deletion include/bitcoin/system/impl/hash/sha/algorithm_merkle.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,7 @@ merkle_hash_vector(idigests_t& digests, iblocks_t& blocks) NOEXCEPT
compress_(xstate, xbuffer);

// Second hash
reinput_left(xbuffer, xstate);
inject_left(xbuffer, xstate);
pad_half(xbuffer);
schedule_(xbuffer);
xstate = initial;
Expand Down
36 changes: 18 additions & 18 deletions include/bitcoin/system/impl/hash/sha/algorithm_native.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@

// Native (SHA-NI or NEON)
// ============================================================================
// The iterative method is used for sha native as it is an order of magnitude
// more efficient and cannot benefit from vectorization.
// The rotating variables method is used for sha native. Tha native
// instructions rely on register locality to achieve performance benefits.
// Implementation of native sha using buffer expansion is horribly slow.
// This split creates bifurcations (additional complexities) in this template.

namespace libbitcoin {
namespace system {
Expand Down Expand Up @@ -98,9 +100,6 @@ round_4(xint128_t& state0, xint128_t& state1, xint128_t message) NOEXCEPT

// Platform agnostic.
// ----------------------------------------------------------------------------
// Individual state vars are used vs. array to ensure register persistence.
// This creates bifurcations in this template because of the lack of a buffer
// and the differing optimal locations for applying endianness conversions.

TEMPLATE
template <bool Swap>
Expand Down Expand Up @@ -223,6 +222,9 @@ native_transform(state_t& state, const auto& block) NOEXCEPT
// accumulation and performs big-endian conversion from state_t to digest_t.
// As padding blocks are generated and therefore do not require endianness
// conversion, those calls are not applied when transforming the pad block.
// This lack of conversion also applies to double hashing. In both cases
// the "inject" functions are using in place of the "input" functions.
// There is no benefit to caching pading because it is not prescheduled.
// ----------------------------------------------------------------------------

TEMPLATE
Expand Down Expand Up @@ -251,8 +253,6 @@ template <size_t Blocks>
typename CLASS::digest_t CLASS::
native_finalize(state_t& state) NOEXCEPT
{
// We could use Blocks to cache padding but given the padding blocks are
// unscheduled when performing native transformations there's no benefit.
return native_finalize(state, Blocks);
}

Expand All @@ -273,7 +273,7 @@ native_finalize_second(const state_t& state) NOEXCEPT
// Hash a state value and finalize it.
auto state2 = H::get;
words_t block{};
reinput_left(block, state); // swapped
inject_left(block, state); // swapped
pad_half(block); // swapped
return native_finalize(state2, block); // no block swap (swaps state)
}
Expand All @@ -288,7 +288,7 @@ native_finalize_double(state_t& state, size_t blocks) NOEXCEPT

// This is native_finalize_second() but reuses the initial block.
auto state2 = H::get;
reinput_left(block, state); // swapped
inject_left(block, state); // swapped
pad_half(block); // swapped
return native_finalize(state2, block); // no block swap (swaps state)
}
Expand Down Expand Up @@ -316,8 +316,8 @@ native_hash(const half_t& left, const half_t& right) NOEXCEPT
{
auto state = H::get;
words_t block{};
reinput_left(block, array_cast<word_t>(left)); // unswapped
reinput_right(block, array_cast<word_t>(right)); // unswapped
inject_left(block, array_cast<word_t>(left)); // unswapped
inject_right(block, array_cast<word_t>(right)); // unswapped
native_transform<true>(state, block); // swap
return native_finalize<one>(state); // no block swap (swaps state)
}
Expand All @@ -335,7 +335,7 @@ native_double_hash(const block_t& block) NOEXCEPT

// Second hash
words_t block2{};
reinput_left(block2, state); // swapped
inject_left(block2, state); // swapped
pad_half(block2); // swapped
state = H::get; // [reuse state var]
return native_finalize(state, block2); // no block swap (swaps state)
Expand All @@ -352,7 +352,7 @@ native_double_hash(const half_t& half) NOEXCEPT
native_transform<false>(state, block); // no block swap

// Second hash
reinput_left(block, state); // swapped
inject_left(block, state); // swapped
pad_half(block); // swapped
state = H::get; // [reuse state var]
return native_finalize(state, block); // no block swap (swaps state)
Expand All @@ -364,13 +364,13 @@ native_double_hash(const half_t& left, const half_t& right) NOEXCEPT
{
auto state = H::get;
words_t block{};
reinput_left(block, array_cast<word_t>(left)); // unswapped
reinput_right(block, array_cast<word_t>(right)); // unswapped
native_transform<true>(state, block); // swap
native_transform<false>(state, pad_block()); // swapped
inject_left(block, array_cast<word_t>(left)); // unswapped
inject_right(block, array_cast<word_t>(right)); // unswapped
native_transform<true>(state, block); // swap
native_transform<false>(state, pad_block()); // swapped

// Second hash
reinput_left(block, state); // swapped
inject_left(block, state); // swapped
pad_half(block); // swapped
state = H::get; // [reuse state var]
return native_finalize(state, block); // no block swap (swaps state)
Expand Down
8 changes: 6 additions & 2 deletions include/bitcoin/system/impl/hash/sha/algorithm_parsing.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ input(buffer_t& buffer, const block_t& block) NOEXCEPT
}
else if constexpr (bc::is_little_endian)
{
// This optimization is neutral in 4/8/16 lane sha256 perf.
////if constexpr (have_lanes<word_t, 16> && !with_clang)
////{
//// using xword_t = to_extended<word_t, 16>;
Expand Down Expand Up @@ -131,6 +132,7 @@ input_left(auto& buffer, const half_t& half) NOEXCEPT
}
else if constexpr (bc::is_little_endian)
{
// This optimization is neutral in 4/8 lane sha256 perf.
////if constexpr (have_lanes<word_t, 8> && !with_clang)
////{
//// using xword_t = to_extended<word_t, 8>;
Expand Down Expand Up @@ -185,6 +187,7 @@ input_right(auto& buffer, const half_t& half) NOEXCEPT
}
else if constexpr (bc::is_little_endian)
{
// This optimization is neutral in 4/8 lane sha256 perf.
////if constexpr (have_lanes<word_t, 8> && !with_clang)
////{
//// using xword_t = to_extended<word_t, 8>;
Expand Down Expand Up @@ -248,6 +251,7 @@ output(const state_t& state) NOEXCEPT
{
if constexpr (SHA::strength != 160)
{
// This optimization is neutral in 4/8 lane sha256 perf.
////if constexpr (have_lanes<word_t, 8> && !with_clang)
////{
//// using xword_t = to_extended<word_t, 8>;
Expand Down Expand Up @@ -306,7 +310,7 @@ output(const state_t& state) NOEXCEPT

TEMPLATE
INLINE constexpr void CLASS::
reinput_left(auto& buffer, const auto& left) NOEXCEPT
inject_left(auto& buffer, const auto& left) NOEXCEPT
{
using words = decltype(buffer);
static_assert(array_count<words> >= SHA::state_words);
Expand All @@ -331,7 +335,7 @@ reinput_left(auto& buffer, const auto& left) NOEXCEPT

TEMPLATE
INLINE constexpr void CLASS::
reinput_right(auto& buffer, const auto& right) NOEXCEPT
inject_right(auto& buffer, const auto& right) NOEXCEPT
{
using words = decltype(buffer);
static_assert(array_count<words> >= SHA::state_words);
Expand Down
12 changes: 6 additions & 6 deletions include/bitcoin/system/impl/hash/sha/algorithm_single.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ TEMPLATE
constexpr typename CLASS::digest_t CLASS::
hash(const half_t& half) NOEXCEPT
{
const auto hash1 = [](const half_t& half) NOEXCEPT
const auto hasher = [](const half_t& half) NOEXCEPT
{
auto state = H::get;
buffer_t buffer{};
Expand All @@ -75,23 +75,23 @@ hash(const half_t& half) NOEXCEPT

if (std::is_constant_evaluated())
{
return hash1(half);
return hasher(half);
}
else if constexpr (native && SHA::strength == 256)
{
return native_hash(half);
}
else
{
return hash1(half);
return hasher(half);
}
}

TEMPLATE
constexpr typename CLASS::digest_t CLASS::
hash(const half_t& left, const half_t& right) NOEXCEPT
{
const auto hash1 = [](const half_t& left, const half_t& right) NOEXCEPT
const auto hasher = [](const half_t& left, const half_t& right) NOEXCEPT
{
auto state = H::get;
buffer_t buffer{};
Expand All @@ -106,15 +106,15 @@ hash(const half_t& left, const half_t& right) NOEXCEPT

if (std::is_constant_evaluated())
{
return hash1(left, right);
return hasher(left, right);
}
else if constexpr (native && SHA::strength == 256)
{
return native_hash(left, right);
}
else
{
return hash1(left, right);
return hasher(left, right);
}
}

Expand Down
4 changes: 2 additions & 2 deletions include/bitcoin/system/impl/hash/sha/algorithm_stream.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ finalize_second(const state_t& state) NOEXCEPT
{
auto state2 = H::get;
buffer_t buffer{};
reinput_left(buffer, state);
inject_left(buffer, state);
pad_half(buffer);
schedule(buffer);
compress(state2, buffer);
Expand Down Expand Up @@ -150,7 +150,7 @@ finalize_double(state_t& state, size_t blocks) NOEXCEPT

// This is finalize_second() but reuses the initial buffer.
auto state2 = H::get;
reinput_left(buffer, state);
inject_left(buffer, state);
pad_half(buffer);
schedule(buffer);
compress(state2, buffer);
Expand Down

0 comments on commit 6ebf3b5

Please sign in to comment.