Skip to the content.

Quantum Random Number Generator (QRNG) API

Overview

The Quantum Random Number Generator (QRNG) models random number generation via quantum measurement. On real quantum hardware, measurements are fundamentally non-deterministic and yield true (quantum) randomness.

⚠️ Important — local simulation is not quantum randomness. By default this module simulates the measurements classically. The unseeded local path draws its outcomes from the OS cryptographically secure RNG (System.Security.Cryptography.RandomNumberGenerator) — CSPRNG-quality, suitable for cryptographic key material, but still classical randomness. True quantum randomness requires executing the circuit on a hardware backend that returns per-shot measurement results.

Key Features:

When to Use:

When NOT to Use (use System.Random instead):


Quick Start

Generate Random Bytes (e.g., Cryptographic Key)

open FSharp.Azure.Quantum.Algorithms

// Generate 256-bit (32-byte) cryptographic key
let keyBytes = QRNG.generateBytes 32
printfn "Key: %s" (System.Convert.ToBase64String(keyBytes))

Generate Random Integer in Range

// Simulate 6-sided die roll
let diceRoll = QRNG.generateInt 6 + 1  // Returns 1-6
printfn "Rolled: %d" diceRoll

// Random index for array of 100 elements
let randomIndex = QRNG.generateInt 100  // Returns 0-99

Generate Random Float [0.0, 1.0)

// Monte Carlo sampling
let randomSample = QRNG.generateFloat()  // Returns float in [0.0, 1.0)
printfn "Sample: %.6f" randomSample

Core Functions

generate

val generate : numBits:int -> QRNGResult

Generates random bits using quantum measurement (Hadamard + measurement).

Parameters:

Returns: QRNGResult containing:

Example:

let result = QRNG.generate 8
printfn "Bits: %A" result.Bits
printfn "As byte: %d" result.AsBytes.[0]
printfn "Entropy: %.3f" result.Entropy

generateInt

val generateInt : maxValue:int -> int

Generates random integer in range [0, maxValue) using rejection sampling.

Parameters:

Returns: Random integer n where 0 ≤ n < maxValue

Example:

// Random number from 0-99
let randomPercent = QRNG.generateInt 100

// Random array index
let arr = [|1; 2; 3; 4; 5|]
let idx = QRNG.generateInt arr.Length
let randomElement = arr.[idx]

generateFloat

val generateFloat : unit -> float

Generates random float in range [0.0, 1.0) with 53-bit precision (IEEE 754 double mantissa).

Returns: Random float in [0.0, 1.0)

Example:

// Monte Carlo estimation of π
let estimatePi samples =
    [1..samples]
    |> List.map (fun _ ->
        let x = QRNG.generateFloat()
        let y = QRNG.generateFloat()
        if x*x + y*y <= 1.0 then 1 else 0)
    |> List.average
    |> (*) 4.0

let pi = estimatePi 10000
printfn "π ≈ %.4f" pi

generateBytes

val generateBytes : numBytes:int -> byte[]

Generates random byte array (8 bits per byte).

Parameters:

Returns: byte[] with random values

Example:

// Generate 256-bit AES key
let aesKey = QRNG.generateBytes 32

// Generate random salt for password hashing
let salt = QRNG.generateBytes 16

Backend Integration

generateWithBackend

val generateWithBackend : 
    numBits:int -> 
    backend:IQuantumBackend -> 
    Async<Result<QRNGResult, string>>

Generates random bits by executing the H-superposition circuit through the specified backend.

⚠️ Randomness source: this path obtains a quantum state from the backend (ExecuteToState) and then samples it once locally with a classical PRNG. With LocalBackend — and any backend that returns a simulated state vector — the resulting bits are classical pseudo-randomness, not hardware quantum randomness. For cryptographic key material prefer generateBits/generateBytes (unseeded → OS CSPRNG).

⚠️ Cost Warning: Most real quantum backends charge per circuit execution. For production QRNG, LocalBackend is recommended unless you specifically need hardware-generated randomness for cryptographic certification.

Parameters:

Returns: Async<Result<QRNGResult, string>>

Note: This API currently uses F# Async<_>. For Task-based async patterns with CancellationToken, see IQuantumBackend.ExecuteToStateAsync in the API Reference.

Example:

open FSharp.Azure.Quantum.Backends

async {
    // Use local simulator (free, fast)
    let backend = LocalBackendFactory.createUnified()
    
    let! result = QRNG.generateWithBackend 32 backend
    
    match result with
    | Ok qrng -> 
        printfn "Generated 32 bits with entropy: %.3f" qrng.Entropy
    | Error err -> 
        printfn "Error: %s" err.Message
}
|> Async.RunSynchronously

Statistical Quality Testing

testRandomness

val testRandomness : bits:bool[] -> RandomnessTest

Performs basic statistical tests on generated bits to assess randomness quality.

Tests Performed:

  1. Frequency Test: Ratio of 1s vs 0s (should be ~0.5)
  2. Run Test: Count of alternations between 0 and 1
  3. Entropy: Shannon entropy (should be ~1.0 for perfect randomness)

Returns: RandomnessTest with:

Example:

let result = QRNG.generate 10000
let test = QRNG.testRandomness result.Bits

printfn "Frequency Ratio: %.3f (expect ~0.500)" test.FrequencyRatio
printfn "Entropy: %.3f (expect ~1.000)" test.Entropy
printfn "Quality: %s" test.Quality

Expected Output:

Frequency Ratio: 0.498 (expect ~0.500)
Entropy: 0.997 (expect ~1.000)
Quality: EXCELLENT

Technical Details

Algorithm

QRNG uses the simplest quantum circuit for true randomness:

  1. Initialize qubits to 0⟩ state
  2. Apply Hadamard gate to each qubit → Creates uniform superposition: ψ⟩ = ( 0⟩ + 1⟩)/√2
  3. Measure in computational basis → Each qubit collapses to 0 or 1 with exactly 50% probability
  4. Extract bits from measurement outcomes

Quantum Advantage: Unlike pseudo-random number generators (PRNGs) which are deterministic and periodic, quantum measurements provide genuine randomness due to the fundamental indeterminism of quantum mechanics.

Entropy Calculation

Shannon entropy for binary sequence:

H = -p₀ log₂(p₀) - p₁ log₂(p₁)

Where:

Perfect randomness: H = 1.0 (maximum entropy for binary)

Batch Processing

To avoid excessive memory usage, QRNG processes bits in batches of ≤20 qubits at a time (state vector size = 2²⁰ = 1M complex numbers). This allows generating up to 1 million random bits efficiently.


References


See Also