Skip to content

Instantly share code, notes, and snippets.

@MarekKnapek
Created September 18, 2025 02:23
Show Gist options
  • Select an option

  • Save MarekKnapek/bbca266da777a7ce97936ef254ddece3 to your computer and use it in GitHub Desktop.

Select an option

Save MarekKnapek/bbca266da777a7ce97936ef254ddece3 to your computer and use it in GitHub Desktop.
SHA-1 C++ constexpr
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