164 lines
4.3 KiB
Python
164 lines
4.3 KiB
Python
|
import hashlib
|
||
|
import secrets
|
||
|
from struct import pack, pack_into, unpack_from
|
||
|
|
||
|
def sha(x):
|
||
|
m = hashlib.sha256()
|
||
|
m.update(x)
|
||
|
result = m.digest()
|
||
|
return result[0] & 0b1
|
||
|
|
||
|
def bit_at_index(buffer, index):
|
||
|
offset = (index >> 3) % len(buffer)
|
||
|
return buffer[offset] & (1 << (index & 0b111)) != 0
|
||
|
|
||
|
def evaluate(f, x):
|
||
|
stack = []
|
||
|
offset = 0
|
||
|
value = 0
|
||
|
while offset < len(f):
|
||
|
opcode = f[offset]
|
||
|
offset += 1
|
||
|
if opcode == 0 or opcode == 1:
|
||
|
stack.append((opcode, value))
|
||
|
value = 0
|
||
|
elif opcode == 2:
|
||
|
if len(stack) == 0:
|
||
|
return (value, offset)
|
||
|
(last_opcode, _) = stack[-1]
|
||
|
if last_opcode > 0:
|
||
|
stack.append((0, value))
|
||
|
value = 0
|
||
|
continue
|
||
|
right = value
|
||
|
(_, left) = stack.pop()
|
||
|
(opcode, value) = stack.pop()
|
||
|
value ^= ((left & right) ^ (opcode & 0b1))
|
||
|
else:
|
||
|
try:
|
||
|
index = unpack_from('I', f, offset)[0]
|
||
|
offset += 4
|
||
|
if bit_at_index(x, index):
|
||
|
value ^= 1
|
||
|
except:
|
||
|
break
|
||
|
|
||
|
while len(stack) > 0:
|
||
|
(opcode, other_value) = stack.pop()
|
||
|
if opcode == 0:
|
||
|
right = other_value
|
||
|
(opcode, left) = stack.pop()
|
||
|
value ^= ((left & right) ^ (opcode & 0b1))
|
||
|
value ^= other_value ^ (opcode & 0b1)
|
||
|
return (value, offset)
|
||
|
|
||
|
def random_generator():
|
||
|
return secrets.token_bytes(256)
|
||
|
|
||
|
def random_input():
|
||
|
return secrets.token_bytes(4)
|
||
|
|
||
|
def generate(generator, sample):
|
||
|
f_size = 1024
|
||
|
f = bytearray(f_size)
|
||
|
x = bytearray(4) + sample
|
||
|
for i in range(0, f_size):
|
||
|
build_value = 0
|
||
|
for j in range(0, 8):
|
||
|
step = i * 8 + j
|
||
|
pack_into('H', x, 0, step)
|
||
|
(value, _) = evaluate(generator, x)
|
||
|
build_value <<= 1
|
||
|
build_value |= value
|
||
|
f[i] = build_value
|
||
|
return f
|
||
|
|
||
|
def sample(N):
|
||
|
inputs = [random_input() for i in range(0, N)]
|
||
|
outputs = [sha(x) for x in inputs]
|
||
|
return (inputs, outputs)
|
||
|
|
||
|
def augment_inputs(inputs, layers):
|
||
|
augmented_inputs = []
|
||
|
for x in inputs:
|
||
|
x_n = bytearray(1) + x
|
||
|
for layer in layers:
|
||
|
build_value = 0
|
||
|
for candidate in layer:
|
||
|
(value, _) = evaluate(candidate, x_n)
|
||
|
build_value <<= 1
|
||
|
build_value |= value
|
||
|
x_n[0] = build_value
|
||
|
augmented_inputs.append(x_n)
|
||
|
return augmented_inputs
|
||
|
|
||
|
def pack_sample(inputs, outputs):
|
||
|
sample = bytearray()
|
||
|
for i in range(0, len(inputs)):
|
||
|
sample += inputs[i]
|
||
|
sample += bytearray([outputs[i]])
|
||
|
return sample
|
||
|
|
||
|
def compute_score(f, inputs, outputs):
|
||
|
correct = 0.0
|
||
|
for i in range(0, len(inputs)):
|
||
|
(value, _) = evaluate(f, inputs[i])
|
||
|
if value == outputs[i]:
|
||
|
correct += 1
|
||
|
return correct / len(outputs)
|
||
|
|
||
|
def evaluate_generator(g):
|
||
|
num_candidates = 8
|
||
|
num_train_samples = 64
|
||
|
num_test_samples = 1000
|
||
|
num_epochs = 10
|
||
|
threshold = 0
|
||
|
|
||
|
layers = []
|
||
|
for epoch in range(0, num_epochs):
|
||
|
difficulty = 0
|
||
|
layer = []
|
||
|
candidate = 0
|
||
|
scores = []
|
||
|
while candidate < num_candidates:
|
||
|
(x, y) = sample(num_train_samples)
|
||
|
x_n = augment_inputs(x, layers)
|
||
|
f = generate(g, pack_sample(x_n, y))
|
||
|
print(f)
|
||
|
|
||
|
(x, y) = sample(num_test_samples)
|
||
|
x_n = augment_inputs(x, layers)
|
||
|
score = compute_score(f, x_n, y)
|
||
|
|
||
|
if score < threshold - difficulty * 0.0001:
|
||
|
difficulty += 1
|
||
|
continue
|
||
|
|
||
|
print(epoch, score, difficulty)
|
||
|
|
||
|
layer.append(f)
|
||
|
scores.append(score)
|
||
|
difficulty = 0
|
||
|
candidate += 1
|
||
|
threshold = sum(scores) / len(scores)
|
||
|
layers.append(layer)
|
||
|
return threshold
|
||
|
|
||
|
def main():
|
||
|
num_random_candidates = 1000
|
||
|
|
||
|
g = None
|
||
|
score = 0
|
||
|
|
||
|
for i in range(0, num_random_candidates):
|
||
|
g_n = random_generator()
|
||
|
print(g_n)
|
||
|
score_n = evaluate_generator(g_n)
|
||
|
print(i, score_n)
|
||
|
if score > score_n:
|
||
|
score = score_n
|
||
|
g = g_n
|
||
|
|
||
|
|
||
|
if __name__ == "__main__":
|
||
|
main()
|