| /** | |
| * Computes RIPEMD-160 hashes of arbitrary data. RIPEMD-160 hashes are 20 byte quantities | |
| * that are like a checksum or CRC, but are more robust. | |
| * | |
| $(SCRIPT inhibitQuickIndex = 1;) | |
| $(DIVC quickindex, | |
| $(BOOKTABLE , | |
| $(TR $(TH Category) $(TH Functions) | |
| ) | |
| $(TR $(TDNW Template API) $(TD $(MYREF RIPEMD160) | |
| ) | |
| ) | |
| $(TR $(TDNW OOP API) $(TD $(MYREF RIPEMD160Digest)) | |
| ) | |
| $(TR $(TDNW Helpers) $(TD $(MYREF ripemd160Of)) | |
| ) | |
| ) | |
| ) | |
| * This module conforms to the APIs defined in $(MREF std, digest). To understand the | |
| * differences between the template and the OOP API, see $(MREF std, digest). | |
| * | |
| * This module publicly imports `std.digest` and can be used as a stand-alone | |
| * module. | |
| * | |
| * License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). | |
| * | |
| * CTFE: | |
| * Digests do not work in CTFE | |
| * | |
| * Authors: | |
| * Kai Nacke $(BR) | |
| * The algorithm was designed by Hans Dobbertin, Antoon Bosselaers, and Bart Preneel. $(BR) | |
| * The D implementation is a direct translation of the ANSI C implementation by Antoon Bosselaers. | |
| * | |
| * References: | |
| * $(UL | |
| * $(LI $(LINK2 http://homes.esat.kuleuven.be/~bosselae/ripemd160.html, The hash function RIPEMD-160)) | |
| * $(LI $(LINK2 http://en.wikipedia.org/wiki/RIPEMD-160, Wikipedia on RIPEMD-160)) | |
| * ) | |
| * | |
| * Source: $(PHOBOSSRC std/digest/ripemd.d) | |
| * | |
| */ | |
| module std.digest.ripemd; | |
| public import std.digest; | |
| /// | |
| @safe unittest | |
| { | |
| //Template API | |
| import std.digest.md; | |
| ubyte[20] hash = ripemd160Of("abc"); | |
| assert(toHexString(hash) == "8EB208F7E05D987A9B044A8E98C6B087F15A0BFC"); | |
| //Feeding data | |
| ubyte[1024] data; | |
| RIPEMD160 md; | |
| md.start(); | |
| md.put(data[]); | |
| md.start(); //Start again | |
| md.put(data[]); | |
| hash = md.finish(); | |
| } | |
| /// | |
| @safe unittest | |
| { | |
| //OOP API | |
| import std.digest.md; | |
| auto md = new RIPEMD160Digest(); | |
| ubyte[] hash = md.digest("abc"); | |
| assert(toHexString(hash) == "8EB208F7E05D987A9B044A8E98C6B087F15A0BFC"); | |
| //Feeding data | |
| ubyte[1024] data; | |
| md.put(data[]); | |
| md.reset(); //Start again | |
| md.put(data[]); | |
| hash = md.finish(); | |
| } | |
| /** | |
| * Template API RIPEMD160 implementation. | |
| * See `std.digest` for differences between template and OOP API. | |
| */ | |
| struct RIPEMD160 | |
| { | |
| import core.bitop : rol; | |
| private: | |
| // magic initialization constants | |
| uint[5] _state = [0x67452301,0xefcdab89,0x98badcfe,0x10325476,0xc3d2e1f0]; // state (ABCDE) | |
| ulong _count; //number of bits, modulo 2^64 | |
| ubyte[64] _buffer; // input buffer | |
| static immutable ubyte[64] _padding = | |
| [ | |
| 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 | |
| ]; | |
| // F, G, H, I and J are basic RIPEMD160 functions | |
| static @safe pure nothrow @nogc | |
| { | |
| uint F(uint x, uint y, uint z) { return x ^ y ^ z; } | |
| uint G(uint x, uint y, uint z) { return (x & y) | (~x & z); } | |
| uint H(uint x, uint y, uint z) { return (x | ~y) ^ z; } | |
| uint I(uint x, uint y, uint z) { return (x & z) | (y & ~z); } | |
| uint J(uint x, uint y, uint z) { return x ^ (y | ~z); } | |
| } | |
| /* | |
| * FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. | |
| * Rotation is separate from addition to prevent recomputation. | |
| */ | |
| /* the ten basic operations FF() through III() */ | |
| static void FF(ref uint a, uint b, ref uint c, uint d, uint e, uint x, uint s) | |
| @safe pure nothrow @nogc | |
| { | |
| a += F(b, c, d) + x; | |
| a = rol(a, s) + e; | |
| c = rol(c, 10); | |
| } | |
| static void GG(ref uint a, uint b, ref uint c, uint d, uint e, uint x, uint s) | |
| @safe pure nothrow @nogc | |
| { | |
| a += G(b, c, d) + x + 0x5a827999UL; | |
| a = rol(a, s) + e; | |
| c = rol(c, 10); | |
| } | |
| static void HH(ref uint a, uint b, ref uint c, uint d, uint e, uint x, uint s) | |
| @safe pure nothrow @nogc | |
| { | |
| a += H(b, c, d) + x + 0x6ed9eba1UL; | |
| a = rol(a, s) + e; | |
| c = rol(c, 10); | |
| } | |
| static void II(ref uint a, uint b, ref uint c, uint d, uint e, uint x, uint s) | |
| @safe pure nothrow @nogc | |
| { | |
| a += I(b, c, d) + x + 0x8f1bbcdcUL; | |
| a = rol(a, s) + e; | |
| c = rol(c, 10); | |
| } | |
| static void JJ(ref uint a, uint b, ref uint c, uint d, uint e, uint x, uint s) | |
| @safe pure nothrow @nogc | |
| { | |
| a += J(b, c, d) + x + 0xa953fd4eUL; | |
| a = rol(a, s) + e; | |
| c = rol(c, 10); | |
| } | |
| /* | |
| * FFF, GGG, HHH, and III transformations for parallel rounds 1, 2, 3, and 4. | |
| * Rotation is separate from addition to prevent recomputation. | |
| */ | |
| static void FFF(ref uint a, uint b, ref uint c, uint d, uint e, uint x, uint s) | |
| @safe pure nothrow @nogc | |
| { | |
| a += F(b, c, d) + x; | |
| a = rol(a, s) + e; | |
| c = rol(c, 10); | |
| } | |
| static void GGG(ref uint a, uint b, ref uint c, uint d, uint e, uint x, uint s) | |
| @safe pure nothrow @nogc | |
| { | |
| a += G(b, c, d) + x + 0x7a6d76e9UL; | |
| a = rol(a, s) + e; | |
| c = rol(c, 10); | |
| } | |
| static void HHH(ref uint a, uint b, ref uint c, uint d, uint e, uint x, uint s) | |
| @safe pure nothrow @nogc | |
| { | |
| a += H(b, c, d) + x + 0x6d703ef3UL; | |
| a = rol(a, s) + e; | |
| c = rol(c, 10); | |
| } | |
| static void III(ref uint a, uint b, ref uint c, uint d, uint e, uint x, uint s) | |
| @safe pure nothrow @nogc | |
| { | |
| a += I(b, c, d) + x + 0x5c4dd124UL; | |
| a = rol(a, s) + e; | |
| c = rol(c, 10); | |
| } | |
| static void JJJ(ref uint a, uint b, ref uint c, uint d, uint e, uint x, uint s) | |
| @safe pure nothrow @nogc | |
| { | |
| a += J(b, c, d) + x + 0x50a28be6UL; | |
| a = rol(a, s) + e; | |
| c = rol(c, 10); | |
| } | |
| /* | |
| * RIPEMD160 basic transformation. Transforms state based on block. | |
| */ | |
| void transform(const(ubyte[64])* block) | |
| pure nothrow @nogc | |
| { | |
| uint aa = _state[0], | |
| bb = _state[1], | |
| cc = _state[2], | |
| dd = _state[3], | |
| ee = _state[4]; | |
| uint aaa = _state[0], | |
| bbb = _state[1], | |
| ccc = _state[2], | |
| ddd = _state[3], | |
| eee = _state[4]; | |
| uint[16] x = void; | |
| version (BigEndian) | |
| { | |
| import std.bitmanip : littleEndianToNative; | |
| for (size_t i = 0; i < 16; i++) | |
| { | |
| x[i] = littleEndianToNative!uint(*cast(ubyte[4]*)&(*block)[i*4]); | |
| } | |
| } | |
| else | |
| { | |
| (cast(ubyte*) x.ptr)[0 .. 64] = (cast(ubyte*) block)[0 .. 64]; | |
| } | |
| /* round 1 */ | |
| FF(aa, bb, cc, dd, ee, x[ 0], 11); | |
| FF(ee, aa, bb, cc, dd, x[ 1], 14); | |
| FF(dd, ee, aa, bb, cc, x[ 2], 15); | |
| FF(cc, dd, ee, aa, bb, x[ 3], 12); | |
| FF(bb, cc, dd, ee, aa, x[ 4], 5); | |
| FF(aa, bb, cc, dd, ee, x[ 5], 8); | |
| FF(ee, aa, bb, cc, dd, x[ 6], 7); | |
| FF(dd, ee, aa, bb, cc, x[ 7], 9); | |
| FF(cc, dd, ee, aa, bb, x[ 8], 11); | |
| FF(bb, cc, dd, ee, aa, x[ 9], 13); | |
| FF(aa, bb, cc, dd, ee, x[10], 14); | |
| FF(ee, aa, bb, cc, dd, x[11], 15); | |
| FF(dd, ee, aa, bb, cc, x[12], 6); | |
| FF(cc, dd, ee, aa, bb, x[13], 7); | |
| FF(bb, cc, dd, ee, aa, x[14], 9); | |
| FF(aa, bb, cc, dd, ee, x[15], 8); | |
| /* round 2 */ | |
| GG(ee, aa, bb, cc, dd, x[ 7], 7); | |
| GG(dd, ee, aa, bb, cc, x[ 4], 6); | |
| GG(cc, dd, ee, aa, bb, x[13], 8); | |
| GG(bb, cc, dd, ee, aa, x[ 1], 13); | |
| GG(aa, bb, cc, dd, ee, x[10], 11); | |
| GG(ee, aa, bb, cc, dd, x[ 6], 9); | |
| GG(dd, ee, aa, bb, cc, x[15], 7); | |
| GG(cc, dd, ee, aa, bb, x[ 3], 15); | |
| GG(bb, cc, dd, ee, aa, x[12], 7); | |
| GG(aa, bb, cc, dd, ee, x[ 0], 12); | |
| GG(ee, aa, bb, cc, dd, x[ 9], 15); | |
| GG(dd, ee, aa, bb, cc, x[ 5], 9); | |
| GG(cc, dd, ee, aa, bb, x[ 2], 11); | |
| GG(bb, cc, dd, ee, aa, x[14], 7); | |
| GG(aa, bb, cc, dd, ee, x[11], 13); | |
| GG(ee, aa, bb, cc, dd, x[ 8], 12); | |
| /* round 3 */ | |
| HH(dd, ee, aa, bb, cc, x[ 3], 11); | |
| HH(cc, dd, ee, aa, bb, x[10], 13); | |
| HH(bb, cc, dd, ee, aa, x[14], 6); | |
| HH(aa, bb, cc, dd, ee, x[ 4], 7); | |
| HH(ee, aa, bb, cc, dd, x[ 9], 14); | |
| HH(dd, ee, aa, bb, cc, x[15], 9); | |
| HH(cc, dd, ee, aa, bb, x[ 8], 13); | |
| HH(bb, cc, dd, ee, aa, x[ 1], 15); | |
| HH(aa, bb, cc, dd, ee, x[ 2], 14); | |
| HH(ee, aa, bb, cc, dd, x[ 7], 8); | |
| HH(dd, ee, aa, bb, cc, x[ 0], 13); | |
| HH(cc, dd, ee, aa, bb, x[ 6], 6); | |
| HH(bb, cc, dd, ee, aa, x[13], 5); | |
| HH(aa, bb, cc, dd, ee, x[11], 12); | |
| HH(ee, aa, bb, cc, dd, x[ 5], 7); | |
| HH(dd, ee, aa, bb, cc, x[12], 5); | |
| /* round 4 */ | |
| II(cc, dd, ee, aa, bb, x[ 1], 11); | |
| II(bb, cc, dd, ee, aa, x[ 9], 12); | |
| II(aa, bb, cc, dd, ee, x[11], 14); | |
| II(ee, aa, bb, cc, dd, x[10], 15); | |
| II(dd, ee, aa, bb, cc, x[ 0], 14); | |
| II(cc, dd, ee, aa, bb, x[ 8], 15); | |
| II(bb, cc, dd, ee, aa, x[12], 9); | |
| II(aa, bb, cc, dd, ee, x[ 4], 8); | |
| II(ee, aa, bb, cc, dd, x[13], 9); | |
| II(dd, ee, aa, bb, cc, x[ 3], 14); | |
| II(cc, dd, ee, aa, bb, x[ 7], 5); | |
| II(bb, cc, dd, ee, aa, x[15], 6); | |
| II(aa, bb, cc, dd, ee, x[14], 8); | |
| II(ee, aa, bb, cc, dd, x[ 5], 6); | |
| II(dd, ee, aa, bb, cc, x[ 6], 5); | |
| II(cc, dd, ee, aa, bb, x[ 2], 12); | |
| /* round 5 */ | |
| JJ(bb, cc, dd, ee, aa, x[ 4], 9); | |
| JJ(aa, bb, cc, dd, ee, x[ 0], 15); | |
| JJ(ee, aa, bb, cc, dd, x[ 5], 5); | |
| JJ(dd, ee, aa, bb, cc, x[ 9], 11); | |
| JJ(cc, dd, ee, aa, bb, x[ 7], 6); | |
| JJ(bb, cc, dd, ee, aa, x[12], 8); | |
| JJ(aa, bb, cc, dd, ee, x[ 2], 13); | |
| JJ(ee, aa, bb, cc, dd, x[10], 12); | |
| JJ(dd, ee, aa, bb, cc, x[14], 5); | |
| JJ(cc, dd, ee, aa, bb, x[ 1], 12); | |
| JJ(bb, cc, dd, ee, aa, x[ 3], 13); | |
| JJ(aa, bb, cc, dd, ee, x[ 8], 14); | |
| JJ(ee, aa, bb, cc, dd, x[11], 11); | |
| JJ(dd, ee, aa, bb, cc, x[ 6], 8); | |
| JJ(cc, dd, ee, aa, bb, x[15], 5); | |
| JJ(bb, cc, dd, ee, aa, x[13], 6); | |
| /* parallel round 1 */ | |
| JJJ(aaa, bbb, ccc, ddd, eee, x[ 5], 8); | |
| JJJ(eee, aaa, bbb, ccc, ddd, x[14], 9); | |
| JJJ(ddd, eee, aaa, bbb, ccc, x[ 7], 9); | |
| JJJ(ccc, ddd, eee, aaa, bbb, x[ 0], 11); | |
| JJJ(bbb, ccc, ddd, eee, aaa, x[ 9], 13); | |
| JJJ(aaa, bbb, ccc, ddd, eee, x[ 2], 15); | |
| JJJ(eee, aaa, bbb, ccc, ddd, x[11], 15); | |
| JJJ(ddd, eee, aaa, bbb, ccc, x[ 4], 5); | |
| JJJ(ccc, ddd, eee, aaa, bbb, x[13], 7); | |
| JJJ(bbb, ccc, ddd, eee, aaa, x[ 6], 7); | |
| JJJ(aaa, bbb, ccc, ddd, eee, x[15], 8); | |
| JJJ(eee, aaa, bbb, ccc, ddd, x[ 8], 11); | |
| JJJ(ddd, eee, aaa, bbb, ccc, x[ 1], 14); | |
| JJJ(ccc, ddd, eee, aaa, bbb, x[10], 14); | |
| JJJ(bbb, ccc, ddd, eee, aaa, x[ 3], 12); | |
| JJJ(aaa, bbb, ccc, ddd, eee, x[12], 6); | |
| /* parallel round 2 */ | |
| III(eee, aaa, bbb, ccc, ddd, x[ 6], 9); | |
| III(ddd, eee, aaa, bbb, ccc, x[11], 13); | |
| III(ccc, ddd, eee, aaa, bbb, x[ 3], 15); | |
| III(bbb, ccc, ddd, eee, aaa, x[ 7], 7); | |
| III(aaa, bbb, ccc, ddd, eee, x[ 0], 12); | |
| III(eee, aaa, bbb, ccc, ddd, x[13], 8); | |
| III(ddd, eee, aaa, bbb, ccc, x[ 5], 9); | |
| III(ccc, ddd, eee, aaa, bbb, x[10], 11); | |
| III(bbb, ccc, ddd, eee, aaa, x[14], 7); | |
| III(aaa, bbb, ccc, ddd, eee, x[15], 7); | |
| III(eee, aaa, bbb, ccc, ddd, x[ 8], 12); | |
| III(ddd, eee, aaa, bbb, ccc, x[12], 7); | |
| III(ccc, ddd, eee, aaa, bbb, x[ 4], 6); | |
| III(bbb, ccc, ddd, eee, aaa, x[ 9], 15); | |
| III(aaa, bbb, ccc, ddd, eee, x[ 1], 13); | |
| III(eee, aaa, bbb, ccc, ddd, x[ 2], 11); | |
| /* parallel round 3 */ | |
| HHH(ddd, eee, aaa, bbb, ccc, x[15], 9); | |
| HHH(ccc, ddd, eee, aaa, bbb, x[ 5], 7); | |
| HHH(bbb, ccc, ddd, eee, aaa, x[ 1], 15); | |
| HHH(aaa, bbb, ccc, ddd, eee, x[ 3], 11); | |
| HHH(eee, aaa, bbb, ccc, ddd, x[ 7], 8); | |
| HHH(ddd, eee, aaa, bbb, ccc, x[14], 6); | |
| HHH(ccc, ddd, eee, aaa, bbb, x[ 6], 6); | |
| HHH(bbb, ccc, ddd, eee, aaa, x[ 9], 14); | |
| HHH(aaa, bbb, ccc, ddd, eee, x[11], 12); | |
| HHH(eee, aaa, bbb, ccc, ddd, x[ 8], 13); | |
| HHH(ddd, eee, aaa, bbb, ccc, x[12], 5); | |
| HHH(ccc, ddd, eee, aaa, bbb, x[ 2], 14); | |
| HHH(bbb, ccc, ddd, eee, aaa, x[10], 13); | |
| HHH(aaa, bbb, ccc, ddd, eee, x[ 0], 13); | |
| HHH(eee, aaa, bbb, ccc, ddd, x[ 4], 7); | |
| HHH(ddd, eee, aaa, bbb, ccc, x[13], 5); | |
| /* parallel round 4 */ | |
| GGG(ccc, ddd, eee, aaa, bbb, x[ 8], 15); | |
| GGG(bbb, ccc, ddd, eee, aaa, x[ 6], 5); | |
| GGG(aaa, bbb, ccc, ddd, eee, x[ 4], 8); | |
| GGG(eee, aaa, bbb, ccc, ddd, x[ 1], 11); | |
| GGG(ddd, eee, aaa, bbb, ccc, x[ 3], 14); | |
| GGG(ccc, ddd, eee, aaa, bbb, x[11], 14); | |
| GGG(bbb, ccc, ddd, eee, aaa, x[15], 6); | |
| GGG(aaa, bbb, ccc, ddd, eee, x[ 0], 14); | |
| GGG(eee, aaa, bbb, ccc, ddd, x[ 5], 6); | |
| GGG(ddd, eee, aaa, bbb, ccc, x[12], 9); | |
| GGG(ccc, ddd, eee, aaa, bbb, x[ 2], 12); | |
| GGG(bbb, ccc, ddd, eee, aaa, x[13], 9); | |
| GGG(aaa, bbb, ccc, ddd, eee, x[ 9], 12); | |
| GGG(eee, aaa, bbb, ccc, ddd, x[ 7], 5); | |
| GGG(ddd, eee, aaa, bbb, ccc, x[10], 15); | |
| GGG(ccc, ddd, eee, aaa, bbb, x[14], 8); | |
| /* parallel round 5 */ | |
| FFF(bbb, ccc, ddd, eee, aaa, x[12] , 8); | |
| FFF(aaa, bbb, ccc, ddd, eee, x[15] , 5); | |
| FFF(eee, aaa, bbb, ccc, ddd, x[10] , 12); | |
| FFF(ddd, eee, aaa, bbb, ccc, x[ 4] , 9); | |
| FFF(ccc, ddd, eee, aaa, bbb, x[ 1] , 12); | |
| FFF(bbb, ccc, ddd, eee, aaa, x[ 5] , 5); | |
| FFF(aaa, bbb, ccc, ddd, eee, x[ 8] , 14); | |
| FFF(eee, aaa, bbb, ccc, ddd, x[ 7] , 6); | |
| FFF(ddd, eee, aaa, bbb, ccc, x[ 6] , 8); | |
| FFF(ccc, ddd, eee, aaa, bbb, x[ 2] , 13); | |
| FFF(bbb, ccc, ddd, eee, aaa, x[13] , 6); | |
| FFF(aaa, bbb, ccc, ddd, eee, x[14] , 5); | |
| FFF(eee, aaa, bbb, ccc, ddd, x[ 0] , 15); | |
| FFF(ddd, eee, aaa, bbb, ccc, x[ 3] , 13); | |
| FFF(ccc, ddd, eee, aaa, bbb, x[ 9] , 11); | |
| FFF(bbb, ccc, ddd, eee, aaa, x[11] , 11); | |
| /* combine results */ | |
| ddd += cc + _state[1]; /* final result for _state[0] */ | |
| _state[1] = _state[2] + dd + eee; | |
| _state[2] = _state[3] + ee + aaa; | |
| _state[3] = _state[4] + aa + bbb; | |
| _state[4] = _state[0] + bb + ccc; | |
| _state[0] = ddd; | |
| //Zeroize sensitive information. | |
| x[] = 0; | |
| } | |
| public: | |
| enum blockSize = 512; | |
| /** | |
| * Use this to feed the digest with data. | |
| * Also implements the $(REF isOutputRange, std,range,primitives) | |
| * interface for `ubyte` and `const(ubyte)[]`. | |
| * | |
| * Example: | |
| * ---- | |
| * RIPEMD160 dig; | |
| * dig.put(cast(ubyte) 0); //single ubyte | |
| * dig.put(cast(ubyte) 0, cast(ubyte) 0); //variadic | |
| * ubyte[10] buf; | |
| * dig.put(buf); //buffer | |
| * ---- | |
| */ | |
| void put(scope const(ubyte)[] data...) @trusted pure nothrow @nogc | |
| { | |
| uint i, index, partLen; | |
| auto inputLen = data.length; | |
| //Compute number of bytes mod 64 | |
| index = (cast(uint)_count >> 3) & (64 - 1); | |
| //Update number of bits | |
| _count += inputLen * 8; | |
| partLen = 64 - index; | |
| //Transform as many times as possible | |
| if (inputLen >= partLen) | |
| { | |
| (&_buffer[index])[0 .. partLen] = data.ptr[0 .. partLen]; | |
| transform(&_buffer); | |
| for (i = partLen; i + 63 < inputLen; i += 64) | |
| { | |
| transform(cast(const(ubyte[64])*)(data[i .. i + 64].ptr)); | |
| } | |
| index = 0; | |
| } | |
| else | |
| { | |
| i = 0; | |
| } | |
| /* Buffer remaining input */ | |
| if (inputLen - i) | |
| (&_buffer[index])[0 .. inputLen-i] = (&data[i])[0 .. inputLen-i]; | |
| } | |
| /** | |
| * Used to (re)initialize the RIPEMD160 digest. | |
| * | |
| * Note: | |
| * For this RIPEMD160 Digest implementation calling start after default construction | |
| * is not necessary. Calling start is only necessary to reset the Digest. | |
| * | |
| * Generic code which deals with different Digest types should always call start though. | |
| * | |
| * Example: | |
| * -------- | |
| * RIPEMD160 digest; | |
| * //digest.start(); //Not necessary | |
| * digest.put(0); | |
| * -------- | |
| */ | |
| void start() @safe pure nothrow @nogc | |
| { | |
| this = RIPEMD160.init; | |
| } | |
| /** | |
| * Returns the finished RIPEMD160 hash. This also calls $(LREF start) to | |
| * reset the internal state. | |
| * | |
| * Example: | |
| * -------- | |
| * //Simple example | |
| * RIPEMD160 hash; | |
| * hash.start(); | |
| * hash.put(cast(ubyte) 0); | |
| * ubyte[20] result = hash.finish(); | |
| * assert(toHexString(result) == "C81B94933420221A7AC004A90242D8B1D3E5070D"); | |
| * -------- | |
| */ | |
| ubyte[20] finish() @trusted pure nothrow @nogc | |
| { | |
| import std.bitmanip : nativeToLittleEndian; | |
| ubyte[20] data = void; | |
| ubyte[8] bits = void; | |
| uint index, padLen; | |
| //Save number of bits | |
| bits[0 .. 8] = nativeToLittleEndian(_count)[]; | |
| //Pad out to 56 mod 64 | |
| index = (cast(uint)_count >> 3) & (64 - 1); | |
| padLen = (index < 56) ? (56 - index) : (120 - index); | |
| put(_padding[0 .. padLen]); | |
| //Append length (before padding) | |
| put(bits); | |
| //Store state in digest | |
| data[0 .. 4] = nativeToLittleEndian(_state[0])[]; | |
| data[4 .. 8] = nativeToLittleEndian(_state[1])[]; | |
| data[8 .. 12] = nativeToLittleEndian(_state[2])[]; | |
| data[12 .. 16] = nativeToLittleEndian(_state[3])[]; | |
| data[16 .. 20] = nativeToLittleEndian(_state[4])[]; | |
| /* Zeroize sensitive information. */ | |
| start(); | |
| return data; | |
| } | |
| } | |
| /// | |
| @safe unittest | |
| { | |
| //Simple example, hashing a string using ripemd160Of helper function | |
| ubyte[20] hash = ripemd160Of("abc"); | |
| //Let's get a hash string | |
| assert(toHexString(hash) == "8EB208F7E05D987A9B044A8E98C6B087F15A0BFC"); | |
| } | |
| /// | |
| @safe unittest | |
| { | |
| //Using the basic API | |
| RIPEMD160 hash; | |
| hash.start(); | |
| ubyte[1024] data; | |
| //Initialize data here... | |
| hash.put(data); | |
| ubyte[20] result = hash.finish(); | |
| } | |
| /// | |
| @safe unittest | |
| { | |
| //Let's use the template features: | |
| void doSomething(T)(ref T hash) | |
| if (isDigest!T) | |
| { | |
| hash.put(cast(ubyte) 0); | |
| } | |
| RIPEMD160 md; | |
| md.start(); | |
| doSomething(md); | |
| assert(toHexString(md.finish()) == "C81B94933420221A7AC004A90242D8B1D3E5070D"); | |
| } | |
| /// | |
| @safe unittest | |
| { | |
| //Simple example | |
| RIPEMD160 hash; | |
| hash.start(); | |
| hash.put(cast(ubyte) 0); | |
| ubyte[20] result = hash.finish(); | |
| assert(toHexString(result) == "C81B94933420221A7AC004A90242D8B1D3E5070D"); | |
| } | |
| @safe unittest | |
| { | |
| assert(isDigest!RIPEMD160); | |
| } | |
| @system unittest | |
| { | |
| import std.conv : hexString; | |
| import std.range; | |
| ubyte[20] digest; | |
| RIPEMD160 md; | |
| md.put(cast(ubyte[])"abcdef"); | |
| md.start(); | |
| md.put(cast(ubyte[])""); | |
| assert(md.finish() == cast(ubyte[]) hexString!"9c1185a5c5e9fc54612808977ee8f548b2258d31"); | |
| digest = ripemd160Of(""); | |
| assert(digest == cast(ubyte[]) hexString!"9c1185a5c5e9fc54612808977ee8f548b2258d31"); | |
| digest = ripemd160Of("a"); | |
| assert(digest == cast(ubyte[]) hexString!"0bdc9d2d256b3ee9daae347be6f4dc835a467ffe"); | |
| digest = ripemd160Of("abc"); | |
| assert(digest == cast(ubyte[]) hexString!"8eb208f7e05d987a9b044a8e98c6b087f15a0bfc"); | |
| digest = ripemd160Of("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"); | |
| assert(digest == cast(ubyte[]) hexString!"12a053384a9c0c88e405a06c27dcf49ada62eb2b"); | |
| digest = ripemd160Of("message digest"); | |
| assert(digest == cast(ubyte[]) hexString!"5d0689ef49d2fae572b881b123a85ffa21595f36"); | |
| digest = ripemd160Of("abcdefghijklmnopqrstuvwxyz"); | |
| assert(digest == cast(ubyte[]) hexString!"f71c27109c692c1b56bbdceb5b9d2865b3708dbc"); | |
| digest = ripemd160Of("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"); | |
| assert(digest == cast(ubyte[]) hexString!"b0e20b6e3116640286ed3a87a5713079b21f5189"); | |
| digest = ripemd160Of("1234567890123456789012345678901234567890"~ | |
| "1234567890123456789012345678901234567890"); | |
| assert(digest == cast(ubyte[]) hexString!"9b752e45573d4b39f4dbd3323cab82bf63326bfb"); | |
| enum ubyte[20] input = cast(ubyte[20]) hexString!"f71c27109c692c1b56bbdceb5b9d2865b3708dbc"; | |
| assert(toHexString(input) | |
| == "F71C27109C692C1B56BBDCEB5B9D2865B3708DBC"); | |
| ubyte[] onemilliona = new ubyte[1000000]; | |
| onemilliona[] = 'a'; | |
| digest = ripemd160Of(onemilliona); | |
| assert(digest == cast(ubyte[]) hexString!"52783243c1697bdbe16d37f97f68f08325dc1528"); | |
| auto oneMillionRange = repeat!ubyte(cast(ubyte)'a', 1000000); | |
| digest = ripemd160Of(oneMillionRange); | |
| assert(digest == cast(ubyte[]) hexString!"52783243c1697bdbe16d37f97f68f08325dc1528"); | |
| } | |
| /** | |
| * This is a convenience alias for $(REF digest, std,digest) using the | |
| * RIPEMD160 implementation. | |
| */ | |
| //simple alias doesn't work here, hope this gets inlined... | |
| auto ripemd160Of(T...)(T data) | |
| { | |
| return digest!(RIPEMD160, T)(data); | |
| } | |
| /// | |
| @safe unittest | |
| { | |
| ubyte[20] hash = ripemd160Of("abc"); | |
| assert(hash == digest!RIPEMD160("abc")); | |
| } | |
| /** | |
| * OOP API RIPEMD160 implementation. | |
| * See `std.digest` for differences between template and OOP API. | |
| * | |
| * This is an alias for $(D $(REF WrapperDigest, std,digest)!RIPEMD160), | |
| * see there for more information. | |
| */ | |
| alias RIPEMD160Digest = WrapperDigest!RIPEMD160; | |
| /// | |
| @safe unittest | |
| { | |
| //Simple example, hashing a string using Digest.digest helper function | |
| auto md = new RIPEMD160Digest(); | |
| ubyte[] hash = md.digest("abc"); | |
| //Let's get a hash string | |
| assert(toHexString(hash) == "8EB208F7E05D987A9B044A8E98C6B087F15A0BFC"); | |
| } | |
| /// | |
| @system unittest | |
| { | |
| //Let's use the OOP features: | |
| void test(Digest dig) | |
| { | |
| dig.put(cast(ubyte) 0); | |
| } | |
| auto md = new RIPEMD160Digest(); | |
| test(md); | |
| //Let's use a custom buffer: | |
| ubyte[20] buf; | |
| ubyte[] result = md.finish(buf[]); | |
| assert(toHexString(result) == "C81B94933420221A7AC004A90242D8B1D3E5070D"); | |
| } | |
| @system unittest | |
| { | |
| import std.conv : hexString; | |
| auto md = new RIPEMD160Digest(); | |
| md.put(cast(ubyte[])"abcdef"); | |
| md.reset(); | |
| md.put(cast(ubyte[])""); | |
| assert(md.finish() == cast(ubyte[]) hexString!"9c1185a5c5e9fc54612808977ee8f548b2258d31"); | |
| md.put(cast(ubyte[])"abcdefghijklmnopqrstuvwxyz"); | |
| ubyte[20] result; | |
| auto result2 = md.finish(result[]); | |
| assert(result[0 .. 20] == result2 && result2 == cast(ubyte[]) hexString!"f71c27109c692c1b56bbdceb5b9d2865b3708dbc"); | |
| debug | |
| { | |
| import std.exception; | |
| assertThrown!Error(md.finish(result[0 .. 19])); | |
| } | |
| assert(md.length == 20); | |
| assert(md.digest("") == cast(ubyte[]) hexString!"9c1185a5c5e9fc54612808977ee8f548b2258d31"); | |
| assert(md.digest("a") == cast(ubyte[]) hexString!"0bdc9d2d256b3ee9daae347be6f4dc835a467ffe"); | |
| assert(md.digest("abc") == cast(ubyte[]) hexString!"8eb208f7e05d987a9b044a8e98c6b087f15a0bfc"); | |
| assert(md.digest("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") | |
| == cast(ubyte[]) hexString!"12a053384a9c0c88e405a06c27dcf49ada62eb2b"); | |
| assert(md.digest("message digest") == cast(ubyte[]) hexString!"5d0689ef49d2fae572b881b123a85ffa21595f36"); | |
| assert(md.digest("abcdefghijklmnopqrstuvwxyz") | |
| == cast(ubyte[]) hexString!"f71c27109c692c1b56bbdceb5b9d2865b3708dbc"); | |
| assert(md.digest("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") | |
| == cast(ubyte[]) hexString!"b0e20b6e3116640286ed3a87a5713079b21f5189"); | |
| assert(md.digest("1234567890123456789012345678901234567890", | |
| "1234567890123456789012345678901234567890") | |
| == cast(ubyte[]) hexString!"9b752e45573d4b39f4dbd3323cab82bf63326bfb"); | |
| assert(md.digest(new ubyte[160/8]) // 160 zero bits | |
| == cast(ubyte[]) hexString!"5c00bd4aca04a9057c09b20b05f723f2e23deb65"); | |
| } |