File: System\Diagnostics\RandomNumberGenerator.cs
Web Access
Project: src\src\libraries\System.Diagnostics.DiagnosticSource\src\System.Diagnostics.DiagnosticSource.csproj (System.Diagnostics.DiagnosticSource)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
namespace System.Diagnostics
{
    /// <summary>
    /// RandomNumberGenerator implementation is the 64-bit random number generator based on the Xoshiro256StarStar algorithm (known as shift-register generators).
    /// </summary>
    internal sealed class RandomNumberGenerator
    {
        [ThreadStatic] private static RandomNumberGenerator? t_random;
 
        private ulong _s0, _s1, _s2, _s3;
 
        public static RandomNumberGenerator Current => t_random ??= new RandomNumberGenerator();
 
        public unsafe RandomNumberGenerator()
        {
            do
            {
                Guid g1 = Guid.NewGuid();
                Guid g2 = Guid.NewGuid();
                ulong* g1p = (ulong*)&g1;
                ulong* g2p = (ulong*)&g2;
                _s0 = *g1p;
                _s1 = *(g1p + 1);
                _s2 = *g2p;
                _s3 = *(g2p + 1);
 
                // Guid uses the 4 most significant bits of the first long as the version which would be fixed and not randomized.
                // and uses 2 other bits in the second long for variants which would be fixed and not randomized too.
                // let's overwrite the fixed bits in each long part by the other long.
                _s0 = (_s0 & 0x0FFFFFFFFFFFFFFF) | (_s1 & 0xF000000000000000);
                _s2 = (_s2 & 0x0FFFFFFFFFFFFFFF) | (_s3 & 0xF000000000000000);
                _s1 = (_s1 & 0xFFFFFFFFFFFFFF3F) | (_s0 & 0x00000000000000C0);
                _s3 = (_s3 & 0xFFFFFFFFFFFFFF3F) | (_s2 & 0x00000000000000C0);
            }
            while ((_s0 | _s1 | _s2 | _s3) == 0);
        }
 
        private static ulong Rol64(ulong x, int k) => (x << k) | (x >> (64 - k));
 
        public long Next()
        {
            ulong result = Rol64(_s1 * 5, 7) * 9;
            ulong t = _s1 << 17;
 
            _s2 ^= _s0;
            _s3 ^= _s1;
            _s1 ^= _s2;
            _s0 ^= _s3;
 
            _s2 ^= t;
            _s3 = Rol64(_s3, 45);
 
            return (long)result;
        }
    }
}