Coretex
random_generator.py
1 # Copyright (C) 2023 Coretex LLC
2 
3 # This file is part of Coretex.ai
4 
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License as
7 # published by the Free Software Foundation, either version 3 of the
8 # License, or (at your option) any later version.
9 
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU Affero General Public License for more details.
14 
15 # You should have received a copy of the GNU Affero General Public License
16 # along with this program. If not, see <https://www.gnu.org/licenses/>.
17 
18 from cryptography.hazmat.primitives import hashes
19 
20 
21 class ByteBuffer:
22 
23  def __init__(self, data: bytes) -> None:
24  self.data = data
25  self.position = 0
26 
27  def update(self, data: bytes) -> None:
28  """
29  Sets the internal state of the buffer
30  to the provided bytes array
31 
32  Parameters
33  ----------
34  data : bytes
35  new internal state of the buffer
36  """
37 
38  self.data = data
39  self.position = 0
40 
41  def get(self) -> int:
42  """
43  Retrieves the byte at the current position, and
44  increments internal state
45 
46  Returns
47  -------
48  int -> byte at the current position
49 
50  Raises
51  ------
52  OverflowError -> if the bytes have been exhausted
53  """
54 
55  if self.position >= len(self.data):
56  raise OverflowError
57 
58  byte = self.data[self.position]
59  self.position += 1
60 
61  return byte
62 
63 
64 class Random:
65 
66  """
67  Random generator based on recursive hashing the provided seed
68  using the provided hashing algorithm. Entropy is equal to the
69  provided seed.
70  """
71 
72  def __init__(self, seed: bytes, algorithm: hashes.HashAlgorithm) -> None:
73  self.algorithmalgorithm = algorithm
74 
75  numberGenerator = hashes.Hash(algorithm)
76  numberGenerator.update(seed)
77 
78  self._currentState_currentState = numberGenerator.finalize()
79  self._buffer_buffer = ByteBuffer(self._currentState_currentState)
80 
81  def getRandomByte(self) -> int:
82  """
83  Returns
84  -------
85  int -> randomly generated byte value
86  """
87 
88  try:
89  return self._buffer_buffer.get()
90  except OverflowError:
91  # Raised when all bytes from current state have been exhausted
92  # so we need to generate new bytes
93  numberGenerator = hashes.Hash(self.algorithmalgorithm)
94  numberGenerator.update(self._currentState_currentState)
95 
96  self._currentState_currentState = numberGenerator.finalize()
97  self._buffer_buffer.update(self._currentState_currentState)
98 
99  return self.getRandomBytegetRandomByte()
100 
101  def getRandomBytes(self, count: int) -> bytes:
102  """
103  Parameters
104  ----------
105  count : int
106  # of how many bytes should be generated
107 
108  Returns
109  -------
110  bytes -> randomly generated bytes array
111  """
112 
113  values = bytearray(count)
114 
115  for i in range(count):
116  values[i] = self.getRandomBytegetRandomByte()
117 
118  return values