Exemple #1
0
    def divide_and_round_q_last_inplace(self, input):
        base_q_size = self.base_q.size
        last_ptr = input[base_q_size - 1]

        # Add (qi-1)/2 to change from flooring to rounding
        last_modulus = self.base_q.base[-1]
        half = last_modulus >> 1

        last_ptr = [(x + half) % last_modulus for x in last_ptr]

        temp_ptr = []
        for i in range(base_q_size - 1):
            temp_ptr = [x % self.base_q.base[i] for x in last_ptr]
            half_mod = half % self.base_q.base[i]

            temp_ptr = [(x - half_mod) % self.base_q.base[i] for x in temp_ptr]

            input[i] = poly_sub_mod(input[i], temp_ptr, self.base_q.base[i],
                                    self.coeff_count)

            # qk^(-1) * ((ct mod qi) - (ct mod qk)) mod qi
            input[i] = [(x * self.inv_q_last_mod_q[i]) % self.base_q.base[i]
                        for x in input[i]]

        return input
Exemple #2
0
    def _sub_cipher_cipher(self, ct1, ct2):
        """Subtract two ciphertexts.

        Args:
            ct1 (Ciphertext): First polynomial argument (Minuend).
            ct2 (Ciphertext): Second polynomial argument (Subtrahend).

        Returns:
            A Ciphertext object with value equivalent to result of subtraction of two provided
                arguments.
        """
        ct1, ct2 = copy.deepcopy(ct1.data), copy.deepcopy(ct2.data)
        result = ct2 if len(ct2) > len(ct1) else ct1
        min_size, max_size = min(len(ct1), len(ct2)), max(len(ct1), len(ct2))

        for i in range(min_size):
            for j in range(len(self.coeff_modulus)):
                result[i][j] = poly_sub_mod(ct1[i][j], ct2[i][j],
                                            self.coeff_modulus[j],
                                            self.poly_modulus)

        for i in range(min_size + 1, max_size):
            for j in range(len(self.coeff_modulus)):
                result[i][j] = poly_negate_mod(result[i][j],
                                               self.coeff_modulus[j])

        return CipherText(result)
Exemple #3
0
    def _switch_key_inplace(self, ct, key):

        if not isinstance(key, RelinKey):
            raise RuntimeError("Relinearization key is invalid")

        param_id = ct.param_id
        ct = ct.data
        key_vector = key.data
        context_data = self.context.context_data_map[param_id]
        key_context = self.context.context_data_map[self.context.key_param_id]

        coeff_modulus = context_data.param.coeff_modulus
        decomp_mod_count = len(coeff_modulus)
        key_mod = key_context.param.coeff_modulus
        key_mod_count = len(key_mod)
        rns_mod_count = decomp_mod_count + 1

        target = ct[-1]  # Last component of ciphertext

        modswitch_factors = key_context.rns_tool.inv_q_last_mod_q

        for i in range(decomp_mod_count):

            local_small_poly_0 = copy.deepcopy(target[i])

            temp_poly = [[[0] for x in range(rns_mod_count)],
                         [[0] for x in range(rns_mod_count)]]

            for j in range(rns_mod_count):
                index = key_mod_count - 1 if j == decomp_mod_count else j

                if key_mod[i] <= key_mod[index]:
                    local_small_poly_1 = copy.deepcopy(local_small_poly_0)
                else:
                    local_small_poly_1 = [
                        x % key_mod[index] for x in local_small_poly_0
                    ]

                for k in range(2):
                    local_small_poly_2 = poly_mul_mod(
                        local_small_poly_1,
                        key_vector[i][k][index],
                        key_mod[index],
                        self.poly_modulus,
                    )
                    temp_poly[k][j] = poly_add_mod(local_small_poly_2,
                                                   temp_poly[k][j],
                                                   key_mod[index],
                                                   self.poly_modulus)

        # Results are now stored in temp_poly[k]
        # Modulus switching should be performed
        for k in range(2):
            temp_poly_ptr = temp_poly[k][decomp_mod_count]
            temp_last_poly_ptr = temp_poly[k][decomp_mod_count]

            temp_poly_ptr = [x % key_mod[-1] for x in temp_poly_ptr]

            # Add (p-1)/2 to change from flooring to rounding.
            half = key_mod[-1] >> 1
            temp_last_poly_ptr = [(x + half) % key_mod[-1]
                                  for x in temp_last_poly_ptr]

            encrypted_ptr = ct[k]
            for j in range(decomp_mod_count):
                temp_poly_ptr = temp_poly[k][j]

                temp_poly_ptr = [x % key_mod[j] for x in temp_poly_ptr]
                local_small_poly = [x % key_mod[j] for x in temp_last_poly_ptr]
                half_mod = half % key_mod[j]

                local_small_poly = [(x - half_mod) % key_mod[j]
                                    for x in local_small_poly]

                # ((ct mod qi) - (ct mod qk)) mod qi
                temp_poly_ptr = poly_sub_mod(temp_poly_ptr, local_small_poly,
                                             key_mod[j], self.poly_modulus)

                # qk^(-1) * ((ct mod qi) - (ct mod qk)) mod qi
                temp_poly_ptr = [(x * modswitch_factors[j]) % key_mod[j]
                                 for x in temp_poly_ptr]

                encrypted_ptr[j] = poly_add_mod(temp_poly_ptr,
                                                encrypted_ptr[j], key_mod[j],
                                                self.poly_modulus)

        return CipherText(ct[0:2], param_id)