CSPRNG
Cryptographically Secure Pseudo Random Number Generator. Use this for ALL cryptographic randomness. Never use math.random() for anything security related.
local CSPRNG = Cryptography.Utilities.CSPRNG
Random Numbers
CSPRNG.Random() -> number
Returns a random float between 0 (inclusive) and 1 (exclusive).
local RandomFloat = CSPRNG.Random()
print(RandomFloat) -- e.g., 0.7234891...
CSPRNG.RandomInt(Min: number, Max: number?) -> number
Returns a random integer. If only one argument, returns 1 to Min.
local DiceRoll = CSPRNG.RandomInt(1, 6)
local Index = CSPRNG.RandomInt(100) -- 1 to 100
CSPRNG.RandomNumber(Min: number, Max: number?) -> number
Returns a random float in range. If only one argument, returns 0 to Min.
local Value = CSPRNG.RandomNumber(0.5, 10.5)
local Normalized = CSPRNG.RandomNumber(1.0) -- 0 to 1
Random Bytes
CSPRNG.RandomBytes(Count: number) -> buffer
The workhorse function. Returns Count cryptographically random bytes.
local Key = CSPRNG.RandomBytes(32) -- 256 bit key
local Nonce = CSPRNG.RandomBytes(12) -- 96 bit nonce
local IV = CSPRNG.RandomBytes(16) -- 128 bit IV
Use this for generating keys, nonces, IVs, salts, and any other security sensitive random data.
CSPRNG.RandomHex(Length: number) -> string
Returns a hex string of the specified length.
local HexToken = CSPRNG.RandomHex(32) -- 32 hex chars
print(HexToken) -- e.g., "a7f3c1d4e8b2..."
CSPRNG.RandomString(Length: number, AsBuffer: boolean?) -> buffer | string
Returns random alphanumeric characters.
local Token = CSPRNG.RandomString(20) -- returns string
local TokenBuffer = CSPRNG.RandomString(20, true) -- returns buffer
Ed25519 Key Generation
CSPRNG.Ed25519Random() -> buffer
Generates a properly clamped 32 byte Ed25519 secret key.
local SecretKey = CSPRNG.Ed25519Random()
local PublicKey = EdDSA.PublicKey(SecretKey)
Always use this instead of RandomBytes(32) for Ed25519 keys. The clamping ensures the key is a valid scalar for the curve.
CSPRNG.Ed25519ClampedBytes(Input: buffer) -> buffer
Clamps existing 32 bytes to valid Ed25519 format.
local SomeBytes = CSPRNG.RandomBytes(32)
local ClampedKey = CSPRNG.Ed25519ClampedBytes(SomeBytes)
Clamping clears the lowest 3 bits, clears the highest bit, and sets the second highest bit. This ensures the scalar is in the right subgroup and has consistent bit length.
Entropy Management
CSPRNG.Reseed(CustomEntropy: buffer?)
Forces state regeneration with optional custom entropy.
-- Reseed with system entropy only
CSPRNG.Reseed()
-- Add custom entropy
local Entropy = buffer.create(8)
buffer.writef64(Entropy, 0, tick())
CSPRNG.Reseed(Entropy)
The CSPRNG auto reseeds periodically, but you can force a reseed if you want to mix in application specific entropy.
CSPRNG.AddEntropyProvider(ProviderFunction: () -> buffer?)
Registers a function that provides additional entropy.
local function GameEntropy()
local Buf = buffer.create(12)
buffer.writeu32(Buf, 0, PlayerCount)
buffer.writef64(Buf, 4, SomeUnpredictableGameState)
return Buf
end
CSPRNG.AddEntropyProvider(GameEntropy)
Provider functions are called during reseeding. They should return fresh entropy each time or nil if nothing new is available.
CSPRNG.RemoveEntropyProvider(ProviderFunction: () -> buffer?)
Unregisters an entropy provider.
CSPRNG.RemoveEntropyProvider(GameEntropy)
How It Works
The CSPRNG uses ChaCha20 as a deterministic random bit generator (DRBG) with BLAKE3 for entropy mixing.
Initialization Gather entropy from available sources (tick, os.clock, os.time, math.random for initial seeding), mix entropy with BLAKE3 to derive the ChaCha20 key and nonce, generate initial random block.
Generation Run ChaCha20 to produce 64 byte blocks, extract bytes as needed, when the block is exhausted increment counter and generate another.
Reseeding Auto reseeds periodically, mixes fresh entropy with BLAKE3.
Security Notes
Do:
- Use
CSPRNGfor all cryptographic randomness - Use
Ed25519Random()for Ed25519 secret keys - Consider adding application specific entropy via providers
Do not:
- Use
math.random()for keys, nonces, or anything security sensitive - Assume CSPRNG output is truly random (it is pseudorandom, unless you use TrueRandom example)
- Expose CSPRNG state or output directly to untrusted parties
The CSPRNG produces output computationally indistinguishable from random for anyone who does not know the internal state. The auto reseeding limits damage if state is ever found out.