/// <summary>
        /// Construct a new cryptographically secure random stream object.
        /// </summary>
        /// <param name="a">Algorithm to use.</param>
        /// <param name="pbKey">Initialization key. Must not be <c>null</c>
        /// and must contain at least 1 byte.</param>
        public CryptoRandomStream(CrsAlgorithm a, byte[] pbKey)
        {
            if (pbKey == null)
            {
                Debug.Assert(false); throw new ArgumentNullException("pbKey");
            }

            int cbKey = pbKey.Length;

            if (cbKey <= 0)
            {
                Debug.Assert(false);                 // Need at least one byte
                throw new ArgumentOutOfRangeException("pbKey");
            }

            m_crsAlgorithm = a;

            if (a == CrsAlgorithm.ChaCha20)
            {
                byte[] pbKey32 = new byte[32];
                byte[] pbIV12  = new byte[12];

                using (SHA512Managed h = new SHA512Managed())
                {
                    byte[] pbHash = h.ComputeHash(pbKey);
                    Array.Copy(pbHash, pbKey32, 32);
                    Array.Copy(pbHash, 32, pbIV12, 0, 12);
                    MemUtil.ZeroByteArray(pbHash);
                }

                m_chacha20 = new ChaCha20Cipher(pbKey32, pbIV12, true);
            }
            else if (a == CrsAlgorithm.Salsa20)
            {
                byte[] pbKey32 = CryptoUtil.HashSha256(pbKey);
                byte[] pbIV8   = new byte[8] {
                    0xE8, 0x30, 0x09, 0x4B,
                    0x97, 0x20, 0x5D, 0x2A
                };                                                // Unique constant

                m_salsa20 = new Salsa20Cipher(pbKey32, pbIV8);
            }
            else if (a == CrsAlgorithm.ArcFourVariant)
            {
                // Fill the state linearly
                m_pbState = new byte[256];
                for (int w = 0; w < 256; ++w)
                {
                    m_pbState[w] = (byte)w;
                }

                unchecked
                {
                    byte j = 0, t;
                    int  inxKey = 0;
                    for (int w = 0; w < 256; ++w)                    // Key setup
                    {
                        j += (byte)(m_pbState[w] + pbKey[inxKey]);

                        t            = m_pbState[0];              // Swap entries
                        m_pbState[0] = m_pbState[j];
                        m_pbState[j] = t;

                        ++inxKey;
                        if (inxKey >= cbKey)
                        {
                            inxKey = 0;
                        }
                    }
                }

                GetRandomBytes(512); // Increases security, see cryptanalysis
            }
            else                     // Unknown algorithm
            {
                Debug.Assert(false);
                throw new ArgumentOutOfRangeException("a");
            }
        }