Example #1
0
        public void ScaleTest()
        {
            EncryptionParameters parms = new EncryptionParameters(SchemeType.CKKS)
            {
                PolyModulusDegree = 8,
                CoeffModulus      = CoeffModulus.Create(8, new int[] { 40, 40, 40, 40 })
            };
            SEALContext context = new SEALContext(parms,
                                                  expandModChain: true,
                                                  secLevel: SecLevelType.None);
            KeyGenerator keygen = new KeyGenerator(context);

            keygen.CreatePublicKey(out PublicKey publicKey);
            keygen.CreateGaloisKeys(out GaloisKeys galoisKeys);

            Encryptor   encryptor = new Encryptor(context, publicKey);
            Evaluator   evaluator = new Evaluator(context);
            CKKSEncoder encoder   = new CKKSEncoder(context);

            MemoryPoolHandle pool = MemoryManager.GetPool(MMProfOpt.ForceNew);

            Assert.AreEqual(0ul, pool.AllocByteCount);

            Ciphertext encrypted = new Ciphertext(pool);
            Plaintext  plain     = new Plaintext();

            MemoryPoolHandle cipherPool = encrypted.Pool;

            Assert.IsNotNull(cipherPool);
            Assert.AreEqual(0ul, cipherPool.AllocByteCount);

            List <Complex> input = new List <Complex>()
            {
                new Complex(1, 1),
                new Complex(2, 2),
                new Complex(3, 3),
                new Complex(4, 4)
            };
            double delta = Math.Pow(2, 70);

            encoder.Encode(input, context.FirstParmsId, delta, plain);
            encryptor.Encrypt(plain, encrypted);

            Assert.AreEqual(delta, encrypted.Scale, delta: Math.Pow(2, 60));

            Ciphertext encrypted2 = new Ciphertext();

            encrypted2.Set(encrypted);
            Assert.AreEqual(delta, encrypted2.Scale, delta: Math.Pow(2, 60));

            evaluator.RescaleToNextInplace(encrypted);

            Assert.AreEqual(Math.Pow(2, 30), encrypted.Scale, delta: 10000);
            Assert.AreNotEqual(0ul, cipherPool.AllocByteCount);

            double newScale = Math.Pow(2, 10);

            encrypted.Scale = newScale;
            Assert.AreEqual(newScale, encrypted.Scale, delta: 100);
        }
Example #2
0
        public void EncodeDecodeComplexTest()
        {
            EncryptionParameters parms = new EncryptionParameters(SchemeType.CKKS)
            {
                PolyModulusDegree = 64,
                CoeffModulus      = new List <SmallModulus>()
                {
                    DefaultParams.SmallMods40Bit(0),
                    DefaultParams.SmallMods40Bit(1),
                    DefaultParams.SmallMods40Bit(2),
                    DefaultParams.SmallMods40Bit(3)
                }
            };

            SEALContext context = SEALContext.Create(parms);
            CKKSEncoder encoder = new CKKSEncoder(context);

            Plaintext plain = new Plaintext();
            Complex   value = new Complex(3.1415, 2.71828);

            encoder.Encode(value, scale: Math.Pow(2, 20), destination: plain);

            List <Complex> result = new List <Complex>();

            encoder.Decode(plain, result);

            Assert.IsTrue(result.Count > 0);
            Assert.AreEqual(3.1415, result[0].Real, delta: 0.0001);
            Assert.AreEqual(2.71828, result[0].Imaginary, delta: 0.0001);
        }
Example #3
0
        public void EncodeDecodeComplexTest()
        {
            EncryptionParameters parms = new EncryptionParameters(SchemeType.CKKS)
            {
                PolyModulusDegree = 64,
                CoeffModulus      = CoeffModulus.Create(64, new int[] { 40, 40, 40, 40 })
            };

            SEALContext context = new SEALContext(parms,
                                                  expandModChain: false,
                                                  secLevel: SecLevelType.None);
            CKKSEncoder encoder = new CKKSEncoder(context);

            Plaintext plain = new Plaintext();
            Complex   value = new Complex(3.1415, 2.71828);

            encoder.Encode(value, scale: Math.Pow(2, 20), destination: plain);

            List <Complex> result = new List <Complex>();

            encoder.Decode(plain, result);

            Assert.IsTrue(result.Count > 0);
            Assert.AreEqual(3.1415, result[0].Real, delta: 0.0001);
            Assert.AreEqual(2.71828, result[0].Imaginary, delta: 0.0001);
        }
Example #4
0
        public void EncodeDecodeUlongTest()
        {
            int slots = 32;
            EncryptionParameters parms = new EncryptionParameters(SchemeType.CKKS);

            parms.PolyModulusDegree = (ulong)slots * 2;
            parms.CoeffModulus      = CoeffModulus.Create(64, new int[] { 40, 40, 40, 40 });
            SEALContext context = new SEALContext(parms,
                                                  expandModChain: false,
                                                  secLevel: SecLevelType.None);
            CKKSEncoder encoder = new CKKSEncoder(context);

            Plaintext      plain  = new Plaintext();
            List <Complex> result = new List <Complex>();

            long value = 15;

            encoder.Encode(value, plain);
            encoder.Decode(plain, result);

            for (int i = 0; i < slots; i++)
            {
                double tmp = Math.Abs(value - result[i].Real);
                Assert.IsTrue(tmp < 0.5);
            }
        }
Example #5
0
        public void EncodeDecodeDoubleTest()
        {
            EncryptionParameters parms = new EncryptionParameters(SchemeType.CKKS);

            parms.PolyModulusDegree = 64;
            parms.CoeffModulus      = CoeffModulus.Create(64, new int[] { 40, 40, 40, 40 });
            SEALContext context = new SEALContext(parms,
                                                  expandModChain: false,
                                                  secLevel: SecLevelType.None);

            int            slots  = 16;
            Plaintext      plain  = new Plaintext();
            double         delta  = 1 << 16;
            List <Complex> result = new List <Complex>();

            CKKSEncoder encoder = new CKKSEncoder(context);

            Assert.AreEqual(32ul, encoder.SlotCount);

            double value = 10d;

            encoder.Encode(value, delta, plain);
            encoder.Decode(plain, result);

            for (int i = 0; i < slots; i++)
            {
                double tmp = Math.Abs(value - result[i].Real);
                Assert.IsTrue(tmp < 0.5);
            }
        }
Example #6
0
        public void EncodeDecodeVectorDoubleTest()
        {
            EncryptionParameters parms = new EncryptionParameters(SchemeType.CKKS)
            {
                PolyModulusDegree = 64,
                CoeffModulus      = CoeffModulus.Create(64, new int[] { 30, 30 })
            };

            SEALContext context = new SEALContext(parms,
                                                  expandModChain: false,
                                                  secLevel: SecLevelType.None);
            CKKSEncoder encoder = new CKKSEncoder(context);
            Plaintext   plain   = new Plaintext();

            double[] values = new double[] { 0.1, 2.3, 34.4 };
            encoder.Encode(values, scale: Math.Pow(2, 20), destination: plain);

            List <double> result = new List <double>();

            encoder.Decode(plain, result);

            Assert.IsNotNull(result);
            Assert.AreEqual(0.1, result[0], delta: 0.001);
            Assert.AreEqual(2.3, result[1], delta: 0.001);
            Assert.AreEqual(34.4, result[2], delta: 0.001);
        }
Example #7
0
        public void EncodeDecodeUlongTest()
        {
            int slots = 32;
            EncryptionParameters parms = new EncryptionParameters(SchemeType.CKKS);

            parms.PolyModulusDegree = (ulong)slots * 2;
            List <SmallModulus> coeffModulus = new List <SmallModulus>(4);

            coeffModulus.Add(DefaultParams.SmallMods40Bit(0));
            coeffModulus.Add(DefaultParams.SmallMods40Bit(1));
            coeffModulus.Add(DefaultParams.SmallMods40Bit(2));
            coeffModulus.Add(DefaultParams.SmallMods40Bit(3));
            parms.CoeffModulus = coeffModulus;
            SEALContext context = SEALContext.Create(parms);
            CKKSEncoder encoder = new CKKSEncoder(context);

            Plaintext      plain  = new Plaintext();
            List <Complex> result = new List <Complex>();

            long value = 15;

            encoder.Encode(value, plain);
            encoder.Decode(plain, result);

            for (int i = 0; i < slots; i++)
            {
                double tmp = Math.Abs(value - result[i].Real);
                Assert.IsTrue(tmp < 0.5);
            }
        }
