257 lines
6.6 KiB
C++
257 lines
6.6 KiB
C++
/***
|
|
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
|
|
|
File: AuRandomDevice.cpp
|
|
Date: 2021-9-3
|
|
Author: Reece
|
|
***/
|
|
#include <AuroraRuntime.hpp>
|
|
#include "AuRandomDevice.hpp"
|
|
|
|
namespace Aurora::RNG
|
|
{
|
|
RandomDevice::RandomDevice()
|
|
{
|
|
|
|
}
|
|
|
|
RandomDevice::RandomDevice(const RandomDef &def)
|
|
{
|
|
this->Init(def);
|
|
}
|
|
|
|
void RandomDevice::Init(const RandomDef &def)
|
|
{
|
|
this->def_ = def;
|
|
|
|
// Gross...
|
|
if (!def.bSecure)
|
|
{
|
|
if (def.seed)
|
|
{
|
|
this->fast_ = AuMove(WELL_SeedRand(def.seed.value()));
|
|
}
|
|
else if (def.seed64)
|
|
{
|
|
this->fast_ = AuMove(WELL_SeedRand64(def.seed64.value()));
|
|
}
|
|
else if (def.seedMassive)
|
|
{
|
|
this->fast_ = AuMove(WELL_SeedRandBig64(def.seedMassive.value()));
|
|
}
|
|
else
|
|
{
|
|
RNG::RngFillArray<false>(this->fast_.state);
|
|
}
|
|
}
|
|
// secure rng requires no init -> we just passthrough to the global ReadSecureRNG function
|
|
}
|
|
|
|
void RandomDevice::Read(Memory::MemoryViewWrite view)
|
|
{
|
|
if (!view)
|
|
{
|
|
SysPushErrorArg();
|
|
return;
|
|
}
|
|
|
|
if (this->def_.bSecure)
|
|
{
|
|
ReadSecureRNG(view);
|
|
}
|
|
else
|
|
{
|
|
WELL_NextBytes(&this->fast_, view.ptr, AuUInt32(view.length));
|
|
}
|
|
}
|
|
|
|
AuString RandomDevice::NextString(AuUInt32 uLength, ERngStringCharacters type)
|
|
{
|
|
AuString ret(uLength, '\00');
|
|
NextString(ret.data(), AuUInt32(ret.size()), type);
|
|
return ret;
|
|
}
|
|
|
|
static AuUInt64 RngConvertBounds(AuUInt32 i)
|
|
{
|
|
AuUInt8 ret;
|
|
AuBitScanReverse(ret, i);
|
|
return 1ull << (ret + 1);
|
|
}
|
|
|
|
void RandomDevice::NextString(char *pString, AuUInt32 uLength, ERngStringCharacters type)
|
|
{
|
|
static AuPair<const char *, int> rngSequence[static_cast<int>(ERngStringCharacters::eEnumCount)] =
|
|
{
|
|
{"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", 52},
|
|
{"abcdefghijklmnopqrstuvwxyz", 26},
|
|
{"ABCDEFGHIJKLMNOPQRSTUVWXYZ", 26},
|
|
{"1234567890", 10},
|
|
{"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890", 62},
|
|
{"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890=-+!$%^*.[];:", 75}
|
|
};
|
|
|
|
if (!pString)
|
|
{
|
|
SysPushErrorArg();
|
|
return;
|
|
}
|
|
|
|
Read(AuMemoryViewWrite { pString, uLength });
|
|
|
|
if (!ERngStringCharactersIsValid(type))
|
|
{
|
|
SysPushErrorArg("NextString was called with an invalid ERngStringCharacters {}", (AuUInt)type);
|
|
type = ERngStringCharacters::eAlphaNumericCharacters; // guess we cant just return false
|
|
}
|
|
|
|
const auto &pair = rngSequence[static_cast<int>(type)];
|
|
|
|
for (auto i = 0u; i < uLength; i++)
|
|
{
|
|
auto uUpperBound = RngConvertBounds(pair.second);
|
|
AuUInt8 uNext {};
|
|
auto uWord = reinterpret_cast<const AuUInt8 *>(pString)[i];
|
|
while ((uNext = (uWord & (uUpperBound - 1))) >= pair.second)
|
|
{
|
|
uWord = AuFnv1a32Runtime(&uWord, sizeof(uWord));
|
|
}
|
|
pString[i] = pair.first[uNext];
|
|
}
|
|
}
|
|
|
|
AuUInt8 RandomDevice::NextByte()
|
|
{
|
|
if (this->def_.bSecure)
|
|
{
|
|
AuUInt8 uRet {};
|
|
ReadSecureRNG({ &uRet, 1 });
|
|
return uRet;
|
|
}
|
|
else
|
|
{
|
|
return AuUInt8(WELL_NextLong(&this->fast_) & 0xFF);
|
|
}
|
|
}
|
|
|
|
bool RandomDevice::NextBoolean()
|
|
{
|
|
if (this->def_.bSecure)
|
|
{
|
|
AuUInt8 uRet {};
|
|
ReadSecureRNG({ &uRet, 1 });
|
|
return bool(uRet & 0x1);
|
|
}
|
|
else
|
|
{
|
|
return bool(WELL_NextLong(&this->fast_) & 0x1);
|
|
}
|
|
}
|
|
|
|
AuUInt32 RandomDevice::NextU32()
|
|
{
|
|
if (this->def_.bSecure)
|
|
{
|
|
AuUInt32 uRet {};
|
|
ReadSecureRNG({ &uRet, 4 });
|
|
return uRet;
|
|
}
|
|
else
|
|
{
|
|
return WELL_NextLong(&this->fast_);
|
|
}
|
|
}
|
|
|
|
AuUInt64 RandomDevice::NextU64()
|
|
{
|
|
if (this->def_.bSecure)
|
|
{
|
|
AuUInt64 uRet {};
|
|
ReadSecureRNG({ &uRet, 8 });
|
|
return uRet;
|
|
}
|
|
else
|
|
{
|
|
return NextFillTmpl<AuUInt64>();
|
|
}
|
|
}
|
|
|
|
AuInt32 RandomDevice::NextInt(AuInt32 uMin, AuInt32 uMax)
|
|
{
|
|
auto uRange = uMax - uMin;
|
|
auto uMassiveWord = NextU32();
|
|
auto uUpperBound = RngConvertBounds(uRange + 1);
|
|
AuUInt32 uNext {};
|
|
while ((uNext = (uMassiveWord & (uUpperBound - 1))) > uRange)
|
|
{
|
|
uMassiveWord = AuFnv1a32Runtime(&uMassiveWord, sizeof(uMassiveWord));
|
|
}
|
|
return uMin + uNext;
|
|
}
|
|
|
|
AuUInt32 RandomDevice::NextU32(AuUInt32 uMin, AuUInt32 uMax)
|
|
{
|
|
auto uRange = uMax - uMin;
|
|
auto uMassiveWord = NextU32();
|
|
auto uUpperBound = RngConvertBounds(uRange + 1);
|
|
AuUInt32 uNext {};
|
|
while ((uNext = (uMassiveWord & (uUpperBound - 1))) > uRange)
|
|
{
|
|
uMassiveWord = AuFnv1a32Runtime(&uMassiveWord, sizeof(uMassiveWord));
|
|
}
|
|
return uMin + uNext;
|
|
}
|
|
|
|
double RandomDevice::NextDecimal()
|
|
{
|
|
return double(NextU32()) * (double(1.0) / double(AuNumericLimits<AuUInt32>::max()));
|
|
}
|
|
|
|
AuUInt32 RandomDevice::NextIndex(AuUInt32 uCount /* = max + 1*/)
|
|
{
|
|
auto uMassiveWord = NextU32();
|
|
auto uUpperBound = RngConvertBounds(uCount);
|
|
AuUInt32 uNext {};
|
|
while ((uNext = (uMassiveWord & (uUpperBound - 1))) >= uCount)
|
|
{
|
|
uMassiveWord = AuFnv1a32Runtime(&uMassiveWord, sizeof(uMassiveWord));
|
|
}
|
|
return uNext;
|
|
}
|
|
|
|
float RandomDevice::NextNumber(float fMin, float fMax)
|
|
{
|
|
auto fRange = fMax - fMin;
|
|
return NextDecimal() * fRange + fMin;
|
|
}
|
|
|
|
AuMemoryViewRead RandomDevice::ToSeed()
|
|
{
|
|
if (this->def_.bSecure)
|
|
{
|
|
return {};
|
|
}
|
|
|
|
return this->fast_.state;
|
|
}
|
|
|
|
AUKN_SYM IRandomDevice *RandomNew(const Aurora::RNG::RandomDef &def)
|
|
{
|
|
auto pDevice = _new RandomDevice();
|
|
if (!pDevice)
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
pDevice->Init(def);
|
|
|
|
return pDevice;
|
|
}
|
|
|
|
AUKN_SYM void RandomRelease(IRandomDevice *pDevice)
|
|
{
|
|
AuSafeDelete<RandomDevice *>(pDevice);
|
|
}
|
|
|
|
AUROXTL_INTERFACE_SOO_SRC(Random, RandomDevice, (const RandomDef &, def))
|
|
} |