Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

std.util.digest.digest

Category Functions
Template API isDigest  digestType  ExampleDigest  calculateDigest 
OOP API Digest  calculateDigestOOP 
Helper functions digestToString 

This module describes the digest APIs used in phobos. All digests follow these APIs. Additionally, this module contains useful helper methods which can be used with any hash type.

APIs:
There are two APIs for digests: The template API and the OOP API. The template API uses structs and template helpers like isDigest. The OOP API implements digests as classes inheriting the Digest interface. All digests are named so that the template API struct is called "x" and the OOP API class is called "xDigest". For example we have MD5 <--> MD5Digest, CRC32 <--> CRC32Digest, etc.

The template API is slightly more efficient. It does not have to allocate memory dynamically, all memory is allocated on the stack. The OOP API has to allocate in the finish method if no buffer was provided. If you provide a buffer to the OOP APIs finish function, it doesn't allocate, but the Digest classes still have to be created using new which allocates them using the GC.

The OOP API is useful to change the hash function and/or hash backend at 'runtime'. The benefit here is that switching e.g Phobos MD5Digest and an OpenSSLMD5Digest implementation is ABI compatible.

Usually, if just one specific hash type and backend is needed, the template API is a good fit. In this simplest case, the template API can even be used without templates: Just use the "x" structs directly.

License:
Boost License 1.0

Source:
std/util/digest/digest.d

Examples:
 //Generating the hashes of a file using the template API
 import std.util.digest.crc, std.util.digest.sha, std.util.digest.md5;

 import std.stdio;

 void main(string[] args)
 {
     MD5 md5;
     SHA1 sha1;
     CRC32 crc32;

     md5.start();
     sha1.start();
     crc32.start();

     foreach (arg; args[1 .. $])
     {
         digestFile(md5, arg);
         digestFile(sha1, arg);
         digestFile(crc32, arg);
     }
 }

 // Digests a file and prints the result.
 void digestFile(Hash)(ref Hash hash, string filename) if(isDigest!Hash)
 {
     File file = File(filename);
     scope(exit) file.close();

     //As digests implement OutputRange, we could use std.algorithm.copy
     //Let's do it manually for now
     foreach (buffer; file.byChunk(4096 * 1024))
         hash.put(buffer);

     auto result = hash.finish();
     writefln("%s (%s) = %s", hash.stringof, filename, digestToString(result));
 }
 //The same using the OOP API
 import std.util.digest.crc, std.util.digest.sha, std.util.digest.md5;

 import std.stdio;

 void main(string[] args)
 {
     auto md5 = new MD5Digest();
     auto sha1 = new SHA1Digest();
     auto crc32 = new CRC32Digest();

     md5.start();
     sha1.start();
     crc32.start();

     foreach (arg; args[1 .. $])
     {
         digestFile(md5, arg);
         digestFile(sha1, arg);
         digestFile(crc32, arg);
     }
 }

 // Digests a file and prints the result.
 void digestFile(Digest hash, string filename)
 {
     File file = File(filename);
     scope(exit) file.close();

     //As digests implement OutputRange, we could use std.algorithm.copy
     //Let's do it manually for now
     foreach (buffer; file.byChunk(4096 * 1024))
         hash.put(buffer);

     auto result = hash.finish();
     writefln("%s (%s) = %s", typeid(hash).toString(), filename, digestToString(result));
 }

TODO:
Digesting single bits (as opposed to bytes) is not implemented. This will be done as another template constraint helper (hasBitDigesting!T) and an additional interface (BitDigest)

struct ExampleDigest;
This documents the general structure of a Digest in the template API. All digest implementations should implement the following members and therefore pass the isDigest test.

Note:
A digest must be a struct (value type) to pass the isDigest test.

@trusted void put(scope const(ubyte)[] data...);
Use this to feed the digest with data. Also implements the std.range.OutputRange interface for ubyte and const(ubyte)[]. The following usages of put must work for any type which passes isDigest:

Examples:
 ExampleDigest dig;
 dig.put(cast(ubyte)0); //single ubyte
 dig.put(cast(ubyte)0, cast(ubyte)0); //variadic
 ubyte[10] buf;
 dig.put(buf); //buffer

@trusted void start();
Used to initialize the digest.

@trusted void reset();
Resets the internal state of the digest.

Note:
finish calls this internally, so it's not necessary to call reset manually after a call to finish.

@trusted ubyte[16u] finish();
@trusted void finish(ref ubyte[16u] data);
A digest implementation must provide two finish functions: The first variant returns the result on the stack and is a useful convenience function. The second variant takes a reference to a buffer and updates the buffer in place.

