1 /*
2  *  Chocobo1/Hash
3  *
4  *   Copyright 2017-2020 by Mike Tzou (Chocobo1)
5  *     https://github.com/Chocobo1/Hash
6  *
7  *   Licensed under GNU General Public License 3 or later.
8  *
9  *  @license GPL3 <https://www.gnu.org/licenses/gpl-3.0-standalone.html>
10  */
11 
12 #ifndef CHOCOBO1_RIPEMD_128_H
13 #define CHOCOBO1_RIPEMD_128_H
14 
15 #include <array>
16 #include <cassert>
17 #include <climits>
18 #include <cmath>
19 #include <cstdint>
20 #include <initializer_list>
21 #include <string>
22 #include <type_traits>
23 #include <vector>
24 
25 #if (__cplusplus > 201703L)
26 #include <version>
27 #endif
28 
29 #ifndef USE_STD_SPAN_CHOCOBO1_HASH
30 #if (__cpp_lib_span >= 202002L)
31 #define USE_STD_SPAN_CHOCOBO1_HASH 1
32 #else
33 #define USE_STD_SPAN_CHOCOBO1_HASH 0
34 #endif
35 #endif
36 
37 #if (USE_STD_SPAN_CHOCOBO1_HASH == 1)
38 #include <span>
39 #else
40 #include "gsl/span"
41 #endif
42 
43 
44 namespace Chocobo1
45 {
46 	// Use these!!
47 	// RIPEMD_128();
48 }
49 
50 
51 namespace Chocobo1
52 {
53 // users should ignore things in this namespace
54 
55 namespace Hash
56 {
57 #ifndef CONSTEXPR_CPP17_CHOCOBO1_HASH
58 #if __cplusplus >= 201703L
59 #define CONSTEXPR_CPP17_CHOCOBO1_HASH constexpr
60 #else
61 #define CONSTEXPR_CPP17_CHOCOBO1_HASH
62 #endif
63 #endif
64 
65 #if (USE_STD_SPAN_CHOCOBO1_HASH == 1)
66 	using IndexType = std::size_t;
67 #else
68 	using IndexType = gsl::index;
69 #endif
70 
71 #ifndef CHOCOBO1_HASH_BUFFER_IMPL
72 #define CHOCOBO1_HASH_BUFFER_IMPL
73 	template <typename T, IndexType N>
74 	class Buffer
75 	{
76 		public:
77 			using value_type = T;
78 			using index_type = IndexType;
79 			using size_type = std::size_t;
80 
81 			constexpr Buffer() = default;
82 			constexpr Buffer(const Buffer &) = default;
83 
Buffer(const std::initializer_list<T> initList)84 			CONSTEXPR_CPP17_CHOCOBO1_HASH Buffer(const std::initializer_list<T> initList)
85 			{
86 #if !defined(NDEBUG)
87 				// check if out-of-bounds
88 				static_cast<void>(m_array.at(m_dataEndIdx + initList.size() - 1));
89 #endif
90 
91 				for (const auto &i : initList)
92 				{
93 					m_array[m_dataEndIdx] = i;
94 					++m_dataEndIdx;
95 				}
96 			}
97 
98 			template <typename InputIt>
Buffer(const InputIt first,const InputIt last)99 			constexpr Buffer(const InputIt first, const InputIt last)
100 			{
101 				for (InputIt iter = first; iter != last; ++iter)
102 				{
103 					this->fill(*iter);
104 				}
105 			}
106 
107 			constexpr T& operator[](const index_type pos)
108 			{
109 				return m_array[pos];
110 			}
111 
112 			constexpr T operator[](const index_type pos) const
113 			{
114 				return m_array[pos];
115 			}
116 
117 			CONSTEXPR_CPP17_CHOCOBO1_HASH void fill(const T &value, const index_type count = 1)
118 			{
119 #if !defined(NDEBUG)
120 				// check if out-of-bounds
121 				static_cast<void>(m_array.at(m_dataEndIdx + count - 1));
122 #endif
123 
124 				for (index_type i = 0; i < count; ++i)
125 				{
126 					m_array[m_dataEndIdx] = value;
127 					++m_dataEndIdx;
128 				}
129 			}
130 
131 			template <typename InputIt>
push_back(const InputIt first,const InputIt last)132 			constexpr void push_back(const InputIt first, const InputIt last)
133 			{
134 				for (InputIt iter = first; iter != last; ++iter)
135 				{
136 					this->fill(*iter);
137 				}
138 			}
139 
clear()140 			constexpr void clear()
141 			{
142 				m_array = {};
143 				m_dataEndIdx = 0;
144 			}
145 
empty()146 			constexpr bool empty() const
147 			{
148 				return (m_dataEndIdx == 0);
149 			}
150 
size()151 			constexpr size_type size() const
152 			{
153 				return m_dataEndIdx;
154 			}
155 
data()156 			constexpr const T* data() const
157 			{
158 				return m_array.data();
159 			}
160 
161 		private:
162 			std::array<T, N> m_array {};
163 			index_type m_dataEndIdx = 0;
164 	};
165 #endif
166 
167 
168 namespace RIPEMD_128_NS
169 {
170 	class RIPEMD_128
171 	{
172 		// https://homes.esat.kuleuven.be/~bosselae/ripemd160.html
173 
174 		public:
175 			using Byte = uint8_t;
176 			using ResultArrayType = std::array<Byte, 16>;
177 
178 #if (USE_STD_SPAN_CHOCOBO1_HASH == 1)
179 			template <typename T, std::size_t Extent = std::dynamic_extent>
180 			using Span = std::span<T, Extent>;
181 #else
182 			template <typename T, std::size_t Extent = gsl::dynamic_extent>
183 			using Span = gsl::span<T, Extent>;
184 #endif
185 
186 
187 			constexpr RIPEMD_128();
188 
189 			constexpr void reset();
190 			CONSTEXPR_CPP17_CHOCOBO1_HASH RIPEMD_128& finalize();  // after this, only `toArray()`, `toString()`, `toVector()`, `reset()` are available
191 
192 			std::string toString() const;
193 			std::vector<Byte> toVector() const;
194 			CONSTEXPR_CPP17_CHOCOBO1_HASH ResultArrayType toArray() const;
195 
196 			CONSTEXPR_CPP17_CHOCOBO1_HASH RIPEMD_128& addData(const Span<const Byte> inData);
197 			CONSTEXPR_CPP17_CHOCOBO1_HASH RIPEMD_128& addData(const void *ptr, const std::size_t length);
198 			template <std::size_t N>
199 			CONSTEXPR_CPP17_CHOCOBO1_HASH RIPEMD_128& addData(const Byte (&array)[N]);
200 			template <typename T, std::size_t N>
201 			RIPEMD_128& addData(const T (&array)[N]);
202 			template <typename T>
203 			RIPEMD_128& addData(const Span<T> inSpan);
204 
205 		private:
206 			CONSTEXPR_CPP17_CHOCOBO1_HASH void addDataImpl(const Span<const Byte> data);
207 
208 			static constexpr int BLOCK_SIZE = 64;
209 
210 			Buffer<Byte, (BLOCK_SIZE * 2)> m_buffer;  // x2 for paddings
211 			uint64_t m_sizeCounter = 0;
212 
213 			uint32_t m_h[4] = {};
214 	};
215 
216 
217 	// helpers
218 	template <typename T>
219 	class Loader
220 	{
221 		// this class workaround loading data from unaligned memory boundaries
222 		// also eliminate endianness issues
223 		public:
Loader(const uint8_t * ptr)224 			explicit constexpr Loader(const uint8_t *ptr)
225 				: m_ptr(ptr)
226 			{
227 			}
228 
229 			constexpr T operator[](const IndexType idx) const
230 			{
231 				static_assert(std::is_same<T, uint32_t>::value, "");
232 				// handle specific endianness here
233 				const uint8_t *ptr = m_ptr + (sizeof(T) * idx);
234 				return  ( (static_cast<T>(*(ptr + 0)) <<  0)
235 						| (static_cast<T>(*(ptr + 1)) <<  8)
236 						| (static_cast<T>(*(ptr + 2)) << 16)
237 						| (static_cast<T>(*(ptr + 3)) << 24));
238 			}
239 
240 		private:
241 			const uint8_t *m_ptr;
242 	};
243 
244 	template <typename R, typename T>
ror(const T x,const unsigned int s)245 	constexpr R ror(const T x, const unsigned int s)
246 	{
247 		static_assert(std::is_unsigned<R>::value, "");
248 		static_assert(std::is_unsigned<T>::value, "");
249 		return static_cast<R>(x >> s);
250 	}
251 
252 	template <typename T>
rotl(const T x,const unsigned int s)253 	constexpr T rotl(const T x, const unsigned int s)
254 	{
255 		static_assert(std::is_unsigned<T>::value, "");
256 		if (s == 0)
257 			return x;
258 		return ((x << s) | (x >> ((sizeof(T) * 8) - s)));
259 	}
260 
261 
262 	//
RIPEMD_128()263 	constexpr RIPEMD_128::RIPEMD_128()
264 	{
265 		static_assert((CHAR_BIT == 8), "Sorry, we don't support exotic CPUs");
266 		reset();
267 	}
268 
reset()269 	constexpr void RIPEMD_128::reset()
270 	{
271 		m_buffer.clear();
272 		m_sizeCounter = 0;
273 
274 		m_h[0] = 0x67452301;
275 		m_h[1] = 0xEFCDAB89;
276 		m_h[2] = 0x98BADCFE;
277 		m_h[3] = 0x10325476;
278 	}
279 
finalize()280 	CONSTEXPR_CPP17_CHOCOBO1_HASH RIPEMD_128& RIPEMD_128::finalize()
281 	{
282 		m_sizeCounter += m_buffer.size();
283 
284 		// append 1 bit
285 		m_buffer.fill(1 << 7);
286 
287 		// append paddings
288 		const size_t len = BLOCK_SIZE - ((m_buffer.size() + 8) % BLOCK_SIZE);
289 		m_buffer.fill(0, (len + 8));
290 
291 		// append size in bits
292 		const uint64_t sizeCounterBits = m_sizeCounter * 8;
293 		const uint32_t sizeCounterBitsL = ror<uint32_t>(sizeCounterBits, 0);
294 		const uint32_t sizeCounterBitsH = ror<uint32_t>(sizeCounterBits, 32);
295 		for (int i = 0; i < 4; ++i)
296 		{
297 			m_buffer[m_buffer.size() - 8 + i] = ror<Byte>(sizeCounterBitsL, (8 * i));
298 			m_buffer[m_buffer.size() - 4 + i] = ror<Byte>(sizeCounterBitsH, (8 * i));
299 		}
300 
301 		addDataImpl({m_buffer.data(), m_buffer.size()});
302 		m_buffer.clear();
303 
304 		return (*this);
305 	}
306 
toString()307 	std::string RIPEMD_128::toString() const
308 	{
309 		const auto a = toArray();
310 		std::string ret;
311 		ret.resize(2 * a.size());
312 
313 		auto retPtr = &ret.front();
314 		for (const auto c : a)
315 		{
316 			const Byte upper = ror<Byte>(c, 4);
317 			*(retPtr++) = static_cast<char>((upper < 10) ? (upper + '0') : (upper - 10 + 'a'));
318 
319 			const Byte lower = c & 0xf;
320 			*(retPtr++) = static_cast<char>((lower < 10) ? (lower + '0') : (lower - 10 + 'a'));
321 		}
322 
323 		return ret;
324 	}
325 
toVector()326 	std::vector<RIPEMD_128::Byte> RIPEMD_128::toVector() const
327 	{
328 		const auto a = toArray();
329 		return {a.begin(), a.end()};
330 	}
331 
toArray()332 	CONSTEXPR_CPP17_CHOCOBO1_HASH RIPEMD_128::ResultArrayType RIPEMD_128::toArray() const
333 	{
334 		const Span<const uint32_t> state(m_h);
335 		const int dataSize = sizeof(decltype(state)::value_type);
336 
337 		ResultArrayType ret {};
338 		auto retPtr = ret.data();
339 		for (const auto i : state)
340 		{
341 			for (int j = 0; j < dataSize; ++j)
342 				*(retPtr++) = ror<Byte>(i, (j * 8));
343 		}
344 
345 		return ret;
346 	}
347 
addData(const Span<const Byte> inData)348 	CONSTEXPR_CPP17_CHOCOBO1_HASH RIPEMD_128& RIPEMD_128::addData(const Span<const Byte> inData)
349 	{
350 		Span<const Byte> data = inData;
351 
352 		if (!m_buffer.empty())
353 		{
354 			const size_t len = std::min<size_t>((BLOCK_SIZE - m_buffer.size()), data.size());  // try fill to BLOCK_SIZE bytes
355 			m_buffer.push_back(data.begin(), (data.begin() + len));
356 
357 			if (m_buffer.size() < BLOCK_SIZE)  // still doesn't fill the buffer
358 				return (*this);
359 
360 			addDataImpl({m_buffer.data(), m_buffer.size()});
361 			m_buffer.clear();
362 
363 			data = data.subspan(len);
364 		}
365 
366 		const size_t dataSize = data.size();
367 		if (dataSize < BLOCK_SIZE)
368 		{
369 			m_buffer = {data.begin(), data.end()};
370 			return (*this);
371 		}
372 
373 		const size_t len = dataSize - (dataSize % BLOCK_SIZE);  // align on BLOCK_SIZE bytes
374 		addDataImpl(data.first(len));
375 
376 		if (len < dataSize)  // didn't consume all data
377 			m_buffer = {(data.begin() + len), data.end()};
378 
379 		return (*this);
380 	}
381 
addData(const void * ptr,const std::size_t length)382 	CONSTEXPR_CPP17_CHOCOBO1_HASH RIPEMD_128& RIPEMD_128::addData(const void *ptr, const std::size_t length)
383 	{
384 		// Span::size_type = std::size_t
385 		return addData({static_cast<const Byte*>(ptr), length});
386 	}
387 
388 	template <std::size_t N>
addData(const Byte (& array)[N])389 	CONSTEXPR_CPP17_CHOCOBO1_HASH RIPEMD_128& RIPEMD_128::addData(const Byte (&array)[N])
390 	{
391 		return addData({array, N});
392 	}
393 
394 	template <typename T, std::size_t N>
addData(const T (& array)[N])395 	RIPEMD_128& RIPEMD_128::addData(const T (&array)[N])
396 	{
397 		return addData({reinterpret_cast<const Byte*>(array), (sizeof(T) * N)});
398 	}
399 
400 	template <typename T>
addData(const Span<T> inSpan)401 	RIPEMD_128& RIPEMD_128::addData(const Span<T> inSpan)
402 	{
403 		return addData({reinterpret_cast<const Byte*>(inSpan.data()), inSpan.size_bytes()});
404 	}
405 
addDataImpl(const Span<const Byte> data)406 	CONSTEXPR_CPP17_CHOCOBO1_HASH void RIPEMD_128::addDataImpl(const Span<const Byte> data)
407 	{
408 		assert((data.size() % BLOCK_SIZE) == 0);
409 
410 		m_sizeCounter += data.size();
411 
412 		for (size_t i = 0, iend = static_cast<size_t>(data.size() / BLOCK_SIZE); i < iend; ++i)
413 		{
414 			const Loader<uint32_t> x(static_cast<const Byte *>(data.data() + (i * BLOCK_SIZE)));
415 
416 			const auto f1 = [](const uint32_t x, const uint32_t y, const uint32_t z) -> uint32_t
417 			{
418 				return (x ^ y ^ z);
419 			};
420 			const auto f2 = [](const uint32_t x, const uint32_t y, const uint32_t z) -> uint32_t
421 			{
422 				return ((x & (y ^ z)) ^ z);  // alternative
423 			};
424 			const auto f3 = [](const uint32_t x, const uint32_t y, const uint32_t z) -> uint32_t
425 			{
426 				return ((x | (~y)) ^ z);
427 			};
428 			const auto f4 = [](const uint32_t x, const uint32_t y, const uint32_t z) -> uint32_t
429 			{
430 				return (((x ^ y) & z) ^ y);  // alternative
431 			};
432 
433 			uint32_t a = m_h[0];
434 			uint32_t b = m_h[1];
435 			uint32_t c = m_h[2];
436 			uint32_t d = m_h[3];
437 			const auto lineLeft = [x](uint32_t &a, uint32_t &b, uint32_t &c, uint32_t &d, const auto &f, const uint32_t k, const unsigned int r, const unsigned int s) -> void
438 			{
439 				a = rotl((a + f(b, c, d) + x[r] + k), s);
440 			};
441 
442 			uint32_t aa = m_h[0];
443 			uint32_t bb = m_h[1];
444 			uint32_t cc = m_h[2];
445 			uint32_t dd = m_h[3];
446 			const auto &lineRight = lineLeft;
447 
448 			lineLeft(a, b, c, d, f1, 0x00000000, 0, 11);
449 			lineLeft(d, a, b, c, f1, 0x00000000, 1, 14);
450 			lineRight(aa, bb, cc, dd, f4, 0x50A28BE6, 5, 8);
451 			lineRight(dd, aa, bb, cc, f4, 0x50A28BE6, 14, 9);
452 			lineLeft(c, d, a, b, f1, 0x00000000, 2, 15);
453 			lineLeft(b, c, d, a, f1, 0x00000000, 3, 12);
454 			lineRight(cc, dd, aa, bb, f4, 0x50A28BE6, 7, 9);
455 			lineRight(bb, cc, dd, aa, f4, 0x50A28BE6, 0, 11);
456 			lineLeft(a, b, c, d, f1, 0x00000000, 4, 5);
457 			lineLeft(d, a, b, c, f1, 0x00000000, 5, 8);
458 			lineRight(aa, bb, cc, dd, f4, 0x50A28BE6, 9, 13);
459 			lineRight(dd, aa, bb, cc, f4, 0x50A28BE6, 2, 15);
460 			lineLeft(c, d, a, b, f1, 0x00000000, 6, 7);
461 			lineLeft(b, c, d, a, f1, 0x00000000, 7, 9);
462 			lineRight(cc, dd, aa, bb, f4, 0x50A28BE6, 11, 15);
463 			lineRight(bb, cc, dd, aa, f4, 0x50A28BE6, 4, 5);
464 			lineLeft(a, b, c, d, f1, 0x00000000, 8, 11);
465 			lineLeft(d, a, b, c, f1, 0x00000000, 9, 13);
466 			lineRight(aa, bb, cc, dd, f4, 0x50A28BE6, 13, 7);
467 			lineRight(dd, aa, bb, cc, f4, 0x50A28BE6, 6, 7);
468 			lineLeft(c, d, a, b, f1, 0x00000000, 10, 14);
469 			lineLeft(b, c, d, a, f1, 0x00000000, 11, 15);
470 			lineRight(cc, dd, aa, bb, f4, 0x50A28BE6, 15, 8);
471 			lineRight(bb, cc, dd, aa, f4, 0x50A28BE6, 8, 11);
472 			lineLeft(a, b, c, d, f1, 0x00000000, 12, 6);
473 			lineLeft(d, a, b, c, f1, 0x00000000, 13, 7);
474 			lineRight(aa, bb, cc, dd, f4, 0x50A28BE6, 1, 14);
475 			lineRight(dd, aa, bb, cc, f4, 0x50A28BE6, 10, 14);
476 			lineLeft(c, d, a, b, f1, 0x00000000, 14, 9);
477 			lineLeft(b, c, d, a, f1, 0x00000000, 15, 8);
478 			lineRight(cc, dd, aa, bb, f4, 0x50A28BE6, 3, 12);
479 			lineRight(bb, cc, dd, aa, f4, 0x50A28BE6, 12, 6);
480 			lineLeft(a, b, c, d, f2, 0x5A827999, 7, 7);
481 			lineLeft(d, a, b, c, f2, 0x5A827999, 4, 6);
482 			lineRight(aa, bb, cc, dd, f3, 0x5C4DD124, 6, 9);
483 			lineRight(dd, aa, bb, cc, f3, 0x5C4DD124, 11, 13);
484 			lineLeft(c, d, a, b, f2, 0x5A827999, 13, 8);
485 			lineLeft(b, c, d, a, f2, 0x5A827999, 1, 13);
486 			lineRight(cc, dd, aa, bb, f3, 0x5C4DD124, 3, 15);
487 			lineRight(bb, cc, dd, aa, f3, 0x5C4DD124, 7, 7);
488 			lineLeft(a, b, c, d, f2, 0x5A827999, 10, 11);
489 			lineLeft(d, a, b, c, f2, 0x5A827999, 6, 9);
490 			lineRight(aa, bb, cc, dd, f3, 0x5C4DD124, 0, 12);
491 			lineRight(dd, aa, bb, cc, f3, 0x5C4DD124, 13, 8);
492 			lineLeft(c, d, a, b, f2, 0x5A827999, 15, 7);
493 			lineLeft(b, c, d, a, f2, 0x5A827999, 3, 15);
494 			lineRight(cc, dd, aa, bb, f3, 0x5C4DD124, 5, 9);
495 			lineRight(bb, cc, dd, aa, f3, 0x5C4DD124, 10, 11);
496 			lineLeft(a, b, c, d, f2, 0x5A827999, 12, 7);
497 			lineLeft(d, a, b, c, f2, 0x5A827999, 0, 12);
498 			lineRight(aa, bb, cc, dd, f3, 0x5C4DD124, 14, 7);
499 			lineRight(dd, aa, bb, cc, f3, 0x5C4DD124, 15, 7);
500 			lineLeft(c, d, a, b, f2, 0x5A827999, 9, 15);
501 			lineLeft(b, c, d, a, f2, 0x5A827999, 5, 9);
502 			lineRight(cc, dd, aa, bb, f3, 0x5C4DD124, 8, 12);
503 			lineRight(bb, cc, dd, aa, f3, 0x5C4DD124, 12, 7);
504 			lineLeft(a, b, c, d, f2, 0x5A827999, 2, 11);
505 			lineLeft(d, a, b, c, f2, 0x5A827999, 14, 7);
506 			lineRight(aa, bb, cc, dd, f3, 0x5C4DD124, 4, 6);
507 			lineRight(dd, aa, bb, cc, f3, 0x5C4DD124, 9, 15);
508 			lineLeft(c, d, a, b, f2, 0x5A827999, 11, 13);
509 			lineLeft(b, c, d, a, f2, 0x5A827999, 8, 12);
510 			lineRight(cc, dd, aa, bb, f3, 0x5C4DD124, 1, 13);
511 			lineRight(bb, cc, dd, aa, f3, 0x5C4DD124, 2, 11);
512 			lineLeft(a, b, c, d, f3, 0x6ED9EBA1, 3, 11);
513 			lineLeft(d, a, b, c, f3, 0x6ED9EBA1, 10, 13);
514 			lineRight(aa, bb, cc, dd, f2, 0x6D703EF3, 15, 9);
515 			lineRight(dd, aa, bb, cc, f2, 0x6D703EF3, 5, 7);
516 			lineLeft(c, d, a, b, f3, 0x6ED9EBA1, 14, 6);
517 			lineLeft(b, c, d, a, f3, 0x6ED9EBA1, 4, 7);
518 			lineRight(cc, dd, aa, bb, f2, 0x6D703EF3, 1, 15);
519 			lineRight(bb, cc, dd, aa, f2, 0x6D703EF3, 3, 11);
520 			lineLeft(a, b, c, d, f3, 0x6ED9EBA1, 9, 14);
521 			lineLeft(d, a, b, c, f3, 0x6ED9EBA1, 15, 9);
522 			lineRight(aa, bb, cc, dd, f2, 0x6D703EF3, 7, 8);
523 			lineRight(dd, aa, bb, cc, f2, 0x6D703EF3, 14, 6);
524 			lineLeft(c, d, a, b, f3, 0x6ED9EBA1, 8, 13);
525 			lineLeft(b, c, d, a, f3, 0x6ED9EBA1, 1, 15);
526 			lineRight(cc, dd, aa, bb, f2, 0x6D703EF3, 6, 6);
527 			lineRight(bb, cc, dd, aa, f2, 0x6D703EF3, 9, 14);
528 			lineLeft(a, b, c, d, f3, 0x6ED9EBA1, 2, 14);
529 			lineLeft(d, a, b, c, f3, 0x6ED9EBA1, 7, 8);
530 			lineRight(aa, bb, cc, dd, f2, 0x6D703EF3, 11, 12);
531 			lineRight(dd, aa, bb, cc, f2, 0x6D703EF3, 8, 13);
532 			lineLeft(c, d, a, b, f3, 0x6ED9EBA1, 0, 13);
533 			lineLeft(b, c, d, a, f3, 0x6ED9EBA1, 6, 6);
534 			lineRight(cc, dd, aa, bb, f2, 0x6D703EF3, 12, 5);
535 			lineRight(bb, cc, dd, aa, f2, 0x6D703EF3, 2, 14);
536 			lineLeft(a, b, c, d, f3, 0x6ED9EBA1, 13, 5);
537 			lineLeft(d, a, b, c, f3, 0x6ED9EBA1, 11, 12);
538 			lineRight(aa, bb, cc, dd, f2, 0x6D703EF3, 10, 13);
539 			lineRight(dd, aa, bb, cc, f2, 0x6D703EF3, 0, 13);
540 			lineLeft(c, d, a, b, f3, 0x6ED9EBA1, 5, 7);
541 			lineLeft(b, c, d, a, f3, 0x6ED9EBA1, 12, 5);
542 			lineRight(cc, dd, aa, bb, f2, 0x6D703EF3, 4, 7);
543 			lineRight(bb, cc, dd, aa, f2, 0x6D703EF3, 13, 5);
544 			lineLeft(a, b, c, d, f4, 0x8F1BBCDC, 1, 11);
545 			lineLeft(d, a, b, c, f4, 0x8F1BBCDC, 9, 12);
546 			lineRight(aa, bb, cc, dd, f1, 0x00000000, 8, 15);
547 			lineRight(dd, aa, bb, cc, f1, 0x00000000, 6, 5);
548 			lineLeft(c, d, a, b, f4, 0x8F1BBCDC, 11, 14);
549 			lineLeft(b, c, d, a, f4, 0x8F1BBCDC, 10, 15);
550 			lineRight(cc, dd, aa, bb, f1, 0x00000000, 4, 8);
551 			lineRight(bb, cc, dd, aa, f1, 0x00000000, 1, 11);
552 			lineLeft(a, b, c, d, f4, 0x8F1BBCDC, 0, 14);
553 			lineLeft(d, a, b, c, f4, 0x8F1BBCDC, 8, 15);
554 			lineRight(aa, bb, cc, dd, f1, 0x00000000, 3, 14);
555 			lineRight(dd, aa, bb, cc, f1, 0x00000000, 11, 14);
556 			lineLeft(c, d, a, b, f4, 0x8F1BBCDC, 12, 9);
557 			lineLeft(b, c, d, a, f4, 0x8F1BBCDC, 4, 8);
558 			lineRight(cc, dd, aa, bb, f1, 0x00000000, 15, 6);
559 			lineRight(bb, cc, dd, aa, f1, 0x00000000, 0, 14);
560 			lineLeft(a, b, c, d, f4, 0x8F1BBCDC, 13, 9);
561 			lineLeft(d, a, b, c, f4, 0x8F1BBCDC, 3, 14);
562 			lineRight(aa, bb, cc, dd, f1, 0x00000000, 5, 6);
563 			lineRight(dd, aa, bb, cc, f1, 0x00000000, 12, 9);
564 			lineLeft(c, d, a, b, f4, 0x8F1BBCDC, 7, 5);
565 			lineLeft(b, c, d, a, f4, 0x8F1BBCDC, 15, 6);
566 			lineRight(cc, dd, aa, bb, f1, 0x00000000, 2, 12);
567 			lineRight(bb, cc, dd, aa, f1, 0x00000000, 13, 9);
568 			lineLeft(a, b, c, d, f4, 0x8F1BBCDC, 14, 8);
569 			lineLeft(d, a, b, c, f4, 0x8F1BBCDC, 5, 6);
570 			lineRight(aa, bb, cc, dd, f1, 0x00000000, 9, 12);
571 			lineRight(dd, aa, bb, cc, f1, 0x00000000, 7, 5);
572 			lineLeft(c, d, a, b, f4, 0x8F1BBCDC, 6, 5);
573 			lineLeft(b, c, d, a, f4, 0x8F1BBCDC, 2, 12);
574 			lineRight(cc, dd, aa, bb, f1, 0x00000000, 10, 15);
575 			lineRight(bb, cc, dd, aa, f1, 0x00000000, 14, 8);
576 
577 			const uint32_t t = m_h[1] + c + dd;
578 			m_h[1] = m_h[2] + d + aa;
579 			m_h[2] = m_h[3] + a + bb;
580 			m_h[3] = m_h[0] + b + cc;
581 			m_h[0] = t;
582 		}
583 	}
584 }
585 }
586 	using RIPEMD_128 = Hash::RIPEMD_128_NS::RIPEMD_128;
587 }
588 
589 #endif  // CHOCOBO1_RIPEMD_128_H
590