/* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE. */
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define TAIL /* tail call (declaration of intent) */
/* Input */
static uint8_t buf[64 * 2];
static size_t inlength;
/* K[i] = floor(abs(sin(i + 1)) * 2**32) */
static const uint32_t K[64] = {
0xD76AA478u, 0xE8C7B756u, 0x242070DBu, 0xC1BDCEEEu,
0xF57C0FAFu, 0x4787C62Au, 0xA8304613u, 0xFD469501u,
0x698098D8u, 0x8B44F7AFu, 0xFFFF5BB1u, 0x895CD7BEu,
0x6B901122u, 0xFD987193u, 0xA679438Eu, 0x49B40821u,
0xF61E2562u, 0xC040B340u, 0x265E5A51u, 0xE9B6C7AAu,
0xD62F105Du, 0x02441453u, 0xD8A1E681u, 0xE7D3FBC8u,
0x21E1CDE6u, 0xC33707D6u, 0xF4D50D87u, 0x455A14EDu,
0xA9E3E905u, 0xFCEFA3F8u, 0x676F02D9u, 0x8D2A4C8Au,
0xFFFA3942u, 0x8771F681u, 0x6D9D6122u, 0xFDE5380Cu,
0xA4BEEA44u, 0x4BDECFA9u, 0xF6BB4B60u, 0xBEBFBC70u,
0x289B7EC6u, 0xEAA127FAu, 0xD4EF3085u, 0x04881D05u,
0xD9D4D039u, 0xE6DB99E5u, 0x1FA27CF8u, 0xC4AC5665u,
0xF4292244u, 0x432AFF97u, 0xAB9423A7u, 0xFC93A039u,
0x655B59C3u, 0x8F0CCC92u, 0xFFEFF47Du, 0x85845DD1u,
0x6FA87E4Fu, 0xFE2CE6E0u, 0xA3014314u, 0x4E0811A1u,
0xF7537E82u, 0xBD3AF235u, 0x2AD7D2BBu, 0xEB86D391u,
};
/* Shift amounts */
static const uint8_t SA[64] = {
7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21,
};
/* State variables */
static uint32_t a0, b0, c0, d0, a, b, c, d, f, w[16];
/* Hash output */
static uint8_t digest[16];
/* Utilities */
#define rotl(x, n) ((x) << (n) | (x) >> (32 - (n)))
static void read32le(uint32_t *out, const uint8_t *d, char _[(
*out = d[0] | d[1] << 8 | d[2] << 16 | d[3] << 24,
1)]) {}
static void write32le(uint8_t *d, uint32_t n, char _[(
d[0] = n, d[1] = n >> 8, d[2] = n >> 16, d[3] = n >> 24,
1)]) {}
static void write64le(uint8_t *d, uint64_t n, char _[(
write32le(d + 0, n >> 0, ""),
write32le(d + 4, n >> 32, ""),
1)]) {}
/* State initialization */
static void ini(char _[(
a0 = 0x67452301u, b0 = 0xEFCDAB89u,
c0 = 0x98BADCFEu, d0 = 0x10325476u,
1)]) {}
/* Read chunk as 32-bit words into w[0..15] */
static void readwords(const uint8_t *chunk, size_t i, char *);
static void readwords(const uint8_t *chunk, size_t i, char _[(
read32le(&w[i], chunk + (i * 4), ""),
(++i < 16) ?
TAIL readwords(chunk, i, "")
: (void)0,
1)]) {}
static void dochunk_loop(const uint8_t *chunk, size_t i, size_t g, char *);
static void dochunk_loop(const uint8_t *chunk, size_t i, size_t g, char _[(
(i < 16) ? (
f = (b & c) | (~b & d),
g = i
) : (i < 32) ? (
f = (d & b) | (~d & c),
g = (5*i + 1) & 15
) : (i < 48) ? (
f = b ^ c ^ d,
g = (3*i + 5) & 15
) : ( // i < 64
f = c ^ (b | ~d),
g = 7*i & 15
),
f += a + K[i] + w[g],
a = d,
d = c,
c = b,
b += rotl(f, SA[i]),
(++i < 64) ?
TAIL dochunk_loop(chunk, i, g, "")
: (void)0,
1)]) {}
/* Process one 64-byte chunk */
static void dochunk(const uint8_t *chunk, char _[(
a = a0,
b = b0,
c = c0,
d = d0,
readwords(chunk, 0, ""),
dochunk_loop(chunk, 0, 0, ""),
a0 += a,
b0 += b,
c0 += c,
d0 += d,
1)]) {}
/* Process the last chunk(s) and create digest */
static void finish(size_t n, char *);
static void finish(size_t n, char _[(
dochunk(buf, ""),
(n == 128) ? dochunk(buf + 64, "")
: (n != 64) ? abort(/*unreachable*/)
: (void)0,
write32le(digest + 0, a0, ""),
write32le(digest + 4, b0, ""),
write32le(digest + 8, c0, ""),
write32le(digest + 12, d0, ""),
1)]) {}
/* Read file, processing each 64-byte chunk. At end of input, we append
* post-processing data and process the final 1 or 2 chunks that result. */
static void md5sum(FILE *in, int tmp, size_t i, char *);
static void md5sum(FILE *in, int tmp, size_t i, char _[(
((tmp = fgetc(in)) == EOF) ? (
/* append '1' bit */
buf[i++] = 0x80,
/* pad with zeroes to multiple of 64 */
tmp = (56 - (i % 64)) % 64,
memset(buf + i, 0, tmp),
/* put original message length in bits (as a 64-bit uint) */
write64le(buf + i + tmp, inlength * 8, ""),
finish(i + tmp + 8, "")
) : (
++inlength,
buf[i++] = tmp,
(i == 64) ? (
dochunk(buf, ""),
i = 0
) : (void)0,
TAIL md5sum(in, 0, i, "")
),
1)]) {}
static void prihex(const uint8_t *dat, size_t n, char *);
static void prihex(const uint8_t *dat, size_t n, char _[(
n ? (
putchar("0123456789abcdef"[*dat >> 4]),
putchar("0123456789abcdef"[*dat & 15]),
TAIL prihex(dat + 1, n - 1, "")
) : (void)0,
1)]) {}
static void dofile(const char *name, FILE *fp, char _[(
!fp ? (
perror(name),
exit(1)
) : (void)0,
inlength = 0,
ini(""),
md5sum(fp, 0, 0, ""),
prihex(digest, sizeof digest, ""),
printf(" %s\n", name),
1)]) {}
static void dofiles(const char **argv, FILE *fp, char *);
static void dofiles(const char **argv, FILE *fp, char _[(
*argv ? (
dofile(*argv, !strcmp(*argv, "-") ? stdin : (fp = fopen(*argv, "rb")), ""),
fp ? fclose(fp) : (void)0,
TAIL dofiles(argv + 1, NULL, "")
) : (void)0,
1)]) {}
int main(int argc, const char **argv, char *envp[(
(argc == 1) ?
dofile("-", stdin, "")
:
dofiles(argv + 1, NULL, ""),
1)]) {}