From 800140bafaf4ec14f6353099f8265a0a1c41462c Mon Sep 17 00:00:00 2001 From: Leonetienne Date: Thu, 26 May 2022 12:52:04 +0200 Subject: [PATCH] Added a method to GPrng to get a random uint32, which is about twice as fast as GetRandom --- GCryptLib/include/GCrypt/GPrng.h | 3 +++ GCryptLib/src/GPrng.cpp | 46 ++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/GCryptLib/include/GCrypt/GPrng.h b/GCryptLib/include/GCrypt/GPrng.h index b037a53..01845f5 100644 --- a/GCryptLib/include/GCrypt/GPrng.h +++ b/GCryptLib/include/GCrypt/GPrng.h @@ -46,6 +46,9 @@ namespace Leonetienne::GCrypt { return t; } + //! Will return a random unsigned 32-bit integer + std::uint32_t operator()(); + //! Will return a random block Block GetBlock(); diff --git a/GCryptLib/src/GPrng.cpp b/GCryptLib/src/GPrng.cpp index 94b228b..b1731bf 100644 --- a/GCryptLib/src/GPrng.cpp +++ b/GCryptLib/src/GPrng.cpp @@ -53,6 +53,10 @@ namespace Leonetienne::GCrypt { // We don't even have to AdvanceBlock(), because we've only given out // hashsum', not hashsum. + // Performance improvement over the previous method: + // (generating 100.000 blocks): + // 12 seconds -> 0.12 seconds + // Fetch our current block Block hashsum = hasher.GetHashsum(); @@ -65,5 +69,47 @@ namespace Leonetienne::GCrypt { return hashsum; } + std::uint32_t GPrng::operator()() { + // Tactic: + // A block intrinsically consists of 16 32-bit uints. + // We'll just skip all the bits until the next whole integer, + // fetch this complete int, and then advance our pointer + // by 32 bits. + + // Performance improvement over the previous method: + // (generating 1.000.000 integers): + // 5.26 seconds -> 3.84 seconds + + + // Advance our pointer to the next whole uint32 + + // Do we even have >= 32 bits left in our block? + if (nextBit > Block::BLOCK_SIZE_BITS - Block::CHUNK_SIZE_BITS) { + // No: Create a new block + AdvanceBlock(); + } + + // We don't have to do this, if our pointer is already at + // the beginning of a whole uint32 + if (nextBit % Block::CHUNK_SIZE_BITS != 0) { + nextBit = ((nextBit / Block::CHUNK_SIZE_BITS) + 1) * Block::CHUNK_SIZE_BITS; + } + + // Fetch our integer from the block + const std::uint32_t randint = + hasher.GetHashsum().Get(nextBit / Block::CHUNK_SIZE_BITS); + + // Advance our pointer + nextBit += Block::CHUNK_SIZE_BITS; + + // New state of the pointer: + // It ow may be more now than the size of a block, but that + // gets checked at the begin of a function. + // Not at the end, like here. + + // Return our integer + return randint; + } + }