def tpr_fixed_key(net, n, key, nr=7, diff=(0x40, 0x0), batch_size=5000): pt0a = np.frombuffer(urandom(2 * n), dtype=np.uint16) pt1a = np.frombuffer(urandom(2 * n), dtype=np.uint16) pt0b, pt1b = pt0a ^ diff[0], pt1a ^ diff[1] ks = sp.expand_key(key, nr) ct0a, ct1a = sp.encrypt((pt0a, pt1a), ks) ct0b, ct1b = sp.encrypt((pt0b, pt1b), ks) X = sp.convert_to_binary([ct0a, ct1a, ct0b, ct1b]) Z = net.predict(X, batch_size=batch_size).flatten() acc = np.sum(Z > 0.5) / n v = 1 - Z mse = np.mean(v * v) return (acc, mse)
def make_testset(n, nr=7, diff=(0x40, 0x0)): Y = np.frombuffer(urandom(n), dtype=np.uint8) Y = Y & 1 pt0a = np.frombuffer(urandom(2 * n), dtype=np.uint16) pt1a = np.frombuffer(urandom(2 * n), dtype=np.uint16) pt0b, pt1b = pt0a ^ diff[0], pt1a ^ diff[1] keys = np.frombuffer(urandom(8 * n), dtype=np.uint16).reshape(4, -1) ks = sp.expand_key(keys, nr) ct0a, ct1a = sp.encrypt((pt0a, pt1a), ks) ct0b, ct1b = sp.encrypt((pt0b, pt1b), ks) num_rnd = np.sum(Y == 0) ct0b[Y == 0] = np.frombuffer(urandom(2 * num_rnd), dtype=np.uint16) ct1b[Y == 0] = np.frombuffer(urandom(2 * num_rnd), dtype=np.uint16) return ([ct0a, ct1a, ct0b, ct1b], Y)
def test(n): pt0a = np.frombuffer(urandom(2 * n), dtype=np.uint16) pt1a = np.frombuffer(urandom(2 * n), dtype=np.uint16) pt0b, pt1b = pt0a ^ 0x40, pt1a ^ 0x0 keys = np.frombuffer(urandom(8 * n), dtype=np.uint16).reshape(4, -1) ks = sp.expand_key(keys, 7) ct0a, ct1a = sp.encrypt((pt0a, pt1a), ks) ct0b, ct1b = sp.encrypt((pt0b, pt1b), ks) Z1 = evaluate_ciphertexts([ct0a, ct1a, ct0b, ct1b]) r = np.frombuffer(urandom(8 * n), dtype=np.uint16).reshape(4, -1) Z0 = evaluate_ciphertexts(r) tpr, tnr = np.sum(Z1 > 0.5), np.sum(Z0 < 0.5) tpr = tpr / n tnr = tnr / n acc = (tpr + tnr) / 2 print("Acc: ", acc, ", TPR: ", tpr, ", TNR: ", tnr)
def gen_challenge(n, nr, diff=(0x211, 0xa04), neutral_bits=[20, 21, 22, 14, 15, 23], keyschedule='real'): pt0, pt1 = gen_plain(n) pt0a, pt1a, pt0b, pt1b = make_structure(pt0, pt1, diff=diff, neutral_bits=neutral_bits) pt0a, pt1a = sp.dec_one_round((pt0a, pt1a), 0) pt0b, pt1b = sp.dec_one_round((pt0b, pt1b), 0) key = gen_key(nr) if (keyschedule is 'free'): key = np.frombuffer(urandom(2 * nr), dtype=np.uint16) ct0a, ct1a = sp.encrypt((pt0a, pt1a), key) ct0b, ct1b = sp.encrypt((pt0b, pt1b), key) return ([ct0a, ct1a, ct0b, ct1b], key)
def wrong_key_decryption(n, diff=(0x0040, 0x0), nr=7, net=net7): means = np.zeros(2**16) sig = np.zeros(2**16) for i in range(2**16): keys = np.frombuffer(urandom(8 * n), dtype=np.uint16).reshape(4, -1) ks = sp.expand_key(keys, nr + 1) #ks[nr-1] = 17123; pt0a = np.frombuffer(urandom(2 * n), dtype=np.uint16) pt1a = np.frombuffer(urandom(2 * n), dtype=np.uint16) pt0b, pt1b = pt0a ^ diff[0], pt1a ^ diff[1] ct0a, ct1a = sp.encrypt((pt0a, pt1a), ks) ct0b, ct1b = sp.encrypt((pt0b, pt1b), ks) rsubkeys = i ^ ks[nr] #rsubkeys = rdiff ^ 0; c0a, c1a = sp.dec_one_round((ct0a, ct1a), rsubkeys) c0b, c1b = sp.dec_one_round((ct0b, ct1b), rsubkeys) X = sp.convert_to_binary([c0a, c1a, c0b, c1b]) Z = net.predict(X, batch_size=10000) Z = Z.flatten() means[i] = np.mean(Z) sig[i] = np.std(Z) return (means, sig)
def key_rank_one_round(nr, net, n_blocks=1, diff=(0x0040, 0x0)): pt0a = np.frombuffer(urandom(2 * n_blocks), dtype=np.uint16).reshape(n_blocks, -1) pt1a = np.frombuffer(urandom(2 * n_blocks), dtype=np.uint16).reshape(n_blocks, -1) pt0b, pt1b = pt0a ^ diff[0], pt1a ^ diff[1] pt0a, pt1a = sp.dec_one_round((pt0a, pt1a), 0) pt0b, pt1b = sp.dec_one_round((pt0b, pt1b), 0) key = np.frombuffer(urandom(8), dtype=np.uint16) ks = sp.expand_key(key, nr) k1 = ks[nr - 1] ct0a, ct1a = sp.encrypt((pt0a, pt1a), ks) ct0b, ct1b = sp.encrypt((pt0b, pt1b), ks) trial_keys = np.arange(2**16) c0a, c1a = sp.dec_one_round((ct0a, ct1a), trial_keys) c0b, c1b = sp.dec_one_round((ct0b, ct1b), trial_keys) c1a = np.tile(c1a, 2**16) c1b = np.tile(c1b, 2**16) #the next two lines are the only bits of this function that change #if instead of a neural network the difference distribution table is used for inference #in particular, in this case, conversion to network input is replaced by calculation of trial decryption differences #Z is then calculated simply by looking up the relevant transition probabilities in the ddt #instead of a neural net, the function then expects as second input a table of size 2**32 X = sp.convert_to_binary( [c0a.flatten(), c1a.flatten(), c0b.flatten(), c1b.flatten()]) Z = net.predict(X, batch_size=10000) Z = Z / (1 - Z) Z = np.log2(Z) Z = Z.reshape(n_blocks, -1) Z = np.sum(Z, axis=0) rank0 = np.sum(Z > Z[k1]) rank1 = np.sum(Z >= Z[k1]) return (rank0, rank1)
elif (sys.argv[11] == "fix_diff"): diff = (int(sys.argv[12], 16), int(sys.argv[13], 16)) if (loop == 1): keys = np.repeat(np.frombuffer(urandom(8), dtype=np.uint16).reshape(4, -1), n, axis=1) plain0_0 = np.frombuffer(urandom(2 * n), dtype=np.uint16) plain0_1 = np.frombuffer(urandom(2 * n), dtype=np.uint16) plain1_0 = plain0_0 ^ diff[0] plain1_1 = plain0_1 ^ diff[1] ks = sp.expand_key(keys, (r_start - 1) + nr) cdata0 = sp.encrypt((plain0_0, plain0_1), ks, r_start) cdata1 = sp.encrypt((plain1_0, plain1_1), ks, r_start) cdata0_mid = sp.encrypt((plain0_0, plain0_1), ks[0:r_mid], r_start) cdata1_mid = sp.encrypt((plain1_0, plain1_1), ks[0:r_mid], r_start) X = convert_to_binary_64_block(np.array(cdata0 ^ cdata1), 16, 2) elif (sys.argv[1] == "simon"): diff_default = (int(file_name.split('_')[4][1:-1].split(',')[0]), int(file_name.split('_')[4][1:-1].split(',')[1])) if (sys.argv[11] == "default_diff"): diff = diff_default elif (sys.argv[11] == "random_diff" and loop == 1): diff = (randint(0, (2**16) - 1), randint(0, (2**16) - 1)) elif (sys.argv[11] == "fix_diff"): diff = (int(sys.argv[12], 16), int(sys.argv[13], 16)) if (loop == 1):