/* See LICENSE file for copyright and license details. */
#include "common.h"
#ifdef SUPPORT_RIPEMD_256
#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[8], const uint32_t *x)
{
#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 F1(A, B, C, D, I, S) (A = rol32(F0(B, C, D) + A + x[I] + UINT32_C(0x00000000), S))
#define G1(A, B, C, D, I, S) (A = rol32(G0(B, C, D) + A + x[I] + UINT32_C(0x5a827999), S))
#define H1(A, B, C, D, I, S) (A = rol32(H0(B, C, D) + A + x[I] + UINT32_C(0x6ed9eba1), S))
#define I1(A, B, C, D, I, S) (A = rol32(I0(B, C, D) + A + x[I] + UINT32_C(0x8f1bbcdc), S))
#define F2(A, B, C, D, I, S) (A = rol32(F0(B, C, D) + A + x[I] + UINT32_C(0x00000000), S))
#define G2(A, B, C, D, I, S) (A = rol32(G0(B, C, D) + A + x[I] + UINT32_C(0x6d703ef3), S))
#define H2(A, B, C, D, I, S) (A = rol32(H0(B, C, D) + A + x[I] + UINT32_C(0x5c4dd124), S))
#define I2(A, B, C, D, I, S) (A = rol32(I0(B, C, D) + A + x[I] + UINT32_C(0x50a28be6), S))
#define FOUR(P, M, I1, S1, I2, S2, I3, S3, I4, S4)\
(M(a##P, b##P, c##P, d##P, I1, S1),\
M(d##P, a##P, b##P, c##P, I2, S2),\
M(c##P, d##P, a##P, b##P, I3, S3),\
M(b##P, c##P, d##P, a##P, I4, S4))
#define SIXTEEN(P, F, I11, I12, I13, I14, S11, S12, S13, S14,\
I21, I22, I23, I24, S21, S22, S23, S24,\
I31, I32, I33, I34, S31, S32, S33, S34,\
I41, I42, I43, I44, S41, S42, S43, S44)\
(FOUR(P, F##P, I11, S11, I12, S12, I13, S13, I14, S14),\
FOUR(P, F##P, I21, S21, I22, S22, I23, S23, I24, S24),\
FOUR(P, F##P, I31, S31, I32, S32, I33, S33, I34, S34),\
FOUR(P, F##P, I41, S41, I42, S42, I43, S43, I44, S44))
register uint32_t a1 = h[0], a2 = h[4];
register uint32_t b1 = h[1], b2 = h[5];
register uint32_t c1 = h[2], c2 = h[6];
register uint32_t d1 = h[3], d2 = h[7];
register uint32_t t;
SIXTEEN(1, F, 0, 1, 2, 3, 11, 14, 15, 12,
4, 5, 6, 7, 5, 8, 7, 9,
8, 9, 10, 11, 11, 13, 14, 15,
12, 13, 14, 15, 6, 7, 9, 8);
SIXTEEN(2, I, 5, 14, 7, 0, 8, 9, 9, 11,
9, 2, 11, 4, 13, 15, 15, 5,
13, 6, 15, 8, 7, 7, 8, 11,
1, 10, 3, 12, 14, 14, 12, 6);
t = a1, a1 = a2, a2 = t;
SIXTEEN(1, G, 7, 4, 13, 1, 7, 6, 8, 13,
10, 6, 15, 3, 11, 9, 7, 15,
12, 0, 9, 5, 7, 12, 15, 9,
2, 14, 11, 8, 11, 7, 13, 12);
SIXTEEN(2, H, 6, 11, 3, 7, 9, 13, 15, 7,
0, 13, 5, 10, 12, 8, 9, 11,
14, 15, 8, 12, 7, 7, 12, 7,
4, 9, 1, 2, 6, 15, 13, 11);
t = b1, b1 = b2, b2 = t;
SIXTEEN(1, H, 3, 10, 14, 4, 11, 13, 6, 7,
9, 15, 8, 1, 14, 9, 13, 15,
2, 7, 0, 6, 14, 8, 13, 6,
13, 11, 5, 12, 5, 12, 7, 5);
SIXTEEN(2, G, 15, 5, 1, 3, 9, 7, 15, 11,
7, 14, 6, 9, 8, 6, 6, 14,
11, 8, 12, 2, 12, 13, 5, 14,
10, 0, 4, 13, 13, 13, 7, 5);
t = c1, c1 = c2, c2 = t;
SIXTEEN(1, I, 1, 9, 11, 10, 11, 12, 14, 15,
0, 8, 12, 4, 14, 15, 9, 8,
13, 3, 7, 15, 9, 14, 5, 6,
14, 5, 6, 2, 8, 6, 5, 12);
SIXTEEN(2, F, 8, 6, 4, 1, 15, 5, 8, 11,
3, 11, 15, 0, 14, 14, 6, 14,
5, 12, 2, 13, 6, 9, 12, 9,
9, 7, 10, 14, 12, 5, 15, 8);
t = d1, d1 = d2, d2 = t;
h[0] += a1;
h[1] += b1;
h[2] += c1;
h[3] += d1;
h[4] += a2;
h[5] += b2;
h[6] += c2;
h[7] += d2;
}
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_256.m.m32[i] = LETO32(&m[off + i * 4U]);
process_block(this->state.ripemd_256.h.h32, this->state.ripemd_256.m.m32);
}
this->state.ripemd_256.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_256.count += bytes;
this->state.ripemd_256.count *= 8U;
this->state.ripemd_256.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_256.m.m32[i] = LETO32(&m[i * 4U]);
if (bytes > 55U) {
this->state.ripemd_256.m.m32[14] = LETO32(&m[14U * 4U]);
this->state.ripemd_256.m.m32[15] = LETO32(&m[15U * 4U]);
process_block(this->state.ripemd_256.h.h32, this->state.ripemd_256.m.m32);
memset(this->state.ripemd_256.m.m32, 0, 56U);
}
this->state.ripemd_256.m.m32[14] = (uint32_t)(this->state.ripemd_256.count >> 0);
this->state.ripemd_256.m.m32[15] = (uint32_t)(this->state.ripemd_256.count >> 32);
process_block(this->state.ripemd_256.h.h32, this->state.ripemd_256.m.m32);
memset(&this->state.ripemd_256.m, 0, sizeof(this->state.ripemd_256.m));
this->state.ripemd_256.count = 0;
if (!this->hash_output)
this->hash_output = this->state.ripemd_256.h.sum;
for (i = 0; i < 8U; i++) {
hi = this->state.ripemd_256.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_256.m.m8[bytes] = 0;
memcpy(this->state.ripemd_256.m.m8, m, bytes + (size_t)(extra_bits > 0U));
return finalise_common(this, this->state.ripemd_256.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_256.m.m8[bytes] = 0;
memcpy(this->state.ripemd_256.m.m8, m, bytes + (size_t)(extra_bits > 0U));
m = this->state.ripemd_256.m.m8;
}
return finalise_common(this, m, bytes, extra_bits);
}
int
libhashsum_init_ripemd_256_hasher(struct libhashsum_hasher *this)
{
this->algorithm = LIBHASHSUM_RIPEMD_256;
this->algorithm_string = "RIPEMD-256";
this->input_block_size = 64U;
this->hash_size = sizeof(this->state.ripemd_256.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_256, 0, sizeof(this->state.ripemd_256));
this->state.ripemd_256.h.h32[0] = UINT32_C(0x67452301);
this->state.ripemd_256.h.h32[1] = UINT32_C(0xefcdab89);
this->state.ripemd_256.h.h32[2] = UINT32_C(0x98badcfe);
this->state.ripemd_256.h.h32[3] = UINT32_C(0x10325476);
this->state.ripemd_256.h.h32[4] = UINT32_C(0x76543210);
this->state.ripemd_256.h.h32[5] = UINT32_C(0xfedcba98);
this->state.ripemd_256.h.h32[6] = UINT32_C(0x89abcdef);
this->state.ripemd_256.h.h32[7] = UINT32_C(0x01234567);
return 0;
}
#else
int
libhashsum_init_ripemd_256_hasher(struct libhashsum_hasher *this)
{
(void) this;
errno = ENOSYS;
return -1;
}
#endif