I'm not familiar with hash functions in general. I think the core of std.hash is the digest function:
digestType!Hash digest(Hash)(scope const(void[])[] data...) if(isDigest!Hash) { Hash hash; hash.start(); foreach(datum; data) hash.put(cast(const(ubyte[]))datum); return hash.finish(); } That seems to be too restrictive: you can only provide a void[][] or one or several void[], but you should be able to give it any range of void[] or of ubyte[] like: auto dig = file.byChunk.digest!MD5; That's the point of the range interface. this can be done by templatizing the function, something like (untested): template digest(Hash) if(isDigest!Hash) { auto digest(R)(R data) if (isInputRange!R && is(ElementType!R : void[]) { Hash hash; hash.start(); data.copy(hash); return hash.finish(); } } An interesting overload for range of single ubyte could be provided. This overload would fill a buffer of with data from this range, feed the hash, and start again.