D Programming Language 2.0

# std.digest.digest

Category | Functions
--- | ---
Template API | isDigest DigestType hasPeek ExampleDigest digest hexDigest makeDigest
OOP API | Digest
Helper functions | toHexString
Implementation helpers | digestLength WrapperDigest

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 every digest 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 digest function and/or digest backend at 'runtime'. The benefit here is that switching e.g. Phobos MD5Digest and an OpenSSLMD5Digest implementation is ABI compatible.

If just one specific digest type and backend is needed, the template API is usually 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

Authors:
Johannes Pfau

Source:
std/digest/digest.d

CTFE:
Digests do not work in CTFE

Examples:

    import std.digest.crc;

    //Simple example
    char[8] hexHash = hexDigest!CRC32("The quick brown fox jumps over the lazy dog");
    assert(hexHash == "39A34F41");

    //Simple example, using the API manually
    CRC32 context = makeDigest!CRC32();
    context.put(cast(ubyte[])"The quick brown fox jumps over the lazy dog");
    ubyte[4] hash = context.finish();
    assert(toHexString(hash) == "39A34F41");

    //Generating the hashes of a file, idiomatic D way
    import std.digest.crc, std.digest.sha, std.digest.md;
    import std.stdio;

    // Digests a file and prints the result.
    void digestFile(Hash)(string filename) if(isDigest!Hash)
    {
        auto file = File(filename);
        auto result = digest!Hash(file.byChunk(4096 * 1024));
        writefln("%s (%s) = %s", Hash.stringof, filename, toHexString(result));
    }

    void main(string[] args)
    {
        foreach (name; args[1 .. $])
        {
            digestFile!MD5(name);
            digestFile!SHA1(name);
            digestFile!CRC32(name);
        }
    }

    //Generating the hashes of a file using the template API, old school way
    import std.digest.crc, std.digest.sha, std.digest.md;
    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);

        //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, toHexString(result));
    }

    //The same using the OOP API
    import std.digest.crc, std.digest.sha, std.digest.md;
    import std.stdio;

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

        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);

        //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);

        ubyte[] result = hash.finish();
        writefln("%s (%s) = %s", typeid(hash).toString(), filename, toHexString(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.
  - A digest passing the isDigest test is always an OutputRange

  Examples:

      //Using the OutputRange feature
      import std.algorithm : copy;
      import std.range : repeat;
      import std.digest.md;

      auto oneMillionRange = repeat!ubyte(cast(ubyte)'a', 1000000);
      auto ctx = makeDigest!MD5();
      copy(oneMillionRange, &ctx); //Note: You must pass a pointer to copy!
      assert(ctx.finish().toHexString() == "7707D6AE4E027C70EEA2A935C2296F21");

  @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();
    This function is used to (re)initialize the digest. It must be called before using the digest and it also works as a 'reset' function if the digest has already processed data.

  @trusted ubyte[16] finish();
    The finish function returns the final hash sum and resets the Digest.

    Note:
    The actual type returned by finish depends on the digest implementation. ubyte[16] is just used as an example. It is guaranteed that the type is a static array of ubytes.

    - Use DigestType to obtain the actual return type.
    - Use digestLength to obtain the length of the ubyte array.

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:

      import std.digest.crc;
      static assert(isDigest!CRC32);

      void myFunction(T)() if(isDigest!T)
      {
          T dig;
          dig.start();
          auto result = dig.finish();
      }

  BUGS:
  - Does not yet verify that put takes scope parameters.
  - Should check that finish() returns a ubyte[num] array

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

  Examples:

      import std.digest.crc;
      assert(is(DigestType!(CRC32) == ubyte[4]));

      import std.digest.crc;
      CRC32 dig;
      dig.start();
      DigestType!CRC32 result = dig.finish();

template hasPeek(T)
  Used to check if a digest supports the peek method. Peek has exactly the same function signatures as finish, but it doesn't reset the digest's internal state.

  Note:
  - This is very useful as a template constraint (see examples)
  - This also checks if T passes isDigest

  Examples:

      import std.digest.crc, std.digest.md;
      assert(!hasPeek!(MD5));
      assert(hasPeek!CRC32);

      void myFunction(T)() if(hasPeek!T)
      {
          T dig;
          dig.start();
          auto result = dig.peek();
      }

DigestType!(Hash) digest(Hash, Range)(auto ref Range range);
  This is a convenience function to calculate a hash using the template API. Every digest passing the isDigest test can be used with this function.

  Parameters:

  range | an InputRange with ElementType ubyte, ubyte[] or ubyte[num]

  Examples:

      import std.digest.md;
      auto testRange = repeat!ubyte(cast(ubyte)'a', 100);
      auto md5 = digest!MD5(testRange);

DigestType!(Hash) digest(Hash, T...)(scope const T data);
  This overload of the digest function handles arrays.

  Parameters:

  data | one or more arrays of any type

  Examples:

      import std.digest.md, std.digest.sha, std.digest.crc;
      auto md5   = digest!MD5(  "The quick brown fox jumps over the lazy dog");
      auto sha1  = digest!SHA1( "The quick brown fox jumps over the lazy dog");
      auto crc32 = digest!CRC32("The quick brown fox jumps over the lazy dog");
      assert(toHexString(crc32) == "39A34F41");

      //It's also possible to pass multiple values to this function:
      import std.digest.crc;
      auto crc32 = digest!CRC32("The quick ", "brown ", "fox jumps over the lazy dog");
      assert(toHexString(crc32) == "39A34F41");

char[digestLength!(Hash) * 2] hexDigest(Hash, Order order = Order.increasing, Range)(ref Range range);
  This is a convenience function similar to digest, but it returns the string representation of the hash. Every digest passing the isDigest test can be used with this function.

  Parameters:

  Order | the order in which the bytes are processed (see toHexString)
  range | an InputRange with ElementType ubyte, ubyte[] or ubyte[num]

  Examples:

      import std.digest.md;
      auto testRange = repeat!ubyte(cast(ubyte)'a', 100);
      assert(hexDigest!MD5(testRange) == "36A92CC94A9E0FA21F625F8BFB007ADF");

char[digestLength!(Hash) * 2] hexDigest(Hash, Order order = Order.increasing, T...)(scope const T data);
  This overload of the hexDigest function handles arrays.

  Parameters:

  Order | the order in which the bytes are processed (see toHexString)
  data | one or more arrays of any type

  Examples:

      import std.digest.crc;
      assert(hexDigest!(CRC32, Order.decreasing)("The quick brown fox jumps over the lazy dog") == "414FA339");

      //It's also possible to pass multiple values to this function:
      import std.digest.crc;
      assert(hexDigest!(CRC32, Order.decreasing)("The quick ", "brown ", "fox jumps over the lazy dog") == "414FA339");

Hash makeDigest(Hash)();
  This is a convenience function which returns an initialized digest, so it's not necessary to call start manually.

  Examples:

      import std.digest.md;
      auto md5 = makeDigest!MD5();
      md5.put("Hello");
      assert(toHexString(md5.finish()) == "93B885ADFE0DA089CDF634904FD59F71");

abstract interface Digest;
  This 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.

  Note:
  A Digest implementation is always an OutputRange

  Examples:

      //Using the OutputRange feature
      import std.algorithm : copy;
      import std.range : repeat;
      import std.digest.md;

      auto oneMillionRange = repeat!ubyte(cast(ubyte)'a', 1000000);
      auto ctx = new MD5Digest();
      copy(oneMillionRange, ctx);
      assert(ctx.finish().toHexString() == "7707D6AE4E027C70EEA2A935C2296F21");

  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 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 nothrow @trusted ubyte[] finish();
  abstract nothrow ubyte[] finish(scope ubyte[] buf);
    The finish function returns the hash value. It takes an optional buffer to copy the data into. If a buffer is passed, it must be at least length bytes big.

  final nothrow @trusted ubyte[] digest(scope const(void[])[] data...);
    This is a convenience function to calculate the hash of a value using the OOP API.

    Examples:

        import std.digest.md, std.digest.sha, std.digest.crc;
        ubyte[] md5   = (new MD5Digest()).digest("The quick brown fox jumps over the lazy dog");
        ubyte[] sha1  = (new SHA1Digest()).digest("The quick brown fox jumps over the lazy dog");
        ubyte[] crc32 = (new CRC32Digest()).digest("The quick brown fox jumps over the lazy dog");
        assert(crcHexString(crc32) == "414FA339");

        //It's also possible to pass multiple values to this function:
        import std.digest.crc;
        ubyte[] crc32 = (new CRC32Digest()).digest("The quick ", "brown ", "fox jumps over the lazy dog");
        assert(crcHexString(crc32) == "414FA339");

enum Order;
  See toHexString

  increasing

  decreasing

char[num * 2] toHexString(Order order = Order.increasing, size_t num)(in ubyte[num] digest);
string toHexString(Order order = Order.increasing)(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.

  The additional order parameter can be used to specify the order of the input data. By default the data is processed in increasing order, starting at index 0. To process it in the opposite order, pass Order.decreasing as a parameter.

  Examples:

      //With template API:
      auto crc32 = digest!CRC32("The quick ", "brown ", "fox jumps over the lazy dog");
      assert(toHexString(crc32) == "39A34F41");

      //Usually CRCs are printed in this order, though:
      auto crc32 = digest!CRC32("The quick ", "brown ", "fox jumps over the lazy dog");
      assert(toHexString!(Order.decreasing)(crc32) == "414FA339");

      //With OOP API:
      auto crc32 = (new CRC32Digest()).digest("The quick ", "brown ", "fox jumps over the lazy dog");
      assert(toHexString(crc32) == "39A34F41");

      //Usually CRCs are printed in this order, though:
      auto crc32 = (new CRC32Digest()).digest("The quick ", "brown ", "fox jumps over the lazy dog");
      assert(toHexString!(Order.decreasing)(crc32) == "414FA339");

template digestLength(T) if (isDigest!(T))
  This helper is used internally in the WrapperDigest template, but it might be useful for other purposes as well. It returns the length (in bytes) of the hash value produced by T.

class WrapperDigest(T) if (isDigest!(T)): Digest;
  Wraps a template API hash struct into a Digest interface. Modules providing digest implementations will usually provide an alias for this template (e.g. MD5Digest, SHA1Digest, ...).

  this();
    Initializes the digest.

  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
        }

  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.

  const pure 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.

  ubyte[] finish(scope ubyte[] buf);
  ubyte[] finish();
    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.

    Examples:

        //Simple example
        import std.digest.md;
        auto hash = new WrapperDigest!MD5();
        hash.put(cast(ubyte)0);
        auto result = hash.finish();

        //using a supplied buffer
        import std.digest.md;
        ubyte[16] buf;
        auto hash = new WrapperDigest!MD5();
        hash.put(cast(ubyte)0);
        auto result = hash.finish(buf[]);
        //The result is now in result (and in buf). If you pass a buffer which is bigger than
        //necessary, result will have the correct length, but buf will still have it's original
        //length

  const ubyte[] peek(scope ubyte[] buf);
  const ubyte[] peek();
    Works like finish but does not reset the internal state, so it's possible to continue putting data into this WrapperDigest after a call to peek.

    These functions are only available if hasPeek!T is true.

Copyright © 1999-2013 by Digital Mars, All Rights Reserved | Page generated by Ddoc.