Example #1
0
        public void FVEncryptSquareDecryptNET()
        {
            var parms = new EncryptionParameters(MemoryPoolHandle.AcquireNew());

            parms.SetDecompositionBitCount(4);
            parms.SetNoiseStandardDeviation(3.19);
            parms.SetNoiseMaxDeviation(35.06);

            var coeffModulus = new BigUInt(48);

            coeffModulus.Set("FFFFFFFFC001");
            parms.SetCoeffModulus(coeffModulus);

            var plainModulus = new BigUInt(7);

            plainModulus.Set(1 << 6);
            parms.SetPlainModulus(plainModulus);

            var polyModulus = new BigPoly(65, 1);

            polyModulus[0].Set(1);
            polyModulus[64].Set(1);
            parms.SetPolyModulus(polyModulus);

            parms.Validate();

            var keygen = new KeyGenerator(parms, MemoryPoolHandle.AcquireNew());

            keygen.Generate();

            var encoder = new BalancedEncoder(parms.PlainModulus, MemoryPoolHandle.AcquireNew());

            var encryptor = new Encryptor(parms, keygen.PublicKey, MemoryPoolHandle.AcquireNew());
            var evaluator = new Evaluator(parms, MemoryPoolHandle.AcquireNew());
            var decryptor = new Decryptor(parms, keygen.SecretKey, MemoryPoolHandle.AcquireNew());

            var encrypted1 = encryptor.Encrypt(encoder.Encode(1));
            var product    = evaluator.Square(encrypted1);

            Assert.AreEqual(1UL, encoder.DecodeUInt64(decryptor.Decrypt(product)));

            encrypted1 = encryptor.Encrypt(encoder.Encode(0));
            product    = evaluator.Square(encrypted1);
            Assert.AreEqual(0UL, encoder.DecodeUInt64(decryptor.Decrypt(product)));

            encrypted1 = encryptor.Encrypt(encoder.Encode(-5));
            product    = evaluator.Square(encrypted1);
            Assert.AreEqual(25UL, encoder.DecodeUInt64(decryptor.Decrypt(product)));

            encrypted1 = encryptor.Encrypt(encoder.Encode(-1));
            product    = evaluator.Square(encrypted1);
            Assert.AreEqual(1UL, encoder.DecodeUInt64(decryptor.Decrypt(product)));

            encrypted1 = encryptor.Encrypt(encoder.Encode(123));
            product    = evaluator.Square(encrypted1);
            Assert.AreEqual(15129UL, encoder.DecodeUInt64(decryptor.Decrypt(product)));
        }
        public void BalancedEncodeDecodeInt32NET()
        {
            var modulus = new BigUInt("10000");
            var encoder = new BalancedEncoder(modulus, 3);

            var poly = encoder.Encode(0);

            Assert.AreEqual(0, poly.GetSignificantCoeffCount());
            Assert.IsTrue(poly.IsZero);
            Assert.AreEqual(0, encoder.DecodeInt32(poly));

            var poly1 = encoder.Encode(1);

            Assert.AreEqual(1, poly1.GetSignificantCoeffCount());
            Assert.AreEqual(modulus.BitCount, poly1.CoeffBitCount);
            Assert.AreEqual("1", poly1.ToString());
            Assert.AreEqual(1, encoder.DecodeInt32(poly1));

            var poly2 = encoder.Encode(2);

            Assert.AreEqual(2, poly2.GetSignificantCoeffCount());
            Assert.AreEqual(modulus.BitCount, poly2.CoeffBitCount);
            Assert.AreEqual("1x^1 + FFFF", poly2.ToString());
            Assert.AreEqual(2, encoder.DecodeInt32(poly2));

            var poly3 = encoder.Encode(3);

            Assert.AreEqual(2, poly3.GetSignificantCoeffCount());
            Assert.AreEqual(modulus.BitCount, poly3.CoeffBitCount);
            Assert.AreEqual("1x^1", poly3.ToString());
            Assert.AreEqual(3, encoder.DecodeInt32(poly3));

            var poly4 = encoder.Encode(-1);

            Assert.AreEqual(1, poly4.GetSignificantCoeffCount());
            Assert.AreEqual(modulus.BitCount, poly4.CoeffBitCount);
            Assert.AreEqual("FFFF", poly4.ToString());
            Assert.AreEqual(-1, encoder.DecodeInt32(poly4));

            var poly5 = encoder.Encode(-2);

            Assert.AreEqual(2, poly5.GetSignificantCoeffCount());
            Assert.AreEqual(modulus.BitCount, poly5.CoeffBitCount);
            Assert.AreEqual("FFFFx^1 + 1", poly5.ToString());
            Assert.AreEqual(-2, encoder.DecodeInt32(poly5));

            var poly6 = encoder.Encode(-3);

            Assert.AreEqual(2, poly6.GetSignificantCoeffCount());
            Assert.AreEqual(modulus.BitCount, poly6.CoeffBitCount);
            Assert.AreEqual("FFFFx^1", poly6.ToString());
            Assert.AreEqual(-3, encoder.DecodeInt32(poly6));

            var poly7 = encoder.Encode(-0x2671);

            Assert.AreEqual(9, poly7.GetSignificantCoeffCount());
            Assert.AreEqual(modulus.BitCount, poly7.CoeffBitCount);
            for (int i = 0; i < 9; ++i)
            {
                Assert.AreEqual("FFFF", poly7[i].ToString());
            }
            Assert.AreEqual(-0x2671, encoder.DecodeInt32(poly7));

            var poly8 = encoder.Encode(-4374);

            Assert.AreEqual(9, poly8.GetSignificantCoeffCount());
            Assert.AreEqual(modulus.BitCount, poly8.CoeffBitCount);
            Assert.AreEqual("FFFF", poly8[8].ToString());
            Assert.AreEqual("1", poly8[7].ToString());
            for (int i = 0; i < 7; ++i)
            {
                Assert.IsTrue(poly8[i].IsZero);
            }
            Assert.AreEqual(-4374, encoder.DecodeInt32(poly8));

            var poly9 = encoder.Encode(-0xD4EB);

            Assert.AreEqual(11, poly9.GetSignificantCoeffCount());
            Assert.AreEqual(modulus.BitCount, poly9.CoeffBitCount);
            for (int i = 0; i < 11; ++i)
            {
                if (i % 3 == 1)
                {
                    Assert.AreEqual("FFFF", poly9[i].ToString());
                }
                else if (i % 3 == 0)
                {
                    Assert.IsTrue(poly9[i].IsZero);
                }
                else
                {
                    Assert.AreEqual("1", poly9[i].ToString());
                }
            }
            Assert.AreEqual(-0xD4EB, encoder.DecodeInt32(poly9));

            var poly10 = encoder.Encode(-30724);

            Assert.AreEqual(11, poly10.GetSignificantCoeffCount());
            Assert.AreEqual(modulus.BitCount, poly10.CoeffBitCount);
            Assert.AreEqual("FFFF", poly10[10].ToString());
            Assert.AreEqual("1", poly10[9].ToString());
            Assert.AreEqual("1", poly10[8].ToString());
            Assert.AreEqual("1", poly10[7].ToString());
            Assert.IsTrue(poly10[6].IsZero);
            Assert.IsTrue(poly10[5].IsZero);
            Assert.AreEqual("FFFF", poly10[4].ToString());
            Assert.AreEqual("FFFF", poly10[3].ToString());
            Assert.IsTrue(poly10[2].IsZero);
            Assert.AreEqual("1", poly10[1].ToString());
            Assert.AreEqual("FFFF", poly10[0].ToString());
            Assert.AreEqual(-30724, encoder.DecodeInt32(poly10));

            modulus.Set("FFFF");
            var encoder2 = new BalancedEncoder(modulus, 7);
            var poly12   = new BigPoly(6, 16);

            poly12[0].Set(1);
            poly12[1].Set("FFFE"); // -1
            poly12[2].Set("FFFD"); // -2
            poly12[3].Set("8000"); // -32767
            poly12[4].Set("7FFF"); // 32767
            poly12[5].Set("7FFE"); // 32766
            Assert.AreEqual(1 + -1 * 7 + -2 * 49 + -32767 * 343 + 32767 * 2401 + 32766 * 16807, encoder2.DecodeInt32(poly12));
        }
        public void BalancedEncodeDecodeUInt32NET()
        {
            var modulus = new BigUInt("10000");
            var encoder = new BalancedEncoder(modulus, 3);

            var poly = encoder.Encode(0U);

            Assert.AreEqual(0, poly.GetSignificantCoeffCount());
            Assert.IsTrue(poly.IsZero);
            Assert.AreEqual(0U, encoder.DecodeUInt32(poly));

            var poly1 = encoder.Encode(1U);

            Assert.AreEqual(1, poly1.GetSignificantCoeffCount());
            Assert.AreEqual(modulus.BitCount, poly1.CoeffBitCount);
            Assert.AreEqual("1", poly1.ToString());
            Assert.AreEqual(1U, encoder.DecodeUInt32(poly1));

            var poly2 = encoder.Encode(2U);

            Assert.AreEqual(2, poly2.GetSignificantCoeffCount());
            Assert.AreEqual(modulus.BitCount, poly2.CoeffBitCount);
            Assert.AreEqual("1x^1 + FFFF", poly2.ToString());
            Assert.AreEqual(2U, encoder.DecodeUInt32(poly2));

            var poly3 = encoder.Encode(3U);

            Assert.AreEqual(2, poly3.GetSignificantCoeffCount());
            Assert.AreEqual(modulus.BitCount, poly3.CoeffBitCount);
            Assert.AreEqual("1x^1", poly3.ToString());
            Assert.AreEqual(3U, encoder.DecodeUInt32(poly3));

            var poly4 = encoder.Encode(0x2671U);

            Assert.AreEqual(9, poly4.GetSignificantCoeffCount());
            Assert.AreEqual(modulus.BitCount, poly4.CoeffBitCount);
            for (int i = 0; i < 9; ++i)
            {
                Assert.IsTrue("1" == poly4[i].ToString());
            }
            Assert.AreEqual(0x2671U, encoder.DecodeUInt32(poly4));

            var poly5 = encoder.Encode(0xD4EBU);

            Assert.AreEqual(11, poly5.GetSignificantCoeffCount());
            Assert.AreEqual(modulus.BitCount, poly5.CoeffBitCount);
            for (int i = 0; i < 11; ++i)
            {
                if (i % 3 == 1)
                {
                    Assert.AreEqual("1", poly5[i].ToString());
                }
                else if (i % 3 == 0)
                {
                    Assert.IsTrue(poly5[i].IsZero);
                }
                else
                {
                    Assert.AreEqual("FFFF", poly5[i].ToString());
                }
            }
            Assert.AreEqual(0xD4EBU, encoder.DecodeUInt32(poly5));

            var poly6 = new BigPoly(3, 10);

            poly6[0].Set(1);
            poly6[1].Set(500);
            poly6[2].Set(1023);
            Assert.AreEqual(1U + 500 * 3 + 1023 * 9, encoder.DecodeUInt32(poly6));

            var encoder2 = new BalancedEncoder(modulus, 7);
            var poly7    = new BigPoly(4, 16);

            poly7[0].Set(123);    // 123   (*1)
            poly7[1].Set("FFFF"); // -1 (*7)
            poly7[2].Set(511);    // 511  (*49)
            poly7[3].Set(1);      // 1    (*343)
            Assert.AreEqual((UInt32)(123 + -1 * 7 + 511 * 49 + 1 * 343), encoder2.DecodeUInt32(poly7));
        }
Example #4
0
        public void BalancedEncodeDecodeInt32NET()
        {
            var modulus = new SmallModulus(0x10000);
            var encoder = new BalancedEncoder(modulus, 3, MemoryPoolHandle.New());

            var poly = encoder.Encode(0);

            Assert.AreEqual(0, poly.SignificantCoeffCount());
            Assert.IsTrue(poly.IsZero);
            Assert.AreEqual(0, encoder.DecodeInt32(poly));

            var poly1 = encoder.Encode(1);

            Assert.AreEqual(1, poly1.SignificantCoeffCount());
            Assert.AreEqual("1", poly1.ToString());
            Assert.AreEqual(1, encoder.DecodeInt32(poly1));

            var poly2 = encoder.Encode(2);

            Assert.AreEqual(2, poly2.SignificantCoeffCount());
            Assert.AreEqual("1x^1 + FFFF", poly2.ToString());
            Assert.AreEqual(2, encoder.DecodeInt32(poly2));

            var poly3 = encoder.Encode(3);

            Assert.AreEqual(2, poly3.SignificantCoeffCount());
            Assert.AreEqual("1x^1", poly3.ToString());
            Assert.AreEqual(3, encoder.DecodeInt32(poly3));

            var poly4 = encoder.Encode(-1);

            Assert.AreEqual(1, poly4.SignificantCoeffCount());
            Assert.AreEqual("FFFF", poly4.ToString());
            Assert.AreEqual(-1, encoder.DecodeInt32(poly4));

            var poly5 = encoder.Encode(-2);

            Assert.AreEqual(2, poly5.SignificantCoeffCount());
            Assert.AreEqual("FFFFx^1 + 1", poly5.ToString());
            Assert.AreEqual(-2, encoder.DecodeInt32(poly5));

            var poly6 = encoder.Encode(-3);

            Assert.AreEqual(2, poly6.SignificantCoeffCount());
            Assert.AreEqual("FFFFx^1", poly6.ToString());
            Assert.AreEqual(-3, encoder.DecodeInt32(poly6));

            var poly7 = encoder.Encode(-0x2671);

            Assert.AreEqual(9, poly7.SignificantCoeffCount());
            for (int i = 0; i < 9; ++i)
            {
                Assert.AreEqual(0xFFFFUL, poly7[i]);
            }
            Assert.AreEqual(-0x2671, encoder.DecodeInt32(poly7));

            var poly8 = encoder.Encode(-4374);

            Assert.AreEqual(9, poly8.SignificantCoeffCount());
            Assert.AreEqual(0xFFFFUL, poly8[8]);
            Assert.AreEqual(1UL, poly8[7]);
            for (int i = 0; i < 7; ++i)
            {
                Assert.IsTrue(poly8[i] == 0);
            }
            Assert.AreEqual(-4374, encoder.DecodeInt32(poly8));

            var poly9 = encoder.Encode(-0xD4EB);

            Assert.AreEqual(11, poly9.SignificantCoeffCount());
            for (int i = 0; i < 11; ++i)
            {
                if (i % 3 == 1)
                {
                    Assert.AreEqual(0xFFFFUL, poly9[i]);
                }
                else if (i % 3 == 0)
                {
                    Assert.IsTrue(poly9[i] == 0);
                }
                else
                {
                    Assert.AreEqual(1UL, poly9[i]);
                }
            }
            Assert.AreEqual(-0xD4EB, encoder.DecodeInt32(poly9));

            var poly10 = encoder.Encode(-30724);

            Assert.AreEqual(11, poly10.SignificantCoeffCount());
            Assert.AreEqual(0xFFFFUL, poly10[10]);
            Assert.AreEqual(1UL, poly10[9]);
            Assert.AreEqual(1UL, poly10[8]);
            Assert.AreEqual(1UL, poly10[7]);
            Assert.IsTrue(poly10[6] == 0);
            Assert.IsTrue(poly10[5] == 0);
            Assert.AreEqual(0xFFFFUL, poly10[4]);
            Assert.AreEqual(0xFFFFUL, poly10[3]);
            Assert.IsTrue(poly10[2] == 0);
            Assert.AreEqual(1UL, poly10[1]);
            Assert.AreEqual(0xFFFFUL, poly10[0]);
            Assert.AreEqual(-30724, encoder.DecodeInt32(poly10));

            modulus.Set(0xFFFF);
            var encoder2 = new BalancedEncoder(modulus, 7, MemoryPoolHandle.New());
            var poly12   = new Plaintext(6);

            poly12[0] = 1;
            poly12[1] = 0xFFFE; // -1
            poly12[2] = 0xFFFD; // -2
            poly12[3] = 0x8000; // -32767
            poly12[4] = 0x7FFF; // 32767
            poly12[5] = 0x7FFE; // 32766
            Assert.AreEqual(1 + -1 * 7 + -2 * 49 + -32767 * 343 + 32767 * 2401 + 32766 * 16807, encoder2.DecodeInt32(poly12));

            var encoder4 = new BalancedEncoder(modulus, 6, MemoryPoolHandle.New());

            poly8    = new Plaintext(4);
            poly8[0] = 5;
            poly8[1] = 4;
            poly8[2] = 3;
            poly8[3] = (modulus.Value - 2);
            Int32 value = 5 + 4 * 6 + 3 * 36 - 2 * 216;

            Assert.AreEqual(value, encoder4.DecodeInt32(poly8));

            var encoder5 = new BalancedEncoder(modulus, 10, MemoryPoolHandle.New());

            poly9    = new Plaintext(4);
            poly9[0] = 1;
            poly9[1] = 2;
            poly9[2] = 3;
            poly9[3] = 4;
            value    = 4321;
            Assert.AreEqual(value, encoder5.DecodeInt32(poly9));

            value = -1234;
            poly10.Set(encoder2.Encode(value));
            Assert.AreEqual(5, poly10.SignificantCoeffCount());
            Assert.IsTrue(value.Equals(encoder2.DecodeInt32(poly10)));

            value = -1234;
            var poly11 = encoder4.Encode(value);

            Assert.AreEqual(5, poly11.SignificantCoeffCount());
            Assert.AreEqual(value, encoder4.DecodeInt32(poly11));

            value = -1234;
            poly12.Set(encoder5.Encode(value));
            Assert.AreEqual(4, poly12.SignificantCoeffCount());
            Assert.IsTrue(value.Equals(encoder5.DecodeInt32(poly12)));
        }
Example #5
0
        public void BalancedEncodeDecodeUInt32NET()
        {
            var modulus = new SmallModulus(0x10000);
            var encoder = new BalancedEncoder(modulus, 3, MemoryPoolHandle.New());

            var poly = encoder.Encode(0U);

            Assert.AreEqual(0, poly.SignificantCoeffCount());
            Assert.IsTrue(poly.IsZero);
            Assert.AreEqual(0U, encoder.DecodeUInt32(poly));

            var poly1 = encoder.Encode(1U);

            Assert.AreEqual(1, poly1.SignificantCoeffCount());
            Assert.AreEqual("1", poly1.ToString());
            Assert.AreEqual(1U, encoder.DecodeUInt32(poly1));

            var poly2 = encoder.Encode(2U);

            Assert.AreEqual(2, poly2.SignificantCoeffCount());
            Assert.AreEqual("1x^1 + FFFF", poly2.ToString());
            Assert.AreEqual(2U, encoder.DecodeUInt32(poly2));

            var poly3 = encoder.Encode(3U);

            Assert.AreEqual(2, poly3.SignificantCoeffCount());
            Assert.AreEqual("1x^1", poly3.ToString());
            Assert.AreEqual(3U, encoder.DecodeUInt32(poly3));

            var poly4 = encoder.Encode(0x2671U);

            Assert.AreEqual(9, poly4.SignificantCoeffCount());
            for (int i = 0; i < 9; ++i)
            {
                Assert.AreEqual(1UL, poly4[i]);
            }
            Assert.AreEqual(0x2671U, encoder.DecodeUInt32(poly4));

            var poly5 = encoder.Encode(0xD4EBU);

            Assert.AreEqual(11, poly5.SignificantCoeffCount());
            for (int i = 0; i < 11; ++i)
            {
                if (i % 3 == 1)
                {
                    Assert.AreEqual(1UL, poly5[i]);
                }
                else if (i % 3 == 0)
                {
                    Assert.IsTrue(poly5[i] == 0);
                }
                else
                {
                    Assert.AreEqual(0xFFFFUL, poly5[i]);
                }
            }
            Assert.AreEqual(0xD4EBU, encoder.DecodeUInt32(poly5));

            var poly6 = new Plaintext(3);

            poly6[0] = 1;
            poly6[1] = 500;
            poly6[2] = 1023;
            Assert.AreEqual(1U + 500 * 3 + 1023 * 9, encoder.DecodeUInt32(poly6));

            var encoder2 = new BalancedEncoder(modulus, 7, MemoryPoolHandle.New());
            var poly7    = new Plaintext(4);

            poly7[0] = 123;    // 123   (*1)
            poly7[1] = 0xFFFF; // -1 (*7)
            poly7[2] = 511;    // 511  (*49)
            poly7[3] = 1;      // 1    (*343)
            Assert.AreEqual((UInt32)(123 + -1 * 7 + 511 * 49 + 1 * 343), encoder2.DecodeUInt32(poly7));

            var encoder3 = new BalancedEncoder(modulus, 6, MemoryPoolHandle.New());
            var poly8    = new Plaintext(4);

            poly8[0] = 5;
            poly8[1] = 4;
            poly8[2] = 3;
            poly8[3] = 2;
            UInt64 value = 5 + 4 * 6 + 3 * 36 + 2 * 216;

            Assert.AreEqual(value, encoder3.DecodeUInt32(poly8));

            var encoder4 = new BalancedEncoder(modulus, 10, MemoryPoolHandle.New());
            var poly9    = new Plaintext(4);

            poly9[0] = 1;
            poly9[1] = 2;
            poly9[2] = 3;
            poly9[3] = 4;
            value    = 4321;
            Assert.AreEqual(value, encoder4.DecodeUInt32(poly9));

            value = 1234;
            var poly10 = encoder2.Encode(value);

            Assert.AreEqual(5, poly10.SignificantCoeffCount());
            Assert.IsTrue(value.Equals(encoder2.DecodeUInt32(poly10)));

            value = 1234;
            var poly11 = encoder3.Encode(value);

            Assert.AreEqual(5, poly11.SignificantCoeffCount());
            Assert.IsTrue(value.Equals(encoder3.DecodeUInt32(poly11)));

            value = 1234;
            var poly12 = encoder4.Encode(value);

            Assert.AreEqual(4, poly12.SignificantCoeffCount());
            Assert.IsTrue(value.Equals(encoder4.DecodeUInt32(poly12)));
        }
        public void FVEncryptDecryptNET()
        {
            var parms         = new EncryptionParameters();
            var plain_modulus = new SmallModulus(1 << 6);

            parms.NoiseStandardDeviation = 3.19;
            parms.PlainModulus           = plain_modulus;
            {
                parms.PolyModulus  = "1x^64 + 1";
                parms.CoeffModulus = new List <SmallModulus> {
                    DefaultParams.SmallMods60Bit(0)
                };
                var context = new SEALContext(parms);

                var keygen  = new KeyGenerator(context);
                var encoder = new BalancedEncoder(plain_modulus);

                var encryptor = new Encryptor(context, keygen.PublicKey);
                var decryptor = new Decryptor(context, keygen.SecretKey);

                var encrypted = new Ciphertext();
                var plain     = new Plaintext();
                encryptor.Encrypt(encoder.Encode(0x12345678), encrypted);
                decryptor.Decrypt(encrypted, plain);
                Assert.AreEqual(0x12345678UL, encoder.DecodeUInt64(plain));
                Assert.AreEqual(encrypted.HashBlock, parms.HashBlock);

                encryptor.Encrypt(encoder.Encode(0), encrypted);
                decryptor.Decrypt(encrypted, plain);
                Assert.AreEqual(0UL, encoder.DecodeUInt64(plain));
                Assert.AreEqual(encrypted.HashBlock, parms.HashBlock);

                encryptor.Encrypt(encoder.Encode(1), encrypted);
                decryptor.Decrypt(encrypted, plain);
                Assert.AreEqual(1UL, encoder.DecodeUInt64(plain));
                Assert.AreEqual(encrypted.HashBlock, parms.HashBlock);

                encryptor.Encrypt(encoder.Encode(2), encrypted);
                decryptor.Decrypt(encrypted, plain);
                Assert.AreEqual(2UL, encoder.DecodeUInt64(plain));
                Assert.AreEqual(encrypted.HashBlock, parms.HashBlock);

                encryptor.Encrypt(encoder.Encode(0x7FFFFFFFFFFFFFFD), encrypted);
                decryptor.Decrypt(encrypted, plain);
                Assert.AreEqual(0x7FFFFFFFFFFFFFFDUL, encoder.DecodeUInt64(plain));
                Assert.AreEqual(encrypted.HashBlock, parms.HashBlock);

                encryptor.Encrypt(encoder.Encode(0x7FFFFFFFFFFFFFFE), encrypted);
                decryptor.Decrypt(encrypted, plain);
                Assert.AreEqual(0x7FFFFFFFFFFFFFFEUL, encoder.DecodeUInt64(plain));
                Assert.AreEqual(encrypted.HashBlock, parms.HashBlock);

                encryptor.Encrypt(encoder.Encode(0x7FFFFFFFFFFFFFFF), encrypted);
                decryptor.Decrypt(encrypted, plain);
                Assert.AreEqual(0x7FFFFFFFFFFFFFFFUL, encoder.DecodeUInt64(plain));
                Assert.AreEqual(encrypted.HashBlock, parms.HashBlock);

                encryptor.Encrypt(encoder.Encode(314159265), encrypted);
                decryptor.Decrypt(encrypted, plain);
                Assert.AreEqual(314159265UL, encoder.DecodeUInt64(plain));
                Assert.AreEqual(encrypted.HashBlock, parms.HashBlock);
            }
            {
                parms.PolyModulus  = "1x^128 + 1";
                parms.CoeffModulus = new List <SmallModulus> {
                    DefaultParams.SmallMods40Bit(0), DefaultParams.SmallMods40Bit(1)
                };
                var context = new SEALContext(parms);
                var keygen  = new KeyGenerator(context);

                var encoder = new BalancedEncoder(plain_modulus);

                var encryptor = new Encryptor(context, keygen.PublicKey);
                var decryptor = new Decryptor(context, keygen.SecretKey);

                var encrypted = new Ciphertext();
                var plain     = new Plaintext();
                encryptor.Encrypt(encoder.Encode(0x12345678), encrypted);
                decryptor.Decrypt(encrypted, plain);
                Assert.AreEqual(0x12345678UL, encoder.DecodeUInt64(plain));
                Assert.AreEqual(encrypted.HashBlock, parms.HashBlock);

                encryptor.Encrypt(encoder.Encode(0), encrypted);
                decryptor.Decrypt(encrypted, plain);
                Assert.AreEqual(0UL, encoder.DecodeUInt64(plain));
                Assert.AreEqual(encrypted.HashBlock, parms.HashBlock);

                encryptor.Encrypt(encoder.Encode(1), encrypted);
                decryptor.Decrypt(encrypted, plain);
                Assert.AreEqual(1UL, encoder.DecodeUInt64(plain));
                Assert.AreEqual(encrypted.HashBlock, parms.HashBlock);

                encryptor.Encrypt(encoder.Encode(2), encrypted);
                decryptor.Decrypt(encrypted, plain);
                Assert.AreEqual(2UL, encoder.DecodeUInt64(plain));
                Assert.AreEqual(encrypted.HashBlock, parms.HashBlock);

                encryptor.Encrypt(encoder.Encode(0x7FFFFFFFFFFFFFFD), encrypted);
                decryptor.Decrypt(encrypted, plain);
                Assert.AreEqual(0x7FFFFFFFFFFFFFFDUL, encoder.DecodeUInt64(plain));
                Assert.AreEqual(encrypted.HashBlock, parms.HashBlock);

                encryptor.Encrypt(encoder.Encode(0x7FFFFFFFFFFFFFFE), encrypted);
                decryptor.Decrypt(encrypted, plain);
                Assert.AreEqual(0x7FFFFFFFFFFFFFFEUL, encoder.DecodeUInt64(plain));
                Assert.AreEqual(encrypted.HashBlock, parms.HashBlock);

                encryptor.Encrypt(encoder.Encode(0x7FFFFFFFFFFFFFFF), encrypted);
                decryptor.Decrypt(encrypted, plain);
                Assert.AreEqual(0x7FFFFFFFFFFFFFFFUL, encoder.DecodeUInt64(plain));
                Assert.AreEqual(encrypted.HashBlock, parms.HashBlock);

                encryptor.Encrypt(encoder.Encode(314159265), encrypted);
                decryptor.Decrypt(encrypted, plain);
                Assert.AreEqual(314159265UL, encoder.DecodeUInt64(plain));
                Assert.AreEqual(encrypted.HashBlock, parms.HashBlock);
            }

            {
                parms.PolyModulus  = "1x^256 + 1";
                parms.CoeffModulus = new List <SmallModulus> {
                    DefaultParams.SmallMods40Bit(0), DefaultParams.SmallMods40Bit(1), DefaultParams.SmallMods40Bit(2)
                };
                var context = new SEALContext(parms);
                var keygen  = new KeyGenerator(context);

                var encoder = new BalancedEncoder(plain_modulus);

                var encryptor = new Encryptor(context, keygen.PublicKey);
                var decryptor = new Decryptor(context, keygen.SecretKey);

                var encrypted = new Ciphertext();
                var plain     = new Plaintext();
                encryptor.Encrypt(encoder.Encode(0x12345678), encrypted);
                decryptor.Decrypt(encrypted, plain);
                Assert.AreEqual(0x12345678UL, encoder.DecodeUInt64(plain));
                Assert.AreEqual(encrypted.HashBlock, parms.HashBlock);

                encryptor.Encrypt(encoder.Encode(0), encrypted);
                decryptor.Decrypt(encrypted, plain);
                Assert.AreEqual(0UL, encoder.DecodeUInt64(plain));
                Assert.AreEqual(encrypted.HashBlock, parms.HashBlock);

                encryptor.Encrypt(encoder.Encode(1), encrypted);
                decryptor.Decrypt(encrypted, plain);
                Assert.AreEqual(1UL, encoder.DecodeUInt64(plain));
                Assert.AreEqual(encrypted.HashBlock, parms.HashBlock);

                encryptor.Encrypt(encoder.Encode(2), encrypted);
                decryptor.Decrypt(encrypted, plain);
                Assert.AreEqual(2UL, encoder.DecodeUInt64(plain));
                Assert.AreEqual(encrypted.HashBlock, parms.HashBlock);

                encryptor.Encrypt(encoder.Encode(0x7FFFFFFFFFFFFFFD), encrypted);
                decryptor.Decrypt(encrypted, plain);
                Assert.AreEqual(0x7FFFFFFFFFFFFFFDUL, encoder.DecodeUInt64(plain));
                Assert.AreEqual(encrypted.HashBlock, parms.HashBlock);

                encryptor.Encrypt(encoder.Encode(0x7FFFFFFFFFFFFFFE), encrypted);
                decryptor.Decrypt(encrypted, plain);
                Assert.AreEqual(0x7FFFFFFFFFFFFFFEUL, encoder.DecodeUInt64(plain));
                Assert.AreEqual(encrypted.HashBlock, parms.HashBlock);

                encryptor.Encrypt(encoder.Encode(0x7FFFFFFFFFFFFFFF), encrypted);
                decryptor.Decrypt(encrypted, plain);
                Assert.AreEqual(0x7FFFFFFFFFFFFFFFUL, encoder.DecodeUInt64(plain));
                Assert.AreEqual(encrypted.HashBlock, parms.HashBlock);

                encryptor.Encrypt(encoder.Encode(314159265), encrypted);
                decryptor.Decrypt(encrypted, plain);
                Assert.AreEqual(314159265UL, encoder.DecodeUInt64(plain));
                Assert.AreEqual(encrypted.HashBlock, parms.HashBlock);
            }
        }
Example #7
0
        static void ExampleBasics()
        {
            PrintExampleBanner("Example: Basics");

            // In this example we demonstrate using some of the basic arithmetic operations on integers.

            // Create encryption parameters.
            var parms = new EncryptionParameters();

            /*
             * First choose the polynomial modulus. This must be a power-of-2 cyclotomic polynomial,
             * i.e. a polynomial of the form "1x^(power-of-2) + 1". We recommend using polynomials of
             * degree at least 1024.
             */
            parms.PolyModulus.Set("1x^4096 + 1");

            /*
             * Next choose the coefficient modulus. The values we recommend to be used are:
             *
             * [ degree(poly_modulus), coeff_modulus ]
             * [ 1024, "FFFFFFFFC001" ],
             * [ 2048, "7FFFFFFFFFFFFFFFFFFF001"],
             * [ 4096, "7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"],
             * [ 8192, "1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC000001"],
             * [ 16384, "7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000001"].
             *
             * These can be conveniently accessed using ChooserEvaluator.DefaultParameterOptions(),
             * which returns the above list of options as a Dictionary, keyed by the degree of the polynomial modulus.
             */
            parms.CoeffModulus.Set(ChooserEvaluator.DefaultParameterOptions[4096]);

            /*
             * Now we set the plaintext modulus. This can be any integer, even though here we take it to be a power of two.
             * A larger plaintext modulus causes the noise to grow faster in homomorphic multiplication, and
             * also lowers the maximum amount of noise in ciphertexts that the system can tolerate.
             * On the other hand, a larger plaintext modulus typically allows for better homomorphic integer arithmetic,
             * although this depends strongly on which encoder is used to encode integers into plaintext polynomials.
             */
            parms.PlainModulus.Set(1 << 10);

            /*
             * The decomposition bit count affects the behavior of the relinearization (key switch) operation,
             * which is typically performed after each homomorphic multiplication. A smaller decomposition
             * bit count makes relinearization slower, but improves the noise growth behavior on multiplication.
             * Conversely, a larger decomposition bit count makes homomorphic multiplication faster at the cost
             * of increased noise growth.
             */
            parms.DecompositionBitCount = 32;

            /*
             * We use a constant standard deviation for the error distribution. Using a larger standard
             * deviation will result in larger noise growth, but in theory should make the system more secure.
             */
            parms.NoiseStandardDeviation = ChooserEvaluator.DefaultNoiseStandardDeviation;

            // For the bound on the error distribution we can take for instance 5 * standard_deviation.
            parms.NoiseMaxDeviation = 5 * parms.NoiseStandardDeviation;

            Console.WriteLine("Encryption parameters specify {0} coefficients with {1} bits per coefficient",
                              parms.PolyModulus.GetSignificantCoeffCount(), parms.CoeffModulus.GetSignificantBitCount());

            // Encode two integers as polynomials.
            const int value1   = 5;
            const int value2   = -7;
            var       encoder  = new BalancedEncoder(parms.PlainModulus);
            var       encoded1 = encoder.Encode(value1);
            var       encoded2 = encoder.Encode(value2);

            Console.WriteLine("Encoded {0} as polynomial {1}", value1, encoded1);
            Console.WriteLine("Encoded {0} as polynomial {1}", value2, encoded2);

            // Generate keys.
            Console.WriteLine("Generating keys...");
            var generator = new KeyGenerator(parms);

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

            //Console.WriteLine("Public Key = {0}", publicKey);
            //Console.WriteLine("Secret Key = {0}", secretKey);

            // Encrypt values.
            Console.WriteLine("Encrypting values...");
            var encryptor  = new Encryptor(parms, publicKey);
            var encrypted1 = encryptor.Encrypt(encoded1);
            var encrypted2 = encryptor.Encrypt(encoded2);

            // Perform arithmetic on encrypted values.
            Console.WriteLine("Performing encrypted arithmetic...");
            var evaluator = new Evaluator(parms, evaluationKeys);

            Console.WriteLine("... Performing negation...");
            var encryptedNegated1 = evaluator.Negate(encrypted1);

            Console.WriteLine("... Performing addition...");
            var encryptedSum = evaluator.Add(encrypted1, encrypted2);

            Console.WriteLine("... Performing subtraction...");
            var encryptedDiff = evaluator.Sub(encrypted1, encrypted2);

            Console.WriteLine("... Performing multiplication...");
            var encryptedProduct = evaluator.Multiply(encrypted1, encrypted2);

            // Decrypt results.
            Console.WriteLine("Decrypting results...");
            var decryptor         = new Decryptor(parms, secretKey);
            var decrypted1        = decryptor.Decrypt(encrypted1);
            var decrypted2        = decryptor.Decrypt(encrypted2);
            var decryptedNegated1 = decryptor.Decrypt(encryptedNegated1);
            var decryptedSum      = decryptor.Decrypt(encryptedSum);
            var decryptedDiff     = decryptor.Decrypt(encryptedDiff);
            var decryptedProduct  = decryptor.Decrypt(encryptedProduct);

            // Decode results.
            var decoded1        = encoder.DecodeInt32(decrypted1);
            var decoded2        = encoder.DecodeInt32(decrypted2);
            var decodedNegated1 = encoder.DecodeInt32(decryptedNegated1);
            var decodedSum      = encoder.DecodeInt32(decryptedSum);
            var decodedDiff     = encoder.DecodeInt32(decryptedDiff);
            var decodedProduct  = encoder.DecodeInt32(decryptedProduct);

            // Display results.
            Console.WriteLine("{0} after encryption/decryption = {1}", value1, decoded1);
            Console.WriteLine("{0} after encryption/decryption = {1}", value2, decoded2);
            Console.WriteLine("encrypted negate of {0} = {1}", value1, decodedNegated1);
            Console.WriteLine("encrypted addition of {0} and {1} = {2}", value1, value2, decodedSum);
            Console.WriteLine("encrypted subtraction of {0} and {1} = {2}", value1, value2, decodedDiff);
            Console.WriteLine("encrypted multiplication of {0} and {1} = {2}", value1, value2, decodedProduct);

            // How did the noise grow in these operations?
            var maxNoiseBitCount = Utilities.InherentNoiseMax(parms).GetSignificantBitCount();

            Console.WriteLine("Noise in encryption of {0}: {1}/{2} bits", value1, Utilities.InherentNoise(encrypted1, parms, secretKey).GetSignificantBitCount(), maxNoiseBitCount);
            Console.WriteLine("Noise in encryption of {0}: {1}/{2} bits", value2, Utilities.InherentNoise(encrypted1, parms, secretKey).GetSignificantBitCount(), maxNoiseBitCount);
            Console.WriteLine("Noise in the sum: {0}/{1} bits", Utilities.InherentNoise(encryptedSum, parms, secretKey).GetSignificantBitCount(), maxNoiseBitCount);
            Console.WriteLine("Noise in the product: {0}/{1} bits", Utilities.InherentNoise(encryptedProduct, parms, secretKey).GetSignificantBitCount(), maxNoiseBitCount);
        }
Example #8
0
        static void ExampleParameterSelection()
        {
            PrintExampleBanner("Example: Automatic Parameter Selection");

            /*
             * Here we demonstrate the automatic parameter selection tool. Suppose we want to find parameters
             * that are optimized in a way that allows us to evaluate the polynomial 42x^3-27x+1. We need to know
             * the size of the input data, so let's assume that x is an integer with base-3 representation of length
             * at most 10.
             */
            Console.Write("Finding optimized parameters for computing 42x^3-27x+1 ... ");

            var chooserEncoder   = new ChooserEncoder();
            var chooserEvaluator = new ChooserEvaluator();

            // First create a ChooserPoly representing the input data. You can think of this modeling a freshly
            // encrypted cipheretext of a plaintext polynomial with length at most 10 coefficients, where the
            // coefficients have absolute value at most 1.
            var cinput = new ChooserPoly(10, 1);

            // Compute the first term
            var ccubedInput = chooserEvaluator.Exponentiate(cinput, 3);
            var cterm1      = chooserEvaluator.MultiplyPlain(ccubedInput, chooserEncoder.Encode(42));

            // Compute the second term
            var cterm2 = chooserEvaluator.MultiplyPlain(cinput, chooserEncoder.Encode(27));

            // Subtract the first two terms
            var csum12 = chooserEvaluator.Sub(cterm1, cterm2);

            // Add the constant term 1
            var cresult = chooserEvaluator.AddPlain(csum12, chooserEncoder.Encode(1));

            // To find an optimized set of parameters, we use ChooserEvaluator::select_parameters(...).
            var optimalParms = new EncryptionParameters();

            chooserEvaluator.SelectParameters(cresult, optimalParms);

            Console.WriteLine("done.");

            // Let's print these to see what was recommended
            Console.WriteLine("Selected parameters:");
            Console.WriteLine("{{ poly_modulus: {0}", optimalParms.PolyModulus.ToString());
            Console.WriteLine("{{ coeff_modulus: {0}", optimalParms.CoeffModulus.ToString());
            Console.WriteLine("{{ plain_modulus: {0}", optimalParms.PlainModulus.ToDecimalString());
            Console.WriteLine("{{ decomposition_bit_count: {0}", optimalParms.DecompositionBitCount);
            Console.WriteLine("{{ noise_standard_deviation: {0}", optimalParms.NoiseStandardDeviation);
            Console.WriteLine("{{ noise_max_deviation: {0}", optimalParms.NoiseMaxDeviation);

            // Let's try to actually perform the homomorphic computation using the recommended parameters.
            // Generate keys.
            Console.WriteLine("Generating keys...");
            var generator = new KeyGenerator(optimalParms);

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

            // Create the encoding/encryption tools
            var encoder   = new BalancedEncoder(optimalParms.PlainModulus);
            var encryptor = new Encryptor(optimalParms, publicKey);
            var evaluator = new Evaluator(optimalParms, evaluationKeys);
            var decryptor = new Decryptor(optimalParms, secretKey);

            // Now perform the computations on real encrypted data.
            const int inputValue = 12345;
            var       plainInput = encoder.Encode(inputValue);

            Console.WriteLine("Encoded {0} as polynomial {1}", inputValue, plainInput.ToString());

            Console.Write("Encrypting ... ");
            var input = encryptor.Encrypt(plainInput);

            Console.WriteLine("done.");

            // Compute the first term
            Console.Write("Computing first term ... ");
            var cubedInput = evaluator.Exponentiate(input, 3);
            var term1      = evaluator.MultiplyPlain(cubedInput, encoder.Encode(42));

            Console.WriteLine("done.");

            // Compute the second term
            Console.Write("Computing second term ... ");
            var term2 = evaluator.MultiplyPlain(input, encoder.Encode(27));

            Console.WriteLine("done.");

            // Subtract the first two terms
            Console.Write("Subtracting first two terms ... ");
            var sum12 = evaluator.Sub(term1, term2);

            Console.WriteLine("done.");

            // Add the constant term 1
            Console.Write("Adding one ... ");
            var result = evaluator.AddPlain(sum12, encoder.Encode(1));

            Console.WriteLine("done.");

            // Decrypt and decode
            Console.Write("Decrypting ... ");
            var plainResult = decryptor.Decrypt(result);

            Console.WriteLine("done.");

            // Finally print the result
            Console.WriteLine("Polynomial 42x^3-27x+1 evaluated at x=12345: {0}", encoder.DecodeUInt64(plainResult));

            // How much noise did we end up with?
            Console.WriteLine("Noise in the result: {0}/{1} bits", Utilities.InherentNoise(result, optimalParms, secretKey).GetSignificantBitCount(),
                              Utilities.InherentNoiseMax(optimalParms).GetSignificantBitCount());
        }
