/** * 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 $(D 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(); } //rotateLeft rotates x left n bits private uint rotateLeft(uint x, uint n) @safe pure nothrow @nogc { // With recently added optimization to DMD (commit 32ea0206 at 07/28/11), this is translated to rol. // No assembler required. return (x << n) | (x >> (32-n)); } /** * Template API RIPEMD160 implementation. * See $(D std.digest) for differences between template and OOP API. */ struct RIPEMD160 { 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 = rotateLeft(a, s) + e; c = rotateLeft(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 = rotateLeft(a, s) + e; c = rotateLeft(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 = rotateLeft(a, s) + e; c = rotateLeft(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 = rotateLeft(a, s) + e; c = rotateLeft(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 = rotateLeft(a, s) + e; c = rotateLeft(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 = rotateLeft(a, s) + e; c = rotateLeft(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 = rotateLeft(a, s) + e; c = rotateLeft(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 = rotateLeft(a, s) + e; c = rotateLeft(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 = rotateLeft(a, s) + e; c = rotateLeft(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 = rotateLeft(a, s) + e; c = rotateLeft(c, 10); } /* * RIPEMD160 basic transformation. Transforms state based on block. */ private 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 $(D ubyte) and $(D 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.range; ubyte[20] digest; RIPEMD160 md; md.put(cast(ubyte[])"abcdef"); md.start(); md.put(cast(ubyte[])""); assert(md.finish() == cast(ubyte[]) x"9c1185a5c5e9fc54612808977ee8f548b2258d31"); digest = ripemd160Of(""); assert(digest == cast(ubyte[]) x"9c1185a5c5e9fc54612808977ee8f548b2258d31"); digest = ripemd160Of("a"); assert(digest == cast(ubyte[]) x"0bdc9d2d256b3ee9daae347be6f4dc835a467ffe"); digest = ripemd160Of("abc"); assert(digest == cast(ubyte[]) x"8eb208f7e05d987a9b044a8e98c6b087f15a0bfc"); digest = ripemd160Of("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"); assert(digest == cast(ubyte[]) x"12a053384a9c0c88e405a06c27dcf49ada62eb2b"); digest = ripemd160Of("message digest"); assert(digest == cast(ubyte[]) x"5d0689ef49d2fae572b881b123a85ffa21595f36"); digest = ripemd160Of("abcdefghijklmnopqrstuvwxyz"); assert(digest == cast(ubyte[]) x"f71c27109c692c1b56bbdceb5b9d2865b3708dbc"); digest = ripemd160Of("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"); assert(digest == cast(ubyte[]) x"b0e20b6e3116640286ed3a87a5713079b21f5189"); digest = ripemd160Of("1234567890123456789012345678901234567890"~ "1234567890123456789012345678901234567890"); assert(digest == cast(ubyte[]) x"9b752e45573d4b39f4dbd3323cab82bf63326bfb"); assert(toHexString(cast(ubyte[20]) x"f71c27109c692c1b56bbdceb5b9d2865b3708dbc") == "F71C27109C692C1B56BBDCEB5B9D2865B3708DBC"); ubyte[] onemilliona = new ubyte[1000000]; onemilliona[] = 'a'; digest = ripemd160Of(onemilliona); assert(digest == cast(ubyte[]) x"52783243c1697bdbe16d37f97f68f08325dc1528"); auto oneMillionRange = repeat!ubyte(cast(ubyte)'a', 1000000); digest = ripemd160Of(oneMillionRange); assert(digest == cast(ubyte[]) x"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 $(D 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 { auto md = new RIPEMD160Digest(); md.put(cast(ubyte[])"abcdef"); md.reset(); md.put(cast(ubyte[])""); assert(md.finish() == cast(ubyte[]) x"9c1185a5c5e9fc54612808977ee8f548b2258d31"); md.put(cast(ubyte[])"abcdefghijklmnopqrstuvwxyz"); ubyte[20] result; auto result2 = md.finish(result[]); assert(result[0 .. 20] == result2 && result2 == cast(ubyte[]) x"f71c27109c692c1b56bbdceb5b9d2865b3708dbc"); debug { import std.exception; assertThrown!Error(md.finish(result[0 .. 19])); } assert(md.length == 20); assert(md.digest("") == cast(ubyte[]) x"9c1185a5c5e9fc54612808977ee8f548b2258d31"); assert(md.digest("a") == cast(ubyte[]) x"0bdc9d2d256b3ee9daae347be6f4dc835a467ffe"); assert(md.digest("abc") == cast(ubyte[]) x"8eb208f7e05d987a9b044a8e98c6b087f15a0bfc"); assert(md.digest("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") == cast(ubyte[]) x"12a053384a9c0c88e405a06c27dcf49ada62eb2b"); assert(md.digest("message digest") == cast(ubyte[]) x"5d0689ef49d2fae572b881b123a85ffa21595f36"); assert(md.digest("abcdefghijklmnopqrstuvwxyz") == cast(ubyte[]) x"f71c27109c692c1b56bbdceb5b9d2865b3708dbc"); assert(md.digest("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") == cast(ubyte[]) x"b0e20b6e3116640286ed3a87a5713079b21f5189"); assert(md.digest("1234567890123456789012345678901234567890", "1234567890123456789012345678901234567890") == cast(ubyte[]) x"9b752e45573d4b39f4dbd3323cab82bf63326bfb"); assert(md.digest(new ubyte[160/8]) // 160 zero bits == cast(ubyte[]) x"5c00bd4aca04a9057c09b20b05f723f2e23deb65"); }