28 requires(
typename T::digest_type& digest, std::span<const uint8_t> input,
size_t blocks) {
29 { T::init(digest) } -> std::same_as<void>;
30 { T::compress_n(digest, input, blocks) } -> std::same_as<void>;
36 } && T::block_bytes >= 64 &&
is_power_of_2(T::block_bytes) && T::output_bytes >= 16 && T::ctr_bytes >= 8 &&
44 void update(std::span<const uint8_t> input) {
48 if(
const auto one_block = m_buffer.handle_unaligned_data(in)) {
49 MD::compress_n(m_digest, one_block.value(), 1);
52 if(m_buffer.in_alignment()) {
53 const auto [aligned_data, full_blocks] = m_buffer.aligned_data_to_process(in);
55 MD::compress_n(m_digest, aligned_data, full_blocks);
60 m_count += input.size();
63 void final(std::span<uint8_t> output) {
65 append_counter_and_finalize();
77 void append_padding_bit() {
80 const uint8_t final_byte = 0x80;
81 m_buffer.
append({&final_byte, 1});
83 const uint8_t final_byte = 0x01;
84 m_buffer.append({&final_byte, 1});
88 void append_counter_and_finalize() {
91 if(m_buffer.elements_until_alignment() < MD::ctr_bytes) {
92 m_buffer.fill_up_with_zeros();
93 MD::compress_n(m_digest, m_buffer.consume(), 1);
98 m_buffer.fill_up_with_zeros();
101 const uint64_t bit_count = m_count * 8;
102 auto last_bytes = m_buffer.directly_modify_last(
sizeof(bit_count));
104 store_be(bit_count, last_bytes.data());
106 store_le(bit_count, last_bytes.data());
110 MD::compress_n(m_digest, m_buffer.consume(), 1);
113 void copy_output(std::span<uint8_t> output) {
117 copy_out_be(output.first(MD::output_bytes), m_digest);
119 copy_out_le(output.first(MD::output_bytes), m_digest);
124 typename MD::digest_type m_digest;
127 AlignmentBuffer<uint8_t, MD::block_bytes> m_buffer;