context: using System;
  using System.Globalization;
  using Org.BouncyCastle.Crypto.Digests;
  using Org.BouncyCastle.Crypto.Prng;
  
  namespace Org.BouncyCastle.Security
  {
      public class SecureRandom
  		: Random
      {
  		// Note: all objects of this class should be deriving their random data from
  		// a single generator appropriate to the digest being used.
  		private static readonly IRandomGenerator sha1Generator = new DigestRandomGenerator(new Sha1Digest());
  		private static readonly IRandomGenerator sha256Generator = new DigestRandomGenerator(new Sha256Digest());
  
  		private static readonly SecureRandom[] master = { null };
  		private static SecureRandom Master
  		{
  			get
  			{
  				if (master[0] == null)
  				{
  					IRandomGenerator gen = sha256Generator;
  					gen = new ReversedWindowGenerator(gen, 32);
  					SecureRandom sr = master[0] = new SecureRandom(gen);
  
  					sr.SetSeed(DateTime.Now.Ticks);
  					sr.SetSeed(new ThreadedSeedGenerator().GenerateSeed(24, true));
  					sr.GenerateSeed(1 + sr.Next(32));
  				}
  
  				return master[0];
  			}
  		}
  
  		public static SecureRandom GetInstance(
  			string algorithm)
  		{
  			// TODO Compared to JDK, we don't auto-seed if the client forgets - problem?
  
  			// TODO Support all digests more generally, by stripping PRNG and calling DigestUtilities?
  			string drgName = algorithm.ToUpper(CultureInfo.InvariantCulture);
  
  			IRandomGenerator drg = null;
  			if (drgName == "SHA1PRNG")
  			{
  				drg = sha1Generator;
  			}
  			else if (drgName == "SHA256PRNG")
  			{
  				drg = sha256Generator;
  			}
  
  			if (drg != null)
  			{
  				return new SecureRandom(drg);
  			}
  
  			throw new ArgumentException("Unrecognised PRNG algorithm: " + algorithm, "algorithm");
  		}
  
  		public static byte[] GetSeed(
  			int length)
  		{
  			return Master.GenerateSeed(length);
  		}
  
  		protected IRandomGenerator generator;
  
  		public SecureRandom()
  			: this(sha1Generator)
          {
  			SetSeed(GetSeed(8));
  		}
  
  		public SecureRandom(
  			byte[] inSeed)
  			: this(sha1Generator)
          {
  			SetSeed(inSeed);
          }
  
  		/// <summary>Use the specified instance of IRandomGenerator as random source.</summary>
  		/// <remarks>
  		/// This constructor performs no seeding of either the <c>IRandomGenerator</c> or the
  		/// constructed <c>SecureRandom</c>. It is the responsibility of the client to provide
  		/// proper seed material as necessary/appropriate for the given <c>IRandomGenerator</c>
  		/// implementation.
  		/// </remarks>
  		/// <param name="generator">The source to generate all random bytes from.</param>
  		public SecureRandom(
  			IRandomGenerator generator)
  			: base(0)
  		{
  			this.generator = generator;
  		}
  
  		public virtual byte[] GenerateSeed(
  			int length)
  		{
  			SetSeed(DateTime.Now.Ticks);
  
  			byte[] rv = new byte[length];
  			NextBytes(rv);
  			return rv;
  		}
  
  		public virtual void SetSeed(
  			byte[] inSeed)
          {
  			generator.AddSeedMaterial(inSeed);
          }
  
          public virtual void SetSeed(
  			long seed)
          {
  			generator.AddSeedMaterial(seed);
  		}
  
  		public override int Next()
  		{
  			for (;;)
  			{
  				int i = NextInt() & int.MaxValue;
  
  				if (i != int.MaxValue)
  					return i;
  			}
  		}
  
  		public override int Next(
  			int maxValue)
  		{
  			if (maxValue < 2)
  			{
  				if (maxValue < 0)
  					throw new ArgumentOutOfRangeException("maxValue < 0");
  
  				return 0;
  			}
  
  			// Test whether maxValue is a power of 2
  			if ((maxValue & -maxValue) == maxValue)
  			{
  				int val = NextInt() & int.MaxValue;
  				long lr = ((long) maxValue * (long) val) >> 31;
  				return (int) lr;
  			}
  
  			int bits, result;
  			do
  			{
  				bits = NextInt() & int.MaxValue;
  				result = bits % maxValue;
  			}
  			while (bits - result + (maxValue - 1) < 0); // Ignore results near overflow
  
  			return result;
  		}
  
  		public override int Next(
  			int	minValue,
  			int	maxValue)
  		{
  			if (maxValue <= minValue)
  			{
  				if (maxValue == minValue)
  					return minValue;
  
  				throw new ArgumentException("maxValue cannot be less than minValue");
  			}
  
  			int diff = maxValue - minValue;
  			if (diff > 0)
  				return minValue + Next(diff);
  
  			for (;;)
  			{
  				int i = NextInt();
  
  				if (i >= minValue && i < maxValue)
  					return i;
  			}
  		}
  
  		public override void NextBytes(
  			byte[] buffer)
          {
  			generator.NextBytes(buffer);
          }
  
  		public virtual void NextBytes(
  			byte[]	buffer,
  			int		start,
  			int		length)
  		{
  			generator.NextBytes(buffer, start, length);
  		}
  
  		private static readonly double DoubleScale = System.Math.Pow(2.0, 64.0);
  
  		public override double NextDouble()
  		{
  
gt: 			return Convert.ToDouble((ulong) NextLong()) / DoubleScale;