X931Rng
                    class X931Rng
                
                using System;
namespace Org.BouncyCastle.Crypto.Prng
{
    internal class X931Rng
    {
        private const long BLOCK64_RESEED_MAX = 32768;
        private const long BLOCK128_RESEED_MAX = 8388608;
        private const int BLOCK64_MAX_BITS_REQUEST = 4096;
        private const int BLOCK128_MAX_BITS_REQUEST = 262144;
        private readonly IBlockCipher mEngine;
        private readonly IEntropySource mEntropySource;
        private readonly byte[] mDT;
        private readonly byte[] mI;
        private readonly byte[] mR;
        private byte[] mV;
        private long mReseedCounter = 1;
        internal IEntropySource EntropySource => mEntropySource;
        internal X931Rng(IBlockCipher engine, byte[] dateTimeVector, IEntropySource entropySource)
        {
            mEngine = engine;
            mEntropySource = entropySource;
            mDT = new byte[engine.GetBlockSize()];
            Array.Copy(dateTimeVector, 0, mDT, 0, mDT.Length);
            mI = new byte[engine.GetBlockSize()];
            mR = new byte[engine.GetBlockSize()];
        }
        internal int Generate(byte[] output, int outputOff, int outputLen, bool predictionResistant)
        {
            int num;
            if (mR.Length == 8) {
                if (mReseedCounter > 32768)
                    return -1;
                if (outputLen > 512) {
                    num = 4096;
                    throw new ArgumentException("Number of bits per request limited to " + num.ToString(), "output");
                }
            } else {
                if (mReseedCounter > 8388608)
                    return -1;
                if (outputLen > 32768) {
                    num = 262144;
                    throw new ArgumentException("Number of bits per request limited to " + num.ToString(), "output");
                }
            }
            if (predictionResistant || mV == null) {
                mV = mEntropySource.GetEntropy();
                if (mV.Length != mEngine.GetBlockSize())
                    throw new InvalidOperationException("Insufficient entropy returned");
            }
            int num2 = outputLen / mR.Length;
            for (int i = 0; i < num2; i++) {
                mEngine.ProcessBlock(mDT, 0, mI, 0);
                Process(mR, mI, mV);
                Process(mV, mR, mI);
                Array.Copy(mR, 0, output, outputOff + i * mR.Length, mR.Length);
                Increment(mDT);
            }
            int num3 = outputLen - num2 * mR.Length;
            if (num3 > 0) {
                mEngine.ProcessBlock(mDT, 0, mI, 0);
                Process(mR, mI, mV);
                Process(mV, mR, mI);
                Array.Copy(mR, 0, output, outputOff + num2 * mR.Length, num3);
                Increment(mDT);
            }
            mReseedCounter++;
            return outputLen * 8;
        }
        internal void Reseed()
        {
            mV = mEntropySource.GetEntropy();
            if (mV.Length != mEngine.GetBlockSize())
                throw new InvalidOperationException("Insufficient entropy returned");
            mReseedCounter = 1;
        }
        private void Process(byte[] res, byte[] a, byte[] b)
        {
            for (int i = 0; i != res.Length; i++) {
                res[i] = (byte)(a[i] ^ b[i]);
            }
            mEngine.ProcessBlock(res, 0, res, 0);
        }
        private void Increment(byte[] val)
        {
            int num = val.Length - 1;
            while (num >= 0 && ++val[num] == 0) {
                num--;
            }
        }
    }
}