Example #1
0
def seal_obj():
    # params obj
    params = EncryptionParameters()
    # set params
    params.set_poly_modulus("1x^4096 + 1")
    params.set_coeff_modulus(seal.coeff_modulus_128(4096))
    params.set_plain_modulus(1 << 16)
    # get context
    context = SEALContext(params)
    # get evaluator
    evaluator = Evaluator(context)
    # gen keys
    keygen = KeyGenerator(context)
    public_key = keygen.public_key()
    private_key = keygen.secret_key()
    # evaluator keys
    ev_keys = EvaluationKeys()
    keygen.generate_evaluation_keys(30, ev_keys)
    # get encryptor and decryptor
    encryptor = Encryptor(context, public_key)
    decryptor = Decryptor(context, private_key)
    # float number encoder
    encoder = FractionalEncoder(context.plain_modulus(),
                                context.poly_modulus(), 64, 32, 3)
    return evaluator, encoder.encode, encoder.decode, encryptor.encrypt, decryptor.decrypt, ev_keys
Example #2
0
def initialize_fractional(
        poly_modulus_degree=4096,
        security_level_bits=128,
        plain_modulus_power_of_two=10,
        plain_modulus=None,
        encoder_integral_coefficients=1024,
        encoder_fractional_coefficients=3072,
        encoder_base=2
):
    parameters = EncryptionParameters()

    poly_modulus = "1x^" + str(poly_modulus_degree) + " + 1"
    parameters.set_poly_modulus(poly_modulus)

    if security_level_bits == 128:
        parameters.set_coeff_modulus(seal.coeff_modulus_128(poly_modulus_degree))
    elif security_level_bits == 192:
        parameters.set_coeff_modulus(seal.coeff_modulus_192(poly_modulus_degree))
    else:
        parameters.set_coeff_modulus(seal.coeff_modulus_128(poly_modulus_degree))
        print("Info: security_level_bits unknown - using default security_level_bits = 128")

    if plain_modulus is None:
        plain_modulus = 1 << plain_modulus_power_of_two

    parameters.set_plain_modulus(plain_modulus)

    context = SEALContext(parameters)

    print_parameters(context)

    global encoder
    encoder = FractionalEncoder(
        context.plain_modulus(),
        context.poly_modulus(),
        encoder_integral_coefficients,
        encoder_fractional_coefficients,
        encoder_base
    )

    keygen = KeyGenerator(context)
    public_key = keygen.public_key()
    secret_key = keygen.secret_key()

    global encryptor
    encryptor = Encryptor(context, public_key)

    global evaluator
    evaluator = Evaluator(context)

    global decryptor
    decryptor = Decryptor(context, secret_key)

    global evaluation_keys
    evaluation_keys = EvaluationKeys()

    keygen.generate_evaluation_keys(16, evaluation_keys)
Example #3
0
    def _create_keys(self, context):

        keygen = KeyGenerator(context)
        public_key = keygen.public_key()
        secret_key = keygen.secret_key()

        ev_keys16 = EvaluationKeys()
        keygen.generate_evaluation_keys(16, ev_keys16)

        return public_key, secret_key, ev_keys16
Example #4
0
def keygen(context, batching):
    #print("Generating secret/public keys: ")
    time_start = time.time()
    keygen = KeyGenerator(context)
    time_end = time.time()
    #print("Done in {} miliseconds".format((str)(1000 * (time_end - time_start))))
    public_key = keygen.public_key()
    secret_key = keygen.secret_key()
    #use moderate size decomposition bit count
    if batching:
        gal_keys = GaloisKeys()
        keygen.generate_galois_keys(30, gal_keys)
        #since we are going to do some multiplications we are going to relinearize
        ev_keys = EvaluationKeys()
        keygen.generate_evaluation_keys(30, ev_keys)
        return public_key, secret_key, ev_keys, gal_keys
    else:
        return public_key, secret_key
                 ChooserPoly

parms = EncryptionParameters()
parms.set_poly_modulus("1x^8192 + 1")
parms.set_coeff_modulus(seal.coeff_modulus_128(8192))
parms.set_plain_modulus(1 << 21)
context = SEALContext(parms)

