Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
Hash.inl
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#include <type_traits>
5
6#include "Stroika/Foundation/Cryptography/Digest/ResultTypes.h"
7#include "Stroika/Foundation/Cryptography/Format.h"
8
9namespace Stroika::Foundation::Cryptography::Digest {
10
11 /*
12 ********************************************************************************
13 ***************************** SystemHashDigester<T> ****************************
14 ********************************************************************************
15 */
16 template <typename T>
17 size_t SystemHashDigester<T>::operator() (const Streams::InputStream::Ptr<byte>& from) const
18 {
19 Memory::BLOB b = from.ReadAll ();
20 return this->operator() (b.begin (), b.end ());
21 }
22 template <typename T>
23 inline size_t SystemHashDigester<T>::operator() (const byte* from, const byte* to) const
24 {
25 Require (to - from == sizeof (T));
26 return hash<T>{}(*reinterpret_cast<const T*> (from));
27 }
28 template <typename T>
29 inline size_t SystemHashDigester<T>::operator() (const BLOB& from) const
30 {
31 return this->operator() (from.begin (), from.end ());
32 }
33
34 /*
35 ********************************************************************************
36 ********************** Cryptography::Digest::Hash<T> ***************************
37 ********************************************************************************
38 */
39 template <typename T, typename DIGESTER, typename HASH_RETURN_TYPE, typename SERIALIZER>
40 constexpr inline Hash<T, DIGESTER, HASH_RETURN_TYPE, SERIALIZER>::Hash (const T& seed)
41 : fSeed{nullopt}
42 {
43 // NOTE - if not for support of SystemHashDigester<> - which combines hashing with digesting in one -
44 // we could do fSeed{DIGESTER{}(CONVERT_T_2_DIGEST_ARG{}(seed))} and skip this re-assignment
45 fSeed = (*this) (seed); // OK to call now with no seed set
46 }
47 template <typename T, typename DIGESTER, typename HASH_RETURN_TYPE, typename SERIALIZER>
48 inline HASH_RETURN_TYPE Hash<T, DIGESTER, HASH_RETURN_TYPE, SERIALIZER>::operator() (const T& t) const
49 {
50 HASH_RETURN_TYPE result;
51 if constexpr (same_as<DIGESTER, SystemHashDigester<T>> or same_as<DIGESTER, hash<T>>) {
52 result = hash<T>{}(t);
53 }
54 else {
55 result = ConvertResult<HASH_RETURN_TYPE> (DIGESTER{}(SERIALIZER{}(t)));
56 }
57 if (fSeed) {
58 result = HashValueCombine (*fSeed, result);
59 }
60 return result;
61 }
62
63 /*
64 ********************************************************************************
65 ****************** Cryptography::Digest::HashValueCombine **********************
66 ********************************************************************************
67 */
68 namespace Private_ {
69 // @todo VERY WEAK impl - of template matching - but good enuf for now - really want to use concept to see if << defined and returns same type
70 template <typename RESULT_TYPE>
71 inline RESULT_TYPE HashValueCombine (RESULT_TYPE lhs, RESULT_TYPE rhs)
72 {
73 if constexpr (is_arithmetic_v<RESULT_TYPE> or same_as<RESULT_TYPE, byte>) {
74 // inspired by https://en.cppreference.com/w/cpp/utility/hash - return h1 ^ (h2 << 1); // or use boost::hash_combine
75 return lhs ^ (rhs << 1); // don't simply XOR, I think, because this would be symetric and produce zero if lhs==rhs
76 }
77 else {
78 RESULT_TYPE result = lhs;
79 auto i = result.begin ();
80 auto ri = rhs.begin ();
81 while (i != result.end () and ri != rhs.end ()) {
82 *i = HashValueCombine (*i, *ri);
83 ++i;
84 ++ri;
85 }
86 // e.g. if lhs empty, result sb rhs, so we always look at all chars of both sides
87 // @todo if constexpr check if has append!!!
88 if constexpr (same_as<RESULT_TYPE, string>) {
89 while (ri != rhs.end ()) {
90 result += *ri;
91 ++ri;
92 }
93 }
94 return result;
95 }
96 }
97 }
98 template <typename RESULT_TYPE>
99 inline RESULT_TYPE HashValueCombine (RESULT_TYPE lhs, RESULT_TYPE rhs)
100 {
101 if constexpr (same_as<RESULT_TYPE, Common::GUID>) {
102 auto l = lhs.template As<array<uint8_t, 16>> ();
103 auto r = lhs.template As<array<uint8_t, 16>> ();
104 return RESULT_TYPE{Private_::HashValueCombine (l, r)};
105 }
106 else {
107 return Private_::HashValueCombine (lhs, rhs);
108 }
109 }
110
111}