1 /*******************************************************************************
2 
3         This module implements the Ripemd160 algorithm by Hans Dobbertin,
4         Antoon Bosselaers and Bart Preneel.
5 
6         See http://homes.esat.kuleuven.be/~bosselae/ripemd160.html for more
7         information.
8 
9         The implementation is based on:
10         RIPEMD-160 software written by Antoon Bosselaers,
11         available at http://www.esat.kuleuven.ac.be/~cosicart/ps/AB-9601/
12 
13         Copyright:
14             Copyright (c) 2009 Tango contributors.
15             Some parts copyright (c) 2009-2016 dunnhumby Germany GmbH.
16             All rights reserved.
17 
18         License:
19             Tango Dual License: 3-Clause BSD License / Academic Free License v3.0.
20             See LICENSE_TANGO.txt for details.
21 
22         Version: Initial release: Sep 2009
23 
24         Authors: Kai Nacke
25 
26 *******************************************************************************/
27 
28 module ocean.util.digest.Ripemd320;
29 
30 import ocean.meta.types.Qualifiers;
31 
32 import ocean.util.digest.MerkleDamgard;
33 
34 public  import ocean.util.digest.Digest;
35 
36 version (unittest) import ocean.core.Test;
37 
38 /*******************************************************************************
39 
40 *******************************************************************************/
41 
42 final class Ripemd320 : MerkleDamgard
43 {
44     private uint[10]        context;
45     private static immutable uint     padChar = 0x80;
46 
47     /***********************************************************************
48 
49     ***********************************************************************/
50 
51     private static const(uint[10]) initial =
52     [
53         0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0,
54         0x76543210, 0xfedcba98, 0x89abcdef, 0x01234567, 0x3c2d1e0f
55     ];
56 
57     /***********************************************************************
58 
59         Construct a Ripemd320
60 
61      ***********************************************************************/
62 
63     this() { }
64 
65     /***********************************************************************
66 
67         The size of a Ripemd320 digest is 40 bytes
68 
69      ***********************************************************************/
70 
71     override uint digestSize() {return 40;}
72 
73 
74     /***********************************************************************
75 
76         Initialize the cipher
77 
78         Remarks:
79             Returns the cipher state to it's initial value
80 
81      ***********************************************************************/
82 
83     override void reset()
84     {
85         super.reset();
86         context[] = initial[];
87     }
88 
89     /***********************************************************************
90 
91         Obtain the digest
92 
93         Returns:
94             the digest
95 
96         Remarks:
97             Returns a digest of the current cipher state, this may be the
98             final digest, or a digest of the state between calls to update()
99 
100      ***********************************************************************/
101 
102     override void createDigest(ubyte[] buf)
103     {
104         version (BigEndian)
105             ByteSwap.swap32 (context.ptr, context.length * uint.sizeof);
106 
107         buf[] = cast(ubyte[]) context;
108     }
109 
110 
111     /***********************************************************************
112 
113         block size
114 
115         Returns:
116             the block size
117 
118         Remarks:
119             Specifies the size (in bytes) of the block of data to pass to
120             each call to transform(). For Ripemd320 the blockSize is 64.
121 
122      ***********************************************************************/
123 
124     protected override uint blockSize() { return 64; }
125 
126     /***********************************************************************
127 
128         Length padding size
129 
130         Returns:
131             the length padding size
132 
133         Remarks:
134             Specifies the size (in bytes) of the padding which uses the
135             length of the data which has been ciphered, this padding is
136             carried out by the padLength method. For Ripemd320 the addSize is 8.
137 
138      ***********************************************************************/
139 
140     override protected uint addSize()   { return 8;  }
141 
142     /***********************************************************************
143 
144         Pads the cipher data
145 
146         Params:
147             at = a slice of the cipher buffer to fill with padding
148 
149         Remarks:
150             Fills the passed buffer slice with the appropriate padding for
151             the final call to transform(). This padding will fill the cipher
152             buffer up to blockSize()-addSize().
153 
154      ***********************************************************************/
155 
156     protected override void padMessage(ubyte[] at)
157     {
158         at[0] = padChar;
159         at[1..at.length] = 0;
160     }
161 
162     /***********************************************************************
163 
164         Performs the length padding
165 
166         Params:
167             at   = the slice of the cipher buffer to fill with padding
168             length = the length of the data which has been ciphered
169 
170         Remarks:
171             Fills the passed buffer slice with addSize() bytes of padding
172             based on the length in bytes of the input data which has been
173             ciphered.
174 
175      ***********************************************************************/
176 
177     protected override void padLength(ubyte[] at, ulong length)
178     {
179         length <<= 3;
180         littleEndian64((cast(ubyte*)&length)[0..8],cast(ulong[]) at);
181     }
182 
183     /***********************************************************************
184 
185         Performs the cipher on a block of data
186 
187         Params:
188             input = the block of data to cipher
189 
190         Remarks:
191             The actual cipher algorithm is carried out by this method on
192             the passed block of data. This method is called for every
193             blockSize() bytes of input data and once more with the remaining
194             data padded to blockSize().
195 
196      ***********************************************************************/
197 
198     protected override void transform(ubyte[] input)
199     {
200         uint al, bl, cl, dl, el;
201         uint ar, br, cr, dr, er;
202         uint[16] x;
203         uint t;
204 
205         littleEndian32(input,x);
206 
207         al = context[0];
208         bl = context[1];
209         cl = context[2];
210         dl = context[3];
211         el = context[4];
212         ar = context[5];
213         br = context[6];
214         cr = context[7];
215         dr = context[8];
216         er = context[9];
217 
218         // Round 1 and parallel round 1
219         al = rotateLeft(al + (bl ^ cl ^ dl) + x[0], 11) + el;
220         ar = rotateLeft(ar + (br ^ (cr | ~(dr))) + x[5] + 0x50a28be6, 8) + er;
221         cl = rotateLeft(cl, 10);
222         cr = rotateLeft(cr, 10);
223         el = rotateLeft(el + (al ^ bl ^ cl) + x[1], 14) + dl;
224         er = rotateLeft(er + (ar ^ (br | ~(cr))) + x[14] + 0x50a28be6, 9) + dr;
225         bl = rotateLeft(bl, 10);
226         br = rotateLeft(br, 10);
227         dl = rotateLeft(dl + (el ^ al ^ bl) + x[2], 15) + cl;
228         dr = rotateLeft(dr + (er ^ (ar | ~(br))) + x[7] + 0x50a28be6, 9) + cr;
229         al = rotateLeft(al, 10);
230         ar = rotateLeft(ar, 10);
231         cl = rotateLeft(cl + (dl ^ el ^ al) + x[3], 12) + bl;
232         cr = rotateLeft(cr + (dr ^ (er | ~(ar))) + x[0] + 0x50a28be6, 11) + br;
233         el = rotateLeft(el, 10);
234         er = rotateLeft(er, 10);
235         bl = rotateLeft(bl + (cl ^ dl ^ el) + x[4], 5) + al;
236         br = rotateLeft(br + (cr ^ (dr | ~(er))) + x[9] + 0x50a28be6, 13) + ar;
237         dl = rotateLeft(dl, 10);
238         dr = rotateLeft(dr, 10);
239         al = rotateLeft(al + (bl ^ cl ^ dl) + x[5], 8) + el;
240         ar = rotateLeft(ar + (br ^ (cr | ~(dr))) + x[2] + 0x50a28be6, 15) + er;
241         cl = rotateLeft(cl, 10);
242         cr = rotateLeft(cr, 10);
243         el = rotateLeft(el + (al ^ bl ^ cl) + x[6], 7) + dl;
244         er = rotateLeft(er + (ar ^ (br | ~(cr))) + x[11] + 0x50a28be6, 15) + dr;
245         bl = rotateLeft(bl, 10);
246         br = rotateLeft(br, 10);
247         dl = rotateLeft(dl + (el ^ al ^ bl) + x[7], 9) + cl;
248         dr = rotateLeft(dr + (er ^ (ar | ~(br))) + x[4] + 0x50a28be6, 5) + cr;
249         al = rotateLeft(al, 10);
250         ar = rotateLeft(ar, 10);
251         cl = rotateLeft(cl + (dl ^ el ^ al) + x[8], 11) + bl;
252         cr = rotateLeft(cr + (dr ^ (er | ~(ar))) + x[13] + 0x50a28be6, 7) + br;
253         el = rotateLeft(el, 10);
254         er = rotateLeft(er, 10);
255         bl = rotateLeft(bl + (cl ^ dl ^ el) + x[9], 13) + al;
256         br = rotateLeft(br + (cr ^ (dr | ~(er))) + x[6] + 0x50a28be6, 7) + ar;
257         dl = rotateLeft(dl, 10);
258         dr = rotateLeft(dr, 10);
259         al = rotateLeft(al + (bl ^ cl ^ dl) + x[10], 14) + el;
260         ar = rotateLeft(ar + (br ^ (cr | ~(dr))) + x[15] + 0x50a28be6, 8) + er;
261         cl = rotateLeft(cl, 10);
262         cr = rotateLeft(cr, 10);
263         el = rotateLeft(el + (al ^ bl ^ cl) + x[11], 15) + dl;
264         er = rotateLeft(er + (ar ^ (br | ~(cr))) + x[8] + 0x50a28be6, 11) + dr;
265         bl = rotateLeft(bl, 10);
266         br = rotateLeft(br, 10);
267         dl = rotateLeft(dl + (el ^ al ^ bl) + x[12], 6) + cl;
268         dr = rotateLeft(dr + (er ^ (ar | ~(br))) + x[1] + 0x50a28be6, 14) + cr;
269         al = rotateLeft(al, 10);
270         ar = rotateLeft(ar, 10);
271         cl = rotateLeft(cl + (dl ^ el ^ al) + x[13], 7) + bl;
272         cr = rotateLeft(cr + (dr ^ (er | ~(ar))) + x[10] + 0x50a28be6, 14) + br;
273         el = rotateLeft(el, 10);
274         er = rotateLeft(er, 10);
275         bl = rotateLeft(bl + (cl ^ dl ^ el) + x[14], 9) + al;
276         br = rotateLeft(br + (cr ^ (dr | ~(er))) + x[3] + 0x50a28be6, 12) + ar;
277         dl = rotateLeft(dl, 10);
278         dr = rotateLeft(dr, 10);
279         al = rotateLeft(al + (bl ^ cl ^ dl) + x[15], 8) + el;
280         ar = rotateLeft(ar + (br ^ (cr | ~(dr))) + x[12] + 0x50a28be6, 6) + er;
281         cl = rotateLeft(cl, 10);
282         cr = rotateLeft(cr, 10);
283 
284         t = al; al = ar; ar = t;
285 
286         // Round 2 and parallel round 2
287         el = rotateLeft(el + (((bl ^ cl) & al) ^ cl) + x[7] + 0x5a827999, 7) + dl;
288         er = rotateLeft(er + ((ar & cr) | (br & ~(cr))) + x[6] + 0x5c4dd124, 9) + dr;
289         bl = rotateLeft(bl, 10);
290         br = rotateLeft(br, 10);
291         dl = rotateLeft(dl + (((al ^ bl) & el) ^ bl) + x[4] + 0x5a827999, 6) + cl;
292         dr = rotateLeft(dr + ((er & br) | (ar & ~(br))) + x[11] + 0x5c4dd124, 13) + cr;
293         al = rotateLeft(al, 10);
294         ar = rotateLeft(ar, 10);
295         cl = rotateLeft(cl + (((el ^ al) & dl) ^ al) + x[13] + 0x5a827999, 8) + bl;
296         cr = rotateLeft(cr + ((dr & ar) | (er & ~(ar))) + x[3] + 0x5c4dd124, 15) + br;
297         el = rotateLeft(el, 10);
298         er = rotateLeft(er, 10);
299         bl = rotateLeft(bl + (((dl ^ el) & cl) ^ el) + x[1] + 0x5a827999, 13) + al;
300         br = rotateLeft(br + ((cr & er) | (dr & ~(er))) + x[7] + 0x5c4dd124, 7) + ar;
301         dl = rotateLeft(dl, 10);
302         dr = rotateLeft(dr, 10);
303         al = rotateLeft(al + (((cl ^ dl) & bl) ^ dl) + x[10] + 0x5a827999, 11) + el;
304         ar = rotateLeft(ar + ((br & dr) | (cr & ~(dr))) + x[0] + 0x5c4dd124, 12) + er;
305         cl = rotateLeft(cl, 10);
306         cr = rotateLeft(cr, 10);
307         el = rotateLeft(el + (((bl ^ cl) & al) ^ cl) + x[6] + 0x5a827999, 9) + dl;
308         er = rotateLeft(er + ((ar & cr) | (br & ~(cr))) + x[13] + 0x5c4dd124, 8) + dr;
309         bl = rotateLeft(bl, 10);
310         br = rotateLeft(br, 10);
311         dl = rotateLeft(dl + (((al ^ bl) & el) ^ bl) + x[15] + 0x5a827999, 7) + cl;
312         dr = rotateLeft(dr + ((er & br) | (ar & ~(br))) + x[5] + 0x5c4dd124, 9) + cr;
313         al = rotateLeft(al, 10);
314         ar = rotateLeft(ar, 10);
315         cl = rotateLeft(cl + (((el ^ al) & dl) ^ al) + x[3] + 0x5a827999, 15) + bl;
316         cr = rotateLeft(cr + ((dr & ar) | (er & ~(ar))) + x[10] + 0x5c4dd124, 11) + br;
317         el = rotateLeft(el, 10);
318         er = rotateLeft(er, 10);
319         bl = rotateLeft(bl + (((dl ^ el) & cl) ^ el) + x[12] + 0x5a827999, 7) + al;
320         br = rotateLeft(br + ((cr & er) | (dr & ~(er))) + x[14] + 0x5c4dd124, 7) + ar;
321         dl = rotateLeft(dl, 10);
322         dr = rotateLeft(dr, 10);
323         al = rotateLeft(al + (((cl ^ dl) & bl) ^ dl) + x[0] + 0x5a827999, 12) + el;
324         ar = rotateLeft(ar + ((br & dr) | (cr & ~(dr))) + x[15] + 0x5c4dd124, 7) + er;
325         cl = rotateLeft(cl, 10);
326         cr = rotateLeft(cr, 10);
327         el = rotateLeft(el + (((bl ^ cl) & al) ^ cl) + x[9] + 0x5a827999, 15) + dl;
328         er = rotateLeft(er + ((ar & cr) | (br & ~(cr))) + x[8] + 0x5c4dd124, 12) + dr;
329         bl = rotateLeft(bl, 10);
330         br = rotateLeft(br, 10);
331         dl = rotateLeft(dl + (((al ^ bl) & el) ^ bl) + x[5] + 0x5a827999, 9) + cl;
332         dr = rotateLeft(dr + ((er & br) | (ar & ~(br))) + x[12] + 0x5c4dd124, 7) + cr;
333         al = rotateLeft(al, 10);
334         ar = rotateLeft(ar, 10);
335         cl = rotateLeft(cl + (((el ^ al) & dl) ^ al) + x[2] + 0x5a827999, 11) + bl;
336         cr = rotateLeft(cr + ((dr & ar) | (er & ~(ar))) + x[4] + 0x5c4dd124, 6) + br;
337         el = rotateLeft(el, 10);
338         er = rotateLeft(er, 10);
339         bl = rotateLeft(bl + (((dl ^ el) & cl) ^ el) + x[14] + 0x5a827999, 7) + al;
340         br = rotateLeft(br + ((cr & er) | (dr & ~(er))) + x[9] + 0x5c4dd124, 15) + ar;
341         dl = rotateLeft(dl, 10);
342         dr = rotateLeft(dr, 10);
343         al = rotateLeft(al + (((cl ^ dl) & bl) ^ dl) + x[11] + 0x5a827999, 13) + el;
344         ar = rotateLeft(ar + ((br & dr) | (cr & ~(dr))) + x[1] + 0x5c4dd124, 13) + er;
345         cl = rotateLeft(cl, 10);
346         cr = rotateLeft(cr, 10);
347         el = rotateLeft(el + (((bl ^ cl) & al) ^ cl) + x[8] + 0x5a827999, 12) + dl;
348         er = rotateLeft(er + ((ar & cr) | (br & ~(cr))) + x[2] + 0x5c4dd124, 11) + dr;
349         bl = rotateLeft(bl, 10);
350         br = rotateLeft(br, 10);
351 
352         t = bl; bl = br; br = t;
353 
354         // Round 3 and parallel round 3
355         dl = rotateLeft(dl + ((el | ~(al)) ^ bl) + x[3] + 0x6ed9eba1, 11) + cl;
356         dr = rotateLeft(dr + ((er | ~(ar)) ^ br) + x[15] + 0x6d703ef3, 9) + cr;
357         al = rotateLeft(al, 10);
358         ar = rotateLeft(ar, 10);
359         cl = rotateLeft(cl + ((dl | ~(el)) ^ al) + x[10] + 0x6ed9eba1, 13) + bl;
360         cr = rotateLeft(cr + ((dr | ~(er)) ^ ar) + x[5] + 0x6d703ef3, 7) + br;
361         el = rotateLeft(el, 10);
362         er = rotateLeft(er, 10);
363         bl = rotateLeft(bl + ((cl | ~(dl)) ^ el) + x[14] + 0x6ed9eba1, 6) + al;
364         br = rotateLeft(br + ((cr | ~(dr)) ^ er) + x[1] + 0x6d703ef3, 15) + ar;
365         dl = rotateLeft(dl, 10);
366         dr = rotateLeft(dr, 10);
367         al = rotateLeft(al + ((bl | ~(cl)) ^ dl) + x[4] + 0x6ed9eba1, 7) + el;
368         ar = rotateLeft(ar + ((br | ~(cr)) ^ dr) + x[3] + 0x6d703ef3, 11) + er;
369         cl = rotateLeft(cl, 10);
370         cr = rotateLeft(cr, 10);
371         el = rotateLeft(el + ((al | ~(bl)) ^ cl) + x[9] + 0x6ed9eba1, 14) + dl;
372         er = rotateLeft(er + ((ar | ~(br)) ^ cr) + x[7] + 0x6d703ef3, 8) + dr;
373         bl = rotateLeft(bl, 10);
374         br = rotateLeft(br, 10);
375         dl = rotateLeft(dl + ((el | ~(al)) ^ bl) + x[15] + 0x6ed9eba1, 9) + cl;
376         dr = rotateLeft(dr + ((er | ~(ar)) ^ br) + x[14] + 0x6d703ef3, 6) + cr;
377         al = rotateLeft(al, 10);
378         ar = rotateLeft(ar, 10);
379         cl = rotateLeft(cl + ((dl | ~(el)) ^ al) + x[8] + 0x6ed9eba1, 13) + bl;
380         cr = rotateLeft(cr + ((dr | ~(er)) ^ ar) + x[6] + 0x6d703ef3, 6) + br;
381         el = rotateLeft(el, 10);
382         er = rotateLeft(er, 10);
383         bl = rotateLeft(bl + ((cl | ~(dl)) ^ el) + x[1] + 0x6ed9eba1, 15) + al;
384         br = rotateLeft(br + ((cr | ~(dr)) ^ er) + x[9] + 0x6d703ef3, 14) + ar;
385         dl = rotateLeft(dl, 10);
386         dr = rotateLeft(dr, 10);
387         al = rotateLeft(al + ((bl | ~(cl)) ^ dl) + x[2] + 0x6ed9eba1, 14) + el;
388         ar = rotateLeft(ar + ((br | ~(cr)) ^ dr) + x[11] + 0x6d703ef3, 12) + er;
389         cl = rotateLeft(cl, 10);
390         cr = rotateLeft(cr, 10);
391         el = rotateLeft(el + ((al | ~(bl)) ^ cl) + x[7] + 0x6ed9eba1, 8) + dl;
392         er = rotateLeft(er + ((ar | ~(br)) ^ cr) + x[8] + 0x6d703ef3, 13) + dr;
393         bl = rotateLeft(bl, 10);
394         br = rotateLeft(br, 10);
395         dl = rotateLeft(dl + ((el | ~(al)) ^ bl) + x[0] + 0x6ed9eba1, 13) + cl;
396         dr = rotateLeft(dr + ((er | ~(ar)) ^ br) + x[12] + 0x6d703ef3, 5) + cr;
397         al = rotateLeft(al, 10);
398         ar = rotateLeft(ar, 10);
399         cl = rotateLeft(cl + ((dl | ~(el)) ^ al) + x[6] + 0x6ed9eba1, 6) + bl;
400         cr = rotateLeft(cr + ((dr | ~(er)) ^ ar) + x[2] + 0x6d703ef3, 14) + br;
401         el = rotateLeft(el, 10);
402         er = rotateLeft(er, 10);
403         bl = rotateLeft(bl + ((cl | ~(dl)) ^ el) + x[13] + 0x6ed9eba1, 5) + al;
404         br = rotateLeft(br + ((cr | ~(dr)) ^ er) + x[10] + 0x6d703ef3, 13) + ar;
405         dl = rotateLeft(dl, 10);
406         dr = rotateLeft(dr, 10);
407         al = rotateLeft(al + ((bl | ~(cl)) ^ dl) + x[11] + 0x6ed9eba1, 12) + el;
408         ar = rotateLeft(ar + ((br | ~(cr)) ^ dr) + x[0] + 0x6d703ef3, 13) + er;
409         cl = rotateLeft(cl, 10);
410         cr = rotateLeft(cr, 10);
411         el = rotateLeft(el + ((al | ~(bl)) ^ cl) + x[5] + 0x6ed9eba1, 7) + dl;
412         er = rotateLeft(er + ((ar | ~(br)) ^ cr) + x[4] + 0x6d703ef3, 7) + dr;
413         bl = rotateLeft(bl, 10);
414         br = rotateLeft(br, 10);
415         dl = rotateLeft(dl + ((el | ~(al)) ^ bl) + x[12] + 0x6ed9eba1, 5) + cl;
416         dr = rotateLeft(dr + ((er | ~(ar)) ^ br) + x[13] + 0x6d703ef3, 5) + cr;
417         al = rotateLeft(al, 10);
418         ar = rotateLeft(ar, 10);
419 
420         t = cl; cl = cr; cr = t;
421 
422         // Round 4 and parallel round 4
423         cl = rotateLeft(cl + ((dl & al) | (el & ~(al))) + x[1] + 0x8f1bbcdc, 11) + bl;
424         cr = rotateLeft(cr + (((er ^ ar) & dr) ^ ar) + x[8] + 0x7a6d76e9, 15) + br;
425         el = rotateLeft(el, 10);
426         er = rotateLeft(er, 10);
427         bl = rotateLeft(bl + ((cl & el) | (dl & ~(el))) + x[9] + 0x8f1bbcdc, 12) + al;
428         br = rotateLeft(br + (((dr ^ er) & cr) ^ er) + x[6] + 0x7a6d76e9, 5) + ar;
429         dl = rotateLeft(dl, 10);
430         dr = rotateLeft(dr, 10);
431         al = rotateLeft(al + ((bl & dl) | (cl & ~(dl))) + x[11] + 0x8f1bbcdc, 14) + el;
432         ar = rotateLeft(ar + (((cr ^ dr) & br) ^ dr) + x[4] + 0x7a6d76e9, 8) + er;
433         cl = rotateLeft(cl, 10);
434         cr = rotateLeft(cr, 10);
435         el = rotateLeft(el + ((al & cl) | (bl & ~(cl))) + x[10] + 0x8f1bbcdc, 15) + dl;
436         er = rotateLeft(er + (((br ^ cr) & ar) ^ cr) + x[1] + 0x7a6d76e9, 11) + dr;
437         bl = rotateLeft(bl, 10);
438         br = rotateLeft(br, 10);
439         dl = rotateLeft(dl + ((el & bl) | (al & ~(bl))) + x[0] + 0x8f1bbcdc, 14) + cl;
440         dr = rotateLeft(dr + (((ar ^ br) & er) ^ br) + x[3] + 0x7a6d76e9, 14) + cr;
441         al = rotateLeft(al, 10);
442         ar = rotateLeft(ar, 10);
443         cl = rotateLeft(cl + ((dl & al) | (el & ~(al))) + x[8] + 0x8f1bbcdc, 15) + bl;
444         cr = rotateLeft(cr + (((er ^ ar) & dr) ^ ar) + x[11] + 0x7a6d76e9, 14) + br;
445         el = rotateLeft(el, 10);
446         er = rotateLeft(er, 10);
447         bl = rotateLeft(bl + ((cl & el) | (dl & ~(el))) + x[12] + 0x8f1bbcdc, 9) + al;
448         br = rotateLeft(br + (((dr ^ er) & cr) ^ er) + x[15] + 0x7a6d76e9, 6) + ar;
449         dl = rotateLeft(dl, 10);
450         dr = rotateLeft(dr, 10);
451         al = rotateLeft(al + ((bl & dl) | (cl & ~(dl))) + x[4] + 0x8f1bbcdc, 8) + el;
452         ar = rotateLeft(ar + (((cr ^ dr) & br) ^ dr) + x[0] + 0x7a6d76e9, 14) + er;
453         cl = rotateLeft(cl, 10);
454         cr = rotateLeft(cr, 10);
455         el = rotateLeft(el + ((al & cl) | (bl & ~(cl))) + x[13] + 0x8f1bbcdc, 9) + dl;
456         er = rotateLeft(er + (((br ^ cr) & ar) ^ cr) + x[5] + 0x7a6d76e9, 6) + dr;
457         bl = rotateLeft(bl, 10);
458         br = rotateLeft(br, 10);
459         dl = rotateLeft(dl + ((el & bl) | (al & ~(bl))) + x[3] + 0x8f1bbcdc, 14) + cl;
460         dr = rotateLeft(dr + (((ar ^ br) & er) ^ br) + x[12] + 0x7a6d76e9, 9) + cr;
461         al = rotateLeft(al, 10);
462         ar = rotateLeft(ar, 10);
463         cl = rotateLeft(cl + ((dl & al) | (el & ~(al))) + x[7] + 0x8f1bbcdc, 5) + bl;
464         cr = rotateLeft(cr + (((er ^ ar) & dr) ^ ar) + x[2] + 0x7a6d76e9, 12) + br;
465         el = rotateLeft(el, 10);
466         er = rotateLeft(er, 10);
467         bl = rotateLeft(bl + ((cl & el) | (dl & ~(el))) + x[15] + 0x8f1bbcdc, 6) + al;
468         br = rotateLeft(br + (((dr ^ er) & cr) ^ er) + x[13] + 0x7a6d76e9, 9) + ar;
469         dl = rotateLeft(dl, 10);
470         dr = rotateLeft(dr, 10);
471         al = rotateLeft(al + ((bl & dl) | (cl & ~(dl))) + x[14] + 0x8f1bbcdc, 8) + el;
472         ar = rotateLeft(ar + (((cr ^ dr) & br) ^ dr) + x[9] + 0x7a6d76e9, 12) + er;
473         cl = rotateLeft(cl, 10);
474         cr = rotateLeft(cr, 10);
475         el = rotateLeft(el + ((al & cl) | (bl & ~(cl))) + x[5] + 0x8f1bbcdc, 6) + dl;
476         er = rotateLeft(er + (((br ^ cr) & ar) ^ cr) + x[7] + 0x7a6d76e9, 5) + dr;
477         bl = rotateLeft(bl, 10);
478         br = rotateLeft(br, 10);
479         dl = rotateLeft(dl + ((el & bl) | (al & ~(bl))) + x[6] + 0x8f1bbcdc, 5) + cl;
480         dr = rotateLeft(dr + (((ar ^ br) & er) ^ br) + x[10] + 0x7a6d76e9, 15) + cr;
481         al = rotateLeft(al, 10);
482         ar = rotateLeft(ar, 10);
483         cl = rotateLeft(cl + ((dl & al) | (el & ~(al))) + x[2] + 0x8f1bbcdc, 12) + bl;
484         cr = rotateLeft(cr + (((er ^ ar) & dr) ^ ar) + x[14] + 0x7a6d76e9, 8) + br;
485         el = rotateLeft(el, 10);
486         er = rotateLeft(er, 10);
487 
488         t = dl; dl = dr; dr = t;
489 
490         // Round 5 and parallel round 5
491         bl = rotateLeft(bl + (cl ^ (dl | ~(el))) + x[4] + 0xa953fd4e, 9) + al;
492         br = rotateLeft(br + (cr ^ dr ^ er) + x[12], 8) + ar;
493         dl = rotateLeft(dl, 10);
494         dr = rotateLeft(dr, 10);
495         al = rotateLeft(al + (bl ^ (cl | ~(dl))) + x[0] + 0xa953fd4e, 15) + el;
496         ar = rotateLeft(ar + (br ^ cr ^ dr) + x[15], 5) + er;
497         cl = rotateLeft(cl, 10);
498         cr = rotateLeft(cr, 10);
499         el = rotateLeft(el + (al ^ (bl | ~(cl))) + x[5] + 0xa953fd4e, 5) + dl;
500         er = rotateLeft(er + (ar ^ br ^ cr) + x[10], 12) + dr;
501         bl = rotateLeft(bl, 10);
502         br = rotateLeft(br, 10);
503         dl = rotateLeft(dl + (el ^ (al | ~(bl))) + x[9] + 0xa953fd4e, 11) + cl;
504         dr = rotateLeft(dr + (er ^ ar ^ br) + x[4], 9) + cr;
505         al = rotateLeft(al, 10);
506         ar = rotateLeft(ar, 10);
507         cl = rotateLeft(cl + (dl ^ (el | ~(al))) + x[7] + 0xa953fd4e, 6) + bl;
508         cr = rotateLeft(cr + (dr ^ er ^ ar) + x[1], 12) + br;
509         el = rotateLeft(el, 10);
510         er = rotateLeft(er, 10);
511         bl = rotateLeft(bl + (cl ^ (dl | ~(el))) + x[12] + 0xa953fd4e, 8) + al;
512         br = rotateLeft(br + (cr ^ dr ^ er) + x[5], 5) + ar;
513         dl = rotateLeft(dl, 10);
514         dr = rotateLeft(dr, 10);
515         al = rotateLeft(al + (bl ^ (cl | ~(dl))) + x[2] + 0xa953fd4e, 13) + el;
516         ar = rotateLeft(ar + (br ^ cr ^ dr) + x[8], 14) + er;
517         cl = rotateLeft(cl, 10);
518         cr = rotateLeft(cr, 10);
519         el = rotateLeft(el + (al ^ (bl | ~(cl))) + x[10] + 0xa953fd4e, 12) + dl;
520         er = rotateLeft(er + (ar ^ br ^ cr) + x[7], 6) + dr;
521         bl = rotateLeft(bl, 10);
522         br = rotateLeft(br, 10);
523         dl = rotateLeft(dl + (el ^ (al | ~(bl))) + x[14] + 0xa953fd4e, 5) + cl;
524         dr = rotateLeft(dr + (er ^ ar ^ br) + x[6], 8) + cr;
525         al = rotateLeft(al, 10);
526         ar = rotateLeft(ar, 10);
527         cl = rotateLeft(cl + (dl ^ (el | ~(al))) + x[1] + 0xa953fd4e, 12) + bl;
528         cr = rotateLeft(cr + (dr ^ er ^ ar) + x[2], 13) + br;
529         el = rotateLeft(el, 10);
530         er = rotateLeft(er, 10);
531         bl = rotateLeft(bl + (cl ^ (dl | ~(el))) + x[3] + 0xa953fd4e, 13) + al;
532         br = rotateLeft(br + (cr ^ dr ^ er) + x[13], 6) + ar;
533         dl = rotateLeft(dl, 10);
534         dr = rotateLeft(dr, 10);
535         al = rotateLeft(al + (bl ^ (cl | ~(dl))) + x[8] + 0xa953fd4e, 14) + el;
536         ar = rotateLeft(ar + (br ^ cr ^ dr) + x[14], 5) + er;
537         cl = rotateLeft(cl, 10);
538         cr = rotateLeft(cr, 10);
539         el = rotateLeft(el + (al ^ (bl | ~(cl))) + x[11] + 0xa953fd4e, 11) + dl;
540         er = rotateLeft(er + (ar ^ br ^ cr) + x[0], 15) + dr;
541         bl = rotateLeft(bl, 10);
542         br = rotateLeft(br, 10);
543         dl = rotateLeft(dl + (el ^ (al | ~(bl))) + x[6] + 0xa953fd4e, 8) + cl;
544         dr = rotateLeft(dr + (er ^ ar ^ br) + x[3], 13) + cr;
545         al = rotateLeft(al, 10);
546         ar = rotateLeft(ar, 10);
547         cl = rotateLeft(cl + (dl ^ (el | ~(al))) + x[15] + 0xa953fd4e, 5) + bl;
548         cr = rotateLeft(cr + (dr ^ er ^ ar) + x[9], 11) + br;
549         el = rotateLeft(el, 10);
550         er = rotateLeft(er, 10);
551         bl = rotateLeft(bl + (cl ^ (dl | ~(el))) + x[13] + 0xa953fd4e, 6) + al;
552         br = rotateLeft(br + (cr ^ dr ^ er) + x[11], 11) + ar;
553         dl = rotateLeft(dl, 10);
554         dr = rotateLeft(dr, 10);
555 
556         // Do not swap el and er; simply add the right value to context
557 
558         context[0] += al;
559         context[1] += bl;
560         context[2] += cl;
561         context[3] += dl;
562         context[4] += er;
563         context[5] += ar;
564         context[6] += br;
565         context[7] += cr;
566         context[8] += dr;
567         context[9] += el;
568 
569         x[] = 0;
570     }
571 
572 }
573 
574 /*******************************************************************************
575 
576     Unittests
577 
578 *******************************************************************************/
579 
580 unittest
581 {
582     static istring[] strings = [
583         "",
584         "a",
585         "abc",
586         "message digest",
587         "abcdefghijklmnopqrstuvwxyz",
588         "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
589         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
590         "12345678901234567890123456789012345678901234567890123456789012345678901234567890"
591     ];
592 
593     static istring[] results = [
594         "22d65d5661536cdc75c1fdf5c6de7b41b9f27325ebc61e8557177d705a0ec880151c3a32a00899b8",
595         "ce78850638f92658a5a585097579926dda667a5716562cfcf6fbe77f63542f99b04705d6970dff5d",
596         "de4c01b3054f8930a79d09ae738e92301e5a17085beffdc1b8d116713e74f82fa942d64cdbc4682d",
597         "3a8e28502ed45d422f68844f9dd316e7b98533fa3f2a91d29f84d425c88d6b4eff727df66a7c0197",
598         "cabdb1810b92470a2093aa6bce05952c28348cf43ff60841975166bb40ed234004b8824463e6b009",
599         "d034a7950cf722021ba4b84df769a5de2060e259df4c9bb4a4268c0e935bbc7470a969c9d072a1ac",
600         "ed544940c86d67f250d232c30b7b3e5770e0c60c8cb9a4cafe3b11388af9920e1b99230b843c86a4",
601         "557888af5f6d8ed62ab66945c6d2a0a47ecd5341e915eb8fea1d0524955f825dc717e4a008ab2d42"
602     ];
603 
604     Ripemd320 h = new Ripemd320();
605 
606     foreach (i, s; strings)
607     {
608         h.update(cast(ubyte[]) s);
609         char[] d = h.hexDigest;
610 
611         test(d == results[i],":("~s~")("~d~")!=("~results[i]~")");
612     }
613 
614     char[] s = new char[1000000];
615     for (auto i = 0; i < s.length; i++) s[i] = 'a';
616     auto result = "bdee37f4371e20646b8b0d862dda16292ae36f40965e8c8509e63d1dbddecc503e2b63eb9245bb66";
617     h.update(cast(ubyte[]) s);
618     auto d = h.hexDigest;
619 
620     test (d == result,":(1 million times \"a\")("~d~")!=("~result~")");
621 }