// MakeRIPEMD128.cpp: CMakeRIPEMD128 クラスのインプリメンテーション
//
////////////////////////////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "MakeRIPEMD128.h"


static void MakeRIPEMD128Helper_c(const void *pBuffer, void *hash, DWORD len);
extern "C" void CDECL MakeRIPEMD128Helper_asm(const void *pBuffer, void *hash, DWORD len);


static const DWORD hinit[] = { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476 };
static const DWORD k1[] = { 0x00000000, 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc };
static const DWORD k2[] = { 0x50a28be6, 0x5c4dd124, 0x6d703ef3, 0x00000000 };
static const DWORD r1[] = {
   0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
   7,  4, 13,  1, 10,  6, 15,  3, 12,  0,  9,  5,  2, 14, 11,  8,
   3, 10, 14,  4,  9, 15,  8,  1,  2,  7,  0,  6, 13, 11,  5, 12,
   1,  9, 11, 10,  0,  8, 12,  4, 13,  3,  7, 15, 14,  5,  6,  2,
};
static const DWORD s1[] = {
  11, 14, 15, 12,  5,  8,  7,  9, 11, 13, 14, 15,  6,  7,  9,  8,
   7,  6,  8, 13, 11,  9,  7, 15,  7, 12, 15,  9, 11,  7, 13, 12,
  11, 13,  6,  7, 14,  9, 13, 15, 14,  8, 13,  6,  5, 12,  7,  5,
  11, 12, 14, 15, 14, 15,  9,  8,  9, 14,  5,  6,  8,  6,  5, 12,
};
static const DWORD r2[] = {
   5, 14,  7,  0,  9,  2, 11,  4, 13,  6, 15,  8,  1, 10,  3, 12,
   6, 11,  3,  7,  0, 13,  5, 10, 14, 15,  8, 12,  4,  9,  1,  2,
  15,  5,  1,  3,  7, 14,  6,  9, 11,  8, 12,  2, 10,  0,  4, 13,
   8,  6,  4,  1,  3, 11, 15,  0,  5, 12,  2, 13,  9,  7, 10, 14,
};
static const DWORD s2[] = {
   8,  9,  9, 11, 13, 15, 15,  5,  7,  7,  8, 11, 14, 14, 12,  6,
   9, 13, 15,  7, 12,  8,  9, 11,  7,  7, 12,  7,  6, 15, 13, 11,
   9,  7, 15, 11,  8,  6,  6, 14, 12, 13,  5, 14, 13, 13,  7,  5,
  15,  5,  8, 11, 14, 14,  6, 14,  6,  9, 12,  9, 12,  5, 15,  8,
};


////////////////////////////////////////////////////////////////////////////////////////////////////

CMakeRIPEMD128::CMakeRIPEMD128()
{
    Initialize();
}

