示例#1
0
        public static void ExampleRelinearizationPart1()
        {
            Console.WriteLine("Example 1: Performing relinearization too early can increase noise in the final result.");

            // Set up encryption parameters
            var parms = new EncryptionParameters();

            parms.SetPolyModulus("1x^4096 + 1");
            parms.SetCoeffModulus(ChooserEvaluator.DefaultParameterOptions[4096]);
            parms.SetPlainModulus(1 << 8);

            /*
             * The choice of decomposition_bit_count (dbc) can affect the performance of relinearization
             * noticeably. A reasonable choice for it is between 1/10 and 1/2 of the significant bit count
             * of the coefficient modulus. Sometimes when the dbc needs to be very small (due to noise growth),
             * it might make more sense to move up to a larger PolyModulus and CoeffModulus, and set dbc to
             * be as large as possible.
             *
             * A smaller dbc will make relinearization too slow. A higher dbc will increase noise growth
             * while not making relinearization any faster. Here, the CoeffModulus has 116 significant
             * bits, so we choose dbc to be half of this. We can expect to see extreme differences in
             * noise growth between the relinearizing and non-relinearizing cases due to the decomposition
             * bit count being so large.
             */
            parms.SetDecompositionBitCount(58);

            // Validate the parameters
            parms.Validate();

            /*
             * By default, KeyGenerator.Generate() will generate no evaluation keys. This means that we
             * cannot perform any relinearization. However, this is sufficient for performing all other
             * homomorphic evaluation operations as they do not use evaluation keys, and is enough for
             * now as we start by demonstrating the computation without relinearization.
             */
            Console.WriteLine("Generating keys ...");
            var generator = new KeyGenerator(parms);

            generator.Generate();
            Console.WriteLine("... key generation complete");
            var publicKey = generator.PublicKey;
            var secretKey = generator.SecretKey;

            /*
             * Suppose we want to homomorphically multiply four ciphertexts together. Does it make sense
             * to relinearize at an intermediate stage of the computation?
             */

            // Encrypt plaintexts to generate the four fresh ciphertexts
            var plain1 = new Plaintext("5");
            var plain2 = new Plaintext("6");
            var plain3 = new Plaintext("7");
            var plain4 = new Plaintext("8");

            Console.WriteLine("Encrypting values { 5, 6, 7, 8 } as { encrypted1, encrypted2, encrypted3, encrypted4 }");
            var encryptor  = new Encryptor(parms, publicKey);
            var encrypted1 = encryptor.Encrypt(plain1);
            var encrypted2 = encryptor.Encrypt(plain2);
            var encrypted3 = encryptor.Encrypt(plain3);
            var encrypted4 = encryptor.Encrypt(plain4);

            // We need a Decryptor to be able to measure the inherent noise
            var decryptor = new Decryptor(parms, secretKey);

            // What are the noise budgets in the four ciphertexts?
            Console.WriteLine("Noise budgets in the four ciphertexts: {0} bits, {1} bits, {2} bits, {3} bits",
                              decryptor.InvariantNoiseBudget(encrypted1),
                              decryptor.InvariantNoiseBudget(encrypted2),
                              decryptor.InvariantNoiseBudget(encrypted3),
                              decryptor.InvariantNoiseBudget(encrypted4));

            // Construct an Evaluator
            var evaluator = new Evaluator(parms);

            // Perform first part of computation
            Console.WriteLine("Computing encProd1 as encrypted1*encrypted2 ...");
            var encProd1 = evaluator.Multiply(encrypted1, encrypted2);

            Console.WriteLine("Computing encProd2 as encrypted3*encrypted4 ...");
            var encProd2 = evaluator.Multiply(encrypted3, encrypted4);

            Console.WriteLine();
            Console.WriteLine("Path 1: No relinearization.");

            // Compute product of all four
            Console.WriteLine("Computing encResult as encProd1*encProd2 ...");
            var encResult = evaluator.Multiply(encProd1, encProd2);

            // Now enc_result has size 5
            Console.WriteLine("Size of encResult: {0}", encResult.Size);

            // How much noise budget are we left with?
            var noiseBudgetNoRelin = decryptor.InvariantNoiseBudget(encResult);

            Console.WriteLine("Noise budget in encResult: {0} bits", noiseBudgetNoRelin);

            /*
             * We didn't create any evaluation keys, so we can't relinearize at all with the current
             * Evaluator. In general, relinearizing down from size K to any smaller size (but at least 2)
             * requires at least K-2 evaluation keys. In this case we wish to relinearize encProd1 and
             * encProd2, which both have size 3. Thus we need only one evaluation key.
             *
             * We can create this newn evaluation key by calling KeyGenerator.GenerateEvaluationKeys(...).
             * Alternatively, we could have created it already in the beginning by instead of calling
             * generator.Generate(1) instead of generator.Generate().
             *
             * We will also need a new Evaluator, as the previous one was constructed without enough
             * indeed, any) evaluation keys. It is not possible to add new evaluation keys to a previously
             * created Evaluator.
             */
            generator.GenerateEvaluationKeys(1);
            var evaluationKeys = generator.EvaluationKeys;
            var evaluator2     = new Evaluator(parms, evaluationKeys);

            // Now with relinearization
            Console.WriteLine("");
            Console.WriteLine("Path 2: With relinearization");

            // What if we do intermediate relinearization of encProd1 and encProd2?
            Console.WriteLine("Relinearizing encProd1 and encProd2 to size 2 ...");
            var encRelinProd1 = evaluator2.Relinearize(encProd1);
            var encRelinProd2 = evaluator2.Relinearize(encProd2);

            // Now multiply the relinearized products together
            Console.WriteLine("Computing encResult as encRelinProd1*encRelinProd2");
            encResult = evaluator2.Multiply(encRelinProd1, encRelinProd2);

            // Now enc_result has size 3
            Console.WriteLine("Size of encResult: {0}", encResult.Size);

            // How much noise budget are we left with?
            var noiseBudgetRelin = decryptor.InvariantNoiseBudget(encResult);

            Console.WriteLine("Noise budget in encResult: {0} bits", noiseBudgetRelin);

            /*
             * While in this case the noise increased significantly due to relinearization, in other
             * computations the situation might be entirely different. Indeed, recall that larger
             * ciphertext sizes can have a huge adverse effect on noise growth in multiplication.
             * Also recall that homomorphic multiplication is much slower when the ciphertexts are
             * larger.
             */
        }