/src/WasmEdge/lib/common/hash.cpp
Line | Count | Source |
1 | | #include "common/hash.h" |
2 | | |
3 | | #include <array> |
4 | | #include <cstring> |
5 | | |
6 | | namespace { |
7 | | |
8 | | using namespace WasmEdge; |
9 | | |
10 | | // rapidhash v3 secrets — only the 4 used by the Nano variant. |
11 | | // Indices match upstream rapid_secret[]: [0], [1], [2], [7]. |
12 | | static constexpr std::array<uint64_t, 4> Secret = { |
13 | | 0x2d358dccaa6c78a5ull, // rapid_secret[0] |
14 | | 0x8bb84b93962eacc9ull, // rapid_secret[1] |
15 | | 0x4b33a62ed433d4a3ull, // rapid_secret[2] |
16 | | 0xaaaaaaaaaaaaaaaaull, // rapid_secret[7] |
17 | | }; |
18 | | |
19 | | static const uint64_t RandomSeed = Hash::RandEngine(); |
20 | | |
21 | | // Intentional: assumes little-endian. Trades platform-independent hash |
22 | | // values for speed by skipping byte-swap on big-endian targets. |
23 | 4.07M | inline uint64_t read(Span<const std::byte, 8> Data) noexcept { |
24 | 4.07M | uint64_t V; |
25 | 4.07M | std::memcpy(&V, Data.data(), 8); |
26 | 4.07M | return V; |
27 | 4.07M | } |
28 | 24.5k | inline uint64_t read(Span<const std::byte, 4> Data) noexcept { |
29 | 24.5k | uint32_t V; |
30 | 24.5k | std::memcpy(&V, Data.data(), 4); |
31 | 24.5k | return V; |
32 | 24.5k | } |
33 | | |
34 | | } // namespace |
35 | | |
36 | | namespace WasmEdge::Hash { |
37 | | |
38 | 574k | WASMEDGE_EXPORT uint64_t Hash::rapidHash(Span<const std::byte> Data) noexcept { |
39 | 574k | uint64_t Seed = RandomSeed; |
40 | 574k | Seed ^= rapidMix(Seed ^ Secret[2], Secret[1]); |
41 | 574k | uint64_t A = 0, B = 0; |
42 | 574k | if (likely(Data.size() <= 16)) { |
43 | 547k | if (Data.size() >= 4) { |
44 | 102k | Seed ^= Data.size(); |
45 | 102k | if (Data.size() >= 8) { |
46 | 90.5k | A = read(Data.first<8>()); |
47 | 90.5k | B = read(Data.last<8>()); |
48 | 90.5k | } else { |
49 | 12.2k | A = read(Data.first<4>()); |
50 | 12.2k | B = read(Data.last<4>()); |
51 | 12.2k | } |
52 | 444k | } else if (Data.size() > 0) { |
53 | 444k | A = (static_cast<uint64_t>(Data[0]) << 45) | |
54 | 444k | static_cast<uint64_t>(Data[Data.size() - 1]); |
55 | 444k | B = static_cast<uint64_t>(Data[Data.size() >> 1]); |
56 | 444k | } else { |
57 | 65 | A = B = 0; |
58 | 65 | } |
59 | 547k | } else { |
60 | 26.8k | if (Data.size() > 48) { |
61 | 245 | uint64_t See1 = Seed, See2 = Seed; |
62 | 630k | do { |
63 | 630k | Seed = rapidMix(read(Data.first<8>()) ^ Secret[0], |
64 | 630k | read(Data.subspan<8>().first<8>()) ^ Seed); |
65 | 630k | See1 = rapidMix(read(Data.subspan<16>().first<8>()) ^ Secret[1], |
66 | 630k | read(Data.subspan<24>().first<8>()) ^ See1); |
67 | 630k | See2 = rapidMix(read(Data.subspan<32>().first<8>()) ^ Secret[2], |
68 | 630k | read(Data.subspan<40>().first<8>()) ^ See2); |
69 | 630k | Data = Data.subspan<48>(); |
70 | 630k | } while (Data.size() > 48); |
71 | 245 | Seed ^= See1; |
72 | 245 | Seed ^= See2; |
73 | 245 | } |
74 | 26.8k | if (Data.size() > 16) { |
75 | 26.7k | Seed = rapidMix(read(Data.first<8>()) ^ Secret[2], |
76 | 26.7k | read(Data.subspan<8>().first<8>()) ^ Seed); |
77 | 26.7k | if (Data.size() > 32) { |
78 | 2.08k | Seed = rapidMix(read(Data.subspan<16>().first<8>()) ^ Secret[2], |
79 | 2.08k | read(Data.subspan<24>().first<8>()) ^ Seed); |
80 | 2.08k | } |
81 | 26.7k | } |
82 | 26.8k | A = read(Data.last<16>().first<8>()) ^ Data.size(); |
83 | 26.8k | B = read(Data.last<8>()); |
84 | 26.8k | } |
85 | 574k | A ^= Secret[1]; |
86 | 574k | B ^= Seed; |
87 | 574k | rapidMum(A, B); |
88 | 574k | return rapidMix(A ^ Secret[3], B ^ Secret[1] ^ Data.size()); |
89 | 574k | } |
90 | | |
91 | | } // namespace WasmEdge::Hash |