encoder = IntegerEncoder(context.plain_modulus())
keygen = KeyGenerator(context)
public_key = keygen.public_key()
secret_key = keygen.secret_key()
ev_keys40 = EvaluationKeys()
ev_keys20 = EvaluationKeys()
#keygen.generate_evaluation_keys(40,5,ev_keys40)
keygen.generate_evaluation_keys(20, 3, ev_keys20)
encryptor = Encryptor(context, public_key)
evaluator = Evaluator(context)
decryptor = Decryptor(context, secret_key)

A = []
n = int(input("Enter dimension: "))

for i in range(n):
    a = []
    for j in range(n):
        encrypted_data1 = Ciphertext()
        ran = random.randint(0, 10)
        print(ran)
        encryptor.encrypt(encoder.encode(ran), encrypted_data1)
        a.append(encrypted_data1)
Example #6
0
parms.set_poly_modulus("1x^4096 + 1")
parms.set_coeff_modulus(seal.coeff_modulus_128(4096))

# Note that 40961 is a prime number and 2*4096 divides 40960.
parms.set_plain_modulus(40961)

context = SEALContext(parms)
keygen = KeyGenerator(context)
public_key = keygen.public_key()
secret_key = keygen.secret_key()
gal_keys = GaloisKeys()
keygen.generate_galois_keys(30, gal_keys)

# Since we are going to do some multiplications we will also relinearize.
ev_keys = EvaluationKeys()
keygen.generate_evaluation_keys(30, ev_keys)

# We also set up an Encryptor, Evaluator, and Decryptor here.
encryptor = Encryptor(context, public_key)
evaluator = Evaluator(context)
decryptor = Decryptor(context, secret_key)

# Batching is done through an instance of the PolyCRTBuilder class so need
# to start by constructing one.
crtbuilder = PolyCRTBuilder(context)
slot_count = (int)(crtbuilder.slot_count())
row_size = (int)(slot_count / 2)

