-
Notifications
You must be signed in to change notification settings - Fork 2
/
randomness_choice.py
157 lines (107 loc) · 3.98 KB
/
randomness_choice.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
#!/usr/bin/python3
import sys
from randomness_mixer import get_random_bytes
from randomness_mixer import get_hash
global_accumulator = list()
global_use_mouse = True
def use_mouse(b):
assert type(b) == bool
global global_use_mouse
global_use_mouse = b
def refill_global_accumulator():
global global_accumulator
global global_use_mouse
print("Refilling the random numbers accumulator - refill_global_accumulator() called.")
this_hash = b''
#this_hash = get_hash()
#from hashlib import sha512
#this_hash = sha512(get_random_bytes(256)).digest()
this_hash = get_hash(use_mouse=global_use_mouse)
assert this_hash != b''
assert isinstance(global_accumulator, list)
global_accumulator += list(this_hash)
assert isinstance(global_accumulator, list)
def get_random_bytes_from_global_accumulator(howmany):
assert isinstance(howmany, int)
assert howmany > 0
global global_accumulator
while len(global_accumulator) < howmany:
refill_global_accumulator()
result = bytearray()
for c in range(howmany):
result += bytes(global_accumulator.pop(0).to_bytes(1, 'big'))
assert len(result) == howmany
return result
def how_many_bytes_are_needed(n):
if n < 0:
raise ValueError("The number should not be negative.")
i = 0
while(n > 0):
n = n >> 8;
i += 1;
return i
def get_integer_from_accumulator(size):
assert size > 0
assert isinstance(size, int)
return int.from_bytes(get_random_bytes_from_global_accumulator(size), 'big')
# get random integer from [0, exclusive_upper_bound)
def random_below(exclusive_upper_bound):
if not (isinstance(exclusive_upper_bound, int) and (exclusive_upper_bound > 0)):
raise ValueError("Upper bound must be positive integer.")
if (exclusive_upper_bound == 1):
return 0
inclusive_upper_bound = exclusive_upper_bound - 1
# Intentionally adding one more byte to reduce the cycles
how_many_bytes = 1 + how_many_bytes_are_needed(inclusive_upper_bound)
source_exclusive_upper_bound = 256 ** how_many_bytes
source_inclusive_upper_bound = source_exclusive_upper_bound - 1
assert source_exclusive_upper_bound >= exclusive_upper_bound
# floor division is used
buckets = source_inclusive_upper_bound // exclusive_upper_bound
assert isinstance(buckets, int)
assert buckets > 0
while (True):
r = get_integer_from_accumulator(how_many_bytes) // buckets
if r < ( exclusive_upper_bound):
return r
def main():
global global_use_mouse
if len(sys.argv) > 2:
print("Too many arguments.")
quit()
elif len(sys.argv) == 2:
if (sys.argv[1] == "nomouse") or (sys.argv[1] == "nomice"):
print("The mouse will not be used as randomness source.")
use_mouse(False)
else:
print("Invalid argument.")
quit()
while True:
try:
exclusive_range = int(input("Exclusive range: "))
except ValueError as detail:
print(" Wrong input.", detail)
continue
if exclusive_range < 1:
print ("Invalid number, it should be positive.")
elif exclusive_range < 2:
print ("It does not make senese to ask for a random number between 0 and 0.")
else:
break
while True:
try:
how_many = int(input("How many random numbers you need: "))
except ValueError as detail:
print(" Wrong input.", detail)
continue
if how_many < 1:
print ("It does not make senese to ask for a less than 1 random number.")
else:
break
list_of_random_numbers = list()
for c in range(how_many):
list_of_random_numbers.append(random_below(exclusive_range))
print (how_many, "random numbers between 0 and", exclusive_range - 1, ":")
print (list_of_random_numbers)
if __name__ == "__main__":
main()