Annotation of embedaddon/rsync/lib/md5p8.c, revision 1.1.1.1
1.1 misho 1: /*
2: * MD5-based hash friendly to parallel processing, reference implementation
3: *
4: * Author: Jorrit Jongma, 2020
5: *
6: * Released in the public domain falling back to the MIT license
7: * ( http://www.opensource.org/licenses/MIT ) in case public domain does not
8: * apply in your country.
9: */
10: /*
11: * MD5P8 is an MD5-based hash friendly to parallel processing. The input
12: * stream is divided into 8 independent streams. For each 512 bytes of input,
13: * the first 64 bytes are send to the first stream, the second 64 bytes to
14: * the second stream, etc. The input stream is padded with zeros to the next
15: * multiple of 512 bytes, then a normal MD5 hash is computed on a buffer
16: * containing the A, B, C, and D states of the 8 individual streams, followed
17: * by the (unpadded) length of the input.
18: *
19: * On non-SIMD accelerated CPUs the performance of MD5P8 is slightly lower
20: * than normal MD5 (particularly on files smaller than 10 kB), but with
21: * SIMD-based parallel processing it can be two to six times as fast. Even in
22: * the best-case scenario, xxHash is still at least twice as fast and should
23: * be preferred when available.
24: */
25:
26: #include "rsync.h"
27:
28: #ifdef HAVE_SIMD
29: #define MD5P8_Init MD5P8_Init_c
30: #define MD5P8_Update MD5P8_Update_c
31: #define MD5P8_Final MD5P8_Final_c
32: #endif
33:
34: /* each MD5_CTX needs to be 8-byte aligned */
35: #define MD5P8_Contexts_c(ctx, index) ((MD5_CTX*)((((uintptr_t)((ctx)->context_storage) + 7) & ~7) + (index)*((sizeof(MD5_CTX) + 7) & ~7)))
36:
37: void MD5P8_Init(MD5P8_CTX *ctx)
38: {
39: int i;
40: for (i = 0; i < 8; i++) {
41: MD5_Init(MD5P8_Contexts_c(ctx, i));
42: }
43: ctx->used = 0;
44: ctx->next = 0;
45: }
46:
47: void MD5P8_Update(MD5P8_CTX *ctx, const uchar *input, uint32 length)
48: {
49: uint32 pos = 0;
50:
51: if ((ctx->used) || (length < 64)) {
52: int cpy = MIN(length, 64 - ctx->used);
53: memmove(&ctx->buffer[ctx->used], input, cpy);
54: ctx->used += cpy;
55: length -= cpy;
56: pos += cpy;
57:
58: if (ctx->used == 64) {
59: MD5_Update(MD5P8_Contexts_c(ctx, ctx->next), ctx->buffer, 64);
60: ctx->used = 0;
61: ctx->next = (ctx->next + 1) % 8;
62: }
63: }
64:
65: while (length >= 64) {
66: MD5_Update(MD5P8_Contexts_c(ctx, ctx->next), &input[pos], 64);
67: ctx->next = (ctx->next + 1) % 8;
68: pos += 64;
69: length -= 64;
70: }
71:
72: if (length) {
73: memcpy(ctx->buffer, &input[pos], length);
74: ctx->used = length;
75: }
76: }
77:
78: void MD5P8_Final(uchar digest[MD5_DIGEST_LEN], MD5P8_CTX *ctx)
79: {
80: int i;
81: uint32 low = 0, high = 0, sub = ctx->used ? 64 - ctx->used : 0;
82: if (ctx->used) {
83: uchar tmp[64];
84: memset(tmp, 0, 64);
85: MD5P8_Update(ctx, tmp, 64 - ctx->used);
86: }
87: memset(ctx->buffer, 0, 64);
88: while (ctx->next != 0) {
89: MD5P8_Update(ctx, ctx->buffer, 64);
90: sub += 64;
91: }
92:
93: uchar state[34*4] = {0};
94:
95: for (i = 0; i < 8; i++) {
96: MD5_CTX* md = MD5P8_Contexts_c(ctx, i);
97: #ifdef USE_OPENSSL
98: if (low + md->Nl < low) high++;
99: low += md->Nl;
100: high += md->Nh;
101: #else
102: if (low + md->totalN < low) high++;
103: low += md->totalN;
104: high += md->totalN2;
105: #endif
106: SIVALu(state, i*16, md->A);
107: SIVALu(state, i*16 + 4, md->B);
108: SIVALu(state, i*16 + 8, md->C);
109: SIVALu(state, i*16 + 12, md->D);
110: }
111:
112: #ifndef USE_OPENSSL
113: high = (low >> 29) | (high << 3);
114: low = (low << 3);
115: #endif
116:
117: sub <<= 3;
118: if (low - sub > low) high--;
119: low -= sub;
120:
121: SIVALu(state, 32*4, low);
122: SIVALu(state, 33*4, high);
123:
124: MD5_CTX md;
125: MD5_Init(&md);
126: MD5_Update(&md, state, 34*4);
127: MD5_Final(digest, &md);
128: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>