pod_matrix = [1,2,3,4,8,-4,3,2]
plain_matrix = Plaintext()
crtbuilder.compose(pod_matrix, plain_matrix)
Example #7
0
def example_basics_ii():
    print_example_banner("Example: Basics II")

    # In this example we explain what relinearization is, how to use it, and how
    # it affects noise budget consumption.

    # First we set the parameters, create a SEALContext, and generate the public
    # and secret keys. We use slightly larger parameters than be fore to be able
    # to do more homomorphic multiplications.
    parms = EncryptionParameters()
    parms.set_poly_modulus("1x^8192 + 1")

    # The default coefficient modulus consists of the following primes:

    #     0x7fffffffba0001,
    #     0x7fffffffaa0001,
    #     0x7fffffff7e0001,
    #     0x3fffffffd60001.

    # The total size is 219 bits.
    parms.set_coeff_modulus(seal.coeff_modulus_128(8192))
    parms.set_plain_modulus(1 << 10)

    context = SEALContext(parms)
    print_parameters(context)

    keygen = KeyGenerator(context)
    public_key = keygen.public_key()
    secret_key = keygen.secret_key()

    # We also set up an Encryptor, Evaluator, and Decryptor here. We will
    # encrypt polynomials directly in this example, so there is no need for
    # an encoder.
    encryptor = Encryptor(context, public_key)
    evaluator = Evaluator(context)
    decryptor = Decryptor(context, secret_key)

    # There are actually two more types of keys in SEAL: `evaluation keys' and
    # `Galois keys'. Here we will discuss evaluation keys, and Galois keys will
    # be discussed later in example_batching().

    # In SEAL, a valid ciphertext consists of two or more polynomials with
    # coefficients integers modulo the product of the primes in coeff_modulus.
    # The current size of a ciphertext can be found using Ciphertext::size().
    # A freshly encrypted ciphertext always has size 2.
    #plain1 = Plaintext("1x^2 + 2x^1 + 3")
    plain1 = Plaintext("1x^2 + 2x^1 + 3")
    encrypted = Ciphertext()

    print("")
    print("Encrypting " + plain1.to_string() + ": ")
    encryptor.encrypt(plain1, encrypted)
    print("Done")
    print("Size of a fresh encryption: " + (str)(encrypted.size()))
    print("Noise budget in fresh encryption: " +
          (str)(decryptor.invariant_noise_budget(encrypted)) + " bits")

    # Homomorphic multiplication results in the output ciphertext growing in size.
    # More precisely, if the input ciphertexts have size M and N, then the output
    # ciphertext after homomorphic multiplication will have size M+N-1. In this
    # case we square encrypted twice to observe this growth (also observe noise
    # budget consumption).
    evaluator.square(encrypted)
    print("Size after squaring: " + (str)(encrypted.size()))
    print("Noise budget after squaring: " +
          (str)(decryptor.invariant_noise_budget(encrypted)) + " bits")
    plain2 = Plaintext()
    decryptor.decrypt(encrypted, plain2)
    print("Second power: " + plain2.to_string())

    evaluator.square(encrypted)
    print("Size after squaring: " + (str)(encrypted.size()))
    print("Noise budget after squaring: " +
          (str)(decryptor.invariant_noise_budget(encrypted)) + " bits")

    # It does not matter that the size has grown -- decryption works as usual.
    # Observe from the print-out that the coefficients in the plaintext have
    # grown quite large. One more squaring would cause some of them to wrap
    # around plain_modulus (0x400), and as a result we would no longer obtain
    # the expected result as an integer-coefficient polynomial. We can fix this
    # problem to some extent by increasing plain_modulus. This would make sense,
    # since we still have plenty of noise budget left.
    plain2 = Plaintext()
    decryptor.decrypt(encrypted, plain2)
    print("Fourth power: " + plain2.to_string())

    # The problem here is that homomorphic operations on large ciphertexts are
    # computationally much more costly than on small ciphertexts. Specifically,
    # homomorphic multiplication on input ciphertexts of size M and N will require
    # O(M*N) polynomial multiplications to be performed, and an addition will
    # require O(M+N) additions. Relinearization reduces the size of the ciphertexts
    # after multiplication back to the initial size (2). Thus, relinearizing one
    # or both inputs before the next multiplication, or e.g. before serializing the
    # ciphertexts, can have a huge positive impact on performance.

    # Another problem is that the noise budget consumption in multiplication is
    # bigger when the input ciphertexts sizes are bigger. In a complicated
    # computation the contribution of the sizes to the noise budget consumption
    # can actually become the dominant term. We will point this out again below
    # once we get to our example.

    # Relinearization itself has both a computational cost and a noise budget cost.
    # These both depend on a parameter called `decomposition bit count', which can
    # be any integer at least 1 [dbc_min()] and at most 60 [dbc_max()]. A large
    # decomposition bit count makes relinearization fast, but consumes more noise
    # budget. A small decomposition bit count can make relinearization slower, but
    # might not change the noise budget by any observable amount.

    # Relinearization requires a special type of key called `evaluation keys'.
    # These can be created by the KeyGenerator for any decomposition bit count.
    # To relinearize a ciphertext of size M >= 2 back to size 2, we actually need
    # M-2 evaluation keys. Attempting to relinearize a too large ciphertext with
    # too few evaluation keys will result in an exception being thrown.

    # We repeat our computation, but this time relinearize after both squarings.
    # Since our ciphertext never grows past size 3 (we relinearize after every
    # multiplication), it suffices to generate only one evaluation key.

    # First, we need to create evaluation keys. We use a decomposition bit count
    # of 16 here, which can be thought of as quite small.
    ev_keys16 = EvaluationKeys()

    # This function generates one single evaluation key. Another overload takes
    # the number of keys to be generated as an argument, but one is all we need
    # in this example (see above).
    keygen.generate_evaluation_keys(16, ev_keys16)

    print("")
    print("Encrypting " + plain1.to_string() + ": ")
    encryptor.encrypt(plain1, encrypted)
    print("Done")
    print("Size of a fresh encryption: " + (str)(encrypted.size()))
    print("Noise budget in fresh encryption: " +
          (str)(decryptor.invariant_noise_budget(encrypted)) + " bits")

    evaluator.square(encrypted)
    print("Size after squaring: " + (str)(encrypted.size()))
    print("Noise budget after squaring: " +
          (str)(decryptor.invariant_noise_budget(encrypted)) + " bits")

    evaluator.relinearize(encrypted, ev_keys16)
    print("Size after relinearization: " + (str)(encrypted.size()))
    print("Noise budget after relinearizing (dbs = " +
          (str)(ev_keys16.decomposition_bit_count()) + "): " +
          (str)(decryptor.invariant_noise_budget(encrypted)) + " bits")

    evaluator.square(encrypted)
    print("Size after second squaring: " + (str)(encrypted.size()) + " bits")
    print("Noise budget after second squaring: " +
          (str)(decryptor.invariant_noise_budget(encrypted)) + " bits")

    evaluator.relinearize(encrypted, ev_keys16)
    print("Size after relinearization: " + (str)(encrypted.size()))
    print("Noise budget after relinearizing (dbs = " +
          (str)(ev_keys16.decomposition_bit_count()) + "): " +
          (str)(decryptor.invariant_noise_budget(encrypted)) + " bits")

    decryptor.decrypt(encrypted, plain2)
    print("Fourth power: " + plain2.to_string())

    # Of course the result is still the same, but this time we actually
    # used less of our noise budget. This is not surprising for two reasons:

    #     - We used a very small decomposition bit count, which is why
    #       relinearization itself did not consume the noise budget by any
    #       observable amount;
    #     - Since our ciphertext sizes remain small throughout the two
    #       squarings, the noise budget consumption rate in multiplication
    #       remains as small as possible. Recall from above that operations
    #       on larger ciphertexts actually cause more noise growth.

    # To make matters even more clear, we repeat the computation a third time,
    # now using the largest possible decomposition bit count (60). We are not
    # measuring the time here, but relinearization with these evaluation keys
    # is significantly faster than with ev_keys16.
    ev_keys60 = EvaluationKeys()
    keygen.generate_evaluation_keys(seal.dbc_max(), ev_keys60)

    print("")
    print("Encrypting " + plain1.to_string() + ": ")
    encryptor.encrypt(plain1, encrypted)
    print("Done")
    print("Size of a fresh encryption: " + (str)(encrypted.size()))
    print("Noise budget in fresh encryption: " +
          (str)(decryptor.invariant_noise_budget(encrypted)) + " bits")

    evaluator.square(encrypted)
    print("Size after squaring: " + (str)(encrypted.size()))
    print("Noise budget after squaring: " +
          (str)(decryptor.invariant_noise_budget(encrypted)) + " bits")
    evaluator.relinearize(encrypted, ev_keys60)
    print("Size after relinearization: " + (str)(encrypted.size()))
    print("Noise budget after relinearizing (dbc = " +
          (str)(ev_keys60.decomposition_bit_count()) + "): " +
          (str)(decryptor.invariant_noise_budget(encrypted)) + " bits")

    evaluator.square(encrypted)
    print("Size after second squaring: " + (str)(encrypted.size()))
    print("Noise budget after second squaring: " +
          (str)(decryptor.invariant_noise_budget) + " bits")
    evaluator.relinearize(encrypted, ev_keys60)
    print("Size after relinearization: " + (str)(encrypted.size()))
    print("Noise budget after relinearizing (dbc = " +
          (str)(ev_keys60.decomposition_bit_count()) + "): " +
          (str)(decryptor.invariant_noise_budget(encrypted)) + " bits")

    decryptor.decrypt(encrypted, plain2)
    print("Fourth power: " + plain2.to_string())

    # Observe from the print-out that we have now used significantly more of our
    # noise budget than in the two previous runs. This is again not surprising,
    # since the first relinearization chops off a huge part of the noise budget.

    # However, note that the second relinearization does not change the noise
    # budget by any observable amount. This is very important to understand when
    # optimal performance is desired: relinearization always drops the noise
    # budget from the maximum (freshly encrypted ciphertext) down to a fixed
    # amount depending on the encryption parameters and the decomposition bit
    # count. On the other hand, homomorphic multiplication always consumes the
    # noise budget from its current level. This is why the second relinearization
    # does not change the noise budget anymore: it is already consumed past the
    # fixed amount determinted by the decomposition bit count and the encryption
    # parameters.

    # We now perform a third squaring and observe an even further compounded
    # decrease in the noise budget. Again, relinearization does not consume the
    # noise budget at this point by any observable amount, even with the largest
    # possible decomposition bit count.
    evaluator.square(encrypted)
    print("Size after third squaring " + (str)(encrypted.size()))
    print("Noise budget after third squaring: " +
          (str)(decryptor.invariant_noise_budget(encrypted)) + " bits")
    evaluator.relinearize(encrypted, ev_keys60)
    print("Size after relinearization: " + (str)(encrypted.size()))
    print("Noise budget after relinearizing (dbc = " +
          (str)(ev_keys60.decomposition_bit_count()) + "): " +
          (str)(decryptor.invariant_noise_budget(encrypted)) + " bits")

    decryptor.decrypt(encrypted, plain2)
    print("Eighth power: " + plain2.to_string())