# INFO # @author: TheCookingSenpai # @github: https://github.com/TheCookingSenpai # @homepage: https://github.com/TheCookingSenpai/AmbianceRNG # # @description: # This is a very simple proof of concept for generating true random numbers by # feeding the python pseudo-random number generator with ambiental noise. # While is not enforced, the ambiental noise is expected to be generated by # having an input device that is able to capture sound from the environment. # A cheap and simple way to generate ambiental noise is to use a simple radio # with antenna and headphone out and to connect the headphone to your computer. # Be sure to tune your radio into an empty frequency so that the ambiental # recording is purely background noise. # import pyaudio import wave from bitstring import BitArray import hashlib import random class AmbianceRNG: def __init__(self): self.CHUNK = 1024 self.FORMAT = pyaudio.paInt16 self.CHANNELS = 1 self.RATE = 44100 self.RECORD_SECONDS = 2 self.WAVE_OUTPUT_FILENAME = "seed.wav" self.frames = [] self.stream = None self.device = None self.bin_bytes = '' def record_seed(self): # Opening our device and setting up the stream for recording self.device = pyaudio.PyAudio() self.stream = self.device.open(format=self.FORMAT, channels=self.CHANNELS, rate=self.RATE, input=True, frames_per_buffer=self.CHUNK) print("* detecting ambiental noise...") # Recording ambiental noise for _ in range(int(self.RATE / self.CHUNK * self.RECORD_SECONDS)): data = self.stream.read(self.CHUNK) self.frames.append(data) print("* done recording ambiental noise") self.stream.stop_stream() self.stream.close() self.device.terminate() return self.frames def save_seed(self): wf = wave.open(self.WAVE_OUTPUT_FILENAME, 'wb') wf.setnchannels(self.CHANNELS) wf.setsampwidth(self.device.get_sample_size(self.FORMAT)) wf.setframerate(self.RATE) wf.writeframes(b''.join(self.frames)) wf.close() def serialize_seed(self): print("* serializing ambiental noise... [ ]", end="\b\b", flush=True) counter = 1 # Initialized to 1 to avoid unnecessary assignment later bin_bytes = '' with open(self.WAVE_OUTPUT_FILENAME, 'rb') as f: all_bytes = f.read() raw_bytes = all_bytes[44:] # Removing the first 44 bytes self.bin_bytes = BitArray(raw_bytes) print("\b\b\n* done serializing ambiental noise") # Logging to file with open("seed.txt", "w") as f: f.write(str(self.bin_bytes)) def get_random_number(self, min, max): # Using an hash representation is way faster than using the whole string hash_object = hashlib.sha256(str(self.bin_bytes).encode()) hex_dig = hash_object.hexdigest() print(f"* using seed {hex_dig}") with open("hash.txt", "a") as f: f.write(f"{hex_dig}\n") # Seeding the prng random.seed(hex_dig, version=2) # Getting a random number arn = random.randint(min, max) with open("random.txt", "a+") as f: f.write(f"{arn} ") with open("seeds_history.txt", "a+") as f: f.write(f"{hex_dig}\n") return arn if __name__ == "__main__": counter = 0 while True: arng = AmbianceRNG() arng.record_seed() arng.save_seed() arng.serialize_seed() rn = arng.get_random_number(1, 100) counter += 1 print(f"Produced {counter} random numbers") print(rn)