අනෙක් පිළිතුරු සමාලෝචනය කිරීමෙන් පසුව සහ කෝඩ්ඉන්චාඕස්ගේ අදහස් සලකා බැලීමෙන් පසුව, කෝඩ්ඉන්චාඕස් තවමත් පක්ෂග්රාහී (අඩු වුවද) පිළිතුර සමඟ, අවසාන අවසාන කැපුම් හා පේස්ට් විසඳුමක් අවශ්ය යැයි මම සිතුවෙමි . ඒ නිසා මගේ පිළිතුර යාවත්කාලීන කරන අතරතුර මම සියල්ල පිටතට යාමට තීරණය කළෙමි.
මෙම කේතයේ යාවත්කාලීන අනුවාදයක් සඳහා, කරුණාකර බිට්බකට් හි නව Hg ගබඩාවට පිවිසෙන්න: https://bitbucket.org/merarischroeder/secureswiftrandom . කේතය පිටපත් කර අලවන්නැයි මම නිර්දේශ කරමි: https://bitbucket.org/merarischroeder/secureswiftrandom/src/6c14b874f34a3f6576b0213379ecdf0ffc7496ea/Code/Alivate.SolidSwiftRandom/SolidSwift ? අමු බොත්තම පහසුවෙන් පිටපත් කර ඔබට නවතම අනුවාදය ඇති බවට වග බලා ගන්න, මෙම සබැඳිය යන්නේ කේතයේ නිශ්චිත අනුවාදයකට මිස නවතම ඒවාට නොවේ).
යාවත්කාලීන කළ සටහන්:
- වෙනත් පිළිතුරු වලට අදාළව - ප්රතිදානයේ දිග ඔබ දන්නේ නම්, ඔබට StringBuilder අවශ්ය නොවන අතර ToCharArray භාවිතා කරන විට, මෙය අරාව නිර්මාණය කර පුරවයි (ඔබට මුලින් හිස් අරාවක් සෑදීමට අවශ්ය නැත)
- වෙනත් පිළිතුරු වලට සම්බන්ධ වීම - කාර්ය සාධනය සඳහා වරකට එකක් ලබා ගැනීමට වඩා ඔබ NextBytes භාවිතා කළ යුතුය
- තාක්ෂණික වශයෙන් ඔබට වේගවත් ප්රවේශය සඳහා බයිට් අරාව ඇලවිය හැකිය .. සාමාන්යයෙන් එය බයිට් අරාවකට වඩා 6-8 වාරයකට වඩා වැඩි වාර ගණනක් යෙදීම වටී. (මෙහි සිදු කර නැත)
- හොඳම අහඹු බව සඳහා RNGCryptoServiceProvider භාවිතය
- අහඹු දත්ත 1MB බෆරයක හැඹිලිය භාවිතා කිරීම - මිණුම් සලකුණු කිරීම මඟින් හැඹිලි තනි බයිට් වලට ප්රවේශවීමේ වේගය x 1000x වේගවත් බව පෙන්නුම් කරයි - 1MB ට වඩා 9m හා එදිරිව 989ms නොබැඳි සඳහා.
- මගේ නව පන්තිය තුළ පක්ෂග්රාහී කලාපය ප්රශස්ත ලෙස ප්රතික්ෂේප කිරීම .
ප්රශ්නයට විසඳුම අවසන් කරන්න:
static char[] charSet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".ToCharArray();
static int byteSize = 256; //Labelling convenience
static int biasZone = byteSize - (byteSize % charSet.Length);
public string GenerateRandomString(int Length) //Configurable output string length
{
byte[] rBytes = new byte[Length]; //Do as much before and after lock as possible
char[] rName = new char[Length];
SecureFastRandom.GetNextBytesMax(rBytes, biasZone);
for (var i = 0; i < Length; i++)
{
rName[i] = charSet[rBytes[i] % charSet.Length];
}
return new string(rName);
}
නමුත් ඔබට මගේ නව (පරීක්ෂා නොකළ) පන්තිය අවශ්යයි:
/// <summary>
/// My benchmarking showed that for RNGCryptoServiceProvider:
/// 1. There is negligable benefit of sharing RNGCryptoServiceProvider object reference
/// 2. Initial GetBytes takes 2ms, and an initial read of 1MB takes 3ms (starting to rise, but still negligable)
/// 2. Cached is ~1000x faster for single byte at a time - taking 9ms over 1MB vs 989ms for uncached
/// </summary>
class SecureFastRandom
{
static byte[] byteCache = new byte[1000000]; //My benchmark showed that an initial read takes 2ms, and an initial read of this size takes 3ms (starting to raise)
static int lastPosition = 0;
static int remaining = 0;
/// <summary>
/// Static direct uncached access to the RNGCryptoServiceProvider GetBytes function
/// </summary>
/// <param name="buffer"></param>
public static void DirectGetBytes(byte[] buffer)
{
using (var r = new RNGCryptoServiceProvider())
{
r.GetBytes(buffer);
}
}
/// <summary>
/// Main expected method to be called by user. Underlying random data is cached from RNGCryptoServiceProvider for best performance
/// </summary>
/// <param name="buffer"></param>
public static void GetBytes(byte[] buffer)
{
if (buffer.Length > byteCache.Length)
{
DirectGetBytes(buffer);
return;
}
lock (byteCache)
{
if (buffer.Length > remaining)
{
DirectGetBytes(byteCache);
lastPosition = 0;
remaining = byteCache.Length;
}
Buffer.BlockCopy(byteCache, lastPosition, buffer, 0, buffer.Length);
lastPosition += buffer.Length;
remaining -= buffer.Length;
}
}
/// <summary>
/// Return a single byte from the cache of random data.
/// </summary>
/// <returns></returns>
public static byte GetByte()
{
lock (byteCache)
{
return UnsafeGetByte();
}
}
/// <summary>
/// Shared with public GetByte and GetBytesWithMax, and not locked to reduce lock/unlocking in loops. Must be called within lock of byteCache.
/// </summary>
/// <returns></returns>
static byte UnsafeGetByte()
{
if (1 > remaining)
{
DirectGetBytes(byteCache);
lastPosition = 0;
remaining = byteCache.Length;
}
lastPosition++;
remaining--;
return byteCache[lastPosition - 1];
}
/// <summary>
/// Rejects bytes which are equal to or greater than max. This is useful for ensuring there is no bias when you are modulating with a non power of 2 number.
/// </summary>
/// <param name="buffer"></param>
/// <param name="max"></param>
public static void GetBytesWithMax(byte[] buffer, byte max)
{
if (buffer.Length > byteCache.Length / 2) //No point caching for larger sizes
{
DirectGetBytes(buffer);
lock (byteCache)
{
UnsafeCheckBytesMax(buffer, max);
}
}
else
{
lock (byteCache)
{
if (buffer.Length > remaining) //Recache if not enough remaining, discarding remaining - too much work to join two blocks
DirectGetBytes(byteCache);
Buffer.BlockCopy(byteCache, lastPosition, buffer, 0, buffer.Length);
lastPosition += buffer.Length;
remaining -= buffer.Length;
UnsafeCheckBytesMax(buffer, max);
}
}
}
/// <summary>
/// Checks buffer for bytes equal and above max. Must be called within lock of byteCache.
/// </summary>
/// <param name="buffer"></param>
/// <param name="max"></param>
static void UnsafeCheckBytesMax(byte[] buffer, byte max)
{
for (int i = 0; i < buffer.Length; i++)
{
while (buffer[i] >= max)
buffer[i] = UnsafeGetByte(); //Replace all bytes which are equal or above max
}
}
}
ඉතිහාසය සඳහා - මෙම පිළිතුර සඳහා මගේ පැරණි විසඳුම, භාවිතා කළ සසම්භාවී වස්තුව:
private static char[] charSet =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".ToCharArray();
static rGen = new Random(); //Must share, because the clock seed only has Ticks (~10ms) resolution, yet lock has only 20-50ns delay.
static int byteSize = 256; //Labelling convenience
static int biasZone = byteSize - (byteSize % charSet.Length);
static bool SlightlyMoreSecurityNeeded = true; //Configuration - needs to be true, if more security is desired and if charSet.Length is not divisible by 2^X.
public string GenerateRandomString(int Length) //Configurable output string length
{
byte[] rBytes = new byte[Length]; //Do as much before and after lock as possible
char[] rName = new char[Length];
lock (rGen) //~20-50ns
{
rGen.NextBytes(rBytes);
for (int i = 0; i < Length; i++)
{
while (SlightlyMoreSecurityNeeded && rBytes[i] >= biasZone) //Secure against 1/5 increased bias of index[0-7] values against others. Note: Must exclude where it == biasZone (that is >=), otherwise there's still a bias on index 0.
rBytes[i] = rGen.NextByte();
rName[i] = charSet[rBytes[i] % charSet.Length];
}
}
return new string(rName);
}
කාර්ය සාධනය:
- SecureFastRandom - පළමු තනි ධාවනය = ~ 9-33ms . නොපෙනෙන. සිදු කෙරෙමින් : 5ms (සමහර විට එය 13ms දක්වා යයි) අනුකරණ 10,000 කට අධික, තනි සාමාන්ය ප්රතිඵලයක්ම = සමඟ 1.5 තත්පර. . සටහන: සාමාන්යයෙන් 2 ක් අවශ්ය වේ, නමුත් ඉඳහිට හැඹිලි ප්රබෝධ 8 ක් දක්වා - පක්ෂග්රාහී කලාපය ඉක්මවා යන තනි බයිට් ගණන මත රඳා පවතී
- සසම්භාවී - පළමු තනි ධාවනය = ~ 0-1ms . නොපෙනෙන. සිදු කෙරෙමින් : 5ms අනුකරණ 10,000 කට අධික. තනි සාමාන්ය ක්රියාවලියක් සමඟ = .5 මයික්රෝ තත්පර. . එකම වේගය ගැන.
එසේම පරීක්ෂා කරන්න:
මෙම සබැඳි තවත් ප්රවේශයකි. මෙම නව කේත පදනමට බෆරින් එකතු කළ හැකි නමුත් වඩාත්ම වැදගත් වූයේ නැඹුරුව ඉවත් කිරීම සඳහා විවිධ ප්රවේශයන් ගවේෂණය කිරීම සහ වේගය සහ වාසි / අවාසි මිණුම් සලකුණු කිරීමයි.