diff --git a/sprout/checksum/sha1.hpp b/sprout/checksum/sha1.hpp index 41c941c3..744d3fb3 100644 --- a/sprout/checksum/sha1.hpp +++ b/sprout/checksum/sha1.hpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -19,7 +20,8 @@ namespace sprout { static_assert(CHAR_BIT == 8, "CHAR_BIT == 8"); namespace detail { - inline SPROUT_CONSTEXPR std::uint32_t sha1_left_rotate(std::uint32_t x, std::size_t n) { + inline SPROUT_CONSTEXPR std::uint32_t + sha1_left_rotate(std::uint32_t x, std::size_t n) { return (x << n) ^ (x >> (32 - n)); } } // namespace detail @@ -34,18 +36,18 @@ namespace sprout { sprout::array h_; sprout::array block_; std::size_t block_byte_index_; - std::size_t byte_count_; + std::uint64_t bit_count_; private: SPROUT_CONSTEXPR sha1( sprout::array const& h, sprout::array const& block, std::size_t block_byte_index, - std::size_t byte_count + std::uint64_t bit_count ) : h_(h) , block_(block) , block_byte_index_(block_byte_index) - , byte_count_(byte_count) + , bit_count_(bit_count) {} SPROUT_CONSTEXPR std::uint32_t calc_w(std::size_t i) const { return i < 16 @@ -59,11 +61,11 @@ namespace sprout { ) ; } - SPROUT_CONSTEXPR sha1 process( + SPROUT_CONSTEXPR sha1 const process( sprout::array const& h, sprout::array const& block, std::size_t block_byte_index, - std::size_t byte_count + std::uint64_t bit_count ) const { return block_byte_index != 64 @@ -71,17 +73,17 @@ namespace sprout { h, block, block_byte_index, - byte_count + bit_count ) : sha1( h, block, 0, - byte_count - ).process_block() + bit_count + ).process_block_0() ; } - SPROUT_CONSTEXPR sha1 process_block_2( + SPROUT_CONSTEXPR sha1 const process_block_2( std::uint32_t a, std::uint32_t b, std::uint32_t c, @@ -101,7 +103,7 @@ namespace sprout { i + 1 ); } - SPROUT_CONSTEXPR sha1 process_block_1( + SPROUT_CONSTEXPR sha1 const process_block_1( std::uint32_t a, std::uint32_t b, std::uint32_t c, @@ -132,17 +134,17 @@ namespace sprout { sprout::array{{h_[0] + a, h_[1] + b, h_[2] + c, h_[3] + d, h_[4] + e}}, block_, block_byte_index_, - byte_count_ + bit_count_ ) ; } - SPROUT_CONSTEXPR sha1 process_block() const { + SPROUT_CONSTEXPR sha1 const process_block_0() const { return process_block_1(h_[0], h_[1], h_[2], h_[3], h_[4]); } template SPROUT_CONSTEXPR typename std::enable_if< sizeof...(Args) == 64, - sha1 + sha1 const >::type process_block_impl( Iterator first, Iterator last, @@ -153,20 +155,20 @@ namespace sprout { h_, sprout::make_array(args...), 64, - byte_count_ + 64 + bit_count_ + 64 * 8 ) : process( h_, sprout::make_array(args...), 64, - byte_count_ + 64 + bit_count_ + 64 * 8 ).process_block_impl(first, last) ; } template SPROUT_CONSTEXPR typename std::enable_if< sizeof...(Args) != 64, - sha1 + sha1 const >::type process_block_impl( Iterator first, Iterator last, @@ -177,74 +179,69 @@ namespace sprout { h_, sprout::get_internal(sprout::range::fixed::copy(sprout::make_array(args...), sprout::sub(block_, block_byte_index_))), block_byte_index_ + sizeof...(Args), - byte_count_ + sizeof...(Args) + bit_count_ + sizeof...(Args) * 8 ) : block_byte_index_ + sizeof...(Args) == 64 ? process( h_, sprout::get_internal(sprout::range::fixed::copy(sprout::make_array(args...), sprout::sub(block_, block_byte_index_))), block_byte_index_ + sizeof...(Args), - byte_count_ + sizeof...(Args) + bit_count_ + sizeof...(Args) * 8 ).process_block_impl(first, last) : process_block_impl(sprout::next(first), last, args..., *first) ; } - template - SPROUT_CONSTEXPR typename std::enable_if< - sizeof...(Args) == 64, - sha1 - >::type process_padding( - Args... args - ) const - { + SPROUT_CONSTEXPR sha1 const process_one() const { return process( - h_, - sprout::make_array(args...), - 64, - byte_count_ + 64 - ).process_padding() - ; + h_, + sprout::fixed::set(block_, block_.begin() + block_byte_index_, static_cast(0x80)), + block_byte_index_ + 1, + bit_count_ + ); } template - SPROUT_CONSTEXPR typename std::enable_if< - sizeof...(Args) != 64, - sha1 - >::type process_padding( - Args... args - ) const - { - return block_byte_index_ + sizeof...(Args) == 56 ? process( + SPROUT_CONSTEXPR sha1 const process_padding_after() const { + return process( + h_, + sprout::array{{}}, + 56, + bit_count_ + ); + } + template + SPROUT_CONSTEXPR sha1 const process_padding() const { + return block_byte_index_ == 56 ? *this + : block_byte_index_ > 56 ? process( h_, - sprout::get_internal(sprout::range::fixed::copy(sprout::make_array(args...), sprout::sub(block_, block_byte_index_))), - block_byte_index_ + sizeof...(Args), - byte_count_ + sizeof...(Args) + sprout::get_internal(sprout::fixed::fill(sprout::sub(block_, block_byte_index_), static_cast(0))), + 64, + bit_count_ + ).process_padding_after() + : process( + h_, + sprout::get_internal(sprout::fixed::fill(sprout::sub(block_, block_byte_index_, 56), static_cast(0))), + 56, + bit_count_ ) - : block_byte_index_ + sizeof...(Args) == 64 ? process( - h_, - sprout::get_internal(sprout::range::fixed::copy(sprout::make_array(args...), sprout::sub(block_, block_byte_index_))), - block_byte_index_ + sizeof...(Args), - byte_count_ + sizeof...(Args) - ).process_padding() - : process_padding(args..., static_cast(0)) ; } - SPROUT_CONSTEXPR sha1 process_append() const { + SPROUT_CONSTEXPR sha1 const process_append() const { return process( h_, sprout::get_internal(sprout::range::fixed::copy( sprout::array{{ - static_cast(0), - static_cast(0), - static_cast(0), - static_cast(0), - static_cast((byte_count_ * 8 >> 24) & 0xFF), - static_cast((byte_count_ * 8 >> 16) & 0xFF), - static_cast((byte_count_ * 8 >> 8) & 0xFF), - static_cast((byte_count_ * 8) & 0xFF) + static_cast((bit_count_ >> 56) & 0xFF), + static_cast((bit_count_ >> 48) & 0xFF), + static_cast((bit_count_ >> 40) & 0xFF), + static_cast((bit_count_ >> 32) & 0xFF), + static_cast((bit_count_ >> 24) & 0xFF), + static_cast((bit_count_ >> 16) & 0xFF), + static_cast((bit_count_ >> 8) & 0xFF), + static_cast(bit_count_ & 0xFF) }}, sprout::sub(block_, block_byte_index_) )), block_byte_index_ + 8, - byte_count_ + 8 + bit_count_ ); } SPROUT_CONSTEXPR value_type make_value() const { @@ -271,38 +268,111 @@ namespace sprout { static_cast((h_[4]) & 0xFF) }}; } + void process_block() { + std::uint32_t w[80]; + for (std::size_t i = 0; i < 16; ++i) { + w[i] = (block_[i * 4 + 0] << 24); + w[i] |= (block_[i * 4 + 1] << 16); + w[i] |= (block_[i * 4 + 2] << 8); + w[i] |= (block_[i * 4 + 3]); + } + for (std::size_t i = 16; i < 80; ++i) { + w[i] = sprout::detail::sha1_left_rotate((w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]), 1); + } + std::uint32_t a = h_[0]; + std::uint32_t b = h_[1]; + std::uint32_t c = h_[2]; + std::uint32_t d = h_[3]; + std::uint32_t e = h_[4]; + for (std::size_t i = 0; i < 80; ++i) { + std::uint32_t f; + std::uint32_t k; + if (i<20) { + f = (b & c) | (~b & d); + k = 0x5A827999; + } else if (i<40) { + f = b ^ c ^ d; + k = 0x6ED9EBA1; + } else if (i<60) { + f = (b & c) | (b & d) | (c & d); + k = 0x8F1BBCDC; + } else { + f = b ^ c ^ d; + k = 0xCA62C1D6; + } + unsigned temp = sprout::detail::sha1_left_rotate(a, 5) + f + e + k + w[i]; + e = d; + d = c; + c = sprout::detail::sha1_left_rotate(b, 30); + b = a; + a = temp; + } + h_[0] += a; + h_[1] += b; + h_[2] += c; + h_[3] += d; + h_[4] += e; + } + void process_byte_impl(unsigned char byte) { + block_[block_byte_index_++] = byte; + if (block_byte_index_ == 64) { + block_byte_index_ = 0; + process_block(); + } + } public: SPROUT_CONSTEXPR sha1() : h_{{0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0}} , block_{{}} , block_byte_index_() - , byte_count_() + , bit_count_() {} - SPROUT_CONSTEXPR sha1 process_byte(std::uint8_t byte) const { + + SPROUT_CONSTEXPR sha1 const process_byte(std::uint8_t byte) const { return process( h_, sprout::fixed::set(block_, block_.begin() + block_byte_index_, byte), block_byte_index_ + 1, - byte_count_ + 1 + bit_count_ + 8 ); } template - SPROUT_CONSTEXPR sha1 process_block(Iterator bytes_begin, Iterator bytes_end) const { + SPROUT_CONSTEXPR sha1 const process_block(Iterator bytes_begin, Iterator bytes_end) const { return process_block_impl( sprout::make_bytes_iterator(bytes_begin), sprout::make_bytes_iterator(bytes_end) ); } template - SPROUT_CONSTEXPR sha1 process_bytes(Iterator buffer, std::size_t byte_count) const { + SPROUT_CONSTEXPR sha1 const process_bytes(Iterator buffer, std::size_t byte_count) const { return process_block(buffer, sprout::next(buffer, byte_count)); } template - SPROUT_CONSTEXPR sha1 process_range(Range const& bytes_range) const { + SPROUT_CONSTEXPR sha1 const process_range(Range const& bytes_range) const { return process_block(sprout::begin(bytes_range), sprout::end(bytes_range)); } + + void process_byte(std::uint8_t byte) { + process_byte_impl(byte); + bit_count_ += 8; + } + template + void process_block(Iterator bytes_begin, Iterator bytes_end) { + for(; bytes_begin != bytes_end; ++bytes_begin) { + process_byte(*bytes_begin); + } + } + template + void process_bytes(Iterator buffer, std::size_t byte_count) { + process_block(buffer, sprout::next(buffer, byte_count)); + } + template + void process_range(Range const& bytes_range) { + process_block(sprout::begin(bytes_range), sprout::end(bytes_range)); + } + SPROUT_CONSTEXPR value_type checksum() const { - return process_byte(0x80).process_padding().process_append().make_value(); + return process_one().process_padding().process_append().make_value(); } SPROUT_CONSTEXPR value_type operator()() const { return checksum(); diff --git a/sprout/uuid/name_generator.hpp b/sprout/uuid/name_generator.hpp index 6fdfb6a0..52a85d90 100644 --- a/sprout/uuid/name_generator.hpp +++ b/sprout/uuid/name_generator.hpp @@ -15,6 +15,7 @@ namespace sprout { public: typedef sprout::uuids::uuid result_type; private: + typedef sprout::sha1 const sha1_const_type; typedef typename result_type::value_type value_type; private: sprout::sha1 sha_; @@ -44,10 +45,10 @@ namespace sprout { } public: SPROUT_CONSTEXPR name_generator() - : sha_(sprout::sha1().process_range(sprout::uuids::uuid{{0}})) + : sha_(sha1_const_type().process_range(sprout::uuids::uuid{{0}})) {} explicit SPROUT_CONSTEXPR name_generator(sprout::uuids::uuid const& namespace_uuid) - : sha_(sprout::sha1().process_range(namespace_uuid)) + : sha_(sha1_const_type().process_range(namespace_uuid)) {} template SPROUT_CONSTEXPR result_type operator()(sprout::basic_string const& name) const {