text: #ifndef SPROUT_CHECKSUM_SHA1_HPP
  #define SPROUT_CHECKSUM_SHA1_HPP
  
  #include <cstddef>
  #include <cstdint>
  #include <climits>
  #include <type_traits>
  #include <sprout/config.hpp>
  #include <sprout/array/array.hpp>
  #include <sprout/array/make_array.hpp>
  #include <sprout/sub_array/sub_array.hpp>
  #include <sprout/sub_array/sub.hpp>
  #include <sprout/container/functions.hpp>
  #include <sprout/iterator/operation.hpp>
  #include <sprout/iterator/bytes_iterator.hpp>
  #include <sprout/algorithm/fixed/fill.hpp>
  #include <sprout/range/algorithm/fixed/copy.hpp>
  #include <sprout/operation/fixed/set.hpp>
  #include <sprout/bit/rotate.hpp>
  #ifdef SPROUT_WORKAROUND_NOT_TERMINATE_RECURSIVE_CONSTEXPR_FUNCTION_TEMPLATE
  #	include <sprout/workaround/recursive_function_template.hpp>
  #endif
  
  namespace sprout {
  	static_assert(CHAR_BIT == 8, "CHAR_BIT == 8");
  
  	//
  	// sha1
  	//
  	class sha1 {
  	public:
  		typedef sprout::array<std::uint8_t, 20> value_type;
  		typedef sha1 const const_type;
  	private:
  		sprout::array<std::uint32_t, 5> h_;
  		sprout::array<std::uint8_t, 64> block_;
  		std::size_t block_byte_index_;
  		std::uint64_t bit_count_;
  	private:
  		SPROUT_CONSTEXPR sha1(
  			sprout::array<std::uint32_t, 5> const& h,
  			sprout::array<std::uint8_t, 64> const& block,
  			std::size_t block_byte_index,
  			std::uint64_t bit_count
  			)
  			: h_(h)
  			, block_(block)
  			, block_byte_index_(block_byte_index)
  			, bit_count_(bit_count)
  		{}
  		SPROUT_CONSTEXPR std::uint32_t calc_w(std::size_t i) const {
  			return i < 16
  				? (block_[i * 4] << 24)
  					| (block_[i * 4 + 1] << 16)
  					| (block_[i * 4 + 2] << 8)
  					| (block_[i * 4 + 3])
  				: sprout::left_rotate(
  					calc_w(i - 3) ^ calc_w(i - 8) ^ calc_w(i - 14) ^ calc_w(i - 16),
  					1
  					)
  				;
  		}
  #ifdef SPROUT_WORKAROUND_NOT_TERMINATE_RECURSIVE_CONSTEXPR_FUNCTION_TEMPLATE
  		template<int D = 16, SPROUT_RECURSIVE_FUNCTION_TEMPLATE_CONTINUE(D)>
  		SPROUT_CONSTEXPR sha1 const process(
  			sprout::array<std::uint32_t, 5> const& h,
  			sprout::array<std::uint8_t, 64> const& block,
  			std::size_t block_byte_index,
  			std::uint64_t bit_count
  			) const
  		{
  			return block_byte_index != 64
  				? const_type(h, block, block_byte_index, bit_count)
  				: const_type(h, block, 0, bit_count).process_block<D + 1>()
  				;
  		}
  		template<int D = 16, SPROUT_RECURSIVE_FUNCTION_TEMPLATE_BREAK(D)>
  		SPROUT_CONSTEXPR sha1 const process(
  			sprout::array<std::uint32_t, 5> const& h,
  			sprout::array<std::uint8_t, 64> const& block,
  			std::size_t block_byte_index,
  			std::uint64_t bit_count
  			) const
  		{
  			return sprout::throw_recursive_function_template_instantiation_exeeded();
  		}
  		template<int D, SPROUT_RECURSIVE_FUNCTION_TEMPLATE_CONTINUE(D)>
  		SPROUT_CONSTEXPR sha1 const process_block_2(
  			std::uint32_t a, std::uint32_t b, std::uint32_t c, std::uint32_t d, std::uint32_t e,
  			std::size_t i, std::uint32_t f, std::uint32_t k
  			) const
  		{
  			return process_block_1<D + 1>(
  				sprout::left_rotate(a, 5) + f + e + k + calc_w(i),
  				a,
  				sprout::left_rotate(b, 30),
  				c,
  				d,
  				i + 1
  				);
  		}
  		template<int D, SPROUT_RECURSIVE_FUNCTION_TEMPLATE_BREAK(D)>
  		SPROUT_CONSTEXPR sha1 const process_block_2(
  			std::uint32_t a, std::uint32_t b, std::uint32_t c, std::uint32_t d, std::uint32_t e,
  			std::size_t i, std::uint32_t f, std::uint32_t k
  			) const
  		{
  			return sprout::throw_recursive_function_template_instantiation_exeeded();
  		}
  		template<int D, SPROUT_RECURSIVE_FUNCTION_TEMPLATE_CONTINUE(D)>
  		SPROUT_CONSTEXPR sha1 const process_block_1(
  			std::uint32_t a, std::uint32_t b, std::uint32_t c, std::uint32_t d, std::uint32_t e,
  			std::size_t i = 0
  			) const
  		{
  			return i < 80
  				? process_block_2<D + 1>(
  					a, b, c, d, e,
  					i,
  					i < 20 ? (b & c) | (~b & d)
  						: i < 40 ? b ^ c ^ d
  						: i < 60 ? (b & c) | (b & d) | (c & d)
  						: b ^ c ^ d
  						,
  					i < 20 ? 0x5A827999
  						: i < 40 ? 0x6ED9EBA1
  						: i < 60 ? 0x8F1BBCDC
  						: 0xCA62C1D6
  					)
  				: sha1(
  					sprout::array<std::uint32_t, 5>{{h_[0] + a, h_[1] + b, h_[2] + c, h_[3] + d, h_[4] + e}},
  					block_,
  					block_byte_index_,
  					bit_count_
  					)
  				;
  		}
  		template<int D, SPROUT_RECURSIVE_FUNCTION_TEMPLATE_BREAK(D)>
  		SPROUT_CONSTEXPR sha1 const process_block_1(
  			std::uint32_t a, std::uint32_t b, std::uint32_t c, std::uint32_t d, std::uint32_t e,
  			std::size_t i = 0
  			) const
  		{
  			return sprout::throw_recursive_function_template_instantiation_exeeded();
  		}
  		template<int D, SPROUT_RECURSIVE_FUNCTION_TEMPLATE_CONTINUE(D)>
  		SPROUT_CONSTEXPR sha1 const process_block() const {
  			return process_block_1<D + 1>(h_[0], h_[1], h_[2], h_[3], h_[4]);
  		}
  		template<int D, SPROUT_RECURSIVE_FUNCTION_TEMPLATE_BREAK(D)>
  		SPROUT_CONSTEXPR sha1 const process_block() const {
  			return sprout::throw_recursive_function_template_instantiation_exeeded();
  		}
  		template<int D = 16, typename Iterator, typename... Args, SPROUT_RECURSIVE_FUNCTION_TEMPLATE_CONTINUE(D)>
  		SPROUT_CONSTEXPR typename std::enable_if<sizeof...(Args) == 64, sha1 const>::type
  		process_block_impl(Iterator first, Iterator last, Args... args) const {
  			return first == last ? process<D + 1>(
  					h_,
  					sprout::make_array<std::uint8_t>(args...),
  					64,
  					bit_count_ + 64 * 8
  					)
  				: /*process<D + 1>(
  					h_,
  					sprout::make_array<std::uint8_t>(args...),
  					64,
  					bit_count_ + 64 * 8
  					).template process_block_impl<D + 1>(first, last)*/ sprout::throw_recursive_function_template_instantiation_exeeded()
  				;
  		}
  		template<int D = 16, typename Iterator, typename... Args, SPROUT_RECURSIVE_FUNCTION_TEMPLATE_BREAK(D)>
  		SPROUT_CONSTEXPR typename std::enable_if<sizeof...(Args) == 64, sha1 const>::type
  		process_block_impl(Iterator first, Iterator last, Args... args) const {
  			return sprout::throw_recursive_function_template_instantiation_exeeded();
  		}
  		template<int D = 16, typename Iterator, typename... Args, SPROUT_RECURSIVE_FUNCTION_TEMPLATE_CONTINUE(D)>
  		SPROUT_CONSTEXPR typename std::enable_if<sizeof...(Args) != 64, sha1 const>::type
  		process_block_impl(Iterator first, Iterator last, Args... args) const {
  			return first == last ? process<D + 1>(
  					h_,
  					sprout::get_internal(sprout::range::fixed::copy(sprout::make_array<std::uint8_t>(args...), sprout::sub(block_, block_byte_index_))),
  					block_byte_index_ + sizeof...(Args),
  					bit_count_ + sizeof...(Args) * 8
  					)
  				: block_byte_index_ + sizeof...(Args) == 64 ? /*process<D + 1>(
  					h_,
  					sprout::get_internal(sprout::range::fixed::copy(sprout::make_array<std::uint8_t>(args...), sprout::sub(block_, block_byte_index_))),
  					block_byte_index_ + sizeof...(Args),
  					bit_count_ + sizeof...(Args) * 8
  					).template process_block_impl<D + 1>(first, last)*/ sprout::throw_recursive_function_template_instantiation_exeeded()
  				: process_block_impl<D + 1>(sprout::next(first), last, args..., *first)
  				;
  		}
  		template<int D = 16, typename Iterator, typename... Args, SPROUT_RECURSIVE_FUNCTION_TEMPLATE_BREAK(D)>
  		SPROUT_CONSTEXPR typename std::enable_if<sizeof...(Args) != 64, sha1 const>::type
  		process_block_impl(Iterator first, Iterator last, Args... args) const {
  			return sprout::throw_recursive_function_template_instantiation_exeeded();
  		}
  #else
  		SPROUT_CONSTEXPR sha1 const process(
  			sprout::array<std::uint32_t, 5> const& h,
  			sprout::array<std::uint8_t, 64> const& block,
  			std::size_t block_byte_index,
  			std::uint64_t bit_count
  			) const
  		{
  			return block_byte_index != 64
  				? const_type(h, block, block_byte_index, bit_count)
  				: const_type(h, block, 0, bit_count).process_block()
  				;
  		}
  		SPROUT_CONSTEXPR sha1 const process_block_2(
  			std::uint32_t a, std::uint32_t b, std::uint32_t c, std::uint32_t d, std::uint32_t e,
  			std::size_t i, std::uint32_t f, std::uint32_t k
  			) const
  		{
  			return process_block_1(
  				sprout::left_rotate(a, 5) + f + e + k + calc_w(i),
  				a,
  				sprout::left_rotate(b, 30),
  				c,
  				d,
  				i + 1
  				);
  		}
  		SPROUT_CONSTEXPR sha1 const process_block_1(
  			std::uint32_t a, std::uint32_t b, std::uint32_t c, std::uint32_t d, std::uint32_t e,
  			std::size_t i = 0
  			) const
  		{
  			return i < 80
  				? process_block_2(
  					a, b, c, d, e,
  					i,
  					i < 20 ? (b & c) | (~b & d)
  						: i < 40 ? b ^ c ^ d
  						: i < 60 ? (b & c) | (b & d) | (c & d)
  						: b ^ c ^ d
  						,
  					i < 20 ? 0x5A827999
  						: i < 40 ? 0x6ED9EBA1
  						: i < 60 ? 0x8F1BBCDC
  						: 0xCA62C1D6
  					)
  				: sha1(
  					sprout::array<std::uint32_t, 5>{{h_[0] + a, h_[1] + b, h_[2] + c, h_[3] + d, h_[4] + e}},
  					block_,
  					block_byte_index_,
  					bit_count_
  					)
  				;
  		}
  		SPROUT_CONSTEXPR sha1 const process_block() const {
  			return process_block_1(h_[0], h_[1], h_[2], h_[3], h_[4]);
  		}
  		template<typename Iterator, typename... Args>
  		SPROUT_CONSTEXPR typename std::enable_if<sizeof...(Args) == 64, sha1 const>::type
  		process_block_impl(Iterator first, Iterator last, Args... args) const {
  			return first == last ? process(
  					h_,
  					sprout::make_array<std::uint8_t>(args...),
  					64,
  					bit_count_ + 64 * 8
  					)
  				: process(
  					h_,
  					sprout::make_array<std::uint8_t>(args...),
  					64,
  					bit_count_ + 64 * 8
  					).process_block_impl(first, last)
  				;
  		}
  		template<typename Iterator, typename... Args>
  		SPROUT_CONSTEXPR typename std::enable_if<sizeof...(Args) != 64, sha1 const>::type
  		process_block_impl(Iterator first, Iterator last, Args... args) const {
  			return first == last ? process(
  					h_,
  					sprout::get_internal(sprout::range::fixed::copy(sprout::make_array<std::uint8_t>(args...), sprout::sub(block_, block_byte_index_))),
  					block_byte_index_ + 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<std::uint8_t>(args...), sprout::sub(block_, block_byte_index_))),
  					block_byte_index_ + sizeof...(Args),
  					bit_count_ + sizeof...(Args) * 8
  					).process_block_impl(first, last)
  				: process_block_impl(sprout::next(first), last, args..., *first)
  				;
  		}
  #endif
  		SPROUT_CONSTEXPR sha1 const process_one() const {
  			return process(
  				h_,
  				sprout::fixed::set(block_, block_.begin() + block_byte_index_, static_cast<std::uint8_t>(0x80)),
  				block_byte_index_ + 1,
  				bit_count_
  				);
  		}
  		template<typename... Args>
  		SPROUT_CONSTEXPR sha1 const process_padding_after() const {
  			return process(
  				h_,
  				sprout::array<std::uint8_t, 64>{{}},
  				56,
  				bit_count_
  				);
  		}
  		template<typename... Args>
  		SPROUT_CONSTEXPR sha1 const process_padding() const {
  			return block_byte_index_ == 56 ? *this
  				: block_byte_index_ > 56 ? process(
  					h_,
  					sprout::get_internal(sprout::fixed::fill(sprout::sub(block_, block_byte_index_), static_cast<std::uint8_t>(0))),
  					64,
  					bit_count_
  					).process_padding_after()
  				: process(
  					h_,
  					sprout::get_internal(sprout::fixed::fill(sprout::sub(block_, block_byte_index_, 56), static_cast<std::uint8_t>(0))),
  					56,
  					bit_count_
  					)
  				;
  		}
  		SPROUT_CONSTEXPR sha1 const process_length() const {
  			return process(
  				h_,
  				sprout::get_internal(sprout::range::fixed::copy(
  					sprout::array<std::uint8_t, 8>{{
  						static_cast<std::uint8_t>((bit_count_ >> 56) & 0xFF),
  						static_cast<std::uint8_t>((bit_count_ >> 48) & 0xFF),
  						static_cast<std::uint8_t>((bit_count_ >> 40) & 0xFF),
  						static_cast<std::uint8_t>((bit_count_ >> 32) & 0xFF),
  						static_cast<std::uint8_t>((bit_count_ >> 24) & 0xFF),
  						static_cast<std::uint8_t>((bit_count_ >> 16) & 0xFF),
  						static_cast<std::uint8_t>((bit_count_ >> 8) & 0xFF),
  						static_cast<std::uint8_t>(bit_count_ & 0xFF)
  						}},
  					sprout::sub(block_, block_byte_index_)
  					)),
  				block_byte_index_ + 8,
  				bit_count_
  				);
  		}
  		SPROUT_CONSTEXPR value_type make_value() const {
  			return value_type{{
  				static_cast<std::uint8_t>((h_[0] >> 24) & 0xFF),
  				static_cast<std::uint8_t>((h_[0] >> 16) & 0xFF),
  				static_cast<std::uint8_t>((h_[0] >> 8) & 0xFF),
  				static_cast<std::uint8_t>((h_[0]) & 0xFF),
  				static_cast<std::uint8_t>((h_[1] >> 24) & 0xFF),
  				static_cast<std::uint8_t>((h_[1] >> 16) & 0xFF),
  				static_cast<std::uint8_t>((h_[1] >> 8) & 0xFF),
  				static_cast<std::uint8_t>((h_[1]) & 0xFF),
  				static_cast<std::uint8_t>((h_[2] >> 24) & 0xFF),
  				static_cast<std::uint8_t>((h_[2] >> 16) & 0xFF),
  				static_cast<std::uint8_t>((h_[2] >> 8) & 0xFF),
  				static_cast<std::uint8_t>((h_[2]) & 0xFF),
  				static_cast<std::uint8_t>((h_[3] >> 24) & 0xFF),
  				static_cast<std::uint8_t>((h_[3] >> 16) & 0xFF),
  				static_cast<std::uint8_t>((h_[3] >> 8) & 0xFF),
  				static_cast<std::uint8_t>((h_[3]) & 0xFF),
  				static_cast<std::uint8_t>((h_[4] >> 24) & 0xFF),
  				static_cast<std::uint8_t>((h_[4] >> 16) & 0xFF),
  				static_cast<std::uint8_t>((h_[4] >> 8) & 0xFF),
  				static_cast<std::uint8_t>((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::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::left_rotate(a, 5) + f + e + k + w[i];
  				e = d;
  				d = c;
  				c = sprout::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();
  			}
  		}
  		template<typename Iterator>
  		void process_block_impl(Iterator first, Iterator last) {
  			for(; first != last; ++first) {
  				process_byte(*first);
  			}
  		}
  	public:
  		SPROUT_CONSTEXPR sha1()
  			: h_{{0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0}}
  			, block_{{}}
  			, block_byte_index_()
  			, bit_count_()
  		{}
  		void reset() {
  			h_[0] = 0x67452301;
  			h_[1] = 0xEFCDAB89;
  			h_[2] = 0x98BADCFE;
  			h_[3] = 0x10325476;
  			h_[4] = 0xC3D2E1F0;
  			block_byte_index_ = 0;
  			bit_count_ = 0;
  		}
  
  		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,
  				bit_count_ + 8
  				);
  		}
  		template<typename Iterator>
  		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<typename Iterator>
  		SPROUT_CONSTEXPR sha1 const process_bytes(Iterator buffer, std::size_t byte_count) const {
  			return process_block(buffer, sprout::next(buffer, byte_count));
  		}
  		template<typename Range>
  		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<typename Iterator>
  		void process_block(Iterator bytes_begin, Iterator bytes_end) {
  			process_block_impl(
  				sprout::make_bytes_iterator(bytes_begin),
  				sprout::make_bytes_iterator(bytes_end)
  				);
  		}
  		template<typename Iterator>
  		void process_bytes(Iterator buffer, std::size_t byte_count) {
  			process_block(buffer, sprout::next(buffer, byte_count));
  		}
  		template<typename Range>
  		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_one().process_padding().process_length().make_value();
  		}
  		SPROUT_CONSTEXPR value_type operator()() const {
  			return checksum();
  		}
  	};
  }	// namespace sprout
  
  #endif	// #ifndef SPROUT_CHECKSUM_SHA1_HPP
  