def __mul__(self, other): if isinstance(other, (ReSeal, seal.Ciphertext)): # if multiplying ciphertext * ciphertext encrypted_result = seal.Ciphertext() if isinstance(other, ReSeal): other = other.ciphertext ciphertext, other = self._homogenise_parameters( self.ciphertext, other) self.evaluator.multiply(ciphertext, other, encrypted_result) self.evaluator.relinearize_inplace(encrypted_result, self.relin_keys) self.evaluator.rescale_to_next_inplace(encrypted_result) else: # if multiplying ciphertext * numeric plaintext = self._to_plaintext(other) encrypted_result = seal.Ciphertext() # switching modulus chain of plaintex to ciphertexts level # so computation is possible ciphertext, plaintext = self._homogenise_parameters( a=self.ciphertext, b=plaintext) # the computation self.evaluator.multiply_plain(ciphertext, plaintext, encrypted_result) # dropping one level of modulus chain to stabalise ciphertext self.evaluator.rescale_to_next_inplace(encrypted_result) # now we take this encrypted result and return it as a new reseal obj # so that it can be used as input to __add__ and __mult__ again new_reseal_object = self.duplicate() new_reseal_object.ciphertext = encrypted_result return new_reseal_object
def __add__(self, other): if isinstance(other, (ReSeal, seal.Ciphertext)): # if adding ciphertext + ciphertext encrypted_result = seal.Ciphertext() if isinstance(other, ReSeal): other = other.ciphertext ciphertext, other = self._homogenise_parameters( self.ciphertext, other) self.evaluator.add(ciphertext, other, encrypted_result) # addition of two ciphertexts does not require relinearization # or rescaling (by modulus swapping). else: # if adding ciphertext + numeric plaintext plaintext = self._to_plaintext(other) encrypted_result = seal.Ciphertext() # switching modulus chain of plaintex to ciphertexts level # so computation is possible ciphertext, plaintext = self._homogenise_parameters( a=self.ciphertext, b=plaintext) self.evaluator.add_plain(ciphertext, plaintext, encrypted_result) # no need to drop modulus chain addition is fairly small # now we take this encrypted result and return it as a new reseal obj # so that it can be used as input to __add__ and __mult__ again new_reseal_object = self.duplicate() new_reseal_object.ciphertext = encrypted_result return new_reseal_object
def _homogenise_parameters(self, a, b): """Function to harmonise encryption parameters between objects. In particular this prevents: ValueError: encrypted1 and encrypted2 parameter mismatch which is caused by the encryption parameters such as scale, and modulus chain being mismatched. This function varied depending on if two ciphers or cipher and plain is supplied. """ if isinstance(a, seal.Ciphertext) and isinstance(b, seal.Ciphertext): # find which one is lowest on modulus chain and swap both to that a_new, b_new = seal.Ciphertext(), seal.Ciphertext() a_chain_id = self.context.get_context_data( a.parms_id()).chain_index() b_chain_id = self.context.get_context_data( b.parms_id()).chain_index() if b_chain_id < a_chain_id: lowest_parms_id = b.parms_id() else: lowest_parms_id = a.parms_id() self.evaluator.mod_switch_to(a, lowest_parms_id, a_new) self.evaluator.mod_switch_to(b, lowest_parms_id, b_new) # lie to ms seal about scales since they SHOULD BE CLOSE! # TODO should happen before modulus switching where we have # a bigger noise budget a_new.scale() b_new.scale() a_new.scale(self.scale) b_new.scale(self.scale) return (a_new, b_new) elif isinstance(a, seal.Ciphertext) and isinstance(b, seal.Plaintext): # swap modulus chain of plaintext to be that of ciphertext ciphertext, plaintext = seal.Ciphertext(), seal.Plaintext() # doing both so they are both copied exactly as each other # rather than one being a reference, and the other being a new obj self.evaluator.mod_switch_to(a, a.parms_id(), ciphertext) self.evaluator.mod_switch_to(b, a.parms_id(), plaintext) ciphertext.scale() ciphertext.scale(self.scale) plaintext.scale() return (ciphertext, plaintext) elif isinstance(b, seal.Ciphertext) and isinstance(a, seal.Plaintext): # same as above by swapping a and b around so code is reused flipped_tuple = self._homogenise_parameters(a=b, b=a) return (flipped_tuple[1], flipped_tuple[0]) else: # someone has been naughty and not given this function propper # encryption based objects to work with. raise TypeError("Neither parameters are ciphertext or plaintext.")
def get_ciphertext_bfv(self): import seal encryptor, evaluator, decryptor = self.get_workers_bfv() x = 1447 plaintext = seal.Plaintext(x) ciphertext = seal.Ciphertext() encryptor.encrypt(plaintext, ciphertext) return ciphertext
def ciphertext(self, data): if isinstance(data, seal.Ciphertext): self._ciphertext = data elif isinstance(data, ReSeal): # compatibility so old setter "r.ciphertext = r + 2" still works self.ciphertext = data.ciphertext else: plaintext = self._to_plaintext(data) ciphertext = seal.Ciphertext() self.encryptor.encrypt(plaintext, ciphertext) self._ciphertext = ciphertext
def __setstate__(self, state): """Rebuild all constituent objects from serialised state.""" # ensuring scheme type is decoded first and must always exist self._scheme = seal.scheme_type(state["_scheme"]) # the order of the dictionary is very important, we will ensure it is # as expected or else we may end up trying to initialise the ciphertext # before the context which will fail. if state.get("_coefficient_modulus"): self._coefficient_modulus = state["_coefficient_modulus"] if state.get("_poly_modulus_degree"): self._poly_modulus_degree = state["_poly_modulus_degree"] if state.get("_scale"): self._scale = state["_scale"] if state.get("_parameters"): parameters = seal.EncryptionParameters(self._scheme) parameters.__setstate__(state["_parameters"]) self._parameters = parameters if state.get("_ciphertext"): ciphertext = seal.Ciphertext() state["_ciphertext"].update({"context": self.context}) ciphertext.__setstate__(state["_ciphertext"]) self._ciphertext = ciphertext if state.get("_public_key"): public_key = seal.PublicKey() state["_public_key"].update({"context": self.context}) public_key.__setstate__(state["_public_key"]) self._public_key = public_key if state.get("_private_key"): private_key = seal.SecretKey() state["_private_key"].update({"context": self.context}) private_key.__setstate__(state["_private_key"]) self._private_key = private_key if state.get("_switch_keys"): switch_keys = seal.KSwitchKeys() state["_switch_keys"].update({"context": self.context}) switch_keys.__setstate__(state["_switch_keys"]) self._switch_keys = switch_keys if state.get("_relin_keys"): relin_keys = seal.RelinKeys() state["_relin_keys"].update({"context": self.context}) relin_keys.__setstate__(state["_relin_keys"]) self._relin_keys = relin_keys if state.get("_galois_keys"): galois_keys = seal.GaloisKeys() state["_galois_keys"].update({"context": self.context}) galois_keys.__setstate__(state["_galois_keys"]) self._galois_keys = galois_keys
def encrypt(self, matrix): """ :param matrix: :return: """ self.context = self.secret_key self.public_key [m, n] = self.shape for i in range(m): for j in range(n): self.ciphermat[i,j] = seal.Ciphertext(self.params) self.ciphermat[i,j] =