From 65fbed5bbf97fbc03a5cb42255793f7b90869659 Mon Sep 17 00:00:00 2001 From: metabeyond Date: Fri, 14 Feb 2025 10:46:04 +0800 Subject: [PATCH 1/7] Added constexpr SHA-3 Algorithm Implementation Added some numeric conversion utilities. Added some constexpr math functions. --- include/ylt/util/meta_math.hpp | 258 ++++++++++ include/ylt/util/meta_numeric_conversion.hpp | 92 ++++ include/ylt/util/sha3_constexpr.hpp | 134 +++++ include/ylt/util/sha3_detail.hpp | 497 +++++++++++++++++++ src/util/tests/CMakeLists.txt | 4 +- src/util/tests/test_sha3_constexpr.cpp | 53 ++ 6 files changed, 1037 insertions(+), 1 deletion(-) create mode 100644 include/ylt/util/meta_math.hpp create mode 100644 include/ylt/util/meta_numeric_conversion.hpp create mode 100644 include/ylt/util/sha3_constexpr.hpp create mode 100644 include/ylt/util/sha3_detail.hpp create mode 100644 src/util/tests/test_sha3_constexpr.cpp diff --git a/include/ylt/util/meta_math.hpp b/include/ylt/util/meta_math.hpp new file mode 100644 index 000000000..830505af0 --- /dev/null +++ b/include/ylt/util/meta_math.hpp @@ -0,0 +1,258 @@ +/* + * Copyright (c) 2023, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Author's Email: metabeyond@outlook.com + * Author's Github: https://github.com/refvalue/ + * Description: this source file contains code for parsing function names from + * their signatures, especially optimized for the MSVC implementation. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +namespace ylt { +inline constexpr std::size_t byte_bits = + std::numeric_limits::digits; + +} // namespace ylt + +namespace ylt::detail { +template + requires std::is_arithmetic_v +constexpr auto number_move_bits_helper(std::index_sequence, + bool big_endian, + Callable&& handler) noexcept { + constexpr std::size_t total_bits = sizeof(Number) * byte_bits; + constexpr std::size_t max_move_bits = total_bits - byte_bits; + std::ptrdiff_t baseline_move_bits = + big_endian ? static_cast(max_move_bits) : 0; + std::ptrdiff_t sign = big_endian ? -1 : 1; + + return std::forward(handler)((std::pair{ + Indexes, baseline_move_bits + sign * static_cast( + Indexes * byte_bits)})...); +} + +template + requires std::is_unsigned_v +constexpr auto bitwise_rotate_impl(UnsignedNumber number, int bits) noexcept { + using limits_type = std::numeric_limits; + using rotate_impl_type = UnsignedNumber (*)(UnsignedNumber number, int bits); + + constexpr auto rotl_impl = [](UnsignedNumber number, int bits) { + return (number << bits) | (number >> (limits_type::digits - bits)); + }; + constexpr auto rotr_impl = [](UnsignedNumber number, int bits) { + return (number >> bits) | (number << (limits_type::digits - bits)); + }; + constexpr auto rotate_impl = + Left ? static_cast(rotl_impl) : rotr_impl; + + if (bits == 0) { + return number; + } + + bits %= limits_type::digits; + + if (bits > 0) { + return rotate_impl(number, bits); + } + else { + return bitwise_rotate_impl(number, -bits); + } +} +} // namespace ylt::detail + +namespace ylt { +template +struct get_min : std::integral_constant< + std::common_type_t, + std::min(Left, Right)> {}; + +template +inline constexpr auto get_min_v = get_min::value; + +template +struct get_max : std::integral_constant< + std::common_type_t, + std::max(Left, Right)> {}; + +template +inline constexpr auto get_max_v = get_max::value; + +/** + * Calculates the binary logarithm of an unsigned number. + * @tparam UnsignedNumber The numeric type + * @param number The number + * @return The result + */ +template + requires std::is_unsigned_v +constexpr auto log2(UnsignedNumber number) noexcept { + UnsignedNumber result{}; + + while ((number >>= 1) != 0) { + ++result; + } + + return result; +} + +/** + * Splits a number into one or more bytes. + * @tparam Number The numeric type + * @tparam Callable The callable type + * @tparam TruncateSize The size in bytes of the sequence to be passed to + * @param number The number + * @param handler The handler whose arguments are the bytes of the number + * @param big_endian A boolean that indicates whether the byte order is + * big-endian + * @return The return value of the handler + */ +template + requires std::is_arithmetic_v +constexpr decltype(auto) split_number( + Number number, Callable&& handler, bool big_endian = true, + std::integral_constant = {}) noexcept { + return detail::number_move_bits_helper( + std::make_index_sequence>{}, + big_endian, [&](Args&&... parts) { + return std::forward(handler)( + static_cast((static_cast(number) >> + std::forward(parts).second) & + 0xFF)...); + }); +} + +/** + * Gets a certain bit of an unsigned number. + * @tparam UnsignedNumber The numeric type + * @param number The number + * @param offset The bit offset + * @return The bit value + */ +template + requires std::is_unsigned_v +constexpr std::uint8_t get_number_bit(UnsignedNumber number, + int offset) noexcept { + return static_cast((number >> offset) & 0x01); +} + +/** + * ets a certain bit of an unsigned number. + * @tparam UnsignedNumber The numeric type + * @param number The number + * @param offset The bit offset + * @param bit The bit value + */ +template + requires std::is_unsigned_v +constexpr void set_number_bit(UnsignedNumber& number, int offset, + std::uint8_t bit) noexcept { + number = (number & ~(static_cast(1) << offset)) | + (static_cast(bit) << offset); +} + +/// +/// Computes the result of bitwise left-rotating the value of "number" by "bits" +/// positions. This operation is also known as a left circular shift. +/// +/// The unsigned numeric type +/// The unsigned number +/// The bits +/// The result +/** + * Computes the result of bitwise left-rotating the value of "number" by "bits" + * positions. This operation is also known as a left circular shift. + * @tparam UnsignedNumber The unsigned numeric type + * @param number The unsigned number + * @param bits The bits + * @return The result + */ +template + requires std::is_unsigned_v +constexpr auto rotl(UnsignedNumber number, int bits) noexcept { + return detail::bitwise_rotate_impl(number, bits); +} + +/** + * Computes the result of bitwise right-rotating the value of "number" by + * "bits" positions. This operation is also known as a right circular shift. + * @tparam UnsignedNumber The unsigned numeric type + * @param number The unsigned number + * @param bits The bits + * @return The result + */ +template + requires std::is_unsigned_v +constexpr auto rotr(UnsignedNumber number, int bits) noexcept { + return detail::bitwise_rotate_impl(number, bits); +} + +/** + * Calculates (a - b) % c in which a, b and c are unsigned numbers. + * Overflow is fixed up here. + * @tparam UnsignedNumber The numeric type + * @param minuend The minuend + * @param subtrahend The subtrahend + * @param divisor The divisor + * @return The result + */ +template + requires std::is_unsigned_v +constexpr auto minus_mod_unsigned(UnsignedNumber minuend, + UnsignedNumber subtrahend, + UnsignedNumber divisor) noexcept { + if (minuend >= subtrahend) { + return (minuend - subtrahend) % divisor; + } + + UnsignedNumber subtraction = minuend - subtrahend; + UnsignedNumber addition = + (subtraction / divisor + (subtraction % divisor != 0 ? 1 : 0)) * divisor; + + return (subtraction + addition) % divisor; +} + +/** + * Combines multiple bytes into a number. + * @tparam Number The numeric type + * @param data The bytes + * @param big_endian A boolean that indicates whether the byte order is + * big-endian + * @return The number + */ +template + requires std::is_arithmetic_v +constexpr auto make_number(const std::array& data, + bool big_endian = true) noexcept { + return detail::number_move_bits_helper( + std::make_index_sequence{}, big_endian, + [&](Args&&... parts) { + return static_cast( + ((static_cast(data[std::forward(parts).first]) + << std::forward(parts).second) + + ...)); + }); +} +} // namespace ylt diff --git a/include/ylt/util/meta_numeric_conversion.hpp b/include/ylt/util/meta_numeric_conversion.hpp new file mode 100644 index 000000000..e3aad9c23 --- /dev/null +++ b/include/ylt/util/meta_numeric_conversion.hpp @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2023, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Author's Email: metabeyond@outlook.com + * Author's Github: https://github.com/refvalue/ + * Description: this source file contains code for parsing function names from + * their signatures, especially optimized for the MSVC implementation. + */ + +#pragma once + +#include +#include +#include +#include + +#include "meta_math.hpp" +#include "meta_string.hpp" + +namespace ylt::detail { +template + requires std::is_standard_layout_v +inline constexpr std::size_t hexadecimal_character_size_v = sizeof(T) * 2; + +inline constexpr std::string_view hexadecimal_characters{"0123456789ABCDEF"}; + +constexpr auto to_hexadecimal_character(std::uint8_t byte) noexcept { + return refvalue::meta_string{hexadecimal_characters[byte >> 4], + hexadecimal_characters[byte & 0xF]}; +} +} // namespace ylt::detail + +namespace ylt { +/** + * Converts a number to a hexadecimal meta_string. + * @tparam Number The numeric type + * @param number The number + * @param big_endian A boolean that indicates whether the byte order is + * big-endian + * @return The hexadecimal meta_string + */ +template + requires std::is_arithmetic_v +constexpr auto to_hexadecimal_meta_string(Number number, + bool big_endian = true) noexcept { + return split_number( + number, + [](auto... bytes) { + return refvalue::meta_string{ + detail::to_hexadecimal_character(bytes)...}; + }, + big_endian); +} + +/** + * Converts a buffer to hexadecimal meta_string. + * @tparam N The size of the buffer. + * @param data The data. + * @return The hexadecimal meta_string + */ +template +constexpr auto to_hexadecimal_meta_string( + std::span data) noexcept { + return [&](std::index_sequence) { + return refvalue::meta_string{detail::to_hexadecimal_character(data[Is])...}; + }(std::make_index_sequence{}); +} + +/** + * Converts a buffer to hexadecimal meta_string. + * @tparam N The size of the buffer. + * @param data The data. + * @return The hexadecimal meta_string + */ +template +constexpr auto to_hexadecimal_meta_string( + const std::array& data) noexcept { + return to_hexadecimal_meta_string(std::span{data}); +} +} // namespace ylt diff --git a/include/ylt/util/sha3_constexpr.hpp b/include/ylt/util/sha3_constexpr.hpp new file mode 100644 index 000000000..e2fbdd4fe --- /dev/null +++ b/include/ylt/util/sha3_constexpr.hpp @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2023, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Author's Email: metabeyond@outlook.com + * Author's Github: https://github.com/refvalue/ + * Paper Cited: https://doi.org/10.6028/NIST.FIPS.202 + * Description: this source file contains code for parsing function names from + * their signatures, especially optimized for the MSVC implementation. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "meta_numeric_conversion.hpp" +#include "meta_string.hpp" +#include "sha3_detail.hpp" + +namespace ylt::detail { +/** + * A helper class that digests input data. + * @tparam Type The type of SHA3. + */ +template +class hash_digest { + public: + using context_type = hash_context; + + /** + * Updates the context with a piece of data. + * @tparam Size The size in bytes. + * @param data The data. + * @return The reference to self. + */ + template + constexpr hash_digest& update( + const std::array& data) noexcept { + return update(data.data(), data.size()); + } + + /** + * Updates the context with a piece of data. + * @param data Updates the context with a piece of data. + * @param size The size in bytes. + * @return The reference to self. + */ + constexpr hash_digest& update(const std::uint8_t* data, + std::size_t size) noexcept { + auto source_ptr = data; + const auto source_end_ptr = data + size; + auto destination_ptr = context_.block.data() + context_.block_index; + + std::size_t real_size{}; + + // Fills the internal buffer and updates the context if necessary. + while (source_ptr < source_end_ptr) { + real_size = std::min(source_end_ptr - source_ptr, + context_.block_remaining_size()); + destination_ptr = + std::copy(source_ptr, source_ptr + real_size, destination_ptr); + source_ptr += real_size; + context_.block_index += real_size; + + // Updates the state when the internal buffer is full. + if (context_.block_index >= context_type::block_size) { + detail::sponge_step_6(context_); + destination_ptr = context_.block.data(); + } + } + + return *this; + } + + /** + * Finalizes the context (pads the data and calculates the final hash value). + * @return The finalized data. + */ + constexpr auto finalize() noexcept { + return detail::sponge_finalize(context_); + } + + private: + context_type context_; +}; + +template +constexpr auto sha3_digest(std::span data) noexcept { + return detail::hash_digest{} + .update(data.data(), data.size()) + .finalize(); +} + +template +constexpr auto sha3_digest(std::string_view data) noexcept { + detail::hash_digest digest; + std::array buffer{}; + const auto blocks = data.size() / buffer.size(); + std::size_t index{}; + + auto update = [&](std::size_t size) { + std::copy_n(data.data() + index * buffer.size(), + static_cast(size), buffer.data()); + digest.update(buffer.data(), size); + }; + + for (; index < blocks; ++index) { + update(buffer.size()); + } + + if (const auto remaining_size = data.size() % buffer.size(); + remaining_size != 0) { + update(remaining_size); + } + + return digest.finalize(); +} +} // namespace ylt::detail diff --git a/include/ylt/util/sha3_detail.hpp b/include/ylt/util/sha3_detail.hpp new file mode 100644 index 000000000..0f02175c5 --- /dev/null +++ b/include/ylt/util/sha3_detail.hpp @@ -0,0 +1,497 @@ +/* + * Copyright (c) 2023, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Author's Email: metabeyond@outlook.com + * Author's Github: https://github.com/refvalue/ + * Paper Cited: https://doi.org/10.6028/NIST.FIPS.202 + * Description: this source file contains code for parsing function names from + * their signatures, especially optimized for the MSVC implementation. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "meta_math.hpp" + +namespace ylt { +enum class sha3_type { sha3_224, sha3_256, sha3_384, sha3_512, sha3_type_size }; +} // namespace ylt + +namespace ylt::detail { +struct sha3_type_traits { + /** + * The block size of a SHA3 algorithm, in bytes, defined in Table 3, + Section 7. The comment in the footer notes that in general, the input + block size of a sponge function is its rate (also known as r). + */ + std::size_t block_size{}; + + /** + * The final hash size in bytes. + */ + std::size_t final_hash_size{}; +}; + +/** +* A std::uint64_t is 64-bit which has an identical bit length to para + (also known as the length of z coordinate). The definition is in + Section 5.2. + */ +using word_type = std::uint64_t; + +/** + * The number of rounds. + */ +inline constexpr std::size_t round_size = 24; + +/** + * The size of a word, in bits. + */ +inline constexpr std::size_t word_bits = std::numeric_limits::digits; + +/** + * l = log2(w). + */ +inline constexpr std::size_t log2_word_bits = log2(word_bits); + +/** + * A common factor which is commonly used, i.e. number 5. + */ +inline constexpr std::size_t common_factor = 5; + +/** + * The size of a sponge, in words, defined in Section 5.2. + */ +inline constexpr std::size_t sponge_words = + 1600 / byte_bits / sizeof(word_type); + +/** + * Available traits of available SHA3 algorithms. + */ +inline constexpr std::array(sha3_type::sha3_type_size)> + available_sha3_type_traits{sha3_type_traits{144, 224 / byte_bits}, + sha3_type_traits{136, 256 / byte_bits}, + sha3_type_traits{104, 384 / byte_bits}, + sha3_type_traits{72, 512 / byte_bits}}; + +/** +* Represents a state array defined in Section 3.1, of which the data are + word-aligned (std::uint64_t). + */ +class state_array { + public: + constexpr state_array() noexcept : data_{} {} + + [[nodiscard]] constexpr std::size_t size() const noexcept { + return data_.size(); + } + + constexpr void reset() noexcept { data_ = {}; } + + constexpr word_type& operator[](std::size_t index) noexcept { + return data_[index]; + } + + constexpr const word_type& operator[](std::size_t index) const noexcept { + return data_[index]; + } + + constexpr word_type& operator()(std::size_t x, std::size_t y) noexcept { + return data_[calculate_index(x, y)]; + } + + constexpr const word_type& operator()(std::size_t x, + std::size_t y) const noexcept { + return data_[calculate_index(x, y)]; + } + + template > + constexpr void truncate_as_bytes( + std::array& buffer) noexcept { + constexpr std::size_t buffer_words = Size / sizeof(word_type); + constexpr std::size_t remaining_bytes = Size % sizeof(word_type); + std::size_t index = 0; + + for (std::size_t i = 0; i < buffer_words; i++) { + // According to the NIST standard, "strings" defined in that are + // little-endian. + split_number( + data_[i], + [&](auto... bytes) { + ((buffer[index++] = bytes), ...); + }, + false); + } + + // Add the remaining bytes in the last incomplete word. + if constexpr (remaining_bytes != 0) { + split_number( + data_[buffer_words], + [&](auto... bytes) { + ((buffer[index++] = bytes), ...); + }, + false, std::integral_constant{}); + } + } + + static constexpr std::size_t calculate_index(std::size_t x, + std::size_t y) noexcept { + // A[x, y, z] = S[w(5y + x) + z] defined in Section 3.1.2. + // The calculation is simplified as follows because values of a lane (values + // along z coordinate) are combined into a word (std::uint64_t). + return common_factor * (y % common_factor) + (x % common_factor); + } + + private: + std::array data_; +}; + +/** + * The context of a hash algorithm. + * @tparam Type The type of the SHA3. + */ +template +struct hash_context { + static constexpr std::size_t block_size = + available_sha3_type_traits[static_cast(Type)].block_size; + static constexpr std::size_t final_hash_size = + available_sha3_type_traits[static_cast(Type)] + .final_hash_size; + + state_array state; + state_array intermediate; + std::size_t block_index; + std::array tmp; + std::array block; + + constexpr hash_context() noexcept : block_index{}, tmp{}, block{} {} + + [[nodiscard]] constexpr std::size_t block_remaining_size() const noexcept { + return block_size - block_index; + } + + constexpr void reset() noexcept { + tmp = {}; + block = {}; + state.reset(); + intermediate.reset(); + block_index = 0; + } +}; + +/** + * A helper function for rc(A) below defined in Section 3.2.5. + * @param number The number. + * @return The result. + */ +constexpr std::uint8_t step_mapping_helper_rc(word_type number) noexcept { + // If t mod 255 = 0, return 1. + if (number % 0xFF == 0) { + return 1; + } + + // Let R = 1000'0000. + // Here all numbers are inverted for convenience. + std::uint8_t bit = 0; + word_type result = 0b0000'0001; + + for (std::size_t i = 1; i <= number % 0xFF; i++) { + // For i from 1 to t mod 255, let: + // a.R = 0 || R; + // b.R[0] = R[0] ⊕ R[8]; + // c.R[4] = R[4] ⊕ R[8]; + // d.R[5] = R[5] ⊕ R[8]; + // e.R[6] = R[6] ⊕ R[8]; + // f.R = Trunc8[R]. + result <<= 1; + bit = get_number_bit(result, 8); + + set_number_bit(result, 0, get_number_bit(result, 0) ^ bit); + set_number_bit(result, 4, get_number_bit(result, 4) ^ bit); + set_number_bit(result, 5, get_number_bit(result, 5) ^ bit); + set_number_bit(result, 6, get_number_bit(result, 6) ^ bit); + + result &= 0xFF; + } + + // Return R[0]. + return static_cast(result & 0x01); +} + +/** +* Generates a table of rotation bits for ��(A) at compile-time, defined in + Section 3.2.2. + */ +inline constexpr auto step_mapping_rho_rotation_bits = [] { + std::array result{}; + + /// (x, y) = (1, 0) + /// For t from 0 to 23, (t + 1)(t + 2) / 2 mod w + for (std::size_t x = 1, y = 0, t = 0, tmp = 0; t < 24; t++) { + result[state_array::calculate_index(x, y)] = + static_cast((((t + 1) * (t + 2)) >> 1) % word_bits); + + // (x, y) = (y, (2x + 3y) mod 5) + tmp = y; + y = (2 * x + 3 * y) % common_factor; + x = tmp; + } + + return result; +}(); + +/** + * Generates an RC table for tau(A) at compile-time. + */ +inline constexpr auto step_mapping_tau_rc_table = + [](std::index_sequence) { + constexpr auto func_rc = [](std::size_t round) { + // Let RC = 0w. + // For j from 0 to l = log2(w), let RC[2 ^ j – 1] = rc(j + 7ir). + word_type result = 0; + + for (std::size_t i = 0; i <= log2_word_bits; i++) { + set_number_bit(result, (1 << i) - 1, + step_mapping_helper_rc(i + 7 * round)); + } + + return result; + }; + + return std::array{func_rc(Is)...}; + }(std::make_index_sequence{}); + +/** + * A step mapping function named theta(A) defined in Section 3.2.1. + * @tparam Type The type of SHA3. + * @param context The hash context. + */ +template +constexpr void step_mapping_theta(hash_context& context) noexcept { + // For all pairs (x, z) such that 0 ≤ x < 5 and 0 ≤ z < w, let C[x, z] = A[x, + // 0, z] ⊕ A[x, 1, z] ⊕ A[x, 2, z] ⊕ A[x, 3, z] ⊕ A[x, 4, z]. Here a lane + // (values along z coordinate) is represented as a word (std::uint64_t). + for (std::size_t x = 0; x < common_factor; x++) { + context.tmp[x] = [&](std::index_sequence) { + return (context.state(x, Is) ^ ...); + }(std::make_index_sequence{}); + } + + // For all pairs (x, z) such that 0 ≤ x < 5 and 0 ≤ z < w, let D[x, z] = C[(x + // - 1) mod 5, z] ⊕ C[(x + 1) mod 5, (z - 1) mod w]. For all triples(x, y, z) + // such that 0 ≤ x < 5, 0 ≤ y < 5, and 0 ≤ z < w, let A′[x, y, z] = A[x, y, z] + // ⊕ D[x, z]. Figure 3 in Section 3.2.1 is intuitive and (z - 1) mod w is + // equivalent to rotating a word to the left by one bit. + for (std::size_t x = 0; x < common_factor; x++) { + for (std::size_t y = 0; y < common_factor; y++) { + context.state(x, y) ^= + (context.tmp[minus_mod_unsigned(x, 1, common_factor)] ^ + rotl(context.tmp[(x + 1) % common_factor], 1)); + } + } +} + +/** + * A step mapping function named rho(A) defined in Section 3.2.2. + * @tparam Type The type of sha3. + * @param context The hash context. + */ +template +constexpr void step_mapping_rho(hash_context& context) noexcept { + // For all z such that 0 �� z �� w, let A'[0, 0, z] = A[0, 0, z]. + context.intermediate(0, 0) = context.state(0, 0); + + // (x, y) = (1, 0) + // For t from 0 to 23. + [&](std::index_sequence) { + // For all z such that 0 ≤ z < w, let A′[x, y, z] = A[x, y, (z – (t + 1)(t + + // 2) / 2) mod w]. Here a lane (values along z coordinate) is represented as + // a word (std::uint64_t). (x, y) = (y, (2x + 3y) mod 5) + ((context.intermediate[Is] = + rotl(context.state[Is], step_mapping_rho_rotation_bits[Is])), + ...); + }(std::make_index_sequence{}); +} + +/** + * A step mapping function named pi(A) defined in Section 3.2.3. + * @tparam Type The type of SHA3. + * @param context The hash context. + */ +template +constexpr void step_mapping_pi(hash_context& context) noexcept { + for (std::size_t x = 0; x < common_factor; x++) { + for (std::size_t y = 0; y < common_factor; y++) { + // For all triples (x, y, z) such that 0 ≤ x < 5, 0 ≤ y < 5, and 0 ≤ z < + // w, let A′[x, y, z] = A[(x + 3y) mod 5, x, z]. Here a lane (values along + // z coordinate) is represented as a word (std::uint64_t). + context.state(x, y) = context.intermediate(x + 3 * y, x); + } + } +} + +/** + * A step mapping function named chi(A) defined in Section 3.2.4. + * @tparam Type The type of SHA3. + * @param context The hash context. + */ +template +constexpr void step_mapping_chi(hash_context& context) noexcept { + for (std::size_t x = 0; x < common_factor; x++) { + for (std::size_t y = 0; y < common_factor; y++) { + // For all triples (x, y, z) such that 0 ≤ x < 5, 0 ≤ y < 5, and 0 ≤ z < + // w, let A′[x, y, z] = A[x, y, z] ⊕((A[(x + 1) mod 5, y, z] ⊕ 1) · A[(x + + // 2) mod 5, y, z]). Here a lane (values along z coordinate) is + // represented as a word (std::uint64_t). + context.intermediate(x, y) = + context.state(x, y) ^ + (~context.state(x + 1, y) & context.state(x + 2, y)); + } + } +} + +/** + * A step mapping function named tau(A) defined in Section 3.2.5. + * @tparam Type The type of SHA3. + * @param context The hash context. + * @param round The round index. + */ +template +constexpr void step_mapping_tau(hash_context& context, + std::size_t round) noexcept { + // For all triples (x, y, z) such that 0 ≤ x < 5, 0 ≤ y < 5, and 0 ≤ z < w, + // let A′[x, y, z] = A[x, y, z]. For all z such that 0 ≤ z < w, let A′ [0, 0, + // z] = A′ [0, 0, z] ⊕ RC[z]. Here a lane (values along z coordinate) is + // represented as a word (std::uint64_t). + context.state = context.intermediate; + context.state(0, 0) ^= step_mapping_tau_rc_table[round]; +} + +/** + * A function that implements the KECCAK-p[b, nr] permutation. + * @tparam Type The type of SHA3. + * @param context The hash context. + */ +template +constexpr void keccak_p(hash_context& context) noexcept { + for (std::size_t i = 0; i < round_size; i++) { + step_mapping_theta(context); + step_mapping_rho(context); + step_mapping_pi(context); + step_mapping_chi(context); + step_mapping_tau(context, i); + } +} + +/** +* A function that implements pad10*1(x, m) defined in Section 5.1 and M || 01 + defined in Section 6.1. + * @tparam Type The type of SHA3. + * @param context The hash context. + */ +template +constexpr void pad10_1_and_append_01(hash_context& context) noexcept { + // pad10*1(x, m) = string P such that m + len(P) is a positive multiple of x. + // 1. Let j = (– m – 2) mod x. + // 2. Return P = 1 || 0j || 1. + // For a byte buffer, the padding bytes are 0x01(0b0000'0001) and + // 0x80(0b1000'0000). Considering M || 01 defined in Section 6.1, the final + // padding bytes are 0x06((0b0000'0001 << 2) | 0b0000'0010, which shortens the + // padding zeros by 2 bits) and 0x80; + if (context.block_index + 1 == hash_context::block_size) { + // For only one single byte, just combines two parts as a result of + // 0x86(0b1000'0000 | 0b0000'0110). + context.block[context.block_index] = 0x86; + } + else { + context.block[context.block_index] = 0x06; + + for (std::size_t i = context.block_index + 1; + i < hash_context::block_size - 1; ++i) { + context.block[i] = 0; + } + + context.block.back() = 0x80; + } +} + +/** +* A function that updates the current state by SPONGE[f, pad, r](N, d) (when r + = block size) defined in Step 6, Algorithm 8, Section 4. + * @tparam Type The type of SHA3. + * @param context The hash context. + */ +template +constexpr void sponge_step_6(hash_context& context) noexcept { + // For i from 0 to n - 1, let S = f(S ⊕ (Pi || 0c)). + // Here n refers to the block at index n. + constexpr std::size_t block_words = + hash_context::block_size / sizeof(word_type); + + for (std::size_t i = 0; i < block_words; i++) { + [&](std::index_sequence) { + // According to the NIST standard, "strings" defined in that are + // little-endian. + context.state[i] ^= make_number( + {context.block[i * sizeof(word_type) + Is]...}, false); + }(std::make_index_sequence{}); + } + + // f = KECCAK-p[b, nr] + keccak_p(context); + context.block_index = 0; +} + +/** +* A function that finalizes the state by SPONGE[f, pad, r](N, d) (when r = + block size) defined in Algorithm 8, Section 4 and Section 4. + * @tparam Type The type of SHA3. + * @param context The hash context. + * @return The finalized data. + */ +template +constexpr auto sponge_finalize(hash_context& context) noexcept { + // 1. Let P = N || pad(r, len(N)). + // 2. Let n = len(P) / r. + // 3. Let c = b - r. + // 4. Let P0, ... , Pn - 1 be the unique sequence of strings of length r such + // that P = P0 || … || Pn-1. + // 5. Let S = 0b. + // 6. For i from 0 to n - 1, let S = f(S ⊕(Pi || 0c)). + // 7. Let Z be the empty string. + // 8. Let Z = Z || Trunc_r(S). + // 9. If d ≤ |Z| , then return Trunc d(Z); else continue. + // 10. Let S = f(S), and continue with Step 8. + pad10_1_and_append_01(context); + sponge_step_6(context); + + std::array::final_hash_size> result{}; + + // The final hash size denoted by d is always smaller than |Z|, so "else" in + // Step 9, and Step 10 are omitted here. + context.state.truncate_as_bytes(result); + context.reset(); + + return result; +} +} // namespace ylt::detail diff --git a/src/util/tests/CMakeLists.txt b/src/util/tests/CMakeLists.txt index 3718acb78..dfc2d615c 100644 --- a/src/util/tests/CMakeLists.txt +++ b/src/util/tests/CMakeLists.txt @@ -3,6 +3,8 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/output/tests/util) add_executable(util_meta_string_test test_meta_string.cpp) add_executable(util_time_test test_time_util.cpp) +add_executable(util_sha3_constexpr_test test_sha3_constexpr.cpp) add_test(NAME util_meta_string_test COMMAND util_meta_string_test) -add_test(NAME util_time_test COMMAND util_time_test) \ No newline at end of file +add_test(NAME util_time_test COMMAND util_time_test) +add_test(NAME util_sha3_constexpr_test COMMAND util_sha3_constexpr_test) \ No newline at end of file diff --git a/src/util/tests/test_sha3_constexpr.cpp b/src/util/tests/test_sha3_constexpr.cpp new file mode 100644 index 000000000..d6247d3b5 --- /dev/null +++ b/src/util/tests/test_sha3_constexpr.cpp @@ -0,0 +1,53 @@ +#include +#include + +namespace ylt { +constexpr void test_meta_numeric_conversion() { + static_assert(to_hexadecimal_meta_string(static_cast( + 0x12345)) == refvalue::meta_string{"00012345"}); + + static_assert( + to_hexadecimal_meta_string(static_cast(0x12345), false) == + refvalue::meta_string{"45230100"}); + + static_assert(to_hexadecimal_meta_string(static_cast( + 0x6789ABCD)) == refvalue::meta_string{"000000006789ABCD"}); + + static_assert(to_hexadecimal_meta_string( + static_cast(0x6789ABCD), false) == + refvalue::meta_string{"CDAB896700000000"}); + + static_assert(to_hexadecimal_meta_string( + std::array{0x12, 0x34, 0x60, 0xAB}) == + refvalue::meta_string{"123460AB"}); +} + +constexpr void test_sha3_constexpr() noexcept { + static_assert( + to_hexadecimal_meta_string(detail::sha3_digest( + "This is a UTF-8 string.")) == + refvalue::meta_string{ + "E41EA1F40E1378DFA4A0847D1BF7EACEF488622BFA9839DAA6C64FE8"}); + + static_assert( + to_hexadecimal_meta_string( + detail::sha3_digest("Hello World!")) == + refvalue::meta_string{ + "D0E47486BBF4C16ACAC26F8B653592973C1362909F90262877089F9C8A4536AF"}); + + static_assert( + to_hexadecimal_meta_string(detail::sha3_digest( + "Whenever you want to, I can help.")) == + refvalue::meta_string{"4ACB502EEC4FE8ECDA6E0A8D386FFE6B9B24B8CE2E22F6C8AB" + "C729EC521D361CD883044B720458DCC7472906CC49D9D5"}); + + static_assert( + to_hexadecimal_meta_string(detail::sha3_digest( + "Forgive me and leave me alone.")) == + refvalue::meta_string{ + "6377D5E3BBA8BB2DC3A956E458F00F0BED5716B0AB419F593DCD7BFE16FB5C4D7F42" + "FC2B06C7DB073CE849A6122845558D58C7BBA2CDCD01A6F046FF9B35BD3D"}); +} +} // namespace ylt + +int main() {} \ No newline at end of file From d31a224e43f248aa8fcd078e6b0b089f549c7ee6 Mon Sep 17 00:00:00 2001 From: metabeyond Date: Fri, 14 Feb 2025 11:01:18 +0800 Subject: [PATCH 2/7] Added constexpr SHA-3 Algorithm Implementation Added some numeric conversion utilities. Added some constexpr math functions. --- include/ylt/util/sha3_constexpr.hpp | 4 +++- src/util/tests/test_sha3_constexpr.cpp | 12 ++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/include/ylt/util/sha3_constexpr.hpp b/include/ylt/util/sha3_constexpr.hpp index e2fbdd4fe..9d5c454a5 100644 --- a/include/ylt/util/sha3_constexpr.hpp +++ b/include/ylt/util/sha3_constexpr.hpp @@ -99,7 +99,9 @@ class hash_digest { private: context_type context_; }; +} // namespace ylt::detail +namespace ylt { template constexpr auto sha3_digest(std::span data) noexcept { return detail::hash_digest{} @@ -131,4 +133,4 @@ constexpr auto sha3_digest(std::string_view data) noexcept { return digest.finalize(); } -} // namespace ylt::detail +} // namespace ylt diff --git a/src/util/tests/test_sha3_constexpr.cpp b/src/util/tests/test_sha3_constexpr.cpp index d6247d3b5..601ce2060 100644 --- a/src/util/tests/test_sha3_constexpr.cpp +++ b/src/util/tests/test_sha3_constexpr.cpp @@ -24,26 +24,26 @@ constexpr void test_meta_numeric_conversion() { constexpr void test_sha3_constexpr() noexcept { static_assert( - to_hexadecimal_meta_string(detail::sha3_digest( - "This is a UTF-8 string.")) == + to_hexadecimal_meta_string( + sha3_digest("This is a UTF-8 string.")) == refvalue::meta_string{ "E41EA1F40E1378DFA4A0847D1BF7EACEF488622BFA9839DAA6C64FE8"}); static_assert( to_hexadecimal_meta_string( - detail::sha3_digest("Hello World!")) == + sha3_digest("Hello World!")) == refvalue::meta_string{ "D0E47486BBF4C16ACAC26F8B653592973C1362909F90262877089F9C8A4536AF"}); static_assert( - to_hexadecimal_meta_string(detail::sha3_digest( + to_hexadecimal_meta_string(sha3_digest( "Whenever you want to, I can help.")) == refvalue::meta_string{"4ACB502EEC4FE8ECDA6E0A8D386FFE6B9B24B8CE2E22F6C8AB" "C729EC521D361CD883044B720458DCC7472906CC49D9D5"}); static_assert( - to_hexadecimal_meta_string(detail::sha3_digest( - "Forgive me and leave me alone.")) == + to_hexadecimal_meta_string( + sha3_digest("Forgive me and leave me alone.")) == refvalue::meta_string{ "6377D5E3BBA8BB2DC3A956E458F00F0BED5716B0AB419F593DCD7BFE16FB5C4D7F42" "FC2B06C7DB073CE849A6122845558D58C7BBA2CDCD01A6F046FF9B35BD3D"}); From 89339a48910bf2dbe8663416492ec04d69d38a3d Mon Sep 17 00:00:00 2001 From: metabeyond Date: Fri, 14 Feb 2025 11:13:32 +0800 Subject: [PATCH 3/7] Formatting code --- include/ylt/util/meta_math.hpp | 20 ++++++++++---------- include/ylt/util/meta_numeric_conversion.hpp | 4 ++-- include/ylt/util/sha3_detail.hpp | 11 ++++++----- 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/include/ylt/util/meta_math.hpp b/include/ylt/util/meta_math.hpp index 830505af0..f104d7068 100644 --- a/include/ylt/util/meta_math.hpp +++ b/include/ylt/util/meta_math.hpp @@ -37,7 +37,7 @@ inline constexpr std::size_t byte_bits = namespace ylt::detail { template - requires std::is_arithmetic_v +requires std::is_arithmetic_v constexpr auto number_move_bits_helper(std::index_sequence, bool big_endian, Callable&& handler) noexcept { @@ -53,7 +53,7 @@ constexpr auto number_move_bits_helper(std::index_sequence, } template - requires std::is_unsigned_v +requires std::is_unsigned_v constexpr auto bitwise_rotate_impl(UnsignedNumber number, int bits) noexcept { using limits_type = std::numeric_limits; using rotate_impl_type = UnsignedNumber (*)(UnsignedNumber number, int bits); @@ -106,7 +106,7 @@ inline constexpr auto get_max_v = get_max::value; * @return The result */ template - requires std::is_unsigned_v +requires std::is_unsigned_v constexpr auto log2(UnsignedNumber number) noexcept { UnsignedNumber result{}; @@ -130,7 +130,7 @@ constexpr auto log2(UnsignedNumber number) noexcept { */ template - requires std::is_arithmetic_v +requires std::is_arithmetic_v constexpr decltype(auto) split_number( Number number, Callable&& handler, bool big_endian = true, std::integral_constant = {}) noexcept { @@ -152,7 +152,7 @@ constexpr decltype(auto) split_number( * @return The bit value */ template - requires std::is_unsigned_v +requires std::is_unsigned_v constexpr std::uint8_t get_number_bit(UnsignedNumber number, int offset) noexcept { return static_cast((number >> offset) & 0x01); @@ -166,7 +166,7 @@ constexpr std::uint8_t get_number_bit(UnsignedNumber number, * @param bit The bit value */ template - requires std::is_unsigned_v +requires std::is_unsigned_v constexpr void set_number_bit(UnsignedNumber& number, int offset, std::uint8_t bit) noexcept { number = (number & ~(static_cast(1) << offset)) | @@ -190,7 +190,7 @@ constexpr void set_number_bit(UnsignedNumber& number, int offset, * @return The result */ template - requires std::is_unsigned_v +requires std::is_unsigned_v constexpr auto rotl(UnsignedNumber number, int bits) noexcept { return detail::bitwise_rotate_impl(number, bits); } @@ -204,7 +204,7 @@ constexpr auto rotl(UnsignedNumber number, int bits) noexcept { * @return The result */ template - requires std::is_unsigned_v +requires std::is_unsigned_v constexpr auto rotr(UnsignedNumber number, int bits) noexcept { return detail::bitwise_rotate_impl(number, bits); } @@ -219,7 +219,7 @@ constexpr auto rotr(UnsignedNumber number, int bits) noexcept { * @return The result */ template - requires std::is_unsigned_v +requires std::is_unsigned_v constexpr auto minus_mod_unsigned(UnsignedNumber minuend, UnsignedNumber subtrahend, UnsignedNumber divisor) noexcept { @@ -243,7 +243,7 @@ constexpr auto minus_mod_unsigned(UnsignedNumber minuend, * @return The number */ template - requires std::is_arithmetic_v +requires std::is_arithmetic_v constexpr auto make_number(const std::array& data, bool big_endian = true) noexcept { return detail::number_move_bits_helper( diff --git a/include/ylt/util/meta_numeric_conversion.hpp b/include/ylt/util/meta_numeric_conversion.hpp index e3aad9c23..8096a6b6e 100644 --- a/include/ylt/util/meta_numeric_conversion.hpp +++ b/include/ylt/util/meta_numeric_conversion.hpp @@ -31,7 +31,7 @@ namespace ylt::detail { template - requires std::is_standard_layout_v +requires std::is_standard_layout_v inline constexpr std::size_t hexadecimal_character_size_v = sizeof(T) * 2; inline constexpr std::string_view hexadecimal_characters{"0123456789ABCDEF"}; @@ -52,7 +52,7 @@ namespace ylt { * @return The hexadecimal meta_string */ template - requires std::is_arithmetic_v +requires std::is_arithmetic_v constexpr auto to_hexadecimal_meta_string(Number number, bool big_endian = true) noexcept { return split_number( diff --git a/include/ylt/util/sha3_detail.hpp b/include/ylt/util/sha3_detail.hpp index 0f02175c5..a6e032507 100644 --- a/include/ylt/util/sha3_detail.hpp +++ b/include/ylt/util/sha3_detail.hpp @@ -292,9 +292,8 @@ constexpr void step_mapping_theta(hash_context& context) noexcept { // 0, z] ⊕ A[x, 1, z] ⊕ A[x, 2, z] ⊕ A[x, 3, z] ⊕ A[x, 4, z]. Here a lane // (values along z coordinate) is represented as a word (std::uint64_t). for (std::size_t x = 0; x < common_factor; x++) { - context.tmp[x] = [&](std::index_sequence) { - return (context.state(x, Is) ^ ...); - }(std::make_index_sequence{}); + context.tmp[x] = [&](std::index_sequence) { return (context.state(x, Is) ^ ...); } + (std::make_index_sequence{}); } // For all pairs (x, z) such that 0 ≤ x < 5 and 0 ≤ z < w, let D[x, z] = C[(x @@ -330,7 +329,8 @@ constexpr void step_mapping_rho(hash_context& context) noexcept { ((context.intermediate[Is] = rotl(context.state[Is], step_mapping_rho_rotation_bits[Is])), ...); - }(std::make_index_sequence{}); + } + (std::make_index_sequence{}); } /** @@ -454,7 +454,8 @@ constexpr void sponge_step_6(hash_context& context) noexcept { // little-endian. context.state[i] ^= make_number( {context.block[i * sizeof(word_type) + Is]...}, false); - }(std::make_index_sequence{}); + } + (std::make_index_sequence{}); } // f = KECCAK-p[b, nr] From c69396f26f159eaa99ddd30e0748aebb9f942b65 Mon Sep 17 00:00:00 2001 From: metabeyond Date: Fri, 14 Feb 2025 11:25:41 +0800 Subject: [PATCH 4/7] Formatting code --- include/ylt/util/meta_numeric_conversion.hpp | 3 ++- include/ylt/util/sha3_detail.hpp | 27 +++++++++++--------- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/include/ylt/util/meta_numeric_conversion.hpp b/include/ylt/util/meta_numeric_conversion.hpp index 8096a6b6e..1adcaa005 100644 --- a/include/ylt/util/meta_numeric_conversion.hpp +++ b/include/ylt/util/meta_numeric_conversion.hpp @@ -75,7 +75,8 @@ constexpr auto to_hexadecimal_meta_string( std::span data) noexcept { return [&](std::index_sequence) { return refvalue::meta_string{detail::to_hexadecimal_character(data[Is])...}; - }(std::make_index_sequence{}); + } + (std::make_index_sequence{}); } /** diff --git a/include/ylt/util/sha3_detail.hpp b/include/ylt/util/sha3_detail.hpp index a6e032507..cc52de7b8 100644 --- a/include/ylt/util/sha3_detail.hpp +++ b/include/ylt/util/sha3_detail.hpp @@ -265,21 +265,22 @@ inline constexpr auto step_mapping_rho_rotation_bits = [] { */ inline constexpr auto step_mapping_tau_rc_table = [](std::index_sequence) { - constexpr auto func_rc = [](std::size_t round) { - // Let RC = 0w. - // For j from 0 to l = log2(w), let RC[2 ^ j – 1] = rc(j + 7ir). - word_type result = 0; + constexpr auto func_rc = [](std::size_t round) { + // Let RC = 0w. + // For j from 0 to l = log2(w), let RC[2 ^ j – 1] = rc(j + 7ir). + word_type result = 0; - for (std::size_t i = 0; i <= log2_word_bits; i++) { - set_number_bit(result, (1 << i) - 1, - step_mapping_helper_rc(i + 7 * round)); - } + for (std::size_t i = 0; i <= log2_word_bits; i++) { + set_number_bit(result, (1 << i) - 1, + step_mapping_helper_rc(i + 7 * round)); + } - return result; - }; + return result; + }; return std::array{func_rc(Is)...}; - }(std::make_index_sequence{}); + } +(std::make_index_sequence{}); /** * A step mapping function named theta(A) defined in Section 3.2.1. @@ -292,7 +293,9 @@ constexpr void step_mapping_theta(hash_context& context) noexcept { // 0, z] ⊕ A[x, 1, z] ⊕ A[x, 2, z] ⊕ A[x, 3, z] ⊕ A[x, 4, z]. Here a lane // (values along z coordinate) is represented as a word (std::uint64_t). for (std::size_t x = 0; x < common_factor; x++) { - context.tmp[x] = [&](std::index_sequence) { return (context.state(x, Is) ^ ...); } + context.tmp[x] = [&](std::index_sequence) { + return (context.state(x, Is) ^ ...); + } (std::make_index_sequence{}); } From 49d299964d2bfb29cfe13dc66d7875c6be683e03 Mon Sep 17 00:00:00 2001 From: metabeyond Date: Fri, 14 Feb 2025 11:56:11 +0800 Subject: [PATCH 5/7] Formatting code --- include/ylt/util/sha3_detail.hpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/include/ylt/util/sha3_detail.hpp b/include/ylt/util/sha3_detail.hpp index cc52de7b8..ca58a4c94 100644 --- a/include/ylt/util/sha3_detail.hpp +++ b/include/ylt/util/sha3_detail.hpp @@ -265,21 +265,21 @@ inline constexpr auto step_mapping_rho_rotation_bits = [] { */ inline constexpr auto step_mapping_tau_rc_table = [](std::index_sequence) { - constexpr auto func_rc = [](std::size_t round) { - // Let RC = 0w. - // For j from 0 to l = log2(w), let RC[2 ^ j – 1] = rc(j + 7ir). - word_type result = 0; - - for (std::size_t i = 0; i <= log2_word_bits; i++) { - set_number_bit(result, (1 << i) - 1, - step_mapping_helper_rc(i + 7 * round)); - } + constexpr auto func_rc = [](std::size_t round) { + // Let RC = 0w. + // For j from 0 to l = log2(w), let RC[2 ^ j – 1] = rc(j + 7ir). + word_type result = 0; + + for (std::size_t i = 0; i <= log2_word_bits; i++) { + set_number_bit(result, (1 << i) - 1, + step_mapping_helper_rc(i + 7 * round)); + } - return result; - }; + return result; + }; - return std::array{func_rc(Is)...}; - } + return std::array{func_rc(Is)...}; +} (std::make_index_sequence{}); /** From b6df454354171de15a36f4c2d997e2fa47297e20 Mon Sep 17 00:00:00 2001 From: metabeyond Date: Fri, 14 Feb 2025 13:01:47 +0800 Subject: [PATCH 6/7] Formatting code --- include/ylt/util/meta_math.hpp | 8 -------- include/ylt/util/sha3_detail.hpp | 2 +- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/include/ylt/util/meta_math.hpp b/include/ylt/util/meta_math.hpp index f104d7068..fcbdda8bf 100644 --- a/include/ylt/util/meta_math.hpp +++ b/include/ylt/util/meta_math.hpp @@ -173,14 +173,6 @@ constexpr void set_number_bit(UnsignedNumber& number, int offset, (static_cast(bit) << offset); } -/// -/// Computes the result of bitwise left-rotating the value of "number" by "bits" -/// positions. This operation is also known as a left circular shift. -/// -/// The unsigned numeric type -/// The unsigned number -/// The bits -/// The result /** * Computes the result of bitwise left-rotating the value of "number" by "bits" * positions. This operation is also known as a left circular shift. diff --git a/include/ylt/util/sha3_detail.hpp b/include/ylt/util/sha3_detail.hpp index ca58a4c94..95e11d59d 100644 --- a/include/ylt/util/sha3_detail.hpp +++ b/include/ylt/util/sha3_detail.hpp @@ -320,7 +320,7 @@ constexpr void step_mapping_theta(hash_context& context) noexcept { */ template constexpr void step_mapping_rho(hash_context& context) noexcept { - // For all z such that 0 �� z �� w, let A'[0, 0, z] = A[0, 0, z]. + // For all z such that 0 ≤ z ≤ w, let A'[0, 0, z] = A[0, 0, z]. context.intermediate(0, 0) = context.state(0, 0); // (x, y) = (1, 0) From a6078b20666a26b0d6cb849e057ff1ee6e5a8ee2 Mon Sep 17 00:00:00 2001 From: metabeyond Date: Fri, 14 Feb 2025 18:26:40 +0800 Subject: [PATCH 7/7] Added tests for ylt::make_number. --- src/util/tests/test_sha3_constexpr.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/util/tests/test_sha3_constexpr.cpp b/src/util/tests/test_sha3_constexpr.cpp index 601ce2060..6dc802173 100644 --- a/src/util/tests/test_sha3_constexpr.cpp +++ b/src/util/tests/test_sha3_constexpr.cpp @@ -20,6 +20,9 @@ constexpr void test_meta_numeric_conversion() { static_assert(to_hexadecimal_meta_string( std::array{0x12, 0x34, 0x60, 0xAB}) == refvalue::meta_string{"123460AB"}); + + static_assert(make_number(std::array{ + 0x12, 0x34, 0x56, 0x78}) == 0x12345678); } constexpr void test_sha3_constexpr() noexcept {