Example #8
0
        //
        private static void SinglePredict(Svc secureSvc, double[] feature, int i, CKKSEncoder encoder, Encryptor encryptor, Decryptor decryptor,
                                          Stopwatch innerProductStopwatch, Stopwatch degreeStopwatch, Stopwatch negateStopwatch, Stopwatch serverDecisionStopWatch, double scale, Result[] results)
        {
            double finalResult = 0;

            Console.WriteLine($"start {i} \n");

            var plaintexts          = new Plaintext();
            var featuresCiphertexts = new Ciphertext();

            encoder.Encode(feature, scale, plaintexts);
            encryptor.Encrypt(plaintexts, featuresCiphertexts);
            // Server side start
            var cyphetResult = secureSvc.Predict(featuresCiphertexts, true, true, innerProductStopwatch, degreeStopwatch, negateStopwatch, serverDecisionStopWatch);
            // Server side end
            //timePredictSum.Stop();
            Plaintext plainResult = new Plaintext();

            decryptor.Decrypt(cyphetResult, plainResult);
            List <double> result = new List <double>();

            encoder.Decode(plainResult, result);
            finalResult = result[0];
            int estimation = finalResult > 0 ? 0 : 1;

            Console.WriteLine($"\n ************************************************");
            Console.WriteLine($"SVC estimation{i} is : {estimation} , result : {finalResult}");
            //file.WriteLine($"{i} , {estimation} , {finalResult} ");
            Console.WriteLine($"************************************************ \n");
            results[i] = new Result(finalResult, estimation);
            //Console.WriteLine($"SecureSVC estimation{i} is : {estimation} , finalResult = {finalResult} , Time = {timePredictSum.ElapsedMilliseconds}");
        }
Example #9
0
        public static List <Ciphertext> Encrypt(
            this byte[] data,
            CKKSEncoder encoder,
            Encryptor encryptor,
            double scale,
            int slots)
        {
            return(ComputeInBatches(
                       data,
                       slots,
                       bytes =>
            {
                using var pt = new Plaintext();
                encoder.Encode(
                    bytes.Select(d => Convert.ToDouble(d)),
                    scale,
                    pt);

                var ct = new Ciphertext();

                encryptor.Encrypt(pt, ct);

                return ct;
            }));
        }
Example #10
0
        public void EncodeDecodeVectorDoubleTest()
        {
            EncryptionParameters parms = new EncryptionParameters(SchemeType.CKKS)
            {
                PolyModulusDegree = 64,
                CoeffModulus      = new List <SmallModulus>()
                {
                    DefaultParams.SmallMods30Bit(0),
                    DefaultParams.SmallMods30Bit(1)
                }
            };

            SEALContext context = SEALContext.Create(parms);
            CKKSEncoder encoder = new CKKSEncoder(context);
            Plaintext   plain   = new Plaintext();

            double[] values = new double[] { 0.1, 2.3, 34.4 };
            encoder.Encode(values, scale: Math.Pow(2, 20), destination: plain);

            List <double> result = new List <double>();

            encoder.Decode(plain, result);

            Assert.IsNotNull(result);
            Assert.AreEqual(0.1, result[0], delta: 0.001);
            Assert.AreEqual(2.3, result[1], delta: 0.001);
            Assert.AreEqual(34.4, result[2], delta: 0.001);
        }
Example #11
0
        public void EncodeDecodeDoubleTest()
        {
            EncryptionParameters parms = new EncryptionParameters(SchemeType.CKKS);

            parms.PolyModulusDegree = 64;
            List <SmallModulus> coeffModulus = new List <SmallModulus>(4);

            coeffModulus.Add(DefaultParams.SmallMods40Bit(0));
            coeffModulus.Add(DefaultParams.SmallMods40Bit(1));
            coeffModulus.Add(DefaultParams.SmallMods40Bit(2));
            coeffModulus.Add(DefaultParams.SmallMods40Bit(3));
            parms.CoeffModulus = coeffModulus;
            SEALContext context = SEALContext.Create(parms);

            int            slots  = 16;
            Plaintext      plain  = new Plaintext();
            double         delta  = 1 << 16;
            List <Complex> result = new List <Complex>();

            CKKSEncoder encoder = new CKKSEncoder(context);

            Assert.AreEqual(32ul, encoder.SlotCount);

            double value = 10d;

            encoder.Encode(value, delta, plain);
            encoder.Decode(plain, result);

            for (int i = 0; i < slots; i++)
            {
                double tmp = Math.Abs(value - result[i].Real);
                Assert.IsTrue(tmp < 0.5);
            }
        }
        public Bitmap DecryptFromVector(
            Decryptor decryptor,
            CKKSEncoder encoder)
        {
            var bmp = new Bitmap(_width, _height);

            var rVals = _rValueVector.DecryptData(decryptor, encoder);
            var gVals = _gValueVector.DecryptData(decryptor, encoder);
            var bVals = _bValueVector.DecryptData(decryptor, encoder);

            var data = new List <int>();

            var ind = 0;

            for (var i = 0; i < bmp.Width; i++)
            {
                for (var j = 0; j < bmp.Height; j++)
                {
                    var color = Color.FromArgb(
                        _aValues[ind],
                        rVals[ind],
                        gVals[ind],
                        bVals[ind]);

                    data.Add(rVals[ind]);

                    bmp.SetPixel(i, j, color);

                    ind++;
                }
            }

            return(bmp);
        }
 public CKKSDecryptor(SEALContext Context, SecretKey privateKey)
 {
     //Takes in a context and private key and creates instance of decoder and Context.
     context   = Context;
     scale     = Math.Pow(2.0, 40);
     decryptor = new Decryptor(Context, privateKey);
     encoder   = new CKKSEncoder(Context);
 }
Example #14
0
        public ImageProcessorServer(
            Evaluator evaluator,
            CKKSEncoder encoder,
            double scale)
        {
            _evaluator = evaluator ?? throw new ArgumentNullException(nameof(evaluator));

            encoder.Encode(0.3, scale, RMultiplePtx);
            encoder.Encode(0.59, scale, GMultiplePtx);
            encoder.Encode(0.11, scale, BMultiplePtx);
        }
        public static EncryptedImage FromBmp(
            Bitmap bmp,
            Encryptor encryptor,
            CKKSEncoder encoder,
            double scale,
            int slots)
        {
            var count = bmp.Height * bmp.Width;

            var aVals = new int[count];
            var rVals = new Ciphertext[count];
            var gVals = new Ciphertext[count];
            var bVals = new Ciphertext[count];

            var rValPlain = new byte[count];
            var gValPlain = new byte[count];
            var bValPlain = new byte[count];

            var ind = 0;

            for (var i = 0; i < bmp.Width; i++)
            {
                for (var j = 0; j < bmp.Height; j++)
                {
                    var pixel = bmp.GetPixel(i, j);

                    aVals[ind] = pixel.A;

                    rValPlain[ind] = pixel.R;
                    gValPlain[ind] = pixel.G;
                    bValPlain[ind] = pixel.B;

                    // Add when implementing edge detector.
                    // rVals[ind] = pixel.R.Encrypt(encoder, encryptor, scale);
                    // gVals[ind] = pixel.G.Encrypt(encoder, encryptor, scale);
                    // bVals[ind] = pixel.B.Encrypt(encoder, encryptor, scale);

                    ind++;
                }
            }

            return(new EncryptedImage(
                       bmp.Width,
                       bmp.Height,
                       aVals,
                       rVals,
                       gVals,
                       bVals,
                       rValPlain.Encrypt(encoder, encryptor, scale, slots),
                       gValPlain.Encrypt(encoder, encryptor, scale, slots),
                       bValPlain.Encrypt(encoder, encryptor, scale, slots)));
        }
Example #16
0
 public SalaryComputation()
 {
     //Constructor.
     parms = new EncryptionParameters(SchemeType.CKKS);
     parms.PolyModulusDegree = polyModulusDegree;
     parms.CoeffModulus      = CoeffModulus.Create(
         polyModulusDegree, new int[] { 60, 40, 40, 60 });
     //parms.PlainModulus = PlainModulus.Batching(polyModulusDegree, 20);
     context   = new SEALContext(parms);
     evaluator = new Evaluator(context);
     encoder   = new CKKSEncoder(context);
     SetConstants();
 }
Example #17
0
			//private static bool _firstTime = true;

            //private static Decryptor _decryptor;

            public SecureSvc(int nRows, double[][] vectors, double[][] coefficients, double[] intercepts,
				 String kernel, double gamma, double coef0, ulong degree , int power)
			{


				//this._nRows			= nRows;

				this._vectors		= vectors;
				this._coefficients	= coefficients;
				this._intercepts		= intercepts;

				this._kernel			= Enum.Parse<Kernel>(kernel, true);
				this._gamma			= gamma;
				this._coef0			= coef0;
				this._degree			= degree;
				this._power			= power;
				EncryptionParameters parms = new EncryptionParameters(SchemeType.CKKS);

				ulong polyModulusDegree = 16384;
				
				if (power >= 20 && power < 40 )
				{
					parms.CoeffModulus = CoeffModulus.Create(polyModulusDegree,
						new int[] { 60, 20, 21, 22, 23, 24, 25, 26, 27, 60 });
				}
				else if (power >= 40 && power < 60)
				{
					parms.CoeffModulus = CoeffModulus.Create(polyModulusDegree,
						new int[] { 60, 40, 40, 40, 40, 40, 40, 40 , 60 });
				}
				else if (power == 60)
				{
					polyModulusDegree = 32768;
                    parms.CoeffModulus = CoeffModulus.Create(polyModulusDegree,
						new int[] { 60, 60, 60, 60, 60, 60, 60, 60, 60 });
				}
				parms.PolyModulusDegree = polyModulusDegree;
                _context = new SEALContext(parms);

				KeyGenerator keygen = new KeyGenerator(_context);
				_publicKey = keygen.PublicKey;
				_secretKey = keygen.SecretKey;
				_relinKeys = keygen.RelinKeys();
				_galoisKeys = keygen.GaloisKeys();

				_encryptor = new Encryptor(_context, _publicKey);
				_evaluator = new Evaluator(_context);
				_decryptor = new Decryptor(_context, _secretKey);
				_encoder = new CKKSEncoder(_context);
			}
 public BMIComputation(RelinKeys Keys)
 {
     parms = new EncryptionParameters(SchemeType.CKKS);
     parms.PolyModulusDegree = polyModulusDegree;
     parms.CoeffModulus      = CoeffModulus.Create(
         polyModulusDegree, new int[] { 60, 40, 40, 60 });
     //parms.PlainModulus = PlainModulus.Batching(polyModulusDegree, 20);
     context   = new SEALContext(parms);
     evaluator = new Evaluator(context);
     encoder   = new CKKSEncoder(context);
     scale     = Math.Pow(2.0, 40);
     SetConstants();
     KeysRelin = Keys;
 }
