#define _RIPEMD160_C_ 1 #include "ripemd160_256.h" // adapted by Pieter Wuille in 2012; all changes are in the public domain // modified by Ryan Castellucci in 2015; all changes are in the public domain /* * * RIPEMD160.c : RIPEMD-160 implementation * * Written in 2008 by Dwayne C. Litzenberger * * =================================================================== * The contents of this file are dedicated to the public domain. To * the extent that dedication to the public domain is not available, * everyone is granted a worldwide, perpetual, royalty-free, * non-exclusive license to exercise all rights associated with the * contents of this file for any purpose whatsoever. * No rights are reserved. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * =================================================================== * * Country of origin: Canada * * This implementation (written in C) is based on an implementation the author * wrote in Python. * * This implementation was written with reference to the RIPEMD-160 * specification, which is available at: * http://homes.esat.kuleuven.be/~cosicart/pdf/AB-9601/ * * It is also documented in the _Handbook of Applied Cryptography_, as * Algorithm 9.55. It's on page 30 of the following PDF file: * http://www.cacr.math.uwaterloo.ca/hac/about/chap9.pdf * * The RIPEMD-160 specification doesn't really tell us how to do padding, but * since RIPEMD-160 is inspired by MD4, you can use the padding algorithm from * RFC 1320. * * According to http://www.users.zetnet.co.uk/hopwood/crypto/scan/md.html: * "RIPEMD-160 is big-bit-endian, little-byte-endian, and left-justified." */ #include #include #define RIPEMD160_DIGEST_SIZE 20 #define BLOCK_SIZE 64 /* cyclic left-shift the 32-bit word n left by s bits */ #define ROL(s, n) (((n) << (s)) | ((n) >> (32-(s)))) /* Initial values for the chaining variables. * This is just 0123456789ABCDEFFEDCBA9876543210F0E1D2C3 in little-endian. */ static const uint32_t initial_h[5] = { 0x67452301u, 0xEFCDAB89u, 0x98BADCFEu, 0x10325476u, 0xC3D2E1F0u }; /* Ordering of message words. Based on the permutations rho(i) and pi(i), defined as follows: * * rho(i) := { 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8 }[i] 0 <= i <= 15 * * pi(i) := 9*i + 5 (mod 16) * * Line | Round 1 | Round 2 | Round 3 | Round 4 | Round 5 * -------+-----------+-----------+-----------+-----------+----------- * left | id | rho | rho^2 | rho^3 | rho^4 * right | pi | rho pi | rho^2 pi | rho^3 pi | rho^4 pi */ /* Left line */ static const uint8_t RL[5][16] = { { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, /* Round 1: id */ { 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8 }, /* Round 2: rho */ { 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12 }, /* Round 3: rho^2 */ { 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2 }, /* Round 4: rho^3 */ { 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13 } /* Round 5: rho^4 */ }; /* Right line */ static const uint8_t RR[5][16] = { { 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12 }, /* Round 1: pi */ { 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2 }, /* Round 2: rho pi */ { 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13 }, /* Round 3: rho^2 pi */ { 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14 }, /* Round 4: rho^3 pi */ { 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11 } /* Round 5: rho^4 pi */ }; /* * Shifts - Since we don't actually re-order the message words according to * the permutations above (we could, but it would be slower), these tables * come with the permutations pre-applied. */ /* Shifts, left line */ static const uint8_t SL[5][16] = { { 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8 }, /* Round 1 */ { 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12 }, /* Round 2 */ { 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5 }, /* Round 3 */ { 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12 }, /* Round 4 */ { 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6 } /* Round 5 */ }; /* Shifts, right line */ static const uint8_t SR[5][16] = { { 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6 }, /* Round 1 */ { 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11 }, /* Round 2 */ { 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5 }, /* Round 3 */ { 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8 }, /* Round 4 */ { 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11 } /* Round 5 */ }; /* static padding for 256 bit input */ static const uint8_t pad256[32] = { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* length 256 bits, little endian uint64_t */ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; /* Boolean functions */ #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 F5(x, y, z) ((x) ^ ((y) | ~(z))) /* Round constants, left line */ static const uint32_t KL[5] = { 0x00000000u, /* Round 1: 0 */ 0x5A827999u, /* Round 2: floor(2**30 * sqrt(2)) */ 0x6ED9EBA1u, /* Round 3: floor(2**30 * sqrt(3)) */ 0x8F1BBCDCu, /* Round 4: floor(2**30 * sqrt(5)) */ 0xA953FD4Eu /* Round 5: floor(2**30 * sqrt(7)) */ }; /* Round constants, right line */ static const uint32_t KR[5] = { 0x50A28BE6u, /* Round 1: floor(2**30 * cubert(2)) */ 0x5C4DD124u, /* Round 2: floor(2**30 * cubert(3)) */ 0x6D703EF3u, /* Round 3: floor(2**30 * cubert(5)) */ 0x7A6D76E9u, /* Round 4: floor(2**30 * cubert(7)) */ 0x00000000u /* Round 5: 0 */ }; static inline void byteswap32(uint32_t *v) { union { uint32_t w; uint8_t b[4]; } x, y; x.w = *v; y.b[0] = x.b[3]; y.b[1] = x.b[2]; y.b[2] = x.b[1]; y.b[3] = x.b[0]; *v = y.w; /* Wipe temporary variables */ x.w = y.w = 0; } static inline void byteswap_digest(uint32_t *p) { unsigned int i; for (i = 0; i < 4; i++) { byteswap32(p++); byteswap32(p++); byteswap32(p++); byteswap32(p++); } } /* The RIPEMD160 compression function. */ static inline void ripemd160_rawcompress(void *pbuf, void *ph) { uint8_t w, round; uint32_t T; uint32_t AL, BL, CL, DL, EL; /* left line */ uint32_t AR, BR, CR, DR, ER; /* right line */ uint32_t *buf = pbuf; uint32_t *h = ph; /* Byte-swap the buffer if we're on a big-endian machine */ #ifdef PCT_BIG_ENDIAN byteswap_digest(buf); #endif /* initialize state */ memcpy(h, initial_h, RIPEMD160_DIGEST_SIZE); /* Load the left and right lines with the initial state */ AL = AR = h[0]; BL = BR = h[1]; CL = CR = h[2]; DL = DR = h[3]; EL = ER = h[4]; /* Round 1 */ round = 0; for (w = 0; w < 16; w++) { /* left line */ T = ROL(SL[round][w], AL + F1(BL, CL, DL) + buf[RL[round][w]] + KL[round]) + EL; AL = EL; EL = DL; DL = ROL(10, CL); CL = BL; BL = T; } for (w = 0; w < 16; w++) { /* right line */ T = ROL(SR[round][w], AR + F5(BR, CR, DR) + buf[RR[round][w]] + KR[round]) + ER; AR = ER; ER = DR; DR = ROL(10, CR); CR = BR; BR = T; } /* Round 2 */ round++; for (w = 0; w < 16; w++) { /* left line */ T = ROL(SL[round][w], AL + F2(BL, CL, DL) + buf[RL[round][w]] + KL[round]) + EL; AL = EL; EL = DL; DL = ROL(10, CL); CL = BL; BL = T; } for (w = 0; w < 16; w++) { /* right line */ T = ROL(SR[round][w], AR + F4(BR, CR, DR) + buf[RR[round][w]] + KR[round]) + ER; AR = ER; ER = DR; DR = ROL(10, CR); CR = BR; BR = T; } /* Round 3 */ round++; for (w = 0; w < 16; w++) { /* left line */ T = ROL(SL[round][w], AL + F3(BL, CL, DL) + buf[RL[round][w]] + KL[round]) + EL; AL = EL; EL = DL; DL = ROL(10, CL); CL = BL; BL = T; } for (w = 0; w < 16; w++) { /* right line */ T = ROL(SR[round][w], AR + F3(BR, CR, DR) + buf[RR[round][w]] + KR[round]) + ER; AR = ER; ER = DR; DR = ROL(10, CR); CR = BR; BR = T; } /* Round 4 */ round++; for (w = 0; w < 16; w++) { /* left line */ T = ROL(SL[round][w], AL + F4(BL, CL, DL) + buf[RL[round][w]] + KL[round]) + EL; AL = EL; EL = DL; DL = ROL(10, CL); CL = BL; BL = T; } for (w = 0; w < 16; w++) { /* right line */ T = ROL(SR[round][w], AR + F2(BR, CR, DR) + buf[RR[round][w]] + KR[round]) + ER; AR = ER; ER = DR; DR = ROL(10, CR); CR = BR; BR = T; } /* Round 5 */ round++; for (w = 0; w < 16; w++) { /* left line */ T = ROL(SL[round][w], AL + F5(BL, CL, DL) + buf[RL[round][w]] + KL[round]) + EL; AL = EL; EL = DL; DL = ROL(10, CL); CL = BL; BL = T; } for (w = 0; w < 16; w++) { /* right line */ T = ROL(SR[round][w], AR + F1(BR, CR, DR) + buf[RR[round][w]] + KR[round]) + ER; AR = ER; ER = DR; DR = ROL(10, CR); CR = BR; BR = T; } /* Final mixing stage */ T = h[1] + CL + DR; h[1] = h[2] + DL + ER; h[2] = h[3] + EL + AR; h[3] = h[4] + AL + BR; h[4] = h[0] + BL + CR; h[0] = T; /* Byte-swap the output if we're on a big-endian machine */ #ifdef PCT_BIG_ENDIAN byteswap_digest(h); #endif } void ripemd160_256(const void *in, void *out) { unsigned char buf[64]; /* copy input data */ memcpy(buf + 0, in, 32); /* append fixed padding */ memcpy(buf + 32, pad256, 32); /* compute and output hash */ ripemd160_rawcompress(buf, out); }