def encrypt(pk, m, d, t, c_q, p_q): p_0 = pk[0] p_1 = pk[1] u = draw_from_binary(d) e_1 = draw_from_normal(d, c_q) e_2 = draw_from_normal(d, c_q) delta = c_q // t c_0 = mod((p_0 * u) + e_1 + (delta * m), c_q, p_q) c_1 = mod((p_1 * u) + e_2, c_q, p_q) # --- Tests --- assert c_q == delta * t + (c_q % t) return c_0, c_1
def public_keygen(s, d, c_q, p_q): a = draw_from_integer(d, c_q) e = draw_from_normal(d, c_q) pk_0 = mod(-(a * s) + e, c_q, p_q) pk_1 = a # --- Tests --- assert mod(pk_0 + s * pk_1, c_q, p_q) == e return pk_0, pk_1
def public_keygen(s, n, q): N = (n + 1) * int((log2(q) + 1)) A = draw_from_integer((N, n), q) e = draw_from_normal(N, q) b = (A.dot(s) + e) % q P = np.column_stack((b, -A)) # --- Tests --- # Prepend a 1 to the secret key v = np.insert(s, 0, 1) # We should be able to extract the error from the Public key via the Secret Key assert_array_equal(P.dot(v) % q, e) return P
def evaluate_keygen(s, d, T, c_q, p_q): l = floor(log(c_q, T)) rlks = [] # NOTE: [0..l] is inclusive (see: https://en.wikipedia.org/wiki/Interval_(mathematics)#Integer_intervals) for i in range(l + 1): a_i = draw_from_integer(d, c_q) e_i = draw_from_normal(d, c_q) rlk_0 = mod(-(a_i * s) + e_i + ((T**i) * (s**2)), c_q, p_q) rlk_1 = a_i # --- Tests --- assert mod(rlk_0 + (rlk_1 * s - (T**i) * (s**2)), c_q, p_q) == e_i rlks.append((rlk_0, rlk_1)) return rlks
def switch_keygen(s, t, q): s_bin = powers_of_two(s, q) n_s = s.shape[0] n_h_s = s_bin.shape[0] n_t = t.shape[0] A = draw_from_integer((n_h_s, n_t), q) e = draw_from_normal(n_h_s, q) b = (A.dot(t) + e + s_bin) % q P = np.column_stack((b, -A)) # --- Tests --- c_s = draw_from_integer(n_s, q) c_t = switch_key(P, c_s, q) assert np.dot(c_s, s) % q == (np.dot(c_t, np.insert(t, 0, 1)) - np.dot(bit_decomp(c_s, q), e)) % q return P
def secret_keygen(d, c_q): return draw_from_normal(d, c_q)