Created
September 18, 2025 02:23
-
-
Save MarekKnapek/bbca266da777a7ce97936ef254ddece3 to your computer and use it in GitHub Desktop.
SHA-1 C++ constexpr
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| void xxxxxxxxxx() noexcept(true) = delete; | |
| #define my_assert(x) ((!!(x)) ? ((void)(0)) : ((void)(xxxxxxxxxx()))) | |
| typedef decltype(1uz) my_usize_t; | |
| typedef unsigned char my_uint8_t; | |
| typedef unsigned int my_uint32_t; | |
| typedef unsigned long long int my_uint64_t; | |
| struct my_string_view | |
| { | |
| char const* m_str; | |
| my_usize_t m_len; | |
| }; | |
| [[nodiscard]] constexpr my_string_view operator ""_my_sv(char const* const str, my_usize_t const len) noexcept(true) | |
| { | |
| my_string_view r; | |
| r.m_str = str; | |
| r.m_len = len; | |
| return r; | |
| } | |
| template<typename t> | |
| [[nodiscard]] constexpr auto my_begin(t&) noexcept(true); | |
| template<typename t, my_usize_t n> | |
| [[nodiscard]] constexpr auto my_begin(t(&arr)[n]) noexcept(true) | |
| { | |
| return &arr[0]; | |
| } | |
| template<typename t> | |
| [[nodiscard]] constexpr auto my_end(t&) noexcept(true); | |
| template<typename t, my_usize_t n> | |
| [[nodiscard]] constexpr auto my_end(t(&arr)[n]) noexcept(true) | |
| { | |
| return &arr[0] + n; | |
| } | |
| template<typename iterator1_t, typename iterator2_t, typename value_t> | |
| constexpr void my_fill(iterator1_t const& begin, iterator2_t const& end, value_t const& value) noexcept(true) | |
| { | |
| iterator1_t it; | |
| for(it = begin; it != end; ++it) | |
| { | |
| *it = value; | |
| } | |
| } | |
| constexpr void my_copy(char const* const& begin, char const* const& end, my_uint8_t* const& dst) noexcept(true) | |
| { | |
| char const* it; | |
| my_uint8_t* dd; | |
| for(it = begin, dd = dst; it != end; ++it, ++dd) | |
| { | |
| *dd = static_cast<my_uint8_t>(*it); | |
| } | |
| } | |
| template<typename t, my_usize_t n> | |
| struct my_array_t | |
| { | |
| t m_arr[n]; | |
| constexpr my_array_t() noexcept(true) | |
| { | |
| my_fill(my_begin(m_arr), my_end(m_arr), t{}); | |
| } | |
| [[nodiscard]] constexpr my_usize_t size() const noexcept(true) | |
| { | |
| return n; | |
| } | |
| }; | |
| [[nodiscard]] constexpr my_uint32_t my_bytes_to_u32_be(my_uint8_t const* const& ptr) noexcept(true) | |
| { | |
| my_uint32_t r; | |
| r = | |
| (static_cast<my_uint32_t>(ptr[0]) << (3 * 8)) | | |
| (static_cast<my_uint32_t>(ptr[1]) << (2 * 8)) | | |
| (static_cast<my_uint32_t>(ptr[2]) << (1 * 8)) | | |
| (static_cast<my_uint32_t>(ptr[3]) << (0 * 8)) | | |
| 0; | |
| return r; | |
| } | |
| constexpr void my_u32_to_bytes_be(my_uint32_t const& u32, my_uint8_t* const& ptr) noexcept(true) | |
| { | |
| ptr[0] = static_cast<my_uint8_t>((u32 >> (3 * 8)) & static_cast<my_uint32_t>(0xff)); | |
| ptr[1] = static_cast<my_uint8_t>((u32 >> (2 * 8)) & static_cast<my_uint32_t>(0xff)); | |
| ptr[2] = static_cast<my_uint8_t>((u32 >> (1 * 8)) & static_cast<my_uint32_t>(0xff)); | |
| ptr[3] = static_cast<my_uint8_t>((u32 >> (0 * 8)) & static_cast<my_uint32_t>(0xff)); | |
| } | |
| constexpr void my_u64_to_bytes_be(my_uint64_t const& u64, my_uint8_t* const& ptr) noexcept(true) | |
| { | |
| ptr[0] = static_cast<my_uint8_t>((u64 >> (7 * 8)) & static_cast<my_uint64_t>(0xff)); | |
| ptr[1] = static_cast<my_uint8_t>((u64 >> (6 * 8)) & static_cast<my_uint64_t>(0xff)); | |
| ptr[2] = static_cast<my_uint8_t>((u64 >> (5 * 8)) & static_cast<my_uint64_t>(0xff)); | |
| ptr[3] = static_cast<my_uint8_t>((u64 >> (4 * 8)) & static_cast<my_uint64_t>(0xff)); | |
| ptr[4] = static_cast<my_uint8_t>((u64 >> (3 * 8)) & static_cast<my_uint64_t>(0xff)); | |
| ptr[5] = static_cast<my_uint8_t>((u64 >> (2 * 8)) & static_cast<my_uint64_t>(0xff)); | |
| ptr[6] = static_cast<my_uint8_t>((u64 >> (1 * 8)) & static_cast<my_uint64_t>(0xff)); | |
| ptr[7] = static_cast<my_uint8_t>((u64 >> (0 * 8)) & static_cast<my_uint64_t>(0xff)); | |
| } | |
| [[nodiscard]] constexpr my_uint32_t my_rotl(my_uint32_t const& a, int const& b) noexcept(true) | |
| { | |
| my_uint32_t r; | |
| r = (a << b) | (a >> (32 - b)); | |
| return r; | |
| } | |
| template<typename t> | |
| [[nodiscard]] constexpr t my_min(t const& a, t const& b) noexcept(true) | |
| { | |
| return b < a ? b : a; | |
| } | |
| struct sha1_block_t | |
| { | |
| typedef my_array_t<my_uint8_t, 64> block_t; | |
| my_uint32_t m_state[5]; | |
| my_uint64_t m_blocks; | |
| static constexpr my_uint32_t m_k_table[4] = | |
| { | |
| static_cast<my_uint32_t>(0x5a827999ul), | |
| static_cast<my_uint32_t>(0x6ed9eba1ul), | |
| static_cast<my_uint32_t>(0x8f1bbcdcul), | |
| static_cast<my_uint32_t>(0xca62c1d6ul), | |
| }; | |
| constexpr sha1_block_t() noexcept(true) | |
| { | |
| m_state[0] = static_cast<my_uint32_t>(0x67452301ul); | |
| m_state[1] = static_cast<my_uint32_t>(0xefcdab89ul); | |
| m_state[2] = static_cast<my_uint32_t>(0x98badcfeul); | |
| m_state[3] = static_cast<my_uint32_t>(0x10325476ul); | |
| m_state[4] = static_cast<my_uint32_t>(0xc3d2e1f0ul); | |
| m_blocks = 0; | |
| } | |
| [[nodiscard]] constexpr my_uint32_t func_ch(my_uint32_t const* const& x, my_uint32_t const* const& y, my_uint32_t const* const& z) noexcept(true) | |
| { | |
| my_uint32_t r; | |
| r = (*x & *y) | ((~*x) & *z); | |
| return r; | |
| } | |
| [[nodiscard]] constexpr my_uint32_t func_par(my_uint32_t const* const& x, my_uint32_t const* const& y, my_uint32_t const* const& z) noexcept(true) | |
| { | |
| my_uint32_t r; | |
| r = *x ^ *y ^ *z; | |
| return r; | |
| } | |
| [[nodiscard]] constexpr my_uint32_t func_maj(my_uint32_t const* const& x, my_uint32_t const* const& y, my_uint32_t const* const& z) noexcept(true) | |
| { | |
| my_uint32_t r; | |
| r = (*x & *y) ^ (*x & *z) ^ (*y & *z); | |
| return r; | |
| } | |
| [[nodiscard]] constexpr my_uint32_t func_f(int const& idx, my_uint32_t const* const& x, my_uint32_t const* const& y, my_uint32_t const* const& z) noexcept(true) | |
| { | |
| my_uint32_t r; | |
| switch(idx / 20) | |
| { | |
| case 0: r = func_ch (x, y, z); break; | |
| case 1: r = func_par(x, y, z); break; | |
| case 2: r = func_maj(x, y, z); break; | |
| case 3: r = func_par(x, y, z); break; | |
| default: r = 666; break; | |
| } | |
| return r; | |
| } | |
| constexpr void append_block(block_t const& block) noexcept(true) | |
| { | |
| my_uint32_t h[5]; | |
| my_uint32_t* a; | |
| my_uint32_t* b; | |
| my_uint32_t* c; | |
| my_uint32_t* d; | |
| my_uint32_t* e; | |
| int ir; | |
| my_uint32_t w[16]; | |
| my_uint32_t t; | |
| ++m_blocks; | |
| h[0] = m_state[0]; | |
| h[1] = m_state[1]; | |
| h[2] = m_state[2]; | |
| h[3] = m_state[3]; | |
| h[4] = m_state[4]; | |
| a = &h[0]; | |
| b = &h[1]; | |
| c = &h[2]; | |
| d = &h[3]; | |
| e = &h[4]; | |
| for(ir = 0; ir != 80; ++ir) | |
| { | |
| if(ir < 16) | |
| { | |
| w[ir % 16] = my_bytes_to_u32_be(&block.m_arr[ir * 4]); | |
| } | |
| else | |
| { | |
| w[ir % 16] = my_rotl(w[(ir - 3) % 16] ^ w[(ir - 8) % 16] ^ w[(ir - 14) % 16] ^ w[(ir - 16) % 16], 1); | |
| } | |
| t = my_rotl(*a, 5) + func_f(ir, b, c, d) + *e + m_k_table[ir / 20] + w[ir % 16]; | |
| *e = *d; | |
| *d = *c; | |
| *c = my_rotl(*b, 30); | |
| *b = *a; | |
| *a = t; | |
| } | |
| m_state[0] += h[0]; | |
| m_state[1] += h[1]; | |
| m_state[2] += h[2]; | |
| m_state[3] += h[3]; | |
| m_state[4] += h[4]; | |
| } | |
| }; | |
| struct sha1_stream_t : sha1_block_t | |
| { | |
| typedef my_array_t<my_uint8_t, 160 / 8> digest_t; | |
| sha1_block_t::block_t m_block; | |
| my_usize_t m_idx; | |
| constexpr sha1_stream_t() noexcept(true) | |
| { | |
| my_fill(my_begin(m_block.m_arr), my_end(m_block.m_arr), my_uint8_t{}); | |
| m_idx = 0; | |
| } | |
| constexpr void append_chars(char const* const& data_buf, my_usize_t const& data_len) noexcept(true) | |
| { | |
| char const* ptr; | |
| my_usize_t rem; | |
| my_usize_t fre; | |
| my_usize_t to_copy; | |
| ptr = data_buf; | |
| rem = data_len; | |
| while(rem != 0) | |
| { | |
| fre = m_block.size() - m_idx; | |
| to_copy = my_min(fre, rem); | |
| my_copy(ptr, ptr + to_copy, &m_block.m_arr[0] + m_idx); | |
| m_idx += to_copy; | |
| ptr += to_copy; | |
| rem -= to_copy; | |
| if(m_idx == m_block.size()) | |
| { | |
| m_idx = 0; | |
| append_block(m_block); | |
| } | |
| } | |
| } | |
| [[nodiscard]] constexpr digest_t finish() noexcept(true) | |
| { | |
| my_usize_t rest; | |
| int i; | |
| digest_t r; | |
| m_block.m_arr[m_idx] = 0x80; | |
| rest = m_block.size() - m_idx - 1; | |
| if(rest >= 64 / 8) | |
| { | |
| my_fill(&m_block.m_arr[m_idx + 1], &m_block.m_arr[m_idx + 1] + (rest - 64 / 8), my_uint8_t{}); | |
| } | |
| else | |
| { | |
| my_fill(&m_block.m_arr[m_idx + 1], &m_block.m_arr[0] + (rest), my_uint8_t{}); | |
| append_block(m_block); | |
| my_fill(&m_block.m_arr[0], &m_block.m_arr[0] + (m_block.size() - 64 / 8), my_uint8_t{}); | |
| } | |
| my_u64_to_bytes_be((m_blocks << (6 + 3)) + (static_cast<my_uint64_t>(m_idx) << 3), &m_block.m_arr[m_block.size() - 64 / 8]); | |
| append_block(m_block); | |
| for(i = 0; i != 5; ++i) | |
| { | |
| my_u32_to_bytes_be(m_state[i], &r.m_arr[i * 32 / 8]); | |
| } | |
| return r; | |
| } | |
| }; | |
| constexpr auto sha1(my_string_view const& sv) | |
| { | |
| sha1_stream_t sha1; | |
| sha1_stream_t::digest_t digest; | |
| sha1.append_chars(sv.m_str, sv.m_len); | |
| digest = sha1.finish(); | |
| return digest; | |
| } | |
| int main() | |
| { | |
| constexpr auto my_text = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"_my_sv; | |
| constexpr auto my_digest = sha1(my_text); | |
| // 003ef1ba9ea9f2f4dab3a2004e505ca8a4e7e5a3 | |
| static_assert(my_digest.m_arr[ 0] == 0x00); | |
| static_assert(my_digest.m_arr[ 1] == 0x3e); | |
| static_assert(my_digest.m_arr[ 2] == 0xf1); | |
| static_assert(my_digest.m_arr[ 3] == 0xba); | |
| static_assert(my_digest.m_arr[ 4] == 0x9e); | |
| static_assert(my_digest.m_arr[ 5] == 0xa9); | |
| static_assert(my_digest.m_arr[ 6] == 0xf2); | |
| static_assert(my_digest.m_arr[ 7] == 0xf4); | |
| static_assert(my_digest.m_arr[ 8] == 0xda); | |
| static_assert(my_digest.m_arr[ 9] == 0xb3); | |
| static_assert(my_digest.m_arr[10] == 0xa2); | |
| static_assert(my_digest.m_arr[11] == 0x00); | |
| static_assert(my_digest.m_arr[12] == 0x4e); | |
| static_assert(my_digest.m_arr[13] == 0x50); | |
| static_assert(my_digest.m_arr[14] == 0x5c); | |
| static_assert(my_digest.m_arr[15] == 0xa8); | |
| static_assert(my_digest.m_arr[16] == 0xa4); | |
| static_assert(my_digest.m_arr[17] == 0xe7); | |
| static_assert(my_digest.m_arr[18] == 0xe5); | |
| static_assert(my_digest.m_arr[19] == 0xa3); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment