Stroika Library 3.0d18
 
Loading...
Searching...
No Matches
SuperFastHash.cpp
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 *
4 * Copyright(c) 2004-2008 by Paul Hsieh
5 * PARTS OF THIS CODE MAYBE COVERED BY http://www.gnu.org/licenses/lgpl-2.1.txt - See
6 * http://www.azillionmonkeys.com/qed/hash.html
7 */
8#include "Stroika/Foundation/StroikaPreComp.h"
9
11
12#include "SuperFastHash.h"
13
14using std::byte;
15
16using namespace Stroika::Foundation;
17using namespace Stroika::Foundation::Cryptography;
18using namespace Stroika::Foundation::Cryptography::Digest;
19
20namespace {
21 inline uint16_t get16bits_ (const byte* p)
22 {
24 uint16_t result;
25 switch (Common::GetEndianness ()) {
26 case Common::Endian::eLittle:
27 (void)::memcpy (&result, p, 2);
28 break;
29 case Common::Endian::eBig:
30 result = (to_integer<uint16_t> (p[1]) << 8) + to_integer<uint16_t> (p[0]);
31 break;
32 default:
34 result = 0;
35 }
36 return result;
37 }
38}
39
40/*
41 ********************************************************************************
42 ************ Algorithm::DigesterAlgorithm<Algorithm::SuperFastHash> ************
43 ********************************************************************************
44 */
45void Algorithm::DigesterAlgorithm<Algorithm::SuperFastHash>::Write (const byte* start, const byte* end)
46{
47#if qStroika_Foundation_Debug_AssertionsChecked
48 Require (not fCompleted_);
49#endif
50 /*
51 * Require() here cuz of following cast.
52 * NB: apparently broken if large data input! > 4gig on 64bit machine.
53 * But this still produces a reasonable hashed result, and this misfeature
54 * of ignoring higher order bits appears implied by the reference algorithm
55 * on http://www.azillionmonkeys.com/qed/hash.html
56 */
57 size_t len = static_cast<size_t> (end - start);
58 Require (len < numeric_limits<uint32_t>::max ());
59
60 fRemainder_ += static_cast<uint32_t> (len);
61 fRemainder_ &= 0x3; // old code just did fRemainder_ = len & 3, but we now get len in bits and pieces
62 Assert (0 <= fRemainder_ && fRemainder_ <= 3);
63
64 const byte* data = start;
65
66 len >>= 2;
67
68 auto hash = fHash_;
69 /* Main loop */
70 for (; len > 0; len--) {
71 hash += get16bits_ (data);
72 uint32_t tmp = (get16bits_ (data + 2) << 11) ^ hash;
73 hash = (hash << 16) ^ tmp;
74 data += 2 * sizeof (uint16_t);
75 hash += hash >> 11;
76 }
77 fHash_ = hash;
78 Assert (0 <= fRemainder_ and fRemainder_ <= 3);
79 copy (data, data + fRemainder_, fFinalBytes_.data ());
80}
81
83{
84#if qStroika_Foundation_Debug_AssertionsChecked
85 Require (not fCompleted_);
86 fCompleted_ = true;
87#endif
88 const byte* data = &fFinalBytes_[0];
89 auto hash = fHash_;
90 /* Handle end cases */
91 switch (fRemainder_) {
92 case 3:
93 hash += get16bits_ (data);
94 hash ^= hash << 16;
95 hash ^= ((signed char)data[sizeof (uint16_t)]) << 18;
96 hash += hash >> 11;
97 break;
98 case 2:
99 hash += get16bits_ (data);
100 hash ^= hash << 11;
101 hash += hash >> 17;
102 break;
103 case 1:
104 hash += (signed char)*data;
105 hash ^= hash << 10;
106 hash += hash >> 1;
107 }
108
109 /* Force "avalanching" of final 127 bits */
110 hash ^= hash << 3;
111 hash += hash >> 5;
112 hash ^= hash << 4;
113 hash += hash >> 17;
114 hash ^= hash << 25;
115 hash += hash >> 6;
116
117 return hash;
118}
#define RequireNotNull(p)
Definition Assertions.h:347
#define AssertNotReached()
Definition Assertions.h:355
DigesterAlgorithm is specialized for each algorithm; generally don't use this directly,...
Definition Algorithm.h:55
constexpr Endian GetEndianness()
returns native (std::endian::native) Endianness flag. Can be complicated (mixed, etc)....
Definition Endian.inl:25