//
//! \file  libecc/rng.h
//! \brief Random number generator.
//!
//! This header file declares <code>class libecc::rng</code>, a pseudo random number generator.
//
// This file is part of the libecc package.
// Copyright (C) 2002, by
//
// Carlo Wood, Run on IRC <carlo@alinoe.com>
// RSA-1024 0x624ACAD5 1997-01-26                    Sign & Encrypt
// Fingerprint16 = 32 EC A7 B6 AC DB 65 A6  F6 F6 55 DD 1C DC FF 61
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
//

#ifndef LIBECC_RNG_H
#define LIBECC_RNG_H

#include <libecc/bitset.h>

namespace libecc {

class rng {
  public:
    static unsigned int const S_pool_size = 521;		//!< Pool size in bits.  This RNG uses a pool of 521 bits.

  private:
    uint32_t M_pool[S_pool_size / 32 + 1];
    bitset<512> M_out;
    unsigned int M_out_cnt;

    class bit_iterator {
      private:
	uint32_t* M_ptr;
	uint32_t M_head_mask;
      public:
	bit_iterator(uint32_t* pool, int bit) : M_ptr(pool + bit / 32), M_head_mask(1 << bit % 32) { }
	void toggle(void) const { *M_ptr ^= M_head_mask; }
	void set(void) { *M_ptr |= M_head_mask; }
	void clear(void) { *M_ptr &= ~M_head_mask; }
	uint32_t increment_and_test(uint32_t* pool)
	{
	  M_head_mask <<= 1;
	  if (M_head_mask == 0)
	  {
	    M_head_mask = 1;
	    ++M_ptr;
	  }
	  else if (M_head_mask == (1 << (S_pool_size % 32)) && M_ptr - pool == S_pool_size / 32)
	  {
	    M_ptr = pool;
	    M_head_mask = 1;
	  }
	  return (*M_ptr & M_head_mask);
	}
    };

    uint32_t* M_entropy_ptr;
    uint32_t const* M_entropy_ptr_end;

    bit_iterator M_head;
    bit_iterator M_fbp1;
    bit_iterator M_fbp2;
    bit_iterator M_fbp3;
    bit_iterator M_fbp4;
    bit_iterator M_fbp5;
    bit_iterator M_fbp6;
    bit_iterator M_fbp7;
    bit_iterator M_fbp8;
    bit_iterator M_fbp9;
   
  public:
    /**
     * \brief The type of the constructor argument.
     */
    typedef bitset<S_pool_size> pool_type;
    rng(pool_type const& seed);

    void generate_512_bits(void);
    /** \brief Retrieve a reference to the 512 bits that were generated with a call to rng::generate_512_bits(). */
    bitset<512> const& get_512_bits(void) const { return M_out; }

    void add_entropy(uint32_t const* noise, unsigned int number_of_ints);

    /**
     * \brief Add entropy from a bitset.
     *
     * Calls <code>add_entropy(uint32_t const*, unsigned int)</code>.
     */
    template<unsigned int n>
      void add_entropy(bitset<n> const noise)
      {
	add_entropy(reinterpret_cast<uint32_t const*>(noise.digits_ptr()), bitset<n>::digits * sizeof(bitset_digit_t) / 4);
      }
};

} // namespace libecc

#endif // LIBECC_RNG_H
