Created
May 8, 2019 06:16
-
-
Save Coding-Enthusiast/dbcbe197a6ad74ee61de90c5c9920061 to your computer and use it in GitHub Desktop.
Unsafe implementation of some hash functions
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Runtime.CompilerServices; | |
namespace Autarkysoft.Cryptocurrency.Cryptography.Hashing | |
{ | |
/// <summary> | |
/// https://tools.ietf.org/html/rfc6234 | |
/// </summary> | |
public class Sha512 : IHashFunction, IDisposable | |
{ | |
/// <summary> | |
/// Initializes a new instance of the <see cref="Sha512"/>. | |
/// </summary> | |
/// <param name="isDouble">Determines whether the hash should be performed twice.</param> | |
public Sha512(bool isDouble = false) | |
{ | |
IsDouble = isDouble; | |
} | |
/// <summary> | |
/// Indicates whether the hash function should be performed twice on message. | |
/// For example Double SHA256 that bitcoin uses. | |
/// </summary> | |
public bool IsDouble { get; set; } | |
/// <summary> | |
/// Size of the hash result in bytes. | |
/// </summary> | |
public virtual int HashByteSize => 64; | |
/// <summary> | |
/// Size of the blocks used in each round. | |
/// </summary> | |
public virtual int BlockByteSize => 128; | |
private readonly ulong[] Ks = | |
{ | |
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, | |
}; | |
protected ulong[] block = new ulong[16]; | |
protected ulong[] hashState = new ulong[8]; | |
protected ulong[] w = new ulong[80]; | |
/// <summary> | |
/// Computes the hash value for the specified byte array. | |
/// </summary> | |
/// <exception cref="ArgumentNullException"/> | |
/// <exception cref="ObjectDisposedException"/> | |
/// <param name="data">The byte array to compute hash for</param> | |
/// <returns>The computed hash</returns> | |
public byte[] ComputeHash(byte[] data) | |
{ | |
if (disposedValue) | |
throw new ObjectDisposedException("Instance was disposed."); | |
if (data == null) | |
throw new ArgumentNullException(nameof(data), "Data can not be null."); | |
Init(); | |
DoHash(data); | |
return GetBytes(); | |
} | |
/// <summary> | |
/// Computes the hash value for the specified region of the specified byte array. | |
/// </summary> | |
/// <exception cref="ArgumentNullException"/> | |
/// <exception cref="IndexOutOfRangeException"/> | |
/// <exception cref="ObjectDisposedException"/> | |
/// <param name="buffer">The byte array to compute hash for</param> | |
/// <param name="offset">The offset into the byte array from which to begin using data.</param> | |
/// <param name="count">The number of bytes in the array to use as data.</param> | |
/// <returns>The computed hash</returns> | |
public byte[] ComputeHash(byte[] buffer, int offset, int count) | |
{ | |
return ComputeHash(buffer.SubArray(offset, count)); | |
} | |
internal virtual unsafe byte[] GetBytes() | |
{ | |
byte[] res = new byte[HashByteSize]; | |
fixed (ulong* hPt = &hashState[0]) | |
fixed (byte* bPt = &res[0]) | |
{ | |
for (int i = 0, j = 0; i < res.Length; i += 8, j++) | |
{ | |
bPt[i] = (byte)(hPt[j] >> 56); | |
bPt[i + 1] = (byte)(hPt[j] >> 48); | |
bPt[i + 2] = (byte)(hPt[j] >> 40); | |
bPt[i + 3] = (byte)(hPt[j] >> 32); | |
bPt[i + 4] = (byte)(hPt[j] >> 24); | |
bPt[i + 5] = (byte)(hPt[j] >> 16); | |
bPt[i + 6] = (byte)(hPt[j] >> 8); | |
bPt[i + 7] = (byte)hPt[j]; | |
} | |
} | |
return res; | |
} | |
internal virtual unsafe void Init() | |
{ | |
hashState = new ulong[8] | |
{ | |
0x6a09e667f3bcc908, // 0 | |
0xbb67ae8584caa73b, // 1 | |
0x3c6ef372fe94f82b, // 2 | |
0xa54ff53a5f1d36f1, // 3 | |
0x510e527fade682d1, // 4 | |
0x9b05688c2b3e6c1f, // 5 | |
0x1f83d9abfb41bd6b, // 6 | |
0x5be0cd19137e2179 // 7 | |
}; | |
} | |
internal unsafe void DoHash(byte[] data) | |
{ | |
fixed (byte* dPt = data) // Data length can be 0 and &data[0] will throw | |
fixed (ulong* xPt = &block[0], hPt = &hashState[0], wPt = &w[0]) | |
{ | |
int remainingBytes = data.Length; | |
int dIndex = 0; | |
while (remainingBytes >= BlockByteSize) | |
{ | |
for (int i = 0; i < block.Length; i++, dIndex += 8) | |
{ | |
xPt[i] = | |
((ulong)dPt[dIndex] << 56) | | |
((ulong)dPt[dIndex + 1] << 48) | | |
((ulong)dPt[dIndex + 2] << 40) | | |
((ulong)dPt[dIndex + 3] << 32) | | |
((ulong)dPt[dIndex + 4] << 24) | | |
((ulong)dPt[dIndex + 5] << 16) | | |
((ulong)dPt[dIndex + 6] << 8) | | |
dPt[dIndex + 7]; | |
} | |
CompressBlock(xPt, hPt, wPt); | |
remainingBytes -= BlockByteSize; | |
} | |
byte[] finalBlock = new byte[BlockByteSize]; | |
fixed (byte* fPt = &finalBlock[0]) | |
{ | |
long msgLen = (long)data.Length << 3; // *8 | |
// Message length is added at the end in big-endian order (different from MD4 and RIPEMD160) | |
fPt[127] = (byte)msgLen; | |
fPt[126] = (byte)(msgLen >> 8); | |
fPt[125] = (byte)(msgLen >> 16); | |
fPt[124] = (byte)(msgLen >> 24); | |
fPt[123] = (byte)(msgLen >> 32); | |
/* | |
* Maximum of `msgLen` is (int.MaxValue * 8) = 17179869176 | |
* = ..._00000000 00000000_00000000_00000000_00000011 11111111_11111111_11111111_11111000 | |
* in other words the first 11 bytes are always zero | |
*/ | |
//fPt[122] = (byte)(msgLen >> 40); | |
//fPt[121] = (byte)(msgLen >> 48); | |
//fPt[120] = (byte)(msgLen >> 56); | |
//fPt[119] = (byte)(msgLen >> 64); <-- shifts won't happen correctly. 64=01000000 and shift only take first 6 bits | |
//fPt[118] = (byte)(msgLen >> 72); <-- ... ie. count & 3f(=0b_0011_1111) | |
//fPt[117] = (byte)(msgLen >> 80); | |
//fPt[116] = (byte)(msgLen >> 88); | |
//fPt[115] = (byte)(msgLen >> 96); | |
//fPt[114] = (byte)(msgLen >> 104); | |
//fPt[113] = (byte)(msgLen >> 112); | |
//fPt[112] = (byte)(msgLen >> 120); | |
if (remainingBytes < 112) // blockSize - pad2.Len = 128 - 16 | |
{ | |
Buffer.BlockCopy(data, data.Length - remainingBytes, finalBlock, 0, remainingBytes); | |
fPt[remainingBytes] = 0b1000_0000; | |
for (int i = 0, j = 0; i < block.Length; i++, j += 8) | |
{ | |
xPt[i] = | |
((ulong)fPt[j] << 56) | | |
((ulong)fPt[j + 1] << 48) | | |
((ulong)fPt[j + 2] << 40) | | |
((ulong)fPt[j + 3] << 32) | | |
((ulong)fPt[j + 4] << 24) | | |
((ulong)fPt[j + 5] << 16) | | |
((ulong)fPt[j + 6] << 8) | | |
fPt[j + 7]; | |
} | |
CompressBlock(xPt, hPt, wPt); | |
} | |
else // if (remainingBytes >= 112) | |
{ | |
byte[] finalBlock0 = new byte[BlockByteSize]; | |
Buffer.BlockCopy(data, data.Length - remainingBytes, finalBlock0, 0, remainingBytes); | |
fixed (byte* fPt0 = &finalBlock0[0]) | |
{ | |
fPt0[remainingBytes] = 0b1000_0000; | |
for (int i = 0, j = 0; i < block.Length; i++, j += 8) | |
{ | |
xPt[i] = | |
((ulong)fPt0[j] << 56) | | |
((ulong)fPt0[j + 1] << 48) | | |
((ulong)fPt0[j + 2] << 40) | | |
((ulong)fPt0[j + 3] << 32) | | |
((ulong)fPt0[j + 4] << 24) | | |
((ulong)fPt0[j + 5] << 16) | | |
((ulong)fPt0[j + 6] << 8) | | |
fPt0[j + 7]; | |
} | |
CompressBlock(xPt, hPt, wPt); | |
for (int i = 0, j = 0; i < block.Length; i++, j += 8) | |
{ | |
xPt[i] = | |
((ulong)fPt[j] << 56) | | |
((ulong)fPt[j + 1] << 48) | | |
((ulong)fPt[j + 2] << 40) | | |
((ulong)fPt[j + 3] << 32) | | |
((ulong)fPt[j + 4] << 24) | | |
((ulong)fPt[j + 5] << 16) | | |
((ulong)fPt[j + 6] << 8) | | |
fPt[j + 7]; | |
} | |
CompressBlock(xPt, hPt, wPt); | |
} | |
} | |
} | |
} | |
if (IsDouble) | |
{ | |
DoSecondHash(); | |
} | |
} | |
internal virtual unsafe void DoSecondHash() | |
{ | |
block = new ulong[16] | |
{ | |
hashState[0], hashState[1], hashState[2], hashState[3], | |
hashState[4], hashState[5], hashState[6], hashState[7], // 8*8=64 byte | |
0b10000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000UL, 0, 0, 0, 0, 0, // 6*8=48 byte pad1 | |
0, 512 // 2*8=16 byte pad2 equal to length (64byte=512bit) | |
/* 64+48+16=128 -> 1 block */ | |
}; | |
Init(); | |
fixed (ulong* xPt = &block[0], hPt = &hashState[0], wPt = &w[0]) | |
{ | |
// We only have 1 block so there is no need for a loop. | |
CompressBlock(xPt, hPt, wPt); | |
} | |
} | |
internal unsafe void CompressBlock(ulong* xPt, ulong* hPt, ulong* wPt) | |
{ | |
for (int i = 0; i < 16; i++) | |
{ | |
wPt[i] = xPt[i]; | |
} | |
for (int i = 16; i < w.Length; i++) | |
{ | |
wPt[i] = SSIG1(wPt[i - 2]) + wPt[i - 7] + SSIG0(wPt[i - 15]) + wPt[i - 16]; | |
} | |
ulong a = hPt[0]; | |
ulong b = hPt[1]; | |
ulong c = hPt[2]; | |
ulong d = hPt[3]; | |
ulong e = hPt[4]; | |
ulong f = hPt[5]; | |
ulong g = hPt[6]; | |
ulong h = hPt[7]; | |
ulong temp, aa, bb, cc, dd, ee, ff, hh, gg; | |
fixed (ulong* kPt = &Ks[0]) | |
{ | |
for (int j = 0; j < 80;) | |
{ | |
temp = h + BSIG1(e) + CH(e, f, g) + kPt[j] + wPt[j]; | |
ee = d + temp; | |
aa = temp + BSIG0(a) + MAJ(a, b, c); | |
j++; | |
temp = g + BSIG1(ee) + CH(ee, e, f) + kPt[j] + wPt[j]; | |
ff = c + temp; | |
bb = temp + BSIG0(aa) + MAJ(aa, a, b); | |
j++; | |
temp = f + BSIG1(ff) + CH(ff, ee, e) + kPt[j] + wPt[j]; | |
gg = b + temp; | |
cc = temp + BSIG0(bb) + MAJ(bb, aa, a); | |
j++; | |
temp = e + BSIG1(gg) + CH(gg, ff, ee) + kPt[j] + wPt[j]; | |
hh = a + temp; | |
dd = temp + BSIG0(cc) + MAJ(cc, bb, aa); | |
j++; | |
temp = ee + BSIG1(hh) + CH(hh, gg, ff) + kPt[j] + wPt[j]; | |
h = aa + temp; | |
d = temp + BSIG0(dd) + MAJ(dd, cc, bb); | |
j++; | |
temp = ff + BSIG1(h) + CH(h, hh, gg) + kPt[j] + wPt[j]; | |
g = bb + temp; | |
c = temp + BSIG0(d) + MAJ(d, dd, cc); | |
j++; | |
temp = gg + BSIG1(g) + CH(g, h, hh) + kPt[j] + wPt[j]; | |
f = cc + temp; | |
b = temp + BSIG0(c) + MAJ(c, d, dd); | |
j++; | |
temp = hh + BSIG1(f) + CH(f, g, h) + kPt[j] + wPt[j]; | |
e = dd + temp; | |
a = temp + BSIG0(b) + MAJ(b, c, d); | |
j++; | |
} | |
} | |
hPt[0] += a; | |
hPt[1] += b; | |
hPt[2] += c; | |
hPt[3] += d; | |
hPt[4] += e; | |
hPt[5] += f; | |
hPt[6] += g; | |
hPt[7] += h; | |
} | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
private ulong CH(ulong x, ulong y, ulong z) | |
{ | |
return z ^ (x & (y ^ z)); //TODO: find mathematical proof for this change | |
//return (x & y) ^ ((~x) & z); | |
} | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
private ulong MAJ(ulong x, ulong y, ulong z) | |
{ | |
return (x & y) | (z & (x | y)); //TODO: find mathematical proof for this change | |
//return (x & y) ^ (x & z) ^ (y & z); | |
} | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
private ulong BSIG0(ulong x) | |
{ | |
return (x >> 28 | x << 36) ^ (x >> 34 | x << 30) ^ (x >> 39 | x << 25); | |
//return ROTR(x, 28) ^ ROTR(x, 34) ^ ROTR(x, 39); | |
} | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
private ulong BSIG1(ulong x) | |
{ | |
return (x >> 14 | x << 50) ^ (x >> 18 | x << 46) ^ (x >> 41 | x << 23); | |
//return ROTR(x, 14) ^ ROTR(x, 18) ^ ROTR(x, 41); | |
} | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
private ulong SSIG0(ulong x) | |
{ | |
return (x >> 1 | x << 63) ^ (x >> 8 | x << 56) ^ (x >> 7); | |
//return ROTR(x, 1) ^ ROTR(x, 8) ^ (x >> 7); | |
} | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
private ulong SSIG1(ulong x) | |
{ | |
return (x >> 19 | x << 45) ^ (x >> 61 | x << 3) ^ (x >> 6); | |
//return ROTR(x, 19) ^ ROTR(x, 61) ^ (x >> 6); | |
} | |
//[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
//private ulong ROTR(ulong x, int n) | |
//{ | |
// return (x >> n) | (x << (64 - n)); | |
//} | |
//[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
//private ulong ROTL(ulong x, int n) | |
//{ | |
// return (x << n) | (x >> (64 - n)); | |
//} | |
#region IDisposable Support | |
private bool disposedValue = false; // To detect redundant calls | |
protected virtual void Dispose(bool disposing) | |
{ | |
if (!disposedValue) | |
{ | |
if (disposing) | |
{ | |
if (hashState != null) | |
Array.Clear(hashState, 0, hashState.Length); | |
hashState = null; | |
if (block != null) | |
Array.Clear(block, 0, block.Length); | |
block = null; | |
if (w != null) | |
Array.Clear(w, 0, w.Length); | |
w = null; | |
} | |
disposedValue = true; | |
} | |
} | |
public void Dispose() | |
{ | |
Dispose(true); | |
} | |
#endregion | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace Autarkysoft.Cryptocurrency.Cryptography.Hashing | |
{ | |
/// <summary> | |
/// https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf | |
/// </summary> | |
public class Sha512_224 : Sha512 | |
{ | |
/// <summary> | |
/// Initializes a new instance of the <see cref="Sha512_224"/>. | |
/// </summary> | |
/// <param name="isDouble">Determines whether the hash should be performed twice.</param> | |
public Sha512_224(bool isDouble = false) | |
{ | |
IsDouble = isDouble; | |
} | |
/// <summary> | |
/// Size of the hash result in bytes. | |
/// </summary> | |
public override int HashByteSize => 28; | |
internal override unsafe byte[] GetBytes() | |
{ | |
byte[] res = new byte[HashByteSize]; | |
fixed (ulong* hPt = &hashState[0]) | |
fixed (byte* bPt = &res[0]) | |
{ | |
int i = 0, j = 0; | |
for (; i < 24; i += 8, j++) // 224 is 3*8 + 4 | |
{ | |
bPt[i] = (byte)(hPt[j] >> 56); | |
bPt[i + 1] = (byte)(hPt[j] >> 48); | |
bPt[i + 2] = (byte)(hPt[j] >> 40); | |
bPt[i + 3] = (byte)(hPt[j] >> 32); | |
bPt[i + 4] = (byte)(hPt[j] >> 24); | |
bPt[i + 5] = (byte)(hPt[j] >> 16); | |
bPt[i + 6] = (byte)(hPt[j] >> 8); | |
bPt[i + 7] = (byte)hPt[j]; | |
} | |
bPt[i] = (byte)(hPt[j] >> 56); | |
bPt[i + 1] = (byte)(hPt[j] >> 48); | |
bPt[i + 2] = (byte)(hPt[j] >> 40); | |
bPt[i + 3] = (byte)(hPt[j] >> 32); | |
} | |
return res; | |
} | |
internal override void Init() | |
{ | |
hashState = new ulong[8] | |
{ | |
0x8c3d37c819544da2, // 0 | |
0x73e1996689dcd4d6, // 1 | |
0x1dfab7ae32ff9c82, // 2 | |
0x679dd514582f9fcf, // 3 | |
0x0f6d2b697bd44da8, // 4 | |
0x77e36f7304c48942, // 5 | |
0x3f9d85a86a1d36c8, // 6 | |
0x1112e6ad91d692a1 // 7 | |
}; | |
} | |
internal override unsafe void DoSecondHash() | |
{ | |
block = new ulong[16] | |
{ | |
// The difference with SHA512 is | |
// * 224 bit or 28 byte result of last step = 3*ulong + 4 byte | |
// * 2 extra zero in pad1 | |
// * data length is 384 bit or 48 byte in pad2 | |
hashState[0], hashState[1], hashState[2], // 3*8 = 24 | |
// First 4 bytes of hashState[3] followed by `1` bit = 8 byte | |
hashState[3] & 0xffffffff_00000000UL | 0b10000000_00000000_00000000_00000000UL, | |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 10*8=80 pad1 | |
0, 224 // 2*8=16 byte pad2 equal to length (28byte=224bit) | |
/* (24+8)+80+16=128 -> 1 block */ | |
}; | |
Init(); | |
fixed (ulong* xPt = &block[0], hPt = &hashState[0], wPt = &w[0]) | |
{ | |
// We only have 1 block so there is no need for a loop. | |
CompressBlock(xPt, hPt, wPt); | |
} | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace Autarkysoft.Cryptocurrency.Cryptography.Hashing | |
{ | |
/// <summary> | |
/// https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf | |
/// </summary> | |
public class Sha512_256 : Sha512 | |
{ | |
/// <summary> | |
/// Initializes a new instance of the <see cref="Sha512_256"/>. | |
/// </summary> | |
/// <param name="isDouble">Determines whether the hash should be performed twice.</param> | |
public Sha512_256(bool isDouble = false) | |
{ | |
IsDouble = isDouble; | |
} | |
/// <summary> | |
/// Size of the hash result in bytes. | |
/// </summary> | |
public override int HashByteSize => 32; | |
internal override void Init() | |
{ | |
hashState = new ulong[8] | |
{ | |
0x22312194fc2bf72c, // 0 | |
0x9f555fa3c84c64c2, // 1 | |
0x2393b86b6f53b151, // 2 | |
0x963877195940eabd, // 3 | |
0x96283ee2a88effe3, // 4 | |
0xbe5e1e2553863992, // 5 | |
0x2b0199fc2c85b8aa, // 6 | |
0x0eb72ddc81c52ca2 // 7 | |
}; | |
} | |
internal override unsafe void DoSecondHash() | |
{ | |
block = new ulong[16] | |
{ | |
// The difference with SHA512 is | |
// * 4 less hashstate (256 bit or 32 byte result of last step) | |
// * 4 extra zero in pad1 | |
// * data length is 384 bit or 48 byte in pad2 | |
hashState[0], hashState[1], hashState[2], hashState[3], // 4*8=32 byte | |
0b10000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000UL, | |
0, 0, 0, 0, 0, 0, 0, 0, 0,// 10*8=80 byte pad1 | |
0, 256 // 2*8=16 byte pad2 equal to length (32byte=256bit) | |
/* 32+80+16=128 -> 1 block */ | |
}; | |
Init(); | |
fixed (ulong* xPt = &block[0], hPt = &hashState[0], wPt = &w[0]) | |
{ | |
// We only have 1 block so there is no need for a loop. | |
CompressBlock(xPt, hPt, wPt); | |
} | |
} | |
} | |
} |
Benchmark result same as above but using double (ie. SHA256.ComputeHash(SHA256.ComputeHash(data))
)
BenchmarkDotNet=v0.11.5, OS=Windows 7 SP1 (6.1.7601.0)
Intel Core i3-6100 CPU 3.70GHz (Skylake), 1 CPU, 4 logical and 2 physical cores
Frequency=3609589 Hz, Resolution=277.0399 ns, Timer=TSC
.NET Core SDK=2.1.505
[Host] : .NET Core 2.1.9 (CoreCLR 4.6.27414.06, CoreFX 4.6.27415.01), 64bit RyuJIT
DefaultJob : .NET Core 2.1.9 (CoreCLR 4.6.27414.06, CoreFX 4.6.27415.01), 64bit RyuJIT
Method | Mean | Error | StdDev |
---|---|---|---|
SysSha_double | 1,918.2 ns | 25.421 ns | 23.779 ns |
MySha_double | 684.5 ns | 4.439 ns | 4.152 ns |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Benchmark result for
Sha256
(MySha) versusSHA256
(SysSha) usingbyte[33]
: