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. */ }