import math class BhashException(Exception): pass class Bhash: """ Hash manipulation class. The hash is internally treated as a big-endinan integer. This allows for easy implementation of operations such as modulo. Note: The consumed bits are calculated using math.log() so the exact number may be inprecise. """ def __init__(self): self.bhash = None self.bits_avail = 0 self.bits_used = 0.0 def from_bytes(self, buf: bytes): """ Initialize a Bhash from a bytes object """ self.bhash = int.from_bytes(buf, byteorder='little') self.bits_avail = len(buf) * 8 self.bits_used = 0.0 def modulo(self, mod: int) -> int: """ Treat the hash as a bigint and divide it by mod. The hash is updated with the division result while the module value is returned. """ self.bits_used += math.log(mod) / math.log(2) if self.bits_used > self.bits_avail: raise BhashException("Consumed all bits in hash") r = self.bhash % mod self.bhash //= mod return r