Example #19
0
        public static Ciphertext Encrypt(
            this byte data,
            CKKSEncoder encoder,
            Encryptor encryptor,
            double scale)
        {
            using var pt = new Plaintext();
            encoder.Encode(Convert.ToDouble(data), scale, pt);

            var ct = new Ciphertext();

            encryptor.Encrypt(pt, ct);

            return(ct);
        }
Example #20
0
 public CKKSEncryptor()
 {
     //Set scheme Primes and encryption parameters.
     parms = new EncryptionParameters(SchemeType.CKKS);
     parms.PolyModulusDegree = polyModulusDegree;
     parms.CoeffModulus      = CoeffModulus.Create(
         polyModulusDegree, new int[] { 60, 40, 40, 60 });
     scale   = Math.Pow(2.0, 40);
     context = new SEALContext(parms);
     keygen  = new KeyGenerator(context);
     //Generate private and public key.
     publicKey = keygen.PublicKey;
     secretKey = keygen.SecretKey;
     encryptor = new Encryptor(context, publicKey);
     encoder   = new CKKSEncoder(context);
     KeysRelin = keygen.RelinKeys();
 }
Example #21
0
 public static Plaintext[][][] GetWeightsPlaintext(CKKSEncoder encoder, double scale, double[][][] weights)
 {
     Plaintext[][][] toReturn = new Plaintext[weights.Length][][];
     for (int i = 0; i < weights.Length; i++)
     {
         Plaintext[][] layerWeightsPlaintext = new Plaintext[weights[i].Length][];
         for (int j = 0; j < weights[i].Length; j++)
         {
             Plaintext[] layerNodeWeightsPlaintext = new Plaintext[weights[i][j].Length];
             for (int k = 0; k < weights[i][j].Length; k++)
             {
                 Plaintext weightPT = new Plaintext();
                 encoder.Encode(weights[i][j][k], scale, weightPT);
                 layerNodeWeightsPlaintext[k] = weightPT;
             }
             layerWeightsPlaintext[j] = layerNodeWeightsPlaintext;
         }
         toReturn[i] = layerWeightsPlaintext;
     }
     return(toReturn);
 }
Example #22
0
        public void EncodeDecodeVectorTest()
        {
            int slots = 32;
            EncryptionParameters parms = new EncryptionParameters(SchemeType.CKKS);

            parms.PolyModulusDegree = (ulong)slots * 2;
            List <SmallModulus> coeffModulus = new List <SmallModulus>(4);

            coeffModulus.Add(DefaultParams.SmallMods60Bit(0));
            coeffModulus.Add(DefaultParams.SmallMods60Bit(1));
            coeffModulus.Add(DefaultParams.SmallMods60Bit(2));
            coeffModulus.Add(DefaultParams.SmallMods60Bit(3));
            parms.CoeffModulus = coeffModulus;
            SEALContext context = SEALContext.Create(parms);
            CKKSEncoder encoder = new CKKSEncoder(context);

            List <Complex> values    = new List <Complex>(slots);
            Random         rnd       = new Random();
            int            dataBound = 1 << 30;
            double         delta     = 1ul << 40;

            for (int i = 0; i < slots; i++)
            {
                values.Add(new Complex(rnd.Next() % dataBound, 0));
            }

            Plaintext plain = new Plaintext();

            encoder.Encode(values, delta, plain);

            List <Complex> result = new List <Complex>();

            encoder.Decode(plain, result);

            for (int i = 0; i < slots; i++)
            {
                double tmp = Math.Abs(values[i].Real - result[i].Real);
                Assert.IsTrue(tmp < 0.5);
            }
        }
Example #23
0
        public static List <int> DecryptData(
            this List <Ciphertext> ctxs,
            Decryptor decryptor,
            CKKSEncoder encoder)
        {
            var result = new List <int>();

            foreach (var ctx in ctxs)
            {
                using var ptx = new Plaintext();
                decryptor.Decrypt(ctx, ptx);

                var data = new List <double>();

                encoder.Decode(ptx, data);

                var integers = data.Select(d => (int)d);

                result.AddRange(integers);
            }

            return(result);
        }
        public ImageProcessorClient()
        {
            parms = new EncryptionParameters(SchemeType.CKKS);
            parms.PolyModulusDegree = (ulong)PolyModulusDegree;
            parms.CoeffModulus      = CoeffModulus.Create((ulong)PolyModulusDegree, new int[] { 60, 40, 40, 60 });

            double scale = Math.Pow(2.0, 40);

            context = new SEALContext(parms);

            keygen    = new KeyGenerator(context);
            secretKey = keygen.SecretKey;
            keygen.CreatePublicKey(out PublicKey publicKey);

            // keygen.CreateRelinKeys(out RelinKeys relinKeys);

            encryptor = new Encryptor(context, publicKey);
            evaluator = new Evaluator(context);
            decryptor = new Decryptor(context, secretKey);

            encoder = new CKKSEncoder(context);

            var v1 = Enumerable.Range(0, 2000).Select(e => (double)200);
            var v2 = Enumerable.Range(0, 4000).Select(e => (double)200);
            var v3 = Enumerable.Range(0, 4096).Select(e => (double)200);

            var pd1 = new Plaintext();
            var pd2 = new Plaintext();
            var pd3 = new Plaintext();

            //encoder.Encode(v1, scale, pd1);
            //encoder.Encode(v1, scale, pd2);
            //encoder.Encode(v1, scale, pd3);

            // Pass in encode and evaluator to server.
            _imageProcessorServer = new ImageProcessorServer(evaluator, encoder, scale);
        }
Example #25
0
        public void EncodeDecodeVectorTest()
        {
            int slots = 32;
            EncryptionParameters parms = new EncryptionParameters(SchemeType.CKKS);

            parms.PolyModulusDegree = (ulong)slots * 2;
            parms.CoeffModulus      = CoeffModulus.Create((ulong)slots * 2, new int[] { 60, 60, 60, 60 });
            SEALContext context = new SEALContext(parms,
                                                  expandModChain: false,
                                                  secLevel: SecLevelType.None);
            CKKSEncoder encoder = new CKKSEncoder(context);

            List <Complex> values    = new List <Complex>(slots);
            Random         rnd       = new Random();
            int            dataBound = 1 << 30;
            double         delta     = 1ul << 40;

            for (int i = 0; i < slots; i++)
            {
                values.Add(new Complex(rnd.Next() % dataBound, 0));
            }

            Plaintext plain = new Plaintext();

            encoder.Encode(values, delta, plain);

            List <Complex> result = new List <Complex>();

            encoder.Decode(plain, result);

            for (int i = 0; i < slots; i++)
            {
                double tmp = Math.Abs(values[i].Real - result[i].Real);
                Assert.IsTrue(tmp < 0.5);
            }
        }
Example #26
0
        static private void ExampleCKKSEncoder()
        {
            Utilities.PrintExampleBanner("Example: Encoders / CKKS Encoder");

            /*
             * [CKKSEncoder] (For CKKS scheme only)
             *
             * In this example we demonstrate the Cheon-Kim-Kim-Song (CKKS) scheme for
             * computing on encrypted real or complex numbers. We start by creating
             * encryption parameters for the CKKS scheme. There are two important
             * differences compared to the BFV scheme:
             *
             *  (1) CKKS does not use the PlainModulus encryption parameter;
             *  (2) Selecting the CoeffModulus in a specific way can be very important
             *      when using the CKKS scheme. We will explain this further in the file
             *      `CKKS_Basics.cs'. In this example we use CoeffModulus.Create to
             *      generate 5 40-bit prime numbers.
             */
            using EncryptionParameters parms = new EncryptionParameters(SchemeType.CKKS);

            ulong polyModulusDegree = 8192;

            parms.PolyModulusDegree = polyModulusDegree;
            parms.CoeffModulus      = CoeffModulus.Create(
                polyModulusDegree, new int[] { 40, 40, 40, 40, 40 });

            /*
             * We create the SEALContext as usual and print the parameters.
             */
            using SEALContext context = new SEALContext(parms);
            Utilities.PrintParameters(context);
            Console.WriteLine();

            /*
             * Keys are created the same way as for the BFV scheme.
             */
            using KeyGenerator keygen = new KeyGenerator(context);
            using SecretKey secretKey = keygen.SecretKey;
            keygen.CreatePublicKey(out PublicKey publicKey);
            keygen.CreateRelinKeys(out RelinKeys relinKeys);

            /*
             * We also set up an Encryptor, Evaluator, and Decryptor as usual.
             */
            using Encryptor encryptor = new Encryptor(context, publicKey);
            using Evaluator evaluator = new Evaluator(context);
            using Decryptor decryptor = new Decryptor(context, secretKey);

            /*
             * To create CKKS plaintexts we need a special encoder: there is no other way
             * to create them. The BatchEncoder cannot be used with the
             * CKKS scheme. The CKKSEncoder encodes vectors of real or complex numbers into
             * Plaintext objects, which can subsequently be encrypted. At a high level this
             * looks a lot like what BatchEncoder does for the BFV scheme, but the theory
             * behind it is completely different.
             */
            using CKKSEncoder encoder = new CKKSEncoder(context);

            /*
             * In CKKS the number of slots is PolyModulusDegree / 2 and each slot encodes
             * one real or complex number. This should be contrasted with BatchEncoder in
             * the BFV scheme, where the number of slots is equal to PolyModulusDegree
             * and they are arranged into a matrix with two rows.
             */
            ulong slotCount = encoder.SlotCount;

            Console.WriteLine($"Number of slots: {slotCount}");

            /*
             * We create a small vector to encode; the CKKSEncoder will implicitly pad it
             * with zeros to full size (PolyModulusDegree / 2) when encoding.
             */
            double[] input = new double[] { 0.0, 1.1, 2.2, 3.3 };
            Console.WriteLine("Input vector: ");
            Utilities.PrintVector(input);

            /*
             * Now we encode it with CKKSEncoder. The floating-point coefficients of `input'
             * will be scaled up by the parameter `scale'. This is necessary since even in
             * the CKKS scheme the plaintext elements are fundamentally polynomials with
             * integer coefficients. It is instructive to think of the scale as determining
             * the bit-precision of the encoding; naturally it will affect the precision of
             * the result.
             *
             * In CKKS the message is stored modulo CoeffModulus (in BFV it is stored modulo
             * PlainModulus), so the scaled message must not get too close to the total size
             * of CoeffModulus. In this case our CoeffModulus is quite large (200 bits) so
             * we have little to worry about in this regard. For this simple example a 30-bit
             * scale is more than enough.
             */
            using Plaintext plain = new Plaintext();
            double scale = Math.Pow(2.0, 30);

            Utilities.PrintLine();
            Console.WriteLine("Encode input vector.");
            encoder.Encode(input, scale, plain);

            /*
             * We can instantly decode to check the correctness of encoding.
             */
            List <double> output = new List <double>();

            Console.WriteLine("    + Decode input vector ...... Correct.");
            encoder.Decode(plain, output);
            Utilities.PrintVector(output);

            /*
             * The vector is encrypted the same was as in BFV.
             */
            using Ciphertext encrypted = new Ciphertext();
            Utilities.PrintLine();
            Console.WriteLine("Encrypt input vector, square, and relinearize.");
            encryptor.Encrypt(plain, encrypted);

            /*
             * Basic operations on the ciphertexts are still easy to do. Here we square
             * the ciphertext, decrypt, decode, and print the result. We note also that
             * decoding returns a vector of full size (PolyModulusDegree / 2); this is
             * because of the implicit zero-padding mentioned above.
             */
            evaluator.SquareInplace(encrypted);
            evaluator.RelinearizeInplace(encrypted, relinKeys);

            /*
             * We notice that the scale in the result has increased. In fact, it is now
             * the square of the original scale: 2^60.
             */
            Console.WriteLine("    + Scale in squared input: {0} ({1} bits)",
                              encrypted.Scale,
                              (int)Math.Ceiling(Math.Log(encrypted.Scale, newBase: 2)));
            Utilities.PrintLine();
            Console.WriteLine("Decrypt and decode.");
            decryptor.Decrypt(encrypted, plain);
            encoder.Decode(plain, output);
            Console.WriteLine("    + Result vector ...... Correct.");
            Utilities.PrintVector(output);

            /*
             * The CKKS scheme allows the scale to be reduced between encrypted computations.
             * This is a fundamental and critical feature that makes CKKS very powerful and
             * flexible. We will discuss it in great detail in `3_Levels.cs' and later in
             * `4_CKKS_Basics.cs'.
             */
        }
