]> gitweb.hamatoma.de Git - crepublib/commitdiff
ReDigest + ReRPD64
authorHamatoma <git.tortouse@hm.f-r-e-i.de>
Sat, 28 Feb 2015 23:24:26 +0000 (00:24 +0100)
committerHamatoma <git.tortouse@hm.f-r-e-i.de>
Sat, 28 Feb 2015 23:24:26 +0000 (00:24 +0100)
base/ReLogger.hpp
cunit/cuReMD5.cpp
cunit/cuReRPD64.cpp [new file with mode: 0644]
cunit/testall.cpp
math/ReMD5.cpp
math/ReMD5.hpp
math/ReRPD64.cpp [new file with mode: 0644]
math/ReRPD64.hpp [new file with mode: 0644]
math/remath.hpp

index 4bb436dd37f17e78a704b3748840e9e59d0a1286..b1e99ecc8f8464dac211110bfe253e2019605cb6 100644 (file)
@@ -19,7 +19,10 @@ typedef unsigned long int ReLogLocation;
  * Aborts, errors, warnings and informations.
  */
 enum ReLogClass {
-       LOG_ABORT = 1, LOG_ERROR = 2, LOG_WARNING = 4, LOG_INFO = 8,
+       LOG_ABORT = 1,
+       LOG_ERROR = 2,
+       LOG_WARNING = 4,
+       LOG_INFO = 8,
 
        LOG_CLASS_ALL = 0xf
 };
index 6894de823415671e292480a421e21ec7222155e6..a80828f1a7885e4e28948ceb15374cb280b79bc0 100644 (file)
@@ -9,7 +9,6 @@
 
 #include "base/rebase.hpp"
 #include "math/remath.hpp"
