diff --git a/include/bitcoin/system/hash/sha/algorithm.hpp b/include/bitcoin/system/hash/sha/algorithm.hpp index 4ccf039c92..400460b5c8 100644 --- a/include/bitcoin/system/hash/sha/algorithm.hpp +++ b/include/bitcoin/system/hash/sha/algorithm.hpp @@ -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. /// ----------------------------------------------------------------------- @@ -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; diff --git a/include/bitcoin/system/impl/hash/sha/algorithm_double.ipp b/include/bitcoin/system/impl/hash/sha/algorithm_double.ipp index 2f8dd963a9..b9b6232f63 100644 --- a/include/bitcoin/system/impl/hash/sha/algorithm_double.ipp +++ b/include/bitcoin/system/impl/hash/sha/algorithm_double.ipp @@ -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; @@ -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; @@ -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; diff --git a/include/bitcoin/system/impl/hash/sha/algorithm_merkle.ipp b/include/bitcoin/system/impl/hash/sha/algorithm_merkle.ipp index ce3bf97f9c..6df45eee13 100644 --- a/include/bitcoin/system/impl/hash/sha/algorithm_merkle.ipp +++ b/include/bitcoin/system/impl/hash/sha/algorithm_merkle.ipp @@ -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; diff --git a/include/bitcoin/system/impl/hash/sha/algorithm_native.ipp b/include/bitcoin/system/impl/hash/sha/algorithm_native.ipp index 346969dc5e..e5ffb5d895 100644 --- a/include/bitcoin/system/impl/hash/sha/algorithm_native.ipp +++ b/include/bitcoin/system/impl/hash/sha/algorithm_native.ipp @@ -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(digest); + std::array wdigest{}; store(wdigest[0], byteswap(lo)); store(wdigest[1], byteswap(hi)); - return digest; + return array_cast(wdigest); } TEMPLATE @@ -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); } @@ -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); } @@ -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(left)); - inject_right(block, array_cast(right)); + inject_left_half(block, array_cast(left)); + inject_right_half(block, array_cast(right)); native_transform(state, block); return native_finalize(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(left)); + inject_right_quarter(block, array_cast(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; + 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(block)); } // Double hash functions start with BE data and end with BE digest_t. @@ -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); @@ -388,7 +402,7 @@ native_double_hash(const half_t& half) NOEXCEPT native_transform(state, block); // Second hash - inject_left(block, state); + inject_left_half(block, state); pad_half(block); state = H::get; return native_finalize(state, block); @@ -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(left)); - inject_right(block, array_cast(right)); + inject_left_half(block, array_cast(left)); + inject_right_half(block, array_cast(right)); native_transform(state, block); native_transform(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); diff --git a/include/bitcoin/system/impl/hash/sha/algorithm_parsing.ipp b/include/bitcoin/system/impl/hash/sha/algorithm_parsing.ipp index 14ba84378d..6697e38053 100644 --- a/include/bitcoin/system/impl/hash/sha/algorithm_parsing.ipp +++ b/include/bitcoin/system/impl/hash/sha/algorithm_parsing.ipp @@ -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 >= SHA::state_words); - if (std::is_constant_evaluated()) { buffer.at(0) = left.at(0); @@ -428,18 +425,15 @@ inject_left(auto& buffer, const auto& left) NOEXCEPT } else { - using word = array_element; + using word = array_element; array_cast(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 >= SHA::state_words); - if (std::is_constant_evaluated()) { buffer.at(8) = right.at(0); @@ -453,11 +447,48 @@ inject_right(auto& buffer, const auto& right) NOEXCEPT } else { - using word = array_element; + using word = array_element; array_cast(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; + array_cast(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; + constexpr auto words = to_half(SHA::state_words); + array_cast(buffer) = right; + } +} + } // namespace sha } // namespace system } // namespace libbitcoin diff --git a/include/bitcoin/system/impl/hash/sha/algorithm_stream.ipp b/include/bitcoin/system/impl/hash/sha/algorithm_stream.ipp index bae2e7c0eb..8c027b5690 100644 --- a/include/bitcoin/system/impl/hash/sha/algorithm_stream.ipp +++ b/include/bitcoin/system/impl/hash/sha/algorithm_stream.ipp @@ -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); @@ -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); diff --git a/test/hash/sha/sha256.cpp b/test/hash/sha/sha256.cpp index ef0762b98d..c8c3a50368 100644 --- a/test/hash/sha/sha256.cpp +++ b/test/hash/sha/sha256.cpp @@ -155,7 +155,7 @@ BOOST_AUTO_TEST_CASE(sha256_224__ttt_accumulator_hash__test_vectors__expected) using sha_256_224 = sha::algorithm, 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);