Example #1
0
    def decrypt_scale_and_round(self, input):
        """Perform the remaining procedure of decryptions process after getting the result of
        [c0 + c1 * sk + c2 * sk^2 ...]_q.

        Args:
            input: Result of [c0 + c1 * sk + c2 * sk^2 ...]_q.

        Returns:
            A 1-dim list representing plaintext polynomial of the decrypted result.
        """
        result = [0] * self._coeff_count

        # Computing |gamma * t|_qi * ct(s)
        temp = [0] * self.base_q_size
        for i in range(self.base_q_size):
            temp[i] = [0] * self._coeff_count

        for j in range(self.base_q_size):
            for i in range(self._coeff_count):
                temp[j][i] = multiply_mod(
                    input[j][i], self.prod_t_gamma_mod_q[j], self.base_q.base[j]
                )

        # Base conversion: convert from q to {t, gamma}
        base_q_to_t_gamma_conv = BaseConvertor(self.base_q, self._base_t_gamma)
        temp_t_gamma = base_q_to_t_gamma_conv.fast_convert_list(temp, self._coeff_count)

        # Multiply by -prod(q)^(-1) mod {t, gamma}
        for j in range(self._base_t_gamma_size):
            for i in range(self._coeff_count):
                temp_t_gamma[j][i] = multiply_mod(
                    temp_t_gamma[j][i], self.neg_inv_q_mod_t_gamma[j], self._base_t_gamma.base[j]
                )

        # Need to correct values in temp_t_gamma (gamma component only) which are larger
        # than floor(gamma/2)
        gamma_div_2 = gamma >> 1

        # Now compute the subtraction to remove error and perform final multiplication by gamma
        # inverse mod t
        for i in range(self._coeff_count):
            # Need correction because of centered mod
            if temp_t_gamma[1][i] > gamma_div_2:

                # Compute -(gamma - a) instead of (a - gamma)
                result[i] = (temp_t_gamma[0][i] + (gamma - temp_t_gamma[1][i]) % self._t) % self._t
            else:
                # No correction needed
                result[i] = (temp_t_gamma[0][i] - temp_t_gamma[1][i]) % self._t

            # If this coefficient was non-zero, multiply by t^(-1)
            if 0 != result[i]:

                # Perform final multiplication by gamma inverse mod t
                result[i] = multiply_mod(result[i], self._inv_gamma_mod_t, self._t)

        return result
Example #2
0
    def fastbconv_m_tilde(self, input):
        """
        Require: Input in q
        Ensure: Output in Bsk U {m_tilde}
        """

        # We need to multiply first the input with m_tilde mod q
        # This is to facilitate Montgomery reduction in the next step of multiplication
        # This is NOT an ideal approach: as mentioned in BEHZ16, multiplication by
        # m_tilde can be easily merge into the base conversion operation; however, then
        # we could not use the BaseConvertor as below without modifications.

        temp = [[
            multiply_mod(input[i][j], self.m_tilde, self.base_q.base[i])
            for j in range(self.coeff_count)
        ] for i in range(len(self.q))]

        # Now convert to Bsk
        result = self.base_q_to_Bsk_conv.fast_convert_list(
            temp, self.coeff_count)

        # Finally convert to {m_tilde}
        result += self.base_q_to_m_tilde_conv.fast_convert_list(
            temp, self.coeff_count)
        return result
Example #3
0
    def fast_convert_list(self, input, count):
        """Converts the plain/base of input list from input base to output base
        declared at the time of initialization of BaseConvertor class.

        Args:
            input: A list of integers needed to be converted from input base to output base.
            count: An integer denoting the coefficient count of output base.

        Returns:
            A list of integers converted from input base plain to output base plain.
        """

        output = [0] * self._obase.size
        for i in range(self._obase.size):
            output[i] = [0] * count

        temp = [0] * self._ibase.size
        for i in range(self._ibase.size):
            temp[i] = [0] * count

        for i in range(self._ibase.size):
            inv_punctured_prod_mod_ibase = self._ibase.inv_punctured_prod_mod_base_list[
                i]
            ibase = self._ibase.base[i]

            for k in range(count):
                temp[i][k] = multiply_mod(input[i][k],
                                          inv_punctured_prod_mod_ibase, ibase)

        for j in range(self._obase.size):
            obase = self._obase.base[j]

            for k in range(count):
                dot_product = 0

                for tt in range(self._ibase.size):
                    dot_product += multiply_mod(
                        temp[tt][k], self._base_change_matrix[j][tt], obase)
                output[j][k] = dot_product % obase

        return output
Example #4
0
    def sm_mrq(self, input):
        """
        Require: Input in base Bsk U {m_tilde}
        Ensure: Output in base Bsk
        """
        m_tilde_div_2 = self.m_tilde >> 1
        result = []

        # Compute r_m_tilde; The last component of the input is mod m_tilde
        r_m_tilde = []
        for i in range(self.coeff_count):
            r_m_tilde.append(
                negate_mod(
                    multiply_mod(input[-1][i], self.inv_prod_q_mod_m_tilde,
                                 self.m_tilde),
                    self.m_tilde,
                ))

        for k in range(self.base_Bsk.size):
            base_Bsk_elt = self.base_Bsk.base[k]
            inv_m_tilde_mod_Bsk_elt = self.inv_m_tilde_mod_Bsk[k]
            prod_q_mod_Bsk_elt = self.prod_q_mod_Bsk[k]

            temp_list = []
            for i in range(self.coeff_count):
                # We need centered reduction of r_m_tilde modulo Bsk. Note that m_tilde is chosen
                # to be a power of two so we have '>=' below.
                temp = r_m_tilde[i]
                if temp >= m_tilde_div_2:
                    temp += base_Bsk_elt - self.m_tilde

                # Compute (input + q*r_m_tilde)*m_tilde^(-1) mod Bsk
                temp_list.append(((
                    (prod_q_mod_Bsk_elt * temp + input[k][i]) % base_Bsk_elt) *
                                  inv_m_tilde_mod_Bsk_elt) % base_Bsk_elt)

            result.append(temp_list)
        return result
Example #5
0
def is_prime(value, num_rounds=40):
    """Check for the integer if it is probably a prime number.
    Not intrested in strictly checking for prime.

    Returns:
        True, if it is probably prime number else False.
    """
    # First check the simplest cases.
    if value < 2:
        return False
    if value == 2:
        return True
    if 0 == value % 2:
        return False
    if 3 == value:
        return True
    if 0 == value % 3:
        return False
    if 5 == value:
        return True
    if 0 == value % 5:
        return False
    if 7 == value:
        return True
    if 0 == value % 7:
        return False
    if 11 == value:
        return True
    if 0 == value % 11:
        return False
    if 13 == value:
        return True
    if 0 == value % 13:
        return False

    # Second, Miller-Rabin test.
    # Find r and odd d that satisfy value = 2^r * d + 1.
    d = value - 1
    r = 0
    while 0 == d & 1:
        d >>= 1
        r += 1

    if r == 0:
        return False

    # 1) Pick a = 2, check a^(value - 1).
    # 2) Pick a randomly from [3, value - 1], check a^(value - 1).
    # 3) Repeat 2) for another num_rounds - 1 times.
    for i in range(num_rounds):
        a = random.randint(3, value - 1) if i != 0 else 2
        x = exponentiate_mod(a, d, value)

        if x == 1 or x == value - 1:
            continue
        count = 0

        while True:
            x = multiply_mod(x, x, value)
            count += 1
            if not (x != value - 1 and count < r - 1):
                break

        if x != value - 1:
            return False
    return True