Example #27
0
        private static void CKKSPerformanceTest(SEALContext context)
        {
            Stopwatch timer;

            Utilities.PrintParameters(context);
            Console.WriteLine();

            bool hasZLIB = Serialization.IsSupportedComprMode(ComprModeType.ZLIB);
            bool hasZSTD = Serialization.IsSupportedComprMode(ComprModeType.ZSTD);

            using EncryptionParameters parms = context.FirstContextData.Parms;
            ulong polyModulusDegree = parms.PolyModulusDegree;

            Console.Write("Generating secret/public keys: ");
            using KeyGenerator keygen = new KeyGenerator(context);
            Console.WriteLine("Done");

            using SecretKey secretKey = keygen.SecretKey;
            keygen.CreatePublicKey(out PublicKey publicKey);

            Func <RelinKeys> GetRelinKeys = () => {
                if (context.UsingKeyswitching)
                {
                    /*
                     * Generate relinearization keys.
                     */
                    Console.Write("Generating relinearization keys: ");
                    timer = Stopwatch.StartNew();
                    keygen.CreateRelinKeys(out RelinKeys relinKeys);
                    int micros = (int)(timer.Elapsed.TotalMilliseconds * 1000);
                    Console.WriteLine($"Done [{micros} microseconds]");
                    return(relinKeys);
                }
                else
                {
                    return(null);
                }
            };

            Func <GaloisKeys> GetGaloisKeys = () => {
                if (context.UsingKeyswitching)
                {
                    if (!context.KeyContextData.Qualifiers.UsingBatching)
                    {
                        Console.WriteLine("Given encryption parameters do not support batching.");
                        return(null);
                    }

                    /*
                     * Generate Galois keys. In larger examples the Galois keys can use a lot of
                     * memory, which can be a problem in constrained systems. The user should
                     * try some of the larger runs of the test and observe their effect on the
                     * memory pool allocation size. The key generation can also take a long time,
                     * as can be observed from the print-out.
                     */
                    Console.Write($"Generating Galois keys: ");
                    timer = Stopwatch.StartNew();
                    keygen.CreateGaloisKeys(out GaloisKeys galoisKeys);
                    int micros = (int)(timer.Elapsed.TotalMilliseconds * 1000);
                    Console.WriteLine($"Done [{micros} microseconds]");
                    return(galoisKeys);
                }
                else
                {
                    return(null);
                }
            };

            using RelinKeys relinKeys = GetRelinKeys();
            using GaloisKeys galKeys  = GetGaloisKeys();

            using Encryptor encryptor     = new Encryptor(context, publicKey);
            using Decryptor decryptor     = new Decryptor(context, secretKey);
            using Evaluator evaluator     = new Evaluator(context);
            using CKKSEncoder ckksEncoder = new CKKSEncoder(context);

            Stopwatch timeEncodeSum        = new Stopwatch();
            Stopwatch timeDecodeSum        = new Stopwatch();
            Stopwatch timeEncryptSum       = new Stopwatch();
            Stopwatch timeDecryptSum       = new Stopwatch();
            Stopwatch timeAddSum           = new Stopwatch();
            Stopwatch timeMultiplySum      = new Stopwatch();
            Stopwatch timeMultiplyPlainSum = new Stopwatch();
            Stopwatch timeSquareSum        = new Stopwatch();
            Stopwatch timeRelinearizeSum   = new Stopwatch();
            Stopwatch timeRescaleSum       = new Stopwatch();
            Stopwatch timeRotateOneStepSum = new Stopwatch();
            Stopwatch timeRotateRandomSum  = new Stopwatch();
            Stopwatch timeConjugateSum     = new Stopwatch();
            Stopwatch timeSerializeSum     = new Stopwatch();
            Stopwatch timeSerializeZLIBSum = new Stopwatch();
            Stopwatch timeSerializeZSTDSum = new Stopwatch();

            Random rnd = new Random();

            /*
             * How many times to run the test?
             */
            int count = 10;

            /*
             * Populate a vector of floating-point values to batch.
             */
            ulong slotCount = ckksEncoder.SlotCount;

            double[] podValues = new double[slotCount];
            for (ulong i = 0; i < slotCount; i++)
            {
                podValues[i] = 1.001 * i;
            }

            Console.Write("Running tests ");
            for (int i = 0; i < count; i++)
            {
                /*
                 * [Encoding]
                 * For scale we use the square root of the last CoeffModulus prime
                 * from parms.
                 */
                double scale = Math.Sqrt(parms.CoeffModulus.Last().Value);
                using Plaintext plain = new Plaintext(parms.PolyModulusDegree *
                                                      (ulong)parms.CoeffModulus.Count(), 0);
                timeEncodeSum.Start();
                ckksEncoder.Encode(podValues, scale, plain);
                timeEncodeSum.Stop();

                /*
                 * [Decoding]
                 */
                List <double> podList = new List <double>((int)slotCount);
                timeDecodeSum.Start();
                ckksEncoder.Decode(plain, podList);
                timeDecodeSum.Stop();

                /*
                 * [Encryption]
                 */
                using Ciphertext encrypted = new Ciphertext(context);
                timeEncryptSum.Start();
                encryptor.Encrypt(plain, encrypted);
                timeEncryptSum.Stop();

                /*
                 * [Decryption]
                 */
                using Plaintext plain2 = new Plaintext(polyModulusDegree, 0);
                timeDecryptSum.Start();
                decryptor.Decrypt(encrypted, plain2);
                timeDecryptSum.Stop();

                /*
                 * [Add]
                 */
                using Ciphertext encrypted1 = new Ciphertext(context);
                ckksEncoder.Encode(i + 1, plain);
                encryptor.Encrypt(plain, encrypted1);
                using Ciphertext encrypted2 = new Ciphertext(context);
                ckksEncoder.Encode(i + 1, plain2);
                encryptor.Encrypt(plain2, encrypted2);
                timeAddSum.Start();
                evaluator.AddInplace(encrypted1, encrypted2);
                evaluator.AddInplace(encrypted2, encrypted2);
                evaluator.AddInplace(encrypted1, encrypted2);
                timeAddSum.Stop();

                /*
                 * [Multiply]
                 */
                encrypted1.Reserve(3);
                timeMultiplySum.Start();
                evaluator.MultiplyInplace(encrypted1, encrypted2);
                timeMultiplySum.Stop();

                /*
                 * [Multiply Plain]
                 */
                timeMultiplyPlainSum.Start();
                evaluator.MultiplyPlainInplace(encrypted2, plain);
                timeMultiplyPlainSum.Stop();

                /*
                 * [Square]
                 */
                timeSquareSum.Start();
                evaluator.SquareInplace(encrypted2);
                timeSquareSum.Stop();

                if (context.UsingKeyswitching)
                {
                    /*
                     * [Relinearize]
                     */
                    timeRelinearizeSum.Start();
                    evaluator.RelinearizeInplace(encrypted1, relinKeys);
                    timeRelinearizeSum.Stop();

                    /*
                     * [Rescale]
                     */
                    timeRescaleSum.Start();
                    evaluator.RescaleToNextInplace(encrypted1);
                    timeRescaleSum.Stop();

                    /*
                     * [Rotate Vector]
                     */
                    timeRotateOneStepSum.Start();
                    evaluator.RotateVectorInplace(encrypted, 1, galKeys);
                    evaluator.RotateVectorInplace(encrypted, -1, galKeys);
                    timeRotateOneStepSum.Stop();

                    /*
                     * [Rotate Vector Random]
                     */
                    // ckksEncoder.SlotCount is always a power of 2.
                    int randomRotation = rnd.Next() & ((int)ckksEncoder.SlotCount - 1);
                    timeRotateRandomSum.Start();
                    evaluator.RotateVectorInplace(encrypted, randomRotation, galKeys);
                    timeRotateRandomSum.Stop();

                    /*
                     * [Complex Conjugate]
                     */
                    timeConjugateSum.Start();
                    evaluator.ComplexConjugateInplace(encrypted, galKeys);
                    timeConjugateSum.Stop();
                }

                /*
                 * [Serialize Ciphertext]
                 */
                using MemoryStream stream = new MemoryStream();
                timeSerializeSum.Start();
                encrypted.Save(stream, ComprModeType.None);
                timeSerializeSum.Stop();

                if (hasZLIB)
                {
                    /*
                     * [Serialize Ciphertext (ZLIB)]
                     */
                    timeSerializeZLIBSum.Start();
                    encrypted.Save(stream, ComprModeType.ZLIB);
                    timeSerializeZLIBSum.Stop();
                }

                if (hasZSTD)
                {
                    /*
                     * [Serialize Ciphertext (Zstandard)]
                     */
                    timeSerializeZSTDSum.Start();
                    encrypted.Save(stream, ComprModeType.ZSTD);
                    timeSerializeZSTDSum.Stop();
                }

                /*
                 * Print a dot to indicate progress.
                 */
                Console.Write(".");
                Console.Out.Flush();
            }

            Console.WriteLine(" Done");
            Console.WriteLine();
            Console.Out.Flush();

            int avgEncode           = (int)(timeEncodeSum.Elapsed.TotalMilliseconds * 1000 / count);
            int avgDecode           = (int)(timeDecodeSum.Elapsed.TotalMilliseconds * 1000 / count);
            int avgEncrypt          = (int)(timeEncryptSum.Elapsed.TotalMilliseconds * 1000 / count);
            int avgDecrypt          = (int)(timeDecryptSum.Elapsed.TotalMilliseconds * 1000 / count);
            int avgAdd              = (int)(timeAddSum.Elapsed.TotalMilliseconds * 1000 / (3 * count));
            int avgMultiply         = (int)(timeMultiplySum.Elapsed.TotalMilliseconds * 1000 / count);
            int avgMultiplyPlain    = (int)(timeMultiplyPlainSum.Elapsed.TotalMilliseconds * 1000 / count);
            int avgSquare           = (int)(timeSquareSum.Elapsed.TotalMilliseconds * 1000 / count);
            int avgRelinearize      = (int)(timeRelinearizeSum.Elapsed.TotalMilliseconds * 1000 / count);
            int avgRescale          = (int)(timeRescaleSum.Elapsed.TotalMilliseconds * 1000 / count);
            int avgRotateOneStep    = (int)(timeRotateOneStepSum.Elapsed.TotalMilliseconds * 1000 / (2 * count));
            int avgRotateRandom     = (int)(timeRotateRandomSum.Elapsed.TotalMilliseconds * 1000 / count);
            int avgConjugate        = (int)(timeConjugateSum.Elapsed.TotalMilliseconds * 1000 / count);
            int avgSerializeSum     = (int)(timeSerializeSum.Elapsed.TotalMilliseconds * 1000 / count);
            int avgSerializeZLIBSum = (int)(timeSerializeZLIBSum.Elapsed.TotalMilliseconds * 1000 / count);
            int avgSerializeZSTDSum = (int)(timeSerializeZSTDSum.Elapsed.TotalMilliseconds * 1000 / count);

            Console.WriteLine($"Average encode: {avgEncode} microseconds");
            Console.WriteLine($"Average decode: {avgDecode} microseconds");
            Console.WriteLine($"Average encrypt: {avgEncrypt} microseconds");
            Console.WriteLine($"Average decrypt: {avgDecrypt} microseconds");
            Console.WriteLine($"Average add: {avgAdd} microseconds");
            Console.WriteLine($"Average multiply: {avgMultiply} microseconds");
            Console.WriteLine($"Average multiply plain: {avgMultiplyPlain} microseconds");
            Console.WriteLine($"Average square: {avgSquare} microseconds");
            if (context.UsingKeyswitching)
            {
                Console.WriteLine($"Average relinearize: {avgRelinearize} microseconds");
                Console.WriteLine($"Average rescale: {avgRescale} microseconds");
                Console.WriteLine($"Average rotate vector one step: {avgRotateOneStep} microseconds");
                Console.WriteLine($"Average rotate vector random: {avgRotateRandom} microseconds");
                Console.WriteLine($"Average complex conjugate: {avgConjugate} microseconds");
            }
            Console.WriteLine($"Average serialize ciphertext: {avgSerializeSum} microseconds");
            if (hasZLIB)
            {
                Console.WriteLine(
                    $"Average compressed (ZLIB) serialize ciphertext: {avgSerializeZLIBSum} microseconds");
            }
            if (hasZSTD)
            {
                Console.WriteLine(
                    $"Average compressed (Zstandard) serialize ciphertext: {avgSerializeZSTDSum} microseconds");
            }

            Console.Out.Flush();
        }
