Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix native_finalize for non-default digest lengths, impl native qtr opt. #1587

Merged
merged 4 commits into from
Jan 21, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 10 additions & 5 deletions include/bitcoin/system/hash/sha/algorithm.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -236,13 +236,17 @@ class algorithm
/// -----------------------------------------------------------------------

INLINE static constexpr void input(buffer_t& buffer, const block_t& block) NOEXCEPT;
INLINE static constexpr void input_left(auto& buffer, const quart_t& quarter) NOEXCEPT;
INLINE static constexpr void input_right(auto& buffer, const quart_t& quarter) NOEXCEPT;
INLINE static constexpr digest_t output(const state_t& state) 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 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;
INLINE static constexpr void input_left(auto& buffer, const quart_t& quarter) NOEXCEPT;
INLINE static constexpr void input_right(auto& buffer, const quart_t& quarter) NOEXCEPT;

INLINE static constexpr void inject_left_half(auto& buffer, const auto& left) NOEXCEPT;
INLINE static constexpr void inject_right_half(auto& buffer, const auto& right) NOEXCEPT;
INLINE static constexpr void inject_left_quarter(auto& buffer, const auto& left) NOEXCEPT;
INLINE static constexpr void inject_right_quarter(auto& buffer, const auto& right) NOEXCEPT;

/// Padding.
/// -----------------------------------------------------------------------
Expand Down Expand Up @@ -409,6 +413,7 @@ class algorithm
static digest_t native_hash(const block_t& block) NOEXCEPT;
static digest_t native_hash(const half_t& half) NOEXCEPT;
static digest_t native_hash(const half_t& left, const half_t& right) NOEXCEPT;
static digest_t native_hash(const quart_t& left, const quart_t& right) NOEXCEPT;
static digest_t native_hash(uint8_t byte) NOEXCEPT;

static digest_t native_double_hash(const block_t& block) NOEXCEPT;
Expand Down
6 changes: 3 additions & 3 deletions include/bitcoin/system/impl/hash/sha/algorithm_double.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ double_hash(const block_t& block) NOEXCEPT
compress(state, buffer);

// Second hash
inject_left(buffer, state);
inject_left_half(buffer, state);
pad_half(buffer);
schedule(buffer);
state = H::get;
Expand Down Expand Up @@ -134,7 +134,7 @@ double_hash(const half_t& half) NOEXCEPT
compress(state, buffer);

// Second hash
inject_left(buffer, state);
inject_left_half(buffer, state);
pad_half(buffer);
schedule(buffer);
state = H::get;
Expand Down Expand Up @@ -175,7 +175,7 @@ double_hash(const half_t& left, const half_t& right) NOEXCEPT
compress(state, buffer);

// Second hash
inject_left(buffer, state);
inject_left_half(buffer, state);
pad_half(buffer);
schedule(buffer);
state = H::get;
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
inject_left(xbuffer, xstate);
inject_left_half(xbuffer, xstate);
pad_half(xbuffer);
schedule_(xbuffer);
xstate = initial;
Expand Down
46 changes: 30 additions & 16 deletions include/bitcoin/system/impl/hash/sha/algorithm_native.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -268,11 +268,10 @@ native_finalize(state_t& state, const words_t& pad) NOEXCEPT
unshuffle(lo, hi);

// digest is copied so that state remains valid (LE).
digest_t digest{};
auto& wdigest = array_cast<xint128_t>(digest);
std::array<xint128_t, 2> wdigest{};
store(wdigest[0], byteswap<uint32_t>(lo));
store(wdigest[1], byteswap<uint32_t>(hi));
return digest;
return array_cast<byte_t, sizeof(digest_t)>(wdigest);
}

TEMPLATE
Expand All @@ -285,7 +284,7 @@ native_finalize_second(const state_t& state) NOEXCEPT
// Hash a state value and finalize it.
auto state2 = H::get;
words_t block{};
inject_left(block, state);
inject_left_half(block, state);
pad_half(block);
return native_finalize(state2, block);
}
Expand All @@ -300,7 +299,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;
inject_left(block, state);
inject_left_half(block, state);
pad_half(block);
return native_finalize(state2, block);
}
Expand Down Expand Up @@ -338,23 +337,38 @@ native_hash(const half_t& left, const half_t& right) NOEXCEPT
{
auto state = H::get;
words_t block{};
inject_left(block, array_cast<word_t>(left));
inject_right(block, array_cast<word_t>(right));
inject_left_half(block, array_cast<word_t>(left));
inject_right_half(block, array_cast<word_t>(right));
native_transform<true>(state, block);
return native_finalize<one>(state);
}

TEMPLATE
typename CLASS::digest_t CLASS::
native_hash(const quart_t& left, const quart_t& right) NOEXCEPT
{
auto state = H::get;
words_t block{};
inject_left_quarter(block, array_cast<word_t>(left));
inject_right_quarter(block, array_cast<word_t>(right));
pad_half(block);
return native_finalize(state, block);
}

