Skip to content

Instantly share code, notes, and snippets.

@mjs3339
Last active March 4, 2019 16:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mjs3339/b2e7c1f90f63e2e948df470edcf9f4ae to your computer and use it in GitHub Desktop.
Save mjs3339/b2e7c1f90f63e2e948df470edcf9f4ae to your computer and use it in GitHub Desktop.
C# CryptoGetBytesExperimental
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