""" cryptopy.entropy.prn_rijndael

    A Psudeo Random Number Generator based on Rijndael_256k_256b
    The algorithm is based on Section 13.4 of:
    "AES Proposal: Rijndael", Joan Daemen, Vincent Rijmen

    Copyright (c) 2002 by Paul A. Lambert
    Read LICENSE.txt for license information.
"""

from cryptopy.cipher.rijndael import Rijndael
from cryptopy.cipher.base     import noPadding
from binascii import b2a_hex

defaultSeed = "An arbirary 32 byte string!!!!!!"  # can be changed by the truely paranoid

class PRN_Rijndael:
    """ A Psudeo Random Number Generator based on Rijndael_256k_256b
        The algorithm is based on Section 13.4 of:
        "AES Proposal: Rijndael", Joan Daemen, Vincent Rijmen
    """
    def __init__(self, seed=defaultSeed):
        self.__algorithm = Rijndael(padding=noPadding(),keySize=32, blockSize=32)
        self.reset()
        self.reseed(seed)

    def reset(self):
        self.__algorithm.setKey(self.__algorithm.keySize*chr(0))      # set key to all zeros
        self.__state = self.__algorithm.blockSize*chr(0)              # a single block of zeros

    def reseed(self,seed):
        while len(seed) > 0 :
            if len(seed) < self.__algorithm.blockSize:
                block = seed + (self.__algorithm.blockSize-len(seed))*chr(0)
                seed = ''
            else:
                block =  seed[:self.__algorithm.blockSize]
                seed = seed[self.__algorithm.blockSize:]
            self.__algorithm.setKey( self.__algorithm.encrypt(block) )

    def getBytes(self, numBytes):
        """ Return a psuedo random byte string of length numBytes """
        bytes = ''
        while len(bytes)< numBytes :
            bytes = bytes + self.getSomeBytes()
        return bytes[:numBytes]     # truncate to the requested length

    def getSomeBytes(self):
        """ Psuedo random bytes are generated 16 bytes at a time.
            The state is updated by applying Rijndael using the Cipher
            Key. The first 128 bits of the state are output as a pseudorandom number.
        """
        self.__state = self.__algorithm.encrypt(self.__state)
        return self.__state[:16]