Example #28
0
        private static void ExampleCKKSBasics()
        {
            Utilities.PrintExampleBanner("Example: CKKS Basics");

            /*
             * In this example we demonstrate evaluating a polynomial function
             *
             *  PI*x^3 + 0.4*x + 1
             *
             * on encrypted floating-point input data x for a set of 4096 equidistant points
             * in the interval [0, 1]. This example demonstrates many of the main features
             * of the CKKS scheme, but also the challenges in using it.
             *
             * We start by setting up the CKKS scheme.
             */
            using EncryptionParameters parms = new EncryptionParameters(SchemeType.CKKS);

            /*
             * We saw in `2_Encoders.cs' that multiplication in CKKS causes scales in
             * ciphertexts to grow. The scale of any ciphertext must not get too close to
             * the total size of CoeffModulus, or else the ciphertext simply runs out of
             * room to store the scaled-up plaintext. The CKKS scheme provides a `rescale'
             * functionality that can reduce the scale, and stabilize the scale expansion.
             *
             * Rescaling is a kind of modulus switch operation (recall `3_Levels.cs').
             * As modulus switching, it removes the last of the primes from CoeffModulus,
             * but as a side-effect it scales down the ciphertext by the removed prime.
             * Usually we want to have perfect control over how the scales are changed,
             * which is why for the CKKS scheme it is more common to use carefully selected
             * primes for the CoeffModulus.
             *
             * More precisely, suppose that the scale in a CKKS ciphertext is S, and the
             * last prime in the current CoeffModulus (for the ciphertext) is P. Rescaling
             * to the next level changes the scale to S/P, and removes the prime P from the
             * CoeffModulus, as usual in modulus switching. The number of primes limits
             * how many rescalings can be done, and thus limits the multiplicative depth of
             * the computation.
             *
             * It is possible to choose the initial scale freely. One good strategy can be
             * to is to set the initial scale S and primes P_i in the CoeffModulus to be
             * very close to each other. If ciphertexts have scale S before multiplication,
             * they have scale S^2 after multiplication, and S^2/P_i after rescaling. If all
             * P_i are close to S, then S^2/P_i is close to S again. This way we stabilize the
             * scales to be close to S throughout the computation. Generally, for a circuit
             * of depth D, we need to rescale D times, i.e., we need to be able to remove D
             * primes from the coefficient modulus. Once we have only one prime left in the
             * coeff_modulus, the remaining prime must be larger than S by a few bits to
             * preserve the pre-decimal-point value of the plaintext.
             *
             * Therefore, a generally good strategy is to choose parameters for the CKKS
             * scheme as follows:
             *
             *  (1) Choose a 60-bit prime as the first prime in CoeffModulus. This will
             *      give the highest precision when decrypting;
             *  (2) Choose another 60-bit prime as the last element of CoeffModulus, as
             *      this will be used as the special prime and should be as large as the
             *      largest of the other primes;
             *  (3) Choose the intermediate primes to be close to each other.
             *
             * We use CoeffModulus.Create to generate primes of the appropriate size. Note
             * that our CoeffModulus is 200 bits total, which is below the bound for our
             * PolyModulusDegree: CoeffModulus.MaxBitCount(8192) returns 218.
             */
            ulong polyModulusDegree = 8192;

            parms.PolyModulusDegree = polyModulusDegree;
            parms.CoeffModulus      = CoeffModulus.Create(
                polyModulusDegree, new int[] { 60, 40, 40, 60 });

            /*
             * We choose the initial scale to be 2^40. At the last level, this leaves us
             * 60-40=20 bits of precision before the decimal point, and enough (roughly
             * 10-20 bits) of precision after the decimal point. Since our intermediate
             * primes are 40 bits (in fact, they are very close to 2^40), we can achieve
             * scale stabilization as described above.
             */
            double scale = Math.Pow(2.0, 40);

            using SEALContext context = new SEALContext(parms);
            Utilities.PrintParameters(context);
            Console.WriteLine();

            using KeyGenerator keygen = new KeyGenerator(context);
            using PublicKey publicKey = keygen.PublicKey;
            using SecretKey secretKey = keygen.SecretKey;
            using RelinKeys relinKeys = keygen.RelinKeysLocal();
            using Encryptor encryptor = new Encryptor(context, publicKey);
            using Evaluator evaluator = new Evaluator(context);
            using Decryptor decryptor = new Decryptor(context, secretKey);

            using CKKSEncoder encoder = new CKKSEncoder(context);
            ulong slotCount = encoder.SlotCount;

            Console.WriteLine($"Number of slots: {slotCount}");

            List <double> input = new List <double>((int)slotCount);
            double        currPoint = 0, stepSize = 1.0 / (slotCount - 1);

            for (ulong i = 0; i < slotCount; i++, currPoint += stepSize)
            {
                input.Add(currPoint);
            }
            Console.WriteLine("Input vector:");
            Utilities.PrintVector(input, 3, 7);

            Console.WriteLine("Evaluating polynomial PI*x^3 + 0.4x + 1 ...");

            /*
             * We create plaintexts for PI, 0.4, and 1 using an overload of CKKSEncoder.Encode
             * that encodes the given floating-point value to every slot in the vector.
             */
            using Plaintext plainCoeff3 = new Plaintext(),
                  plainCoeff1           = new Plaintext(),
                  plainCoeff0           = new Plaintext();
            encoder.Encode(3.14159265, scale, plainCoeff3);
            encoder.Encode(0.4, scale, plainCoeff1);
            encoder.Encode(1.0, scale, plainCoeff0);

            using Plaintext xPlain = new Plaintext();
            Utilities.PrintLine();
            Console.WriteLine("Encode input vectors.");
            encoder.Encode(input, scale, xPlain);
            using Ciphertext x1Encrypted = new Ciphertext();
            encryptor.Encrypt(xPlain, x1Encrypted);

            /*
             * To compute x^3 we first compute x^2 and relinearize. However, the scale has
             * now grown to 2^80.
             */
            using Ciphertext x3Encrypted = new Ciphertext();
            Utilities.PrintLine();
            Console.WriteLine("Compute x^2 and relinearize:");
            evaluator.Square(x1Encrypted, x3Encrypted);
            evaluator.RelinearizeInplace(x3Encrypted, relinKeys);
            Console.WriteLine("    + Scale of x^2 before rescale: {0} bits",
                              Math.Log(x3Encrypted.Scale, newBase: 2));

            /*
             * Now rescale; in addition to a modulus switch, the scale is reduced down by
             * a factor equal to the prime that was switched away (40-bit prime). Hence, the
             * new scale should be close to 2^40. Note, however, that the scale is not equal
             * to 2^40: this is because the 40-bit prime is only close to 2^40.
             */
            Utilities.PrintLine();
            Console.WriteLine("Rescale x^2.");
            evaluator.RescaleToNextInplace(x3Encrypted);
            Console.WriteLine("    + Scale of x^2 after rescale: {0} bits",
                              Math.Log(x3Encrypted.Scale, newBase: 2));

            /*
             * Now x3Encrypted is at a different level than x1Encrypted, which prevents us
             * from multiplying them to compute x^3. We could simply switch x1Encrypted to
             * the next parameters in the modulus switching chain. However, since we still
             * need to multiply the x^3 term with PI (plainCoeff3), we instead compute PI*x
             * first and multiply that with x^2 to obtain PI*x^3. To this end, we compute
             * PI*x and rescale it back from scale 2^80 to something close to 2^40.
             */
            Utilities.PrintLine();
            Console.WriteLine("Compute and rescale PI*x.");
            using Ciphertext x1EncryptedCoeff3 = new Ciphertext();
            evaluator.MultiplyPlain(x1Encrypted, plainCoeff3, x1EncryptedCoeff3);
            Console.WriteLine("    + Scale of PI*x before rescale: {0} bits",
                              Math.Log(x1EncryptedCoeff3.Scale, newBase: 2));
            evaluator.RescaleToNextInplace(x1EncryptedCoeff3);
            Console.WriteLine("    + Scale of PI*x after rescale: {0} bits",
                              Math.Log(x1EncryptedCoeff3.Scale, newBase: 2));

            /*
             * Since x3Encrypted and x1EncryptedCoeff3 have the same exact scale and use
             * the same encryption parameters, we can multiply them together. We write the
             * result to x3Encrypted, relinearize, and rescale. Note that again the scale
             * is something close to 2^40, but not exactly 2^40 due to yet another scaling
             * by a prime. We are down to the last level in the modulus switching chain.
             */
            Utilities.PrintLine();
            Console.WriteLine("Compute, relinearize, and rescale (PI*x)*x^2.");
            evaluator.MultiplyInplace(x3Encrypted, x1EncryptedCoeff3);
            evaluator.RelinearizeInplace(x3Encrypted, relinKeys);
            Console.WriteLine("    + Scale of PI*x^3 before rescale: {0} bits",
                              Math.Log(x3Encrypted.Scale, newBase: 2));
            evaluator.RescaleToNextInplace(x3Encrypted);
            Console.WriteLine("    + Scale of PI*x^3 after rescale: {0} bits",
                              Math.Log(x3Encrypted.Scale, newBase: 2));

            /*
             * Next we compute the degree one term. All this requires is one MultiplyPlain
             * with plainCoeff1. We overwrite x1Encrypted with the result.
             */
            Utilities.PrintLine();
            Console.WriteLine("Compute and rescale 0.4*x.");
            evaluator.MultiplyPlainInplace(x1Encrypted, plainCoeff1);
            Console.WriteLine("    + Scale of 0.4*x before rescale: {0} bits",
                              Math.Log(x1Encrypted.Scale, newBase: 2));
            evaluator.RescaleToNextInplace(x1Encrypted);
            Console.WriteLine("    + Scale of 0.4*x after rescale: {0} bits",
                              Math.Log(x1Encrypted.Scale, newBase: 2));

            /*
             * Now we would hope to compute the sum of all three terms. However, there is
             * a serious problem: the encryption parameters used by all three terms are
             * different due to modulus switching from rescaling.
             *
             * Encrypted addition and subtraction require that the scales of the inputs are
             * the same, and also that the encryption parameters (ParmsId) match. If there
             * is a mismatch, Evaluator will throw an exception.
             */
            Console.WriteLine();
            Utilities.PrintLine();
            Console.WriteLine("Parameters used by all three terms are different:");
            Console.WriteLine("    + Modulus chain index for x3Encrypted: {0}",
                              context.GetContextData(x3Encrypted.ParmsId).ChainIndex);
            Console.WriteLine("    + Modulus chain index for x1Encrypted: {0}",
                              context.GetContextData(x1Encrypted.ParmsId).ChainIndex);
            Console.WriteLine("    + Modulus chain index for plainCoeff0: {0}",
                              context.GetContextData(plainCoeff0.ParmsId).ChainIndex);
            Console.WriteLine();

            /*
             * Let us carefully consider what the scales are at this point. We denote the
             * primes in coeff_modulus as P_0, P_1, P_2, P_3, in this order. P_3 is used as
             * the special modulus and is not involved in rescalings. After the computations
             * above the scales in ciphertexts are:
             *
             *  - Product x^2 has scale 2^80 and is at level 2;
             *  - Product PI*x has scale 2^80 and is at level 2;
             *  - We rescaled both down to scale 2^80/P2 and level 1;
             *  - Product PI*x^3 has scale (2^80/P_2)^2;
             *  - We rescaled it down to scale (2^80/P_2)^2/P_1 and level 0;
             *  - Product 0.4*x has scale 2^80;
             *  - We rescaled it down to scale 2^80/P_2 and level 1;
             *  - The contant term 1 has scale 2^40 and is at level 2.
             *
             * Although the scales of all three terms are approximately 2^40, their exact
             * values are different, hence they cannot be added together.
             */
            Utilities.PrintLine();
            Console.WriteLine("The exact scales of all three terms are different:");
            Console.WriteLine("    + Exact scale in PI*x^3: {0:0.0000000000}", x3Encrypted.Scale);
            Console.WriteLine("    + Exact scale in  0.4*x: {0:0.0000000000}", x1Encrypted.Scale);
            Console.WriteLine("    + Exact scale in      1: {0:0.0000000000}", plainCoeff0.Scale);
            Console.WriteLine();

            /*
             * There are many ways to fix this problem. Since P_2 and P_1 are really close
             * to 2^40, we can simply "lie" to Microsoft SEAL and set the scales to be the
             * same. For example, changing the scale of PI*x^3 to 2^40 simply means that we
             * scale the value of PI*x^3 by 2^120/(P_2^2*P_1), which is very close to 1.
             * This should not result in any noticeable error.
             *
             * Another option would be to encode 1 with scale 2^80/P_2, do a MultiplyPlain
             * with 0.4*x, and finally rescale. In this case we would need to additionally
             * make sure to encode 1 with appropriate encryption parameters (ParmsId).
             *
             * In this example we will use the first (simplest) approach and simply change
             * the scale of PI*x^3 and 0.4*x to 2^40.
             */
            Utilities.PrintLine();
            Console.WriteLine("Normalize scales to 2^40.");
            x3Encrypted.Scale = Math.Pow(2.0, 40);
            x1Encrypted.Scale = Math.Pow(2.0, 40);

            /*
             * We still have a problem with mismatching encryption parameters. This is easy
             * to fix by using traditional modulus switching (no rescaling). CKKS supports
             * modulus switching just like the BFV scheme, allowing us to switch away parts
             * of the coefficient modulus when it is simply not needed.
             */
            Utilities.PrintLine();
            Console.WriteLine("Normalize encryption parameters to the lowest level.");
            ParmsId lastParmsId = x3Encrypted.ParmsId;

            evaluator.ModSwitchToInplace(x1Encrypted, lastParmsId);
            evaluator.ModSwitchToInplace(plainCoeff0, lastParmsId);

            /*
             * All three ciphertexts are now compatible and can be added.
             */
            Utilities.PrintLine();
            Console.WriteLine("Compute PI*x^3 + 0.4*x + 1.");
            using Ciphertext encryptedResult = new Ciphertext();
            evaluator.Add(x3Encrypted, x1Encrypted, encryptedResult);
            evaluator.AddPlainInplace(encryptedResult, plainCoeff0);

            /*
             * First print the true result.
             */
            using Plaintext plainResult = new Plaintext();
            Utilities.PrintLine();
            Console.WriteLine("Decrypt and decode PI * x ^ 3 + 0.4x + 1.");
            Console.WriteLine("    + Expected result:");
            List <double> trueResult = new List <double>(input.Count);

            foreach (double x in input)
            {
                trueResult.Add((3.14159265 * x * x + 0.4) * x + 1);
            }
            Utilities.PrintVector(trueResult, 3, 7);

            /*
             * We decrypt, decode, and print the result.
             */
            decryptor.Decrypt(encryptedResult, plainResult);
            List <double> result = new List <double>();

            encoder.Decode(plainResult, result);
            Console.WriteLine("    + Computed result ...... Correct.");
            Utilities.PrintVector(result, 3, 7);

            /*
             * While we did not show any computations on complex numbers in these examples,
             * the CKKSEncoder would allow us to have done that just as easily. Additions
             * and multiplications of complex numbers behave just as one would expect.
             */
        }
            public int Predict(double[] features, int power, bool useRelinearizeInplace, bool useReScale, Stopwatch timePredictSum)
            {
                EncryptionParameters parms = new EncryptionParameters(SchemeType.CKKS);

                if (power < 60)
                {
                    ulong polyModulusDegree = 8192;
                    parms.PolyModulusDegree = polyModulusDegree;
                    parms.CoeffModulus      = CoeffModulus.Create(polyModulusDegree, new int[] { 60, 40, 40, 60 });
                }
                else
                {
                    ulong polyModulusDegree = 16384;
                    parms.PolyModulusDegree = polyModulusDegree;
                    parms.CoeffModulus      = CoeffModulus.Create(polyModulusDegree, new int[] { 60, 60, 60, 60, 60, 60 });
                }
                //

                double scale = Math.Pow(2.0, power);

                SEALContext context = new SEALContext(parms);

                Console.WriteLine();

                KeyGenerator keygen    = new KeyGenerator(context);
                PublicKey    publicKey = keygen.PublicKey;
                SecretKey    secretKey = keygen.SecretKey;
                RelinKeys    relinKeys = keygen.RelinKeys();
                Encryptor    encryptor = new Encryptor(context, publicKey);
                Evaluator    evaluator = new Evaluator(context);
                Decryptor    decryptor = new Decryptor(context, secretKey);

                CKKSEncoder encoder = new CKKSEncoder(context);

                ulong slotCount = encoder.SlotCount;

                Console.WriteLine($"Number of slots: {slotCount}");
                timePredictSum.Start();
                var featuresLength = features.Length;

                var plaintexts          = new Plaintext[featuresLength];
                var featuresCiphertexts = new Ciphertext[featuresLength];

                //Encode and encrypt features
                for (int i = 0; i < featuresLength; i++)
                {
                    plaintexts[i] = new Plaintext();

                    encoder.Encode(features[i], scale, plaintexts[i]);

                    SvcUtilities.PrintScale(plaintexts[i], "featurePlaintext" + i);
                    featuresCiphertexts[i] = new Ciphertext();

                    encryptor.Encrypt(plaintexts[i], featuresCiphertexts[i]);
                    SvcUtilities.PrintScale(featuresCiphertexts[i], "featurefEncrypted" + i);
                }

                // Handle SV
                var numOfrows    = _vectors.Length;
                var numOfcolumns = _vectors[0].Length;
                var svPlaintexts = new Plaintext[numOfrows, numOfcolumns];

                //Encode SV
                for (int i = 0; i < numOfrows; i++)
                {
                    for (int j = 0; j < numOfcolumns; j++)
                    {
                        svPlaintexts[i, j] = new Plaintext();
                        encoder.Encode(_vectors[i][j], scale, svPlaintexts[i, j]);
                        SvcUtilities.PrintScale(svPlaintexts[i, j], "supportVectorsPlaintext" + i + j);
                    }
                }
                // Prepare sum of inner product
                var sums = new Ciphertext[numOfcolumns];

                for (int i = 0; i < numOfcolumns; i++)
                {
                    sums[i] = new Ciphertext();
                }

                var kernels      = new Ciphertext[numOfrows];
                var decisionsArr = new Ciphertext[numOfrows];
                var coefArr      = new Plaintext [numOfrows];

                for (int i = 0; i < numOfrows; i++)
                {
                    kernels[i]      = new Ciphertext();
                    decisionsArr[i] = new Ciphertext();
                    coefArr[i]      = new Plaintext();
                }

                // Level 1
                for (int i = 0; i < numOfrows; i++)
                {
                    var ciphertexts = new List <Ciphertext>();

                    //inner product
                    for (int j = 0; j < numOfcolumns; j++)
                    {
                        evaluator.MultiplyPlain(featuresCiphertexts[j], svPlaintexts[i, j], sums[j]);

                        if (useRelinearizeInplace)
                        {
                            evaluator.RelinearizeInplace(sums[j], relinKeys);
                        }

                        if (useReScale)
                        {
                            evaluator.RescaleToNextInplace(sums[j]);
                        }

                        SvcUtilities.PrintScale(sums[j], "tSum" + j);
                    }

                    evaluator.AddMany(sums, kernels[i]);

                    evaluator.NegateInplace(kernels[i]);

                    SvcUtilities.PrintScale(kernels[i], "kernel" + i);

                    SvcUtilities.PrintCyprherText(decryptor, kernels[i], encoder, "kernel" + i);
                }

                // Encode coefficients : ParmsId! , scale!
                double scale2 = Math.Pow(2.0, power);

                if (useReScale)
                {
                    scale2 = kernels[0].Scale;
                }

                for (int i = 0; i < numOfrows; i++)
                {
                    encoder.Encode(_coefficients[0][i], scale2, coefArr[i]);
                    SvcUtilities.PrintScale(coefArr[i], "coefPlainText+i");
                }



                if (useReScale)
                {
                    for (int i = 0; i < numOfrows; i++)
                    {
                        ParmsId lastParmsId = kernels[i].ParmsId;
                        evaluator.ModSwitchToInplace(coefArr[i], lastParmsId);
                    }
                }
                // Level 2
                // Calculate decisionArr
                for (int i = 0; i < numOfrows; i++)
                {
                    evaluator.MultiplyPlain(kernels[i], coefArr[i], decisionsArr[i]);
                    if (useRelinearizeInplace)
                    {
                        evaluator.RelinearizeInplace(decisionsArr[i], relinKeys);
                    }

                    if (useReScale)
                    {
                        evaluator.RescaleToNextInplace(decisionsArr[i]);
                    }
                    SvcUtilities.PrintScale(decisionsArr[i], "decision" + i);
                    SvcUtilities.PrintCyprherText(decryptor, decisionsArr[i], encoder, "decision" + i);
                }



                // Calculate decisionTotal
                Ciphertext decisionTotal = new Ciphertext();

                //=================================================================
                evaluator.AddMany(decisionsArr, decisionTotal);
                //=================================================================

                SvcUtilities.PrintScale(decisionTotal, "decisionTotal");
                SvcUtilities.PrintCyprherText(decryptor, decisionTotal, encoder, "decision total");


                // Encode intercepts : ParmsId! , scale!
                Plaintext interceptsPlainText = new Plaintext();

                double scale3 = Math.Pow(2.0, power * 3);

                if (useReScale)
                {
                    scale3 = decisionTotal.Scale;
                }
                encoder.Encode(_intercepts[0], scale3, interceptsPlainText);
                if (useReScale)
                {
                    ParmsId lastParmsId = decisionTotal.ParmsId;
                    evaluator.ModSwitchToInplace(interceptsPlainText, lastParmsId);
                }

                SvcUtilities.PrintScale(interceptsPlainText, "interceptsPlainText");
                SvcUtilities.PrintScale(decisionTotal, "decisionTotal");


                //// Calculate finalTotal
                Ciphertext finalTotal = new Ciphertext();

                //=================================================================
                evaluator.AddPlainInplace(decisionTotal, interceptsPlainText);
                //=================================================================
                timePredictSum.Stop();
                SvcUtilities.PrintScale(decisionTotal, "decisionTotal");  //Level 3
                List <double> result = SvcUtilities.PrintCyprherText(decryptor, decisionTotal, encoder, "finalTotal");

                using (System.IO.StreamWriter file =
                           new System.IO.StreamWriter(
                               $@"{OutputDir}IrisLinear_IrisSecureSVC_total_{power}_{useRelinearizeInplace}_{useReScale}.txt", !_firstTime)
                       )
                {
                    _firstTime = false;
                    file.WriteLine($"{result[0]}");
                }

                if (result[0] > 0)
                {
                    return(0);
                }

                return(1);
            }
