mirror of
https://github.com/bolero-MURAKAMI/Sprout.git
synced 2024-12-23 21:25:49 +00:00
458 lines
18 KiB
C++
458 lines
18 KiB
C++
/*=============================================================================
|
|
Copyright (c) 2011-2013 Bolero MURAKAMI
|
|
https://github.com/bolero-MURAKAMI/Sprout
|
|
|
|
Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|
=============================================================================*/
|
|
#ifndef SPROUT_CHECKSUM_MD5_HPP
|
|
#define SPROUT_CHECKSUM_MD5_HPP
|
|
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <climits>
|
|
#include <type_traits>
|
|
#include <sprout/config.hpp>
|
|
#include <sprout/array/array.hpp>
|
|
#include <sprout/container/functions.hpp>
|
|
#include <sprout/iterator/operation.hpp>
|
|
#include <sprout/iterator/bytes_iterator.hpp>
|
|
#include <sprout/operation/fixed/set.hpp>
|
|
#include <sprout/bit/rotate.hpp>
|
|
|
|
namespace sprout {
|
|
static_assert(CHAR_BIT == 8, "CHAR_BIT == 8");
|
|
|
|
namespace md5_detail {
|
|
inline SPROUT_CONSTEXPR std::uint32_t
|
|
func_f(std::uint32_t x, std::uint32_t y, std::uint32_t z) {
|
|
return (x & y) | (~x & z);
|
|
}
|
|
inline SPROUT_CONSTEXPR std::uint32_t
|
|
func_g(std::uint32_t x, std::uint32_t y, std::uint32_t z) {
|
|
return (x & z) | (y & ~z);
|
|
}
|
|
inline SPROUT_CONSTEXPR std::uint32_t
|
|
func_h(std::uint32_t x, std::uint32_t y, std::uint32_t z) {
|
|
return x ^ y ^ z;
|
|
}
|
|
inline SPROUT_CONSTEXPR std::uint32_t
|
|
func_i(std::uint32_t x, std::uint32_t y, std::uint32_t z) {
|
|
return y ^ (x | ~z);
|
|
}
|
|
|
|
struct round1_op {
|
|
public:
|
|
SPROUT_CONSTEXPR std::uint32_t
|
|
operator()(std::uint32_t a, std::uint32_t b, std::uint32_t c, std::uint32_t d, std::uint32_t x, std::uint32_t t, std::uint32_t s) const {
|
|
return b + sprout::left_rotate(a + sprout::md5_detail::func_f(b, c, d) + x + t, s);
|
|
}
|
|
};
|
|
struct round2_op {
|
|
public:
|
|
inline SPROUT_CONSTEXPR std::uint32_t
|
|
operator()(std::uint32_t a, std::uint32_t b, std::uint32_t c, std::uint32_t d, std::uint32_t x, std::uint32_t t, std::uint32_t s) const {
|
|
return b + sprout::left_rotate(a + sprout::md5_detail::func_g(b, c, d) + x + t, s);
|
|
}
|
|
};
|
|
struct round3_op {
|
|
public:
|
|
inline SPROUT_CONSTEXPR std::uint32_t
|
|
operator()(std::uint32_t a, std::uint32_t b, std::uint32_t c, std::uint32_t d, std::uint32_t x, std::uint32_t t, std::uint32_t s) const {
|
|
return b + sprout::left_rotate(a + sprout::md5_detail::func_h(b, c, d) + x + t, s);
|
|
}
|
|
};
|
|
struct round4_op {
|
|
public:
|
|
inline SPROUT_CONSTEXPR std::uint32_t
|
|
operator()(std::uint32_t a, std::uint32_t b, std::uint32_t c, std::uint32_t d, std::uint32_t x, std::uint32_t t, std::uint32_t s) const {
|
|
return b + sprout::left_rotate(a + sprout::md5_detail::func_i(b, c, d) + x + t, s);
|
|
}
|
|
};
|
|
|
|
template<typename RoundOp>
|
|
inline SPROUT_CONSTEXPR sprout::array<std::uint32_t, 4>
|
|
round_x_impl(
|
|
std::uint32_t a, std::uint32_t b, std::uint32_t c, std::uint32_t d, sprout::array<std::uint32_t, 16> const& x, RoundOp round_op,
|
|
sprout::array<std::size_t, 16> const& xis, sprout::array<std::uint32_t, 16> const& ts, sprout::array<std::uint32_t, 16> const& ss,
|
|
std::size_t i = 0
|
|
)
|
|
{
|
|
return i == 16 ? sprout::array<std::uint32_t, 4>{{a, b, c, d}}
|
|
: i % 4 == 0 ? sprout::md5_detail::round_x_impl(round_op(a, b, c, d, x[xis[i]], ts[i], ss[i]), b, c, d, x, round_op, xis, ts, ss, i + 1)
|
|
: i % 4 == 1 ? sprout::md5_detail::round_x_impl(a, b, c, round_op(d, a, b, c, x[xis[i]], ts[i], ss[i]), x, round_op, xis, ts, ss, i + 1)
|
|
: i % 4 == 2 ? sprout::md5_detail::round_x_impl(a, b, round_op(c, d, a, b, x[xis[i]], ts[i], ss[i]), d, x, round_op, xis, ts, ss, i + 1)
|
|
: sprout::md5_detail::round_x_impl(a, round_op(b, c, d, a, x[xis[i]], ts[i], ss[i]), c, d, x, round_op, xis, ts, ss, i + 1)
|
|
;
|
|
}
|
|
template<typename RoundOp>
|
|
inline SPROUT_CONSTEXPR sprout::array<std::uint32_t, 4>
|
|
round_x(
|
|
sprout::array<std::uint32_t, 4> const& k, sprout::array<std::uint32_t, 16> const& x, RoundOp round_op,
|
|
sprout::array<std::size_t, 16> const& xis, sprout::array<std::uint32_t, 16> const& ts, sprout::array<std::uint32_t, 16> const& ss
|
|
)
|
|
{
|
|
return sprout::md5_detail::round_x_impl(k[0], k[1], k[2], k[3], x, round_op, xis, ts, ss);
|
|
}
|
|
|
|
template<int N>
|
|
struct round_table;
|
|
|
|
# define SPROUT_MD5_DETAIL_ROUND_TABLE_DEF(N, XIS, TS, SS) \
|
|
template<> \
|
|
struct round_table<N> { \
|
|
public: \
|
|
typedef sprout::array<std::size_t, 16> xis_type; \
|
|
typedef sprout::array<std::uint32_t, 16> ts_type; \
|
|
typedef sprout::array<std::uint32_t, 16> ss_type; \
|
|
public: \
|
|
SPROUT_STATIC_CONSTEXPR xis_type xis \
|
|
SPROUT_STATIC_CONSTEXPR_DATA_MEMBER_INNER(XIS) \
|
|
; \
|
|
SPROUT_STATIC_CONSTEXPR ts_type ts \
|
|
SPROUT_STATIC_CONSTEXPR_DATA_MEMBER_INNER(TS) \
|
|
; \
|
|
SPROUT_STATIC_CONSTEXPR ss_type ss \
|
|
SPROUT_STATIC_CONSTEXPR_DATA_MEMBER_INNER(SS) \
|
|
; \
|
|
}; \
|
|
SPROUT_CONSTEXPR_OR_CONST typename sprout::md5_detail::round_table<N>::xis_type sprout::md5_detail::round_table<N>::xis \
|
|
SPROUT_STATIC_CONSTEXPR_DATA_MEMBER_OUTER(XIS) \
|
|
; \
|
|
SPROUT_CONSTEXPR_OR_CONST typename sprout::md5_detail::round_table<N>::ts_type sprout::md5_detail::round_table<N>::ts \
|
|
SPROUT_STATIC_CONSTEXPR_DATA_MEMBER_OUTER(TS) \
|
|
; \
|
|
SPROUT_CONSTEXPR_OR_CONST typename sprout::md5_detail::round_table<N>::ss_type sprout::md5_detail::round_table<N>::ss \
|
|
SPROUT_STATIC_CONSTEXPR_DATA_MEMBER_OUTER(SS)
|
|
|
|
SPROUT_MD5_DETAIL_ROUND_TABLE_DEF( \
|
|
1, \
|
|
(xis_type{{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}}), \
|
|
(ts_type{{ \
|
|
0xD76AA478, 0xE8C7B756, 0x242070DB, 0xC1BDCEEE, 0xF57C0FAF, 0x4787C62A, 0xA8304613, 0xFD469501, \
|
|
0x698098D8, 0x8B44F7AF, 0xFFFF5BB1, 0x895CD7BE, 0x6B901122, 0xFD987193, 0xA679438E, 0x49B40821 \
|
|
}}), \
|
|
(ss_type{{7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22}}) \
|
|
);
|
|
SPROUT_MD5_DETAIL_ROUND_TABLE_DEF( \
|
|
2, \
|
|
(xis_type{{1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12}}), \
|
|
(ts_type{{ \
|
|
0xF61E2562, 0xC040B340, 0x265E5A51, 0xE9B6C7AA, 0xD62F105D, 0x02441453, 0xD8A1E681, 0xE7D3FBC8, \
|
|
0x21E1CDE6, 0xC33707D6, 0xF4D50D87, 0x455A14ED, 0xA9E3E905, 0xFCEFA3F8, 0x676F02D9, 0x8D2A4C8A \
|
|
}}), \
|
|
(ss_type{{5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20}}) \
|
|
);
|
|
SPROUT_MD5_DETAIL_ROUND_TABLE_DEF( \
|
|
3, \
|
|
(xis_type{{5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2}}), \
|
|
(ts_type{{ \
|
|
0xFFFA3942, 0x8771F681, 0x6D9D6122, 0xFDE5380C, 0xA4BEEA44, 0x4BDECFA9, 0xF6BB4B60, 0xBEBFBC70, \
|
|
0x289B7EC6, 0xEAA127FA, 0xD4EF3085, 0x04881D05, 0xD9D4D039, 0xE6DB99E5, 0x1FA27CF8, 0xC4AC5665 \
|
|
}}), \
|
|
(ss_type{{4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23}}) \
|
|
);
|
|
SPROUT_MD5_DETAIL_ROUND_TABLE_DEF( \
|
|
4, \
|
|
(xis_type{{0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9}}), \
|
|
(ts_type{{ \
|
|
0xF4292244, 0x432AFF97, 0xAB9423A7, 0xFC93A039, 0x655B59C3, 0x8F0CCC92, 0xFFEFF47D, 0x85845DD1, \
|
|
0x6FA87E4F, 0xFE2CE6E0, 0xA3014314, 0x4E0811A1, 0xF7537E82, 0xBD3AF235, 0x2AD7D2BB, 0xEB86D391 \
|
|
}}), \
|
|
(ss_type{{6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21}}) \
|
|
);
|
|
# undef SPROUT_MD5_DETAIL_ROUND_TABLE_DEF
|
|
|
|
inline SPROUT_CONSTEXPR sprout::array<std::uint32_t, 4>
|
|
round1(sprout::array<std::uint32_t, 4> const& k, sprout::array<std::uint32_t, 16> const& x) {
|
|
return sprout::md5_detail::round_x(
|
|
k, x, sprout::md5_detail::round1_op(),
|
|
sprout::md5_detail::round_table<1>::xis,
|
|
sprout::md5_detail::round_table<1>::ts,
|
|
sprout::md5_detail::round_table<1>::ss
|
|
);
|
|
}
|
|
inline SPROUT_CONSTEXPR sprout::array<std::uint32_t, 4>
|
|
round2(sprout::array<std::uint32_t, 4> const& k, sprout::array<std::uint32_t, 16> const& x) {
|
|
return sprout::md5_detail::round_x(
|
|
k, x, sprout::md5_detail::round2_op(),
|
|
sprout::md5_detail::round_table<2>::xis,
|
|
sprout::md5_detail::round_table<2>::ts,
|
|
sprout::md5_detail::round_table<2>::ss
|
|
);
|
|
}
|
|
inline SPROUT_CONSTEXPR sprout::array<std::uint32_t, 4>
|
|
round3(sprout::array<std::uint32_t, 4> const& k, sprout::array<std::uint32_t, 16> const& x) {
|
|
return sprout::md5_detail::round_x(
|
|
k, x, sprout::md5_detail::round3_op(),
|
|
sprout::md5_detail::round_table<3>::xis,
|
|
sprout::md5_detail::round_table<3>::ts,
|
|
sprout::md5_detail::round_table<3>::ss
|
|
);
|
|
}
|
|
inline SPROUT_CONSTEXPR sprout::array<std::uint32_t, 4>
|
|
round4(sprout::array<std::uint32_t, 4> const& k, sprout::array<std::uint32_t, 16> const& x) {
|
|
return sprout::md5_detail::round_x(
|
|
k, x, sprout::md5_detail::round4_op(),
|
|
sprout::md5_detail::round_table<4>::xis,
|
|
sprout::md5_detail::round_table<4>::ts,
|
|
sprout::md5_detail::round_table<4>::ss
|
|
);
|
|
}
|
|
|
|
inline SPROUT_CONSTEXPR sprout::array<std::uint32_t, 4>
|
|
round_all(sprout::array<std::uint32_t, 4> const& k, sprout::array<std::uint32_t, 16> const& x) {
|
|
return sprout::md5_detail::round4(
|
|
sprout::md5_detail::round3(
|
|
sprout::md5_detail::round2(
|
|
sprout::md5_detail::round1(k, x),
|
|
x
|
|
),
|
|
x
|
|
),
|
|
x
|
|
);
|
|
}
|
|
} // namespace detail
|
|
|
|
//
|
|
// md5
|
|
//
|
|
class md5 {
|
|
public:
|
|
typedef sprout::array<std::uint8_t, 16> value_type;
|
|
typedef md5 const const_type;
|
|
private:
|
|
sprout::array<std::uint32_t, 4> k_;
|
|
sprout::array<std::uint32_t, 16> block_;
|
|
std::uint64_t bit_count_;
|
|
private:
|
|
SPROUT_CONSTEXPR md5(
|
|
sprout::array<std::uint32_t, 4> const& k,
|
|
std::uint64_t bit_count
|
|
)
|
|
: k_(k)
|
|
, block_{{}}
|
|
, bit_count_(bit_count)
|
|
{}
|
|
SPROUT_CONSTEXPR md5(
|
|
sprout::array<std::uint32_t, 4> const& k,
|
|
sprout::array<std::uint32_t, 16> const& block,
|
|
std::uint64_t bit_count
|
|
)
|
|
: k_(k)
|
|
, block_(block)
|
|
, bit_count_(bit_count)
|
|
{}
|
|
SPROUT_CONSTEXPR md5 const process(
|
|
sprout::array<std::uint32_t, 4> const& k,
|
|
sprout::array<std::uint32_t, 16> const& block,
|
|
std::uint64_t bit_count
|
|
) const
|
|
{
|
|
return bit_count % (64 * 8) != 0 ? const_type(k, block, bit_count)
|
|
: const_type(k, block, bit_count).process_block()
|
|
;
|
|
}
|
|
SPROUT_CONSTEXPR md5 const process_block_1(sprout::array<std::uint32_t, 4> const& x) const {
|
|
return md5(
|
|
sprout::array<std::uint32_t, 4>{{k_[0] + x[0], k_[1] + x[1], k_[2] + x[2], k_[3] + x[3]}},
|
|
bit_count_
|
|
);
|
|
}
|
|
SPROUT_CONSTEXPR md5 const process_block() const {
|
|
return process_block_1(sprout::md5_detail::round_all(k_, block_));
|
|
}
|
|
SPROUT_CONSTEXPR md5 const process_bit_impl(bool bit, std::size_t index, std::size_t offset) const {
|
|
return process(
|
|
k_,
|
|
sprout::fixed::set(
|
|
block_,
|
|
block_.begin() + index,
|
|
block_[index] | static_cast<std::uint32_t>(bit) << (offset / 8 * 8 + (7 - offset % 8))
|
|
),
|
|
bit_count_ + 1
|
|
);
|
|
}
|
|
SPROUT_CONSTEXPR md5 const process_bits_impl(std::uint8_t bits, std::size_t i) const {
|
|
return i == 0 ? *this
|
|
: process_bit(((bits >> (i - 1)) & 1) != 0).process_bits_impl(bits, i - 1)
|
|
;
|
|
}
|
|
SPROUT_CONSTEXPR md5 const process_byte_impl(std::uint8_t byte, std::size_t index, std::size_t offset) const {
|
|
return process(
|
|
k_,
|
|
sprout::fixed::set(
|
|
block_,
|
|
block_.begin() + index,
|
|
block_[index]
|
|
| static_cast<std::uint32_t>(((byte >> 7) & 1) != 0) << (offset / 8 * 8 + (7 - offset % 8))
|
|
| static_cast<std::uint32_t>(((byte >> 6) & 1) != 0) << ((offset + 1) / 8 * 8 + (7 - (offset + 1) % 8))
|
|
| static_cast<std::uint32_t>(((byte >> 5) & 1) != 0) << ((offset + 2) / 8 * 8 + (7 - (offset + 2) % 8))
|
|
| static_cast<std::uint32_t>(((byte >> 4) & 1) != 0) << ((offset + 3) / 8 * 8 + (7 - (offset + 3) % 8))
|
|
| static_cast<std::uint32_t>(((byte >> 3) & 1) != 0) << ((offset + 4) / 8 * 8 + (7 - (offset + 4) % 8))
|
|
| static_cast<std::uint32_t>(((byte >> 2) & 1) != 0) << ((offset + 5) / 8 * 8 + (7 - (offset + 5) % 8))
|
|
| static_cast<std::uint32_t>(((byte >> 1) & 1) != 0) << ((offset + 6) / 8 * 8 + (7 - (offset + 6) % 8))
|
|
| static_cast<std::uint32_t>((byte & 1) != 0) << ((offset + 7) / 8 * 8 + (7 - (offset + 7) % 8))
|
|
),
|
|
bit_count_ + 8
|
|
);
|
|
}
|
|
template<typename InputIterator>
|
|
SPROUT_CONSTEXPR md5 const process_block_impl(InputIterator first, InputIterator last) const {
|
|
return first == last ? *this
|
|
: process_byte(*first).process_block_impl(sprout::next(first), last)
|
|
;
|
|
}
|
|
SPROUT_CONSTEXPR std::uint64_t pad_size() const {
|
|
return static_cast<std::size_t>((511 + 448 - bit_count_) % 512);
|
|
}
|
|
SPROUT_CONSTEXPR md5 const process_padding(std::uint64_t pad_size) const {
|
|
return pad_size == 0 ? *this
|
|
: process_bit(false).process_padding(pad_size - 1)
|
|
;
|
|
}
|
|
SPROUT_CONSTEXPR md5 const process_length(std::uint64_t bit_count) const {
|
|
return process_byte(static_cast<std::uint8_t>(bit_count & 0xFF))
|
|
.process_byte(static_cast<std::uint8_t>((bit_count >> 8) & 0xFF))
|
|
.process_byte(static_cast<std::uint8_t>((bit_count >> 16) & 0xFF))
|
|
.process_byte(static_cast<std::uint8_t>((bit_count >> 24) & 0xFF))
|
|
.process_byte(static_cast<std::uint8_t>((bit_count >> 32) & 0xFF))
|
|
.process_byte(static_cast<std::uint8_t>((bit_count >> 40) & 0xFF))
|
|
.process_byte(static_cast<std::uint8_t>((bit_count >> 48) & 0xFF))
|
|
.process_byte(static_cast<std::uint8_t>((bit_count >> 56) & 0xFF))
|
|
;
|
|
}
|
|
SPROUT_CONSTEXPR value_type make_value() const {
|
|
return value_type{{
|
|
static_cast<std::uint8_t>((k_[0]) & 0xFF),
|
|
static_cast<std::uint8_t>((k_[0] >> 8) & 0xFF),
|
|
static_cast<std::uint8_t>((k_[0] >> 16) & 0xFF),
|
|
static_cast<std::uint8_t>((k_[0] >> 24) & 0xFF),
|
|
static_cast<std::uint8_t>((k_[1]) & 0xFF),
|
|
static_cast<std::uint8_t>((k_[1] >> 8) & 0xFF),
|
|
static_cast<std::uint8_t>((k_[1] >> 16) & 0xFF),
|
|
static_cast<std::uint8_t>((k_[1] >> 24) & 0xFF),
|
|
static_cast<std::uint8_t>((k_[2]) & 0xFF),
|
|
static_cast<std::uint8_t>((k_[2] >> 8) & 0xFF),
|
|
static_cast<std::uint8_t>((k_[2] >> 16) & 0xFF),
|
|
static_cast<std::uint8_t>((k_[2] >> 24) & 0xFF),
|
|
static_cast<std::uint8_t>((k_[3]) & 0xFF),
|
|
static_cast<std::uint8_t>((k_[3] >> 8) & 0xFF),
|
|
static_cast<std::uint8_t>((k_[3] >> 16) & 0xFF),
|
|
static_cast<std::uint8_t>((k_[3] >> 24) & 0xFF)
|
|
}};
|
|
}
|
|
void process_block() {
|
|
sprout::array<std::uint32_t, 4> x = sprout::md5_detail::round_all(k_, block_);
|
|
k_[0] += x[0];
|
|
k_[1] += x[1];
|
|
k_[2] += x[2];
|
|
k_[3] += x[3];
|
|
block_.assign(0);
|
|
}
|
|
template<typename InputIterator>
|
|
void process_block_impl(InputIterator first, InputIterator last) {
|
|
for(; first != last; ++first) {
|
|
process_byte(*first);
|
|
}
|
|
}
|
|
public:
|
|
SPROUT_CONSTEXPR md5()
|
|
: k_{{0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476}}
|
|
, block_{{}}
|
|
, bit_count_()
|
|
{}
|
|
void reset() {
|
|
k_[0] = 0x67452301;
|
|
k_[1] = 0xEFCDAB89;
|
|
k_[2] = 0x98BADCFE;
|
|
k_[3] = 0x10325476;
|
|
block_.assign(0);
|
|
bit_count_ = 0;
|
|
}
|
|
|
|
SPROUT_CONSTEXPR md5 const process_bit(bool bit) const {
|
|
return process_bit_impl(
|
|
bit,
|
|
static_cast<std::size_t>(bit_count_ % (64 * 8) / 32),
|
|
static_cast<std::size_t>(bit_count_ % 32)
|
|
);
|
|
}
|
|
SPROUT_CONSTEXPR md5 const process_bits(std::uint8_t bits, std::size_t bit_count) const {
|
|
return process_bits_impl(bits, bit_count);
|
|
}
|
|
SPROUT_CONSTEXPR md5 const process_byte(std::uint8_t byte) const {
|
|
return bit_count_ % 8 == 0 ? process_byte_impl(
|
|
byte,
|
|
static_cast<std::size_t>(bit_count_ % (64 * 8) / 32),
|
|
static_cast<std::size_t>(bit_count_ % 32)
|
|
)
|
|
: process_bit(((byte >> 7) & 1) != 0)
|
|
.process_bit(((byte >> 6) & 1) != 0)
|
|
.process_bit(((byte >> 5) & 1) != 0)
|
|
.process_bit(((byte >> 4) & 1) != 0)
|
|
.process_bit(((byte >> 3) & 1) != 0)
|
|
.process_bit(((byte >> 2) & 1) != 0)
|
|
.process_bit(((byte >> 1) & 1) != 0)
|
|
.process_bit((byte & 1) != 0)
|
|
;
|
|
}
|
|
template<typename InputIterator>
|
|
SPROUT_CONSTEXPR md5 const process_block(InputIterator bytes_begin, InputIterator bytes_end) const {
|
|
return process_block_impl(
|
|
sprout::make_bytes_iterator(bytes_begin),
|
|
sprout::make_bytes_iterator(bytes_end)
|
|
);
|
|
}
|
|
template<typename InputIterator>
|
|
SPROUT_CONSTEXPR md5 const process_bytes(InputIterator buffer, std::size_t byte_count) const {
|
|
return process_block(buffer, sprout::next(buffer, byte_count));
|
|
}
|
|
template<typename InputRange>
|
|
SPROUT_CONSTEXPR md5 const process_range(InputRange const& bytes_range) const {
|
|
return process_block(sprout::begin(bytes_range), sprout::end(bytes_range));
|
|
}
|
|
|
|
void process_bit(bool bit) {
|
|
std::size_t index = static_cast<std::size_t>(bit_count_ % (64 * 8) / 32);
|
|
std::size_t offset = static_cast<std::size_t>(bit_count_ % 32);
|
|
block_[index] |= static_cast<std::uint32_t>(bit) << (offset / 8 * 8 + (7 - offset % 8));
|
|
if (++bit_count_ % 512 == 0) {
|
|
process_block();
|
|
}
|
|
}
|
|
void process_bits(std::uint8_t bits, std::size_t bit_count) {
|
|
while (bit_count--) {
|
|
process_bit(((bits >> bit_count) & 1) != 0);
|
|
}
|
|
}
|
|
void process_byte(std::uint8_t byte) {
|
|
process_bits(byte, 8);
|
|
}
|
|
template<typename InputIterator>
|
|
void process_block(InputIterator bytes_begin, InputIterator bytes_end) {
|
|
process_block_impl(
|
|
sprout::make_bytes_iterator(bytes_begin),
|
|
sprout::make_bytes_iterator(bytes_end)
|
|
);
|
|
}
|
|
template<typename InputIterator>
|
|
void process_bytes(InputIterator buffer, std::size_t byte_count) {
|
|
process_block(buffer, sprout::next(buffer, byte_count));
|
|
}
|
|
template<typename InputRange>
|
|
void process_range(InputRange const& bytes_range) {
|
|
process_block(sprout::begin(bytes_range), sprout::end(bytes_range));
|
|
}
|
|
|
|
SPROUT_CONSTEXPR value_type checksum() const {
|
|
return process_bit(true).process_padding(pad_size()).process_length(bit_count_).make_value();
|
|
}
|
|
SPROUT_CONSTEXPR value_type operator()() const {
|
|
return checksum();
|
|
}
|
|
};
|
|
} // namespace sprout
|
|
|
|
#endif // #ifndef SPROUT_CHECKSUM_MD5_HPP
|