text: // Copyright (c) 2009-2010 Satoshi Nakamoto
  // Copyright (c) 2009-2014 The Bitcoin Core developers
  // Distributed under the MIT software license, see the accompanying
  // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  
  #ifndef NAVCOIN_RANDOM_H
  #define NAVCOIN_RANDOM_H
  
  #include <crypto/chacha20.h>
  #include <uint256.h>
  
  #include <limits>
  
  #include <stdint.h>
  
  /* Seed OpenSSL PRNG with additional entropy data */
  void RandAddSeed();
  
  /**
   * Functions to gather random data via the OpenSSL PRNG
   */
  void GetRandBytes(unsigned char* buf, int num);
  uint64_t GetRand(uint64_t nMax);
  uint64_t GetRand(uint64_t nMin, uint64_t nMax);
  int GetRandInt(int nMax);
  uint256 GetRandHash();
  
  /**
   * Function to gather random data from multiple sources, failing whenever any
   * of those source fail to provide a result.
   */
  void GetStrongRandBytes(unsigned char* buf, int num);
  
  /**
   * Seed insecure_rand using the random pool.
   * @param Deterministic Use a deterministic seed
   */
  void seed_insecure_rand(bool fDeterministic = false);
  
  /**
   * MWC RNG of George Marsaglia
   * This is intended to be fast. It has a period of 2^59.3, though the
   * least significant 16 bits only have a period of about 2^30.1.
   *
   * @return random value
   */
  extern uint32_t insecure_rand_Rz;
  extern uint32_t insecure_rand_Rw;
  static inline uint32_t insecure_rand(void)
  {
      insecure_rand_Rz = 36969 * (insecure_rand_Rz & 65535) + (insecure_rand_Rz >> 16);
      insecure_rand_Rw = 18000 * (insecure_rand_Rw & 65535) + (insecure_rand_Rw >> 16);
      return (insecure_rand_Rw << 16) + insecure_rand_Rz;
  }
  
  /**
   * Fast randomness source. This is seeded once with secure random data, but
   * is completely deterministic and does not gather more entropy after that.
   *
   * This class is not thread-safe.
   */
  class FastRandomContext {
  private:
      bool requires_seed;
      ChaCha20 rng;
  
      unsigned char bytebuf[64];
      int bytebuf_size;
  
      uint64_t bitbuf;
      int bitbuf_size;
  
      void RandomSeed();
  
      void FillByteBuffer()
      {
          if (requires_seed) {
              RandomSeed();
          }
          rng.Keystream(bytebuf, sizeof(bytebuf));
          bytebuf_size = sizeof(bytebuf);
      }
  
      void FillBitBuffer()
      {
          bitbuf = rand64();
          bitbuf_size = 64;
      }
  
  public:
      explicit FastRandomContext(bool fDeterministic = false) noexcept;
  
      /** Initialize with explicit seed (only for testing) */
      explicit FastRandomContext(const uint256& seed) noexcept;
  
      // Do not permit copying a FastRandomContext (move it, or create a new one to get reseeded).
      FastRandomContext(const FastRandomContext&) = delete;
      FastRandomContext(FastRandomContext&&) = delete;
      FastRandomContext& operator=(const FastRandomContext&) = delete;
  
      /** Move a FastRandomContext. If the original one is used again, it will be reseeded. */
      FastRandomContext& operator=(FastRandomContext&& from) noexcept;
  
      /** Generate a random 64-bit integer. */
      uint64_t rand64() noexcept
      {
          if (bytebuf_size < 8) FillByteBuffer();
          uint64_t ret = ReadLE64(bytebuf + 64 - bytebuf_size);
          bytebuf_size -= 8;
          return ret;
      }
  
      /** Generate a random (bits)-bit integer. */
      uint64_t randbits(int bits) noexcept {
          if (bits == 0) {
              return 0;
          } else if (bits > 32) {
              return rand64() >> (64 - bits);
          } else {
              if (bitbuf_size < bits) FillBitBuffer();
              uint64_t ret = bitbuf & (~(uint64_t)0 >> (64 - bits));
              bitbuf >>= bits;
              bitbuf_size -= bits;
              return ret;
          }
      }
  
      /** Generate a random integer in the range [0..range). */
      uint64_t randrange(uint64_t range) noexcept
      {
          --range;
          int bits = CountBits(range);
          while (true) {
              uint64_t ret = randbits(bits);
              if (ret <= range) return ret;
          }
      }
  
      /** Generate random bytes. */
      std::vector<unsigned char> randbytes(size_t len);
  
      /** Generate a random 32-bit integer. */
      uint32_t rand32() noexcept { return randbits(32); }
  
      /** generate a random uint256. */
      uint256 rand256() noexcept;
  
      /** Generate a random boolean. */
      bool randbool() noexcept { return randbits(1); }
  
      // Compatibility with the C++11 UniformRandomBitGenerator concept
      typedef uint64_t result_type;
      static constexpr uint64_t min() { return 0; }
      static constexpr uint64_t max() { return std::numeric_limits<uint64_t>::max(); }
      inline uint64_t operator()() noexcept { return rand64(); }
  };
  
  #endif // NAVCOIN_RANDOM_H
  