Skip to content

Instantly share code, notes, and snippets.

@Infarh
Created December 13, 2022 08:19
Show Gist options
  • Save Infarh/7569103b56758771ba4357544768ddb0 to your computer and use it in GitHub Desktop.
Save Infarh/7569103b56758771ba4357544768ddb0 to your computer and use it in GitHub Desktop.
Hash
public class MD5
{
private MD5() { }
public static byte[] Compute(string str, Encoding? encoding = null) => Compute((encoding ?? Encoding.UTF8).GetBytes(str));
private static void SetLength(byte[] buffer64, ulong length)
{
buffer64[^8] = (byte)(length << 3);
buffer64[^7] = (byte)(length >> 5);
buffer64[^6] = (byte)(length >> 13);
buffer64[^5] = (byte)(length >> 21);
buffer64[^4] = (byte)(length >> 29);
buffer64[^3] = (byte)(length >> 37);
buffer64[^2] = (byte)(length >> 45);
buffer64[^1] = (byte)(length >> 53);
}
public static byte[] Compute(byte[] data)
{
uint[] h = { 0x67452301U, 0xefcdab89U, 0x98badcfeU, 0x10325476U };
const int length_0x80 = 1;
const int length_end = 8;
var length = data.Length;
var zero_length = 64 - length % 64 - length_0x80 - length_end;
if (zero_length < 0) zero_length += 64;
var buffer64_length = length + length_0x80 + zero_length + length_end;
var buffer64 = new byte[buffer64_length];
Array.Copy(data, buffer64, length);
buffer64[length] = 0x80;
SetLength(buffer64, (ulong)length);
var words = new uint[16];
for (var i = 0; i < buffer64_length / 64; i++)
{
Buffer.BlockCopy(buffer64, i * 64, words, 0, 64);
Compute(words, ref h[0], ref h[1], ref h[2], ref h[3]);
}
var result_bytes = new byte[16];
Buffer.BlockCopy(h, 0, result_bytes, 0, result_bytes.Length);
return result_bytes;
}
public static byte[] Compute(Stream data)
{
uint[] result = { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476 };
var buffer64 = new byte[64];
var words = new uint[16];
var completed = false;
var length = 0UL;
int readed;
do
{
readed = data.FillBuffer(buffer64);
length += (ulong)readed;
if (readed < 64)
{
Array.Clear(buffer64, readed, 64 - readed);
buffer64[readed] = 0x80;
if (64 - readed > 8)
{
SetLength(buffer64, length);
completed = true;
}
}
Buffer.BlockCopy(buffer64, 0, words, 0, 64);
Compute(words, ref result[0], ref result[1], ref result[2], ref result[3]);
}
while (readed == 64);
if (readed > 0 && !completed)
{
Array.Clear(buffer64, 0, 64);
SetLength(buffer64, length);
Buffer.BlockCopy(buffer64, 0, words, 0, 64);
Compute(words, ref result[0], ref result[1], ref result[2], ref result[3]);
}
var result_bytes = new byte[16];
Buffer.BlockCopy(result, 0, result_bytes, 0, result_bytes.Length);
return result_bytes;
}
public static async Task<byte[]> ComputeAsync(Stream data, CancellationToken Cancel = default)
{
uint[] result = { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476 };
var buffer64 = new byte[64];
var words = new uint[16];
var completed = false;
var length = 0UL;
int readed;
do
{
readed = await data.FillBufferAsync(buffer64, Cancel).ConfigureAwait(false);
length += (ulong)readed;
if (readed < 64)
{
Array.Clear(buffer64, readed, 64 - readed);
buffer64[readed] = 0x80;
if (64 - readed > 8)
{
SetLength(buffer64, length);
completed = true;
}
}
Buffer.BlockCopy(buffer64, 0, words, 0, 64);
Compute(words, ref result[0], ref result[1], ref result[2], ref result[3]);
}
while (readed == 64);
if (readed > 0 && !completed)
{
Array.Clear(buffer64, 0, 64);
SetLength(buffer64, length);
Buffer.BlockCopy(buffer64, 0, words, 0, 64);
Compute(words, ref result[0], ref result[1], ref result[2], ref result[3]);
}
var result_bytes = new byte[16];
Buffer.BlockCopy(result, 0, result_bytes, 0, result_bytes.Length);
return result_bytes;
}
private static void Compute(uint[] buffer16, ref uint a0, ref uint b0, ref uint c0, ref uint d0)
{
var (A, B, C, D) = (a0, b0, c0, d0);
static uint LeftRotate(uint x, int c) => (x << c) | (x >> (32 - c));
(A, B, C, D) = (D, B + LeftRotate(A + (B & C | ~B & D) + 0xd76aa478 + buffer16[00], 07), B, C);
(A, B, C, D) = (D, B + LeftRotate(A + (B & C | ~B & D) + 0xe8c7b756 + buffer16[01], 12), B, C);
(A, B, C, D) = (D, B + LeftRotate(A + (B & C | ~B & D) + 0x242070db + buffer16[02], 17), B, C);
(A, B, C, D) = (D, B + LeftRotate(A + (B & C | ~B & D) + 0xc1bdceee + buffer16[03], 22), B, C);
(A, B, C, D) = (D, B + LeftRotate(A + (B & C | ~B & D) + 0xf57c0faf + buffer16[04], 07), B, C);
(A, B, C, D) = (D, B + LeftRotate(A + (B & C | ~B & D) + 0x4787c62a + buffer16[05], 12), B, C);
(A, B, C, D) = (D, B + LeftRotate(A + (B & C | ~B & D) + 0xa8304613 + buffer16[06], 17), B, C);
(A, B, C, D) = (D, B + LeftRotate(A + (B & C | ~B & D) + 0xfd469501 + buffer16[07], 22), B, C);
(A, B, C, D) = (D, B + LeftRotate(A + (B & C | ~B & D) + 0x698098d8 + buffer16[08], 07), B, C);
(A, B, C, D) = (D, B + LeftRotate(A + (B & C | ~B & D) + 0x8b44f7af + buffer16[09], 12), B, C);
(A, B, C, D) = (D, B + LeftRotate(A + (B & C | ~B & D) + 0xffff5bb1 + buffer16[10], 17), B, C);
(A, B, C, D) = (D, B + LeftRotate(A + (B & C | ~B & D) + 0x895cd7be + buffer16[11], 22), B, C);
(A, B, C, D) = (D, B + LeftRotate(A + (B & C | ~B & D) + 0x6b901122 + buffer16[12], 07), B, C);
(A, B, C, D) = (D, B + LeftRotate(A + (B & C | ~B & D) + 0xfd987193 + buffer16[13], 12), B, C);
(A, B, C, D) = (D, B + LeftRotate(A + (B & C | ~B & D) + 0xa679438e + buffer16[14], 17), B, C);
(A, B, C, D) = (D, B + LeftRotate(A + (B & C | ~B & D) + 0x49b40821 + buffer16[15], 22), B, C);
(A, B, C, D) = (D, B + LeftRotate(A + (D & B | ~D & C) + 0xf61e2562 + buffer16[(5 * 16 + 1) % 16], 05), B, C);
(A, B, C, D) = (D, B + LeftRotate(A + (D & B | ~D & C) + 0xc040b340 + buffer16[(5 * 17 + 1) % 16], 09), B, C);
(A, B, C, D) = (D, B + LeftRotate(A + (D & B | ~D & C) + 0x265e5a51 + buffer16[(5 * 18 + 1) % 16], 14), B, C);
(A, B, C, D) = (D, B + LeftRotate(A + (D & B | ~D & C) + 0xe9b6c7aa + buffer16[(5 * 19 + 1) % 16], 20), B, C);
(A, B, C, D) = (D, B + LeftRotate(A + (D & B | ~D & C) + 0xd62f105d + buffer16[(5 * 20 + 1) % 16], 05), B, C);
(A, B, C, D) = (D, B + LeftRotate(A + (D & B | ~D & C) + 0x02441453 + buffer16[(5 * 21 + 1) % 16], 09), B, C);
(A, B, C, D) = (D, B + LeftRotate(A + (D & B | ~D & C) + 0xd8a1e681 + buffer16[(5 * 22 + 1) % 16], 14), B, C);
(A, B, C, D) = (D, B + LeftRotate(A + (D & B | ~D & C) + 0xe7d3fbc8 + buffer16[(5 * 23 + 1) % 16], 20), B, C);
(A, B, C, D) = (D, B + LeftRotate(A + (D & B | ~D & C) + 0x21e1cde6 + buffer16[(5 * 24 + 1) % 16], 05), B, C);
(A, B, C, D) = (D, B + LeftRotate(A + (D & B | ~D & C) + 0xc33707d6 + buffer16[(5 * 25 + 1) % 16], 09), B, C);
(A, B, C, D) = (D, B + LeftRotate(A + (D & B | ~D & C) + 0xf4d50d87 + buffer16[(5 * 26 + 1) % 16], 14), B, C);
(A, B, C, D) = (D, B + LeftRotate(A + (D & B | ~D & C) + 0x455a14ed + buffer16[(5 * 27 + 1) % 16], 20), B, C);
(A, B, C, D) = (D, B + LeftRotate(A + (D & B | ~D & C) + 0xa9e3e905 + buffer16[(5 * 28 + 1) % 16], 05), B, C);
(A, B, C, D) = (D, B + LeftRotate(A + (D & B | ~D & C) + 0xfcefa3f8 + buffer16[(5 * 29 + 1) % 16], 09), B, C);
(A, B, C, D) = (D, B + LeftRotate(A + (D & B | ~D & C) + 0x676f02d9 + buffer16[(5 * 30 + 1) % 16], 14), B, C);
(A, B, C, D) = (D, B + LeftRotate(A + (D & B | ~D & C) + 0x8d2a4c8a + buffer16[(5 * 31 + 1) % 16], 20), B, C);
(A, B, C, D) = (D, B + LeftRotate(A + (B ^ C ^ D) + 0xfffa3942 + buffer16[(3 * 32 + 5) % 16], 04), B, C);
(A, B, C, D) = (D, B + LeftRotate(A + (B ^ C ^ D) + 0x8771f681 + buffer16[(3 * 33 + 5) % 16], 11), B, C);
(A, B, C, D) = (D, B + LeftRotate(A + (B ^ C ^ D) + 0x6d9d6122 + buffer16[(3 * 34 + 5) % 16], 16), B, C);
(A, B, C, D) = (D, B + LeftRotate(A + (B ^ C ^ D) + 0xfde5380c + buffer16[(3 * 35 + 5) % 16], 23), B, C);
(A, B, C, D) = (D, B + LeftRotate(A + (B ^ C ^ D) + 0xa4beea44 + buffer16[(3 * 36 + 5) % 16], 04), B, C);
(A, B, C, D) = (D, B + LeftRotate(A + (B ^ C ^ D) + 0x4bdecfa9 + buffer16[(3 * 37 + 5) % 16], 11), B, C);
(A, B, C, D) = (D, B + LeftRotate(A + (B ^ C ^ D) + 0xf6bb4b60 + buffer16[(3 * 38 + 5) % 16], 16), B, C);
(A, B, C, D) = (D, B + LeftRotate(A + (B ^ C ^ D) + 0xbebfbc70 + buffer16[(3 * 39 + 5) % 16], 23), B, C);
(A, B, C, D) = (D, B + LeftRotate(A + (B ^ C ^ D) + 0x289b7ec6 + buffer16[(3 * 40 + 5) % 16], 04), B, C);
(A, B, C, D) = (D, B + LeftRotate(A + (B ^ C ^ D) + 0xeaa127fa + buffer16[(3 * 41 + 5) % 16], 11), B, C);
(A, B, C, D) = (D, B + LeftRotate(A + (B ^ C ^ D) + 0xd4ef3085 + buffer16[(3 * 42 + 5) % 16], 16), B, C);
(A, B, C, D) = (D, B + LeftRotate(A + (B ^ C ^ D) + 0x04881d05 + buffer16[(3 * 43 + 5) % 16], 23), B, C);
(A, B, C, D) = (D, B + LeftRotate(A + (B ^ C ^ D) + 0xd9d4d039 + buffer16[(3 * 44 + 5) % 16], 04), B, C);
(A, B, C, D) = (D, B + LeftRotate(A + (B ^ C ^ D) + 0xe6db99e5 + buffer16[(3 * 45 + 5) % 16], 11), B, C);
(A, B, C, D) = (D, B + LeftRotate(A + (B ^ C ^ D) + 0x1fa27cf8 + buffer16[(3 * 46 + 5) % 16], 16), B, C);
(A, B, C, D) = (D, B + LeftRotate(A + (B ^ C ^ D) + 0xc4ac5665 + buffer16[(3 * 47 + 5) % 16], 23), B, C);
(A, B, C, D) = (D, B + LeftRotate(A + (C ^ (B | ~D)) + 0xf4292244 + buffer16[7 * 48 % 16], 06), B, C);
(A, B, C, D) = (D, B + LeftRotate(A + (C ^ (B | ~D)) + 0x432aff97 + buffer16[7 * 49 % 16], 10), B, C);
(A, B, C, D) = (D, B + LeftRotate(A + (C ^ (B | ~D)) + 0xab9423a7 + buffer16[7 * 50 % 16], 15), B, C);
(A, B, C, D) = (D, B + LeftRotate(A + (C ^ (B | ~D)) + 0xfc93a039 + buffer16[7 * 51 % 16], 21), B, C);
(A, B, C, D) = (D, B + LeftRotate(A + (C ^ (B | ~D)) + 0x655b59c3 + buffer16[7 * 52 % 16], 06), B, C);
(A, B, C, D) = (D, B + LeftRotate(A + (C ^ (B | ~D)) + 0x8f0ccc92 + buffer16[7 * 53 % 16], 10), B, C);
(A, B, C, D) = (D, B + LeftRotate(A + (C ^ (B | ~D)) + 0xffeff47d + buffer16[7 * 54 % 16], 15), B, C);
(A, B, C, D) = (D, B + LeftRotate(A + (C ^ (B | ~D)) + 0x85845dd1 + buffer16[7 * 55 % 16], 21), B, C);
(A, B, C, D) = (D, B + LeftRotate(A + (C ^ (B | ~D)) + 0x6fa87e4f + buffer16[7 * 56 % 16], 06), B, C);
(A, B, C, D) = (D, B + LeftRotate(A + (C ^ (B | ~D)) + 0xfe2ce6e0 + buffer16[7 * 57 % 16], 10), B, C);
(A, B, C, D) = (D, B + LeftRotate(A + (C ^ (B | ~D)) + 0xa3014314 + buffer16[7 * 58 % 16], 15), B, C);
(A, B, C, D) = (D, B + LeftRotate(A + (C ^ (B | ~D)) + 0x4e0811a1 + buffer16[7 * 59 % 16], 21), B, C);
(A, B, C, D) = (D, B + LeftRotate(A + (C ^ (B | ~D)) + 0xf7537e82 + buffer16[7 * 60 % 16], 06), B, C);
(A, B, C, D) = (D, B + LeftRotate(A + (C ^ (B | ~D)) + 0xbd3af235 + buffer16[7 * 61 % 16], 10), B, C);
(A, B, C, D) = (D, B + LeftRotate(A + (C ^ (B | ~D)) + 0x2ad7d2bb + buffer16[7 * 62 % 16], 15), B, C);
(A, B, C, D) = (D, B + LeftRotate(A + (C ^ (B | ~D)) + 0xeb86d391 + buffer16[7 * 63 % 16], 21), B, C);
a0 += A;
b0 += B;
c0 += C;
d0 += D;
}
}
public static class SHA256
{
private static readonly uint[] K =
{
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
};
private static void SetLength(byte[] buffer64, ulong length)
{
buffer64[^8] = (byte)(length >> 53);
buffer64[^7] = (byte)(length >> 45);
buffer64[^6] = (byte)(length >> 37);
buffer64[^5] = (byte)(length >> 29);
buffer64[^4] = (byte)(length >> 21);
buffer64[^3] = (byte)(length >> 13);
buffer64[^2] = (byte)(length >> 5);
buffer64[^1] = (byte)(length << 3);
}
public static byte[] Compute(string str, Encoding? encoding = null) => Compute((encoding ?? Encoding.UTF8).GetBytes(str));
public static byte[] Compute(byte[] data)
{
uint[] h =
{
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
};
var length = (ulong)data.LongLength;
const int length_0x80 = 1;
const int length_end = 8;
var zero_length = 64 - data.LongLength % 64 - length_0x80 - length_end;
if (zero_length < 0) zero_length += 64;
var buffer64_length = data.LongLength + length_0x80 + zero_length + length_end;
var buffer64 = new byte[buffer64_length];
Array.Copy(data, buffer64, (long)length);
buffer64[length] = 0x80;
SetLength(buffer64, length);
var words = new uint[64];
for (var i = 0; i < buffer64.LongLength; i += 64)
{
for (var (j, k) = (0, i); j < 16; j++, k = i + j * 4)
words[j] = (uint)buffer64[k] << 24 | (uint)buffer64[k + 1] << 16 | (uint)buffer64[k + 2] << 8 | buffer64[k + 3];
Compute(words,
ref h[0], ref h[1], ref h[2], ref h[3],
ref h[4], ref h[5], ref h[6], ref h[7]);
}
var result = CreateResult(h);
return result;
}
private static int FillBuffer(Stream stream, byte[] buffer)
{
var length = buffer.Length;
var readed = stream.Read(buffer, 0, length);
if (readed == 0)
return 0;
while (readed < length)
{
var last_readed = stream.Read(buffer, readed, length - readed);
if (last_readed == 0)
return readed;
readed += last_readed;
}
return readed;
}
public static byte[] Compute(Stream data)
{
uint[] h =
{
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
};
var buffer64 = new byte[64];
var words = new uint[64];
var completed = false;
var length = 0UL;
int readed;
do
{
readed = FillBuffer(data, buffer64);
length += (ulong)readed;
if (readed < 64)
{
Array.Clear(buffer64, readed, 64 - readed);
buffer64[readed] = 0x80;
if (64 - readed > 8)
{
SetLength(buffer64, length);
completed = true;
}
}
for (var (j, k) = (0, 0); j < 16; j++, k = j * 4)
words[j] = (uint)buffer64[k] << 24 | (uint)buffer64[k + 1] << 16 | (uint)buffer64[k + 2] << 8 | buffer64[k + 3];
Compute(words,
ref h[0], ref h[1], ref h[2], ref h[3],
ref h[4], ref h[5], ref h[6], ref h[7]);
}
while (readed == 64);
if (readed > 0 && !completed)
{
Array.Clear(buffer64, 0, 64);
SetLength(buffer64, length);
for (var (j, k) = (0, 0); j < 16; j++, k = j * 4)
words[j] = (uint)buffer64[k] << 24 | (uint)buffer64[k + 1] << 16 | (uint)buffer64[k + 2] << 8 | buffer64[k + 3];
Compute(words,
ref h[0], ref h[1], ref h[2], ref h[3],
ref h[4], ref h[5], ref h[6], ref h[7]);
}
var result = CreateResult(h);
return result;
}
private static async Task<int> FillBufferAsync(Stream stream, byte[] buffer, CancellationToken Cancel = default)
{
var length = buffer.Length;
var readed = await stream.ReadAsync(buffer, 0, length, Cancel).ConfigureAwait(false);
if (readed == 0)
return 0;
while (readed < length)
{
var last_readed = await stream.ReadAsync(buffer, readed, length - readed, Cancel).ConfigureAwait(false);
if (last_readed == 0)
return readed;
readed += last_readed;
}
return readed;
}
public static async Task<byte[]> ComputeAsync(Stream data, CancellationToken Cancel = default)
{
uint[] h =
{
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
};
var buffer64 = new byte[64];
var words = new uint[64];
var completed = false;
var length = 0UL;
int readed;
do
{
readed = await FillBufferAsync(data, buffer64, Cancel).ConfigureAwait(false);
length += (ulong)readed;
if (readed < 64)
{
Array.Clear(buffer64, readed, 64 - readed);
buffer64[readed] = 0x80;
if (64 - readed > 8)
{
SetLength(buffer64, length);
completed = true;
}
}
for (var (j, k) = (0, 0); j < 16; j++, k = j * 4)
words[j] = (uint)buffer64[k] << 24 | (uint)buffer64[k + 1] << 16 | (uint)buffer64[k + 2] << 8 | buffer64[k + 3];
Compute(words,
ref h[0], ref h[1], ref h[2], ref h[3],
ref h[4], ref h[5], ref h[6], ref h[7]);
}
while (readed == 64);
if (readed > 0 && !completed)
{
Array.Clear(buffer64, 0, 64);
SetLength(buffer64, length);
for (var (j, k) = (0, 0); j < 16; j++, k = j * 4)
words[j] = (uint)buffer64[k] << 24 | (uint)buffer64[k + 1] << 16 | (uint)buffer64[k + 2] << 8 | buffer64[k + 3];
Compute(words,
ref h[0], ref h[1], ref h[2], ref h[3],
ref h[4], ref h[5], ref h[6], ref h[7]);
}
var result = CreateResult(h);
return result;
}
private static byte[] CreateResult(uint[] h)
{
var result = new byte[32];
for (var i = 0; i < 8; i++)
{
result[4 * i + 0] = (byte)(h[i] >> 24);
result[4 * i + 1] = (byte)(h[i] >> 16);
result[4 * i + 2] = (byte)(h[i] >> 08);
result[4 * i + 3] = (byte)(h[i] >> 00);
}
return result;
}
private static void Compute(uint[] words,
ref uint h0, ref uint h1, ref uint h2, ref uint h3,
ref uint h4, ref uint h5, ref uint h6, ref uint h7)
{
static uint S0(uint x) => RightRotate(x, 7) ^ RightRotate(x, 18) ^ x >> 3;
static uint S1(uint x) => RightRotate(x, 17) ^ RightRotate(x, 19) ^ x >> 10;
for (var j = 16; j < 64; j++)
words[j] = words[j - 16] + S0(words[j - 15]) + words[j - 7] + S1(words[j - 2]);
var (a, b, c, d, e, f, g, h) = (h0, h1, h2, h3, h4, h5, h6, h7);
for (var i = 0; i < 64; i++)
{
static uint Ch(uint x, uint y, uint z) => x & y ^ ~x & z;
static uint Maj(uint x, uint y, uint z) => x & y ^ x & z ^ y & z;
static uint RightRotate(uint x, int c) => (x >> c) | (x << (32 - c));
static uint E0(uint x) => RightRotate(x, 2) ^ RightRotate(x, 13) ^ RightRotate(x, 22);
static uint E1(uint x) => RightRotate(x, 6) ^ RightRotate(x, 11) ^ RightRotate(x, 25);
var t1 = h + E1(e) + Ch(e, f, g) + K[i] + words[i];
var t2 = E0(a) + Maj(a, b, c);
(h, g, f, e, d, c, b, a) = (g, f, e, d + t1, c, b, a, t1 + t2);
}
(h0, h1, h2, h3, h4, h5, h6, h7) = (h0 + a, h1 + b, h2 + c, h3 + d, h4 + e, h5 + f, h6 + g, h7 + h);
}
}
public static class SHA512
{
private static readonly ulong[] K =
{
0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc, 0x3956c25bf348b538,
0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118, 0xd807aa98a3030242, 0x12835b0145706fbe,
0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2, 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235,
0xc19bf174cf692694, 0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65,
0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5, 0x983e5152ee66dfab,
0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4, 0xc6e00bf33da88fc2, 0xd5a79147930aa725,
0x06ca6351e003826f, 0x142929670a0e6e70, 0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed,
0x53380d139d95b3df, 0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b,
0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30, 0xd192e819d6ef5218,
0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8, 0x19a4c116b8d2d0c8, 0x1e376c085141ab53,
0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8, 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373,
0x682e6ff3d6b2b8a3, 0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec,
0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b, 0xca273eceea26619c,
0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178, 0x06f067aa72176fba, 0x0a637dc5a2c898a6,
0x113f9804bef90dae, 0x1b710b35131c471b, 0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc,
0x431d67c49c100d4c, 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817
};
private static void SetLength(byte[] buffer64, ulong length)
{
buffer64[^8] = (byte)(length >> 53);
buffer64[^7] = (byte)(length >> 45);
buffer64[^6] = (byte)(length >> 37);
buffer64[^5] = (byte)(length >> 29);
buffer64[^4] = (byte)(length >> 21);
buffer64[^3] = (byte)(length >> 13);
buffer64[^2] = (byte)(length >> 5);
buffer64[^1] = (byte)(length << 3);
}
public static byte[] Compute(string str, Encoding? encoding = null) => Compute((encoding ?? Encoding.UTF8).GetBytes(str));
public static byte[] Compute(byte[] data)
{
ulong[] h =
{
0x6a09e667f3bcc908, 0xbb67ae8584caa73b, 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1,
0x510e527fade682d1, 0x9b05688c2b3e6c1f, 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179
};
var length = (ulong)data.LongLength;
const int length_0x80 = 1;
var l0 = 128 - (length % 128 + length_0x80);
var buffer128_length = length + l0 + 1;
if (l0 < 16) buffer128_length += 128;
var buffer128 = new byte[buffer128_length];
Array.Copy(data, buffer128, (long)length);
buffer128[length] = 0x80;
SetLength(buffer128, length);
var words = new ulong[80];
for (var i = 0; i < buffer128.LongLength; i += 128)
{
for (var (j, k) = (0, i); j < 16; j++, k = i + j * 8)
words[j] =
(ulong)buffer128[k] << 56 |
(ulong)buffer128[k + 1] << 48 |
(ulong)buffer128[k + 2] << 40 |
(ulong)buffer128[k + 3] << 32 |
(ulong)buffer128[k + 4] << 24 |
(ulong)buffer128[k + 5] << 16 |
(ulong)buffer128[k + 6] << 8 |
buffer128[k + 7];
Compute(words,
ref h[0], ref h[1], ref h[2], ref h[3],
ref h[4], ref h[5], ref h[6], ref h[7]);
}
var result = CreateResult(h);
return result;
}
private static int FillBuffer(Stream stream, byte[] buffer)
{
var length = buffer.Length;
var readed = stream.Read(buffer, 0, length);
if (readed == 0)
return 0;
while (readed < length)
{
var last_readed = stream.Read(buffer, readed, length - readed);
if (last_readed == 0)
return readed;
readed += last_readed;
}
return readed;
}
public static byte[] Compute(Stream data)
{
ulong[] h =
{
0x6a09e667f3bcc908, 0xbb67ae8584caa73b, 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1,
0x510e527fade682d1, 0x9b05688c2b3e6c1f, 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179
};
var buffer128 = new byte[128];
var words = new ulong[80];
var completed = false;
var length = 0UL;
int readed;
do
{
readed = FillBuffer(data, buffer128);
length += (ulong)readed;
if (readed < 128)
{
Array.Clear(buffer128, readed, 128 - readed);
buffer128[readed] = 0x80;
if (128 - readed > 16)
{
SetLength(buffer128, length);
completed = true;
}
}
for (var (j, k) = (0, 0); j < 16; j++, k = j * 8)
words[j] =
(ulong)buffer128[k] << 56 |
(ulong)buffer128[k + 1] << 48 |
(ulong)buffer128[k + 2] << 40 |
(ulong)buffer128[k + 3] << 32 |
(ulong)buffer128[k + 4] << 24 |
(ulong)buffer128[k + 5] << 16 |
(ulong)buffer128[k + 6] << 8 |
buffer128[k + 7];
Compute(words,
ref h[0], ref h[1], ref h[2], ref h[3],
ref h[4], ref h[5], ref h[6], ref h[7]);
}
while (readed == 128);
if (readed > 0 && !completed)
{
Array.Clear(buffer128, 0, 128);
SetLength(buffer128, length);
for (var (j, k) = (0, 0); j < 16; j++, k = j * 8)
words[j] =
(ulong)buffer128[k] << 56 |
(ulong)buffer128[k + 1] << 48 |
(ulong)buffer128[k + 2] << 40 |
(ulong)buffer128[k + 3] << 32 |
(ulong)buffer128[k + 4] << 24 |
(ulong)buffer128[k + 5] << 16 |
(ulong)buffer128[k + 6] << 8 |
buffer128[k + 7];
Compute(words,
ref h[0], ref h[1], ref h[2], ref h[3],
ref h[4], ref h[5], ref h[6], ref h[7]);
}
var result = CreateResult(h);
return result;
}
private static async Task<int> FillBufferAsync(Stream stream, byte[] buffer, CancellationToken Cancel = default)
{
var length = buffer.Length;
var readed = await stream.ReadAsync(buffer, 0, length, Cancel).ConfigureAwait(false);
if (readed == 0)
return 0;
while (readed < length)
{
var last_readed = await stream.ReadAsync(buffer, readed, length - readed, Cancel).ConfigureAwait(false);
if (last_readed == 0)
return readed;
readed += last_readed;
}
return readed;
}
public static async Task<byte[]> ComputeAsync(Stream data, CancellationToken Cancel = default)
{
ulong[] h =
{
0x6a09e667f3bcc908, 0xbb67ae8584caa73b, 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1,
0x510e527fade682d1, 0x9b05688c2b3e6c1f, 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179
};
var buffer128 = new byte[128];
var words = new ulong[80];
var completed = false;
var length = 0UL;
int readed;
do
{
readed = await FillBufferAsync(data, buffer128, Cancel).ConfigureAwait(false);
length += (ulong)readed;
if (readed < 128)
{
Array.Clear(buffer128, readed, 128 - readed);
buffer128[readed] = 0x80;
if (128 - readed > 16)
{
SetLength(buffer128, length);
completed = true;
}
}
for (var (j, k) = (0, 0); j < 16; j++, k = j * 8)
words[j] =
(ulong)buffer128[k] << 56 |
(ulong)buffer128[k + 1] << 48 |
(ulong)buffer128[k + 2] << 40 |
(ulong)buffer128[k + 3] << 32 |
(ulong)buffer128[k + 4] << 24 |
(ulong)buffer128[k + 5] << 16 |
(ulong)buffer128[k + 6] << 8 |
buffer128[k + 7];
Compute(words,
ref h[0], ref h[1], ref h[2], ref h[3],
ref h[4], ref h[5], ref h[6], ref h[7]);
}
while (readed == 128);
if (readed > 0 && !completed)
{
Array.Clear(buffer128, 0, 128);
SetLength(buffer128, length);
for (var (j, k) = (0, 0); j < 16; j++, k = j * 8)
words[j] =
(ulong)buffer128[k] << 56 |
(ulong)buffer128[k + 1] << 48 |
(ulong)buffer128[k + 2] << 40 |
(ulong)buffer128[k + 3] << 32 |
(ulong)buffer128[k + 4] << 24 |
(ulong)buffer128[k + 5] << 16 |
(ulong)buffer128[k + 6] << 8 |
buffer128[k + 7];
Compute(words,
ref h[0], ref h[1], ref h[2], ref h[3],
ref h[4], ref h[5], ref h[6], ref h[7]);
}
var result = CreateResult(h);
return result;
}
private static byte[] CreateResult(ulong[] h)
{
var hash = new byte[64];
for (var i = 0; i < 8; i++)
{
hash[8 * i + 0] = (byte)(h[i] >> 56);
hash[8 * i + 1] = (byte)(h[i] >> 48);
hash[8 * i + 2] = (byte)(h[i] >> 40);
hash[8 * i + 3] = (byte)(h[i] >> 32);
hash[8 * i + 4] = (byte)(h[i] >> 24);
hash[8 * i + 5] = (byte)(h[i] >> 16);
hash[8 * i + 6] = (byte)(h[i] >> 08);
hash[8 * i + 7] = (byte)(h[i] >> 00);
}
return hash;
}
private static void Compute(ulong[] words,
ref ulong h0, ref ulong h1, ref ulong h2, ref ulong h3,
ref ulong h4, ref ulong h5, ref ulong h6, ref ulong h7)
{
static ulong S0(ulong x) => RightRotate(x, 1) ^ RightRotate(x, 8) ^ x >> 7;
static ulong S1(ulong x) => RightRotate(x, 19) ^ RightRotate(x, 61) ^ x >> 6;
for (var j = 16; j < 80; j++)
words[j] = words[j - 16] + S0(words[j - 15]) + words[j - 7] + S1(words[j - 2]);
var (a, b, c, d, e, f, g, h) = (h0, h1, h2, h3, h4, h5, h6, h7);
for (var i = 0; i < 80; i += 1)
{
static ulong Ch(ulong x, ulong y, ulong z) => x & y ^ ~x & z;
static ulong Maj(ulong x, ulong y, ulong z) => x & y ^ x & z ^ y & z;
static ulong RightRotate(ulong x, int c) => (x >> c) | (x << (64 - c));
static ulong E0(ulong x) => RightRotate(x, 28) ^ RightRotate(x, 34) ^ RightRotate(x, 39);
static ulong E1(ulong x) => RightRotate(x, 14) ^ RightRotate(x, 18) ^ RightRotate(x, 41);
var t1 = h + E1(e) + Ch(e, f, g) + K[i] + words[i];
var t2 = E0(a) + Maj(a, b, c);
(h, g, f, e, d, c, b, a) = (g, f, e, d + t1, c, b, a, t1 + t2);
}
(h0, h1, h2, h3, h4, h5, h6, h7) = (h0 + a, h1 + b, h2 + c, h3 + d, h4 + e, h5 + f, h6 + g, h7 + h);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment