@@ -74,7 +74,7 @@ public long NextLong()
7474 public long NextLong ( long maxValue )
7575 {
7676 if ( maxValue < 0 )
77- throw new ArgumentOutOfRangeException ( " maxValue" ) ;
77+ throw new ArgumentOutOfRangeException ( nameof ( maxValue ) ) ;
7878
7979 return NextLong ( 0 , maxValue ) ;
8080 } //NextLong()
@@ -96,7 +96,7 @@ public long NextLong(long minValue, long maxValue)
9696 return minValue ;
9797
9898 if ( minValue > maxValue )
99- throw new ArgumentOutOfRangeException ( " minValue" ) ;
99+ throw new ArgumentOutOfRangeException ( nameof ( minValue ) ) ;
100100
101101 ulong diff = decimal . ToUInt64 ( ( decimal ) maxValue - minValue ) ;
102102 ulong upperBound = ulong . MaxValue / diff * diff ;
@@ -136,7 +136,7 @@ public override int Next()
136136 public override int Next ( int maxValue )
137137 {
138138 if ( maxValue < 0 )
139- throw new ArgumentOutOfRangeException ( " maxValue" ) ;
139+ throw new ArgumentOutOfRangeException ( nameof ( maxValue ) ) ;
140140
141141 return Next ( 0 , maxValue ) ;
142142 } //Next()
@@ -158,7 +158,7 @@ public override int Next(int minValue, int maxValue)
158158 return minValue ;
159159
160160 if ( minValue > maxValue )
161- throw new ArgumentOutOfRangeException ( " minValue" ) ;
161+ throw new ArgumentOutOfRangeException ( nameof ( minValue ) ) ;
162162
163163 long diff = ( long ) maxValue - minValue ;
164164 long upperBound = uint . MaxValue / diff * diff ;
@@ -180,8 +180,8 @@ public override int Next(int minValue, int maxValue)
180180 /// </returns>
181181 public override double NextDouble ( )
182182 {
183- const double max = 1.0 + uint . MaxValue ;
184- return GetRandomUInt ( ) / max ;
183+ const double max = 1L << 53 ; // https://en.wikipedia.org/wiki/Double-precision_floating-point_format
184+ return ( GetRandomULong ( ) >> 11 ) / max ;
185185 } //NextDouble()
186186
187187 /// <summary>
@@ -220,7 +220,7 @@ public void NextBytes(byte[] buffer, int offset, int count)
220220 var checkedBufferSegment = new ArraySegment < byte > ( buffer , offset , count ) ; // bounds-validation happens here
221221 if ( count == 0 ) return ;
222222 NextBytesInternal ( checkedBufferSegment ) ;
223- }
223+ } //NextBytes()
224224
225225 void NextBytesInternal ( ArraySegment < byte > bufferSegment )
226226 {
@@ -236,68 +236,50 @@ void NextBytesInternal(ArraySegment<byte> bufferSegment)
236236 throw new CryptographicException ( ( int ) status ) ;
237237 }
238238
239- while ( true )
239+ lock ( _byteCache )
240240 {
241- int currentByteCachePosition = Interlocked . Add ( ref _byteCachePosition , count ) ;
242- if ( currentByteCachePosition <= BYTE_CACHE_SIZE && currentByteCachePosition > 0 )
241+ if ( _byteCachePosition + count <= BYTE_CACHE_SIZE )
243242 {
244- Utils . BlockCopy ( _byteCache , currentByteCachePosition - count , buffer , 0 , count ) ;
243+ Utils . BlockCopy ( _byteCache , _byteCachePosition , buffer , offset , count ) ;
244+ _byteCachePosition += count ;
245245 return ;
246246 }
247247
248- lock ( _byteCache )
248+ status = BCrypt . BCryptGenRandom ( _byteCache , BYTE_CACHE_SIZE ) ;
249+ if ( status == BCrypt . NTSTATUS . STATUS_SUCCESS )
249250 {
250- currentByteCachePosition = _byteCachePosition ; // atomic read
251- if ( currentByteCachePosition > ( BYTE_CACHE_SIZE - count ) || currentByteCachePosition <= 0 )
252- {
253- status = BCrypt . BCryptGenRandom ( _byteCache , BYTE_CACHE_SIZE ) ;
254- if ( status == BCrypt . NTSTATUS . STATUS_SUCCESS )
255- {
256- _byteCachePosition = count ; // atomic write
257- Utils . BlockCopy ( _byteCache , 0 , buffer , 0 , count ) ;
258- return ;
259- }
260-
261- // defensive logic to prevent _byteCachePosition from wrapping into valid range due to BCryptGenRandom failures
262- if ( currentByteCachePosition > BYTE_CACHE_SIZE || currentByteCachePosition < 0 ) _byteCachePosition = BYTE_CACHE_SIZE ;
263-
264- throw new CryptographicException ( ( int ) status ) ;
265- } // if outside the valid range
266- } // lock
267- } // while(true)
268- } //NextBytes()
251+ _byteCachePosition = count ;
252+ Utils . BlockCopy ( _byteCache , 0 , buffer , offset , count ) ;
253+ return ;
254+ }
255+ throw new CryptographicException ( ( int ) status ) ;
256+ } // lock
257+ } //NextBytesInternal()
269258
270259 /// <summary>
271260 /// Gets one random unsigned 32bit integer in a thread safe manner.
272261 /// </summary>
273262 uint GetRandomUInt ( )
274263 {
275264 BCrypt . NTSTATUS status ;
276- while ( true )
265+
266+ lock ( _byteCache )
277267 {
278- int currentByteCachePosition = Interlocked . Add ( ref _byteCachePosition , sizeof ( uint ) ) ;
279- if ( currentByteCachePosition <= BYTE_CACHE_SIZE && currentByteCachePosition > 0 )
280- return BitConverter . ToUInt32 ( _byteCache , currentByteCachePosition - sizeof ( uint ) ) ;
268+ if ( _byteCachePosition + sizeof ( uint ) <= BYTE_CACHE_SIZE )
269+ {
270+ var result = BitConverter . ToUInt32 ( _byteCache , _byteCachePosition ) ;
271+ _byteCachePosition += sizeof ( uint ) ;
272+ return result ;
273+ }
281274
282- lock ( _byteCache )
275+ status = BCrypt . BCryptGenRandom ( _byteCache , BYTE_CACHE_SIZE ) ;
276+ if ( status == BCrypt . NTSTATUS . STATUS_SUCCESS )
283277 {
284- currentByteCachePosition = _byteCachePosition ; // atomic read
285- if ( currentByteCachePosition > ( BYTE_CACHE_SIZE - sizeof ( uint ) ) || currentByteCachePosition <= 0 )
286- {
287- status = BCrypt . BCryptGenRandom ( _byteCache , BYTE_CACHE_SIZE ) ;
288- if ( status == BCrypt . NTSTATUS . STATUS_SUCCESS )
289- {
290- _byteCachePosition = sizeof ( uint ) ; // atomic write
291- return BitConverter . ToUInt32 ( _byteCache , 0 ) ;
292- }
293-
294- // defensive logic to prevent _byteCachePosition from wrapping into valid range due to BCryptGenRandom failures
295- if ( currentByteCachePosition > BYTE_CACHE_SIZE || currentByteCachePosition < 0 ) _byteCachePosition = BYTE_CACHE_SIZE ;
296-
297- throw new CryptographicException ( ( int ) status ) ;
298- } // if outside the valid range
299- } // lock
300- } // while(true)
278+ _byteCachePosition = sizeof ( uint ) ;
279+ return BitConverter . ToUInt32 ( _byteCache , 0 ) ;
280+ }
281+ throw new CryptographicException ( ( int ) status ) ;
282+ } // lock
301283 } //GetRandomUInt()
302284
303285 /// <summary>
@@ -306,31 +288,24 @@ uint GetRandomUInt()
306288 ulong GetRandomULong ( )
307289 {
308290 BCrypt . NTSTATUS status ;
309- while ( true )
291+
292+ lock ( _byteCache )
310293 {
311- int currentByteCachePosition = Interlocked . Add ( ref _byteCachePosition , sizeof ( ulong ) ) ;
312- if ( currentByteCachePosition <= BYTE_CACHE_SIZE && currentByteCachePosition > 0 )
313- return BitConverter . ToUInt64 ( _byteCache , currentByteCachePosition - sizeof ( ulong ) ) ;
294+ if ( _byteCachePosition + sizeof ( ulong ) <= BYTE_CACHE_SIZE )
295+ {
296+ var result = BitConverter . ToUInt64 ( _byteCache , _byteCachePosition ) ;
297+ _byteCachePosition += sizeof ( ulong ) ;
298+ return result ;
299+ }
314300
315- lock ( _byteCache )
301+ status = BCrypt . BCryptGenRandom ( _byteCache , BYTE_CACHE_SIZE ) ;
302+ if ( status == BCrypt . NTSTATUS . STATUS_SUCCESS )
316303 {
317- currentByteCachePosition = _byteCachePosition ; // atomic read
318- if ( currentByteCachePosition > ( BYTE_CACHE_SIZE - sizeof ( ulong ) ) || currentByteCachePosition <= 0 )
319- {
320- status = BCrypt . BCryptGenRandom ( _byteCache , BYTE_CACHE_SIZE ) ;
321- if ( status == BCrypt . NTSTATUS . STATUS_SUCCESS )
322- {
323- _byteCachePosition = sizeof ( ulong ) ; // atomic write
324- return BitConverter . ToUInt64 ( _byteCache , 0 ) ;
325- }
326-
327- // defensive logic to prevent _byteCachePosition from wrapping into valid range due to BCryptGenRandom failures
328- if ( currentByteCachePosition > BYTE_CACHE_SIZE || currentByteCachePosition < 0 ) _byteCachePosition = BYTE_CACHE_SIZE ;
329-
330- throw new CryptographicException ( ( int ) status ) ;
331- } // if outside the valid range
332- } // lock
333- } // while(true)
304+ _byteCachePosition = sizeof ( ulong ) ;
305+ return BitConverter . ToUInt64 ( _byteCache , 0 ) ;
306+ }
307+ throw new CryptographicException ( ( int ) status ) ;
308+ } // lock
334309 } //GetRandomULong()
335310 } //class CryptoRandom
336311
0 commit comments