def prepare_first_box_MM(sk, root, unroot, ninv, beta, k): sk.goto_ntt(root) M = np.prod(beta) N = sk.modulus Ninv_M = goto_crt(xgcd(N, M)[1], beta, k) fb = {} for dim in range(sk.degree): print_progress(dim, tmp_sk.degree, 64) key = "fb_dim_"+str(dim) fb[key] = [[0]*32 for i in range(32)] s = sk.vector[dim] s = goto_crt(s, beta, k) for j in range(32): a = goto_crt(j, beta, k) for l in range(32): b = goto_crt(l, beta, k) fb[key][j][l] = int( (int(((a[0] * s[0] + b[0]) * (-Ninv_M[0])) % beta[0])) + (int(((a[1] * s[1] + b[1]) * (-Ninv_M[1])) % beta[1]) << 5) + (int(((a[2] * s[2] + b[2]) * (-Ninv_M[2])) % beta[2]) << 10) + (int(((a[3] * s[3] + b[3]) * (-Ninv_M[3])) % beta[3]) << 15) + (int(((a[4] * s[4] + b[4]) * (-Ninv_M[4])) % beta[4]) << 20) ) print_progress(tmp_sk.degree, tmp_sk.degree, 64) sk.goback_ntt(unroot, ninv) return fb
def prepare_second_box_MM3(sk, a1_r, a2_r, a1_ma, a2_ma, root, unroot, ninv, beta, beta_p, k): # compute intermediate encoding values to limit # number of products in Montgomery rot = a2_r + a1_r * sk mask = -(a2_ma + a1_ma * sk) # create alternate key tmp_sk and fake key tmp_sz tmp_sk = sk * rot tmp_sz = sk * mask # go to ntt rot.goto_ntt(root) mask.goto_ntt(root) tmp_sk.goto_ntt(root) tmp_sz.goto_ntt(root) # prepare Montgomery parameters # N = tmp_sk.modulus M = np.prod(beta) M_p = np.prod(beta_p) Minv_M_p = goto_crt(xgcd(M, M_p)[1], beta_p, k) # N_M_p = goto_crt(N, beta_p, k) sb = {} for dim in range(tmp_sk.degree): key = "sb_dim_"+str(dim) sb[key] = [[0]*32 for i in range(32)] # go to crt s = tmp_sk.vector[dim] s = goto_crt(s, beta_p, k) sz = tmp_sz.vector[dim] sz = goto_crt(sz, beta_p, k) r = rot.vector[dim] r = goto_crt(r, beta_p, k) m = mask.vector[dim] m = goto_crt(m, beta_p, k) # parse all possible input values for j in range(32): a = goto_crt(j, beta_p, k) for l in range(32): b = goto_crt(l, beta_p, k) # compute decoding function sb[key][j][l] = int( (int(((a[0] * s[0] + b[0] * r[0] + r[0] * m[0]) * Minv_M_p[0]) % beta_p[0])) + (int(((a[1] * s[1] + b[1] * r[1] + r[1] * m[1]) * Minv_M_p[1]) % beta_p[1]) << 5) + (int(((a[2] * s[2] + b[2] * r[2] + r[2] * m[2]) * Minv_M_p[2]) % beta_p[2]) << 10) + (int(((a[3] * s[3] + b[3] * r[3] + r[3] * m[3]) * Minv_M_p[3]) % beta_p[3]) << 15) + (int(((a[4] * s[4] + b[4] * r[4] + r[4] * m[4]) * Minv_M_p[4]) % beta_p[4]) << 20) ) print_progress(dim, tmp_sk.degree, 64) return sb
def mont_mult(cls, dim, a, b, N): # set up for Montgomery B = cls.white['beta'] B_p = cls.white['beta_p'] k = cls.white['k'] # a and b in base M a_M = goto_crt(a, B, k) b_M = goto_crt(b, B, k) # a and b in base M' a_M_p = goto_crt(a, B_p, k) b_M_p = goto_crt(b, B_p, k) # base M M = np.prod(B) # base M' M_p = np.prod(B_p) # inv(N) mod M # Ninv_M = goto_crt(xgcd(N, M)[1], B, k) # inv(N) mod M' Minv_M_p = goto_crt(xgcd(M, M_p)[1], B_p, k) # N in base M' N_M_p = goto_crt(N, B_p, k) # start computing q # q = [((a_M[i] * s_M[i] + b_M[i]) *\ # (-Ninv_M[i]))%B[i] for i in range(k)] fb = cls.white['fb_dim_' + str(dim)] q = [0] * k q[0] = fb[a_M[0]][b_M[0]] % (1 << 5) q[1] = (fb[a_M[1]][b_M[1]] % (1 << 10)) >> 5 q[2] = (fb[a_M[2]][b_M[2]] % (1 << 15)) >> 10 q[3] = (fb[a_M[3]][b_M[3]] % (1 << 20)) >> 15 q[4] = (fb[a_M[4]][b_M[4]]) >> 20 # shift from base B to B' q = goback_crt(q, B, k) q = goto_crt(q, B_p, k) # compute r # r = [((a_M_p[i] * s_M_p[i] + b_M_p[i] + q[i]*N_M_p[i])\ # * Minv_M_p[i])%B_p[i] for i in range(k) ] sb = cls.white['sb_dim_' + str(dim)] r = [(q[i] * N_M_p[i] * Minv_M_p[i]) % B_p[i] for i in range(k)] r[0] += sb[a_M_p[0]][b_M_p[0]] % (1 << 5) r[1] += (sb[a_M_p[1]][b_M_p[1]] % (1 << 10)) >> 5 r[2] += (sb[a_M_p[2]][b_M_p[2]] % (1 << 15)) >> 10 r[3] += (sb[a_M_p[3]][b_M_p[3]] % (1 << 20)) >> 15 r[4] += (sb[a_M_p[4]][b_M_p[4]]) >> 20 # go back to B from B' r = goback_crt(r, B_p, k) return r * M
def prepare_second_box_MM(sk, root, unroot, ninv, beta, beta_p, k): sk.goto_ntt(root) # N = sk.modulus M = np.prod(beta) M_p = np.prod(beta_p) Minv_M_p = goto_crt(xgcd(M, M_p)[1], beta_p, k) # N_M_p = goto_crt(N, beta_p, k) sb = {} for dim in range(sk.degree): print_progress(dim, tmp_sk.degree, 64) key = "sb_dim_"+str(dim) sb[key] = [[0]*32 for i in range(32)] s = sk.vector[dim] s = goto_crt(s, beta_p, k) for j in range(32): a = goto_crt(j, beta_p, k) for l in range(32): b = goto_crt(l, beta_p, k) sb[key][j][l] = int( (int(((a[0] * s[0] + b[0]) * Minv_M_p[0]) % beta_p[0])) + (int(((a[1] * s[1] + b[1]) * Minv_M_p[1]) % beta_p[1]) << 5) + (int(((a[2] * s[2] + b[2]) * Minv_M_p[2]) % beta_p[2]) << 10) + (int(((a[3] * s[3] + b[3]) * Minv_M_p[3]) % beta_p[3]) << 15) + (int(((a[4] * s[4] + b[4]) * Minv_M_p[4]) % beta_p[4]) << 20) ) print_progress(tmp_sk.degree, tmp_sk.degree, 64) sk.goback_ntt(unroot, ninv) return sb
def write_data(degree, modulus, beta, beta_p, k, chal=0): # set WB keys pka, pkb, sk = key_gen(degree, modulus) # set homomorphic masks if chal 1 one = np.zeros(degree) one[0] = 1 a1_o, a2_o = encrypt(one, pka, pkb, degree, modulus) zero = np.zeros(degree) a1_z, a2_z = encrypt(zero, pka, pkb, degree, modulus) # set homomorphic masks if chal 2 rotate = np.zeros(degree) rot = rand.randint(0, degree) rotate[rot] = 1 a1_rot, a2_rot = encrypt(rotate, pka, pkb, degree, modulus) mask = np.zeros(degree) for i in range(degree): mask[i] = rand.randint(0, 1) a1_ma, a2_ma = encrypt(mask, pka, pkb, degree, modulus) # set root for NTT, this need to be static (put in pub data) root = find_primitive_root(2*degree, modulus-1, modulus) unroot = xgcd(root, modulus)[1] ninv = xgcd(degree, modulus)[1] # writing private data # private data should only be accessed for testing purposes # remove otherwise d = {'sk': sk.vector.tolist(), 'a1_o': a1_o.vector.tolist(), 'a2_o': a2_o.vector.tolist(), 'a1_z': a1_z.vector.tolist(), 'a2_z': a2_z.vector.tolist() } with open('private_data.json', 'w') as f: json.dump(d, f) # writing public encryption data d = {'degree': degree, 'modulus': modulus, 'pka': pka.vector.tolist(), 'pkb': pkb.vector.tolist() } with open('pub_enc_data.json', 'w') as f: json.dump(d, f) # writing whiteboxed decryption data d = {'root': root, 'unroot': unroot, 'ninv': ninv, 'beta': beta, 'beta_p': beta_p, 'k': k, 'mask': mask.tolist(), 'rotate': rot, 'chal': chal } # f = open('wb_dec_data.json', 'w') # json.dump(d, f) # writing lookup tables for white montgomery multiplication (need 2 set) # if chal, no encodings if chal == 0: print("prepare_first_box_MM") d.update(prepare_first_box_MM(sk, root, unroot, ninv, beta, k)) print("prepare_second_box_MM") d.update(prepare_second_box_MM( sk, root, unroot, ninv, beta, beta_p, k)) elif chal == 1: print("prepare_first_box_MM2") d.update(prepare_first_box_MM2( sk, a1_o, a2_o, a1_z, a2_z, root, unroot, ninv, beta, k)) print("prepare_second_box_MM2") d.update(prepare_second_box_MM2( sk, a1_o, a2_o, a1_z, a2_z, root, unroot, ninv, beta, beta_p, k)) elif chal == 2: print("prepare_first_box_MM3") d.update(prepare_first_box_MM3( sk, a1_rot, a2_rot, a1_ma, a2_ma, root, unroot, ninv, beta, k)) print("prepare_second_box_MM3") d.update(prepare_second_box_MM3( sk, a1_rot, a2_rot, a1_ma, a2_ma, root, unroot, ninv, beta, beta_p, k)) with open('wb_dec_data.json', 'w') as f: json.dump(d, f)
def prepare_second_box_MM2(sk, a1_o, a2_o, a1_z, a2_z, root, unroot, ninv, beta, beta_p, k): # compute intermediate encoding values to limit # number of products in Montgomery one = a2_o + a1_o * sk zero = -(a2_z + a1_z * sk) # create alternate key tmp_sk and fake key tmp_sz tmp_sk = sk * one tmp_sz = sk * zero # go to ntt one.goto_ntt(root) zero.goto_ntt(root) tmp_sk.goto_ntt(root) tmp_sz.goto_ntt(root) # prepare Montgomery parameters # N = tmp_sk.modulus M = np.prod(beta) M_p = np.prod(beta_p) Minv_M_p = goto_crt(xgcd(M, M_p)[1], beta_p, k) # N_M_p = goto_crt(N, beta_p, k) sb = {} for dim in range(tmp_sk.degree): print_progress(dim, tmp_sk.degree, 64) key = "sb_dim_"+str(dim) sb[key] = [[0]*32 for i in range(32)] # go to crt s = tmp_sk.vector[dim] s = goto_crt(s, beta_p, k) sz = tmp_sz.vector[dim] sz = goto_crt(sz, beta_p, k) o = one.vector[dim] o = goto_crt(o, beta_p, k) z = zero.vector[dim] z = goto_crt(z, beta_p, k) # parse all possible input values for j in range(32): a = goto_crt(j, beta_p, k) for l in range(32): b = goto_crt(l, beta_p, k) # compute decoding function sb[key][j][l] = int( (int(((a[0] * s[0] + b[0] * o[0] + a[0] * sz[0] + b[0] * z[0]) * Minv_M_p[0]) % beta_p[0])) + (int(((a[1] * s[1] + b[1] * o[1] + a[1] * sz[1] + b[1] * z[1]) * Minv_M_p[1]) % beta_p[1]) << 5) + (int(((a[2] * s[2] + b[2] * o[2] + a[2] * sz[2] + b[2] * z[2]) * Minv_M_p[2]) % beta_p[2]) << 10) + (int(((a[3] * s[3] + b[3] * o[3] + a[3] * sz[3] + b[3] * z[3]) * Minv_M_p[3]) % beta_p[3]) << 15) + (int(((a[4] * s[4] + b[4] * o[4] + a[4] * sz[4] + b[4] * z[4]) * Minv_M_p[4]) % beta_p[4]) << 20) ) print_progress(tmp_sk.degree, tmp_sk.degree, 64) return sb