Example #9
0
        public static void ExampleBasics()
        {
            PrintExampleBanner("Example: Basics");

            /*
             * In this example we demonstrate using some of the basic arithmetic operations on integers.
             *
             * SEAL uses the Fan-Vercauteren (FV) homomorphic encryption scheme. We refer to
             * https://eprint.iacr.org/2012/144 for full details on how the FV scheme works.
             */

            // Create encryption parameters.
            var parms = new EncryptionParameters();

            /*
             * First choose the polynomial modulus. This must be a power-of-2 cyclotomic polynomial,
             * i.e. a polynomial of the form "1x^(power-of-2) + 1". We recommend using polynomials of
             * degree at least 1024.
             */
            parms.PolyModulus.Set("1x^2048 + 1");

            /*
             * Next choose the coefficient modulus. The values we recommend to be used are:
             *
             * [ degree(PolyModulus), CoeffModulus ]
             * [ 1024, "FFFFFFF00001" ],
             * [ 2048, "3FFFFFFFFFFFFFFFFFF00001"],
             * [ 4096, "3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC0000001"],
             * [ 8192, "7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE00000001"],
             * [ 16384, "7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000001"].
             *
             * These can be conveniently accessed using ChooserEvaluator.DefaultParameterOptions, which returns
             * the above list of options as a Dictionary, keyed by the degree of the polynomial modulus.
             *
             * The user can also relatively easily choose their custom coefficient modulus. It should be a prime number
             * of the form 2^A - 2^B + 1, where A > B > degree(PolyModulus). Moreover, B should be as small as possible
             * for improved efficiency in modular reduction. For security, we recommend strictly adhering to the following
             * size bounds: (see Lepoint-Naehrig (2014) [https://eprint.iacr.org/2014/062])
             * /-----------------------------------------------------------------\
             | PolyModulus  | CoeffModulus bound | default CoeffModulus        |
             | -------------|--------------------|-----------------------------|
             | 1x^1024 + 1  | 48 bits            | 2^48 - 2^20 + 1 (47 bits)   |
             | 1x^2048 + 1  | 96 bits            | 2^94 - 2^20 + 1 (93 bits)   |
             | 1x^4096 + 1  | 192 bits           | 2^190 - 2^30 + 1 (189 bits) |
             | 1x^8192 + 1  | 384 bits           | 2^383 - 2^33 + 1 (382 bits) |
             | 1x^16384 + 1 | 768 bits           | 2^767 - 2^56 + 1 (766 bits) |
             \-----------------------------------------------------------------/
             |
             | The size of CoeffModulus affects the upper bound on the "inherent noise" that a ciphertext can contain
             | before becoming corrupted. More precisely, every ciphertext starts with a certain amount of noise in it,
             | which grows in all homomorphic operations - in particular in multiplication. Once a ciphertext contains
             | too much noise, it becomes impossible to decrypt. The upper bound on the noise is roughly given by
             | CoeffModulus/PlainModulus (see below), so increasing CoeffModulus will allow the user to perform more
             | homomorphic operations on the ciphertexts without corrupting them. We would like to stress, however, that
             | the bounds given above for CoeffModulus should absolutely not be exceeded.
             */
            parms.CoeffModulus.Set(ChooserEvaluator.DefaultParameterOptions[2048]);

            /*
             * Now we set the plaintext modulus. This can be any positive integer, even though here we take it to be a
             * power of two. A larger plaintext modulus causes the noise to grow faster in homomorphic multiplication,
             * and also lowers the maximum amount of noise in ciphertexts that the system can tolerate (see above).
             * On the other hand, a larger plaintext modulus typically allows for better homomorphic integer arithmetic,
             * although this depends strongly on which encoder is used to encode integers into plaintext polynomials.
             */
            parms.PlainModulus.Set(1 << 8);

            Console.WriteLine("Encryption parameters specify {0} coefficients with {1} bits per coefficient",
                              parms.PolyModulus.GetSignificantCoeffCount(), parms.CoeffModulus.GetSignificantBitCount());

            /*
             * Plaintext elements in the FV scheme are polynomials (represented by the BigPoly class) with coefficients
             * integers modulo plain_modulus. To encrypt integers instead, one must use an "encoding scheme", i.e.
             * a specific way of representing integers as such polynomials. SEAL comes with a few basic encoders:
             *
             * BinaryEncoder:
             * Encodes positive integers as plaintext polynomials where the coefficients are either 0 or 1 according
             * to the binary representation of the integer to be encoded. Decoding amounts to evaluating the polynomial
             * at x=2. For example, the integer 26 = 2^4 + 2^3 + 2^1 is encoded as the polynomial 1x^4 + 1x^3 + 1x^1.
             * Negative integers are encoded similarly but with each coefficient coefficient of the polynomial replaced
             * with its negative modulo PlainModulus.
             *
             * BalancedEncoder:
             * Given an odd integer base b, encodes integers as plaintext polynomials where the coefficients are according
             * to the "balanced" base b representation of the integer to be encoded, i.e. where each coefficient is in the
             * range -(b-1)/2,...,(b-1)/2. Decoding amounts to evaluating the polynomial at x=b. For example, when b=3 the
             * integer 25 = 3^3 - 3^1 + 3^0 is encoded as the polynomial 1x^3 - 1x^1 + 1.
             *
             * BinaryFractionalEncoder:
             * Encodes rational numbers as follows. First represent the number in binary, possibly truncating an infinite
             * fractional part to some fixed precision, e.g. 26.75 = 2^4 + 2^3 + 2^1 + 2^(-1) + 2^(-2). For the sake of
             * the example, suppose PolyModulus is 1x^1024 + 1. Next represent the integer part of the number in the same
             * was as in BinaryEncoder. Finally, represent the fractional part in the leading coefficients of the polynomial,
             * but when doing so invert the signs of the coefficients. So in this example we would represent 26.75 as the
             * polynomial -1x^1023 - 1x^1022 + 1x^4 + 1x^3 + 1x^1. The negative coefficients of the polynomial will again be
             * represented as their negatives modulo PlainModulus.
             *
             * BalancedFractionalEncoder:
             * Same as BinaryFractionalEncoder, except instead of using base 2 uses any odd base b and balanced
             * representatives for the coefficients, i.e. integers in the range -(b-1)/2,...,(b-1)/2.
             *
             * PolyCRTBuilder:
             * If PolyModulus is 1x^n + 1, PolyCRTBuilder allows "batching" of n plaintext integers modulo PlainModulus
             * into one plaintext polynomial, where homomorphic operations can be carried out very efficiently in a SIMD
             * manner by operating on such a "composed" plaintext or ciphertext polynomials. For full details on this very
             * powerful technique we recommend https://eprint.iacr.org/2012/565.pdf and https://eprint.iacr.org/2011/133.
             *
             * A crucial fact to understand is that when homomorphic operations are performed on ciphertexts, they will
             * carry over to the underlying plaintexts, and as a result of additions and multiplications the coefficients
             * in the plaintext polynomials will increase from what they originally were in freshly encoded polynomials.
             * This becomes a problem when the coefficients reach the size of PlainModulus, in which case they will get
             * automatically reduced modulo PlainModulus, and might render the underlying plaintext polynomial impossible
             * to be correctly decoded back into an integer or rational number. Therefore, it is typically crucial to
             * have a good sense of how large the coefficients will grow in the underlying plaintext polynomials when
             * homomorphic computations are carried out on the ciphertexts, and make sure that PlainModulus is chosen to
             * be at least as large as this number.
             */

            // Encode two integers as polynomials.
            const int value1   = 5;
            const int value2   = -7;
            var       encoder  = new BalancedEncoder(parms.PlainModulus);
            var       encoded1 = encoder.Encode(value1);
            var       encoded2 = encoder.Encode(value2);

            Console.WriteLine("Encoded {0} as polynomial {1}", value1, encoded1);
            Console.WriteLine("Encoded {0} as polynomial {1}", value2, encoded2);

            // Generate keys.
            Console.WriteLine("Generating keys...");
            var generator = new KeyGenerator(parms);

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

            //Console.WriteLine("Public Key = {0}", publicKey);
            //Console.WriteLine("Secret Key = {0}", secretKey);

            // Encrypt values.
            Console.WriteLine("Encrypting values...");
            var encryptor  = new Encryptor(parms, publicKey);
            var encrypted1 = encryptor.Encrypt(encoded1);
            var encrypted2 = encryptor.Encrypt(encoded2);

            // Perform arithmetic on encrypted values.
            Console.WriteLine("Performing encrypted arithmetic...");
            var evaluator = new Evaluator(parms);

            Console.WriteLine("... Performing negation...");
            var encryptedNegated1 = evaluator.Negate(encrypted1);

            Console.WriteLine("... Performing addition...");
            var encryptedSum = evaluator.Add(encrypted1, encrypted2);

            Console.WriteLine("... Performing subtraction...");
            var encryptedDiff = evaluator.Sub(encrypted1, encrypted2);

            Console.WriteLine("... Performing multiplication...");
            var encryptedProduct = evaluator.Multiply(encrypted1, encrypted2);

            // Decrypt results.
            Console.WriteLine("Decrypting results...");
            var decryptor         = new Decryptor(parms, secretKey);
            var decrypted1        = decryptor.Decrypt(encrypted1);
            var decrypted2        = decryptor.Decrypt(encrypted2);
            var decryptedNegated1 = decryptor.Decrypt(encryptedNegated1);
            var decryptedSum      = decryptor.Decrypt(encryptedSum);
            var decryptedDiff     = decryptor.Decrypt(encryptedDiff);
            var decryptedProduct  = decryptor.Decrypt(encryptedProduct);

            // Decode results.
            var decoded1        = encoder.DecodeInt32(decrypted1);
            var decoded2        = encoder.DecodeInt32(decrypted2);
            var decodedNegated1 = encoder.DecodeInt32(decryptedNegated1);
            var decodedSum      = encoder.DecodeInt32(decryptedSum);
            var decodedDiff     = encoder.DecodeInt32(decryptedDiff);
            var decodedProduct  = encoder.DecodeInt32(decryptedProduct);

            // Display results.
            Console.WriteLine("{0} after encryption/decryption = {1}", value1, decoded1);
            Console.WriteLine("{0} after encryption/decryption = {1}", value2, decoded2);
            Console.WriteLine("encrypted negate of {0} = {1}", value1, decodedNegated1);
            Console.WriteLine("encrypted addition of {0} and {1} = {2}", value1, value2, decodedSum);
            Console.WriteLine("encrypted subtraction of {0} and {1} = {2}", value1, value2, decodedDiff);
            Console.WriteLine("encrypted multiplication of {0} and {1} = {2}", value1, value2, decodedProduct);

            // How did the noise grow in these operations?
            var maxNoiseBitCount = Utilities.InherentNoiseMax(parms).GetSignificantBitCount();

            Console.WriteLine("Noise in encryption of {0}: {1}/{2} bits", value1, Utilities.InherentNoise(encrypted1, parms, secretKey).GetSignificantBitCount(), maxNoiseBitCount);
            Console.WriteLine("Noise in encryption of {0}: {1}/{2} bits", value2, Utilities.InherentNoise(encrypted1, parms, secretKey).GetSignificantBitCount(), maxNoiseBitCount);
            Console.WriteLine("Noise in the sum: {0}/{1} bits", Utilities.InherentNoise(encryptedSum, parms, secretKey).GetSignificantBitCount(), maxNoiseBitCount);
            Console.WriteLine("Noise in the product: {0}/{1} bits", Utilities.InherentNoise(encryptedProduct, parms, secretKey).GetSignificantBitCount(), maxNoiseBitCount);
        }