Last active
March 4, 2019 16:27
-
-
Save mjs3339/b2e7c1f90f63e2e948df470edcf9f4ae to your computer and use it in GitHub Desktop.
C# CryptoGetBytesExperimental
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.Security.Cryptography; | |
/// <summary> | |
/// Murmur3 (128b): 16 MBps. | |
/// MD5 (128b): 7.5 MBps. | |
/// SHA1 (160b): 8.5MBps. | |
/// SHA256: 9.5 MBps. | |
/// *SHA512: 13.5 MBps. | |
/// SHA3 (1024b): 12.5 MBps. | |
/// Tested: I7-8700K @4.2Ghz | |
/// </summary> | |
public class CryptoGetBytesExperimental : RandomNumberGenerator | |
{ | |
private readonly int hashSizeInBytes; | |
public HashAlgorithm Algorithm; | |
private int availableCacheBytes; | |
private volatile byte[] buffer; | |
private volatile byte[] cache; | |
private readonly bool ManuallySeeded; | |
private volatile int ptr; | |
public CryptoGetBytesExperimental(byte[] seed, HashAlgorithm algorithm = null) | |
{ | |
ManuallySeeded = true; | |
Algorithm = algorithm ?? new SHA512CryptoServiceProvider(); | |
cache = new byte[CacheSize]; | |
availableCacheBytes = 0; | |
ptr = 0; | |
buffer = Algorithm.ComputeHash(seed); | |
hashSizeInBytes = Algorithm.ComputeHash(2.GetBytes()).Length; | |
FillCache(); | |
} | |
public CryptoGetBytesExperimental(HashAlgorithm algorithm = null) | |
{ | |
Algorithm = algorithm ?? new SHA512CryptoServiceProvider(); | |
cache = new byte[CacheSize]; | |
availableCacheBytes = 0; | |
ptr = 0; | |
buffer = Algorithm.ComputeHash(CryptoEntropySourceExperimental.Entropy); | |
hashSizeInBytes = Algorithm.ComputeHash(2.GetBytes()).Length; | |
FillCache(); | |
} | |
public CryptoGetBytesExperimental(int cacheSize, HashAlgorithm algorithm = null) | |
{ | |
Algorithm = algorithm ?? new SHA512CryptoServiceProvider(); | |
CacheSize = cacheSize; | |
cache = new byte[CacheSize]; | |
availableCacheBytes = 0; | |
ptr = 0; | |
buffer = Algorithm.ComputeHash(CryptoEntropySourceExperimental.Entropy); | |
hashSizeInBytes = Algorithm.ComputeHash(2.GetBytes()).Length; | |
FillCache(); | |
} | |
public int CacheSize {get; set;} = 1000000; | |
public int CacheFills{get; private set;} | |
public override void GetBytes(byte[] data) | |
{ | |
lock(this) | |
{ | |
if(CacheSize != cache.Length) | |
cache = new byte[CacheSize]; | |
if(availableCacheBytes == 0 || availableCacheBytes < data.Length) | |
{ | |
if(CacheSize < data.Length) | |
{ | |
CacheSize = data.Length; | |
cache = new byte[CacheSize]; | |
} | |
FillCache(); | |
} | |
if(ptr + data.Length > CacheSize) | |
FillCache(); | |
Buffer.BlockCopy(cache, ptr, data, 0, data.Length); | |
ptr += data.Length; | |
availableCacheBytes -= data.Length; | |
} | |
} | |
private void FillCache() | |
{ | |
CacheFills++; | |
if(CacheFills % 1000 == 0 && !ManuallySeeded) | |
buffer = Algorithm.ComputeHash(CryptoEntropySourceExperimental.Entropy); | |
availableCacheBytes = 0; | |
ptr = 0; | |
var p = 0; | |
var moveSize = hashSizeInBytes; | |
do | |
{ | |
buffer = Algorithm.ComputeHash(buffer); | |
var blit = CacheSize - availableCacheBytes; | |
if(blit < moveSize) | |
moveSize = blit; | |
if(p + moveSize >= CacheSize) | |
break; | |
if(cache.Length != CacheSize) | |
cache = new byte[CacheSize]; | |
Buffer.BlockCopy(buffer, 0, cache, p, moveSize); | |
p += moveSize; | |
availableCacheBytes += moveSize; | |
} while(availableCacheBytes < CacheSize); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment