diff --git a/CMakeLists.txt b/CMakeLists.txt index 229dc946..b929e77c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -241,8 +241,6 @@ list ( geom/tri.hpp hash.hpp hash/fwd.hpp - hash/simple.hpp - hash/simple.cpp hash/adler.cpp hash/adler.hpp hash/bsdsum.cpp @@ -259,8 +257,6 @@ list ( hash/hmac.hpp hash/hotp.cpp hash/hotp.hpp - hash/keccak.cpp - hash/keccak.hpp hash/md2.cpp hash/md2.hpp hash/md4.cpp @@ -276,10 +272,6 @@ list ( hash/murmur/murmur2.hpp hash/murmur/murmur3.cpp hash/murmur/murmur3.hpp - hash/pbkdf1.cpp - hash/pbkdf1.hpp - hash/pbkdf2.cpp - hash/pbkdf2.hpp hash/ripemd.cpp hash/ripemd.hpp hash/sha1.cpp @@ -287,7 +279,6 @@ list ( hash/sha2.cpp hash/sha2.hpp hash/wang.hpp - hash/wang.ipp hash/xxhash.cpp hash/xxhash.hpp introspection.cpp @@ -509,9 +500,9 @@ if (TESTS) hash/checksum hash/crc hash/fasthash + hash/fnv1a hash/hmac hash/hotp - hash/keccak hash/md2 hash/md4 hash/md5 diff --git a/hash.hpp b/hash.hpp index 2d625b3b..8025707f 100644 --- a/hash.hpp +++ b/hash.hpp @@ -23,8 +23,18 @@ #include namespace util::hash { - constexpr std::uint32_t mix (std::uint32_t a, std::uint32_t b) { return murmur2::mix (a, b); } - constexpr std::uint64_t mix (std::uint64_t a, std::uint64_t b) { return murmur2::mix (a, b); } + constexpr std::uint32_t + mix (std::uint32_t a, std::uint32_t b) + { + return murmur2::mix (a, b); + } + + + constexpr std::uint64_t + mix (std::uint64_t a, std::uint64_t b) + { + return murmur2::mix (a, b); + } } #endif diff --git a/hash/adler.cpp b/hash/adler.cpp index d9f93dbe..6dceafb2 100644 --- a/hash/adler.cpp +++ b/hash/adler.cpp @@ -16,9 +16,6 @@ #include "adler.hpp" -#include "fletcher.hpp" -#include "../debug.hpp" - static constexpr unsigned MODULUS = 65521; using util::hash::adler32; @@ -29,21 +26,3 @@ adler32::adler32 (): fletcher (MODULUS, 1, 0) { ; } - -///////////////////////////////////////////////////////////////////////////////// -//uint32_t -//util::hash::adler32 (const void* restrict _data, size_t _size) noexcept -//{ -// return adler32 ( -// static_cast (_data), -// static_cast (_data) + _size -// ); -//} -// -// -////----------------------------------------------------------------------------- -//uint32_t -//util::hash::adler32 (const uint8_t *restrict first, const uint8_t *restrict last) noexcept -//{ -// return fletcher<32, MODULUS, 1, 0> (first, last - first); -//} diff --git a/hash/bsdsum.cpp b/hash/bsdsum.cpp index f38258f1..d58374a6 100644 --- a/hash/bsdsum.cpp +++ b/hash/bsdsum.cpp @@ -11,67 +11,24 @@ * See the License for the specific language governing permissions and * limitations under the License. * - * Copyright 2010 Danny Robson + * Copyright 2010-2018 Danny Robson */ #include "bsdsum.hpp" -#include "../debug.hpp" +#include "../bitwise.hpp" using util::hash::bsdsum; /////////////////////////////////////////////////////////////////////////////// -bsdsum::bsdsum () -{ - reset (); -} - - -//----------------------------------------------------------------------------- -void -bsdsum::reset (void) -{ - m_accum = 0; -} - - -/////////////////////////////////////////////////////////////////////////////// -void -bsdsum::update (const void *restrict data, size_t size) noexcept -{ - auto first = static_cast (data); - - update (first, first + size); -} - - -/////////////////////////////////////////////////////////////////////////////// -void -bsdsum::update (const uint8_t *const restrict first, - const uint8_t *const restrict last) noexcept -{ - CHECK (first); - CHECK (last); - CHECK_LE (first, last); - - for (auto cursor = first; cursor != last; ++cursor) { - m_accum = (m_accum >> 1u) | ((m_accum & 0x01u) << 15u); - m_accum += *cursor; - } -} - - -//----------------------------------------------------------------------------- -void -bsdsum::finish (void) -{ ; } - - - -//----------------------------------------------------------------------------- typename bsdsum::digest_t -bsdsum::digest (void) const +bsdsum::operator() (util::view data) const noexcept { - return m_accum; + digest_t accum = 0; + + for (const auto i: data) + accum = util::rotater (accum, 1) + i; + + return accum; } diff --git a/hash/bsdsum.hpp b/hash/bsdsum.hpp index 871943a0..a1a4d96c 100644 --- a/hash/bsdsum.hpp +++ b/hash/bsdsum.hpp @@ -11,11 +11,13 @@ * See the License for the specific language governing permissions and * limitations under the License. * - * Copyright 2011 Danny Robson + * Copyright 2011-2018 Danny Robson */ -#ifndef __UTIL_HASH_BSDSUM_HPP -#define __UTIL_HASH_BSDSUM_HPP +#ifndef CRUFT_UTIL_HASH_BSDSUM_HPP +#define CRUFT_UTIL_HASH_BSDSUM_HPP + +#include "../view.hpp" #include #include @@ -27,18 +29,7 @@ namespace util::hash { public: using digest_t = uint16_t; - bsdsum (void); - void reset (void); - - void update (const void *restrict data, size_t bytes) noexcept; - void update (const uint8_t *restrict first, const uint8_t *restrict last) noexcept; - - void finish (void); - - digest_t digest (void) const; - - private: - digest_t m_accum; + digest_t operator() (util::view) const noexcept; }; } diff --git a/hash/crc.cpp b/hash/crc.cpp index ebefc88b..4567f99e 100644 --- a/hash/crc.cpp +++ b/hash/crc.cpp @@ -48,112 +48,23 @@ template < bool ReflectIn, bool ReflectOut > +typename crc::digest_t crc< DigestT,Generator,Initial,Final,ReflectIn,ReflectOut ->::crc () noexcept +>::operator() (const util::view data) const noexcept { - reset (); -} + auto accum = Initial; - -//----------------------------------------------------------------------------- -template < - typename DigestT, - DigestT Generator, - DigestT Initial, - DigestT Final, - bool ReflectIn, - bool ReflectOut -> -void -crc< - DigestT,Generator,Initial,Final,ReflectIn,ReflectOut ->::reset (void) noexcept -{ - m_digest = Initial; -} - - -/////////////////////////////////////////////////////////////////////////////// -template < - typename DigestT, - DigestT Generator, - DigestT Initial, - DigestT Final, - bool ReflectIn, - bool ReflectOut -> -void -crc< - DigestT,Generator,Initial,Final,ReflectIn,ReflectOut ->::update (const uint8_t *restrict first, - const uint8_t *restrict last) noexcept -{ - CHECK_LE (first, last); - - for (auto cursor = first; cursor != last; ++cursor) { + for (auto i: data) { if (ReflectIn) - m_digest = s_table[*cursor ^ (m_digest & 0xFFu)] ^ (m_digest >> 8u); + accum = s_table[i ^ (accum & 0xFFu)] ^ (accum >> 8u); else { constexpr auto shift = sizeof (DigestT) * 8u - 8u; - m_digest = (m_digest << 8u) ^ s_table[(m_digest >> shift) ^ *cursor]; + accum = (accum << 8u) ^ s_table[(accum >> shift) ^ i]; } } -} - -//----------------------------------------------------------------------------- -template < - typename DigestT, - DigestT Generator, - DigestT Initial, - DigestT Final, - bool ReflectIn, - bool ReflectOut -> -void -crc< - DigestT,Generator,Initial,Final,ReflectIn,ReflectOut ->::update (const void *restrict _data, size_t len) noexcept -{ - auto data = reinterpret_cast (_data); - return update(data, data + len); -} - - -//----------------------------------------------------------------------------- -template < - typename DigestT, - DigestT Generator, - DigestT Initial, - DigestT Final, - bool ReflectIn, - bool ReflectOut -> -void -crc< - DigestT,Generator,Initial,Final,ReflectIn,ReflectOut ->::finish (void) -{ - ; -} - - -//----------------------------------------------------------------------------- -template < - typename DigestT, - DigestT Generator, - DigestT Initial, - DigestT Final, - bool ReflectIn, - bool ReflectOut -> -DigestT -crc< - DigestT,Generator,Initial,Final,ReflectIn,ReflectOut ->::digest (void) const -{ - return (ReflectIn != ReflectOut ? util::reverse (m_digest) : m_digest) ^ Final; + return (ReflectIn != ReflectOut ? util::reverse (accum) : accum) ^ Final; } diff --git a/hash/crc.hpp b/hash/crc.hpp index 5f4cd8ec..ac58938a 100644 --- a/hash/crc.hpp +++ b/hash/crc.hpp @@ -11,11 +11,13 @@ * See the License for the specific language governing permissions and * limitations under the License. * - * Copyright 2011 Danny Robson + * Copyright 2011-2018 Danny Robson */ -#ifndef __UTIL_HASH_CRC_HPP -#define __UTIL_HASH_CRC_HPP +#ifndef CRUFT_UTIL_HASH_CRC_HPP +#define CRUFT_UTIL_HASH_CRC_HPP + +#include "../view.hpp" #include #include @@ -24,7 +26,7 @@ /////////////////////////////////////////////////////////////////////////////// -namespace util { namespace hash { +namespace util::hash { // Implements the crc checksum (from ethernet, png, etc). // // Adapted from the PNG specification (ISO/IEC 15948:2003), appendix D and @@ -37,8 +39,8 @@ namespace util { namespace hash { // ReflectOut: whether to reverse the bits of the digest at finish time // // Note that reflection isn't necessarily explicitly performed at update - // time. Instead we construct the lookup table appropriately to directly - // use the data values directly. + // time. Instead we construct the lookup table appropriately to use the + // data values directly. template < typename DigestT, DigestT Generator, @@ -53,33 +55,23 @@ namespace util { namespace hash { static constexpr auto generator = Generator; - crc () noexcept; - - void reset (void) noexcept; - - void update (const void *restrict data, size_t bytes) noexcept; - void update (const uint8_t *restrict first, const uint8_t *restrict last) noexcept; - - void finish (void); - - digest_t digest (void) const; + digest_t operator() (util::view) const noexcept; static constexpr std::array table (void); private: - digest_t m_digest; - static const std::array s_table; }; + using crc32 = crc; using crc32b = crc; using crc32c = crc; using crc32d = crc; using crc64 = crc; -} } +} #endif diff --git a/hash/fasthash.cpp b/hash/fasthash.cpp index 7270e981..46e09270 100644 --- a/hash/fasthash.cpp +++ b/hash/fasthash.cpp @@ -16,35 +16,26 @@ #include "fasthash.hpp" - -/////////////////////////////////////////////////////////////////////////////// -uint64_t -util::hash::fasthash::mix (uint64_t v) -{ - v ^= v >> 23; - v *= 0x2127599bf4325c37; - v ^= v >> 47; - - return v; -} +using util::hash::fasthash; /////////////////////////////////////////////////////////////////////////////// +template <> uint64_t -util::hash::fasthash::hash64 (const void *restrict data, size_t len, uint64_t seed) +fasthash::operator() (uint64_t seed, const util::view data) const { static const uint64_t m = 0x880355f21e6d1965; - uint64_t result = seed ^ (len * m); + uint64_t result = seed ^ (data.size () * m); - auto cursor = reinterpret_cast (data); - auto last = cursor + len / sizeof (*cursor); + auto cursor = reinterpret_cast (data.begin ()); + auto last = cursor + data.size () / sizeof (*cursor); for (; cursor < last; ++cursor) { result ^= mix (*cursor); result *= m; } - size_t remain = len % sizeof (*cursor); + size_t remain = data.size () % sizeof (*cursor); if (remain) { auto tail = reinterpret_cast (cursor); @@ -61,10 +52,11 @@ util::hash::fasthash::hash64 (const void *restrict data, size_t len, uint64_t se //----------------------------------------------------------------------------- +template <> uint32_t -util::hash::fasthash::hash32 (const void *restrict data, size_t len, uint32_t seed) +fasthash::operator() (uint64_t seed, const util::view data) const { - uint64_t h = hash64 (data, len, seed); + auto h = fasthash {} (seed, data); return (h & 0xffffffff) - (h >> 32); } diff --git a/hash/fasthash.hpp b/hash/fasthash.hpp index a1bca98c..b873aa75 100644 --- a/hash/fasthash.hpp +++ b/hash/fasthash.hpp @@ -17,17 +17,31 @@ #ifndef __UTIL_HASH_FASTHASH_HPP #define __UTIL_HASH_FASTHASH_HPP +#include "../view.hpp" + #include #include -// Zilong Tan's FastHash, via George Marsaglia's "Xorshift RNGs" -namespace util::hash::fasthash { - uint64_t mix (uint64_t); - uint32_t hash32 (const void *restrict data, size_t len, uint32_t seed); - uint64_t hash64 (const void *restrict data, size_t len, uint64_t seed); +// Zilong Tan's FastHash, via George Marsaglia's "Xorshift RNGs" +namespace util::hash { + template + struct fasthash { + using digest_t = ValueT; + + static constexpr + uint64_t mix (uint64_t v) + { + v ^= v >> 23; + v *= 0x2127599bf4325c37; + v ^= v >> 47; + + return v; + } + + + digest_t operator() (uint64_t seed, util::view) const; + }; } #endif - - diff --git a/hash/fletcher.cpp b/hash/fletcher.cpp index e8a05125..4955fd15 100644 --- a/hash/fletcher.cpp +++ b/hash/fletcher.cpp @@ -27,61 +27,24 @@ using util::hash::fletcher; template fletcher::fletcher (part_t _modulus, part_t _a, part_t _b): m_modulus { _modulus }, - m_initial { _a, _b }, - m_state { m_initial } + m_initial { _a, _b } { ; } -//----------------------------------------------------------------------------- -template -void -fletcher::reset (void) -{ - m_state = m_initial; -} - /////////////////////////////////////////////////////////////////////////////// -template -void -fletcher::update (const void *restrict data, size_t size) noexcept +template +typename fletcher::digest_t +fletcher::operator() (util::view data) const noexcept { - CHECK (data); + state_t accum = m_initial; - auto first = static_cast (data); - update (first, first + size); -} - - -//----------------------------------------------------------------------------- -template -void -fletcher::update (const uint8_t *restrict first, const uint8_t *restrict last) noexcept -{ - CHECK (first); - CHECK (last); - CHECK_LE (first, last); - - for (auto cursor = first; cursor < last; ++cursor) { - m_state.a = (m_state.a + *cursor ) % m_modulus; - m_state.b = (m_state.a + m_state.b) % m_modulus; + for (const auto i: data) { + accum.a = (accum.a + i) % m_modulus; + accum.b = (accum.a + accum.b) % m_modulus; } -} - -//----------------------------------------------------------------------------- -template -void -fletcher::finish (void) -{ ; } - - -/////////////////////////////////////////////////////////////////////////////// -template -typename fletcher::digest_t -fletcher::digest (void) const -{ - return (m_state.b << (sizeof (part_t) * 8)) + m_state.a; + return accum.b << (sizeof(part_t) * 8u) | accum.a; } diff --git a/hash/fletcher.hpp b/hash/fletcher.hpp index d232b4a7..3e85d899 100644 --- a/hash/fletcher.hpp +++ b/hash/fletcher.hpp @@ -18,6 +18,7 @@ #define __UTIL_HASH_FLETCHER_HPP #include "../types/bits.hpp" +#include "../view.hpp" #include #include @@ -25,31 +26,24 @@ /////////////////////////////////////////////////////////////////////////////// namespace util::hash { - template + template class fletcher { public: - using digest_t = DIGEST; + using digest_t = DigestT; using part_t = typename bytes_type::uint; fletcher (part_t modulus, part_t a, part_t b); - void update (const void *restrict, size_t) noexcept; - void update (const uint8_t *restrict first, const uint8_t *restrict last) noexcept; - - void finish (void); - digest_t digest (void) const; - - void reset (void); + digest_t + operator() (util::view) const noexcept; private: - const digest_t m_modulus; - struct state_t { part_t a, b; }; + const digest_t m_modulus; const state_t m_initial; - state_t m_state; }; } diff --git a/hash/fnv1a.cpp b/hash/fnv1a.cpp index b662f87e..3e648a1d 100644 --- a/hash/fnv1a.cpp +++ b/hash/fnv1a.cpp @@ -16,6 +16,8 @@ #include "fnv1a.hpp" +using util::hash::fnv1a; + /////////////////////////////////////////////////////////////////////////////// // Prime is, @@ -28,48 +30,41 @@ // // Bias is the FNV-0 hash of "chongo /\\../\\" -template +template struct constants { }; -template <> struct constants<32> { - static constexpr uint32_t PRIME = 16777619u; - static constexpr uint32_t BIAS = 2166136261u; -}; -template <> struct constants<64> { - static constexpr uint64_t PRIME = 1099511628211u; - static constexpr uint64_t BIAS = 14695981039346656037u; +//----------------------------------------------------------------------------- +template <> +struct constants { + static constexpr uint32_t prime = 16777619u; + static constexpr uint32_t bias = 2166136261u; }; //----------------------------------------------------------------------------- -template -T -fnv1a (const void *restrict _data, size_t len) -{ - auto *data = static_cast (_data); - T result = constants::BIAS; +template <> +struct constants { + static constexpr uint64_t prime = 1099511628211u; + static constexpr uint64_t bias = 14695981039346656037u; +}; - for (size_t i = 0; i < len; ++i) { - result ^= data[i]; - result *= constants::PRIME; + +/////////////////////////////////////////////////////////////////////////////// +template +typename fnv1a::digest_t +fnv1a::operator() (const util::view data) const noexcept +{ + auto result = constants::bias; + + for (auto i: data) { + result ^= i; + result *= constants::prime; } return result; } -/////////////////////////////////////////////////////////////////////////////// -uint32_t -util::hash::fnv1a32 (const void *data, size_t len) -{ - return fnv1a (data, len); -} - - -//----------------------------------------------------------------------------- -uint64_t -util::hash::fnv1a64 (const void *data, size_t len) -{ - return fnv1a (data, len); -} +template struct util::hash::fnv1a; +template struct util::hash::fnv1a; diff --git a/hash/fnv1a.hpp b/hash/fnv1a.hpp index c75e241a..866c6b31 100644 --- a/hash/fnv1a.hpp +++ b/hash/fnv1a.hpp @@ -17,13 +17,19 @@ #ifndef __UTIL_HASH_FNV1A_HPP #define __UTIL_HASH_FNV1A_HPP +#include "view.hpp" + #include #include namespace util::hash { // Fast and general hashing using FNV-1a - uint32_t fnv1a32 (const void *restrict, size_t); - uint64_t fnv1a64 (const void *restrict, size_t); + template + struct fnv1a { + using digest_t = DigestT; + + digest_t operator() (util::view) const noexcept; + }; } #endif diff --git a/hash/hmac.cpp b/hash/hmac.cpp index c565d7b6..f118f1c1 100644 --- a/hash/hmac.cpp +++ b/hash/hmac.cpp @@ -16,109 +16,5 @@ #include "hmac.hpp" -#include "../debug.hpp" - -#include using util::hash::HMAC; - - -//----------------------------------------------------------------------------- -static const uint8_t IFILL = 0x36; -static const uint8_t OFILL = 0x5C; - - -//----------------------------------------------------------------------------- -template -HMAC::HMAC (const uint8_t *restrict key, size_t len) -{ - CHECK (key); - - static_assert (sizeof (m_ikey) == sizeof (m_okey), "key padding must match"); - - // If the key is larger than the blocklength, use the hash of the key - if (len > T::BLOCK_SIZE) { - m_hash.update (key, len); - m_hash.finish (); - - auto d = m_hash.digest (); - m_hash.reset (); - - std::copy (d.begin (), d.end (), m_ikey.begin ()); - len = d.size (); - // Use the key directly - } else { - std::copy (key, key + len, m_ikey.begin ()); - } - - std::fill (m_ikey.begin () + len, - m_ikey.end (), - 0); - - m_okey = m_ikey; - - std::transform (m_ikey.begin (), - m_ikey.end (), - m_ikey.begin (), - [] (auto v) { return v ^ IFILL; }); - - std::transform (m_okey.begin (), - m_okey.end (), - m_okey.begin (), - [] (auto v) { return v ^ OFILL; }); - - m_hash.update (m_ikey.data (), m_ikey.size ()); -} - - -//----------------------------------------------------------------------------- -template -void -HMAC::update (const void *restrict data, size_t len) -{ - m_hash.update ((const uint8_t*)data, len); -} - - -//----------------------------------------------------------------------------- -template -void -HMAC::finish (void) -{ - m_hash.finish (); - auto d = m_hash.digest (); - - m_hash.reset (); - m_hash.update (m_okey.data (), m_okey.size ()); - m_hash.update (d.data (), d.size ()); - m_hash.finish (); -} - - -//----------------------------------------------------------------------------- -template -void -HMAC::reset (void) -{ - m_hash.reset (); - m_hash.update (m_ikey.data (), m_ikey.size ()); -} - - -//----------------------------------------------------------------------------- -template -typename HMAC::digest_t -HMAC::digest (void) -{ - return m_hash.digest (); -} - - -//----------------------------------------------------------------------------- -#include "md5.hpp" -#include "sha1.hpp" - -namespace util::hash { - template class HMAC; - template class HMAC; -} diff --git a/hash/hmac.hpp b/hash/hmac.hpp index 23e49b8e..541e88d5 100644 --- a/hash/hmac.hpp +++ b/hash/hmac.hpp @@ -14,33 +14,75 @@ * Copyright 2015 Danny Robson */ -#ifndef __UTIL_HASH_HMAC_HPP -#define __UTIL_HASH_HMAC_HPP +#ifndef CRUFT_UTIL_HASH_HMAC_HPP +#define CRUFT_UTIL_HASH_HMAC_HPP + +#include "../debug.hpp" +#include "../view.hpp" + +#include +#include -#include -#include -#include namespace util::hash { - template + template /// RFC 2104 key-hashing for message authentication class HMAC { public: - using digest_t = typename T::digest_t; + using digest_t = typename HashT::digest_t; - HMAC (const uint8_t *key, size_t); - void update (const void *restrict, size_t); - void finish (void); - void reset (void); + //--------------------------------------------------------------------- + HMAC (util::view key) + { + CHECK (!key.empty ()); + + static_assert (sizeof (m_ikey) == sizeof (m_okey), "key padding must match"); + + // If the key is larger than the blocklength, use the hash of the key + if (key.size () > HashT::BLOCK_SIZE) { + auto d = HashT{} (key); + auto tail = std::copy (d.begin (), d.end (), m_ikey.begin ()); + std::fill (tail, std::end (m_ikey), 0); + // Use the key directly + } else { + auto tail = std::copy (key.begin (), key.end (), m_ikey.begin ()); + std::fill (tail, m_ikey.end (), 0); + } + + // copy and xor the key data to the okey + std::transform ( + std::begin (m_ikey), + std::end (m_ikey), + std::begin (m_okey), + [] (auto v) { return v ^ OFILL; }); + + // just xor the ikey in place + std::transform ( + m_ikey.begin (), + m_ikey.end (), + m_ikey.begin (), + [] (auto v) { return v ^ IFILL; }); + } + + + //--------------------------------------------------------------------- + template + digest_t + operator() (DataT&&...data) const noexcept + { + HashT h; + return h (m_okey, h (m_ikey, std::forward (data)...)); + }; - digest_t digest (void); private: - std::array m_ikey; - std::array m_okey; + //--------------------------------------------------------------------- + static constexpr uint8_t IFILL = 0x36; + static constexpr uint8_t OFILL = 0x5C; - T m_hash; + std::array m_ikey; + std::array m_okey; }; } diff --git a/hash/hotp.cpp b/hash/hotp.cpp index 81ac2b0c..2f8e30a8 100644 --- a/hash/hotp.cpp +++ b/hash/hotp.cpp @@ -11,7 +11,7 @@ * See the License for the specific language governing permissions and * limitations under the License. * - * Copyright 2015 Danny Robson + * Copyright 2015-2018 Danny Robson */ #include "hotp.hpp" @@ -23,35 +23,28 @@ using util::hash::HOTP; -//----------------------------------------------------------------------------- -HOTP::HOTP (const char *_key, uint64_t _counter): - HOTP (_key, strlen (_key), _counter) -{ ; } - - -//----------------------------------------------------------------------------- -HOTP::HOTP (const void *_key, size_t _len, uint64_t _counter): +/////////////////////////////////////////////////////////////////////////////// +HOTP::HOTP (util::view _key, uint64_t _counter): m_counter (_counter), - m_hash ((const uint8_t*)_key, _len) + m_hash (_key.template cast ()) { ; } + //----------------------------------------------------------------------------- unsigned HOTP::value (void) { - auto c = htob (m_counter); + union { + uint64_t number; + uint8_t bytes[8]; + }; - m_hash.update (&c, sizeof (c)); - m_hash.finish (); + number = htob (m_counter); - auto h = m_hash.digest (); - auto t = truncate (h); - - m_hash.reset (); + auto res = truncate (m_hash (util::make_cview (bytes))); ++m_counter; - - return t % 1000000; + return res % 1'000'000; } diff --git a/hash/hotp.hpp b/hash/hotp.hpp index 2d9bf406..28b0e152 100644 --- a/hash/hotp.hpp +++ b/hash/hotp.hpp @@ -11,11 +11,13 @@ * See the License for the specific language governing permissions and * limitations under the License. * - * Copyright 2015 Danny Robson + * Copyright 2015-2018 Danny Robson */ -#ifndef __UTIL_HASH_HOTP_HPP -#define __UTIL_HASH_HOTP_HPP +#ifndef CRUFT_UTIL_HASH_HOTP_HPP +#define CRUFT_UTIL_HASH_HOTP_HPP + +#include "../view.hpp" #include "hmac.hpp" #include "sha1.hpp" @@ -26,8 +28,7 @@ namespace util::hash { /// HMAC one-time password (RFC 4226) class HOTP { public: - HOTP (const char *key, uint64_t counter); - HOTP (const void *key, size_t len, uint64_t counter); + HOTP (util::view key, uint64_t counter); unsigned value (void); uint64_t counter (void) const; diff --git a/hash/keccak.cpp b/hash/keccak.cpp deleted file mode 100644 index c0936fec..00000000 --- a/hash/keccak.cpp +++ /dev/null @@ -1,484 +0,0 @@ -#include "keccak.hpp" - -#include "../endian.hpp" -#include "../maths.hpp" -#include "../bitwise.hpp" - -#include -#include -#include -#include -#include - -#if 0 -#define FOR(i,n) for(i=0; i>1; } -#define ROL(a,o) ((((u64)a)<>(64-o))) -static u64 load64(const u8 *x) { ui i; u64 u=0; FOR(i,8) { u<<=8; u|=x[7-i]; } return u; } -static void store64(u8 *x, u64 u) { ui i; FOR(i,8) { x[i]=u; u>>=8; } } -static void xor64(u8 *x, u64 u) { ui i; FOR(i,8) { x[i]^=u; u>>=8; } } -#define rL(x,y) load64((u8*)s+8*(x+5*y)) -#define wL(x,y,l) store64((u8*)s+8*(x+5*y),l) -#define XL(x,y,l) xor64((u8*)s+8*(x+5*y),l) -void KeccakF1600(void *s) -{ - ui r,x,y,i,j,Y; u8 R=0x01; u64 C[5],D; - for(i=0; i<24; i++) { - /*θ*/ FOR(x,5) C[x]=rL(x,0)^rL(x,1)^rL(x,2)^rL(x,3)^rL(x,4); FOR(x,5) { D=C[(x+4)%5]^ROL(C[(x+1)%5],1); FOR(y,5) XL(x,y,D); } - /*ρπ*/ x=1; y=r=0; D=rL(x,y); FOR(j,24) { r+=j+1; Y=(2*x+3*y)%5; x=y; y=Y; C[0]=rL(x,y); wL(x,y,ROL(D,r%64)); D=C[0]; } - /*χ*/ FOR(y,5) { FOR(x,5) C[x]=rL(x,y); FOR(x,5) wL(x,y,C[x]^((~C[(x+1)%5])&C[(x+2)%5])); } - /*ι*/ FOR(j,7) if (LFSR86540(&R)) XL(0,0,(u64)1<<((1<0) { b=(inLen0) { b=(outLen0) KeccakF1600(s); } -} - -#else - -// derived from Keccak (KCP) readable-and-compact C implementation - -/* -Implementation by the Keccak, Keyak and Ketje Teams, namely, Guido Bertoni, -Joan Daemen, Michaël Peeters, Gilles Van Assche and Ronny Van Keer, hereby -denoted as "the implementer". - -For more information, feedback or questions, please refer to our websites: -http://keccak.noekeon.org/ -http://keyak.noekeon.org/ -http://ketje.noekeon.org/ - -To the extent possible under law, the implementer has waived all copyright -and related or neighboring rights to the source code in this file. -http://creativecommons.org/publicdomain/zero/1.0/ -*/ - -/* -================================================================ -The purpose of this source file is to demonstrate a readable and compact -implementation of all the Keccak instances approved in the FIPS 202 standard, -including the hash functions and the extendable-output functions (XOFs). - -We focused on clarity and on source-code compactness, -rather than on the performance. - -The advantages of this implementation are: - + The source code is compact, after removing the comments, that is. :-) - + There are no tables with arbitrary constants. - + For clarity, the comments link the operations to the specifications using - the same notation as much as possible. - + There is no restriction in cryptographic features. In particular, - the SHAKE128 and SHAKE256 XOFs can produce any output length. - + The code does not use much RAM, as all operations are done in place. - -The drawbacks of this implementation are: - - There is no message queue. The whole message must be ready in a buffer. - - It is not optimized for peformance. - -The implementation is even simpler on a little endian platform. Just define the -LITTLE_ENDIAN symbol in that case. - -For a more complete set of implementations, please refer to -the Keccak Code Package at https://github.com/gvanas/KeccakCodePackage - -For more information, please refer to: - * [Keccak Reference] http://keccak.noekeon.org/Keccak-reference-3.0.pdf - * [Keccak Specifications Summary] http://keccak.noekeon.org/specs_summary.html - -This file uses UTF-8 encoding, as some comments use Greek letters. -================================================================ -*/ - -/** - * Function to compute the Keccak[r, c] sponge function over a given input. - * @param rate The value of the rate r. - * @param capacity The value of the capacity c. - * @param input Pointer to the input message. - * @param inputByteLen The number of input bytes provided in the input message. - * @param delimitedSuffix Bits that will be automatically appended to the end - * of the input message, as in domain separation. - * This is a byte containing from 0 to 7 bits - * These n bits must be in the least significant bit positions - * and must be delimited with a bit 1 at position n - * (counting from 0=LSB to 7=MSB) and followed by bits 0 - * from position n+1 to position 7. - * Some examples: - * - If no bits are to be appended, then @a delimitedSuffix must be 0x01. - * - If the 2-bit sequence 0,1 is to be appended (as for SHA3-*), @a delimitedSuffix must be 0x06. - * - If the 4-bit sequence 1,1,1,1 is to be appended (as for SHAKE*), @a delimitedSuffix must be 0x1F. - * - If the 7-bit sequence 1,1,0,1,0,0,0 is to be absorbed, @a delimitedSuffix must be 0x8B. - * @param output Pointer to the buffer where to store the output. - * @param outputByteLen The number of output bytes desired. - * @pre One must have r+c=1600 and the rate a multiple of 8 bits in this implementation. - */ - -/** - * Function to compute SHAKE128 on the input message with any output length. - */ -void -FIPS202_SHAKE128(const uint8_t *input, size_t inputByteLen, uint8_t *output, size_t outputByteLen) -{ - keccak k (1344, 256, 0x1f); - k.update (input, inputByteLen); - k.digest (output, outputByteLen); -} - -/** - * Function to compute SHAKE256 on the input message with any output length. - */ -void FIPS202_SHAKE256(const uint8_t *input, size_t inputByteLen, uint8_t *output, size_t outputByteLen) -{ - keccak k (1088, 512, 0x1f); - k.update (input, inputByteLen); - k.digest (output, outputByteLen); -} - -/** - * Function to compute SHA3-224 on the input message. The output length is fixed to 28 bytes. - */ -void FIPS202_SHA3_224(const uint8_t *input, size_t inputByteLen, uint8_t *output) -{ - keccak k (1152, 448, 0x06); - - for (unsigned int i = 0; i < inputByteLen; ++i) - k.update (&input[i], 1); - //k.update (input, inputByteLen); - k.digest (output, 28); -} - -/** - * Function to compute SHA3-256 on the input message. The output length is fixed to 32 bytes. - */ -void FIPS202_SHA3_256(const uint8_t *input, size_t inputByteLen, uint8_t *output) -{ - keccak k (1088, 512, 0x06); - k.update (input, inputByteLen); - k.digest (output, 32); -} - -/** - * Function to compute SHA3-384 on the input message. The output length is fixed to 48 bytes. - */ -void FIPS202_SHA3_384(const uint8_t *input, size_t inputByteLen, uint8_t *output) -{ - keccak k (832, 768, 0x06); - k.update (input, inputByteLen); - k.digest (output, 48); -} - -/** - * Function to compute SHA3-512 on the input message. The output length is fixed to 64 bytes. - */ -void FIPS202_SHA3_512(const uint8_t *input, size_t inputByteLen, uint8_t *output) -{ - keccak k (576, 1024, 0x06); - k.update (input, inputByteLen); - k.digest (output, 64); -} - - -/* -================================================================ -A readable and compact implementation of the Keccak-f[1600] permutation. -================================================================ -*/ - -//static constexpr -//size_t -//i (size_t x, size_t y) -//{ -// return x + 5 * y; -//} - - -/** - * Function that computes the linear feedback shift register (LFSR) used to - * define the round constants (see [Keccak Reference, Section 1.2]). - */ -class lfsr86540 { -public: - lfsr86540 (): - value (0x1) - { ; } - - - bool - update (void) - { - bool result = value & 0x01; - if (value & 0x80) - // Primitive polynomial over GF(2): x^8+x^6+x^5+x^4+1 - value = (value << 1) ^ 0x71; - else - value <<= 1; - return result; - } - - -private: - uint8_t value; -}; - - -// θ step, see [Keccak Reference, Section 2.3.2] -static void -permute_theta (uint64_t m_words[5][5]) -{ - uint64_t C[5], D; - - // Compute the parity of the columns - for (unsigned x = 0; x < 5; ++x) - C[x] = m_words[0][x] ^ m_words[1][x] ^ m_words[2][x] ^ m_words[3][x] ^ m_words[4][x]; - - for (unsigned x = 0; x < 5; ++x) { - // Compute the θ effect for a given column - D = C[(x+4)%5] ^ util::rotatel (C[(x+1)%5], 1); - - // Add the θ effect to the whole column - for (unsigned y = 0; y < 5; ++y) - m_words[y][x] ^= D; - } -} - - -void -permute_rho (uint64_t m_words[5][5]) -{ - m_words[0][1] = util::rotatel (m_words[0][1], 1); - m_words[0][2] = util::rotatel (m_words[0][2], 62); - m_words[0][3] = util::rotatel (m_words[0][3], 28); - m_words[0][4] = util::rotatel (m_words[0][4], 27); - m_words[1][0] = util::rotatel (m_words[1][0], 36); - m_words[1][1] = util::rotatel (m_words[1][1], 44); - m_words[1][2] = util::rotatel (m_words[1][2], 6); - m_words[1][3] = util::rotatel (m_words[1][3], 55); - m_words[1][4] = util::rotatel (m_words[1][4], 20); - m_words[2][0] = util::rotatel (m_words[2][0], 3); - m_words[2][1] = util::rotatel (m_words[2][1], 10); - m_words[2][2] = util::rotatel (m_words[2][2], 43); - m_words[2][3] = util::rotatel (m_words[2][3], 25); - m_words[2][4] = util::rotatel (m_words[2][4], 39); - m_words[3][0] = util::rotatel (m_words[3][0], 41); - m_words[3][1] = util::rotatel (m_words[3][1], 45); - m_words[3][2] = util::rotatel (m_words[3][2], 15); - m_words[3][3] = util::rotatel (m_words[3][3], 21); - m_words[3][4] = util::rotatel (m_words[3][4], 8); - m_words[4][0] = util::rotatel (m_words[4][0], 18); - m_words[4][1] = util::rotatel (m_words[4][1], 2); - m_words[4][2] = util::rotatel (m_words[4][2], 61); - m_words[4][3] = util::rotatel (m_words[4][3], 56); - m_words[4][4] = util::rotatel (m_words[4][4], 14); - return; - - - for (size_t i = 1; i < 25; ++i) { - //unsigned r = ((t+1)*(t+2)/2)%64; - unsigned r = ((i + 1) * (i + 2) / 2) % 64; - - m_words[i/5][i%5] = util::rotatel (m_words[i/5][i%5], r); - } -} - - -void -permute_pi (uint64_t m_words[5][5]) -{ - //auto A = reinterpret_cast (m_words); - - //uint64_t A1; - //A1 = A[1]; - //A[ 1] = A[ 6]; - //A[ 6] = A[ 9]; - //A[ 9] = A[22]; - //A[22] = A[14]; - //A[14] = A[20]; - //A[20] = A[ 2]; - //A[ 2] = A[12]; - //A[12] = A[13]; - //A[13] = A[19]; - //A[19] = A[23]; - //A[23] = A[15]; - //A[15] = A[ 4]; - //A[ 4] = A[24]; - //A[24] = A[21]; - //A[21] = A[ 8]; - //A[ 8] = A[16]; - //A[16] = A[ 5]; - //A[ 5] = A[ 3]; - //A[ 3] = A[18]; - //A[18] = A[17]; - //A[17] = A[11]; - //A[11] = A[ 7]; - //A[ 7] = A[10]; - //A[10] = A1; - //return; - - unsigned x = 1, y = 0; - uint64_t current = m_words[y][x]; - uint64_t temp; - // Iterate over ((0 1)(2 3))^t * (1 0) for 0 ≤ t ≤ 23 - for (unsigned t = 0; t < 24; ++t) { - unsigned int Y = (2*x+3*y)%5; - x = y; - y = Y; - - temp = m_words[y][x]; - m_words[y][x] = current; - current = temp; - } - - //for (unsigned int i = 0; i < 5; ++i) - // for (unsigned int j = 0; j < 5; ++j) - // m_words[j][(2*i+3*j)%5] = m_words[i][j]; -} - - -/** - * Function that computes the Keccak-f[1600] permutation on the given state. - */ -void -keccak::permute (void) -{ - for (size_t i = 0; i < m_bitrate/64; ++i) - m_words[i/5][i%5] = util::ltoh (m_words[i/5][i%5]); - - lfsr86540 shift; - - for (unsigned round = 0; round < 24; ++round) { - permute_theta (m_words); - permute_rho (m_words); - permute_pi (m_words); - - - if (0) { // === ρ and π steps (see [Keccak Reference, Sections 2.3.3 and 2.3.4]) === - uint64_t current, temp; - // Start at coordinates (1 0) - unsigned x = 1, y = 0; - current = m_words[y][x]; - // Iterate over ((0 1)(2 3))^t * (1 0) for 0 ≤ t ≤ 23 - for (unsigned t = 0; t < 24; ++t) { - // Compute the rotation constant r = (t+1)(t+2)/2 - unsigned int r = ((t+1)*(t+2)/2)%64; - - // Compute ((0 1)(2 3)) * (x y) - unsigned int Y = (2*x+3*y)%5; x = y; y = Y; - - // Swap current and state(x,y), and rotate - temp = m_words[y][x]; - m_words[y][x] = util::rotatel (current, r); - current = temp; - } - } - - { // === χ step (see [Keccak Reference, Section 2.3.1]) === - uint64_t temp[5]; - for (unsigned y = 0; y < 5; ++y) { - // Take a copy of the plane - for (unsigned x = 0; x < 5; ++x) - temp[x] = m_words[y][x]; - - // Compute χ on the plane - for(unsigned x = 0; x < 5; ++x) - m_words[y][x] = temp[x] ^((~temp[(x+1)%5]) & temp[(x+2)%5]); - } - } - - { // === ι step (see [Keccak Reference, Section 2.3.5]) === - for (unsigned j = 0; j < 7; ++j) { - unsigned int bitPosition = (1 << j) - 1; //2^j-1 - if (shift.update ()) - m_words[0][0] ^= uint64_t{1} << bitPosition; - } - } - } -} - -/* -================================================================ -A readable and compact implementation of the Keccak sponge functions -that use the Keccak-f[1600] permutation. -================================================================ -*/ - - -void -keccak::update ( - const uint8_t *input, - size_t len -) { - unsigned int byterate = m_bitrate / 8; - - while (len) { - auto chunk = util::min (len, byterate - m_cursor); - - for (unsigned i = 0; i < chunk; ++i) - m_bytes[m_cursor++] ^= *input++; - - len -= chunk; - - if (m_cursor == byterate) { - permute (); - m_cursor = 0; - } - } -} - - -void -keccak::digest ( - uint8_t *output, - size_t len -) { - unsigned byterate = m_bitrate / 8u; - - // === Do the padding and switch to the squeezing phase === - // Absorb the last few bits and add the first bit of padding (which - // coincides with the delimiter in delimitedSuffix) - m_bytes[m_cursor] ^= m_suffix; - - // If the first bit of padding is at position rate-1, we need a whole new - // block for the second bit of padding - if (m_suffix & 0x80 && m_cursor == byterate - 1) - permute (); - - // Add the second bit of padding - m_bytes[byterate - 1] ^= 0x80; - - // === Squeeze out all the output blocks === - while (len) { - permute (); - - auto chunk = util::min (len, byterate); - std::copy_n (m_bytes.begin (), chunk, output); - - output += chunk; - len -= chunk; - } -} - - -keccak::keccak (unsigned _bitrate, - unsigned _capacity, - uint8_t _suffix): - m_bitrate (_bitrate), - m_capacity (_capacity), - m_suffix (_suffix), - m_cursor (0) -{ - // we could support bitrates that are multiples of 8, but 64 simplifies - // some state handling, and the SHA-3 constants are all multiples of 64 - // bits anyway. - if ((m_bitrate + m_capacity) / 8 != sizeof (m_bytes) || m_bitrate % 64 != 0) - throw "error"; - - std::fill (std::begin (m_bytes), std::end (m_bytes), 0); -} - - - -#endif diff --git a/hash/keccak.hpp b/hash/keccak.hpp deleted file mode 100644 index 682146d9..00000000 --- a/hash/keccak.hpp +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * Copyright 2016 Danny Robson - */ - -#ifndef __HASH_KECCAK_HPP -#define __HASH_KECCAK_HPP - -#include -#include - -class keccak { -public: - keccak (unsigned bitrate, unsigned capacity, uint8_t suffix); - - void update (const uint8_t *input, size_t len); - void digest (uint8_t *output, size_t len); - -private: - void permute (void); - - const unsigned m_bitrate; - const unsigned m_capacity; - const uint8_t m_suffix; - - size_t m_cursor; - - union { - std::array m_bytes; - uint64_t m_words[5][5]; - }; -}; - - -void FIPS202_SHAKE128(const uint8_t *input, size_t inputByteLen, uint8_t *output, size_t outputByteLen); -void FIPS202_SHAKE256(const uint8_t *input, size_t inputByteLen, uint8_t *output, size_t outputByteLen); -void FIPS202_SHA3_224(const uint8_t *input, size_t inputByteLen, uint8_t *output); -void FIPS202_SHA3_256(const uint8_t *input, size_t inputByteLen, uint8_t *output); -void FIPS202_SHA3_384(const uint8_t *input, size_t inputByteLen, uint8_t *output); -void FIPS202_SHA3_512(const uint8_t *input, size_t inputByteLen, uint8_t *output); - -#endif diff --git a/hash/md2.cpp b/hash/md2.cpp index dcbedfc4..b033e21a 100644 --- a/hash/md2.cpp +++ b/hash/md2.cpp @@ -27,14 +27,9 @@ /////////////////////////////////////////////////////////////////////////////// using util::hash::MD2; -using std::array; -using std::begin; -using std::end; -using std::fill; - /////////////////////////////////////////////////////////////////////////////// -static array S = { { +static constexpr std::array S = { { 41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6, 19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188, 76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24, 138, 23, 229, 18, @@ -54,88 +49,16 @@ static array S = { { } }; -/////////////////////////////////////////////////////////////////////////////// -MD2::MD2 () -{ - reset (); -} - - -//----------------------------------------------------------------------------- -void -MD2::reset (void) -{ - m_total = 0; - fill (begin (C), end (C), 0); - fill (begin (X), end (X), 0); -} - - -/////////////////////////////////////////////////////////////////////////////// -void -MD2::update (const uint8_t *restrict first, const uint8_t *restrict last) noexcept -{ - CHECK_LE (first, last); - - update (first, last - first); -} - - //----------------------------------------------------------------------------- static const size_t M_OFFSET = 16; static const size_t M_LENGTH = 16; -//----------------------------------------------------------------------------- -void -MD2::update (const void *restrict _data, size_t size) noexcept -{ - auto data = static_cast (_data); - - uint8_t *M = X + M_OFFSET; - size_t offset = m_total % M_LENGTH; - size_t remain = M_LENGTH - offset; - - if (size > remain) { - memcpy (M + offset, data, remain); - transform (); - - m_total += remain; - size -= remain; - data += remain; - - while (size >= M_LENGTH) { - memcpy (M, data, M_LENGTH); - transform (); - - m_total += M_LENGTH; - size -= M_LENGTH; - data += M_LENGTH; - } - - offset = 0; - } - - memcpy (M + offset, data, size); - m_total += size; -} - - /////////////////////////////////////////////////////////////////////////////// -MD2::digest_t -MD2::digest (void) const +static void +transform (std::array &C, std::array &X) noexcept { - digest_t d; - memcpy (d.data (), X, sizeof (d)); - return d; -} - - -/////////////////////////////////////////////////////////////////////////////// -void -MD2::transform (void) -{ - uint8_t *M = X + M_OFFSET; + util::view M { X.data () + M_OFFSET, M_LENGTH }; // Update the checksum. // XXX: I can't see why we need the xor-assign from the spec, but it's the @@ -145,16 +68,15 @@ MD2::transform (void) for (size_t i = 0; i < std::size (C); ++i) L = C[i] ^= S[M[i] ^ L]; - uint8_t t = 0; // Setup the blocks for (size_t i = 0; i < 16; ++i) - X[32 + i] = X[16 + i] ^ X[i]; + X[32 + i] = X[16 + i] ^ X[i]; // Perform the processing rounds - for (size_t i = 0; i < 18; ++i) { + for (size_t i = 0, t = 0; i < 18; ++i) { for (size_t j = 0; j < 48; ++j) - t = X[j] = X[j] ^ S[t]; + t = X[j] ^= S[t]; t = (t + i) % 256; } @@ -162,21 +84,40 @@ MD2::transform (void) /////////////////////////////////////////////////////////////////////////////// -void -MD2::finish (void) +MD2::digest_t +MD2::operator() (const util::view data) const noexcept { - uint8_t *M = X + M_OFFSET; + // zero initialise the state vectors, and create a simple window `M' into + // the middle of the `X' state vector. + std::array C {}; + std::array X {}; + const util::view M { std::begin (X) + M_OFFSET, M_LENGTH }; - // Append the padding bytes - size_t offset = m_total % M_LENGTH; - size_t remain = M_LENGTH - offset; + // process each complete block by copying to the window `M' and + // transforming X and C. + // + // leave the remainder of the data in `M' for subsequent padding. + auto remain = data; + while (remain.size () >= M_LENGTH) { + std::copy_n (std::begin (remain), M_LENGTH, std::begin (M)); + transform (C, X); - for (size_t i = 0; i < remain; ++i) - M[offset + i] = remain; - transform (); + remain = { remain.begin () + M_LENGTH, remain.end () }; + }; - // Append the checksum - memcpy (M, C, sizeof (C)); - transform (); + // Copying the remaining data then append the padding bytes. Padding + // _must_ be performed even if we have an evenly divisible input buffer. + auto tail = std::copy (remain.begin (), remain.end (), std::begin (M)); + auto unused = std::distance (tail, std::end (M)); + std::fill (tail, std::end (M), unused); + transform (C, X); + + // Append the checksum and transform once more. + std::copy (std::begin (C), std::end (C), std::begin (M)); + transform (C, X); + + // The final digest is the first `n' bytes of the state vector. + digest_t d; + std::copy_n (std::begin (X), d.size (), std::begin (d)); + return d; } - diff --git a/hash/md2.hpp b/hash/md2.hpp index 2bc2b331..254724a0 100644 --- a/hash/md2.hpp +++ b/hash/md2.hpp @@ -17,6 +17,8 @@ #ifndef __UTIL_HASH_MD2_HPP #define __UTIL_HASH_MD2_HPP +#include "../view.hpp" + #include #include @@ -24,26 +26,11 @@ /////////////////////////////////////////////////////////////////////////////// namespace util::hash { class MD2 { - public: - typedef std::array digest_t; + public: + typedef std::array digest_t; - public: - MD2 (); - - void update (const void *restrict data, size_t len) noexcept; - void update (const uint8_t *restrict first, const uint8_t *restrict last) noexcept; - - void finish (void); - digest_t digest (void) const; - void reset (void); - - private: - void transform (void); - - uint64_t m_total; - - uint8_t C[16]; - uint8_t X[48]; + public: + digest_t operator() (util::view) const noexcept; }; } diff --git a/hash/md4.cpp b/hash/md4.cpp index 4857c51f..eefbf5ca 100644 --- a/hash/md4.cpp +++ b/hash/md4.cpp @@ -27,7 +27,7 @@ using util::hash::MD4; /////////////////////////////////////////////////////////////////////////////// // Auxiliary functions for each set of rounds -static constexpr +static inline constexpr uint32_t F (uint32_t X, uint32_t Y, uint32_t Z) { @@ -36,7 +36,7 @@ F (uint32_t X, uint32_t Y, uint32_t Z) //----------------------------------------------------------------------------- -static constexpr +static inline constexpr uint32_t G (uint32_t X, uint32_t Y, uint32_t Z) { @@ -45,7 +45,7 @@ G (uint32_t X, uint32_t Y, uint32_t Z) //----------------------------------------------------------------------------- -static constexpr +static inline constexpr uint32_t H (uint32_t X, uint32_t Y, uint32_t Z) { @@ -54,105 +54,24 @@ H (uint32_t X, uint32_t Y, uint32_t Z) //----------------------------------------------------------------------------- -static constexpr uint32_t DEFAULT_A = 0x67452301; -static constexpr uint32_t DEFAULT_B = 0xefcdab89; -static constexpr uint32_t DEFAULT_C = 0x98badcfe; -static constexpr uint32_t DEFAULT_D = 0x10325476; +static constexpr uint32_t INITIAL_A = 0x67452301; +static constexpr uint32_t INITIAL_B = 0xefcdab89; +static constexpr uint32_t INITIAL_C = 0x98badcfe; +static constexpr uint32_t INITIAL_D = 0x10325476; /////////////////////////////////////////////////////////////////////////////// -MD4::MD4 () -{ - reset (); - static_assert (sizeof (MD4::X) == sizeof (MD4::Xb), - "Byte and word buffer size must match exactly"); - static_assert (sizeof (MD4::ABCD) == sizeof (MD4::digest_t), - "Internal state must match the size of the digest"); -} - - -//----------------------------------------------------------------------------- -void -MD4::reset (void) -{ - m_total = 0; - - ABCD[0] = DEFAULT_A; - ABCD[1] = DEFAULT_B; - ABCD[2] = DEFAULT_C; - ABCD[3] = DEFAULT_D; - - memset (Xb, 0, sizeof (Xb)); -} - - -/////////////////////////////////////////////////////////////////////////////// -void -MD4::update (const uint8_t *restrict first, const uint8_t *restrict last) noexcept -{ - CHECK_LE (first, last); - - update (first, last - first); -} - - -//----------------------------------------------------------------------------- -void -MD4::update (const void *restrict _data, size_t size) noexcept -{ - CHECK (_data); - auto data = static_cast (_data); - - size_t offset = m_total % sizeof (Xb); - size_t remain = sizeof (Xb) - offset; - - if (size > remain) { - memcpy (Xb + offset, data, remain); - transform (); - - m_total += remain; - size -= remain; - data += remain; - - while (size >= sizeof (Xb)) { - memcpy (Xb, data, sizeof (Xb)); - transform (); - - m_total += sizeof (Xb); - size -= sizeof (Xb); - data += sizeof (Xb); - } - - offset = 0; - } - - memcpy (Xb + offset, data, size); - m_total += size; -} - - -/////////////////////////////////////////////////////////////////////////////// -MD4::digest_t -MD4::digest (void) const -{ - digest_t d; - memcpy (d.data (), ABCD.data(), sizeof (ABCD)); - return d; -} - - -/////////////////////////////////////////////////////////////////////////////// -void -MD4::transform (void) +static void +transform (std::array &ABCD, const std::array &X) noexcept { uint32_t A = ABCD[0], - B = ABCD[1], - C = ABCD[2], - D = ABCD[3]; + B = ABCD[1], + C = ABCD[2], + D = ABCD[3]; - #define ROUND1(a,b,c,d,k,s) do { \ +#define ROUND1(a,b,c,d,k,s) do { \ (a) += F((b), (c), (d)) + X[k]; \ - (a) = rotatel ((a), (s)); \ + (a) = util::rotatel ((a), (s)); \ } while (0) ROUND1(A,B,C,D, 0, 3); @@ -175,9 +94,9 @@ MD4::transform (void) ROUND1(C,D,A,B, 14, 11); ROUND1(B,C,D,A, 15, 19); - #define ROUND2(a,b,c,d,k,s) do { \ +#define ROUND2(a,b,c,d,k,s) do { \ (a) += G((b),(c),(d)) + X[k] + 0x5A827999u; \ - (a) = rotatel ((a), (s)); \ + (a) = util::rotatel ((a), (s)); \ } while (0) ROUND2(A,B,C,D, 0, 3); @@ -200,9 +119,9 @@ MD4::transform (void) ROUND2(C,D,A,B, 11, 9); ROUND2(B,C,D,A, 15, 13); - #define ROUND3(a,b,c,d,k,s) do { \ +#define ROUND3(a,b,c,d,k,s) do { \ (a) += H((b),(c),(d)) + X[k] + 0x6ED9EBA1u; \ - (a) = rotatel ((a), (s)); \ + (a) = util::rotatel ((a), (s)); \ } while (0) ROUND3(A,B,C,D, 0, 3); @@ -233,30 +152,64 @@ MD4::transform (void) /////////////////////////////////////////////////////////////////////////////// -void -MD4::finish (void) +MD4::digest_t +MD4::operator() (util::view data) noexcept { - uint64_t bits = m_total * 8; + /* RESET */ + uint64_t total = 0; + std::array ABCD { + INITIAL_A, + INITIAL_B, + INITIAL_C, + INITIAL_D, + }; + + union { + std::array X; + std::array Xb; + }; + static_assert (sizeof (X) == sizeof (Xb)); + static_assert (sizeof (ABCD) == sizeof (digest_t)); + + std::fill (std::begin (X), std::end (X), 0); + + /* UPDATE */ + { + auto remain = data; + while (remain.size () >= sizeof (Xb)) { + std::copy_n (std::begin (remain), sizeof (Xb), std::begin (Xb)); + transform (ABCD, X); + remain = { remain.begin () + sizeof (Xb), remain.end () }; + total += sizeof (Xb); + } + + std::copy (std::begin (remain), std::end (remain), std::begin (Xb)); + total += remain.size (); + } + + uint64_t bits = total * 8; + + /* FINISH */ { // Pad with the mandatory 1 bit - size_t offset = m_total % sizeof (Xb); + size_t offset = total % sizeof (Xb); Xb[offset] = 0x80; } { // Pad the remainder with 0's, until 56 bytes - size_t offset = (m_total + 1) % sizeof (Xb); + size_t offset = (total + 1) % sizeof (Xb); size_t remain = (56 - offset % sizeof (Xb)) % sizeof (Xb); if (offset > 56) { - memset (Xb + offset, 0, sizeof (Xb) - offset); - transform (); + std::fill_n (std::begin (Xb) + offset, sizeof (Xb) - offset, 0); + transform (ABCD, X); remain -= sizeof (Xb) - offset; offset = 0; } - memset (Xb + offset, 0, remain); + std::fill (std::begin (Xb) + offset, std::end (Xb), 0); // Put in the length (in bits) least significant first for (size_t i = 0; i < sizeof (bits); ++i) { @@ -264,6 +217,11 @@ MD4::finish (void) bits >>= 8; } - transform (); + transform (ABCD, X); } + + /* DIGEEST */ + digest_t d; + memcpy (d.data (), ABCD.data(), sizeof (ABCD)); + return d; } diff --git a/hash/md4.hpp b/hash/md4.hpp index 91e94486..ebc05411 100644 --- a/hash/md4.hpp +++ b/hash/md4.hpp @@ -17,6 +17,8 @@ #ifndef __UTIL_HASH_MD4_HPP #define __UTIL_HASH_MD4_HPP +#include "view.hpp" + #include #include @@ -25,28 +27,9 @@ namespace util::hash { class MD4 { public: - typedef std::array digest_t; + using digest_t = std::array; - public: - MD4(); - - void update (const void *restrict data, size_t len) noexcept; - void update (const uint8_t *restrict first, const uint8_t *restrict last) noexcept; - - void finish (void); - digest_t digest (void) const; - void reset (void); - - private: - void transform (void); - - uint64_t m_total; - - std::array ABCD; - union { - uint32_t X [16]; - uint8_t Xb[64]; - }; + digest_t operator() (util::view) noexcept; }; } diff --git a/hash/md5.cpp b/hash/md5.cpp index 07056bcf..cf10b2c5 100644 --- a/hash/md5.cpp +++ b/hash/md5.cpp @@ -16,6 +16,7 @@ #include "md5.hpp" +#include "../iterator.hpp" #include "../bitwise.hpp" #include "../debug.hpp" @@ -95,131 +96,107 @@ const std::array T = { { //----------------------------------------------------------------------------- -static const uint32_t DEFAULT_A = 0x67452301; -static const uint32_t DEFAULT_B = 0xefcdab89; -static const uint32_t DEFAULT_C = 0x98badcfe; -static const uint32_t DEFAULT_D = 0x10325476; +static constexpr uint32_t INITIAL_A = 0x67452301; +static constexpr uint32_t INITIAL_B = 0xefcdab89; +static constexpr uint32_t INITIAL_C = 0x98badcfe; +static constexpr uint32_t INITIAL_D = 0x10325476; /////////////////////////////////////////////////////////////////////////////// -MD5::MD5() +typename MD5::digest_t +MD5::operator() (util::view a) const noexcept { - reset (); + return (*this)(a, nullptr); } //----------------------------------------------------------------------------- -void -MD5::reset (void) +typename MD5::digest_t +MD5::operator() (util::view a, util::view b) const noexcept { - m_total = 0; - - ABCD[0] = DEFAULT_A; - ABCD[1] = DEFAULT_B; - ABCD[2] = DEFAULT_C; - ABCD[3] = DEFAULT_D; + return (*this)(a, b, nullptr); } /////////////////////////////////////////////////////////////////////////////// -void -MD5::update (const uint8_t *restrict first, const uint8_t *restrict last) noexcept -{ - CHECK_LE (first, last); +typename MD5::digest_t +MD5::operator() ( + const util::view data_a, + const util::view data_b, + const util::view data_c +) const noexcept { + union { + std::array w; + std::array b; + } X; - update (first, last - first); -} + static_assert (sizeof (X.w) == BLOCK_SIZE); + static_assert (X.w.size () == DIGEST_SIZE); + static_assert (sizeof (X.b) == BLOCK_SIZE); + static_assert (X.b.size () == BLOCK_SIZE); -//----------------------------------------------------------------------------- -void -MD5::update (const void *restrict _data, size_t size) noexcept -{ - CHECK (_data); - auto data = static_cast (_data); + static_assert ((void*)&X.w == (void*)&X.b); - size_t offset = m_total % sizeof (Xb); - size_t remain = sizeof (Xb) - offset; + uint64_t m_total = 0; + std::array ABCD = { + INITIAL_A, + INITIAL_B, + INITIAL_C, + INITIAL_D + }; - if (size >= remain) { - memcpy (Xb + offset, data, remain); - transform (); + // note we pass in a windowed view of the state block, not the whole + // thing. + util::transform_by_block ( + util::view {X.b}, + [&,this] (auto) { ABCD = transform (ABCD, X.w); }, + data_a, data_b, data_c + ); + m_total = data_a.size () + data_b.size () + data_c.size (); - m_total += remain; - size -= remain; - data += remain; + uint64_t bits = m_total * 8; - while (size >= sizeof (Xb)) { - memcpy (Xb, data, sizeof (Xb)); - transform (); + // Pad with the mandatory 1 bit + X.b[m_total % BLOCK_SIZE] = 0x80; - m_total += sizeof (Xb); - size -= sizeof (Xb); - data += sizeof (Xb); + { + // Pad the remainder with 0's, until 56 bytes + size_t offset = (m_total + 1) % BLOCK_SIZE; + size_t remain = (56 - offset % BLOCK_SIZE) % BLOCK_SIZE; + + if (offset > 56) { + std::fill (&X.b[offset], X.b.end (), 0); + ABCD = transform (ABCD, X.w); + remain -= sizeof (X.b) - offset; + offset = 0; } - offset = 0; + memset (&X.b[offset], 0, remain); + + // Put in the length (in bits) least significant first + for (size_t i = 0; i < sizeof (bits); ++i) { + X.b[56 + i] = bits & 0xFF; + bits >>= 8; + } + + ABCD = transform (ABCD, X.w); } - memcpy (Xb + offset, data, size); - m_total += size; -} - - -/////////////////////////////////////////////////////////////////////////////// -MD5::digest_t -MD5::digest (void) const -{ - static_assert (sizeof (ABCD) == sizeof (digest_t), - "Hash state must be the same size as the final digest"); digest_t d; memcpy (d.data (), ABCD.data (), sizeof (ABCD)); return d; -} +}; /////////////////////////////////////////////////////////////////////////////// -void -MD5::finish (void) +std::array +MD5::transform ( + const std::array &ABCD, + const std::array &X) const noexcept { - uint64_t bits = m_total * 8; - { - // Pad with the mandatory 1 bit - size_t offset = m_total % sizeof (Xb); - Xb[offset] = 0x80; - } - - { - // Pad the remainder with 0's, until 56 bytes - size_t offset = (m_total + 1) % sizeof (Xb); - size_t remain = (56 - offset % sizeof (Xb)) % sizeof (Xb); - - if (offset > 56) { - memset (Xb + offset, 0, sizeof (Xb) - offset); - transform (); - remain -= sizeof (Xb) - offset; - offset = 0; - } - - memset (Xb + offset, 0, remain); - - // Put in the length (in bits) least significant first - for (size_t i = 0; i < sizeof (bits); ++i) { - Xb[56 + i] = bits & 0xFF; - bits >>= 8; - } - - transform (); - } -} - - -/////////////////////////////////////////////////////////////////////////////// -void -MD5::transform (void) -{ uint32_t A = ABCD[0], B = ABCD[1], C = ABCD[2], @@ -315,8 +292,10 @@ MD5::transform (void) ROUNDx(C,D,A,B, 2, 15, 63, I); ROUNDx(B,C,D,A, 9, 21, 64, I); - ABCD[0] += A; - ABCD[1] += B; - ABCD[2] += C; - ABCD[3] += D; + return { + ABCD[0] + A, + ABCD[1] + B, + ABCD[2] + C, + ABCD[3] + D, + }; } diff --git a/hash/md5.hpp b/hash/md5.hpp index 2bb2a9a5..e3cacd32 100644 --- a/hash/md5.hpp +++ b/hash/md5.hpp @@ -17,6 +17,8 @@ #ifndef __UTIL_HASH_MD5_HPP #define __UTIL_HASH_MD5_HPP +#include "../view.hpp" + #include #include #include @@ -26,30 +28,21 @@ namespace util::hash { class MD5 { public: - typedef std::array digest_t; + using digest_t = std::array; static const size_t BLOCK_SIZE = 64; static const size_t DIGEST_SIZE = 16; public: - MD5(); - - void update (const void *restrict data, size_t len) noexcept; - void update (const uint8_t *restrict first, const uint8_t *restrict last) noexcept; - - void finish (void); - digest_t digest (void) const; - void reset (void); + digest_t operator() (util::view) const noexcept; + digest_t operator() (util::view,util::view) const noexcept; + digest_t operator() (util::view,util::view,util::view) const noexcept; private: - void transform (void); - - uint64_t m_total; - std::array ABCD; - - union { - uint32_t X [16]; - uint8_t Xb[64]; - }; + std::array + transform ( + const std::array &ABCD, + const std::array &X + ) const noexcept; }; } diff --git a/hash/murmur/murmur1.cpp b/hash/murmur/murmur1.cpp index e4a84bee..1719097e 100644 --- a/hash/murmur/murmur1.cpp +++ b/hash/murmur/murmur1.cpp @@ -19,40 +19,25 @@ #include "common.hpp" #include "../../debug.hpp" -//----------------------------------------------------------------------------- +using util::hash::murmur1; + + +/////////////////////////////////////////////////////////////////////////////// uint32_t -util::hash::murmur1::mix (uint32_t h, uint32_t k) +murmur1::operator() (util::view data) const noexcept { static const uint32_t m = 0xc6a4a793; - - h += k; - h *= m; - h ^= h >> 16; - - return h; -} - - -//----------------------------------------------------------------------------- -uint32_t -util::hash::murmur1::hash_32 (const void *restrict data, - size_t len, - uint32_t seed) -{ - CHECK (data); - - static const uint32_t m = 0xc6a4a793; - uint32_t h = seed ^ ((len & 0xffffffff) * m); + uint32_t h = m_seed ^ ((data.size () & 0xffffffff) * m); // mix the body - auto cursor = reinterpret_cast (data); - auto last = cursor + len / sizeof (uint32_t); + auto cursor = reinterpret_cast (data.data ()); + auto last = cursor + data.size () / sizeof (uint32_t); for (; cursor < last; ++cursor) h = mix (h, *cursor); // mix the tail - if (len % sizeof (uint32_t)) - h = mix (h, murmur::tail (reinterpret_cast (cursor), len)); + if (data.size () % sizeof (uint32_t)) + h = mix (h, murmur::tail (reinterpret_cast (cursor), data.size ())); // finalise h *= m; h ^= h >> 10; diff --git a/hash/murmur/murmur1.hpp b/hash/murmur/murmur1.hpp index cda30847..ab250099 100644 --- a/hash/murmur/murmur1.hpp +++ b/hash/murmur/murmur1.hpp @@ -17,13 +17,38 @@ #ifndef __UTIL_HASH_MURMUR_MURMUR1_HPP #define __UTIL_HASH_MURMUR_MURMUR1_HPP +#include "../../view.hpp" + #include #include // Austin Appleby's MumurHash1 -namespace util::hash::murmur1 { - uint32_t mix (uint32_t, uint32_t); - uint32_t hash_32 (const void *restrict data, size_t len, uint32_t seed); +namespace util::hash { + class murmur1 { + public: + using digest_t = uint32_t; + using seed_t = uint32_t; + + murmur1 (seed_t _seed): + m_seed (_seed) + { ; } + + static constexpr uint32_t mix (uint32_t h, uint32_t k) + { + constexpr uint32_t m = 0xc6a4a793; + + h += k; + h *= m; + h ^= h >> 16; + + return h; + } + + digest_t operator() (util::view data) const noexcept; + + private: + seed_t m_seed; + }; } #endif diff --git a/hash/murmur/murmur2.cpp b/hash/murmur/murmur2.cpp index f444c8f8..29d18c32 100644 --- a/hash/murmur/murmur2.cpp +++ b/hash/murmur/murmur2.cpp @@ -20,28 +20,28 @@ #include "../../debug.hpp" #include "common.hpp" +using util::hash::murmur2; + /////////////////////////////////////////////////////////////////////////////// -uint32_t -util::hash::murmur2::hash_32 (const void *restrict key, - size_t len, - uint32_t seed) +static uint32_t +hash_32 (const void *restrict key, + size_t len, + uint32_t seed) { - CHECK (key); - // setup - constexpr auto m = detail::constants::m; + constexpr auto m = util::hash::detail::murmur2::constants::m; uint32_t h = seed ^ (len & 0xffffffff); // body auto cursor = reinterpret_cast (key); auto last = cursor + len / sizeof (uint32_t); for (; cursor < last; ++cursor) - h = mix (h, *cursor); + h = util::hash::murmur2::mix (h, *cursor); // tail if (len % sizeof (uint32_t)) { - h ^= murmur::tail (reinterpret_cast (cursor), len); + h ^= util::hash::murmur::tail (reinterpret_cast (cursor), len); h *= m; } @@ -55,14 +55,14 @@ util::hash::murmur2::hash_32 (const void *restrict key, //----------------------------------------------------------------------------- -uint64_t -util::hash::murmur2::hash_64 (const void *restrict key, - size_t len, - uint64_t seed) +static uint64_t +hash_64 (const void *restrict key, + size_t len, + uint64_t seed) { // setup - constexpr auto m = detail::constants::m; - constexpr auto r = detail::constants::r; + constexpr auto m = util::hash::detail::murmur2::constants::m; + constexpr auto r = util::hash::detail::murmur2::constants::r; uint64_t h = seed ^ (len * m); @@ -70,11 +70,11 @@ util::hash::murmur2::hash_64 (const void *restrict key, auto cursor = reinterpret_cast (key); auto last = cursor + len / sizeof (uint64_t); for (; cursor < last; ++cursor) - h = mix (h, *cursor); + h = util::hash::murmur2::mix (h, *cursor); // tail if (len % sizeof (uint64_t)) { - h ^= murmur::tail (reinterpret_cast (cursor), len); + h ^= util::hash::murmur::tail (reinterpret_cast (cursor), len); h *= m; } @@ -87,3 +87,23 @@ util::hash::murmur2::hash_64 (const void *restrict key, } +/////////////////////////////////////////////////////////////////////////////// +template +typename murmur2::digest_t +murmur2::operator() (util::view data) const noexcept +{ + static_assert (std::is_same_v || std::is_same_v); + + if constexpr (std::is_same_v) + return hash_32 (data.data (), data.size (), m_seed); + + if constexpr (std::is_same_v) + return hash_64 (data.data (), data.size (), m_seed); + + unreachable (); +} + + +/////////////////////////////////////////////////////////////////////////////// +template class util::hash::murmur2; +template class util::hash::murmur2; diff --git a/hash/murmur/murmur2.hpp b/hash/murmur/murmur2.hpp index 6f41da26..2607c78b 100644 --- a/hash/murmur/murmur2.hpp +++ b/hash/murmur/murmur2.hpp @@ -17,21 +17,77 @@ #ifndef __UTIL_HASH_MURMUR_MURMUR2_HPP #define __UTIL_HASH_MURMUR_MURMUR2_HPP +#include "../../view.hpp" + #include #include // Austin Appleby's MumurHash2, and MurmurHash64A. The exhaustive list of // variants is deliberately not provided. You can damn well align your data or // fix the algorithm. -namespace util::hash::murmur2 { - constexpr uint32_t mix (uint32_t, uint32_t); - constexpr uint64_t mix (uint64_t, uint64_t); +namespace util::hash { + namespace detail::murmur2 { + template struct constants; - uint32_t hash_32 (const void *restrict data, size_t len, uint32_t seed); - uint64_t hash_64 (const void *restrict data, size_t len, uint64_t seed); + template <> + struct constants { + static const uint32_t m = 0x5bd1e995; + static const int32_t r = 24; + }; + + template <> + struct constants { + static const uint64_t m = 0xc6a4a7935bd1e995; + static const int64_t r = 47; + }; + } + + template + class murmur2 { + public: + using digest_t = DigestT; + using seed_t = DigestT; + + murmur2 (seed_t _seed): + m_seed (_seed) + { ; } + + static constexpr uint32_t mix (uint32_t h, uint32_t k) + { + constexpr uint32_t m = detail::murmur2::constants::m; + constexpr uint32_t r = detail::murmur2::constants::r; + + k *= m; + k ^= k >> r; + k *= m; + + h *= m; + h ^= k; + + return h; + } + + static constexpr uint64_t mix (uint64_t h, uint64_t k) + { + constexpr uint64_t m = detail::murmur2::constants::m; + constexpr uint64_t r = detail::murmur2::constants::r; + + k *= m; + k ^= k >> r; + k *= m; + + h ^= k; + h *= m; + + return h; + } + + digest_t operator() (util::view data) const noexcept; + + private: + seed_t m_seed; + }; } -#include "murmur2.ipp" - #endif diff --git a/hash/murmur/murmur2.ipp b/hash/murmur/murmur2.ipp deleted file mode 100644 index 430ce60b..00000000 --- a/hash/murmur/murmur2.ipp +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * Copyright 2016 Danny Robson - */ - -#if defined(__UTIL_HASH_MURMUR_MURMUR2_IPP) -#error -#endif - -#define __UTIL_HASH_MURMUR_MURMUR2_IPP - - -/////////////////////////////////////////////////////////////////////////////// -namespace util::hash::murmur2::detail { - template struct constants; - - template <> - struct constants { - static const uint32_t m = 0x5bd1e995; - static const int32_t r = 24; - }; - - template <> - struct constants { - static const uint64_t m = 0xc6a4a7935bd1e995; - static const int64_t r = 47; - }; -} - - -///////////////////////////////////////////////////////////////////// -constexpr uint32_t -util::hash::murmur2::mix (uint32_t h, uint32_t k) -{ - constexpr uint32_t m = detail::constants::m; - constexpr uint32_t r = detail::constants::r; - - k *= m; - k ^= k >> r; - k *= m; - - h *= m; - h ^= k; - - return h; -} - - -//----------------------------------------------------------------------------- -// 64 bit murmur2 mixing function. Note the last two lines are swapped -// compared with 32 bit murmur2_mix. It's not clear if this is deliberate -// in the canonical implementation, so we just leave it to help compatibility. -constexpr uint64_t -util::hash::murmur2::mix (uint64_t h, uint64_t k) -{ - constexpr uint64_t m = detail::constants::m; - constexpr uint64_t r = detail::constants::r; - - k *= m; - k ^= k >> r; - k *= m; - - h ^= k; - h *= m; - - return h; -} diff --git a/hash/murmur/murmur3.cpp b/hash/murmur/murmur3.cpp index 1fc54b64..bf72c473 100644 --- a/hash/murmur/murmur3.cpp +++ b/hash/murmur/murmur3.cpp @@ -21,6 +21,8 @@ #include +using util::hash::murmur3; + /////////////////////////////////////////////////////////////////////////////// static @@ -36,8 +38,9 @@ read_u32 (const uint8_t *bytes) /////////////////////////////////////////////////////////////////////////////// // Finalization mix - force all bits of a hash block to avalanche +template uint32_t -util::hash::murmur3::mix (uint32_t h) +murmur3::mix (uint32_t h) { h ^= h >> 16; h *= 0x85ebca6b; @@ -50,8 +53,9 @@ util::hash::murmur3::mix (uint32_t h) //----------------------------------------------------------------------------- +template uint64_t -util::hash::murmur3::mix (uint64_t k) +murmur3::mix (uint64_t k) { k ^= k >> 33; k *= 0xff51afd7ed558ccd; @@ -63,56 +67,60 @@ util::hash::murmur3::mix (uint64_t k) } +/////////////////////////////////////////////////////////////////////////////// +template +struct hash { }; + + //----------------------------------------------------------------------------- -uint32_t -util::hash::murmur3::hash_32(const void *restrict key, - size_t len, - uint32_t seed) -{ - auto data = reinterpret_cast (key); - auto nblocks = len / sizeof (uint32_t); +template +struct hash<32,ArchBits> { + static auto eval (util::view data, uint32_t seed) + { + auto nblocks = data.size () / sizeof (uint32_t); - uint32_t h1 = seed; + uint32_t h1 = seed; - static const uint32_t c1 = 0xcc9e2d51; - static const uint32_t c2 = 0x1b873593; + static const uint32_t c1 = 0xcc9e2d51; + static const uint32_t c2 = 0x1b873593; - //---------- - // body - auto cursor = data; - auto last = cursor + nblocks * sizeof (uint32_t); - for (; cursor < last; cursor += sizeof (uint32_t)) { - uint32_t k1 = read_u32 (cursor); + //---------- + // body + auto cursor = data.begin (); + auto last = cursor + nblocks * sizeof (uint32_t); + for (; cursor < last; cursor += sizeof (uint32_t)) { + uint32_t k1 = read_u32 (cursor); - k1 *= c1; - k1 = util::rotatel (k1, 15); - k1 *= c2; - h1 ^= k1; + k1 *= c1; + k1 = util::rotatel (k1, 15); + k1 *= c2; + h1 ^= k1; - h1 = util::rotatel (h1, 13); - h1 += 0; - h1 = h1 * 5 + 0xe6546b64; + h1 = util::rotatel (h1, 13); + h1 += 0; + h1 = h1 * 5 + 0xe6546b64; + } + + //---------- + // tail + if (data.size () % sizeof (uint32_t)) { + uint32_t k1 = 0 ^ util::hash::murmur::tail (cursor, data.size ()); + + k1 *= c1; + k1 = util::rotatel (k1, 15); + k1 *= c2; + h1 ^= k1; + } + + //---------- + // finalization + + h1 ^= data.size (); + h1 = util::hash::murmur3<32,ArchBits>::mix (h1); + + return h1; } - - //---------- - // tail - if (len % sizeof (uint32_t)) { - uint32_t k1 = 0 ^ murmur::tail (cursor, len); - - k1 *= c1; - k1 = util::rotatel (k1, 15); - k1 *= c2; - h1 ^= k1; - } - - //---------- - // finalization - - h1 ^= len; - h1 = mix (h1); - - return h1; -} +}; /////////////////////////////////////////////////////////////////////////////// @@ -237,7 +245,7 @@ hash_128 (const void *restrict key, for (size_t i = 1; i < traits::COMPONENTS; ++i) h[i] += h[0]; for (auto &v: h) - v = util::hash::murmur3::mix (v); + v = util::hash::murmur3<128,sizeof(T)*8>::mix (v); for (size_t i = 1; i < traits::COMPONENTS; ++i) h[0] += h[i]; for (size_t i = 1; i < traits::COMPONENTS; ++i) h[i] += h[0]; @@ -246,21 +254,33 @@ hash_128 (const void *restrict key, } -/////////////////////////////////////////////////////////////////////////////// -std::array -util::hash::murmur3::hash_128_x86 (const void *restrict key, - const size_t len, - const uint32_t seed) -{ - return ::hash_128 (key, len, seed); -} +template <> +struct hash<128,32> { + static auto eval (util::view data, uint32_t seed) + { + return ::hash_128 (data.data (), data.size (), seed); + } +}; + + +template <> +struct hash<128,64> { + static auto eval (util::view data, uint32_t seed) + { + return ::hash_128 (data.data (), data.size (), seed); + } +}; //----------------------------------------------------------------------------- -std::array -util::hash::murmur3::hash_128_x64 (const void *restrict key, - size_t len, - const uint32_t seed) +template +typename murmur3::digest_t +murmur3::operator() (util::view data) const noexcept { - return ::hash_128 (key, len, seed); + return ::hash::eval (data, m_seed); } + +/////////////////////////////////////////////////////////////////////////////// +template class util::hash::murmur3<32, 32>; +template class util::hash::murmur3<128,32>; +template class util::hash::murmur3<128,64>; diff --git a/hash/murmur/murmur3.hpp b/hash/murmur/murmur3.hpp index 71ac45a7..ffe89bef 100644 --- a/hash/murmur/murmur3.hpp +++ b/hash/murmur/murmur3.hpp @@ -17,18 +17,47 @@ #ifndef __UTIL_HASH_MURMUR_MURMUR3_HPP #define __UTIL_HASH_MURMUR_MURMUR3_HPP +#include "../../view.hpp" + #include #include #include // Austin Appleby's MurmurHash3 -namespace util::hash::murmur3 { - uint32_t mix (uint32_t); - uint64_t mix (uint64_t); +namespace util::hash { + namespace detail::murmur3 { + template + struct digest_type { }; - uint32_t hash_32 (const void *restrict data, size_t len, uint32_t seed); - std::array hash_128_x86 (const void *restrict data, size_t len, uint32_t seed); - std::array hash_128_x64 (const void *restrict data, size_t len, uint32_t seed); + template <> struct digest_type< 32,32> { using type = uint32_t; }; + template <> struct digest_type<128,32> { using type = std::array; }; + template <> struct digest_type<128,64> { using type = std::array; }; + }; + + template + class murmur3 { + public: + murmur3 (uint32_t _seed): + m_seed (_seed) + { ; } + + static_assert (DigestBits % 8 == 0); + + using digest_t = typename detail::murmur3::digest_type::type; + + static uint32_t mix (uint32_t); + static uint64_t mix (uint64_t); + + digest_t + operator() (util::view data) const noexcept; + + private: + uint32_t m_seed; + }; + + using murmur3_32 = murmur3< 32,32>; + using murmur3_128_x86 = murmur3<128,32>; + using murmur3_128_x64 = murmur3<128,64>; } #endif diff --git a/hash/pbkdf1.cpp b/hash/pbkdf1.cpp deleted file mode 100644 index 2a1687b1..00000000 --- a/hash/pbkdf1.cpp +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * Copyright 2013 Danny Robson - */ - -#include "pbkdf1.hpp" diff --git a/hash/pbkdf1.hpp b/hash/pbkdf1.hpp deleted file mode 100644 index 167090cf..00000000 --- a/hash/pbkdf1.hpp +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * Copyright 2013 Danny Robson - */ - -#ifndef __UTIL_HASH_PBKDF1_HPP -#define __UTIL_HASH_PBKDF1_HPP - -namespace util { - namespace hash { - class PBKDF1 { - - }; - } -} - -#endif diff --git a/hash/pbkdf2.cpp b/hash/pbkdf2.cpp deleted file mode 100644 index 45bccae5..00000000 --- a/hash/pbkdf2.cpp +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * Copyright 2013 Danny Robson - */ - -#include "pbkdf2.hpp" diff --git a/hash/pbkdf2.hpp b/hash/pbkdf2.hpp deleted file mode 100644 index d9f66c3e..00000000 --- a/hash/pbkdf2.hpp +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * Copyright 2013 Danny Robson - */ - -#ifndef __UTIL_HASH_PBKDF2_HPP -#define __UTIL_HASH_PBKDF2_HPP - -namespace util { - namespace hash { - class PBKDF2 { - - }; - } -} - -#endif diff --git a/hash/ripemd.cpp b/hash/ripemd.cpp index 49510100..fa02116d 100644 --- a/hash/ripemd.cpp +++ b/hash/ripemd.cpp @@ -12,7 +12,7 @@ * limitations under the License. * * Copyright: - * 2014, Danny Robson + * 2014-2018, Danny Robson */ #include "ripemd.hpp" @@ -25,70 +25,6 @@ using util::hash::RIPEMD; -/////////////////////////////////////////////////////////////////////////////// -RIPEMD::RIPEMD() -{ - reset (); -} - - -//----------------------------------------------------------------------------- -void -RIPEMD::reset (void) -{ - m_state[0] = 0x67452301u; - m_state[1] = 0xEFCDAB89u; - m_state[2] = 0x98BADCFEu; - m_state[3] = 0x10325476u; - m_state[4] = 0xC3D2E1F0u; - - m_length = 0; - - m_buffer.size = 0; -} - - -/////////////////////////////////////////////////////////////////////////////// -void -RIPEMD::update ( - const uint8_t *restrict first, - const uint8_t *restrict last) noexcept -{ - CHECK_LE (first, last); - - update (first, last - first); -} - - -//----------------------------------------------------------------------------- -void -RIPEMD::update (const void *restrict _data, size_t len) noexcept -{ - CHECK (_data); - - auto data = static_cast (_data); - - size_t cursor = 0; - - while (cursor < len) { - size_t width = sizeof (m_buffer.d08) - m_buffer.size; - size_t chunk = min (width, len - cursor); - - memcpy (m_buffer.d08 + m_buffer.size, data + cursor, chunk); - m_length += chunk; - m_buffer.size += chunk; - - if (m_buffer.size == sizeof (m_buffer.d08)) - transform (); - - cursor += chunk; - } - - if (m_length >> sizeof (m_length) * 8 - 3 != 0) - panic ("exceeded maximum message length"); -} - - /////////////////////////////////////////////////////////////////////////////// static constexpr uint32_t @@ -135,11 +71,9 @@ f5 (uint32_t x, uint32_t y, uint32_t z) /////////////////////////////////////////////////////////////////////////////// -void -RIPEMD::transform (void) +static void +transform (uint32_t state[5], const uint32_t d32[16]) { - CHECK_EQ (m_buffer.size, sizeof (m_buffer.d32)); - // Use: boolean function f // state parameters a, b, c, d, e // offset value o @@ -148,10 +82,10 @@ RIPEMD::transform (void) #define ROUND(f,a,b,c,d,e,o,x,s) { \ a += f(b, c, d); \ - a += m_buffer.d32[x] + o; \ - a = rotatel (a, s); \ + a += d32[x] + o; \ + a = util::rotatel (a, s); \ a += e; \ - c = rotatel (c, 10); \ + c = util::rotatel (c, 10); \ } #define R1a(a,b,c,d,e,x,s) ROUND(f1,a,b,c,d,e,0x00000000u,x,s) @@ -169,11 +103,11 @@ RIPEMD::transform (void) uint32_t a1, b1, c1, d1, e1; uint32_t a2, b2, c2, d2, e2; - a1 = a2 = m_state[0]; - b1 = b2 = m_state[1]; - c1 = c2 = m_state[2]; - d1 = d2 = m_state[3]; - e1 = e2 = m_state[4]; + a1 = a2 = state[0]; + b1 = b2 = state[1]; + c1 = c2 = state[2]; + d1 = d2 = state[3]; + e1 = e2 = state[4]; // Left round 1 R1a(a1, b1, c1, d1, e1, 0, 11); @@ -356,61 +290,119 @@ RIPEMD::transform (void) R5b(b2, c2, d2, e2, a2, 11 , 11); // Finalise state - d2 = m_state[1] + c1 + d2; - m_state[1] = m_state[2] + d1 + e2; - m_state[2] = m_state[3] + e1 + a2; - m_state[3] = m_state[4] + a1 + b2; - m_state[4] = m_state[0] + b1 + c2; - m_state[0] = d2; - - m_buffer.size = 0; -} - - -/////////////////////////////////////////////////////////////////////////////// -void -RIPEMD::finish (void) -{ - // Ensure the length wouldn't overflow if converted to bits. We need to - // grab this before there's a chance it gets overwritten. - CHECK_EQ (m_length >> sizeof(m_length) * 8 - 3, 0u); - uint64_t length = m_length * 8; - - // Push a padding byte into the buffer - uint8_t padding = 0x80; - update (&padding, 1); - - // Pad out the line if we couldn't fit a length at the end - size_t remaining = sizeof (m_buffer.d32) - m_buffer.size; - if (remaining < 8) { - static const uint8_t ZEROES[8] = { 0 }; - - update (ZEROES, remaining); - - CHECK_EQ (m_buffer.size, 0u); - remaining = sizeof (m_buffer.d08); - } - - // Write the length to the end of the buffer - union { - uint32_t d32[16]; - uint8_t d08[64]; - }; - - memset (d32, 0, sizeof (d32)); - d32[14] = length & 0xFFFFFFFF; - d32[15] = length >> 32u; - - // Do the final update - size_t offset = sizeof(d08) - remaining; - update (d08 + offset, remaining); + d2 = state[1] + c1 + d2; + state[1] = state[2] + d1 + e2; + state[2] = state[3] + e1 + a2; + state[3] = state[4] + a1 + b2; + state[4] = state[0] + b1 + c2; + state[0] = d2; } /////////////////////////////////////////////////////////////////////////////// RIPEMD::digest_t -RIPEMD::digest (void) const +RIPEMD::operator() (const util::view data) { + struct { + union { + uint32_t d32[16]; + uint8_t d08[64]; + }; + size_t size; + } m_buffer; + + /* INIT */ + uint32_t m_state[5] { + 0x67452301u, + 0xEFCDAB89u, + 0x98BADCFEu, + 0x10325476u, + 0xC3D2E1F0u, + }; + + uint64_t m_length = 0; + + m_buffer.size = 0; + + /* UPDATE */ + { + auto len = data.size (); + auto base = data.begin (); + size_t cursor = 0; + + while (cursor < len) { + size_t width = sizeof (m_buffer.d08) - m_buffer.size; + size_t chunk = min (width, len - cursor); + + memcpy (m_buffer.d08 + m_buffer.size, base + cursor, chunk); + m_length += chunk; + m_buffer.size += chunk; + + if (m_buffer.size == sizeof (m_buffer.d08)) { + transform (m_state, m_buffer.d32); + m_buffer.size = 0; + } + + cursor += chunk; + } + + if (m_length >> sizeof (m_length) * 8 - 3 != 0) + panic ("exceeded maximum message length"); + } + + + /* FINISH */ + { + // Ensure the length wouldn't overflow if converted to bits. We need to + // grab this before there's a chance it gets overwritten. + CHECK_EQ (m_length >> sizeof(m_length) * 8 - 3, 0u); + uint64_t length = m_length * 8; + + // Push a padding byte into the buffer + uint8_t padding = 0x80; + assert (m_buffer.size != sizeof (m_buffer.d08)); + m_buffer.d08[m_buffer.size] = padding; + m_buffer.size++; + m_length++; + if (m_buffer.size == sizeof (m_buffer.d08)) { + transform (m_state, m_buffer.d32); + m_buffer.size = 0; + } + + // Pad out the line if we couldn't fit a length at the end + size_t remaining = sizeof (m_buffer.d32) - m_buffer.size; + if (remaining < 8) { + std::fill_n (m_buffer.d08 + m_buffer.size, remaining, 0); + m_buffer.size += remaining; + transform (m_state, m_buffer.d32); + m_buffer.size = 0; + m_length += remaining; + + CHECK_EQ (m_buffer.size, 0u); + remaining = sizeof (m_buffer.d08); + } + + // Write the length to the end of the buffer + union { + uint32_t d32[16]; + uint8_t d08[64]; + }; + + std::fill (std::begin (d32), std::end (d32), 0); + d32[14] = length & 0xFFFFFFFF; + d32[15] = length >> 32u; + + // Do the final update + size_t offset = sizeof(d08) - remaining; + + std::copy_n (d08 + offset, remaining, m_buffer.d08 + offset); + m_length += remaining; + m_buffer.size += remaining; + transform (m_state, m_buffer.d32); + m_buffer.size = 0; + } + + /* DIGEST */ digest_t d; memcpy (d.data (), m_state, sizeof (m_state)); return d; diff --git a/hash/ripemd.hpp b/hash/ripemd.hpp index 2612d880..e984ab96 100644 --- a/hash/ripemd.hpp +++ b/hash/ripemd.hpp @@ -12,11 +12,13 @@ * limitations under the License. * * Copyright: - * 2014, Danny Robson + * 2014-2018, Danny Robson */ -#ifndef __UTIL_HASH_RIPEMD_HPP -#define __UTIL_HASH_RIPEMD_HPP +#ifndef CRUFT_UTIL_HASH_RIPEMD_HPP +#define CRUFT_UTIL_HASH_RIPEMD_HPP + +#include "../view.hpp" #include @@ -24,34 +26,10 @@ /////////////////////////////////////////////////////////////////////////////// namespace util::hash { class RIPEMD { - public: - typedef std::array digest_t; + public: + typedef std::array digest_t; - public: - RIPEMD(); - - void update (const void *restrict, size_t) noexcept; - void update (const uint8_t *restrict first, const uint8_t *restrict last) noexcept; - - digest_t digest (void) const; - void finish (void); - void reset (void); - - protected: - void transform (); - - bool m_finished; - - uint32_t m_state[5]; - uint64_t m_length; - - struct { - union { - uint32_t d32[16]; - uint8_t d08[64]; - }; - size_t size; - } m_buffer; + digest_t operator() (util::view); }; } diff --git a/hash/sha1.cpp b/hash/sha1.cpp index 331056ad..13527d01 100644 --- a/hash/sha1.cpp +++ b/hash/sha1.cpp @@ -16,6 +16,7 @@ #include "sha1.hpp" +#include "../iterator.hpp" #include "../bitwise.hpp" #include "../debug.hpp" #include "../endian.hpp" @@ -24,23 +25,33 @@ #include #include #include -#include using util::hash::SHA1; /////////////////////////////////////////////////////////////////////////////// -std::ostream& -operator<< (std::ostream &os, SHA1::state_t t) -{ - switch (t) { - case SHA1::READY: return os << "READY"; - case SHA1::FINISHED: return os << "FINISHED"; - } +// Constant words for sequence of rounds +static constexpr uint32_t K_00 = 0x5A827999; +static constexpr uint32_t K_20 = 0x6ED9EBA1; +static constexpr uint32_t K_40 = 0x8F1BBCDC; +static constexpr uint32_t K_60 = 0xCA62C1D6; - unreachable (); -} + +//----------------------------------------------------------------------------- +static constexpr +std::array INITIAL_H = { + 0x67452301, + 0xEFCDAB89, + 0x98BADCFE, + 0x10325476, + 0xC3D2E1F0 +}; + + +//----------------------------------------------------------------------------- +static constexpr size_t BLOCK_WORDS = 16; +static constexpr size_t BLOCK_BYTES = BLOCK_WORDS * sizeof (uint32_t); /////////////////////////////////////////////////////////////////////////////// @@ -81,118 +92,35 @@ f_60 (uint32_t B, uint32_t C, uint32_t D) /////////////////////////////////////////////////////////////////////////////// -// Constant words for sequence of rounds -static constexpr uint32_t K_00 = 0x5A827999; -static constexpr uint32_t K_20 = 0x6ED9EBA1; -static constexpr uint32_t K_40 = 0x8F1BBCDC; -static constexpr uint32_t K_60 = 0xCA62C1D6; - - -static -constexpr uint32_t DEFAULT_H[] = { - 0x67452301, - 0xEFCDAB89, - 0x98BADCFE, - 0x10325476, - 0xC3D2E1F0 -}; - - -static constexpr size_t BLOCK_WORDS = 16; -static constexpr size_t BLOCK_BYTES = BLOCK_WORDS * sizeof (uint32_t); - - -/////////////////////////////////////////////////////////////////////////////// -SHA1::SHA1() +static void +process (std::array &H, std::array &W) { - reset (); -} - - -//----------------------------------------------------------------------------- -void -SHA1::reset (void) -{ - total = 0; - state = READY; - - std::copy (std::begin (DEFAULT_H), std::end (DEFAULT_H), H); -} - - -/////////////////////////////////////////////////////////////////////////////// -void -SHA1::update ( - const uint8_t *restrict first, - const uint8_t *restrict last) noexcept -{ - CHECK_LE (first, last); - - update (first, last - first); -} - - -//----------------------------------------------------------------------------- -void -SHA1::update (const void *restrict _data, size_t size) noexcept -{ - CHECK (_data); - CHECK_EQ (+state, +READY); - CHECK_GE (std::numeric_limits::max () - total, size); - - auto data = static_cast (_data); - - while (size > 0) { - // Copy the data into the remaining available buffer slots - const size_t offset = total % BLOCK_BYTES; - const size_t chunk = std::min (BLOCK_BYTES - offset, size); - - std::copy (data, data + chunk, c + offset); - - total += chunk; - - // Attempt to process if full - if (total % BLOCK_BYTES == 0) - process (); - - size -= chunk; - data += chunk; - } -} - - -/////////////////////////////////////////////////////////////////////////////// -void -SHA1::process (void) -{ - CHECK_EQ (total % BLOCK_BYTES, 0u); - // Byteswap the raw input we have buffered ready for arithmetic std::transform (std::begin (W), std::end (W), std::begin (W), [] (uint32_t x) { - return ntoh (x); - }); + return util::ntoh (x); + }); // Initialise the work buffer and the state variables for (size_t t = 16; t < 80; ++t) - W[t] = rotatel (W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16], 1); + W[t] = util::rotatel (W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16], 1); uint32_t A = H[0], - B = H[1], - C = H[2], - D = H[3], - E = H[4]; + B = H[1], + C = H[2], + D = H[3], + E = H[4]; // Perform each of the four rounds - #define ROTATE_STATE(i) do { \ - uint32_t temp = rotatel (A, 5) + f_##i (B, C, D) + E + W[t] + K_##i; \ - E = D; \ - D = C; \ - C = rotatel (B, 30); \ - B = A; \ - A = temp; \ +#define ROTATE_STATE(i) do { \ + uint32_t temp = util::rotatel (A, 5) + f_##i (B, C, D) + E + W[t] + K_##i; \ + E = D; \ + D = C; \ + C = util::rotatel (B, 30); \ + B = A; \ + A = temp; \ } while (0) for (size_t t = 0; t < 20; ++t) ROTATE_STATE(00); @@ -210,72 +138,80 @@ SHA1::process (void) /////////////////////////////////////////////////////////////////////////////// -void -SHA1::finish (void) +SHA1::digest_t +SHA1::operator() (util::view data) noexcept { - size_t offset = total % BLOCK_BYTES; - size_t used = total * 8; + return (*this) (data, nullptr); +} - // Append a single one bit - c[offset++] = 0x80; - total += 1; - // Zero fill if we can't append length - size_t chunk = BLOCK_BYTES - offset; - if (chunk < sizeof (total)) { - std::fill_n (c + offset, chunk, 0); +//----------------------------------------------------------------------------- +SHA1::digest_t +SHA1::operator() ( + util::view data_a, + util::view data_b +) noexcept { + /* RESET */ + uint64_t total = 0; + + union { + std::array w; + std::array b; + } H; + + union { + std::array c; + std::array W; + } state; + + H.w = INITIAL_H; + + /* UPDATE */ + transform_by_block ( + util::view {state.c.data (), BLOCK_BYTES }, + [&] (auto) { process (H.w, state.W); }, + data_a, data_b + ); + + total += data_a.size () + data_b.size (); + + /* FINISH */ + { + size_t offset = total % BLOCK_BYTES; + size_t used = total * 8; + + // Append a single one bit + state.c[offset++] = 0x80; + total += 1; + + // Zero fill if we can't append length + size_t chunk = BLOCK_BYTES - offset; + if (chunk < sizeof (total)) { + std::fill_n (std::begin (state.c) + offset, chunk, 0); + total += chunk; + + process (H.w, state.W); + + chunk = BLOCK_BYTES; + offset = 0; + } + + // Zero fill and append total length + std::fill_n (std::begin (state.c) + offset, chunk - sizeof (total), 0); + state.c[BLOCK_BYTES - 1] = used & 0xFF; used >>= 8; + state.c[BLOCK_BYTES - 2] = used & 0xFF; used >>= 8; + state.c[BLOCK_BYTES - 3] = used & 0xFF; used >>= 8; + state.c[BLOCK_BYTES - 4] = used & 0xFF; used >>= 8; + state.c[BLOCK_BYTES - 5] = used & 0xFF; used >>= 8; + state.c[BLOCK_BYTES - 6] = used & 0xFF; used >>= 8; + state.c[BLOCK_BYTES - 7] = used & 0xFF; used >>= 8; + state.c[BLOCK_BYTES - 8] = used & 0xFF; + total += chunk; - - process (); - - chunk = BLOCK_BYTES; - offset = 0; + process (H.w, state.W); } - // Zero fill and append total length - std::fill_n (c + offset, chunk - sizeof (total), 0); - c[BLOCK_BYTES - 1] = used & 0xFF; used >>= 8; - c[BLOCK_BYTES - 2] = used & 0xFF; used >>= 8; - c[BLOCK_BYTES - 3] = used & 0xFF; used >>= 8; - c[BLOCK_BYTES - 4] = used & 0xFF; used >>= 8; - c[BLOCK_BYTES - 5] = used & 0xFF; used >>= 8; - c[BLOCK_BYTES - 6] = used & 0xFF; used >>= 8; - c[BLOCK_BYTES - 7] = used & 0xFF; used >>= 8; - c[BLOCK_BYTES - 8] = used & 0xFF; - - total += chunk; - process (); - - state = FINISHED; -} - - -/////////////////////////////////////////////////////////////////////////////// -SHA1::digest_t -SHA1::digest (void) const -{ - CHECK_EQ (+state, +FINISHED); - - return { { - trunc_cast ((H[0] >> 24u) & 0xFF), - trunc_cast ((H[0] >> 16u) & 0xFF), - trunc_cast ((H[0] >> 8u) & 0xFF), - trunc_cast ((H[0] ) & 0xFF), - trunc_cast ((H[1] >> 24u) & 0xFF), - trunc_cast ((H[1] >> 16u) & 0xFF), - trunc_cast ((H[1] >> 8u) & 0xFF), - trunc_cast ((H[1] ) & 0xFF), - trunc_cast ((H[2] >> 24u) & 0xFF), - trunc_cast ((H[2] >> 16u) & 0xFF), - trunc_cast ((H[2] >> 8u) & 0xFF), - trunc_cast ((H[2] ) & 0xFF), - trunc_cast ((H[3] >> 24u) & 0xFF), - trunc_cast ((H[3] >> 16u) & 0xFF), - trunc_cast ((H[3] >> 8u) & 0xFF), - trunc_cast ((H[3] ) & 0xFF), - trunc_cast ((H[4] >> 24u) & 0xFF), - trunc_cast ((H[4] >> 16u) & 0xFF), - trunc_cast ((H[4] >> 8u) & 0xFF), - trunc_cast ((H[4] ) & 0xFF) - } }; + /* DIGEST */ + std::transform (std::begin (H.w), std::end (H.w), std::begin (H.w), util::hton); + return H.b; } diff --git a/hash/sha1.hpp b/hash/sha1.hpp index b34d8efe..0dfbb366 100644 --- a/hash/sha1.hpp +++ b/hash/sha1.hpp @@ -11,53 +11,33 @@ * See the License for the specific language governing permissions and * limitations under the License. * - * Copyright 2013 Danny Robson + * Copyright 2013-2018 Danny Robson */ -#ifndef __UTIL_HASH_SHA1_HPP -#define __UTIL_HASH_SHA1_HPP +#ifndef CRUFT_UTIL_HASH_SHA1_HPP +#define CRUFT_UTIL_HASH_SHA1_HPP -#include -#include +#include "../view.hpp" #include - +#include +#include /////////////////////////////////////////////////////////////////////////////// namespace util::hash { class SHA1 { public: - typedef std::array digest_t; + using digest_t = std::array; static const size_t BLOCK_SIZE = 64; static const size_t DIGEST_SIZE = 20; - public: - SHA1(); - void update (const void *restrict, size_t) noexcept; - void update (const uint8_t *restrict first, const uint8_t *restrict last) noexcept; + //template + //digest_t + //operator() (DataT&&...); - void finish (void); - digest_t digest (void) const; - void reset (void); - - enum state_t { - READY, - FINISHED - }; - - protected: - void process (void); - - state_t state; - - uint64_t total; - uint32_t H[5]; - - union { - uint8_t c[16*4+64*4]; - uint32_t W[16 +64 ]; - }; + digest_t operator() (util::view, util::view) noexcept; + digest_t operator() (util::view) noexcept; }; } diff --git a/hash/sha2.cpp b/hash/sha2.cpp index 8cd9f664..ce794f8b 100644 --- a/hash/sha2.cpp +++ b/hash/sha2.cpp @@ -182,87 +182,86 @@ H_512[] = { /////////////////////////////////////////////////////////////////////////////// -SHA256::SHA256 (): - m_total (0) +SHA256::digest_t +SHA256::operator() (util::view data) noexcept { (void)K_80; (void)H_224; (void)H_384; (void)H_512; + /* INIT */ + m_total = 0; std::copy (std::begin (H_256), std::end (H_256), std::begin (H)); -} + /* UPDATE */ + { + auto cursor = data.begin (); + auto length = data.size (); -//----------------------------------------------------------------------------- -void -SHA256::update (const uint8_t *restrict first, const uint8_t *restrict last) noexcept -{ - CHECK_LE (first, last); + while (length) { + size_t buffered = m_total % sizeof (M); + size_t chunk = std::min (sizeof (M) - buffered, length); + std::copy (cursor, cursor + chunk, C.begin () + buffered); - update (first, last - first); -} + length -= chunk; + m_total += chunk; - -//----------------------------------------------------------------------------- -void -SHA256::update (const void *restrict _data, size_t length) noexcept -{ - CHECK (_data); - auto data = static_cast (_data); - - while (length) { - size_t buffered = m_total % sizeof (M); - size_t chunk = std::min (sizeof (M) - buffered, length); - std::copy (data, data + chunk, C.begin () + buffered); - - length -= chunk; - m_total += chunk; - - if (m_total % sizeof (M) == 0) - process (); + if (m_total % sizeof (M) == 0) + process (); + } } -} + /* FINISH */ + { + // Append a single 1 bit followed by 0s. + auto buffered = m_total % sizeof (M); + auto used = m_total * 8u; -/////////////////////////////////////////////////////////////////////////////// -void -SHA256::finish (void) -{ - // Append a single 1 bit followed by 0s. - auto buffered = m_total % sizeof (M); - auto used = m_total * 8u; + C[buffered++] = 0x80; + ++m_total; - C[buffered++] = 0x80; - ++m_total; + // Pad out to 56 byte length + if (buffered > 56) { + size_t chunk = sizeof (M) - buffered; + std::fill_n (C.begin () + buffered, chunk, 0); + m_total += chunk; + process (); - // Pad out to 56 byte length - if (buffered > 56) { - size_t chunk = sizeof (M) - buffered; + buffered = 0; + } + + size_t chunk = sizeof (M) - sizeof (uint64_t) - buffered; std::fill_n (C.begin () + buffered, chunk, 0); m_total += chunk; - process (); - buffered = 0; + // Finish with the m_total size + C[56] = (used >> 56) & 0xFF; + C[57] = (used >> 48) & 0xFF; + C[58] = (used >> 40) & 0xFF; + C[59] = (used >> 32) & 0xFF; + C[60] = (used >> 24) & 0xFF; + C[61] = (used >> 16) & 0xFF; + C[62] = (used >> 8) & 0xFF; + C[63] = (used >> 0) & 0xFF; + m_total += 8; + + // Reprocess + process (); } - size_t chunk = sizeof (M) - sizeof (uint64_t) - buffered; - std::fill_n (C.begin () + buffered, chunk, 0); - m_total += chunk; + /* DIGEST */ + digest_t out; - // Finish with the m_total size - C[56] = (used >> 56) & 0xFF; - C[57] = (used >> 48) & 0xFF; - C[58] = (used >> 40) & 0xFF; - C[59] = (used >> 32) & 0xFF; - C[60] = (used >> 24) & 0xFF; - C[61] = (used >> 16) & 0xFF; - C[62] = (used >> 8) & 0xFF; - C[63] = (used >> 0) & 0xFF; - m_total += 8; + auto cursor = out.begin (); + for (auto i: H) { + *cursor++ = (i >> 24) & 0xFF; + *cursor++ = (i >> 16) & 0xFF; + *cursor++ = (i >> 8) & 0xFF; + *cursor++ = (i >> 0) & 0xFF; + } - // Reprocess - process (); + return out; } @@ -312,21 +311,3 @@ SHA256::process (void) H[6] += g; H[7] += h; } - - -/////////////////////////////////////////////////////////////////////////////// -SHA256::digest_t -SHA256::digest (void) const -{ - digest_t out; - - auto cursor = out.begin (); - for (auto i: H) { - *cursor++ = (i >> 24) & 0xFF; - *cursor++ = (i >> 16) & 0xFF; - *cursor++ = (i >> 8) & 0xFF; - *cursor++ = (i >> 0) & 0xFF; - } - - return out; -} diff --git a/hash/sha2.hpp b/hash/sha2.hpp index cb296971..b67dde41 100644 --- a/hash/sha2.hpp +++ b/hash/sha2.hpp @@ -18,6 +18,8 @@ #ifndef __UTIL_HASH_SHA2_HPP #define __UTIL_HASH_SHA2_HPP +#include "view.hpp" + #include #include @@ -29,15 +31,7 @@ namespace util::hash { typedef std::array digest_t; public: - SHA256(); - - void update (const void *restrict, size_t) noexcept; - void update (const uint8_t *restrict first, const uint8_t *restrict last) noexcept; - - void finish (void); - digest_t digest (void) const; - - void reset (void); + digest_t operator() (util::view) noexcept; private: void process (void); diff --git a/hash/simple.cpp b/hash/simple.cpp deleted file mode 100644 index 22eb18a3..00000000 --- a/hash/simple.cpp +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * Copyright 2016, Danny Robson - */ - -#include "simple.hpp" diff --git a/hash/simple.hpp b/hash/simple.hpp deleted file mode 100644 index 485126fd..00000000 --- a/hash/simple.hpp +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * Copyright 2016, Danny Robson - */ - -#ifndef __UTIL_HASH_SIMPLE_HPP -#define __UTIL_HASH_SIMPLE_HPP - -#include -#include - - -/////////////////////////////////////////////////////////////////////////////// -namespace util { namespace hash { - //template - template - typename H::digest_t - simple (const void *restrict first, const void *restrict last, Args&&...args) noexcept - { - H h (std::forward (args)...); - - h.update ( - static_cast (first), - static_cast (last) - ); - h.finish (); - - return h.digest (); - } -} } - -#endif diff --git a/hash/wang.hpp b/hash/wang.hpp index 7b1d23b7..06c58da2 100644 --- a/hash/wang.hpp +++ b/hash/wang.hpp @@ -21,10 +21,35 @@ namespace util::hash { // Thomas Wang's integer mixing functions, ca 2007 - constexpr uint32_t wang (uint32_t); - constexpr uint64_t wang (uint64_t); + //------------------------------------------------------------------------- + constexpr uint32_t + util::hash::wang (uint32_t key) { + // a prime or an odd constant + constexpr uint32_t c2 = 0x27d4eb2d; + + key = (key ^ 61) ^ (key >> 16); + key = key + (key << 3); + key = key ^ (key >> 4); + key = key * c2; + key = key ^ (key >> 15); + + return key; + } + + + //------------------------------------------------------------------------- + constexpr uint64_t + util::hash::wang (uint64_t key) { + key = ~key + (key << 21); // key = (key << 21) - key - 1; + key = key ^ (key >> 24); + key = (key + (key << 3)) + (key << 8); // key * 265 + key = key ^ (key >> 14); + key = (key + (key << 2)) + (key << 4); // key * 21 + key = key ^ (key >> 28); + key = key + (key << 31); + + return key; + } } -#include "wang.ipp" - #endif diff --git a/hash/wang.ipp b/hash/wang.ipp deleted file mode 100644 index 2bc8d816..00000000 --- a/hash/wang.ipp +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * Copyright 2010-2015 Danny Robson - */ - -#ifdef __UTIL_HASH_WANG_IPP -#error -#endif -#define __UTIL_HASH_WANG_IPP - - -//----------------------------------------------------------------------------- -constexpr uint32_t -util::hash::wang (uint32_t key) { - // a prime or an odd constant - constexpr uint32_t c2 = 0x27d4eb2d; - - key = (key ^ 61) ^ (key >> 16); - key = key + (key << 3); - key = key ^ (key >> 4); - key = key * c2; - key = key ^ (key >> 15); - - return key; -} - - -//----------------------------------------------------------------------------- -constexpr uint64_t -util::hash::wang (uint64_t key) { - key = ~key + (key << 21); // key = (key << 21) - key - 1; - key = key ^ (key >> 24); - key = (key + (key << 3)) + (key << 8); // key * 265 - key = key ^ (key >> 14); - key = (key + (key << 2)) + (key << 4); // key * 21 - key = key ^ (key >> 28); - key = key + (key << 31); - - return key; -} diff --git a/hash/xxhash.cpp b/hash/xxhash.cpp index 979dc2fa..6a45a264 100644 --- a/hash/xxhash.cpp +++ b/hash/xxhash.cpp @@ -78,40 +78,6 @@ const uint64_t constants::round_rotl = 31; -/////////////////////////////////////////////////////////////////////////////// -constexpr uint32_t DEFAULT_SEED = 0; - - -//----------------------------------------------------------------------------- -template -xxhash::xxhash (void): - xxhash (DEFAULT_SEED) -{ ; } - - -//----------------------------------------------------------------------------- -template -xxhash::xxhash (uint32_t _seed): - m_seed (_seed) -{ - reset (); -} - - -//----------------------------------------------------------------------------- -template -void -xxhash::reset (void) -{ - memset (&m_state, 0, sizeof (m_state)); - - m_state.v1 = m_seed + constants::prime[0] + constants::prime[1]; - m_state.v2 = m_seed + constants::prime[1]; - m_state.v3 = m_seed; - m_state.v4 = m_seed - constants::prime[0]; -} - - /////////////////////////////////////////////////////////////////////////////// template static @@ -128,117 +94,142 @@ round (T seed, T input) /////////////////////////////////////////////////////////////////////////////// template -void -xxhash::update (const uint8_t *restrict first, const uint8_t *restrict last) -{ - CHECK (first); - CHECK (last); - CHECK_LE (first, last); - - //auto endian = XXH_littleEndian; - size_t len = last - first; - auto input = (const void*)first; - - auto p = reinterpret_cast (input); - auto const bEnd = p + len; - - constexpr auto CHUNK = 4 * sizeof (T); - - m_state.total_len_32 += (unsigned)len; - m_state.large_len |= (len >= CHUNK) | (m_state.total_len_32 >= CHUNK); - - if (m_state.memsize + len < CHUNK) { /* fill in tmp buffer */ - memcpy ((uint8_t*)(m_state.mem32) + m_state.memsize, input, len); - m_state.memsize += (unsigned)len; - return; - } - - if (m_state.memsize) { /* some data left from previous update */ - memcpy ((uint8_t*)(m_state.mem32) + m_state.memsize, input, CHUNK - m_state.memsize); - { const uint32_t* p32 = m_state.mem32; - m_state.v1 = round (m_state.v1, ltoh (*p32)); p32++; - m_state.v2 = round (m_state.v2, ltoh (*p32)); p32++; - m_state.v3 = round (m_state.v3, ltoh (*p32)); p32++; - m_state.v4 = round (m_state.v4, ltoh (*p32)); p32++; - } - p += CHUNK - m_state.memsize; - m_state.memsize = 0; - } - - if (p <= bEnd - CHUNK * sizeof (T)) { - const uint8_t* const limit = bEnd - 4 * sizeof (T); - T v1 = m_state.v1; - T v2 = m_state.v2; - T v3 = m_state.v3; - T v4 = m_state.v4; - - do { - v1 = round (v1, read_le (p)); p += sizeof (T); - v2 = round (v2, read_le (p)); p += sizeof (T); - v3 = round (v3, read_le (p)); p += sizeof (T); - v4 = round (v4, read_le (p)); p += sizeof (T); - } while (p <= limit); - - m_state.v1 = v1; - m_state.v2 = v2; - m_state.v3 = v3; - m_state.v4 = v4; - } - - if (p < bEnd) { - memcpy (m_state.mem32, p, (size_t)(bEnd-p)); - m_state.memsize = (unsigned)(bEnd-p); - } -} - - -/////////////////////////////////////////////////////////////////////////////// -template -void -xxhash::finish (void) -{ - ; -} +xxhash::xxhash (uint32_t _seed): + m_seed (_seed) +{ ; } /////////////////////////////////////////////////////////////////////////////// template typename xxhash::digest_t -xxhash::digest (void) const +xxhash::operator() (const util::view data) { - auto p = reinterpret_cast (m_state.mem32); - auto last = p + m_state.memsize; + struct { + uint32_t total_len_32; + uint32_t large_len; - T h; + T v1, v2, v3, v4; + uint32_t mem32[4]; + uint32_t memsize; + uint32_t reserved; - if (m_state.large_len) { - h = rotatel (m_state.v1, T{ 1}) + - rotatel (m_state.v2, T{ 7}) + - rotatel (m_state.v3, T{12}) + - rotatel (m_state.v4, T{18}); - } else { - h = m_state.v3 /* == seed */ + constants::prime[4]; + //uint64_t length; + //T v[4]; + //T mem[4]; + //unsigned memsize; + } m_state; + + /* RESET */ + memset (&m_state, 0, sizeof (m_state)); + + m_state.v1 = m_seed + constants::prime[0] + constants::prime[1]; + m_state.v2 = m_seed + constants::prime[1]; + m_state.v3 = m_seed; + m_state.v4 = m_seed - constants::prime[0]; + + /* UPDATE */ + do { + auto first = data.begin (); + auto last = data.end (); + if (first == last) + break; + + CHECK (first); + CHECK (last); + CHECK_LE (first, last); + + //auto endian = XXH_littleEndian; + size_t len = last - first; + auto input = (const void*)first; + + auto p = reinterpret_cast (input); + auto const bEnd = p + len; + + constexpr auto CHUNK = 4 * sizeof (T); + + m_state.total_len_32 += (unsigned)len; + m_state.large_len |= (len >= CHUNK) | (m_state.total_len_32 >= CHUNK); + + if (m_state.memsize + len < CHUNK) { /* fill in tmp buffer */ + memcpy ((uint8_t*)(m_state.mem32) + m_state.memsize, input, len); + m_state.memsize += (unsigned)len; + break; + } + + if (m_state.memsize) { /* some data left from previous update */ + memcpy ((uint8_t*)(m_state.mem32) + m_state.memsize, input, CHUNK - m_state.memsize); + { const uint32_t* p32 = m_state.mem32; + m_state.v1 = round (m_state.v1, ltoh (*p32)); p32++; + m_state.v2 = round (m_state.v2, ltoh (*p32)); p32++; + m_state.v3 = round (m_state.v3, ltoh (*p32)); p32++; + m_state.v4 = round (m_state.v4, ltoh (*p32)); p32++; + } + p += CHUNK - m_state.memsize; + m_state.memsize = 0; + } + + if (p <= bEnd - CHUNK * sizeof (T)) { + const uint8_t* const limit = bEnd - 4 * sizeof (T); + T v1 = m_state.v1; + T v2 = m_state.v2; + T v3 = m_state.v3; + T v4 = m_state.v4; + + do { + v1 = round (v1, read_le (p)); p += sizeof (T); + v2 = round (v2, read_le (p)); p += sizeof (T); + v3 = round (v3, read_le (p)); p += sizeof (T); + v4 = round (v4, read_le (p)); p += sizeof (T); + } while (p <= limit); + + m_state.v1 = v1; + m_state.v2 = v2; + m_state.v3 = v3; + m_state.v4 = v4; + } + + if (p < bEnd) { + memcpy (m_state.mem32, p, (size_t)(bEnd-p)); + m_state.memsize = (unsigned)(bEnd-p); + } + } while (0); + + /* DIGEST */ + { + auto p = reinterpret_cast (m_state.mem32); + auto last = p + m_state.memsize; + + T h; + + if (m_state.large_len) { + h = rotatel (m_state.v1, T{ 1}) + + rotatel (m_state.v2, T{ 7}) + + rotatel (m_state.v3, T{12}) + + rotatel (m_state.v4, T{18}); + } else { + h = m_state.v3 /* == seed */ + constants::prime[4]; + } + + h += m_state.total_len_32; + + while (p + sizeof (T) <= last) { + h += read_le (p) * constants::prime[2]; + h = rotatel (h, 17) * constants::prime[3]; + p += 4; + } + + while (p < last) { + h += (*p) * constants::prime[4]; + h = rotatel (h, 11) * constants::prime[0]; + p++; + } + + h ^= h >> 15; h *= constants::prime[1]; + h ^= h >> 13; h *= constants::prime[2]; + h ^= h >> 16; + + return h; } - - h += m_state.total_len_32; - - while (p + sizeof (T) <= last) { - h += read_le (p) * constants::prime[2]; - h = rotatel (h, 17) * constants::prime[3]; - p += 4; - } - - while (p < last) { - h += (*p) * constants::prime[4]; - h = rotatel (h, 11) * constants::prime[0]; - p++; - } - - h ^= h >> 15; h *= constants::prime[1]; - h ^= h >> 13; h *= constants::prime[2]; - h ^= h >> 16; - - return h; } diff --git a/hash/xxhash.hpp b/hash/xxhash.hpp index 40ab41da..ad717683 100644 --- a/hash/xxhash.hpp +++ b/hash/xxhash.hpp @@ -17,6 +17,8 @@ #ifndef CRUFT_UTIL_HASH_XXHASH_HPP #define CRUFT_UTIL_HASH_XXHASH_HPP +#include "../view.hpp" + #include #include @@ -27,33 +29,14 @@ namespace util::hash { static_assert (std::is_same::value || std::is_same::value); using digest_t = T; - xxhash (void); - xxhash (uint32_t seed); + static constexpr uint32_t DEFAULT_SEED = 0; - void update (const uint8_t *restrict first, const uint8_t *restrict last); - void finish (void); - - digest_t digest (void) const; + xxhash (uint32_t seed = DEFAULT_SEED); - void reset (void); + digest_t operator() (const util::view data); private: uint32_t m_seed; - - struct { - uint32_t total_len_32; - uint32_t large_len; - - T v1, v2, v3, v4; - uint32_t mem32[4]; - uint32_t memsize; - uint32_t reserved; - - //uint64_t length; - //T v[4]; - //T mem[4]; - //unsigned memsize; - } m_state; }; using xxhash32 = xxhash; diff --git a/io.hpp b/io.hpp index 54d52d9c..0db16f73 100644 --- a/io.hpp +++ b/io.hpp @@ -90,7 +90,7 @@ namespace util { { auto remain = src; while (!remain.empty ()) - remain = src - dst.write (remain); + remain = remain.consume (dst.write (remain)); return src; } diff --git a/io_posix.hpp b/io_posix.hpp index 338f6b25..9409bf95 100644 --- a/io_posix.hpp +++ b/io_posix.hpp @@ -31,6 +31,14 @@ namespace util { namespace detail::posix { class mapped_file { public: + using value_type = uint8_t; + using reference = value_type&; + using const_reference = const value_type&; + using iterator = value_type*; + using const_iterator = const value_type*; + using difference_type = std::iterator_traits::difference_type; + using size_type = size_t; + mapped_file (const std::experimental::filesystem::path&, int fflags = O_RDONLY | O_BINARY, int mflags = PROT_READ); @@ -50,27 +58,19 @@ namespace util { /// often use this in conjunction with sizeof and packed structure. /// it is greatly simpler to cast to signed where it's actually /// required rather than the other way around. - size_t size (void) const; + size_type size (void) const; - const uint8_t* data (void) const &; - uint8_t* data (void) &; + const_iterator data (void) const &; + iterator data (void) &; - uint8_t* begin (void) &; - uint8_t* end (void) &; + iterator begin (void) &; + iterator end (void) &; - const uint8_t* begin (void) const &; - const uint8_t* end (void) const &; + const_iterator begin (void) const &; + const_iterator end (void) const &; - const uint8_t* cbegin (void) const &; - const uint8_t* cend (void) const &; - - template - util::view*> - as_view () const &; - - template - util::view - as_view () &; + const_iterator cbegin (void) const &; + const_iterator cend (void) const &; private: uint8_t *m_data; diff --git a/io_posix.ipp b/io_posix.ipp index 2e66c300..b6f991c8 100644 --- a/io_posix.ipp +++ b/io_posix.ipp @@ -21,27 +21,3 @@ #define __UTIL_IO_POSIX_IPP #include "pointer.hpp" - - -/////////////////////////////////////////////////////////////////////////////// -template -util::view*> -util::detail::posix::mapped_file::as_view (void) const& -{ - return { - reinterpret_cast (cbegin ()), - reinterpret_cast (align (cend (), alignof (T))) - }; -} - - -//----------------------------------------------------------------------------- -template -util::view -util::detail::posix::mapped_file::as_view (void) & -{ - return { - reinterpret_cast (begin ()), - reinterpret_cast (align (end (), alignof(T))) - }; -} diff --git a/iterator.hpp b/iterator.hpp index 0d4428e3..c05e23a0 100644 --- a/iterator.hpp +++ b/iterator.hpp @@ -516,6 +516,75 @@ namespace util { ) { return false; } + + + /////////////////////////////////////////////////////////////////////////// + template + OutputIt + _transform_by_block ( + const util::view &, + OutputIt cursor, + FunctionT && + ) { + return cursor; + } + + + //------------------------------------------------------------------------- + template + OutputIt + _transform_by_block ( + const util::view &dst, + OutputIt cursor, + FunctionT &&func, + const InputT &_src, + TailT &&...tail + ) { + auto remain = _src; + if (cursor != dst.begin ()) { + auto infill = std::distance (cursor, dst.end ()); + if (remain.size () < static_cast (infill)) { + return _transform_by_block ( + dst, + std::copy_n (remain.begin (), remain.size (), cursor), + std::forward (func), + std::forward (tail)... + ); + } + + std::copy_n (remain.begin (), infill, cursor); + func (dst); + cursor = dst.begin (); + remain = { remain.begin () + infill, remain.end () }; + } + + while (remain.size () >= dst.size ()) { + std::copy_n (remain.begin (), dst.size (), dst.begin ()); + func (dst); + remain = { remain.begin () + dst.size (), remain.end () }; + } + + return _transform_by_block ( + dst, + std::copy (remain.begin (), remain.end (), cursor), + std::forward (func), + std::forward (tail)... + ); + } + + + //------------------------------------------------------------------------- + template + OutputIt + transform_by_block (const util::view &dst, FunctionT &&func, Args &&...src) + { + return _transform_by_block ( + dst, + dst.begin (), + std::forward (func), + std::forward (src)... + ); + } }; #endif diff --git a/json/flat.hpp b/json/flat.hpp index b645dc63..28f4207f 100644 --- a/json/flat.hpp +++ b/json/flat.hpp @@ -52,7 +52,8 @@ namespace json::flat { }; template - std::vector> parse (util::view data); + std::vector> + parse (util::view data); std::ostream& operator<< (std::ostream&, type); } diff --git a/json/schema.cpp b/json/schema.cpp index ef477346..35da11dc 100644 --- a/json/schema.cpp +++ b/json/schema.cpp @@ -535,6 +535,6 @@ json::schema::validate (json::tree::node &data, const std::experimental::filesystem::path &schema_path) { const util::mapped_file schema_data (schema_path); - auto schema_object = json::tree::parse (schema_data.as_view ()); + auto schema_object = json::tree::parse (util::view{schema_data}.cast ()); validate (data, schema_object->as_object ()); } diff --git a/json/tree.cpp b/json/tree.cpp index 58c3d9c9..4a49ccd2 100644 --- a/json/tree.cpp +++ b/json/tree.cpp @@ -210,7 +210,7 @@ parse (typename std::vector>::const_iterator first, /////////////////////////////////////////////////////////////////////////////// template std::unique_ptr -json::tree::parse (const util::view src) +json::tree::parse (const util::view &src) { std::unique_ptr output; auto data = json::flat::parse (src); @@ -225,7 +225,7 @@ json::tree::parse (const util::view src) #define INSTANTIATE(KLASS) \ template \ std::unique_ptr \ -json::tree::parse (util::view); +json::tree::parse (const util::view&); MAP0(INSTANTIATE, std::string::iterator, @@ -244,7 +244,7 @@ std::unique_ptr json::tree::parse (const std::experimental::filesystem::path &src) { const util::mapped_file data (src); - return parse (data.as_view ()); + return parse (util::view{data}.cast ()); } @@ -443,6 +443,15 @@ namespace json::tree { { return static_cast (as_sint ()); } + + + //------------------------------------------------------------------------- + template <> + const std::string& + json::tree::node::as (void) const + { + return as_string ().native (); + } #if defined(__clang__) #elif defined(__GNUC__) #pragma GCC diagnostic pop diff --git a/json/tree.hpp b/json/tree.hpp index 1ac06a3e..d5eb7939 100644 --- a/json/tree.hpp +++ b/json/tree.hpp @@ -46,7 +46,7 @@ namespace json::tree { /// Parse an encoded form of JSON into a tree structure template std::unique_ptr - parse (util::view data); + parse (const util::view &data); std::unique_ptr parse (const std::experimental::filesystem::path &); diff --git a/maths.hpp b/maths.hpp index a66336a9..8a318736 100644 --- a/maths.hpp +++ b/maths.hpp @@ -225,7 +225,7 @@ namespace util { typename BaseT, typename ExponentT, typename = std::enable_if_t< - std::is_unsigned_v, + std::is_integral_v, void > > diff --git a/stringid.hpp b/stringid.hpp index a19813fa..cc397a47 100644 --- a/stringid.hpp +++ b/stringid.hpp @@ -11,27 +11,63 @@ * See the License for the specific language governing permissions and * limitations under the License. * - * Copyright 2014 Danny Robson + * Copyright 2014-2018 Danny Robson */ -#ifndef __UTIL_STRINGID_HPP -#define __UTIL_STRINGID_HPP +#ifndef CRUFT_UTIL_STRINGID_HPP +#define CRUFT_UTIL_STRINGID_HPP + +#include "view.hpp" #include #include namespace util { class stringid { - public: - typedef size_t id_t; + public: + typedef size_t id_t; - id_t add (std::string); - id_t find (const std::string&) const; - void clear (void); + /////////////////////////////////////////////////////////////////////// + id_t add (std::string); - private: - std::map m_map; + + //--------------------------------------------------------------------- + template + id_t add (util::view key) + { + return add ( + std::string{ + std::cbegin (key), + std::cend (key) + } + ); + } + + + /////////////////////////////////////////////////////////////////////// + id_t find (const std::string&) const; + + + //--------------------------------------------------------------------- + template + id_t find (util::view key) const + { + return find ( + std::string { + std::cbegin (key), + std::cend (key) + } + ); + } + + + /////////////////////////////////////////////////////////////////////// + void clear (void); + + + private: + std::map m_map; }; } diff --git a/test/hash/checksum.cpp b/test/hash/checksum.cpp index 6a062e49..2bbcc899 100644 --- a/test/hash/checksum.cpp +++ b/test/hash/checksum.cpp @@ -1,7 +1,6 @@ #include "hash/adler.hpp" #include "hash/bsdsum.hpp" -#include "hash/simple.hpp" #include "types.hpp" #include "tap.hpp" @@ -35,19 +34,19 @@ int main (int, char**) { util::TAP::logger tap; + util::hash::adler32 a; + util::hash::bsdsum b; + for (const auto &t: TESTS) { tap.expect_eq ( t.adler, - util::hash::simple ( - (const void*)t.data, - (const void*)(t.data + strlen (t.data)) - ), + a (util::view {t.data}.template cast ()), "adler checksum: %s", t.msg ); tap.expect_eq ( t.bsd, - util::hash::simple (t.data, t.data + strlen (t.data)), + b (util::view {t.data}.template cast ()), "bsdsum checksum: %s", t.msg); } diff --git a/test/hash/crc.cpp b/test/hash/crc.cpp index ba6b2dfe..e8d9c110 100644 --- a/test/hash/crc.cpp +++ b/test/hash/crc.cpp @@ -1,6 +1,5 @@ #include "tap.hpp" #include "hash/crc.hpp" -#include "hash/simple.hpp" #include #include @@ -34,15 +33,8 @@ main (int, char**) util::TAP::logger tap; for (const auto &t: TESTS) { - auto first = t.dat; - auto last = first + strlen (t.dat); - - #define TEST(KLASS) do { \ - auto computed = \ - util::hash::simple< \ - util::hash::KLASS \ - > (first, last); \ - \ + #define TEST(KLASS) do { \ + auto computed = util::hash::KLASS{}(util::view {t.dat}.template cast ()); \ tap.expect_eq (t.result.KLASS, computed, "%s: %s", #KLASS, t.msg); \ } while (0) diff --git a/test/hash/fasthash.cpp b/test/hash/fasthash.cpp index 300914ae..09624c91 100644 --- a/test/hash/fasthash.cpp +++ b/test/hash/fasthash.cpp @@ -3,6 +3,19 @@ #include + +/////////////////////////////////////////////////////////////////////////////// +std::vector +operator"" _u8s (const char *str, size_t len) +{ + std::vector res; + res.resize (len); + std::copy_n (str, len, std::begin (res)); + return res; +} + + +/////////////////////////////////////////////////////////////////////////////// int main (void) { @@ -13,23 +26,26 @@ main (void) uint32_t hash32; uint64_t seed64; uint64_t hash64; - const char *str; + std::vector data; } TESTS[] = { - { 0x00000000, 0x00000000, 0x0000000000000000, 0x0000000000000000, "" }, - { 0x00000001, 0xd30ac4de, 0x0000000000000001, 0x2127599bf4321e79, "" }, - { 0xffffffff, 0xf5c7b4b0, 0xffffffffffffffff, 0x9b4792000001368f, "" }, - { 0xf5c7b4b0, 0x228128b7, 0x9b4792000001368f, 0x67a642098cc81da6, "a" }, - { 0x228128b7, 0x8400568d, 0x67a642098cc81da6, 0xc906440e03ce99a8, "abc" }, - { 0x8400568d, 0x12b4858b, 0x67a642098cc81da6, 0x1a36fbf3d71b0737, "message digest" }, - { 0x12b4858b, 0x730b822e, 0x1a36fbf3d71b0737, 0x7b48e31e3ac40a0f, "abcdefghijklmnopqrstuvwxyz" }, + { 0x00000000, 0x00000000, 0x0000000000000000, 0x0000000000000000, ""_u8s }, + { 0x00000001, 0xd30ac4de, 0x0000000000000001, 0x2127599bf4321e79, ""_u8s }, + { 0xffffffff, 0xf5c7b4b0, 0xffffffffffffffff, 0x9b4792000001368f, ""_u8s }, + { 0xf5c7b4b0, 0x228128b7, 0x9b4792000001368f, 0x67a642098cc81da6, "a"_u8s }, + { 0x228128b7, 0x8400568d, 0x67a642098cc81da6, 0xc906440e03ce99a8, "abc"_u8s }, + { 0x8400568d, 0x12b4858b, 0x67a642098cc81da6, 0x1a36fbf3d71b0737, "message digest"_u8s }, + { 0x12b4858b, 0x730b822e, 0x1a36fbf3d71b0737, 0x7b48e31e3ac40a0f, "abcdefghijklmnopqrstuvwxyz"_u8s }, }; bool success32 = true; bool success64 = true; + util::hash::fasthash h32{}; + util::hash::fasthash h64{}; + for (const auto &t: TESTS) { - success32 = success32 && t.hash32 == util::hash::fasthash::hash32 (t.str, strlen (t.str), t.seed32); - success64 = success64 && t.hash64 == util::hash::fasthash::hash64 (t.str, strlen (t.str), t.seed64); + success32 = success32 && t.hash32 == h32 (t.seed32, t.data); + success64 = success64 && t.hash64 == h64 (t.seed64, t.data); } tap.expect (success32, "fasthash32"); diff --git a/test/hash/fnv1a.cpp b/test/hash/fnv1a.cpp new file mode 100644 index 00000000..06ff28ea --- /dev/null +++ b/test/hash/fnv1a.cpp @@ -0,0 +1,32 @@ +#include "hash/fnv1a.hpp" +#include "tap.hpp" + + +/////////////////////////////////////////////////////////////////////////////// +static const struct { + uint32_t h32; + uint64_t h64; + const char *data; +} TESTS[] = { + { 0x811c9dc5, 0xcbf29ce484222325, "" }, + { 0xe40c292c, 0xaf63dc4c8601ec8c, "a" }, + { 0xbf9cf968, 0x85944171f73967e8, "foobar" }, +}; + + +/////////////////////////////////////////////////////////////////////////////// +int +main (void) +{ + util::TAP::logger tap; + + const util::hash::fnv1a h32; + const util::hash::fnv1a h64; + + for (const auto &t: TESTS) { + tap.expect_eq (h32 (util::view{t.data}.cast ()), t.h32, "fnv1a32: '%s'", t.data); + tap.expect_eq (h64 (util::view{t.data}.cast ()), t.h64, "fnv1a64: '%s'", t.data); + } + + return tap.status (); +} \ No newline at end of file diff --git a/test/hash/hmac.cpp b/test/hash/hmac.cpp index c75afa6a..bf1360b3 100644 --- a/test/hash/hmac.cpp +++ b/test/hash/hmac.cpp @@ -28,11 +28,8 @@ test_hmac (const std::vector &key, const std::vector &dat, const std::vector &res) { - util::hash::HMAC h (key.data (), key.size ()); - h.update (dat.data (), dat.size ()); - h.finish (); - - auto ours = h.digest (); + util::hash::HMAC h (key); + const auto ours = h (dat); return std::equal (ours.begin (), ours.end (), res.begin ()); } @@ -49,7 +46,7 @@ static const struct { std::vector res; test_func fun; } TESTS[] = { - // RFC 2104 test data, MD5 + // 1: RFC 2104 test data, MD5 { { 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b }, @@ -59,6 +56,7 @@ static const struct { &test_hmac }, + // 2: { to_vector ("Jefe"), to_vector ("what do ya want for nothing?"), @@ -67,6 +65,7 @@ static const struct { &test_hmac }, + // 3: { { 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA }, @@ -82,7 +81,7 @@ static const struct { &test_hmac }, - // RFC 2202 test data, MD5 + // 4: RFC 2202 test data, MD5 { { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, @@ -100,6 +99,7 @@ static const struct { &test_hmac }, + // 5: { { 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c }, @@ -110,6 +110,7 @@ static const struct { // digest-96: 0x56461ef2342edc00f9bab995 }, + // 6: { { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, @@ -127,6 +128,7 @@ static const struct { &test_hmac }, + // 7: { { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, @@ -144,7 +146,7 @@ static const struct { &test_hmac }, - // RFC 2202 test data, SHA1 + // 8: RFC 2202 test data, SHA1 { { 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, diff --git a/test/hash/keccak.cpp b/test/hash/keccak.cpp deleted file mode 100644 index 24f938d8..00000000 --- a/test/hash/keccak.cpp +++ /dev/null @@ -1,180 +0,0 @@ -#include "hash/keccak.hpp" -#include "debug.hpp" -#include "tap.hpp" - -#include -#include - - -static constexpr -uint8_t -from_hex (char c) { - switch (c) { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - return c - '0'; - - case 'A': - case 'B': - case 'C': - case 'D': - case 'E': - case 'F': - return 10 + c - 'A'; - - case 'a': - case 'b': - case 'c': - case 'd': - case 'e': - case 'f': - return 10 + c - 'a'; - } - - unreachable (); -} - - -template -static constexpr -std::array -make_array (const char (&str)[S]) -{ - if (S < 1) - return {}; - - static_assert (S % 2 == 1, "requires full bytes + null"); - std::array out {}; - - for (size_t i = 0; i < S - 1; i+=2) { - out[i / 2] = +from_hex (str[i]) << 4 | +from_hex (str[i+1]); - } - - return out; -} - - -template -static -std::vector -make_vector (const char (&str)[S]) { - const auto arr = make_array (str); - return std::vector (arr.cbegin (), arr.cend ()); -} - - -int -main (int, char**) -{ - util::TAP::logger tap; - - static const struct { - const char *msg; - std::vector data; - - std::array sha3_224; - std::array sha3_256; - std::array sha3_384; - std::array sha3_512; - } TESTS[] = { - { - " empty string", - { }, - make_array ("6B4E03423667DBB73B6E15454F0EB1ABD4597F9A1B078E3F5B5A6BC7"), - make_array ("A7FFC6F8BF1ED76651C14756A061D662F580FF4DE43B49FA82D80A4B80F8434A"), - make_array ("0C63A75B845E4F7D01107D852E4C2485C51A50AAAA94FC61995E71BBEE983A2AC3713831264ADB47FB6BD1E058D5F004"), - make_array ("A69F73CCA23A9AC5C8B567DC185A756E97C982164FE25859E0D1DCC1475C80A615B2123AF1F5F94C11E3E9402C3AC558F500199D95B6D3E301758586281DCD26"), - }, - { - " 8-bit string", - make_vector ("CC"), - make_array ("DF70ADC49B2E76EEE3A6931B93FA41841C3AF2CDF5B32A18B5478C39"), - make_array ("677035391CD3701293D385F037BA32796252BB7CE180B00B582DD9B20AAAD7F0"), - make_array ("5EE7F374973CD4BB3DC41E3081346798497FF6E36CB9352281DFE07D07FC530CA9AD8EF7AAD56EF5D41BE83D5E543807"), - make_array ("3939FCC8B57B63612542DA31A834E5DCC36E2EE0F652AC72E02624FA2E5ADEECC7DD6BB3580224B4D6138706FC6E80597B528051230B00621CC2B22999EAA205"), - }, - { - " 16-bit string", - make_vector ("41FB"), - make_array ("BFF295861DAEDF33E70519B1E2BCB4C2E9FE3364D789BC3B17301C15"), - make_array ("39F31B6E653DFCD9CAED2602FD87F61B6254F581312FB6EEEC4D7148FA2E72AA"), - make_array ("1DD81609DCC290EFFD7AC0A95D4A20821580E56BD50DBD843920650BE7A80A1719577DA337CFDF86E51C764CAA2E10BD"), - make_array ("AA092865A40694D91754DBC767B5202C546E226877147A95CB8B4C8F8709FE8CD6905256B089DA37896EA5CA19D2CD9AB94C7192FC39F7CD4D598975A3013C69"), - }, - { - "224-bit string", - make_vector ("0F8B2D8FCFD9D68CFFC17CCFB117709B53D26462A3F346FB7C79B85E"), - make_array ("1E693B0BCE2372550DAEF35B14F13AB43441ED6742DEE3E86FD1D8EF"), - make_array ("6DE164A9626D5A4F54D854AC158994F35A8E362ECC753F55182790934A2E0D06"), - make_array ("641A7AF13B889D1A0F1AA3E4E4FF8CC5903C47E1A52BDEA257D80E37E596564AB33EEAD06717CDB6B706CB6986293D4F"), - make_array ("21132FC11F6040AD493D627027C752CE29816589DE7BE78562914B63D1A9219803DDBD9673AA749F37FF4D6E1B5AE2A12633BA8B0C9994E031EBF6C42E58A793"), - }, - { - "256-bit string", - make_vector ("9F2FCC7C90DE090D6B87CD7E9718C1EA6CB21118FC2D5DE9F97E5DB6AC1E9C10"), - make_array ("887921848AD98458F3DB3E0ECD5AD5DB1F0BF9F2D0CA08601074D597"), - make_array ("2F1A5F7159E34EA19CDDC70EBF9B81F1A66DB40615D7EAD3CC1F1B954D82A3AF"), - make_array ("BAAE7AAED4FBF42F9316C7E8F722EEB06A598B509F184B22FBD5A81C93D95FFF711F5DE90847B3248B6DF76CABCE07EE"), - make_array ("B087C90421AEBF87911647DE9D465CBDA166B672EC47CCD4054A7135A1EF885E7903B52C3F2C3FE722B1C169297A91B82428956A02C631A2240F12162C7BC726"), - }, - { - "384-bit string", - make_vector ("D8FABA1F5194C4DB5F176FABFFF856924EF627A37CD08CF55608BBA8F1E324D7C7F157298EABC4DCE7D89CE5162499F9"), - make_array ("B7A51FBB084DEEB55136EFD7260E5B112E3C40D1A2D14B142DF930DF"), - make_array ("34F8607EC10C092C1BA0B6565CE6197062C4E1A35A8E8C723E48A2D2416C3790"), - make_array ("A127FEFCDD240F762CCE3F5F1551FC7E1CDEBC7950D1CD94C6888F490CB2285A10FD0EE797B168C5CA4761FA232AAF05"), - make_array ("7EF3A2894C6ECBC4201B15348F90671515ACCBA3C8166621F864A9184BF08C3F5A895F6B599D3CB41F20A8A1DF25AE84F1A6D7C8DE74FB7CEF48F7E96FDE8D43"), - }, - { - "512-bit string", - make_vector ("E926AE8B0AF6E53176DBFFCC2A6B88C6BD765F939D3D178A9BDE9EF3AA131C61E31C1E42CDFAF4B4DCDE579A37E150EFBEF5555B4C1CB40439D835A724E2FAE7"), - make_array ("C154607F986F9BF902D831293C8386D36B201EABA6F6FB0B678B4B81"), - make_array ("27A6441EE939B46E2C378D7AFEB0E891C47A28120E488EFF0AB71AF08788CEB3"), - make_array ("423BA134D3BCB5E440AC83372C7EDDBA3AE3BDDF1222F505C19CDE246AD76A2B0D07239A54E1D0934C9B3D29D49E5FBD"), - make_array ("EB5067BF762A291CF258AD69A816A0B089E0BD44F8E5B74CF60BCE64734E59853CCB8D091CD2E33F90AA063FB7942CF5965D459200144C1A0801ABD69A9A094A"), - }, - { - "520-bit string", - make_vector ("16E8B3D8F988E9BB04DE9C96F2627811C973CE4A5296B4772CA3EEFEB80A652BDF21F50DF79F32DB23F9F73D393B2D57D9A0297F7A2F2E79CFDA39FA393DF1AC00"), - make_array ("95E87AC90F541AB90CBCF7FD7E0E0C152CEF78D5EE1830E9ED8A1ED7"), - make_array ("C4BB067383002DB44CA773918BB74104B604A583E12B06BE56C270F8B43512F2"), - make_array ("662C4851D311A786DE4CDA7E9EA1EFF0BFA462761FF6CF804E591ED9A15B0DC93A2BB6A6CFFDC8D7D23A233A52C86EAD"), - make_array ("B0E23D600BA4215F79D50047BBFED50DF7D6E769514D796AFD166DEECA88BD1CBE0AFC72A41E0317A223225B4F5882F723AFCBA3AF7C457EB525946DA6C53BB0"), - }, - { - "1,000,000 'a' string", - std::vector (1'000'000, 'a'), - make_array ("d69335b93325192e516a912e6d19a15cb51c6ed5c15243e7a7fd653c"), - make_array ("5c8875ae474a3634ba4fd55ec85bffd661f32aca75c6d699d0cdcb6c115891c1"), - make_array ("eee9e24d78c1855337983451df97c8ad9eedf256c6334f8e948d252d5e0e76847aa0774ddb90a842190d2c558b4b8340"), - make_array ("3c3a876da14034ab60627c077bb98f7e120a2a5370212dffb3385a18d4f38859ed311d0a9d5141ce9cc5c66ee689b266a8aa18ace8282a0e0db596c90b0a7b87"), - } - }; - - for (const auto &t: TESTS) { - #define TEST(WIDTH) \ - do { \ - std::array sha3_##WIDTH; \ - std::fill (std::begin (sha3_##WIDTH), std::end (sha3_##WIDTH), 0); \ - \ - FIPS202_SHA3_##WIDTH (t.data.data (), t.data.size (), &sha3_##WIDTH[0]); \ - \ - tap.expect_eq (t.sha3_##WIDTH, sha3_##WIDTH, "sha3-%u %s", unsigned (WIDTH), t.msg); \ - } while (0) - - TEST(224); - TEST(256); - TEST(384); - TEST(512); - } - - return tap.status (); -} diff --git a/test/hash/md2.cpp b/test/hash/md2.cpp index 2a4dbed3..cdadb4bd 100644 --- a/test/hash/md2.cpp +++ b/test/hash/md2.cpp @@ -46,13 +46,9 @@ main (int, char **) { bool success = true; + const MD2 h; for (const auto &i: TESTS) { - MD2 h; - h.update (i.input, strlen (i.input)); - h.finish (); - auto out = h.digest (); - - if (out != i.output) { + if (h (util::view{i.input}.cast ()) != i.output) { std::cerr << "Failed on " << i.input << "\n"; success = false; } diff --git a/test/hash/md4.cpp b/test/hash/md4.cpp index a0cdd607..44426b03 100644 --- a/test/hash/md4.cpp +++ b/test/hash/md4.cpp @@ -54,13 +54,9 @@ main (int, char**) { bool success = true; + MD4 h; for (auto i: TESTS) { - MD4 h; - h.update (i.input, strlen (i.input)); - h.finish (); - auto out = h.digest (); - - if (out != i.output) { + if (h (util::view{i.input}.cast ()) != i.output) { std::cerr << "Failed on '" << i.input << "'\n"; success = false; } diff --git a/test/hash/md5.cpp b/test/hash/md5.cpp index 641dcd98..03f0df1d 100644 --- a/test/hash/md5.cpp +++ b/test/hash/md5.cpp @@ -7,57 +7,87 @@ using util::hash::MD5; + +/////////////////////////////////////////////////////////////////////////////// +std::vector +operator"" _u8s (const char *str, size_t len) +{ + std::vector res; + res.resize (len); + std::copy_n (str, len, std::begin (res)); + return res; +} + + +/////////////////////////////////////////////////////////////////////////////// int main (int, char**) { static const struct { - const char *input; + std::vector input; MD5::digest_t output; + const char *msg; } TESTS[] = { - { "", + { {}, { { 0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04, - 0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e } } + 0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e } }, + "empty" }, - { "a", + { "a"_u8s, { { 0x0c, 0xc1, 0x75, 0xb9, 0xc0, 0xf1, 0xb6, 0xa8, - 0x31, 0xc3, 0x99, 0xe2, 0x69, 0x77, 0x26, 0x61 } } + 0x31, 0xc3, 0x99, 0xe2, 0x69, 0x77, 0x26, 0x61 } }, + "1 byte" }, - { "abc", + { "abc"_u8s, { { 0x90, 0x01, 0x50, 0x98, 0x3c, 0xd2, 0x4f, 0xb0, - 0xd6, 0x96, 0x3f, 0x7d, 0x28, 0xe1, 0x7f, 0x72 } } + 0xd6, 0x96, 0x3f, 0x7d, 0x28, 0xe1, 0x7f, 0x72 } }, + "3 bytes" }, - { "message digest", + { "message digest"_u8s, { { 0xf9, 0x6b, 0x69, 0x7d, 0x7c, 0xb7, 0x93, 0x8d, - 0x52, 0x5a, 0x2f, 0x31, 0xaa, 0xf1, 0x61, 0xd0 } } + 0x52, 0x5a, 0x2f, 0x31, 0xaa, 0xf1, 0x61, 0xd0 } }, + "14 bytes, text" }, - { "abcdefghijklmnopqrstuvwxyz", + { "abcdefghijklmnopqrstuvwxyz"_u8s, { { 0xc3, 0xfc, 0xd3, 0xd7, 0x61, 0x92, 0xe4, 0x00, - 0x7d, 0xfb, 0x49, 0x6c, 0xca, 0x67, 0xe1, 0x3b } } + 0x7d, 0xfb, 0x49, 0x6c, 0xca, 0x67, 0xe1, 0x3b } }, + "14 bytes, alphabet" }, - { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", + { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"_u8s, { { 0xd1, 0x74, 0xab, 0x98, 0xd2, 0x77, 0xd9, 0xf5, - 0xa5, 0x61, 0x1c, 0x2c, 0x9f, 0x41, 0x9d, 0x9f } } + 0xa5, 0x61, 0x1c, 0x2c, 0x9f, 0x41, 0x9d, 0x9f } }, + "62 bytes" + }, - { "12345678901234567890123456789012345678901234567890123456789012345678901234567890", + { "12345678901234567890123456789012345678901234567890123456789012345678901234567890"_u8s, { { 0x57, 0xed, 0xf4, 0xa2, 0x2b, 0xe3, 0xc9, 0x55, - 0xac, 0x49, 0xda, 0x2e, 0x21, 0x07, 0xb6, 0x7a } } + 0xac, 0x49, 0xda, 0x2e, 0x21, 0x07, 0xb6, 0x7a } }, + "80 bytes" } }; - bool success = true; + util::TAP::logger tap; - for (auto i: TESTS) { - MD5 h; - h.update (i.input, strlen (i.input)); - h.finish (); - auto out = h.digest (); + MD5 h; + for (const auto &t: TESTS) + tap.expect_eq (h (t.input), t.output, "%s", t.msg); - if (out != i.output) { - std::cerr << "Failed on '" << i.input << "'\n"; - success = false; - } + + // check that appending or prepending an empty data view doesn't change + // the hash for a couple of data lengths + for (auto l: { 0, 1, 8, 64, 80}) { + std::vector data (l); + std::iota (std::begin (data), std::end (data), 0); + tap.expect_eq (h (nullptr, data), h (data), "empty-full vs full hash equality, %! bytes", l); + tap.expect_eq (h (data, nullptr), h (data), "full-empty vs full hash equality, %! bytes", l); } - util::TAP::logger tap; - tap.expect (success, "test vectors"); + for (auto l: { 2, 64, 80}) { + std::vector data (l); + std::iota (std::begin (data), std::end (data), 0); + util::view root {data}; + auto [a,b] = root.split (root.begin () + l / 2); + tap.expect_eq (h (a,b), h(root), "split data hash equality, %! bytes", l); + }; + return tap.status (); } diff --git a/test/hash/murmur.cpp b/test/hash/murmur.cpp index 8a14553d..69761312 100644 --- a/test/hash/murmur.cpp +++ b/test/hash/murmur.cpp @@ -6,11 +6,35 @@ #include +/////////////////////////////////////////////////////////////////////////////// +std::vector +operator"" _u8s (const char *str, size_t len) +{ + std::vector res; + res.resize (len); + std::copy_n (str, len, std::begin (res)); + return res; +} + + +/////////////////////////////////////////////////////////////////////////////// +template +std::ostream& +operator<< (std::ostream &os, std::array &val) +{ + for (auto c: val) + os << c; + return os; +} + + +/////////////////////////////////////////////////////////////////////////////// void test (util::TAP::logger &tap) { struct { - const char *key; + std::vector data; + const char *msg; struct { uint32_t seed; uint32_t hash; } m1_32; struct { uint32_t seed; uint32_t hash; } m2_32; @@ -21,7 +45,8 @@ test (util::TAP::logger &tap) struct { uint32_t seed; std::array hash; } m3_128_x64; } TESTS[] = { - { "", + { ""_u8s, + "empty, zero seed", { 0, 0 }, { 0, 0 }, { 0, 0 }, @@ -30,7 +55,8 @@ test (util::TAP::logger &tap) { 0, 0 }, }, - { "", + { ""_u8s, + "empty, nonzero seed", { 0x00000001, 0x8f5a8d63 }, { 0x00000001, 0x5bd15e36 }, { 1, 0xc6a4a7935bd064dc }, @@ -39,7 +65,8 @@ test (util::TAP::logger &tap) { 1, { 0x4610abe56eff5cb5, 0x51622daa78f83583 } }, }, - { "", + { ""_u8s, + "empty, max seed", { 0xffffffff, 0x7a3f4f7e }, { 0xffffffff, 0xb35966b0 }, { uint64_t(-1), 0xb0d9485c2cd761b2 }, @@ -48,7 +75,8 @@ test (util::TAP::logger &tap) { 0xffffffff, { 0x6af1df4d9d3bc9ec, 0x857421121ee6446b } }, }, - { "a", + { "a"_u8s, + "1 byte", { 0x7a3f4f7e, 0x18abad09 }, { 0xb35966b0, 0x1eea8b10 }, { 0xb0d9485c2cd761b2, 0x0a9b4c93b35b1b9f }, @@ -56,7 +84,8 @@ test (util::TAP::logger &tap) { 0x051e08a9, { 0x08e91d27, 0x12c6d92a, 0x12c6d92a, 0x12c6d92a } }, { 0x9d3bc9ec, { 0xf79489c9f1a785de, 0xf6486d31835a9c7f } }, }, - { "abc", + { "abc"_u8s, + "3 byte", { 0x18abad09, 0x1defb5e9 }, { 0x1eea8b10, 0x72cac527 }, { 0x0a9b4c93b35b1b9f, 0x2ffdf3214d9a4fa4 }, @@ -64,7 +93,8 @@ test (util::TAP::logger &tap) { 0x08e91d27, { 0xc11cc883, 0xb5d7f69a, 0xb5d7f69a, 0xb5d7f69a } }, { 0xf1a785de, { 0x946e5ee63ce3b80e, 0xadb7d6d0e2558c3c } }, }, - { "message digest", + { "message digest"_u8s, + "14 byte", { 0x1defb5e9, 0x7b3ea4bd }, { 0x72cac527, 0x68563c37 }, { 0x2ffdf3214d9a4fa4, 0x9a83e79336350cee }, @@ -73,7 +103,8 @@ test (util::TAP::logger &tap) { 0x3ce3b80e, { 0x2c91b16326bf5f7f, 0xa21acf13c39485bc } }, }, - { "abcdefghijklmnopqrstuvwxyz", + { "abcdefghijklmnopqrstuvwxyz"_u8s, + "26 byte", { 0x7b3ea4bd, 0xd94ee9ea }, { 0x68563c37, 0x0473b699 }, { 0x9a83e79336350cee, 0x1f256c898952ae12 }, @@ -83,42 +114,29 @@ test (util::TAP::logger &tap) } }; - bool m1_32 = true; - bool m2_32 = true; - bool m2_64 = true; - bool m3_32 = true; - - bool m3_128_x86 = true; - bool m3_128_x64 = true; - for (const auto &t: TESTS) { - m1_32 = m1_32 && (t.m1_32.hash == util::hash::murmur1::hash_32 (t.key, strlen (t.key), t.m1_32.seed)); - m2_32 = m2_32 && (t.m2_32.hash == util::hash::murmur2::hash_32 (t.key, strlen (t.key), t.m2_32.seed)); - m2_64 = m2_64 && (t.m2_64.hash == util::hash::murmur2::hash_64 (t.key, strlen (t.key), t.m2_64.seed)); - m3_32 = m3_32 && (t.m3_32.hash == util::hash::murmur3::hash_32 (t.key, strlen (t.key), t.m3_32.seed)); + const util::hash::murmur1 h1 (t.m1_32.seed); - { - auto result = util::hash::murmur3::hash_128_x86 (t.key, strlen (t.key), t.m3_128_x86.seed); - bool success = t.m3_128_x86.hash == result; - m3_128_x86 = m3_128_x86 && success; - } + const util::hash::murmur2 h2_32 (t.m2_32.seed); + const util::hash::murmur2 h2_64 (t.m2_64.seed); - { - auto result = util::hash::murmur3::hash_128_x64 (t.key, strlen (t.key), t.m3_128_x64.seed); - bool success = t.m3_128_x64.hash == result; - m3_128_x64 = m3_128_x64 && success; - } + const util::hash::murmur3_32 h3 (t.m3_32.seed); + const util::hash::murmur3_128_x86 h3_x86 (t.m3_128_x86.seed); + const util::hash::murmur3_128_x64 h3_x64 (t.m3_128_x64.seed); + + tap.expect_eq (h1 (t.data), t.m1_32.hash, "murmur1_32, '%s'", t.msg); + tap.expect_eq (h2_32 (t.data), t.m2_32.hash, "murmur2_32, '%s'", t.msg); + tap.expect_eq (h2_64 (t.data), t.m2_64.hash, "murmur2_64, '%s'", t.msg); + + tap.expect_eq (h3 (t.data), t.m3_32.hash, "murmur3_32, '%s'", t.msg); + tap.expect_eq (h3_x86 (t.data), t.m3_128_x86.hash, "murmur3_128_x86, '%s'", t.msg); + tap.expect_eq (h3_x64 (t.data), t.m3_128_x64.hash, "murmur3_128_x64, '%s'", t.msg); } - - tap.expect (m1_32, "murmur1_32"); - tap.expect (m2_32, "murmur2_32"); - tap.expect (m2_64, "murmur2_64"); - tap.expect (m3_32, "murmur3_32"); - tap.expect (m3_128_x86, "murmur3_128_x86"); - tap.expect (m3_128_x64, "murmur3_128_x64"); } + +/////////////////////////////////////////////////////////////////////////////// int main (void) { diff --git a/test/hash/ripemd.cpp b/test/hash/ripemd.cpp index cc8f4d7c..de599f8b 100644 --- a/test/hash/ripemd.cpp +++ b/test/hash/ripemd.cpp @@ -5,15 +5,28 @@ #include + +/////////////////////////////////////////////////////////////////////////////// +std::vector +operator"" _u8s (const char *str, size_t len) +{ + std::vector res; + res.resize (len); + std::copy_n (str, len, std::begin (res)); + return res; +} + + +/////////////////////////////////////////////////////////////////////////////// static const struct { const char *msg; - const char *data; + std::vector data; util::hash::RIPEMD::digest_t output; } TESTS[] = { { "empty", - "", + ""_u8s, { 0x9c, 0x11, 0x85, 0xa5, 0xc5, 0xe9, 0xfc, 0x54, 0x61, 0x28, 0x08, 0x97, 0x7e, 0xe8, 0xf5, 0x48, 0xb2, 0x25, 0x8d, 0x31 }, // 128: cdf26213a150dc3ecb610f18f6b38b46 @@ -24,7 +37,7 @@ struct { { "a", - "a", + "a"_u8s, { 0x0b, 0xdc, 0x9d, 0x2d, 0x25, 0x6b, 0x3e, 0xe9, 0xda, 0xae, 0x34, 0x7b, 0xe6, 0xf4, 0xdc, 0x83, 0x5a, 0x46, 0x7f, 0xfe }, // 128: 86be7afa339d0fc7cfc785e72f578d33 @@ -35,7 +48,7 @@ struct { { "abc", - "abc", + "abc"_u8s, { 0x8e, 0xb2, 0x08, 0xf7, 0xe0, 0x5d, 0x98, 0x7a, 0x9b, 0x04, 0x4a, 0x8e, 0x98, 0xc6, 0xb0, 0x87, 0xf1, 0x5a, 0x0b, 0xfc }, // 128: c14a12199c66e4ba84636b0f69144c77 @@ -46,7 +59,7 @@ struct { { "message digest", - "message digest", + "message digest"_u8s, { 0x5d, 0x06, 0x89, 0xef, 0x49, 0xd2, 0xfa, 0xe5, 0x72, 0xb8, 0x81, 0xb1, 0x23, 0xa8, 0x5f, 0xfa, 0x21, 0x59, 0x5f, 0x36 }, // 128: 9e327b3d6e523062afc1132d7df9d1b8 @@ -57,7 +70,7 @@ struct { { "26 characters", - "abcdefghijklmnopqrstuvwxyz", + "abcdefghijklmnopqrstuvwxyz"_u8s, { 0xf7, 0x1c, 0x27, 0x10, 0x9c, 0x69, 0x2c, 0x1b, 0x56, 0xbb, 0xdc, 0xeb, 0x5b, 0x9d, 0x28, 0x65, 0xb3, 0x70, 0x8d, 0xbc }, // 128: fd2aa607f71dc8f510714922b371834e @@ -68,7 +81,7 @@ struct { { "57 characters", - "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"_u8s, { 0x12, 0xa0, 0x53, 0x38, 0x4a, 0x9c, 0x0c, 0x88, 0xe4, 0x05, 0xa0, 0x6c, 0x27, 0xdc, 0xf4, 0x9a, 0xda, 0x62, 0xeb, 0x2b }, // 128: a1aa0689d0fafa2ddc22e88b49133a06 @@ -79,7 +92,7 @@ struct { { "63 characters", - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"_u8s, { 0xb0, 0xe2, 0x0b, 0x6e, 0x31, 0x16, 0x64, 0x02, 0x86, 0xed, 0x3a, 0x87, 0xa5, 0x71, 0x30, 0x79, 0xb2, 0x1f, 0x51, 0x89 }, // 128: d1e959eb179c911faea4624c60c5c702 @@ -90,7 +103,7 @@ struct { { "81 digits", - "12345678901234567890123456789012345678901234567890123456789012345678901234567890", + "12345678901234567890123456789012345678901234567890123456789012345678901234567890"_u8s, { 0x9b, 0x75, 0x2e, 0x45, 0x57, 0x3d, 0x4b, 0x39, 0xf4, 0xdb, 0xd3, 0x32, 0x3c, 0xab, 0x82, 0xbf, 0x63, 0x32, 0x6b, 0xfb } // 128: 3f45ef194732c2dbb2c4a2c769795fa3 @@ -100,43 +113,33 @@ struct { } }; -// 1 million times "a" -// 128: 4a7f5723f954eba1216c9d8f6320431f -// 160: 52783243c1697bdbe16d37f97f68f08325dc1528 -// 256: ac953744e10e31514c150d4d8d7b677342e33399788296e43ae4850ce4f97978 -// 320: bdee37f4371e20646b8b0d862dda16292ae36f40965e8c8509e63d1dbddecc503e2b63eb9245bb66 int main(int, char**) { util::TAP::logger tap; // Check against simple test vectors - for (const auto &i: TESTS) { + for (const auto &t: TESTS) { util::hash::RIPEMD obj; - obj.update (reinterpret_cast (i.data), strlen (i.data)); - obj.finish (); - - tap.expect_eq (obj.digest (), i.output, "%s", i.msg); + tap.expect_eq (obj (t.data), t.output, "%s", t.msg); } // Perform 'million-a' check - static const size_t CHUNK_WIDTH = 1'000; util::hash::RIPEMD obj; - for (size_t i = 0; i < 1'000'000; i += CHUNK_WIDTH) { - uint8_t data[CHUNK_WIDTH]; - memset (data, 'a', sizeof (data)); + // 1 million times "a" + // 128: 4a7f5723f954eba1216c9d8f6320431f + // 160: 52783243c1697bdbe16d37f97f68f08325dc1528 + // 256: ac953744e10e31514c150d4d8d7b677342e33399788296e43ae4850ce4f97978 + // 320: bdee37f4371e20646b8b0d862dda16292ae36f40965e8c8509e63d1dbddecc503e2b63eb9245bb66 - obj.update (data, sizeof (data)); - } - - obj.finish (); + std::vector data (1'000'000, 'a'); static const util::hash::RIPEMD::digest_t MILLION { 0x52, 0x78, 0x32, 0x43, 0xc1, 0x69, 0x7b, 0xdb, 0xe1, 0x6d, 0x37, 0xf9, 0x7f, 0x68, 0xf0, 0x83, 0x25, 0xdc, 0x15, 0x28 }; - tap.expect_eq (obj.digest (), MILLION, "million 'a'"); + tap.expect_eq (obj (data), MILLION, "million 'a'"); return tap.status (); } diff --git a/test/hash/sha1.cpp b/test/hash/sha1.cpp index 5c4ee9b0..c0afd57d 100644 --- a/test/hash/sha1.cpp +++ b/test/hash/sha1.cpp @@ -10,6 +10,18 @@ #include +/////////////////////////////////////////////////////////////////////////////// +std::vector +operator"" _u8s (const char *str, size_t len) +{ + std::vector res; + res.resize (len); + std::copy_n (str, len, std::begin (res)); + return res; +} + + +/////////////////////////////////////////////////////////////////////////////// int main (int, char**) { @@ -17,43 +29,58 @@ main (int, char**) static const struct { const char *msg; - const char *input; + std::vector input; util::hash::SHA1::digest_t output; } TESTS[] = { { "empty string", - "", + ""_u8s, { { 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09 } } }, { "single a", - "a", + "a"_u8s, { { 0x86, 0xf7, 0xe4, 0x37, 0xfa, 0xa5, 0xa7, 0xfc, 0xe1, 0x5d, 0x1d, 0xdc, 0xb9, 0xea, 0xea, 0xea, 0x37, 0x76, 0x67, 0xb8 } } }, { "abc", - "abc", + "abc"_u8s, { { 0xA9, 0x99, 0x3E, 0x36, 0x47, 0x06, 0x81, 0x6A, 0xBA, 0x3E, 0x25, 0x71, 0x78, 0x50, 0xC2, 0x6C, 0x9C, 0xD0, 0xD8, 0x9D } } }, { "abc...opq", - "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"_u8s, { { 0x84, 0x98, 0x3E, 0x44, 0x1C, 0x3B, 0xD2, 0x6E, 0xBA, 0xAE, 0x4A, 0xA1, 0xF9, 0x51, 0x29, 0xE5, 0xE5, 0x46, 0x70, 0xF1 } } }, + { + "896 bit alphabet", + "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn" + "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"_u8s, + { 0xa4, 0x9b, 0x24, 0x46, + 0xa0, 0x2c, 0x64, 0x5b, + 0xf4, 0x19, 0xf9, 0x95, + 0xb6, 0x70, 0x91, 0x25, + 0x3a, 0x04, 0xa2, 0x59, } + } + // 1'000'000 * 'a' //{ "a", // { { 0x34, 0xAA, 0x97, 0x3C, 0xD4, 0xC4, 0xDA, 0xA4, 0xF6, 0x1E, // 0xEB, 0x2B, 0xDB, 0xAD, 0x27, 0x31, 0x65, 0x34, 0x01, 0x6F } } //}, + // 16'777'216 x "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmno" + // about 1GiB of text + // 7789f0c9 ef7bfc40 d9331114 3dfbe69e 2017f592 + // 80 repetitions of 01234567 //{ "0123456701234567012345670123456701234567012345670123456701234567", // { { 0xDE, 0xA3, 0x56, 0xA2, 0xCD, 0xDD, 0x90, 0xC7, 0xA7, 0xEC, @@ -61,12 +88,21 @@ main (int, char**) //} }; - for (const auto &i: TESTS) { - util::hash::SHA1 obj; - obj.update (reinterpret_cast (i.input), strlen (i.input)); - obj.finish (); + util::hash::SHA1 obj; - tap.expect_eq (obj.digest (), i.output, "%s", i.msg); + for (const auto &t: TESTS) + tap.expect_eq (obj (t.input), t.output, "%s", t.msg); + + { + std::vector data (1'000'000, 0x61); + util::hash::SHA1::digest_t result { + 0x34, 0xaa, 0x97, 0x3c, + 0xd4, 0xc4, 0xda, 0xa4, + 0xf6, 0x1e, 0xeb, 0x2b, + 0xdb, 0xad, 0x27, 0x31, + 0x65, 0x34, 0x01, 0x6f, + }; + tap.expect_eq (obj (data), result, "1'000'000 a's"); } return tap.status (); diff --git a/test/hash/sha2.cpp b/test/hash/sha2.cpp index 7a01f1c4..3c1be5ab 100644 --- a/test/hash/sha2.cpp +++ b/test/hash/sha2.cpp @@ -9,6 +9,7 @@ static const struct { const char *input; util::hash::SHA256::digest_t output; } TESTS[] = { + { "empty", "", @@ -52,10 +53,7 @@ main (int, char **) { for (const auto &i: TESTS) { util::hash::SHA256 obj; - obj.update (reinterpret_cast (i.input), strlen (i.input)); - obj.finish (); - - tap.expect_eq (obj.digest (), i.output, "%s", i.msg); + tap.expect_eq (obj (util::view{i.input}.cast ()), i.output, "%s", i.msg); } return tap.status (); diff --git a/test/hash/xxhash.cpp b/test/hash/xxhash.cpp index 5dc9663e..ad9b69a1 100644 --- a/test/hash/xxhash.cpp +++ b/test/hash/xxhash.cpp @@ -17,9 +17,21 @@ #include "tap.hpp" -#include "hash/simple.hpp" #include "hash/xxhash.hpp" + +/////////////////////////////////////////////////////////////////////////////// +std::vector +operator"" _u8s (const char *str, size_t len) +{ + std::vector res; + res.resize (len); + std::copy_n (str, len, std::begin (res)); + return res; +} + + +/////////////////////////////////////////////////////////////////////////////// int main (int, char **) { @@ -29,29 +41,27 @@ main (int, char **) uint32_t hash32; uint64_t hash64; unsigned seed; - std::string data; - std::string msg; + std::vector data; + const char *msg; } TESTS[] = { - { 0x02CC5D05, 0xef46db3751d8e999, 0, "", "empty string, 0 seed" }, - { 0x0b2cb792, 0xd5afba1336a3be4b, 1, "", "empty string, 1 seed" }, - { 0x550d7456, 0xd24ec4f1a98c6e5b, 0, "a", "single a, 0 seed" }, - { 0xf514706f, 0xdec2bc81c3cd46c6, 1, "a", "single a, 1 seed" }, - { 0x32d153ff, 0x44bc2cf5ad770999, 0, "abc", "abc, 0 seed" }, - { 0xaa3da8ff, 0xbea9ca8199328908, 1, "abc", "abc, 1 seed" }, + { 0x02CC5D05, 0xef46db3751d8e999, 0, ""_u8s, "empty string, 0 seed" }, + { 0x0b2cb792, 0xd5afba1336a3be4b, 1, ""_u8s, "empty string, 1 seed" }, + { 0x550d7456, 0xd24ec4f1a98c6e5b, 0, "a"_u8s, "single a, 0 seed" }, + { 0xf514706f, 0xdec2bc81c3cd46c6, 1, "a"_u8s, "single a, 1 seed" }, + { 0x32d153ff, 0x44bc2cf5ad770999, 0, "abc"_u8s, "abc, 0 seed" }, + { 0xaa3da8ff, 0xbea9ca8199328908, 1, "abc"_u8s, "abc, 1 seed" }, { 0x54ca7e46, 0x892a0760a6343391, 0x1234, - "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()_+", + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()_+"_u8s, "long alphabet" } }; + for (const auto &t: TESTS) { - auto first = t.data.data (); - auto last = first + t.data.size (); + util::hash::xxhash32 h32 (t.seed); + //util::hash::xxhash32 h64 (t.seed); - auto digest32 = util::hash::simple (first, last, t.seed); - //auto digest64 = util::hash::simple (first, last, t.seed); - - tap.expect_eq (digest32, t.hash32, "xxhash32 %s", t.msg); - //tap.expect_eq (digest64, t.hash64, "xxhash64 %s", t.msg); + tap.expect_eq (h32 (t.data), t.hash32, "xxhash32 %s", t.msg); + //tap.expect_eq (h64 (t.data), t.hash64, "xxhash64 %s", t.msg); } return tap.status (); diff --git a/time/parse8601.cpp.rl b/time/parse8601.cpp.rl index 2be47ac8..d0141781 100644 --- a/time/parse8601.cpp.rl +++ b/time/parse8601.cpp.rl @@ -97,7 +97,6 @@ to_epoch (const tm &t) // similar. in the future we can account for this CHECK_SANITY (t); - constexpr int cumulative_days [12] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 diff --git a/tools/hash.cpp b/tools/hash.cpp index 8596c52e..22b93121 100644 --- a/tools/hash.cpp +++ b/tools/hash.cpp @@ -22,8 +22,6 @@ #include "io.hpp" #include "stream.hpp" -#include "hash/simple.hpp" - #include "hash/adler.hpp" #include "hash/bsdsum.cpp" #include "hash/crc.hpp" @@ -74,34 +72,30 @@ print_digest (std::ostream &os, std::array digest) /////////////////////////////////////////////////////////////////////////////// -static -void -compute (const std::string &name, - const unsigned char *restrict first, - const unsigned char *restrict last) +static void +compute (const std::string &name, const util::view data) { - #define stream(TYPE, ...) do { \ - if (name != #TYPE) \ - break; \ - \ - auto sum = util::hash::simple ( \ - first, last, ##__VA_ARGS__ \ - ); \ - \ - print_digest (std::cout, sum) << '\n'; \ - return; \ + #define stream(TYPE, ...) do { \ + if (name != #TYPE) \ + break; \ + \ + print_digest ( \ + std::cout, \ + util::hash::TYPE{} (data) \ + ) << '\n'; \ + return; \ } while (0); stream (adler32); - stream (bsdsum); - stream (crc32); + //stream (bsdsum); + //stream (crc32); - stream (MD2); - stream (MD4); - stream (MD5); - stream (RIPEMD); - stream (SHA1); - stream (SHA256); + //stream (MD2); + //stream (MD4); + //stream (MD5); + //stream (RIPEMD); + //stream (SHA1); + //stream (SHA256); #undef stream } @@ -140,8 +134,8 @@ main (int argc, char **argv) } if (strcmp (argv[ARG_INPUT], "-")) { - util::mapped_file src (argv[ARG_INPUT]); - compute (argv[ARG_HASH], src.cbegin (), src.cend ()); + const util::mapped_file src (argv[ARG_INPUT]); + compute (argv[ARG_HASH], util::view{src}); return EXIT_SUCCESS; } else { diff --git a/tools/json-clean.cpp b/tools/json-clean.cpp index 5edbf9a0..0dd873de 100644 --- a/tools/json-clean.cpp +++ b/tools/json-clean.cpp @@ -51,7 +51,7 @@ main (int argc, char **argv) try { const util::mapped_file src (argv[ARG_INPUT]); - std::cout << *json::tree::parse (src.as_view ()) << '\n'; + std::cout << *json::tree::parse (util::view{src}.cast ()) << '\n'; } catch (const json::error& err) { std::cerr << err.what () << "\n"; return EXIT_FAILURE; diff --git a/tools/json-schema.cpp b/tools/json-schema.cpp index 6a61b224..cd8e67ce 100644 --- a/tools/json-schema.cpp +++ b/tools/json-schema.cpp @@ -50,8 +50,8 @@ main (int argc, char **argv) { const util::mapped_file schema_src (argv[ARG_SCHEMA]); const util::mapped_file input_src (argv[ARG_INPUT]); - auto schema = json::tree::parse (schema_src.as_view ()); - auto input = json::tree::parse (input_src.as_view ()); + auto schema = json::tree::parse (util::view{schema_src}.cast()); + auto input = json::tree::parse (util::view{input_src} .cast()); json::schema::validate (*input, schema->as_object ()); } catch (const json::error &e) { diff --git a/tools/json-validate.cpp b/tools/json-validate.cpp index f83e8b56..499d61b9 100644 --- a/tools/json-validate.cpp +++ b/tools/json-validate.cpp @@ -42,7 +42,7 @@ main (int argc, char ** argv) { try { const util::mapped_file data (argv[ARG_PATH]); - json::flat::parse (data.as_view ()); + json::flat::parse (util::view{data}.cast ()); } catch (const json::error &x) { std::cerr << "error: " << x.what () << '\n'; return EXIT_FAILURE; diff --git a/types/traits.hpp b/types/traits.hpp index 14cfd55e..265521c2 100644 --- a/types/traits.hpp +++ b/types/traits.hpp @@ -270,6 +270,29 @@ template using nth_argument_t = typename nth_argument::type; +/////////////////////////////////////////////////////////////////////////////// +template > +struct is_container : public std::false_type {}; + +template +struct is_container< + T, + std::void_t< + typename T::value_type, + typename T::reference, + typename T::const_reference, + typename T::iterator, + typename T::const_iterator, + typename T::difference_type, + typename T::size_type + > +> : public std::true_type {}; + + +template +constexpr auto is_container_v = is_container::value; + + /////////////////////////////////////////////////////////////////////////////// #include #include diff --git a/uri.hpp b/uri.hpp index 0480281d..66b3c25f 100644 --- a/uri.hpp +++ b/uri.hpp @@ -43,7 +43,7 @@ namespace util { public: explicit uri (std::string &&); explicit uri (const std::string&); - explicit uri (const char *str); + explicit uri (const char *); explicit uri (util::view); class parse_error : public std::runtime_error diff --git a/view.hpp b/view.hpp index 4fa7a60a..08e935f9 100644 --- a/view.hpp +++ b/view.hpp @@ -45,6 +45,23 @@ namespace util { m_end (last) { ; } + template < + typename ContainerT, + typename = std::enable_if_t>,void> + > + view (ContainerT &rhs): + view (rhs.begin (), rhs.end ()) + { ; } + + + template < + typename ContainerT, + typename = std::enable_if_t>,void> + > + view (const ContainerT &rhs): + view (rhs.begin (), rhs.end ()) + { ; } + //--------------------------------------------------------------------- // cosntruction from pointer/size represenations for ease of use with @@ -179,6 +196,20 @@ namespace util { { ; } + //--------------------------------------------------------------------- + template + view (std::array &rhs): + view (std::data (rhs), std::data (rhs) + std::size (rhs)) + { ; } + + + //--------------------------------------------------------------------- + template + view (const std::array &rhs): + view (std::data (rhs), std::data (rhs) + std::size (rhs)) + { ; } + + //--------------------------------------------------------------------- view& operator= (const view &rhs) noexcept @@ -253,11 +284,44 @@ namespace util { //--------------------------------------------------------------------- - util::view - operator- (util::view prefix) const + constexpr std::tuple< + util::view, + util::view + > + split (BeginT pos) { - assert (prefix.begin () == begin ()); - return { prefix.end (), end () }; + return { + { m_begin, pos }, + { pos, m_end } + }; + } + + + //--------------------------------------------------------------------- + constexpr auto + split (int pos) + { + auto last = m_begin; + std::advance (last, pos); + return split (last); + } + + + //--------------------------------------------------------------------- + constexpr auto + consume (int count) + { + auto [a,b] = split (count); + return b; + } + + + //--------------------------------------------------------------------- + constexpr util::view + consume (util::view val) + { + assert (val.begin () == begin ()); + return { val.end (), end () }; } @@ -321,7 +385,7 @@ namespace util { //------------------------------------------------------------------------- - view (const char*) -> view; + view (const char*) -> view; view (char*) -> view; @@ -351,6 +415,20 @@ namespace util { template view (const std::vector&) -> view; + template + view (std::array) -> view; + + template + view (ContainerT&) -> view< + typename ContainerT::iterator + >; + + template + view (const ContainerT&) -> view< + typename ContainerT::const_iterator + >; + + /////////////////////////////////////////////////////////////////////////// template