TEMPLATE
typename CLASS::digest_t CLASS::
native_hash(uint8_t byte) NOEXCEPT
{
constexpr auto pad = bit_hi<uint8_t>;

auto state = H::get;
block_t block{};
block.at(0) = byte;
block.at(1) = pad;
block.at(63) = byte_bits;
return native_hash(block);

// Order is based on array of little-endian uint32_t.
block.at(3) = byte;
block.at(2) = pad;
block.at(60) = byte_bits;
return native_finalize(state, array_cast<word_t>(block));
}

// Double hash functions start with BE data and end with BE digest_t.
Expand All @@ -370,7 +384,7 @@ native_double_hash(const block_t& block) NOEXCEPT

// Second hash
words_t block2{};
inject_left(block2, state);
inject_left_half(block2, state);
pad_half(block2);
state = H::get;
return native_finalize(state, block2);
Expand All @@ -388,7 +402,7 @@ native_double_hash(const half_t& half) NOEXCEPT
native_transform<false>(state, block);

// Second hash
inject_left(block, state);
inject_left_half(block, state);
pad_half(block);
state = H::get;
return native_finalize(state, block);
Expand All @@ -400,13 +414,13 @@ native_double_hash(const half_t& left, const half_t& right) NOEXCEPT
{
auto state = H::get;
words_t block{};
inject_left(block, array_cast<word_t>(left));
inject_right(block, array_cast<word_t>(right));
inject_left_half(block, array_cast<word_t>(left));
inject_right_half(block, array_cast<word_t>(right));
native_transform<true>(state, block);
native_transform<false>(state, pad_block());

// Second hash
inject_left(block, state);
inject_left_half(block, state);
pad_half(block);
state = H::get;
return native_finalize(state, block);
Expand Down
51 changes: 41 additions & 10 deletions include/bitcoin/system/impl/hash/sha/algorithm_parsing.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -410,11 +410,8 @@ output(const state_t& state) NOEXCEPT

TEMPLATE
INLINE constexpr void CLASS::
inject_left(auto& buffer, const auto& left) NOEXCEPT
inject_left_half(auto& buffer, const auto& left) NOEXCEPT
{
using words = decltype(buffer);
static_assert(array_count<words> >= SHA::state_words);

if (std::is_constant_evaluated())
{
buffer.at(0) = left.at(0);
Expand All @@ -428,18 +425,15 @@ inject_left(auto& buffer, const auto& left) NOEXCEPT
}
else
{
using word = array_element<words>;
using word = array_element<decltype(buffer)>;
array_cast<word, SHA::state_words>(buffer) = left;
}
}

TEMPLATE
INLINE constexpr void CLASS::
inject_right(auto& buffer, const auto& right) NOEXCEPT
inject_right_half(auto& buffer, const auto& right) NOEXCEPT
{
using words = decltype(buffer);
static_assert(array_count<words> >= SHA::state_words);

if (std::is_constant_evaluated())
{
buffer.at(8) = right.at(0);
Expand All @@ -453,11 +447,48 @@ inject_right(auto& buffer, const auto& right) NOEXCEPT
}
else
{
using word = array_element<words>;
using word = array_element<decltype(buffer)>;
array_cast<word, SHA::state_words, SHA::state_words>(buffer) = right;
}
}

TEMPLATE
INLINE constexpr void CLASS::
inject_left_quarter(auto& buffer, const auto& left) NOEXCEPT
{
if (std::is_constant_evaluated())
{
buffer.at(0) = left.at(0);
buffer.at(1) = left.at(1);
buffer.at(2) = left.at(2);
buffer.at(3) = left.at(3);
}
else
{
using word = array_element<decltype(buffer)>;
array_cast<word, to_half(SHA::state_words)>(buffer) = left;
}
}

TEMPLATE
INLINE constexpr void CLASS::
inject_right_quarter(auto& buffer, const auto& right) NOEXCEPT
{
if (std::is_constant_evaluated())
{
buffer.at(4) = right.at(0);
buffer.at(5) = right.at(1);
buffer.at(6) = right.at(2);
buffer.at(7) = right.at(3);
}
else
{
using word = array_element<decltype(buffer)>;
constexpr auto words = to_half(SHA::state_words);
array_cast<word, words, words>(buffer) = right;
}
}

} // namespace sha
} // namespace system
} // namespace libbitcoin
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{};
inject_left(buffer, state);
inject_left_half(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;
inject_left(buffer, state);
inject_left_half(buffer, state);
pad_half(buffer);
schedule(buffer);
compress(state2, buffer);
Expand Down
2 changes: 1 addition & 1 deletion test/hash/sha/sha256.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ BOOST_AUTO_TEST_CASE(sha256_224__ttt_accumulator_hash__test_vectors__expected)
using sha_256_224 = sha::algorithm<sha::h256<224>, true, true, true>;

// Native only for sha256 (and sha160 when implemented).
static_assert(!sha_256_224::native);
static_assert(sha_256_224::native == native);
static_assert(sha_256_224::vector == vector);
static_assert(sha_256_224::caching);

Expand Down
Loading