-#include "math/md5.hpp"
 
 class TestReMd5: public ReTestUnit {
 public:
diff --git a/cunit/cuReRPD64.cpp b/cunit/cuReRPD64.cpp
new file mode 100644 (file)
index 0000000..0c2e4b3
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * 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;
+}
index 7e55440eb75c1be3efe020aad0b4f0e16f8bc7bb..ddc73aed3a17707e30805659f8d639803596d649 100644 (file)
@@ -71,6 +71,8 @@ void testOs() {
 void testMath() {
        extern void testReMD5();
        testReMD5();
+       extern void testReRPD64();
+       testReRPD64();
        extern void testReRandomizer();
        testReRandomizer();
 }
index fe9aea3a504874ac9bb5f813fe80639ac58fb9ac..000252d5397a0bded5f2ad3da8391dfd6b2fc7bd 100644 (file)
@@ -8,15 +8,15 @@
 #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
@@ -31,38 +31,105 @@ const uint32_t ReMD5::m_K[64] = { 0xd76aa478, 0xe8c7b756, 0x242070db,
 \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
@@ -83,7 +150,7 @@ void ReMD5::finalize() {
        //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
@@ -112,8 +179,8 @@ void ReMD5::finalize() {
        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
@@ -130,27 +197,12 @@ void ReMD5::finalize() {
 #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
@@ -173,7 +225,7 @@ void ReMD5::processChunk2(const uint8_t block[64]) {
 #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
@@ -320,7 +372,7 @@ inline void X4(uint32_t& var, uint32_t x, uint32_t y, uint32_t z,
  * ...\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
@@ -442,41 +494,3 @@ void ReMD5::reset() {
        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
index d4b5e1af53573dd20276fef6834421a4d4654cf6..427db8c340b85257f2f46199ef3de2a65358cef2 100644 (file)
@@ -8,45 +8,60 @@
 #ifndef MATH_REMD5_HPP_
 #define MATH_REMD5_HPP_
 
-typedef uint8_t ReDigest[16];
-/**
- * Building of the MD5 checksum.
- *
- * The algorithm is described in http://en.wikipedia.org/wiki/MD5.
- */
-class ReMD5 {
+typedef uint8_t ReMD5Digest_t[16];
+#define RE_DIGEST_CHUNK_SIZE 64
+
+class ReDigest {
 public:
-       ReMD5();
-       virtual ~ReMD5();
+       ReDigest(uint8_t* buffer, size_t bufferSize);
+       virtual ~ReDigest();
 public:
        const uint8_t* digest();
        const ReByteBuffer& hexDigest();
-       void update(const uint8_t* block, int blockLength);
-       void processChunk(const uint8_t block[64]);
-       void processChunk2(const uint8_t block[64]);
-       void reset();
-private:
-       void finalize();
-
-private:
-       ReDigest m_digest;
+       virtual void update(const uint8_t* block, int blockLength);
+       virtual void processChunk(const uint8_t* block) = 0;
+       virtual void reset() = 0;
+protected:
+       virtual void finalize() = 0;
+protected:
+       uint8_t* m_digest;
+       size_t m_digestSize;
        ReByteBuffer m_hexDigest;
        // normally only the first chunk is used (64 byte), but while finalization
        // a 2nd chunk may be needed.
-       uint8_t m_waiting[64 + 64];
+       uint8_t m_waiting[RE_DIGEST_CHUNK_SIZE + RE_DIGEST_CHUNK_SIZE];
        int m_lengthWaiting;
        // total count of input bytes:
        uint32_t m_length;
+       bool m_finalized;
+};
+
+/**
+ * Building of the MD5 checksum.
+ *
+ * The algorithm is described in http://en.wikipedia.org/wiki/MD5.
+ */
+class ReMD5 : public ReDigest {
+public:
+       ReMD5();
+       virtual ~ReMD5();
+public:
+       virtual void processChunk(const uint8_t* block);
+       void processChunk2(const uint8_t* block);
+       virtual void reset();
+protected:
+       virtual void finalize();
+private:
+       ReMD5Digest_t m_digest;
        uint32_t m_a0;
        uint32_t m_b0;
        uint32_t m_c0;
        uint32_t m_d0;
-       bool m_finalized;
 private:
        // number of shifts per round:
-       static const int m_s[64];
+       static const int m_s[RE_DIGEST_CHUNK_SIZE];
        // Constants:
-       static const uint32_t m_K[64];
+       static const uint32_t m_K[RE_DIGEST_CHUNK_SIZE];
 };
 
 #endif /* MATH_REMD5_HPP_ */
diff --git a/math/ReRPD64.cpp b/math/ReRPD64.cpp
new file mode 100644 (file)
index 0000000..5fa6a26
--- /dev/null
@@ -0,0 +1,297 @@
+/*\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
diff --git a/math/ReRPD64.hpp b/math/ReRPD64.hpp
new file mode 100644 (file)
index 0000000..21ba5fa
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * ReRPD64.hpp
+ *
+ *  Created on: 30.01.2015
+ *      Author: hm
+ */
+
+#ifndef MATH_RERPD64_HPP_
+#define MATH_RERPD64_HPP_
+
+typedef uint8_t ReRPD64Digest[16];
+/**
+ * Building of the Real Publib library checksum.
+ *
+ * The algorithm is similar to MD5, but calculation is done in 64-bit.
+ */
+class ReRPD64 {
+public:
+       ReRPD64();
+       virtual ~ReRPD64();
+public:
+       const uint8_t* digest();
+       const ReByteBuffer& hexDigest();
+       void update(const uint8_t* block, int blockLength);
+       void processChunk(const uint8_t block[64]);
+       void reset();
+       void setSalt(uint64_t salt);
+private:
+       void finalize();
+
+private:
+       ReRPD64Digest m_digest;
+       ReByteBuffer m_hexDigest;
+       // normally only the first chunk is used (64 byte), but while finalization
+       // a 2nd chunk may be needed.
+       uint8_t m_waiting[64 + 64];
+       int m_lengthWaiting;
+       // total count of input bytes:
+       uint64_t m_length;
+       uint64_t m_a0;
+       uint64_t m_b0;
+       uint64_t m_c0;
+       uint64_t m_d0;
+       bool m_finalized;
+       uint64_t m_salt;
+};
+
+#endif /* MATH_RERPD64_HPP_ */
index b2b5d00677a9e0d60fe722d24ae3c21ff071610d..db9eca9d3347bb10a66396586964947d70b1c76e 100644 (file)
@@ -14,5 +14,6 @@
 #include "math/ReObfuscator.hpp"
 #include "math/ReRandomizer.hpp"
 #include "math/ReMD5.hpp"
+#include "math/ReRPD64.hpp"
 
 #endif /* REMATH_HPP_ */