﻿Imports System.Security.Cryptography

''' <summary>
''' Represents a random number generator, a device that produces a sequence of numbers that meet cryptographic requirements for randomness.
''' </summary>
''' <remarks>
''' Seed values are meaningless because this class uses a cryptographic service provider internally rather than a pseudo-random sequence.
''' </remarks>
Public Class CryptoRandom
    Inherits Random
    Implements IDisposable

    ''' <summary>
    ''' The internal random number generator.
    ''' </summary>
    Private ReadOnly rng As New RNGCryptoServiceProvider

    ''' <summary>
    ''' Returns a random number between 0.0 and 1.0.
    ''' </summary>
    ''' <returns>
    ''' A double-precision floating point number greater than or equal to 0.0, and less than 1.0.
    ''' </returns>
    ''' <remarks>
    ''' Uses a cryptographic service provider internally rather than a pseudo-random sequence.
    ''' </remarks>
    Protected Overrides Function Sample() As Double
        Dim data(7) As Byte
        Dim number As ULong

        Do
            'Get 8 random bytes.
            rng.GetBytes(data)

            'Convert the bytes to an unsigned 64-bit number.
            number = BitConverter.ToUInt64(data, 0)
        Loop While number = ULong.MaxValue 'The result must be less than 1.0

        'Divide the number by the largest possible unsigned 64-bit number to get a value in the range 0.0 <= N < 1.0.
        Return number / ULong.MaxValue
    End Function

#Region "IDisposable Support"

    Private disposedValue As Boolean ' To detect redundant calls

    ' IDisposable
    Protected Overridable Sub Dispose(disposing As Boolean)
        If Not Me.disposedValue Then
            If disposing Then
                'Dispose the underlying cryptographic random number generator.
                rng.Dispose()
            End If
        End If

        Me.disposedValue = True
    End Sub

    ' This code added by Visual Basic to correctly implement the disposable pattern.
    Public Sub Dispose() Implements IDisposable.Dispose
        ' Do not change this code.  Put cleanup code in Dispose(disposing As Boolean) above.
        Dispose(True)
        GC.SuppressFinalize(Me)
    End Sub

#End Region

End Class