From b33cb706c8d4e9ae9e88c84b4f0856a1b1cacf88 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Thu, 10 Apr 2014 21:04:07 +1000 Subject: [PATCH] Add RIPEMD160 implementation --- Makefile.am | 2 + hash/ripemd.cpp | 367 +++++++++++++++++++++++++++++++++++++++++++++++ hash/ripemd.hpp | 47 ++++++ test/.gitignore | 1 + test/Makefile.am | 1 + test/ripemd.cpp | 136 ++++++++++++++++++ 6 files changed, 554 insertions(+) create mode 100644 hash/ripemd.cpp create mode 100644 hash/ripemd.hpp create mode 100644 test/ripemd.cpp diff --git a/Makefile.am b/Makefile.am index b6a93ea6..eff433d1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -51,6 +51,8 @@ UTIL_FILES = \ hash/pbkdf1.hpp \ hash/pbkdf2.cpp \ hash/pbkdf2.hpp \ + hash/ripemd.cpp \ + hash/ripemd.hpp \ hash/sha1.cpp \ hash/sha1.hpp \ image.cpp \ diff --git a/hash/ripemd.cpp b/hash/ripemd.cpp new file mode 100644 index 00000000..cae7b0c9 --- /dev/null +++ b/hash/ripemd.cpp @@ -0,0 +1,367 @@ +/* + * This file is part of libgim + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2014 Danny Robson + */ + +#include "ripemd.hpp" + +#include "debug.hpp" +#include "bitwise.hpp" + +#include +#include + + +using util::hash::RIPEMD; + +/////////////////////////////////////////////////////////////////////////////// +RIPEMD::RIPEMD() +{ + reset (); +} + + +void +RIPEMD::reset (void) { + m_state[0] = 0x67452301u; + m_state[1] = 0xEFCDAB89u; + m_state[2] = 0x98BADCFEu; + m_state[3] = 0x10325476u; + m_state[4] = 0xC3D2E1F0u; + + m_length = 0; + + m_buffer.size = 0; +} + + +/////////////////////////////////////////////////////////////////////////////// +void +RIPEMD::update(const uint8_t *data, size_t len) { + CHECK_HARD (data); + + size_t cursor = 0; + + while (cursor < len) { + size_t width = sizeof (m_buffer.d08) - m_buffer.size; + size_t chunk = min (width, len - cursor); + + memcpy (m_buffer.d08 + m_buffer.size, data + cursor, chunk); + m_length += chunk; + m_buffer.size += chunk; + + if (m_buffer.size == sizeof (m_buffer.d08)) + transform (); + + cursor += chunk; + } + + if (m_length >> sizeof (m_length) * 8 - 3 != 0) + throw std::length_error ("exceeded maximum message length"); +} + +/////////////////////////////////////////////////////////////////////////////// +static constexpr +uint32_t +f1 (uint32_t x, uint32_t y, uint32_t z) { return x ^ y ^ z; } + +static constexpr +uint32_t +f2 (uint32_t x, uint32_t y, uint32_t z) { return (x & y) | (~x & z); } + +static constexpr +uint32_t +f3 (uint32_t x, uint32_t y, uint32_t z) { return (x | ~y) ^ z; } + +static constexpr +uint32_t +f4 (uint32_t x, uint32_t y, uint32_t z) { return (x & z) | (y & ~z); } + +static constexpr +uint32_t +f5 (uint32_t x, uint32_t y, uint32_t z) { return x ^ (y | ~z); } + + +/////////////////////////////////////////////////////////////////////////////// +void +RIPEMD::transform (void) { + CHECK_EQ (m_buffer.size, sizeof (m_buffer.d32)); + + // Use: boolean function f + // state parameters a, b, c, d, e + // offset value o + // input data value x + // shift length s + + #define ROUND(f,a,b,c,d,e,o,x,s) { \ + a += f(b, c, d); \ + a += m_buffer.d32[x] + o; \ + a = rotatel (a, s); \ + a += e; \ + c = rotatel (c, 10); \ + } + + #define R1a(a,b,c,d,e,x,s) ROUND(f1,a,b,c,d,e,0x00000000u,x,s) + #define R2a(a,b,c,d,e,x,s) ROUND(f2,a,b,c,d,e,0x5A827999u,x,s) + #define R3a(a,b,c,d,e,x,s) ROUND(f3,a,b,c,d,e,0x6ED9EBA1u,x,s) + #define R4a(a,b,c,d,e,x,s) ROUND(f4,a,b,c,d,e,0x8F1BBCDCu,x,s) + #define R5a(a,b,c,d,e,x,s) ROUND(f5,a,b,c,d,e,0xA953FD4Eu,x,s) + + #define R1b(a,b,c,d,e,x,s) ROUND(f5,a,b,c,d,e,0x50A28BE6u,x,s) + #define R2b(a,b,c,d,e,x,s) ROUND(f4,a,b,c,d,e,0x5C4DD124u,x,s) + #define R3b(a,b,c,d,e,x,s) ROUND(f3,a,b,c,d,e,0x6D703EF3u,x,s) + #define R4b(a,b,c,d,e,x,s) ROUND(f2,a,b,c,d,e,0x7A6D76E9u,x,s) + #define R5b(a,b,c,d,e,x,s) ROUND(f1,a,b,c,d,e,0x00000000u,x,s) + + uint32_t a1, b1, c1, d1, e1; + uint32_t a2, b2, c2, d2, e2; + + a1 = a2 = m_state[0]; + b1 = b2 = m_state[1]; + c1 = c2 = m_state[2]; + d1 = d2 = m_state[3]; + e1 = e2 = m_state[4]; + + // Left round 1 + R1a(a1, b1, c1, d1, e1, 0, 11); + R1a(e1, a1, b1, c1, d1, 1, 14); + R1a(d1, e1, a1, b1, c1, 2, 15); + R1a(c1, d1, e1, a1, b1, 3, 12); + R1a(b1, c1, d1, e1, a1, 4, 5); + R1a(a1, b1, c1, d1, e1, 5, 8); + R1a(e1, a1, b1, c1, d1, 6, 7); + R1a(d1, e1, a1, b1, c1, 7, 9); + R1a(c1, d1, e1, a1, b1, 8, 11); + R1a(b1, c1, d1, e1, a1, 9, 13); + R1a(a1, b1, c1, d1, e1, 10, 14); + R1a(e1, a1, b1, c1, d1, 11, 15); + R1a(d1, e1, a1, b1, c1, 12, 6); + R1a(c1, d1, e1, a1, b1, 13, 7); + R1a(b1, c1, d1, e1, a1, 14, 9); + R1a(a1, b1, c1, d1, e1, 15, 8); + + // Left round 2 + R2a(e1, a1, b1, c1, d1, 7, 7); + R2a(d1, e1, a1, b1, c1, 4, 6); + R2a(c1, d1, e1, a1, b1, 13, 8); + R2a(b1, c1, d1, e1, a1, 1, 13); + R2a(a1, b1, c1, d1, e1, 10, 11); + R2a(e1, a1, b1, c1, d1, 6, 9); + R2a(d1, e1, a1, b1, c1, 15, 7); + R2a(c1, d1, e1, a1, b1, 3, 15); + R2a(b1, c1, d1, e1, a1, 12, 7); + R2a(a1, b1, c1, d1, e1, 0, 12); + R2a(e1, a1, b1, c1, d1, 9, 15); + R2a(d1, e1, a1, b1, c1, 5, 9); + R2a(c1, d1, e1, a1, b1, 2, 11); + R2a(b1, c1, d1, e1, a1, 14, 7); + R2a(a1, b1, c1, d1, e1, 11, 13); + R2a(e1, a1, b1, c1, d1, 8, 12); + + // Left round 3 + R3a(d1, e1, a1, b1, c1, 3, 11); + R3a(c1, d1, e1, a1, b1, 10, 13); + R3a(b1, c1, d1, e1, a1, 14, 6); + R3a(a1, b1, c1, d1, e1, 4, 7); + R3a(e1, a1, b1, c1, d1, 9, 14); + R3a(d1, e1, a1, b1, c1, 15, 9); + R3a(c1, d1, e1, a1, b1, 8, 13); + R3a(b1, c1, d1, e1, a1, 1, 15); + R3a(a1, b1, c1, d1, e1, 2, 14); + R3a(e1, a1, b1, c1, d1, 7, 8); + R3a(d1, e1, a1, b1, c1, 0, 13); + R3a(c1, d1, e1, a1, b1, 6, 6); + R3a(b1, c1, d1, e1, a1, 13, 5); + R3a(a1, b1, c1, d1, e1, 11, 12); + R3a(e1, a1, b1, c1, d1, 5, 7); + R3a(d1, e1, a1, b1, c1, 12, 5); + + // Left round 4 + R4a(c1, d1, e1, a1, b1, 1, 11); + R4a(b1, c1, d1, e1, a1, 9, 12); + R4a(a1, b1, c1, d1, e1, 11, 14); + R4a(e1, a1, b1, c1, d1, 10, 15); + R4a(d1, e1, a1, b1, c1, 0, 14); + R4a(c1, d1, e1, a1, b1, 8, 15); + R4a(b1, c1, d1, e1, a1, 12, 9); + R4a(a1, b1, c1, d1, e1, 4, 8); + R4a(e1, a1, b1, c1, d1, 13, 9); + R4a(d1, e1, a1, b1, c1, 3, 14); + R4a(c1, d1, e1, a1, b1, 7, 5); + R4a(b1, c1, d1, e1, a1, 15, 6); + R4a(a1, b1, c1, d1, e1, 14, 8); + R4a(e1, a1, b1, c1, d1, 5, 6); + R4a(d1, e1, a1, b1, c1, 6, 5); + R4a(c1, d1, e1, a1, b1, 2, 12); + + // Left round 5 + R5a(b1, c1, d1, e1, a1, 4, 9); + R5a(a1, b1, c1, d1, e1, 0, 15); + R5a(e1, a1, b1, c1, d1, 5, 5); + R5a(d1, e1, a1, b1, c1, 9, 11); + R5a(c1, d1, e1, a1, b1, 7, 6); + R5a(b1, c1, d1, e1, a1, 12, 8); + R5a(a1, b1, c1, d1, e1, 2, 13); + R5a(e1, a1, b1, c1, d1, 10, 12); + R5a(d1, e1, a1, b1, c1, 14, 5); + R5a(c1, d1, e1, a1, b1, 1, 12); + R5a(b1, c1, d1, e1, a1, 3, 13); + R5a(a1, b1, c1, d1, e1, 8, 14); + R5a(e1, a1, b1, c1, d1, 11, 11); + R5a(d1, e1, a1, b1, c1, 6, 8); + R5a(c1, d1, e1, a1, b1, 15, 5); + R5a(b1, c1, d1, e1, a1, 13, 6); + + // Right round 1 + R1b(a2, b2, c2, d2, e2, 5, 8); + R1b(e2, a2, b2, c2, d2, 14, 9); + R1b(d2, e2, a2, b2, c2, 7, 9); + R1b(c2, d2, e2, a2, b2, 0, 11); + R1b(b2, c2, d2, e2, a2, 9, 13); + R1b(a2, b2, c2, d2, e2, 2, 15); + R1b(e2, a2, b2, c2, d2, 11, 15); + R1b(d2, e2, a2, b2, c2, 4, 5); + R1b(c2, d2, e2, a2, b2, 13, 7); + R1b(b2, c2, d2, e2, a2, 6, 7); + R1b(a2, b2, c2, d2, e2, 15, 8); + R1b(e2, a2, b2, c2, d2, 8, 11); + R1b(d2, e2, a2, b2, c2, 1, 14); + R1b(c2, d2, e2, a2, b2, 10, 14); + R1b(b2, c2, d2, e2, a2, 3, 12); + R1b(a2, b2, c2, d2, e2, 12, 6); + + // Right round 2 + R2b(e2, a2, b2, c2, d2, 6, 9); + R2b(d2, e2, a2, b2, c2, 11, 13); + R2b(c2, d2, e2, a2, b2, 3, 15); + R2b(b2, c2, d2, e2, a2, 7, 7); + R2b(a2, b2, c2, d2, e2, 0, 12); + R2b(e2, a2, b2, c2, d2, 13, 8); + R2b(d2, e2, a2, b2, c2, 5, 9); + R2b(c2, d2, e2, a2, b2, 10, 11); + R2b(b2, c2, d2, e2, a2, 14, 7); + R2b(a2, b2, c2, d2, e2, 15, 7); + R2b(e2, a2, b2, c2, d2, 8, 12); + R2b(d2, e2, a2, b2, c2, 12, 7); + R2b(c2, d2, e2, a2, b2, 4, 6); + R2b(b2, c2, d2, e2, a2, 9, 15); + R2b(a2, b2, c2, d2, e2, 1, 13); + R2b(e2, a2, b2, c2, d2, 2, 11); + + // Right round 3 + R3b(d2, e2, a2, b2, c2, 15, 9); + R3b(c2, d2, e2, a2, b2, 5, 7); + R3b(b2, c2, d2, e2, a2, 1, 15); + R3b(a2, b2, c2, d2, e2, 3, 11); + R3b(e2, a2, b2, c2, d2, 7, 8); + R3b(d2, e2, a2, b2, c2, 14, 6); + R3b(c2, d2, e2, a2, b2, 6, 6); + R3b(b2, c2, d2, e2, a2, 9, 14); + R3b(a2, b2, c2, d2, e2, 11, 12); + R3b(e2, a2, b2, c2, d2, 8, 13); + R3b(d2, e2, a2, b2, c2, 12, 5); + R3b(c2, d2, e2, a2, b2, 2, 14); + R3b(b2, c2, d2, e2, a2, 10, 13); + R3b(a2, b2, c2, d2, e2, 0, 13); + R3b(e2, a2, b2, c2, d2, 4, 7); + R3b(d2, e2, a2, b2, c2, 13, 5); + + // Right round 4 + R4b(c2, d2, e2, a2, b2, 8, 15); + R4b(b2, c2, d2, e2, a2, 6, 5); + R4b(a2, b2, c2, d2, e2, 4, 8); + R4b(e2, a2, b2, c2, d2, 1, 11); + R4b(d2, e2, a2, b2, c2, 3, 14); + R4b(c2, d2, e2, a2, b2, 11, 14); + R4b(b2, c2, d2, e2, a2, 15, 6); + R4b(a2, b2, c2, d2, e2, 0, 14); + R4b(e2, a2, b2, c2, d2, 5, 6); + R4b(d2, e2, a2, b2, c2, 12, 9); + R4b(c2, d2, e2, a2, b2, 2, 12); + R4b(b2, c2, d2, e2, a2, 13, 9); + R4b(a2, b2, c2, d2, e2, 9, 12); + R4b(e2, a2, b2, c2, d2, 7, 5); + R4b(d2, e2, a2, b2, c2, 10, 15); + R4b(c2, d2, e2, a2, b2, 14, 8); + + // Right round 5 + R5b(b2, c2, d2, e2, a2, 12 , 8); + R5b(a2, b2, c2, d2, e2, 15 , 5); + R5b(e2, a2, b2, c2, d2, 10 , 12); + R5b(d2, e2, a2, b2, c2, 4 , 9); + R5b(c2, d2, e2, a2, b2, 1 , 12); + R5b(b2, c2, d2, e2, a2, 5 , 5); + R5b(a2, b2, c2, d2, e2, 8 , 14); + R5b(e2, a2, b2, c2, d2, 7 , 6); + R5b(d2, e2, a2, b2, c2, 6 , 8); + R5b(c2, d2, e2, a2, b2, 2 , 13); + R5b(b2, c2, d2, e2, a2, 13 , 6); + R5b(a2, b2, c2, d2, e2, 14 , 5); + R5b(e2, a2, b2, c2, d2, 0 , 15); + R5b(d2, e2, a2, b2, c2, 3 , 13); + R5b(c2, d2, e2, a2, b2, 9 , 11); + R5b(b2, c2, d2, e2, a2, 11 , 11); + + // Finalise state + d2 = m_state[1] + c1 + d2; + m_state[1] = m_state[2] + d1 + e2; + m_state[2] = m_state[3] + e1 + a2; + m_state[3] = m_state[4] + a1 + b2; + m_state[4] = m_state[0] + b1 + c2; + m_state[0] = d2; + + m_buffer.size = 0; +} + + +/////////////////////////////////////////////////////////////////////////////// +void +RIPEMD::finish (void) { + // Ensure the length wouldn't overflow if converted to bits. We need to + // grab this before there's a chance it gets overwritten. + CHECK_EQ (m_length >> sizeof(m_length) * 8 - 3, 0); + uint64_t length = m_length * 8; + + // Push a padding byte into the buffer + uint8_t padding = 0x80; + update (&padding, 1); + + // Pad out the line if we couldn't fit a length at the end + size_t remaining = sizeof (m_buffer.d32) - m_buffer.size; + if (remaining < 8) { + static const uint8_t ZEROES[8] = { 0 }; + + update (ZEROES, remaining); + + CHECK_EQ (m_buffer.size, 0); + remaining = sizeof (m_buffer.d08); + } + + // Write the length to the end of the buffer + union { + uint32_t d32[16]; + uint8_t d08[64]; + }; + + memset (d32, 0, sizeof (d32)); + d32[14] = length & 0xFFFFFFFF; + d32[15] = length >> 32u; + + // Do the final update + size_t offset = sizeof(d08) - remaining; + update (d08 + offset, remaining); +} + + +/////////////////////////////////////////////////////////////////////////////// +RIPEMD::digest_t +RIPEMD::digest (void) const { + digest_t d; + memcpy (d.data (), m_state, sizeof (m_state)); + return d; +} diff --git a/hash/ripemd.hpp b/hash/ripemd.hpp new file mode 100644 index 00000000..e624e501 --- /dev/null +++ b/hash/ripemd.hpp @@ -0,0 +1,47 @@ +/* + * This file is part of libgim + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2014 Danny Robson + */ + +#ifndef __UTIL_HASH_RIPEMD_HPP +#define __UTIL_HASH_RIPEMD_HPP + +#include + +namespace util { + namespace hash { + class RIPEMD { + public: + typedef std::array digest_t; + + public: + RIPEMD(); + + void update(const uint8_t*, size_t); + void finish(void); + digest_t digest(void) const; + void reset(void); + + protected: + void transform (); + + uint32_t m_state[5]; + uint64_t m_length; + + struct { + union { + uint32_t d32[16]; + uint8_t d08[64]; + }; + size_t size; + } m_buffer; + }; + } +} + +#endif diff --git a/test/.gitignore b/test/.gitignore index d7467331..6947eb0f 100644 --- a/test/.gitignore +++ b/test/.gitignore @@ -15,6 +15,7 @@ /pool* /random* /range* +/ripemd /region* /sha1* /signal* diff --git a/test/Makefile.am b/test/Makefile.am index fc8a6937..61c7a2e3 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -20,6 +20,7 @@ TEST_BIN = \ rand \ range \ region \ + ripemd \ signal \ sha1 \ version diff --git a/test/ripemd.cpp b/test/ripemd.cpp new file mode 100644 index 00000000..ecc69ee8 --- /dev/null +++ b/test/ripemd.cpp @@ -0,0 +1,136 @@ +#include "../debug.hpp" +#include "../types.hpp" +#include "../hash/ripemd.hpp" + +#include +#include +#include + +using util::hash::RIPEMD; + +static const +struct { + const char *input; + RIPEMD::digest_t output; +} TESTS[] = { + { + "", + { 0x9c, 0x11, 0x85, 0xa5, 0xc5, 0xe9, 0xfc, 0x54, 0x61, 0x28, + 0x08, 0x97, 0x7e, 0xe8, 0xf5, 0x48, 0xb2, 0x25, 0x8d, 0x31 }, + // 128: cdf26213a150dc3ecb610f18f6b38b46 + // 160: 9c1185a5c5e9fc54612808977ee8f548b2258d31 + // 256: 02ba4c4e5f8ecd1877fc52d64d30e37a2d9774fb1e5d026380ae0168e3c5522d + // 320: 22d65d5661536cdc75c1fdf5c6de7b41b9f27325ebc61e8557177d705a0ec880151c3a32a00899b8 + }, + + { + "a", + { 0x0b, 0xdc, 0x9d, 0x2d, 0x25, 0x6b, 0x3e, 0xe9, 0xda, 0xae, + 0x34, 0x7b, 0xe6, 0xf4, 0xdc, 0x83, 0x5a, 0x46, 0x7f, 0xfe }, + // 128: 86be7afa339d0fc7cfc785e72f578d33 + // 160: 0bdc9d2d256b3ee9daae347be6f4dc835a467ffe + // 256: f9333e45d857f5d90a91bab70a1eba0cfb1be4b0783c9acfcd883a9134692925 + // 320: ce78850638f92658a5a585097579926dda667a5716562cfcf6fbe77f63542f99b04705d6970dff5d + }, + + { + "abc", + { 0x8e, 0xb2, 0x08, 0xf7, 0xe0, 0x5d, 0x98, 0x7a, 0x9b, 0x04, + 0x4a, 0x8e, 0x98, 0xc6, 0xb0, 0x87, 0xf1, 0x5a, 0x0b, 0xfc }, + // 128: c14a12199c66e4ba84636b0f69144c77 + // 160: 8eb208f7e05d987a9b044a8e98c6b087f15a0bfc + // 256: afbd6e228b9d8cbbcef5ca2d03e6dba10ac0bc7dcbe4680e1e42d2e975459b65 + // 320: de4c01b3054f8930a79d09ae738e92301e5a17085beffdc1b8d116713e74f82fa942d64cdbc4682d + }, + + { + "message digest", + { 0x5d, 0x06, 0x89, 0xef, 0x49, 0xd2, 0xfa, 0xe5, 0x72, 0xb8, + 0x81, 0xb1, 0x23, 0xa8, 0x5f, 0xfa, 0x21, 0x59, 0x5f, 0x36 }, + // 128: 9e327b3d6e523062afc1132d7df9d1b8 + // 160: 5d0689ef49d2fae572b881b123a85ffa21595f36 + // 256: 87e971759a1ce47a514d5c914c392c9018c7c46bc14465554afcdf54a5070c0e + // 320: 3a8e28502ed45d422f68844f9dd316e7b98533fa3f2a91d29f84d425c88d6b4eff727df66a7c0197 + }, + + { + "abcdefghijklmnopqrstuvwxyz", + { 0xf7, 0x1c, 0x27, 0x10, 0x9c, 0x69, 0x2c, 0x1b, 0x56, 0xbb, + 0xdc, 0xeb, 0x5b, 0x9d, 0x28, 0x65, 0xb3, 0x70, 0x8d, 0xbc }, + // 128: fd2aa607f71dc8f510714922b371834e + // 160: f71c27109c692c1b56bbdceb5b9d2865b3708dbc + // 256: 649d3034751ea216776bf9a18acc81bc7896118a5197968782dd1fd97d8d5133 + // 320: cabdb1810b92470a2093aa6bce05952c28348cf43ff60841975166bb40ed234004b8824463e6b009 + }, + + { + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + { 0x12, 0xa0, 0x53, 0x38, 0x4a, 0x9c, 0x0c, 0x88, 0xe4, 0x05, + 0xa0, 0x6c, 0x27, 0xdc, 0xf4, 0x9a, 0xda, 0x62, 0xeb, 0x2b }, + // 128: a1aa0689d0fafa2ddc22e88b49133a06 + // 160: 12a053384a9c0c88e405a06c27dcf49ada62eb2b + // 256: 3843045583aac6c8c8d9128573e7a9809afb2a0f34ccc36ea9e72f16f6368e3f + // 320: d034a7950cf722021ba4b84df769a5de2060e259df4c9bb4a4268c0e935bbc7470a969c9d072a1ac + }, + + { + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", + { 0xb0, 0xe2, 0x0b, 0x6e, 0x31, 0x16, 0x64, 0x02, 0x86, 0xed, + 0x3a, 0x87, 0xa5, 0x71, 0x30, 0x79, 0xb2, 0x1f, 0x51, 0x89 }, + // 128: d1e959eb179c911faea4624c60c5c702 + // 160: b0e20b6e3116640286ed3a87a5713079b21f5189 + // 256: 5740a408ac16b720b84424ae931cbb1fe363d1d0bf4017f1a89f7ea6de77a0b8 + // 320: ed544940c86d67f250d232c30b7b3e5770e0c60c8cb9a4cafe3b11388af9920e1b99230b843c86a4 + }, + + { + "12345678901234567890123456789012345678901234567890123456789012345678901234567890", + { 0x9b, 0x75, 0x2e, 0x45, 0x57, 0x3d, 0x4b, 0x39, 0xf4, 0xdb, + 0xd3, 0x32, 0x3c, 0xab, 0x82, 0xbf, 0x63, 0x32, 0x6b, 0xfb } + // 128: 3f45ef194732c2dbb2c4a2c769795fa3 + // 160: 9b752e45573d4b39f4dbd3323cab82bf63326bfb + // 256: 06fdcc7a409548aaf91368c06a6275b553e3f099bf0ea4edfd6778df89a890dd + // 320: 557888af5f6d8ed62ab66945c6d2a0a47ecd5341e915eb8fea1d0524955f825dc717e4a008ab2d42 + } +}; + +// 1 million times "a" +// 128: 4a7f5723f954eba1216c9d8f6320431f +// 160: 52783243c1697bdbe16d37f97f68f08325dc1528 +// 256: ac953744e10e31514c150d4d8d7b677342e33399788296e43ae4850ce4f97978 +// 320: bdee37f4371e20646b8b0d862dda16292ae36f40965e8c8509e63d1dbddecc503e2b63eb9245bb66 + +int +main(int, char**) { + // Check against simple test vectors + for (size_t i = 0; i < elems (TESTS); ++i) { + std::cout << "testing '" << TESTS[i].input << "'\n"; + + util::hash::RIPEMD obj; + obj.update (reinterpret_cast (TESTS[i].input), + strlen (TESTS[i].input)); + obj.finish (); + + CHECK_HARD (obj.digest () == TESTS[i].output); + } + + // Perform 'million-a' check + static const size_t CHUNK_WIDTH = 1000; + util::hash::RIPEMD obj; + + for (size_t i = 0; i < 1000000; i += CHUNK_WIDTH) { + uint8_t data[CHUNK_WIDTH]; + memset (data, 'a', sizeof (data)); + + obj.update (data, sizeof (data)); + } + + obj.finish (); + static const util::hash::RIPEMD::digest_t MILLION { + 0x52, 0x78, 0x32, 0x43, 0xc1, 0x69, 0x7b, 0xdb, 0xe1, 0x6d, + 0x37, 0xf9, 0x7f, 0x68, 0xf0, 0x83, 0x25, 0xdc, 0x15, 0x28 + }; + CHECK_HARD (obj.digest () == MILLION); + + return EXIT_SUCCESS; +}