CMakeRIPEMD128::~CMakeRIPEMD128()
{
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void CMakeRIPEMD128::Initialize()
{
    CMakeHashAlgorithm::Initialize();
    memcpy(m_pHash, hinit, 16);
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void CMakeRIPEMD128::ComputeHashFinalHelper(void *msg_digest)
{
    BYTE buf[64];
    DWORD len;
    QWORD string_bit_len;

    memcpy(msg_digest, m_pHash, 16);

    len = m_dwRestLen;
    memcpy(buf, m_pRest, len);
    memset(buf+len, 0, 64-len);
    buf[len] |= 0x80;

    if ( len >= 56 )
    {
        ComputeHashHelper(buf, msg_digest, 64);
        memset(buf, 0, 56);
    }

    string_bit_len = m_qwSrcLen * 8;
    memcpy(&buf[56], &string_bit_len, 8);

    ComputeHashHelper(buf, msg_digest, 64);
}

DWORD CMakeRIPEMD128::ComputeHashHelper(const void *pBuffer, void *msg_digest, DWORD len)
{
#if (USE_ASSEMBLER_RIPEMD128==0)
    MakeRIPEMD128Helper_c(pBuffer, msg_digest, len);
#else
    MakeRIPEMD128Helper_asm(pBuffer, msg_digest, len);
#endif
    return len % 64;
}


////////////////////////////////////////////////////////////////////////////////////////////////////
// C

#define F1(x, y, z)      ( (x) ^ (y) ^ (z) )
#define F2(x, y, z)      ( ((x)&(y)) | ((~(x))&(z)) )
#define F3(x, y, z)      ( ((x)|(~(y))) ^ z )
#define F4(x, y, z)      ( ((x)&(z)) | ((y)&(~(z))) )

#define subSUBROUND1(a, bcd, k, i)      ( ROTATE_L32(a+bcd+w[r1[i]]+k,s1[i]) )
#define subSUBROUND2(a, bcd, k, i)      ( ROTATE_L32(a+bcd+w[r2[i]]+k,s2[i]) )

#define SUBROUND1(funcname, a, b, c, d, j, i) \
    a = subSUBROUND1(a, ##funcname(b,c,d), k1[j], i); \

#define SUBROUND2(funcname, a, b, c, d, j, i) \
    a = subSUBROUND2(a, ##funcname(b,c,d), k2[j], i); \


void MakeRIPEMD128Helper_c(const void *pBuffer, void *hash, DWORD len)
{
    DWORD *w = (DWORD*)pBuffer;
    DWORD *h = (DWORD*)hash;
    DWORD A, B, C, D, T;
    DWORD Ad, Bd, Cd, Dd;
    DWORD i=len/64;

    A=h[0];   B=h[1];   C=h[2];   D=h[3];
    Ad=h[0];  Bd=h[1];  Cd=h[2];  Dd=h[3];

    while ( i > 0 ) {
        SUBROUND1(F1, A, B, C, D, 0,  0)    SUBROUND2(F4, Ad, Bd, Cd, Dd, 0,  0)
        SUBROUND1(F1, D, A, B, C, 0,  1)    SUBROUND2(F4, Dd, Ad, Bd, Cd, 0,  1)
        SUBROUND1(F1, C, D, A, B, 0,  2)    SUBROUND2(F4, Cd, Dd, Ad, Bd, 0,  2)
        SUBROUND1(F1, B, C, D, A, 0,  3)    SUBROUND2(F4, Bd, Cd, Dd, Ad, 0,  3)
        SUBROUND1(F1, A, B, C, D, 0,  4)    SUBROUND2(F4, Ad, Bd, Cd, Dd, 0,  4)
        SUBROUND1(F1, D, A, B, C, 0,  5)    SUBROUND2(F4, Dd, Ad, Bd, Cd, 0,  5)
        SUBROUND1(F1, C, D, A, B, 0,  6)    SUBROUND2(F4, Cd, Dd, Ad, Bd, 0,  6)
        SUBROUND1(F1, B, C, D, A, 0,  7)    SUBROUND2(F4, Bd, Cd, Dd, Ad, 0,  7)
        SUBROUND1(F1, A, B, C, D, 0,  8)    SUBROUND2(F4, Ad, Bd, Cd, Dd, 0,  8)
        SUBROUND1(F1, D, A, B, C, 0,  9)    SUBROUND2(F4, Dd, Ad, Bd, Cd, 0,  9)
        SUBROUND1(F1, C, D, A, B, 0, 10)    SUBROUND2(F4, Cd, Dd, Ad, Bd, 0, 10)
        SUBROUND1(F1, B, C, D, A, 0, 11)    SUBROUND2(F4, Bd, Cd, Dd, Ad, 0, 11)
        SUBROUND1(F1, A, B, C, D, 0, 12)    SUBROUND2(F4, Ad, Bd, Cd, Dd, 0, 12)
        SUBROUND1(F1, D, A, B, C, 0, 13)    SUBROUND2(F4, Dd, Ad, Bd, Cd, 0, 13)
        SUBROUND1(F1, C, D, A, B, 0, 14)    SUBROUND2(F4, Cd, Dd, Ad, Bd, 0, 14)
        SUBROUND1(F1, B, C, D, A, 0, 15)    SUBROUND2(F4, Bd, Cd, Dd, Ad, 0, 15)

        SUBROUND1(F2, A, B, C, D, 1, 16)    SUBROUND2(F3, Ad, Bd, Cd, Dd, 1, 16)
        SUBROUND1(F2, D, A, B, C, 1, 17)    SUBROUND2(F3, Dd, Ad, Bd, Cd, 1, 17)
        SUBROUND1(F2, C, D, A, B, 1, 18)    SUBROUND2(F3, Cd, Dd, Ad, Bd, 1, 18)
        SUBROUND1(F2, B, C, D, A, 1, 19)    SUBROUND2(F3, Bd, Cd, Dd, Ad, 1, 19)
        SUBROUND1(F2, A, B, C, D, 1, 20)    SUBROUND2(F3, Ad, Bd, Cd, Dd, 1, 20)
        SUBROUND1(F2, D, A, B, C, 1, 21)    SUBROUND2(F3, Dd, Ad, Bd, Cd, 1, 21)
        SUBROUND1(F2, C, D, A, B, 1, 22)    SUBROUND2(F3, Cd, Dd, Ad, Bd, 1, 22)
        SUBROUND1(F2, B, C, D, A, 1, 23)    SUBROUND2(F3, Bd, Cd, Dd, Ad, 1, 23)
        SUBROUND1(F2, A, B, C, D, 1, 24)    SUBROUND2(F3, Ad, Bd, Cd, Dd, 1, 24)
        SUBROUND1(F2, D, A, B, C, 1, 25)    SUBROUND2(F3, Dd, Ad, Bd, Cd, 1, 25)
        SUBROUND1(F2, C, D, A, B, 1, 26)    SUBROUND2(F3, Cd, Dd, Ad, Bd, 1, 26)
        SUBROUND1(F2, B, C, D, A, 1, 27)    SUBROUND2(F3, Bd, Cd, Dd, Ad, 1, 27)
        SUBROUND1(F2, A, B, C, D, 1, 28)    SUBROUND2(F3, Ad, Bd, Cd, Dd, 1, 28)
        SUBROUND1(F2, D, A, B, C, 1, 29)    SUBROUND2(F3, Dd, Ad, Bd, Cd, 1, 29)
        SUBROUND1(F2, C, D, A, B, 1, 30)    SUBROUND2(F3, Cd, Dd, Ad, Bd, 1, 30)
        SUBROUND1(F2, B, C, D, A, 1, 31)    SUBROUND2(F3, Bd, Cd, Dd, Ad, 1, 31)

        SUBROUND1(F3, A, B, C, D, 2, 32)    SUBROUND2(F2, Ad, Bd, Cd, Dd, 2, 32)
        SUBROUND1(F3, D, A, B, C, 2, 33)    SUBROUND2(F2, Dd, Ad, Bd, Cd, 2, 33)
        SUBROUND1(F3, C, D, A, B, 2, 34)    SUBROUND2(F2, Cd, Dd, Ad, Bd, 2, 34)
        SUBROUND1(F3, B, C, D, A, 2, 35)    SUBROUND2(F2, Bd, Cd, Dd, Ad, 2, 35)
        SUBROUND1(F3, A, B, C, D, 2, 36)    SUBROUND2(F2, Ad, Bd, Cd, Dd, 2, 36)
        SUBROUND1(F3, D, A, B, C, 2, 37)    SUBROUND2(F2, Dd, Ad, Bd, Cd, 2, 37)
        SUBROUND1(F3, C, D, A, B, 2, 38)    SUBROUND2(F2, Cd, Dd, Ad, Bd, 2, 38)
        SUBROUND1(F3, B, C, D, A, 2, 39)    SUBROUND2(F2, Bd, Cd, Dd, Ad, 2, 39)
        SUBROUND1(F3, A, B, C, D, 2, 40)    SUBROUND2(F2, Ad, Bd, Cd, Dd, 2, 40)
        SUBROUND1(F3, D, A, B, C, 2, 41)    SUBROUND2(F2, Dd, Ad, Bd, Cd, 2, 41)
        SUBROUND1(F3, C, D, A, B, 2, 42)    SUBROUND2(F2, Cd, Dd, Ad, Bd, 2, 42)
        SUBROUND1(F3, B, C, D, A, 2, 43)    SUBROUND2(F2, Bd, Cd, Dd, Ad, 2, 43)
        SUBROUND1(F3, A, B, C, D, 2, 44)    SUBROUND2(F2, Ad, Bd, Cd, Dd, 2, 44)
        SUBROUND1(F3, D, A, B, C, 2, 45)    SUBROUND2(F2, Dd, Ad, Bd, Cd, 2, 45)
        SUBROUND1(F3, C, D, A, B, 2, 46)    SUBROUND2(F2, Cd, Dd, Ad, Bd, 2, 46)
        SUBROUND1(F3, B, C, D, A, 2, 47)    SUBROUND2(F2, Bd, Cd, Dd, Ad, 2, 47)

        SUBROUND1(F4, A, B, C, D, 3, 48)    SUBROUND2(F1, Ad, Bd, Cd, Dd, 3, 48)
        SUBROUND1(F4, D, A, B, C, 3, 49)    SUBROUND2(F1, Dd, Ad, Bd, Cd, 3, 49)
        SUBROUND1(F4, C, D, A, B, 3, 50)    SUBROUND2(F1, Cd, Dd, Ad, Bd, 3, 50)
        SUBROUND1(F4, B, C, D, A, 3, 51)    SUBROUND2(F1, Bd, Cd, Dd, Ad, 3, 51)
        SUBROUND1(F4, A, B, C, D, 3, 52)    SUBROUND2(F1, Ad, Bd, Cd, Dd, 3, 52)
        SUBROUND1(F4, D, A, B, C, 3, 53)    SUBROUND2(F1, Dd, Ad, Bd, Cd, 3, 53)
        SUBROUND1(F4, C, D, A, B, 3, 54)    SUBROUND2(F1, Cd, Dd, Ad, Bd, 3, 54)
        SUBROUND1(F4, B, C, D, A, 3, 55)    SUBROUND2(F1, Bd, Cd, Dd, Ad, 3, 55)
        SUBROUND1(F4, A, B, C, D, 3, 56)    SUBROUND2(F1, Ad, Bd, Cd, Dd, 3, 56)
        SUBROUND1(F4, D, A, B, C, 3, 57)    SUBROUND2(F1, Dd, Ad, Bd, Cd, 3, 57)
        SUBROUND1(F4, C, D, A, B, 3, 58)    SUBROUND2(F1, Cd, Dd, Ad, Bd, 3, 58)
        SUBROUND1(F4, B, C, D, A, 3, 59)    SUBROUND2(F1, Bd, Cd, Dd, Ad, 3, 59)
        SUBROUND1(F4, A, B, C, D, 3, 60)    SUBROUND2(F1, Ad, Bd, Cd, Dd, 3, 60)
        SUBROUND1(F4, D, A, B, C, 3, 61)    SUBROUND2(F1, Dd, Ad, Bd, Cd, 3, 61)
        SUBROUND1(F4, C, D, A, B, 3, 62)    SUBROUND2(F1, Cd, Dd, Ad, Bd, 3, 62)
        SUBROUND1(F4, B, C, D, A, 3, 63)    SUBROUND2(F1, Bd, Cd, Dd, Ad, 3, 63)


        T    = h[1] + C + Dd;
        h[1] = h[2] + D + Ad;
        h[2] = h[3] + A + Bd;
        h[3] = h[0] + B + Cd;
        h[0] = T;

        A=h[0];   B=h[1];   C=h[2];   D=h[3];
        Ad=h[0];  Bd=h[1];  Cd=h[2];  Dd=h[3];

        w+=16;
        i--;
    }
}



////////////////////////////////////////////////////////////////////////////////////////////////////
// test

BOOL CMakeRIPEMD128::Test()
{
    static const char *q1 = "abc";
    static const char *q2 = "abcdefghijklmnopqrstuvwxyz";
    static const char *q3 = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq";
    static const char *q4 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
    static const char *q5 = "12345678901234567890123456789012345678901234567890123456789012345678901234567890";

    static const char *a0 = "cdf26213a150dc3ecb610f18f6b38b46";
    static const char *a1 = "c14a12199c66e4ba84636b0f69144c77";
    static const char *a2 = "fd2aa607f71dc8f510714922b371834e";
    static const char *a3 = "a1aa0689d0fafa2ddc22e88b49133a06";
    static const char *a4 = "d1e959eb179c911faea4624c60c5c702";
    static const char *a5 = "3f45ef194732c2dbb2c4a2c769795fa3";
    static const char *a6 = "4a7f5723f954eba1216c9d8f6320431f";


    Initialize();
    if ( CmpHashValue(a0) ) {
        ASSERT(0);
        return FALSE;
    }

    Initialize();
    ComputeHash(q1, strlen(q1));
    if ( CmpHashValue(a1) ) {
        ASSERT(0);
        return FALSE;
    }

    Initialize();
    ComputeHash(q2, strlen(q2));
    if ( CmpHashValue(a2) ) {
        ASSERT(0);
        return FALSE;
    }

    Initialize();
    ComputeHash(q3, strlen(q3));
    if ( CmpHashValue(a3) ) {
        ASSERT(0);
        return FALSE;
    }

    Initialize();
    ComputeHash(q4, strlen(q4));
    if ( CmpHashValue(a4) ) {
        ASSERT(0);
        return FALSE;
    }

    Initialize();
    ComputeHash(q5, strlen(q5));
    if ( CmpHashValue(a5) ) {
        ASSERT(0);
        return FALSE;
    }

    Initialize();
    BYTE *pQ6=new BYTE[1000000];
    memset(pQ6, 'a', 1000000);
    ComputeHash(pQ6, 1000000);
    delete [] pQ6;
    if ( CmpHashValue(a6) ) {
        ASSERT(0);
        return FALSE;
    }

    return TRUE;
}

