def verifier_search(cts, best_guess, use_n=64, net=net6): #print(best_guess); ck1 = best_guess[0] ^ low_weight ck2 = best_guess[1] ^ low_weight n = len(ck1) ck1 = np.repeat(ck1, n) keys1 = np.copy(ck1) ck2 = np.tile(ck2, n) keys2 = np.copy(ck2) ck1 = np.repeat(ck1, use_n) ck2 = np.repeat(ck2, use_n) ct0a = np.tile(cts[0][0:use_n], n * n) ct1a = np.tile(cts[1][0:use_n], n * n) ct0b = np.tile(cts[2][0:use_n], n * n) ct1b = np.tile(cts[3][0:use_n], n * n) pt0a, pt1a = sp.dec_one_round((ct0a, ct1a), ck1) pt0b, pt1b = sp.dec_one_round((ct0b, ct1b), ck1) pt0a, pt1a = sp.dec_one_round((pt0a, pt1a), ck2) pt0b, pt1b = sp.dec_one_round((pt0b, pt1b), ck2) X = sp.convert_to_binary([pt0a, pt1a, pt0b, pt1b]) Z = net.predict(X, batch_size=10000) Z = Z / (1 - Z) Z = np.log2(Z) Z = Z.reshape(-1, use_n) v = np.mean(Z, axis=1) * len(cts[0]) m = np.argmax(v) val = v[m] key1 = keys1[m] key2 = keys2[m] return (key1, key2, val)
def key_average(ct0a, ct1a, ct0b, ct1b, keys, net): n = len(keys) pt0a, pt1a = sp.dec_one_round((ct0a, ct1a), keys) pt0b, pt1b = sp.dec_one_round((ct0b, ct1b), keys) X = sp.convert_to_binary([pt0a, pt1a, pt0b, pt1b]) Z = net.predict(X, batch_size=10000) Z = Z / (1 - Z) v = np.average(Z) v = v / (v + 1) return (v)
def key_rank_one_round(nr, dist, 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.ex_key_test(key, nr); k1 = ks[nr-1]; ct0a, ct1a = sp.enc_test((pt0a, pt1a), ks); ct0b, ct1b = sp.enc_test((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); d0,d1 = c0a ^ c0b, c1a ^ c1b; d = d0 ^ (d1.astype(np.uint32) << 16); Z = dist[d]; Z = np.log2(Z); Z = np.sum(Z,axis=0); rank0 = np.sum(Z > Z[k1]); rank1 = np.sum(Z >= Z[k1]); return(rank0, rank1);
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 bayesian_key_recovery(cts, net=net7, m=m7, s=s7, num_cand=32, num_iter=5, seed=None): n = len(cts[0]) keys = np.random.choice(2**(WORD_SIZE - 2), num_cand, replace=False) scores = 0 best = 0 if (not seed is None): keys = np.copy(seed) ct0a, ct1a, ct0b, ct1b = np.tile(cts[0], num_cand), np.tile( cts[1], num_cand), np.tile(cts[2], num_cand), np.tile(cts[3], num_cand) scores = np.zeros(2**(WORD_SIZE - 2)) used = np.zeros(2**(WORD_SIZE - 2)) all_keys = np.zeros(num_cand * num_iter, dtype=np.uint16) all_v = np.zeros(num_cand * num_iter) for i in range(num_iter): k = np.repeat(keys, n) c0a, c1a = sp.dec_one_round((ct0a, ct1a), k) c0b, c1b = sp.dec_one_round((ct0b, ct1b), k) X = sp.convert_to_binary([c0a, c1a, c0b, c1b]) Z = net.predict(X, batch_size=10000) Z = Z.reshape(num_cand, -1) means = np.mean(Z, axis=1) Z = Z / (1 - Z) Z = np.log2(Z) v = np.sum(Z, axis=1) all_v[i * num_cand:(i + 1) * num_cand] = v all_keys[i * num_cand:(i + 1) * num_cand] = np.copy(keys) scores = bayesian_rank_kr(keys, means, m=m, s=s) tmp = np.argpartition(scores + used, num_cand) keys = tmp[0:num_cand] r = np.random.randint(0, 4, num_cand, dtype=np.uint16) r = r << 14 keys = keys ^ r return (all_keys, scores, all_v)
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)
def test_bayes(cts, it=1, cutoff1=10, cutoff2=10, net=net7, net_help=net6, m_main=m7, m_help=m6, s_main=s7, s_help=s6, verify_breadth=None): n = len(cts[0]) if (verify_breadth is None): verify_breadth = len(cts[0][0]) alpha = sqrt(n) best_val = -100.0 best_key = (0, 0) best_pod = 0 bp = 0 bv = -100.0 keys = np.random.choice(2**WORD_SIZE, 32, replace=False) eps = 0.001 local_best = np.full(n, -10) num_visits = np.full(n, eps) guess_count = np.zeros(2**16, dtype=np.uint16) for j in range(it): priority = local_best + alpha * np.sqrt(log2(j + 1) / num_visits) i = np.argmax(priority) num_visits[i] = num_visits[i] + 1 if (best_val > cutoff2): improvement = (verify_breadth > 0) while improvement: k1, k2, val = verifier_search([ cts[0][best_pod], cts[1][best_pod], cts[2][best_pod], cts[3][best_pod] ], best_key, net=net_help, use_n=verify_breadth) improvement = (val > best_val) if (improvement): best_key = (k1, k2) best_val = val return (best_key, j) keys, scores, v = bayesian_key_recovery( [cts[0][i], cts[1][i], cts[2][i], cts[3][i]], num_cand=32, num_iter=5, net=net, m=m_main, s=s_main) vtmp = np.max(v) if (vtmp > local_best[i]): local_best[i] = vtmp if (vtmp > bv): bv = vtmp bp = i if (vtmp > cutoff1): l2 = [i for i in range(len(keys)) if v[i] > cutoff1] for i2 in l2: c0a, c1a = sp.dec_one_round((cts[0][i], cts[1][i]), keys[i2]) c0b, c1b = sp.dec_one_round((cts[2][i], cts[3][i]), keys[i2]) keys2, scores2, v2 = bayesian_key_recovery( [c0a, c1a, c0b, c1b], num_cand=32, num_iter=5, m=m6, s=s6, net=net_help) vtmp2 = np.max(v2) if (vtmp2 > best_val): best_val = vtmp2 best_key = (keys[i2], keys2[np.argmax(v2)]) best_pod = i improvement = (verify_breadth > 0) while improvement: k1, k2, val = verifier_search([ cts[0][best_pod], cts[1][best_pod], cts[2][best_pod], cts[3][best_pod] ], best_key, net=net_help, use_n=verify_breadth) improvement = (val > best_val) if (improvement): best_key = (k1, k2) best_val = val return (best_key, it)
def evaluate_ciphertexts(ct): ct4, ct5 = sp.dec_one_round((ct[0], ct[1]), 0) ct6, ct7 = sp.dec_one_round((ct[2], ct[3]), 0) X = sp.convert_to_binary([ct[0], ct[1], ct[2], ct[3], ct4, ct5, ct6, ct7]) Z = model.predict(X, batch_size=10000) return (Z.flatten())