/* See LICENSE file for copyright and license details. */
#include "common.h"
#ifdef SUPPORT_RIPEMD_160
#define LETO32(X)\
(((uint32_t)(X)[0] << 0) |\
((uint32_t)(X)[1] << 8) |\
((uint32_t)(X)[2] << 16) |\
((uint32_t)(X)[3] << 24))
static uint32_t rol32(uint32_t n, int k) { return (n << k) | (n >> (32 - k)); } /* k != 0, 32 */
static void
process_block(uint32_t h[5], const uint32_t *x, uint32_t w1[5], uint32_t w2[5])
{
#define F0(X, Y, Z) (X ^ Y ^ Z)
#define G0(X, Y, Z) ((X & Y) | (~X & Z))
#define H0(X, Y, Z) ((X | ~Y) ^ Z)
#define I0(X, Y, Z) ((X & Z) | (Y & ~Z))
#define J0(X, Y, Z) (X ^ (Y | ~Z))
#define F1(A, B, C, D, E, I, S) (A = rol32(F0(B, C, D) + A + x[I] + UINT32_C(0x00000000), S) + E, C = rol32(C, 10))
#define G1(A, B, C, D, E, I, S) (A = rol32(G0(B, C, D) + A + x[I] + UINT32_C(0x5a827999), S) + E, C = rol32(C, 10))
#define H1(A, B, C, D, E, I, S) (A = rol32(H0(B, C, D) + A + x[I] + UINT32_C(0x6ed9eba1), S) + E, C = rol32(C, 10))
#define I1(A, B, C, D, E, I, S) (A = rol32(I0(B, C, D) + A + x[I] + UINT32_C(0x8f1bbcdc), S) + E, C = rol32(C, 10))
#define J1(A, B, C, D, E, I, S) (A = rol32(J0(B, C, D) + A + x[I] + UINT32_C(0xa953fd4e), S) + E, C = rol32(C, 10))
#define F2(A, B, C, D, E, I, S) (A = rol32(F0(B, C, D) + A + x[I] + UINT32_C(0x00000000), S) + E, C = rol32(C, 10))
#define G2(A, B, C, D, E, I, S) (A = rol32(G0(B, C, D) + A + x[I] + UINT32_C(0x7a6d76e9), S) + E, C = rol32(C, 10))
#define H2(A, B, C, D, E, I, S) (A = rol32(H0(B, C, D) + A + x[I] + UINT32_C(0x6d703ef3), S) + E, C = rol32(C, 10))
#define I2(A, B, C, D, E, I, S) (A = rol32(I0(B, C, D) + A + x[I] + UINT32_C(0x5c4dd124), S) + E, C = rol32(C, 10))
#define J2(A, B, C, D, E, I, S) (A = rol32(J0(B, C, D) + A + x[I] + UINT32_C(0x50a28be6), S) + E, C = rol32(C, 10))
#define A 0
#define B 1
#define C 2
#define D 3
#define E 4
#define ONE(N, P, F, ...) F##P(w##P[(N+0)%5], w##P[(N+1)%5], w##P[(N+2)%5], w##P[(N+3)%5], w##P[(N+4)%5], __VA_ARGS__)
#define FIVE(L, P, F, I1, I2, I3, I4, I5, S1, S2, S3, S4, S5)\
(ONE(L + 4 * 0, P, F, I1, S1),\
ONE(L + 4 * 1, P, F, I2, S2),\
ONE(L + 4 * 2, P, F, I3, S3),\
ONE(L + 4 * 3, P, F, I4, S4),\
ONE(L + 4 * 4, P, F, I5, S5))
#define SIXTEEN(L, P, F, I11, I12, I13, I14, I15, I21, I22, I23, S11, S12, S13, S14, S15, S21, S22, S23,\
I24, I25, I31, I32, I33, I34, I35, I41, S24, S25, S31, S32, S33, S34, S35, S41)\
(FIVE(L, P, F, I11, I12, I13, I14, I15, S11, S12, S13, S14, S15),\
FIVE(L, P, F, I21, I22, I23, I24, I25, S21, S22, S23, S24, S25),\
FIVE(L, P, F, I31, I32, I33, I34, I35, S31, S32, S33, S34, S35), ONE(L, P, F, I41, S41))
register uint32_t htmp;
memcpy(w1, h, 5U * sizeof(*w1));
memcpy(w2, h, 5U * sizeof(*w2));
SIXTEEN(A, 1, F, 0, 1, 2, 3, 4, 5, 6, 7, 11, 14, 15, 12, 5, 8, 7, 9,
8, 9, 10, 11, 12, 13, 14, 15, 11, 13, 14, 15, 6, 7, 9, 8);
SIXTEEN(E, 1, G, 7, 4, 13, 1, 10, 6, 15, 3, 7, 6, 8, 13, 11, 9, 7, 15,
12, 0, 9, 5, 2, 14, 11, 8, 7, 12, 15, 9, 11, 7, 13, 12);
SIXTEEN(D, 1, H, 3, 10, 14, 4, 9, 15, 8, 1, 11, 13, 6, 7, 14, 9, 13, 15,
2, 7, 0, 6, 13, 11, 5, 12, 14, 8, 13, 6, 5, 12, 7, 5);
SIXTEEN(C, 1, I, 1, 9, 11, 10, 0, 8, 12, 4, 11, 12, 14, 15, 14, 15, 9, 8,
13, 3, 7, 15, 14, 5, 6, 2, 9, 14, 5, 6, 8, 6, 5, 12);
SIXTEEN(B, 1, J, 4, 0, 5, 9, 7, 12, 2, 10, 9, 15, 5, 11, 6, 8, 13, 12,
14, 1, 3, 8, 11, 6, 15, 13, 5, 12, 13, 14, 11, 8, 5, 6);
SIXTEEN(A, 2, J, 5, 14, 7, 0, 9, 2, 11, 4, 8, 9, 9, 11, 13, 15, 15, 5,
13, 6, 15, 8, 1, 10, 3, 12, 7, 7, 8, 11, 14, 14, 12, 6);
SIXTEEN(E, 2, I, 6, 11, 3, 7, 0, 13, 5, 10, 9, 13, 15, 7, 12, 8, 9, 11,
14, 15, 8, 12, 4, 9, 1, 2, 7, 7, 12, 7, 6, 15, 13, 11);
SIXTEEN(D, 2, H, 15, 5, 1, 3, 7, 14, 6, 9, 9, 7, 15, 11, 8, 6, 6, 14,
11, 8, 12, 2, 10, 0, 4, 13, 12, 13, 5, 14, 13, 13, 7, 5);
SIXTEEN(C, 2, G, 8, 6, 4, 1, 3, 11, 15, 0, 15, 5, 8, 11, 14, 14, 6, 14,
5, 12, 2, 13, 9, 7, 10, 14, 6, 9, 12, 9, 12, 5, 15, 8);
SIXTEEN(B, 2, F, 12, 15, 10, 4, 1, 5, 8, 7, 8, 5, 12, 9, 12, 5, 14, 6,
6, 2, 13, 14, 0, 3, 9, 11, 8, 13, 6, 5, 15, 13, 11, 11);
htmp = h[1];
h[1] = h[2] + w1[3] + w2[4];
h[2] = h[3] + w1[4] + w2[0];
h[3] = h[4] + w1[0] + w2[1];
h[4] = h[0] + w1[1] + w2[2];
h[0] = htmp + w1[2] + w2[3];
}
LIBHASHSUM_1_NONNULL_
static size_t
process(struct libhashsum_hasher *this, const void *data, size_t bytes)
{
const uint8_t *m = data;
size_t off = 0;
size_t i;
for (; bytes - off >= 64U; off += 64U) {
for (i = 0; i < 16U; i++)
this->state.ripemd_160.m.m32[i] = LETO32(&m[off + i * 4U]);
process_block(this->state.ripemd_160.h.h32, this->state.ripemd_160.m.m32,
this->state.ripemd_160.w1, this->state.ripemd_160.w2);
}
this->state.ripemd_160.count += off;
return off;
}
LIBHASHSUM_1_NONNULL_
static int
finalise_common(struct libhashsum_hasher *this, uint8_t *m, size_t bytes, unsigned extra_bits)
{
uint8_t mask;
unsigned i;
register uint32_t hi;
if (extra_bits > 7U) {
errno = EINVAL;
return -1;
}
this->state.ripemd_160.count += bytes;
this->state.ripemd_160.count *= 8U;
this->state.ripemd_160.count += (size_t)extra_bits;
if (extra_bits)
m[bytes] = libhashsum_reverse_byte__(m[bytes]);
memset(&m[bytes + 1U], 0, 63U - bytes);
mask = (uint8_t)(1U << (7U - extra_bits));
m[bytes] |= mask;
m[bytes] &= (uint8_t)~(mask - 1U); /* keep high bits (original value was reversed) */
for (i = 0; i < 14; i++)
this->state.ripemd_160.m.m32[i] = LETO32(&m[i * 4U]);
if (bytes > 55U) {
this->state.ripemd_160.m.m32[14] = LETO32(&m[14U * 4U]);
this->state.ripemd_160.m.m32[15] = LETO32(&m[15U * 4U]);
process_block(this->state.ripemd_160.h.h32, this->state.ripemd_160.m.m32,
this->state.ripemd_160.w1, this->state.ripemd_160.w2);
memset(this->state.ripemd_160.m.m32, 0, 56U);
}
this->state.ripemd_160.m.m32[14] = (uint32_t)(this->state.ripemd_160.count >> 0);
this->state.ripemd_160.m.m32[15] = (uint32_t)(this->state.ripemd_160.count >> 32);
process_block(this->state.ripemd_160.h.h32, this->state.ripemd_160.m.m32,
this->state.ripemd_160.w1, this->state.ripemd_160.w2);
memset(&this->state.ripemd_160.m, 0, sizeof(this->state.ripemd_160.m));
memset(this->state.ripemd_160.w1, 0, sizeof(this->state.ripemd_160.w1));
memset(this->state.ripemd_160.w2, 0, sizeof(this->state.ripemd_160.w2));
this->state.ripemd_160.count = 0;
if (!this->hash_output)
this->hash_output = this->state.ripemd_160.h.sum;
for (i = 0; i < 5U; i++) {
hi = this->state.ripemd_160.h.h32[i];
this->hash_output[i * 4U + 0U] = (uint8_t)(hi >> 0);
this->hash_output[i * 4U + 1U] = (uint8_t)(hi >> 8);
this->hash_output[i * 4U + 2U] = (uint8_t)(hi >> 16);
this->hash_output[i * 4U + 3U] = (uint8_t)(hi >> 24);
}
return 0;
}
LIBHASHSUM_1_NONNULL_
static int
finalise_const(struct libhashsum_hasher *this, const void *data, size_t bytes, unsigned extra_bits)
{
const uint8_t *m = data;
size_t r;
r = process(this, m, bytes);
m = &m[r];
bytes -= r;
this->state.ripemd_160.m.m8[bytes] = 0;
memcpy(this->state.ripemd_160.m.m8, m, bytes + (size_t)(extra_bits > 0U));
return finalise_common(this, this->state.ripemd_160.m.m8, bytes, extra_bits);
}
LIBHASHSUM_1_NONNULL_
static int
finalise(struct libhashsum_hasher *this, void *data, size_t bytes, unsigned extra_bits, size_t size)
{
uint8_t *m = data;
size_t r;
r = process(this, m, bytes);
m = &m[r];
bytes -= r;
size -= r;
if (size < 64U) {
this->state.ripemd_160.m.m8[bytes] = 0;
memcpy(this->state.ripemd_160.m.m8, m, bytes + (size_t)(extra_bits > 0U));
m = this->state.ripemd_160.m.m8;
}
return finalise_common(this, m, bytes, extra_bits);
}
int
libhashsum_init_ripemd_160_hasher(struct libhashsum_hasher *this)
{
this->algorithm = LIBHASHSUM_RIPEMD_160;
this->algorithm_string = "RIPEMD-160";
this->input_block_size = 64U;
this->hash_size = sizeof(this->state.ripemd_160.h.sum);
this->hash_output = NULL;
this->supports_non_whole_bytes = 1;
this->process = &process;
this->finalise_const = &finalise_const;
this->finalise = &finalise;
this->stretch = NULL;
this->destroy = NULL;
memset(&this->state.ripemd_160, 0, sizeof(this->state.ripemd_160));
this->state.ripemd_160.h.h32[0] = UINT32_C(0x67452301);
this->state.ripemd_160.h.h32[1] = UINT32_C(0xefcdab89);
this->state.ripemd_160.h.h32[2] = UINT32_C(0x98badcfe);
this->state.ripemd_160.h.h32[3] = UINT32_C(0x10325476);
this->state.ripemd_160.h.h32[4] = UINT32_C(0xc3d2e1f0);
return 0;
}
#else
int
libhashsum_init_ripemd_160_hasher(struct libhashsum_hasher *this)
{
(void) this;
errno = ENOSYS;
return -1;
}
#endif