Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
Digester.h
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#ifndef _Stroika_Foundation_Cryptography_Digest_Digester_h_
5#define _Stroika_Foundation_Cryptography_Digest_Digester_h_ 1
6
7#include "Stroika/Foundation/StroikaPreComp.h"
8
9#include <cstdint>
10
11#include "Stroika/Foundation/Common/Common.h"
12#include "Stroika/Foundation/Cryptography/Digest/Algorithm/Algorithm.h"
16
17/*
18 * \note Code-Status: <a href="Code-Status.md#Beta">Beta</a>
19 */
20
21namespace Stroika::Foundation::Cryptography::Digest {
22
23 using Memory::BLOB;
24
25 /**
26 * \brief ComputeDigest<ALGORITHM> () is the simplest and generally best way to call Digest algorithms
27 *
28 * A Digest is an algorithm that takes a stream of bytes and computes a series of bits
29 * (can be thought of as a number, or string, or seqeunce of bits) which hopefully as
30 * nearly as possible (given the length of the digest) uniquely identifies the input.
31 *
32 * A digest is generally of fixed length - often 4, or 16, or 20 bytes long.
33 *
34 * RETURN_TYPE is typically uint32_t, uint64_t, Common::GUID, or Result128BitType, Result128BitType etc,
35 * but could in principle be anything.
36 *
37 * \note Endianness - these algorithms logically operate on bytes, so if you use RETURN_TYPE=uin32_t (or anything but byte array) -
38 * expect the actual numerical value will depend on endianness.
39 *
40 * \par Example Usage
41 * \code
42 * string digestStr = Format (ComputeDigest<Algorithm::MD5> (s, e));
43 * \endcode
44 *
45 * \par Example Usage
46 * \code
47 * SourceDefinition tmp; // some struct which defines ostream operator>>
48 * string digestStr = Format (ComputeDigest<Algorithm::MD5> (Streams::iostream::SerializeItemToBLOB (tmp)));
49 * \endcode
50 *
51 * \par Example Usage
52 * \code
53 * return ComputeDigest<Algorithm::MD5> (Memory::BLOB::FromRaw (sb.AsUTF8 ())));
54 * \endcode
55 *
56 * \par Example Usage
57 * \code
58 * // to convert to string
59 * return Format<String> (ComputeDigest<Algorithm::MD5> (Memory::BLOB::FromRaw (sb)));
60 * // OR
61 * return ComputeDigest<Algorithm::MD5, String> (Memory::BLOB::FromRaw (sb)));
62 * \endcode
63 *
64 * \par Example Usage
65 * \code
66 * using namespace IO::Network;
67 * Memory::BLOB value2Hash = DefaultSerializer<InternetAddress>{}(InternetAddress{"192.168.244.33"});
68 * auto h1 = ComputeDigest<Digest::Algorithm::SuperFastHash> (value2Hash);
69 * uint8_t h2 = ComputeDigest<Digest::Algorithm::SuperFastHash, uint8_t> (value2Hash);
70 * EXPECT_TRUE (h1 == 2512011991); // experimentally derived values but they shouldn't float (actually may depend on endianness?)
71 * EXPECT_TRUE (h2 == 215);
72 * std::array<byte, 40> h3 = ComputeDigest<Digest::Algorithm::SuperFastHash, std::array<byte, 40>> (value2Hash);
73 * EXPECT_TRUE (h3[0] == 215_b and h3[1] == 66_b and h3[39] == 0_b);
74 * if (Common::GetEndianness () == Common::Endian::eX86) {
75 * EXPECT_TRUE ((ComputeDigest<Digest::Algorithm::SuperFastHash, string>(value2Hash) == "0x2512011991"));
76 * }
77 * \endcode
78 *
79 * \par Example Usage
80 * \code
81 * String s1 = "abc";
82 * auto r1 = Digest::ComputeDigest<Digest::Algorithm::MD5> (s1);
83 * \endcode
84 *
85 * @see Hash ()
86 * @see IncrementalDigester ()
87 * @see Digester ()
88 *
89 */
90 template <typename ALGORITHM, typename RETURN_TYPE = typename Algorithm::DigesterDefaultTraitsForAlgorithm<ALGORITHM>::ReturnType>
91 RETURN_TYPE ComputeDigest (const Streams::InputStream::Ptr<byte>& from);
92 template <typename ALGORITHM, typename RETURN_TYPE = typename Algorithm::DigesterDefaultTraitsForAlgorithm<ALGORITHM>::ReturnType>
93 RETURN_TYPE ComputeDigest (const byte* from, const byte* to);
94 template <typename ALGORITHM, typename RETURN_TYPE = typename Algorithm::DigesterDefaultTraitsForAlgorithm<ALGORITHM>::ReturnType>
95 RETURN_TYPE ComputeDigest (span<const byte> from);
96 template <typename ALGORITHM, typename RETURN_TYPE = typename Algorithm::DigesterDefaultTraitsForAlgorithm<ALGORITHM>::ReturnType>
97 RETURN_TYPE ComputeDigest (const BLOB& from);
98 template <typename ALGORITHM, typename TRIVIALLY_COPYABLE_T, typename RETURN_TYPE = typename Algorithm::DigesterDefaultTraitsForAlgorithm<ALGORITHM>::ReturnType>
99 RETURN_TYPE ComputeDigest (const Traversal::Iterable<TRIVIALLY_COPYABLE_T>& from)
100 requires (is_trivially_copyable_v<TRIVIALLY_COPYABLE_T>);
101
102 /**
103 * \brief IncrementalDigester<ALGORITHM> () is the low level way to call Digest algorithms, appropriate for streamed sources of data (because it a stateful object you can call Write on multiple times before extracting the digest)
104 *
105 * A Digest is an algorithm that takes a stream of bytes and computes a series of bits
106 * (can be thought of as a number, or string, or sequence of bits) which hopefully as
107 * nearly as possible (given the length of the digest) uniquely identifies the input.
108 *
109 * A digest is generally of fixed length - often 4, or 16, or 20 bytes long.
110 *
111 * RETURN_TYPE is typically uint32_t, uint64_t, or Result128BitType, Result128BitType etc,
112 * but could in principle be anything.
113 *
114 * \note Endianness - these algorithms logically operate on bytes, so if you use RETURN_TYPE=uin32_t (or anything but byte array) -
115 * expect the actual numerical value will depend on endianness.
116 *
117 * \par Example Usage
118 * \code
119 * IncrementalDigester<Algorithm:CRC32> ctx;
120 * ctx.Write (from, to);
121 * uint32_t result = ctx.Complete ();
122 * \endcode
123 *
124 * \par Example Usage
125 * \code
126 * IncrementalDigester<Algorithm:CRC32, string> ctx;
127 * ctx.Write (from, to);
128 * string result = ctx.Complete ();
129 * \endcode
130 *
131 * See Also:
132 * @see ComputeDigest () - this is usually the simplest way to access the digest algorithms.
133 */
134 template <typename ALGORITHM, typename RETURN_TYPE = typename Algorithm::DigesterDefaultTraitsForAlgorithm<ALGORITHM>::ReturnType>
136 public:
137 using ReturnType = RETURN_TYPE;
138
139 public:
140 /**
141 */
142 IncrementalDigester () = default;
143 IncrementalDigester (const IncrementalDigester& src) = default;
144
145 public:
146 nonvirtual IncrementalDigester& operator= (const IncrementalDigester& rhs) = default;
147
148 public:
149 /**
150 * After you construct an IncrementalDigester, call Write() zero or more times, before calling Complete() to retrieve the result.
151 *
152 * \pre not CompleteHasBeenCalled ();
153 */
154 nonvirtual void Write (const byte* from, const byte* to);
155 nonvirtual void Write (span<const byte> from);
156 nonvirtual void Write (const BLOB& from);
157 nonvirtual void Write (const Streams::InputStream::Ptr<byte>& from);
158 template <typename TRIVIALLY_COPYABLE_T>
159 nonvirtual void Write (const Traversal::Iterable<TRIVIALLY_COPYABLE_T>& from)
160 requires (is_trivially_copyable_v<TRIVIALLY_COPYABLE_T>);
161
162 public:
163 /**
164 * When all the data has been accumulated, call Complete () once to retrieve the converted result.
165 *
166 * \pre not CompleteHasBeenCalled ();
167 */
168 nonvirtual ReturnType Complete ();
169
170 private:
171 Algorithm::DigesterAlgorithm<ALGORITHM> fDigesterAlgorithm_;
172#if qStroika_Foundation_Debug_AssertionsChecked
173 bool fCompleted_{false};
174#endif
175 };
176
177 /**
178 * \brief Digester<ALGORITHM> is a function-object way to access the digest algorithm. Its generally almost the same as calling ComputeDigest (just a little more complicated) - but works with overloading properly (which is why it exists) - when you make a separate choice of algorithm from where you call
179 *
180 * A Digest is an algorithm that takes a stream of bytes and computes a series of bits
181 * (can be thought of as a number, or string, or seqeunce of bits) which hopefully as
182 * nearly as possible (given the length of the digest) uniquely identifies the input.
183 *
184 * A digest is generally of fixed length - often 4, or 16, or 20 bytes long.
185 *
186 * RETURN_TYPE is typically uint32_t, uint64_t, or Result128BitType, Result128BitType etc,
187 * but could in principle be anything.
188 *
189 * \note Endianness - these algorithms logically operate on bytes, so if you use RETURN_TYPE=uin32_t (or anything but byte array) -
190 * expect the actual numerical value will depend on endianness.
191 *
192 * \par Example Usage
193 * \code
194 * string digestStr = Format (Digester<Algorithm::MD5>{} (s, e));
195 * \endcode
196 *
197 * \par Example Usage
198 * \code
199 * SourceDefinition tmp; // some struct which defines ostream operator>>
200 * string digestStr = Format (Digester<Algorithm::MD5>{} (Streams::iostream::SerializeItemToBLOB (tmp)));
201 * \endcode
202 *
203 * \par Example Usage
204 * \code
205 * return Digester<Algorithm::MD5>{} (Memory::BLOB::FromRaw (sb.AsASCII ())));
206 * \endcode
207 *
208 * \par Example Usage
209 * \code
210 * // to convert to string
211 * return Format<String> (Digester<Algorithm::MD5>{} (Memory::BLOB::FromRaw (sb.AsASCII ())));
212 * // OR
213 * return Digester<Algorithm::MD5, String>{} (Memory::BLOB::FromRaw (sb.AsASCII ())));
214 * \endcode
215 *
216 * \par Example Usage
217 * \code
218 * using namespace IO::Network;
219 * auto digesterWithDefaultResult = Digester<Algorithm::SuperFastHash>{};
220 * auto digesterWithResult_uint8_t = Digester<Algorithm::SuperFastHash, uint8_t>{};
221 * Memory::BLOB value2Hash = DefaultSerializer<InternetAddress>{}(InternetAddress{"192.168.244.33"});
222 * auto h1 = digesterWithDefaultResult (value2Hash);
223 * uint8_t h2 = digesterWithResult_uint8_t (value2Hash);
224 * EXPECT_TRUE (h1 == 2512011991); // experimentally derived values but they shouldn't float (actually may depend on endiannesss?)
225 * EXPECT_TRUE (h2 == 215);
226 * auto digesterWithResult_array40 = Digester<Algorithm::SuperFastHash, std::array<byte, 40>>{};
227 * std::array<byte, 40> h3 = digesterWithResult_array40 (value2Hash);
228 * EXPECT_TRUE (h3[0] == byte{215} and h3[1] == byte{66} and h3[39] == byte{0});
229 * if (Common::GetEndianness () == Common::Endian::eX86) {
230 * EXPECT_TRUE ((Digester<Digest::Algorithm::SuperFastHash, string>{}(value2Hash) == "0x2512011991"));
231 * }
232 * \endcode
233 *
234 * @see Hash ()
235 *
236 */
237 template <typename ALGORITHM, typename RETURN_TYPE = typename Algorithm::DigesterDefaultTraitsForAlgorithm<ALGORITHM>::ReturnType>
238 class Digester {
239 public:
240 using ReturnType = RETURN_TYPE;
241
242 public:
243 constexpr Digester () = default;
244 Digester (const Digester& src) = delete;
245
246 public:
247 /**
248 * The reason we support the overload BLOB, is that this is the most convenient and univeral argument
249 * to a Digester.
250 *
251 * The reason to provide an InputStream<> parameter, is that this allows operating a digest on some data
252 * without loading it all into RAM at once.
253 *
254 * The reason to provide a const byte* / const byte* overload is - well - maybe pointless - since
255 * that can be quite efficiently turned into a BLOB, but its potentially a little more efficient for
256 * perhaps important cases.
257 *
258 * \note many of these overloads are redundant, but provided as a speed tweak for this situations.
259 */
260 nonvirtual ReturnType operator() (const Streams::InputStream::Ptr<byte>& from) const;
261 nonvirtual ReturnType operator() (const byte* from, const byte* to) const;
262 nonvirtual ReturnType operator() (span<const byte> from) const;
263 nonvirtual ReturnType operator() (const BLOB& from) const;
264 template <typename TRIVIALLY_COPYABLE_T>
265 nonvirtual ReturnType operator() (const Traversal::Iterable<TRIVIALLY_COPYABLE_T>& from) const
266 requires (is_trivially_copyable_v<TRIVIALLY_COPYABLE_T>);
267 };
268
269}
270
271/*
272 ********************************************************************************
273 ***************************** Implementation Details ***************************
274 ********************************************************************************
275 */
276#include "Digester.inl"
277
278#endif /*_Stroika_Foundation_Cryptography_Digest_Digester_h_*/
DigesterAlgorithm is specialized for each algorithm; generally don't use this directly,...
Definition Algorithm.h:55
Digester<ALGORITHM> is a function-object way to access the digest algorithm. Its generally almost the...
Definition Digester.h:238
nonvirtual ReturnType operator()(const Streams::InputStream::Ptr< byte > &from) const
Definition Digester.inl:77
IncrementalDigester<ALGORITHM> () is the low level way to call Digest algorithms, appropriate for str...
Definition Digester.h:135
nonvirtual void Write(const byte *from, const byte *to)
Definition Digester.inl:16
InputStream<>::Ptr is Smart pointer (with abstract Rep) class defining the interface to reading from ...
Iterable<T> is a base class for containers which easily produce an Iterator<T> to traverse them.
Definition Iterable.h:237