Note:
The actual type returned by finish (variant 1) and accepted as an input buffer (variant 2) depends on the digest implementation. ubyte[16] is just used as an example. It is guaranteed that the type returned by variant 1 is the same as the type accepted by variant 2.

Use digestType to obtain the actual return type.

template isDigest(T)
Use this to check if a type is a digest. See ExampleDigest to see what a type must provide to pass this check.

Note:
This is very useful as a template constraint (see examples)

Examples:
 static assert(isDigest!ExampleDigest);
 void myFunction(T)() if(isDigest!T)
 {
     T dig;
     dig.start();
     auto result = dig.finish();
 }

BUGS:
Does not yet verify that put takes scope parameters.

template digestType(T)
Use this template to get the type which is returned by a digest's finish method.

Examples:
 assert(is(digestType!(ExampleDigest) == ubyte[16]));
 ExampleDigest dig;
 dig.start();
 digestType!ExampleDigest buf;
 dig.finish(buf);

digestType!(Hash) calculateDigest(Hash)(scope const(void[])[] data...);
This is a convenience funtion to calculate the hash of a value using the template API. Every hash passing the isDigest test can be used with this function.

Examples:
 import std.util.digest.md5, std.util.digest.sha, std.util.digest.crc;
 auto md5   = calculateDigest!MD5(  "The quick brown fox jumps over the lazy dog");
 auto sha1  = calculateDigest!SHA1( "The quick brown fox jumps over the lazy dog");
 auto crc32 = calculateDigest!CRC32("The quick brown fox jumps over the lazy dog");
 assert(digestToString(crc32) == "414FA339");
 //It's also possible to pass multiple values to this function:
 import std.util.digest.crc;;
 auto crc32 = calculateDigest!CRC32("The quick ", "brown ", "fox jumps over the lazy dog");
 assert(digestToString(crc32) == "414FA339");

abstract interface Digest;
The rest of the documentation now describes the OOP API. To understand when to use the template API and when to use the OOP API, see the module documentation at the top of this page.

The Digest interface is the base interface which is implemented by all digests.

abstract nothrow @trusted void put(scope const(ubyte)[] data...);
Use this to feed the digest with data. Also implements the std.range.OutputRange interface for ubyte and const(ubyte)[].

Examples:
 void test(Digest dig)
 {
     dig.put(cast(ubyte)0); //single ubyte
     dig.put(cast(ubyte)0, cast(ubyte)0); //variadic
     ubyte[10] buf;
     dig.put(buf); //buffer
 }

abstract nothrow @trusted void start();
Used to initialize the digest.

abstract nothrow @trusted void reset();
Resets the internal state of the digest.

Note:
finish calls this internally, so it's not necessary to call reset manually after a call to finish.

abstract const nothrow @property @trusted size_t length();
This is the length in bytes of the hash value which is returned by finish. It's also the required size of a buffer passed to finish.

abstract @trusted ubyte[] finish(scope ubyte[] buf = null);
The finish function returns the hash value. It takes an optional buffer to copy the data into. If a buffer is passed, it must have a length at least length bytes.

TODO:
How to check for buf.length? Using enforce, assert(so only checking in debug mode) or the tango way (silently allocate if buf is too small)?

@trusted ubyte[] calculateDigestOOP(Digest dig, scope const(void[])[] data...);
This is a convenience funtion to calculate the hash of a value using the OOP API. Every hash supporting the OOP API can be used with this function.

Examples:
 import std.util.digest.md5, std.util.digest.sha, std.util.digest.crc;
 auto md5   = calculateDigestOOP(new MD5Digest(),   "The quick brown fox jumps over the lazy dog");
 auto sha1  = calculateDigestOOP(new SHA1Digest(),  "The quick brown fox jumps over the lazy dog");
 auto crc32 = calculateDigestOOP(new CRC32Digest(), "The quick brown fox jumps over the lazy dog");
 assert(digestToString(crc32) == "414FA339");
 //It's also possible to pass multiple values to this function:
 import std.util.digest.crc;;
 auto crc32 = calculateDigestOOP(new CRC32Digest(), "The quick ", "brown ", "fox jumps over the lazy dog");
 assert(digestToString(crc32) == "414FA339");

string digestToString(size_t num)(in ubyte[num] digest);
string digestToString()(in ubyte[] digest);
Used to convert a hash value (a static or dynamic array of ubytes) to a string. Can be used with the OOP and with the template API.

Examples:
 //With template API:
 auto crc32 = calculateDigest!CRC32("The quick ", "brown ", "fox jumps over the lazy dog");
 assert(digestToString(crc32) == "414FA339");
 //With OOP API:
 auto crc32 = calculateDigestOOP(new CRC32Digest(), "The quick ", "brown ", "fox jumps over the lazy dog");
 assert(digestToString(crc32) == "414FA339");