Example #30
0
        //constructor for debugging , because it enables to pass secretkey which will not happen in real life
        // special parameters :
        //  batchsize - number of batches sample in one ciphertext ,if the client batches mulitple  samples in the ciphertet .
        //  featureSize - number of features in sample

        private Svc(double[][] vectors, double[][] coefficients, double[] intercepts, String kernel, double gamma, double coef0, ulong degree, int power, PublicKey publicKey, SecretKey secretKey, RelinKeys relinKeys, GaloisKeys galoisKeys, int batchSize, int featureSize)
        {
            this._vectors      = vectors;
            this._coefficients = coefficients;
            this._intercepts   = intercepts;

            this._kernel = (Kernel)System.Enum.Parse(typeof(Kernel), kernel);
            this._gamma  = gamma;
            this._coef0  = coef0;
            this._degree = degree;
            this._power  = power;
            //Use the ckks SCheme
            EncryptionParameters parms = new EncryptionParameters(SchemeType.CKKS);

            // polyModulusDegree and CoeffModulus used for general SVM algorithm and depends on the polynomial kernel degree
            // ( and the percision constraint ) .
            // My implementation can be used up to dgree = 4 , but it can be easly refactored with some oprimizations  to higher
            // polynomial degree
            ulong polyModulusDegree = 16384;

            if (power >= 20 && power < 40)
            {
                parms.CoeffModulus = CoeffModulus.Create(polyModulusDegree,
                                                         new int[] { 60, 20, 21, 22, 23, 24, 25, 26, 27, 60 });
            }
            else if (power >= 40 && power < 60)
            {
                parms.CoeffModulus = CoeffModulus.Create(polyModulusDegree,
                                                         new int[] { 60, 40, 40, 40, 40, 40, 40, 40, 60 });
            }
            else if (power == 60)
            {
                polyModulusDegree  = 32768;
                parms.CoeffModulus = CoeffModulus.Create(polyModulusDegree,
                                                         new int[] { 60, 60, 60, 60, 60, 60, 60, 60, 60 });
            }
            parms.PolyModulusDegree = polyModulusDegree;
            _context = new SEALContext(parms);



            _publicKey  = publicKey;
            _secretKey  = secretKey;
            _relinKeys  = relinKeys;
            _galoisKeys = galoisKeys;

            _evaluator = new Evaluator(_context);
            if (_secretKey != null)
            {
                _decryptor = new Decryptor(_context, _secretKey);                 //FOR DEBUG ONLY ( not used in real server)
            }
            _encoder = new CKKSEncoder(_context);


            Stopwatch serverInitStopwatch = new Stopwatch();

            serverInitStopwatch.Start();



            _numOfrowsCount    = _vectors.Length;       //Number of Support Vectors
            _numOfcolumnsCount = _vectors[0].Length;    //Number of features in every Support vector
            _scale             = Math.Pow(2.0, _power);


            //	vars for batch rotations
            _svPlaintexts = new Plaintext[_numOfrowsCount];

            //Encode support vectors
            _sums = new Ciphertext[_numOfrowsCount];
            if (UseBatchInnerProduct)
            {
                double[] batchVectors = new double[batchSize * featureSize];

                for (int i = 0; i < _numOfrowsCount; i++)
                {
                    for (int k = 0; k < batchSize * featureSize; k++)
                    {
                        var index0 = k % featureSize;

                        batchVectors[k] = index0 < _numOfcolumnsCount ? _vectors[i][index0] : 0;
                    }
                    _svPlaintexts[i] = new Plaintext();
                    _encoder.Encode(batchVectors, _scale, _svPlaintexts[i]);
                    SVCUtilities.SvcUtilities.PrintScale(_svPlaintexts[i], "batch supportVectorsPlaintext" + i);
                    _sums[i] = new Ciphertext();
                }
            }
            else
            {
                /////////////////////////////////////////////////////////////////////////
                //
                //   vars for simple inner product
                //
                // Handle SV

                _svPlaintextsArr = new Plaintext[_numOfrowsCount, _numOfcolumnsCount];

                //Encode SV
                for (int i = 0; i < _numOfrowsCount; i++)
                {
                    for (int j = 0; j < _numOfcolumnsCount; j++)
                    {
                        _svPlaintextsArr[i, j] = new Plaintext();

                        _encoder.Encode(_vectors[i][j] != 0 ? _vectors[i][j] : Zero, _scale, _svPlaintextsArr[i, j]);
                        SvcUtilities.PrintScale(_svPlaintextsArr[i, j], $"supportVectorsPlaintext[{i}][{j}]");
                    }
                }

                // Prepare sum of inner product
                _innerProdSums = new Ciphertext[_numOfcolumnsCount];
                for (int i = 0; i < _numOfcolumnsCount; i++)
                {
                    _innerProdSums[i] = new Ciphertext();
                }
                //////////////////////////////////////////////////////////////
            }

            // Allocate memory for svm secure calculation
            _kernels      = new Ciphertext[_numOfrowsCount];
            _decisionsArr = new Ciphertext[_numOfrowsCount];
            _coefArr      = new Plaintext[_numOfrowsCount];

            for (int i = 0; i < _numOfrowsCount; i++)
            {
                _kernels[i]      = new Ciphertext();
                _decisionsArr[i] = new Ciphertext();
                _coefArr[i]      = new Plaintext();
            }
            _gamaPlaintext = new Plaintext();
            _encoder.Encode(_gamma != 0 ? _gamma : Zero, _scale, _gamaPlaintext);


            serverInitStopwatch.Stop();
            Console.WriteLine($"server Init elapsed {serverInitStopwatch.ElapsedMilliseconds} ms");
        }