RosettaCodeData/Task/SHA-256/D/sha-256-2.d
2015-02-20 00:35:01 -05:00

348 lines
13 KiB
D

// Copyright (C) 2005, 2006 Free Software Foundation, Inc. GNU License.
// Translated to D language. Only lightly tested, not for serious use.
import core.stdc.string: memcpy;
import core.bitop: bswap;
struct SHA256 {
enum uint BLOCK_SIZE = 4096;
static assert(BLOCK_SIZE % 64 == 0, "Invalid BLOCK_SIZE.");
uint[8] state;
uint[2] total;
uint bufLen;
union {
uint[32] buffer;
ubyte[buffer.sizeof] bufferB;
}
alias TResult = ubyte[256 / 8];
version(WORDS_BIGENDIAN) {
static uint bswap(in uint n) pure nothrow @safe @nogc { return n; }
}
// Bytes used to pad the buffer to the next 64-byte boundary.
static immutable ubyte[64] fillBuf = [0x80, 0 /* , 0, 0, ... */];
/** Initialize structure containing state of computation.
Takes a pointer to a 256 bit block of data (eight 32 bit ints) and
intializes it to the start constants of the SHA256 algorithm. This
must be called before using hash in the call to sha256_hash. */
void init() pure nothrow @safe @nogc {
state = [0x6a09e667U, 0xbb67ae85U, 0x3c6ef372U, 0xa54ff53aU,
0x510e527fU, 0x9b05688cU, 0x1f83d9abU, 0x5be0cd19U];
total[] = 0;
bufLen = 0;
}
/** Starting with the result of former calls of this function (or
the initialization function) update the context for the next LEN
bytes starting at BUFFER.
It is not required that LEN is a multiple of 64. */
void processBytes(in ubyte[] inBuffer) pure nothrow @nogc {
// When we already have some bits in our internal
// buffer concatenate both inputs first.
const(ubyte)* inBufferPtr = inBuffer.ptr;
auto len = inBuffer.length;
if (bufLen != 0) {
immutable size_t left_over = bufLen;
immutable size_t add = (128 - left_over > len) ?
len :
128 - left_over;
memcpy(&bufferB[left_over], inBufferPtr, add);
bufLen += add;
if (bufLen > 64) {
processBlock(bufferB[0 .. bufLen & ~63]);
bufLen &= 63;
// The regions in the following copy operation cannot overlap.
memcpy(bufferB.ptr, &bufferB[(left_over + add) & ~63], bufLen);
}
inBufferPtr += add;
len -= add;
}
// Process available complete blocks.
if (len >= 64) {
processBlock(inBufferPtr[0 .. len & ~63]);
inBufferPtr += (len & ~63);
len &= 63;
}
// Move remaining bytes in internal buffer.
if (len > 0) {
size_t left_over = bufLen;
memcpy(&bufferB[left_over], inBufferPtr, len);
left_over += len;
if (left_over >= 64) {
processBlock(bufferB[0 .. 64]);
left_over -= 64;
memcpy(bufferB.ptr, &bufferB[64], left_over);
}
bufLen = left_over;
}
}
/** Starting with the result of former calls of this function
(or the initialization function) update the context ctx for
the next len bytes starting at buffer.
It is necessary that len is a multiple of 64. */
void processBlock(in ubyte[] inBuffer)
pure nothrow @nogc in {
assert(inBuffer.length % 64 == 0);
} body {
// Round functions.
static uint F1(in uint e, in uint f, in uint g) pure nothrow @safe @nogc {
return g ^ (e & (f ^ g));
}
static uint F2(in uint a, in uint b, in uint c) pure nothrow @safe @nogc {
return (a & b) | (c & (a | b));
}
immutable len = inBuffer.length;
auto words = cast(uint*)inBuffer.ptr;
immutable size_t nWords = len / uint.sizeof;
const uint* endp = words + nWords;
uint[16] x = void;
auto a = state[0];
auto b = state[1];
auto c = state[2];
auto d = state[3];
auto e = state[4];
auto f = state[5];
auto g = state[6];
auto h = state[7];
// First increment the byte count. FIPS PUB 180-2 specifies the
// possible length of the file up to 2^64 bits. Here we only
// compute the number of bytes. Do a double word increment.
total[0] += len;
if (total[0] < len)
total[1]++;
static uint rol(in uint x, in uint n) pure nothrow @safe @nogc {
return (x << n) | (x >> (32 - n)); }
static uint S0(in uint x) pure nothrow @safe @nogc {
return rol(x, 25) ^ rol(x, 14) ^ (x >> 3); }
static uint S1(in uint x) pure nothrow @safe @nogc {
return rol(x, 15) ^ rol(x, 13) ^ (x >> 10); }
static uint SS0(in uint x) pure nothrow @safe @nogc {
return rol(x, 30) ^ rol(x,19) ^ rol(x, 10); }
static uint SS1(in uint x) pure nothrow @safe @nogc {
return rol(x, 26) ^ rol(x, 21) ^ rol(x, 7); }
uint M(in uint I) pure nothrow @safe @nogc {
immutable uint tm = S1(x[(I - 2) & 0x0f]) +
x[(I - 7) & 0x0f] +
S0(x[(I - 15) & 0x0f]) +
x[I & 0x0f];
x[I & 0x0f] = tm;
return tm;
}
static void R(in uint a, in uint b, in uint c, ref uint d,
in uint e, in uint f, in uint g, ref uint h,
in uint k, in uint m) pure nothrow @safe @nogc {
immutable t0 = SS0(a) + F2(a, b, c);
immutable t1 = h + SS1(e) + F1(e, f, g) + k + m;
d += t1;
h = t0 + t1;
}
// SHA256 round constants.
static immutable uint[64] K = [
0x428a2f98U, 0x71374491U, 0xb5c0fbcfU, 0xe9b5dba5U,
0x3956c25bU, 0x59f111f1U, 0x923f82a4U, 0xab1c5ed5U,
0xd807aa98U, 0x12835b01U, 0x243185beU, 0x550c7dc3U,
0x72be5d74U, 0x80deb1feU, 0x9bdc06a7U, 0xc19bf174U,
0xe49b69c1U, 0xefbe4786U, 0x0fc19dc6U, 0x240ca1ccU,
0x2de92c6fU, 0x4a7484aaU, 0x5cb0a9dcU, 0x76f988daU,
0x983e5152U, 0xa831c66dU, 0xb00327c8U, 0xbf597fc7U,
0xc6e00bf3U, 0xd5a79147U, 0x06ca6351U, 0x14292967U,
0x27b70a85U, 0x2e1b2138U, 0x4d2c6dfcU, 0x53380d13U,
0x650a7354U, 0x766a0abbU, 0x81c2c92eU, 0x92722c85U,
0xa2bfe8a1U, 0xa81a664bU, 0xc24b8b70U, 0xc76c51a3U,
0xd192e819U, 0xd6990624U, 0xf40e3585U, 0x106aa070U,
0x19a4c116U, 0x1e376c08U, 0x2748774cU, 0x34b0bcb5U,
0x391c0cb3U, 0x4ed8aa4aU, 0x5b9cca4fU, 0x682e6ff3U,
0x748f82eeU, 0x78a5636fU, 0x84c87814U, 0x8cc70208U,
0x90befffaU, 0xa4506cebU, 0xbef9a3f7U, 0xc67178f2U];
while (words < endp) {
foreach (ref xi; x) {
xi = bswap(*words);
words++;
}
R(a, b, c, d, e, f, g, h, K[ 0], x[ 0]);
R(h, a, b, c, d, e, f, g, K[ 1], x[ 1]);
R(g, h, a, b, c, d, e, f, K[ 2], x[ 2]);
R(f, g, h, a, b, c, d, e, K[ 3], x[ 3]);
R(e, f, g, h, a, b, c, d, K[ 4], x[ 4]);
R(d, e, f, g, h, a, b, c, K[ 5], x[ 5]);
R(c, d, e, f, g, h, a, b, K[ 6], x[ 6]);
R(b, c, d, e, f, g, h, a, K[ 7], x[ 7]);
R(a, b, c, d, e, f, g, h, K[ 8], x[ 8]);
R(h, a, b, c, d, e, f, g, K[ 9], x[ 9]);
R(g, h, a, b, c, d, e, f, K[10], x[10]);
R(f, g, h, a, b, c, d, e, K[11], x[11]);
R(e, f, g, h, a, b, c, d, K[12], x[12]);
R(d, e, f, g, h, a, b, c, K[13], x[13]);
R(c, d, e, f, g, h, a, b, K[14], x[14]);
R(b, c, d, e, f, g, h, a, K[15], x[15]);
R(a, b, c, d, e, f, g, h, K[16], M(16));
R(h, a, b, c, d, e, f, g, K[17], M(17));
R(g, h, a, b, c, d, e, f, K[18], M(18));
R(f, g, h, a, b, c, d, e, K[19], M(19));
R(e, f, g, h, a, b, c, d, K[20], M(20));
R(d, e, f, g, h, a, b, c, K[21], M(21));
R(c, d, e, f, g, h, a, b, K[22], M(22));
R(b, c, d, e, f, g, h, a, K[23], M(23));
R(a, b, c, d, e, f, g, h, K[24], M(24));
R(h, a, b, c, d, e, f, g, K[25], M(25));
R(g, h, a, b, c, d, e, f, K[26], M(26));
R(f, g, h, a, b, c, d, e, K[27], M(27));
R(e, f, g, h, a, b, c, d, K[28], M(28));
R(d, e, f, g, h, a, b, c, K[29], M(29));
R(c, d, e, f, g, h, a, b, K[30], M(30));
R(b, c, d, e, f, g, h, a, K[31], M(31));
R(a, b, c, d, e, f, g, h, K[32], M(32));
R(h, a, b, c, d, e, f, g, K[33], M(33));
R(g, h, a, b, c, d, e, f, K[34], M(34));
R(f, g, h, a, b, c, d, e, K[35], M(35));
R(e, f, g, h, a, b, c, d, K[36], M(36));
R(d, e, f, g, h, a, b, c, K[37], M(37));
R(c, d, e, f, g, h, a, b, K[38], M(38));
R(b, c, d, e, f, g, h, a, K[39], M(39));
R(a, b, c, d, e, f, g, h, K[40], M(40));
R(h, a, b, c, d, e, f, g, K[41], M(41));
R(g, h, a, b, c, d, e, f, K[42], M(42));
R(f, g, h, a, b, c, d, e, K[43], M(43));
R(e, f, g, h, a, b, c, d, K[44], M(44));
R(d, e, f, g, h, a, b, c, K[45], M(45));
R(c, d, e, f, g, h, a, b, K[46], M(46));
R(b, c, d, e, f, g, h, a, K[47], M(47));
R(a, b, c, d, e, f, g, h, K[48], M(48));
R(h, a, b, c, d, e, f, g, K[49], M(49));
R(g, h, a, b, c, d, e, f, K[50], M(50));
R(f, g, h, a, b, c, d, e, K[51], M(51));
R(e, f, g, h, a, b, c, d, K[52], M(52));
R(d, e, f, g, h, a, b, c, K[53], M(53));
R(c, d, e, f, g, h, a, b, K[54], M(54));
R(b, c, d, e, f, g, h, a, K[55], M(55));
R(a, b, c, d, e, f, g, h, K[56], M(56));
R(h, a, b, c, d, e, f, g, K[57], M(57));
R(g, h, a, b, c, d, e, f, K[58], M(58));
R(f, g, h, a, b, c, d, e, K[59], M(59));
R(e, f, g, h, a, b, c, d, K[60], M(60));
R(d, e, f, g, h, a, b, c, K[61], M(61));
R(c, d, e, f, g, h, a, b, K[62], M(62));
R(b, c, d, e, f, g, h, a, K[63], M(63));
a = state[0] += a;
b = state[1] += b;
c = state[2] += c;
d = state[3] += d;
e = state[4] += e;
f = state[5] += f;
g = state[6] += g;
h = state[7] += h;
}
}
/** Process the remaining bytes in the internal buffer and the
usual prolog according to the standard and write the result to
resBuf.
Important: On some systems it is required that resBuf is correctly
aligned for a 32-bit value. */
void conclude() pure nothrow @nogc {
// Take yet unprocessed bytes into account.
immutable bytes = bufLen;
immutable size_t size = (bytes < 56) ? 64 / 4 : 64 * 2 / 4;
// Now count remaining bytes.
total[0] += bytes;
if (total[0] < bytes)
total[1]++;
// Put the 64-bit file length in *bits* at the end of
// the buffer.
buffer[size - 2] = bswap((total[1] << 3) | (total[0] >> 29));
buffer[size - 1] = bswap(total[0] << 3);
memcpy(&bufferB[bytes], fillBuf.ptr, (size - 2) * 4 - bytes);
// Process last bytes.
processBlock(bufferB[0 .. size * 4]);
}
/** Put result from this in first 32 bytes following resBuf. The
result must be in little endian byte order.
Important: On some systems it is required that resBuf is correctly
aligned for a 32-bit value. */
ref TResult read(return ref TResult resBuf) pure nothrow @nogc {
foreach (immutable i, immutable s; state)
(cast(uint*)resBuf.ptr)[i] = bswap(s);
return resBuf;
}
/** Process the remaining bytes in the buffer and put result from
CTX in first 32 (28) bytes following resBuf. The result is always
in little endian byte order, so that a byte-wise output yields to
the wanted ASCII representation of the message digest.
Important: On some systems it is required that resBuf be correctly
aligned for a 32 bits value. */
ref TResult finish(return ref TResult resBuf) pure nothrow @nogc {
conclude;
return read(resBuf);
}
/** Compute SHA512 message digest for LEN bytes beginning at
buffer. The result is always in little endian byte order, so that
a byte-wise output yields to the wanted ASCII representation of
the message digest. */
static ref TResult digest(in ubyte[] inBuffer, return ref TResult resBuf)
pure nothrow @nogc {
SHA256 sha = void;
// Initialize the computation context.
sha.init;
// Process whole buffer but last len % 64 bytes.
sha.processBytes(inBuffer);
// Put result in desired memory area.
return sha.finish(resBuf);
}
/// ditto
static TResult digest(in ubyte[] inBuffer) pure nothrow @nogc {
align(4) TResult resBuf = void;
return digest(inBuffer, resBuf);
}
}
version (sha_256_main) {
void main() {
import std.stdio, std.string;
immutable data = "Rosetta code".representation;
writefln("%(%02x%)", SHA256.digest(data));
}
}