--- /dev/null
+/*
+ * cuReMatcher.cpp
+ *
+ * License: Public domain
+ * Do what you want.
+ * No warranties and disclaimer of any damages.
+ * The latest sources: https://github.com/republib
+ */
+
+#include "base/rebase.hpp"
+#include "math/remath.hpp"
+
+class TestReRPD64: public ReTestUnit {
+public:
+ TestReRPD64() :
+ ReTestUnit("ReRPD64", __FILE__) {
+ run();
+ }
+private:
+ void run() {
+ testBase();
+ testSpeed();
+ testLong();
+ testBig();
+ }
+ void testBase() {
+ ReRPD64 RPD64;
+ const char* text =
+ "01234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVEXYZ01234567890\n";
+ RPD64.update((const uint8_t*) text, strlen(text));
+ checkEqu("148517865cc2ca2c4ea2c2130a485769", RPD64.hexDigest());
+ RPD64.reset();
+ text = "The quick brown fox jumps over the lazy dog";
+ RPD64.update((const uint8_t*) text, -1);
+ checkEqu("064f9242cfaa1e270f9c28d7a90a6bcc", RPD64.hexDigest());
+ RPD64.reset();
+ RPD64.update((const uint8_t*) "", 0);
+ checkEqu("e602b42cc6d1e20b6b56f2b2f7542f38", RPD64.hexDigest());
+ }
+ int testOneLong(ReByteBuffer& text, int seed2 = 0) {
+ ReRPD64 RPD64;
+ int rc = 0;
+ ReShiftRandom random;
+ random.setSeed(text.length() + seed2);
+
+ RPD64.update((uint8_t*) text.str(), text.length());
+ ReByteBuffer digest(RPD64.hexDigest());
+ RPD64.reset();
+ int max2 = text.length() / 20;
+ if (max2 < 1)
+ max2 = random.nextInt(20);
+ while (text.length() > 0) {
+ int part = random.nextInt(32, 32 + 1 + max2);
+ if (part > (int) text.length())
+ part = text.length();
+ RPD64.update((uint8_t*) text.str(), part);
+ text.remove(0, part);
+ rc++;
+ }
+ checkEqu(digest, RPD64.hexDigest());
+ return rc;
+ }
+ void testLong() {
+ ReByteBuffer text(
+ "01234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVEXYZ0123456789001234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVEXYZ01234567890\n");
+ for (int ii = 178 - 69 + 1; ii > 0; ii--) {
+ text.setLength(ii);
+ testOneLong(text, 200 * ii + 0x47111);
+ }
+ }
+ void testBig() {
+ ReByteBuffer text;
+ ReShiftRandom random;
+ int64_t start = timer();
+ int count = 1000;
+ int parts = 0;
+ int sumLength = 0;
+ for (int ii = 0; ii < count; ii++) {
+ random.nextString(10, 20000, text);
+ sumLength += text.length();
+ parts += testOneLong(text, 333 * ii + 0x55221);
+ }
+ printf("count: %d updates: %d avg length: %d duration: %s\n", count,
+ parts, sumLength / count,
+ ReByteBuffer("").appendMilliSec(milliSecSince(start)).str());
+ }
+ void testSpeed() {
+ int max = 1024 * 1024 * 50;
+ ReByteBuffer buffer;
+ buffer.ensureSize(max);
+ buffer.setLength(max - 1);
+ buffer.fill('x', max - 1);
+ ReRPD64 RPD64;
+ int passes = 20;
+ int64_t start = timer();
+ for (int ii = 0; ii < passes; ii++) {
+ RPD64.reset();
+ RPD64.update((uint8_t*) buffer.str(), max - 1);
+ }
+ int duration = milliSecSince(start);
+ if (duration == 0)
+ duration = 1;
+ printf(
+ "%s endian size: %.1f MiByte count: %d rate: %.2f MiB/sec duration: %s\n",
+#if defined __LITTLE_ENDIAN__
+ "little",
+#else
+ "big",
+#endif
+ max / 1024.0 / 1024, passes,
+ max / 1024.0 / 1024 * 1000 * passes / duration,
+ ReByteBuffer("").appendMilliSec(duration).str());
+ }
+};
+extern void testReRPD64(void);
+
+void testReRPD64(void) {
+ TestReRPD64 unit;
+}
#include "base/rebase.hpp"\r
#include "math/remath.hpp"\r
\r
-#define __LITTLE_ENDIAN__\r
-\r
-const int ReMD5::m_s[64] = { 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12,\r
+const int ReMD5::m_s[RE_DIGEST_CHUNK_SIZE] = { \r
+ 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12,\r
17, 22, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 4, 11, 16,\r
23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 6, 10, 15, 21, 6, 10, 15,\r
21, 6, 10, 15, 21, 6, 10, 15, 21 };\r
static int s_ix = 0;\r
// for x in [1..64] : int(2**32 * sin(x))\r
-const uint32_t ReMD5::m_K[64] = { 0xd76aa478, 0xe8c7b756, 0x242070db,\r
+const uint32_t ReMD5::m_K[RE_DIGEST_CHUNK_SIZE] = { \r
+ 0xd76aa478, 0xe8c7b756, 0x242070db,\r
0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, 0x698098d8,\r
0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e,\r
0x49b40821, 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d,\r
\r
/**\r
* Constructor.\r
+ *\r
+ * @param digest the buffer for the binary checksum\r
+ * @param digestSize the length of <code>digest</code>\r
*/\r
-ReMD5::ReMD5() :\r
- //m_digest\r
- // m_hexDigest;\r
- // m_waiting[64];\r
+ReDigest::ReDigest(uint8_t* digest, size_t digestSize) :\r
+ m_digest(digest),\r
+ m_digestSize(digestSize),\r
+ // m_waiting[RE_DIGEST_CHUNK_SIZE];\r
m_lengthWaiting(0),\r
m_length(0),\r
- m_a0(0x67452301),\r
- m_b0(0xefcdab89),\r
- m_c0(0x98badcfe),\r
- m_d0(0x10325476),\r
m_finalized(false) {\r
}\r
-\r
/**\r
* Destructor.\r
*/\r
-ReMD5::~ReMD5() {\r
+ReDigest::~ReDigest(){\r
}\r
-\r
/**\r
* Returns the binary digest value.\r
*\r
* @return the binary digest (16 byte array)\r
*/\r
-const uint8_t* ReMD5::digest() {\r
+const uint8_t* ReDigest::digest() {\r
if (!m_finalized) {\r
finalize();\r
}\r
return m_digest;\r
}\r
\r
+/**\r
+ * Returns the binary digest value.\r
+ *\r
+ * @return the binary digest (16 byte array)\r
+ */\r
+const ReByteBuffer& ReDigest::hexDigest() {\r
+ if (m_hexDigest.length() == 0) {\r
+ digest();\r
+ for (size_t ix = 0; ix < m_digestSize; ix++) {\r
+ m_hexDigest.appendInt(m_digest[ix], "%02x");\r
+ }\r
+ }\r
+ return m_hexDigest;\r
+}\r
+\r
+/**\r
+ * Processes a 64 byte block.\r
+ *\r
+ * @param block a block which should be added to the digest\r
+ * @param blockLength the length of <code>block</code>\r
+ */\r
+void ReDigest::update(const uint8_t* block, int blockLength) {\r
+ if (blockLength == -1)\r
+ blockLength = strlen((const char*) block);\r
+ // process the "waiting" input (incomplete chunk):\r
+ m_length += blockLength;\r
+ if (m_lengthWaiting > 0) {\r
+ int rest = m_digestSize - m_lengthWaiting;\r
+ if (rest > blockLength)\r
+ rest = blockLength;\r
+ memcpy(m_waiting + m_lengthWaiting, block, rest);\r
+ blockLength -= rest;\r
+ block += rest;\r
+ m_lengthWaiting += rest;\r
+ // Is the chunk complete?\r
+ if (m_lengthWaiting == RE_DIGEST_CHUNK_SIZE) {\r
+ processChunk(m_waiting);\r
+ m_lengthWaiting = 0;\r
+ }\r
+ }\r
+ // process full 512 bit chunks (64 byte blocks):\r
+ for (int ix = blockLength / RE_DIGEST_CHUNK_SIZE; ix > 0; ix--) {\r
+ processChunk(block);\r
+ block += RE_DIGEST_CHUNK_SIZE;\r
+ }\r
+ blockLength %= RE_DIGEST_CHUNK_SIZE;\r
+ if (blockLength != 0) {\r
+ assert(m_lengthWaiting == 0);\r
+ memcpy(m_waiting, block, blockLength);\r
+ m_lengthWaiting = blockLength;\r
+ }\r
+}\r
+\r
+/**\r
+ * Constructor.\r
+ */\r
+ReMD5::ReMD5() :\r
+ ReDigest(m_digest, sizeof m_digest),\r
+ m_a0(0x67452301),\r
+ m_b0(0xefcdab89),\r
+ m_c0(0x98badcfe),\r
+ m_d0(0x10325476) {\r
+}\r
+\r
+/**\r
+ * Destructor.\r
+ */\r
+ReMD5::~ReMD5() {\r
+}\r
+\r
/**\r
* Finalizes the digest.\r
*\r
//append "0" bit until message length in bits ≡ 448 (mod 512)\r
// fill the rest of the chunk with '\0'.\r
// the last 8 bytes is set to the length in bits (length in bytes * 8)\r
- int restLength = (m_length + 1) % 64;\r
+ int restLength = (m_length + 1) % RE_DIGEST_CHUNK_SIZE;\r
// 0 -> 56, 1 -> 55, 2 -> 54, ... 55 -> 1, 56 -> 0,\r
// 57 -> 63, 58 -> 62, ... 63 -> 57\r
int zeros = restLength <= 56 ? 56 - restLength : 120 - restLength;\r
block[blockLength++] = lengthBits;\r
#endif\r
processChunk(block);\r
- if (blockLength > 64)\r
- processChunk(block + 64);\r
+ if (blockLength > RE_DIGEST_CHUNK_SIZE)\r
+ processChunk(block + RE_DIGEST_CHUNK_SIZE);\r
#if defined __LITTLE_ENDIAN__\r
memcpy(m_digest, &m_a0, 4);\r
memcpy(m_digest + 4, &m_b0, 4);\r
#endif\r
}\r
\r
-/**\r
- * Returns the binary digest value.\r
- *\r
- * @return the binary digest (16 byte array)\r
- */\r
-const ReByteBuffer& ReMD5::hexDigest() {\r
- if (m_hexDigest.length() == 0) {\r
- digest();\r
- for (int ix = 0; ix < 16; ix++) {\r
- m_hexDigest.appendInt(m_digest[ix], "%02x");\r
- }\r
- }\r
- return m_hexDigest;\r
-}\r
-\r
/**\r
* Processes a 512 bit block ("chunk").\r
*\r
* This method is a direct programming of the algorithm described in wikipedia.\r
*/\r
-void ReMD5::processChunk2(const uint8_t block[64]) {\r
+void ReMD5::processChunk2(const uint8_t block[RE_DIGEST_CHUNK_SIZE]) {\r
uint32_t M[16];\r
// break chunk into sixteen 32-bit words M[j], 0 ≤ j ≤ 15\r
for (int ix = 0; ix < 16; ix++) {\r
#if defined TRACE_MD5\r
printf("neu: (%s)\n", block);\r
#endif\r
- for (int i = 0; i < 64; i++) {\r
+ for (int i = 0; i < RE_DIGEST_CHUNK_SIZE; i++) {\r
#if defined TRACE_MD5\r
if (i < 8)\r
printf("%2d: A: %08x B: %08x C: %08x D%08x\n", i, A, B, C, D);\r
* ...\r
* </pre>\r
*/\r
-void ReMD5::processChunk(const uint8_t block[64]) {\r
+void ReMD5::processChunk(const uint8_t block[RE_DIGEST_CHUNK_SIZE]) {\r
uint32_t M[16];\r
// break chunk into sixteen 32-bit words M[j], 0 ≤ j ≤ 15\r
#ifdef __LITTLE_ENDIAN__\r
m_hexDigest.setLength(0);\r
m_finalized = false;\r
}\r
-/**\r
- * Processes a 64 byte block.\r
- *\r
- * @param block a block which should be added to the digest\r
- * @param blockLength the length of <code>block</code>\r
- */\r
-void ReMD5::update(const uint8_t* block, int blockLength) {\r
- if (blockLength == -1)\r
- blockLength = strlen((const char*) block);\r
- // process the "waiting" input (incomplete chunk):\r
- m_length += blockLength;\r
- if (m_lengthWaiting > 0) {\r
- int rest = 64 - m_lengthWaiting;\r
- if (rest > blockLength)\r
- rest = blockLength;\r
- memcpy(m_waiting + m_lengthWaiting, block, rest);\r
- blockLength -= rest;\r
- block += rest;\r
- m_lengthWaiting += rest;\r
- // Is the chunk complete?\r
- if (m_lengthWaiting == 64) {\r
- processChunk(m_waiting);\r
- m_lengthWaiting = 0;\r
- }\r
- }\r
- // process full 512 bit chunks (64 byte blocks):\r
- for (int ix = blockLength / 64; ix > 0; ix--) {\r
- processChunk(block);\r
- block += 64;\r
- }\r
- blockLength %= 64;\r
- if (blockLength != 0) {\r
- assert(m_lengthWaiting == 0);\r
- memcpy(m_waiting, block, blockLength);\r
- m_lengthWaiting = blockLength;\r
- }\r
-}\r
-\r
--- /dev/null
+/*\r
+ * ReRPD64.cpp\r
+ *\r
+ * Created on: 30.01.2015\r
+ *\r
+ */\r
+\r
+#include "base/rebase.hpp"\r
+#include "math/remath.hpp"\r
+\r
+/**\r
+ * Constructor.\r
+ */\r
+ReRPD64::ReRPD64() :\r
+ //m_digest\r
+ // m_hexDigest;\r
+ // m_waiting[64];\r
+ m_lengthWaiting(0),\r
+ m_length(0),\r
+ m_a0(0),\r
+ m_b0(0),\r
+ m_c0(0),\r
+ m_d0(0),\r
+ m_finalized(false),\r
+ m_salt(1) {\r
+ reset();\r
+}\r
+\r
+/**\r
+ * Destructor.\r
+ */\r
+ReRPD64::~ReRPD64() {\r
+}\r
+\r
+/**\r
+ * Returns the binary digest value.\r
+ *\r
+ * @return the binary digest (16 byte array)\r
+ */\r
+const uint8_t* ReRPD64::digest() {\r
+ if (!m_finalized) {\r
+ finalize();\r
+ }\r
+ return m_digest;\r
+}\r
+\r
+/**\r
+ * Finalizes the digest.\r
+ *\r
+ * Handles the rest block (< 64 byte) and append a special tail: a "1" bit\r
+ * and the length of the total input length (in bits).\r
+ *\r
+ * @param block the rest input (incomplete chunk)\r
+ * @param blockLength the length of the block: 0..63\r
+ */\r
+void ReRPD64::finalize() {\r
+ uint8_t* block = m_waiting;\r
+ int blockLength = m_lengthWaiting;\r
+ // append "1" bit to message\r
+ // Notice: the input bytes are considered as bits strings,\r
+ // where the first bit is the most significant bit of the byte.\r
+ block[blockLength++] = 0x80;\r
+ //Pre-processing: padding with zeros\r
+ //append "0" bit until message length in bits ≡ 448 (mod 512)\r
+ // fill the rest of the chunk with '\0'.\r
+ // the last 8 bytes is set to the length in bits (length in bytes * 8)\r
+ int restLength = (m_length + 1) % 64;\r
+ // 0 -> 56, 1 -> 55, 2 -> 54, ... 55 -> 1, 56 -> 0,\r
+ // 57 -> 63, 58 -> 62, ... 63 -> 57\r
+ int zeros = restLength <= 56 ? 56 - restLength : 120 - restLength;\r
+ memset(block + blockLength, 0, zeros);\r
+ blockLength += zeros;\r
+ //append original length in bits mod (2 pow 64) to message\r
+ uint64_t lengthBits = 8LL * m_length + m_salt;\r
+#if defined __LITTLE_ENDIAN__\r
+ memcpy(block + blockLength, &lengthBits, 8);\r
+ blockLength += 8;\r
+#else\r
+ block[blockLength++] = lengthBits;\r
+ lengthBits >>= 8;\r
+ block[blockLength++] = lengthBits;\r
+ lengthBits >>= 8;\r
+ block[blockLength++] = lengthBits;\r
+ lengthBits >>= 8;\r
+ block[blockLength++] = lengthBits;\r
+ lengthBits >>= 8;\r
+ block[blockLength++] = lengthBits;\r
+ lengthBits >>= 8;\r
+ block[blockLength++] = lengthBits;\r
+ lengthBits >>= 8;\r
+ block[blockLength++] = lengthBits;\r
+ lengthBits >>= 8;\r
+ block[blockLength++] = lengthBits;\r
+#endif\r
+ processChunk(block);\r
+ if (blockLength > 64)\r
+ processChunk(block + 64);\r
+ m_a0 ^= m_b0;\r
+ m_c0 ^= m_d0;\r
+#if defined __LITTLE_ENDIAN__\r
+ memcpy(m_digest, &m_a0, 8);\r
+ memcpy(m_digest + 8, &m_c0, 8);\r
+#else\r
+#define oneQWord(word, ix) m_digest[ix] = word; word >>= 8; \\r
+ m_digest[ix + 1] = word; word >>= 8; m_digest[ix + 2] = word; word >>= 8; \\r
+ m_digest[ix + 3] = word; word >>= 8; m_digest[ix + 4] = word; word >>= 8; \\r
+ m_digest[ix + 4] = word; word >>= 8; m_digest[ix + 5] = word; word >>= 8; \\r
+ m_digest[ix + 6] = word; word >>= 8; m_digest[ix + 7] = word\r
+ oneWord(m_a0, 0);\r
+ oneWord(m_c0, 8);\r
+#endif\r
+}\r
+\r
+/**\r
+ * Returns the binary digest value.\r
+ *\r
+ * @return the binary digest (16 byte array)\r
+ */\r
+const ReByteBuffer& ReRPD64::hexDigest() {\r
+ if (m_hexDigest.length() == 0) {\r
+ digest();\r
+ for (int ix = 0; ix < 16; ix++) {\r
+ m_hexDigest.appendInt(m_digest[ix], "%02x");\r
+ }\r
+ }\r
+ return m_hexDigest;\r
+}\r
+#define F1(B, C, D) ((B & C) | (~ B & D))\r
+#define F2(B, C, D) ((D & B) | (C & ~ D))\r
+#define F3(B, C, D) ((B ^ C) ^ D)\r
+#define F4(B, C, D) (C ^ (B | ~ D))\r
+\r
+#if defined OPTIMIZER_WORKS_GREAT\r
+inline void rotate_left_and_add(uint64_t& rc, uint64_t data, int shift, uint64_t term) {\r
+ rc = ((data << shift) | (data >> (64-shift))) + term;\r
+}\r
+inline void X1(uint64_t &var, uint64_t x, uint64_t y, uint64_t z,\r
+ uint64_t data, uint64_t aConst, uint64_t shift) {\r
+ rotate_left_and_add(var, var + F1(x, y, z) + data + aConst, shift, x);\r
+}\r
+inline void X2(uint64_t& var, uint64_t x, uint64_t y, uint64_t z,\r
+ uint64_t data, uint64_t aConst, uint64_t shift) {\r
+ rotate_left_and_add(var, var + F2(x, y, z) + data + aConst, shift, x);\r
+}\r
+\r
+inline void X3(uint64_t& var, uint64_t x, uint64_t y, uint64_t z,\r
+ uint64_t data, uint64_t aConst, uint64_t shift) {\r
+ rotate_left_and_add(var, var + F3(x, y, z) + data + aConst, shift, x);\r
+}\r
+\r
+inline void X4(uint64_t& var, uint64_t x, uint64_t y, uint64_t z,\r
+ uint64_t data, uint64_t aConst, uint64_t shift) {\r
+ rotate_left_and_add(var, var + F4(x, y, z) + data + aConst, shift, x);\r
+}\r
+#else\r
+#define rotate_left_and_add(var, data, shift, term) { \\r
+ uint64_t val = data; \\r
+ var = ((val << (shift)) | (val >> (64-(shift)))) + term; \\r
+}\r
+#define X1(var, x, y, z, data, aConst, shift) \\r
+ rotate_left_and_add(var, var + F1(x, y, z) + data + aConst, shift, x)\r
+#define X2(var, x, y, z, data, aConst, shift) \\r
+ rotate_left_and_add(var, var + F2(x, y, z) + data + aConst, shift, x)\r
+#define X3(var, x, y, z, data, aConst, shift) \\r
+ rotate_left_and_add(var, var + F3(x, y, z) + data + aConst, shift, x)\r
+#define X4(var, x, y, z, data, aConst, shift) \\r
+ rotate_left_and_add(var, var + F4(x, y, z) + data + aConst, shift, x)\r
+#endif /* OPTIMIZER_WORKS_GREAT */\r
+\r
+/**\r
+ * Processes a 512 bit block ("chunk").\r
+ *\r
+ */\r
+void ReRPD64::processChunk(const uint8_t block[64]) {\r
+ uint64_t M[8];\r
+ // break chunk into sixteen 32-bit words M[j], 0 ≤ j ≤ 15\r
+#ifdef __LITTLE_ENDIAN__\r
+ for (int ix = 0; ix < 8; ix++) {\r
+ //memcpy(&M[ix], block + ix * 8, 8);\r
+ M[ix] = *(uint64_t*) (block + ix * 8);\r
+ }\r
+#elif defined __BIG_ENDIAN__\r
+ for (int ix = 0; ix < 16; ix++) {\r
+ uint64_t x = block[8-1];\r
+ for (int jj = 8 - 2; jj >= 0; jj--) {\r
+ x = (x << 8) + block[jj];\r
+ }\r
+ M[ix] = x;\r
+ block += 8;\r
+ }\r
+#else\r
+# error "missing __LITTLE_ENDIAN__ or __BIG_ENDIAN__"\r
+#endif\r
+ //Initialize hash value for this chunk:\r
+ uint64_t A = m_a0;\r
+ uint64_t B = m_b0;\r
+ uint64_t C = m_c0;\r
+ uint64_t D = m_d0;\r
+ /* Round 1 */\r
+ X1(A, B, C, D, M[0], 0xd76aa478698098d8ll, 7);\r
+ X1(D, A, B, C, M[1], 0xe8c7b7568b44f7afll, 12);\r
+ X1(C, D, A, B, M[2], 0x242070dbffff5bb1ll, 17);\r
+ X1(B, C, D, A, M[3], 0xc1bdceee895cd7bell, 22);\r
+ X1(A, B, C, D, M[4], 0xf57c0faf6b901122ll, 32 + 7);\r
+ X1(D, A, B, C, M[5], 0x4787c62afd987193ll, 32 + 12);\r
+ X1(C, D, A, B, M[6], 0xa8304613a679438ell, 32 + 17);\r
+ X1(B, C, D, A, M[7], 0xfd46950149b40821ll, 32 + 22);\r
+\r
+ /* Round 2 */\r
+ X2(A, B, C, D, M[1], 0xf61e256221e1cde6ll, 5);\r
+ X2(D, A, B, C, M[6], 0xc040b340c33707d6ll, 9);\r
+ X2(C, D, A, B, M[3], 0x265e5a51f4d50d87ll, 14);\r
+ X2(B, C, D, A, M[0], 0xe9b6c7aa455a14edll, 20);\r
+ X2(A, B, C, D, M[5], 0xd62f105da9e3e905ll, 5 + 32);\r
+ X2(D, A, B, C, M[2], 0x02441453fcefa3f8ll, 9 + 32);\r
+ X2(C, D, A, B, M[7], 0xd8a1e681676f02d9ll, 14 + 32);\r
+ X2(B, C, D, A, M[4], 0xe7d3fbc88d2a4c8all, 20 + 32);\r
+\r
+ /* Round 3 */\r
+ X3(A, B, C, D, M[5], 0xfffa3942289b7ec6ll, 4);\r
+ X3(D, A, B, C, M[2], 0x8771f681eaa127fall, 11);\r
+ X3(C, D, A, B, M[7], 0x6d9d6122d4ef3085ll, 16);\r
+ X3(B, C, D, A, M[4], 0xfde5380c04881d05ll, 23);\r
+ X3(A, B, C, D, M[1], 0xa4beea44d9d4d039ll, 4 + 32);\r
+ X3(D, A, B, C, M[6], 0x4bdecfa9e6db99e5ll, 11 + 32);\r
+ X3(C, D, A, B, M[3], 0xf6bb4b601fa27cf8ll, 16 + 32);\r
+ X3(B, C, D, A, M[0], 0xbebfbc70c4ac5665ll, 23 + 32);\r
+\r
+ /* Round 4 */\r
+ X4(A, B, C, D, M[0], 0xf42922446fa87e4fll, 6);\r
+ X4(D, A, B, C, M[7], 0x432aff97fe2ce6e0ll, 10);\r
+ X4(C, D, A, B, M[4], 0xab9423a7a3014314ll, 15);\r
+ X4(B, C, D, A, M[1], 0xfc93a0394e0811a1ll, 21);\r
+ X4(A, B, C, D, M[6], 0x655b59c3f7537e82ll, 6 + 32);\r
+ X4(D, A, B, C, M[3], 0x8f0ccc92bd3af235ll, 10 + 32);\r
+ X4(C, D, A, B, M[0], 0xffeff47d2ad7d2bbll, 15 + 32);\r
+ X4(B, C, D, A, M[5], 0x85845dd1eb86d391ll, 21 + 32);\r
+\r
+ //Add this chunk's hash to result so far:\r
+ m_a0 += A;\r
+ m_b0 += B;\r
+ m_c0 += C;\r
+ m_d0 += D;\r
+}\r
+/**\r
+ * Prepares the instance for a new checksum.\r
+ */\r
+void ReRPD64::reset() {\r
+ m_a0 = 0xd76aa478698098d8ll;\r
+ m_b0 = 0xe8c7b7568b44f7afll;\r
+ m_c0 = 0x242070dbffff5bb1ll;\r
+ m_d0 = 0xc1bdceee895cd7bell;\r
+ memset(m_digest, 0, sizeof m_digest);\r
+ memset(m_waiting, 0, sizeof m_waiting);\r
+ m_lengthWaiting = 0;\r
+ m_length = 0;\r
+ m_hexDigest.setLength(0);\r
+ m_finalized = false;\r
+}\r
+/**\r
+ * Processes a 64 byte block.\r
+ *\r
+ * @param block a block which should be added to the digest\r
+ * @param blockLength the length of <code>block</code>\r
+ */\r
+void ReRPD64::update(const uint8_t* block, int blockLength) {\r
+ if (blockLength == -1)\r
+ blockLength = strlen((const char*) block);\r
+ // process the "waiting" input (incomplete chunk):\r
+ m_length += blockLength;\r
+ if (m_lengthWaiting > 0) {\r
+ int rest = 64 - m_lengthWaiting;\r
+ if (rest > blockLength)\r
+ rest = blockLength;\r
+ memcpy(m_waiting + m_lengthWaiting, block, rest);\r
+ blockLength -= rest;\r
+ block += rest;\r
+ m_lengthWaiting += rest;\r
+ // Is the chunk complete?\r
+ if (m_lengthWaiting == 64) {\r
+ processChunk (m_waiting);\r
+ m_lengthWaiting = 0;\r
+ }\r
+ }\r
+ // process full 512 bit chunks (64 byte blocks):\r
+ for (int ix = blockLength / 64; ix > 0; ix--) {\r
+ processChunk(block);\r
+ block += 64;\r
+ }\r
+ blockLength %= 64;\r
+ if (blockLength != 0) {\r
+ assert(m_lengthWaiting == 0);\r
+ memcpy(m_waiting, block, blockLength);\r
+ m_lengthWaiting = blockLength;\r
+ }\r
+}\r
+\r