コード例 #1
0
        public void CreateRelinKeysTest()
        {
            RelinKeys keys = new RelinKeys();

            Assert.IsNotNull(keys);
            Assert.AreEqual(0ul, keys.Size);
        }
コード例 #2
0
ファイル: RelinKeysTests.cs プロジェクト: jzehr/old-seal
        public void GetKeyTest()
        {
            SEALContext  context   = GlobalContext.Context;
            KeyGenerator keygen    = new KeyGenerator(context);
            RelinKeys    relinKeys = keygen.RelinKeys(decompositionBitCount: 60, count: 3);

            Assert.IsFalse(relinKeys.HasKey(0));
            Assert.IsFalse(relinKeys.HasKey(1));
            Assert.IsTrue(relinKeys.HasKey(2));
            Assert.IsTrue(relinKeys.HasKey(3));
            Assert.IsTrue(relinKeys.HasKey(4));
            Assert.IsFalse(relinKeys.HasKey(5));

            Assert.ThrowsException <ArgumentOutOfRangeException>(() => relinKeys.Key(1));

            List <Ciphertext> key1 = new List <Ciphertext>(relinKeys.Key(2));

            Assert.AreEqual(2, key1.Count);
            Assert.AreEqual(2ul, key1[0].CoeffModCount);
            Assert.AreEqual(2ul, key1[1].CoeffModCount);

            List <Ciphertext> key2 = new List <Ciphertext>(relinKeys.Key(3));

            Assert.AreEqual(2, key2.Count);
            Assert.AreEqual(2ul, key2[0].CoeffModCount);
            Assert.AreEqual(2ul, key2[1].CoeffModCount);

            List <Ciphertext> key3 = new List <Ciphertext>(relinKeys.Key(4));

            Assert.AreEqual(2, key3.Count);
            Assert.AreEqual(2ul, key3[0].CoeffModCount);
            Assert.AreEqual(2ul, key3[1].CoeffModCount);
        }
コード例 #3
0
        /// <summary>
        /// Constructor for MainWindow
        /// </summary>
        public MainWindow()
        {
            // Initialize in background thread
            Task.Run(() =>
            {
                KeyGenerator keygen = new KeyGenerator(GlobalProperties.Context);

                encryptor_ = new Encryptor(GlobalProperties.Context, keygen.PublicKey);
                decryptor_ = new Decryptor(GlobalProperties.Context, keygen.SecretKey);
                encoder_   = new BatchEncoder(GlobalProperties.Context);

                rlk_ = keygen.RelinKeys(decompositionBitCount: GlobalProperties.RelinKeysDBC);

                List <int> rotCounts = new List <int>();
                for (int i = (int)encoder_.SlotCount / GlobalProperties.MatrixSizeMax; i < (int)encoder_.SlotCount / 2; i *= 2)
                {
                    rotCounts.Add(i);
                }
                rotCounts.Add(0);
                galk_ = keygen.GaloisKeys(decompositionBitCount: GlobalProperties.GaloisKeysDBC, steps: rotCounts);

                // Choose the Session ID
                RandomizeSID();
            });

            InitializeComponent();
        }
コード例 #4
0
ファイル: RelinKeysTests.cs プロジェクト: jzehr/old-seal
        public void SaveLoadTest()
        {
            SEALContext  context = GlobalContext.Context;
            KeyGenerator keygen  = new KeyGenerator(context);

            RelinKeys keys = keygen.RelinKeys(decompositionBitCount: 30, count: 2);

            Assert.IsNotNull(keys);
            Assert.AreEqual(30, keys.DecompositionBitCount);
            Assert.AreEqual(2ul, keys.Size);

            RelinKeys        other  = new RelinKeys();
            MemoryPoolHandle handle = other.Pool;

            Assert.AreEqual(0, other.DecompositionBitCount);
            Assert.AreEqual(0ul, other.Size);
            ulong alloced = handle.AllocByteCount;

            using (MemoryStream ms = new MemoryStream())
            {
                keys.Save(ms);

                ms.Seek(offset: 0, loc: SeekOrigin.Begin);

                other.Load(context, ms);
            }

            Assert.AreEqual(30, other.DecompositionBitCount);
            Assert.AreEqual(2ul, other.Size);
            Assert.IsTrue(other.IsMetadataValidFor(context));
            Assert.IsTrue(handle.AllocByteCount > 0ul);

            List <IEnumerable <Ciphertext> > keysData  = new List <IEnumerable <Ciphertext> >(keys.Data);
            List <IEnumerable <Ciphertext> > otherData = new List <IEnumerable <Ciphertext> >(other.Data);

            Assert.AreEqual(keysData.Count, otherData.Count);
            for (int i = 0; i < keysData.Count; i++)
            {
                List <Ciphertext> keysCiphers  = new List <Ciphertext>(keysData[i]);
                List <Ciphertext> otherCiphers = new List <Ciphertext>(otherData[i]);

                Assert.AreEqual(keysCiphers.Count, otherCiphers.Count);

                for (int j = 0; j < keysCiphers.Count; j++)
                {
                    Ciphertext keysCipher  = keysCiphers[j];
                    Ciphertext otherCipher = otherCiphers[j];

                    Assert.AreEqual(keysCipher.Size, otherCipher.Size);
                    Assert.AreEqual(keysCipher.PolyModulusDegree, otherCipher.PolyModulusDegree);
                    Assert.AreEqual(keysCipher.CoeffModCount, otherCipher.CoeffModCount);

                    ulong coeffCount = keysCipher.Size * keysCipher.PolyModulusDegree * keysCipher.CoeffModCount;
                    for (ulong k = 0; k < coeffCount; k++)
                    {
                        Assert.AreEqual(keysCipher[k], otherCipher[k]);
                    }
                }
            }
        }
コード例 #5
0
ファイル: RelinKeysTests.cs プロジェクト: jzehr/old-seal
        public void CreateRelinKeysTest()
        {
            RelinKeys keys = new RelinKeys();

            Assert.IsNotNull(keys);
            Assert.AreEqual(0ul, keys.Size);
            Assert.AreEqual(0, keys.DecompositionBitCount);
        }
コード例 #6
0
 public SecureComputationController(RelinKeys Keys)
 {
     hydrationComputation = new HydrationComputation();
     sleepComputation     = new SleepComputation();
     bmiComputation       = new BMIComputation(Keys);
     salaryComputation    = new SalaryComputation();
     breaksComputation    = new BreaksComputation(Keys);
 }
コード例 #7
0
ファイル: RelinKeysTests.cs プロジェクト: philippejohns/SEAL
        public void SeededKeyTest()
        {
            EncryptionParameters parms = new EncryptionParameters(SchemeType.BFV)
            {
                PolyModulusDegree = 128,
                PlainModulus      = new Modulus(1 << 6),
                CoeffModulus      = CoeffModulus.Create(128, new int[] { 40, 40, 40 })
            };
            SEALContext context = new SEALContext(parms,
                                                  expandModChain: false,
                                                  secLevel: SecLevelType.None);
            KeyGenerator keygen = new KeyGenerator(context);

            RelinKeys relinKeys = new RelinKeys();

            using (MemoryStream stream = new MemoryStream())
            {
                keygen.CreateRelinKeys().Save(stream);
                stream.Seek(0, SeekOrigin.Begin);
                relinKeys.Load(context, stream);
            }

            keygen.CreatePublicKey(out PublicKey publicKey);
            Encryptor encryptor = new Encryptor(context, publicKey);
            Decryptor decryptor = new Decryptor(context, keygen.SecretKey);
            Evaluator evaluator = new Evaluator(context);

            Ciphertext encrypted1 = new Ciphertext(context);
            Ciphertext encrypted2 = new Ciphertext(context);
            Plaintext  plain1     = new Plaintext();
            Plaintext  plain2     = new Plaintext();

            plain1.Set(0);
            encryptor.Encrypt(plain1, encrypted1);
            evaluator.SquareInplace(encrypted1);
            evaluator.RelinearizeInplace(encrypted1, relinKeys);
            decryptor.Decrypt(encrypted1, plain2);

            Assert.AreEqual(1ul, plain2.CoeffCount);
            Assert.AreEqual(0ul, plain2[0]);

            plain1.Set("1x^10 + 2");
            encryptor.Encrypt(plain1, encrypted1);
            evaluator.SquareInplace(encrypted1);
            evaluator.RelinearizeInplace(encrypted1, relinKeys);
            evaluator.SquareInplace(encrypted1);
            evaluator.Relinearize(encrypted1, relinKeys, encrypted2);
            decryptor.Decrypt(encrypted2, plain2);

            // {1x^40 + 8x^30 + 18x^20 + 20x^10 + 10}
            Assert.AreEqual(41ul, plain2.CoeffCount);
            Assert.AreEqual(16ul, plain2[0]);
            Assert.AreEqual(32ul, plain2[10]);
            Assert.AreEqual(24ul, plain2[20]);
            Assert.AreEqual(8ul, plain2[30]);
            Assert.AreEqual(1ul, plain2[40]);
        }
コード例 #8
0
ファイル: Utilities.cs プロジェクト: vdedyukhin/SEAL-Demo
 /// <summary>
 /// Convert a RelinKeys object to a Base64 string
 /// </summary>
 /// <param name="rlk">RelinKeys to convert</param>
 /// <returns>Base64 string representing the RelinKeys</returns>
 public static string RelinKeysToBase64(RelinKeys rlk)
 {
     using (MemoryStream ms = new MemoryStream())
     {
         rlk.Save(ms);
         byte[] bytes = ms.ToArray();
         return(Convert.ToBase64String(bytes));
     }
 }
コード例 #9
0
        public static async Task <IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
            ILogger log)
        {
            log.LogInformation("Processing request: PublicKeysUpload");

            string  requestBody = await new StreamReader(req.Body).ReadToEndAsync();
            dynamic data        = JsonConvert.DeserializeObject(requestBody);
            string  sid         = data?.sid;
            string  keyType     = data?.type;

            if (sid == null || sid.Equals(string.Empty))
            {
                return(new BadRequestObjectResult("sid not present in request"));
            }

            if (keyType?.Equals("GaloisKeys") == true)
            {
                if (GlobalProperties.GaloisKeys.ContainsKey(sid))
                {
                    return(new BadRequestObjectResult($"{keyType} for given sid already present"));
                }

                string keystr = data?.key;
                if (keystr == null)
                {
                    return(new BadRequestObjectResult($"{keyType} not present in request"));
                }

                GaloisKeys galk = Utilities.Base64ToGaloisKeys(keystr, GlobalProperties.Context);
                GlobalProperties.GaloisKeys.Add(sid, galk);
            }
            else if (keyType?.Equals("RelinKeys") == true)
            {
                if (GlobalProperties.RelinKeys.ContainsKey(sid))
                {
                    return(new BadRequestObjectResult($"{keyType} for given sid already present"));
                }

                string keystr = data?.key;
                if (keystr == null)
                {
                    return(new BadRequestObjectResult($"{keyType} not present in request"));
                }

                RelinKeys rlk = Utilities.Base64ToRelinKeys(keystr, GlobalProperties.Context);
                GlobalProperties.RelinKeys.Add(sid, rlk);
            }
            else
            {
                return(new BadRequestObjectResult("Bad key type"));
            }

            return(new OkResult());
        }
コード例 #10
0
ファイル: RelinKeysTests.cs プロジェクト: philippejohns/SEAL
        public void SaveLoadTest()
        {
            SEALContext  context = GlobalContext.BFVContext;
            KeyGenerator keygen  = new KeyGenerator(context);

            keygen.CreateRelinKeys(out RelinKeys keys);

            Assert.IsNotNull(keys);
            Assert.AreEqual(1ul, keys.Size);

            RelinKeys        other  = new RelinKeys();
            MemoryPoolHandle handle = other.Pool;

            Assert.AreEqual(0ul, other.Size);
            ulong alloced = handle.AllocByteCount;

            using (MemoryStream ms = new MemoryStream())
            {
                keys.Save(ms);
                ms.Seek(offset: 0, loc: SeekOrigin.Begin);
                other.Load(context, ms);
            }

            Assert.AreEqual(1ul, other.Size);
            Assert.IsTrue(ValCheck.IsValidFor(other, context));
            Assert.IsTrue(handle.AllocByteCount > 0ul);

            List <IEnumerable <PublicKey> > keysData  = new List <IEnumerable <PublicKey> >(keys.Data);
            List <IEnumerable <PublicKey> > otherData = new List <IEnumerable <PublicKey> >(other.Data);

            Assert.AreEqual(keysData.Count, otherData.Count);
            for (int i = 0; i < keysData.Count; i++)
            {
                List <PublicKey> keysCiphers  = new List <PublicKey>(keysData[i]);
                List <PublicKey> otherCiphers = new List <PublicKey>(otherData[i]);

                Assert.AreEqual(keysCiphers.Count, otherCiphers.Count);

                for (int j = 0; j < keysCiphers.Count; j++)
                {
                    PublicKey keysCipher  = keysCiphers[j];
                    PublicKey otherCipher = otherCiphers[j];

                    Assert.AreEqual(keysCipher.Data.Size, otherCipher.Data.Size);
                    Assert.AreEqual(keysCipher.Data.PolyModulusDegree, otherCipher.Data.PolyModulusDegree);
                    Assert.AreEqual(keysCipher.Data.CoeffModulusSize, otherCipher.Data.CoeffModulusSize);

                    ulong coeffCount = keysCipher.Data.Size * keysCipher.Data.PolyModulusDegree * keysCipher.Data.CoeffModulusSize;
                    for (ulong k = 0; k < coeffCount; k++)
                    {
                        Assert.AreEqual(keysCipher.Data[k], otherCipher.Data[k]);
                    }
                }
            }
        }
コード例 #11
0
ファイル: Utilities.cs プロジェクト: voidp34r/SEAL-Demo
        /// <summary>
        /// Convert a Base64 string to a RelinKeys object
        /// </summary>
        /// <param name="b64">Base 64 string</param>
        /// <param name="context">SEALContext to verify resulting RelinKeys is valid for the SEALContext</param>
        /// <returns>Decoded RelinKeys</returns>
        public static RelinKeys Base64ToRelinKeys(string b64, SEALContext context)
        {
            RelinKeys result = new RelinKeys();

            byte[] bytes = Convert.FromBase64String(b64);
            using (MemoryStream ms = new MemoryStream(bytes))
            {
                result.Load(context, ms);
            }

            return(result);
        }
コード例 #12
0
 public BreaksComputation(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);
     SetConstants();
     keys = Keys;
 }
コード例 #13
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);
			}
コード例 #14
0
        public void GetKeyTest()
        {
            SEALContext  context   = GlobalContext.BFVContext;
            KeyGenerator keygen    = new KeyGenerator(context);
            RelinKeys    relinKeys = keygen.RelinKeys();

            Assert.IsTrue(relinKeys.HasKey(2));
            Assert.IsFalse(relinKeys.HasKey(3));

            Assert.ThrowsException <ArgumentException>(() => relinKeys.Key(0));
            Assert.ThrowsException <ArgumentException>(() => relinKeys.Key(1));

            List <PublicKey> key1 = new List <PublicKey>(relinKeys.Key(2));

            Assert.AreEqual(4, key1.Count);
            Assert.AreEqual(5ul, key1[0].Data.CoeffModCount);
        }
コード例 #15
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();
 }
コード例 #16
0
ファイル: RelinKeysTests.cs プロジェクト: eshnil2000/bootcamp
        public void ExceptionsTest()
        {
            RelinKeys   keys    = new RelinKeys();
            SEALContext context = GlobalContext.BFVContext;

            Utilities.AssertThrows <ArgumentNullException>(() => keys = new RelinKeys(null));
            Utilities.AssertThrows <ArgumentNullException>(() => keys.Set(null));

            Utilities.AssertThrows <ArgumentNullException>(() => ValCheck.IsValidFor(keys, null));

            Utilities.AssertThrows <ArgumentNullException>(() => keys.Save(null));

            Utilities.AssertThrows <ArgumentNullException>(() => keys.Load(context, null));
            Utilities.AssertThrows <ArgumentNullException>(() => keys.Load(null, new MemoryStream()));
            Utilities.AssertThrows <EndOfStreamException>(() => keys.Load(context, new MemoryStream()));
            Utilities.AssertThrows <ArgumentNullException>(() => keys.UnsafeLoad(null, new MemoryStream()));
            Utilities.AssertThrows <ArgumentNullException>(() => keys.UnsafeLoad(context, null));
        }
コード例 #17
0
        public void CreateNonEmptyRelinKeysTest()
        {
            {
                SEALContext  context = GlobalContext.BFVContext;
                KeyGenerator keygen  = new KeyGenerator(context);

                keygen.CreateRelinKeys(out RelinKeys keys);

                Assert.IsNotNull(keys);
                Assert.AreEqual(1ul, keys.Size);

                RelinKeys copy = new RelinKeys(keys);

                Assert.IsNotNull(copy);
                Assert.AreEqual(1ul, copy.Size);

                RelinKeys copy2 = new RelinKeys();

                copy2.Set(keys);
                Assert.IsNotNull(copy2);
                Assert.AreEqual(1ul, copy2.Size);
            }
            {
                SEALContext  context = GlobalContext.BGVContext;
                KeyGenerator keygen  = new KeyGenerator(context);

                keygen.CreateRelinKeys(out RelinKeys keys);

                Assert.IsNotNull(keys);
                Assert.AreEqual(1ul, keys.Size);

                RelinKeys copy = new RelinKeys(keys);

                Assert.IsNotNull(copy);
                Assert.AreEqual(1ul, copy.Size);

                RelinKeys copy2 = new RelinKeys();

                copy2.Set(keys);
                Assert.IsNotNull(copy2);
                Assert.AreEqual(1ul, copy2.Size);
            }
        }
コード例 #18
0
ファイル: RelinKeysTests.cs プロジェクト: jzehr/old-seal
        public void ExceptionsTest()
        {
            RelinKeys   keys    = new RelinKeys();
            SEALContext context = GlobalContext.Context;

            Assert.ThrowsException <ArgumentNullException>(() => keys = new RelinKeys(null));

            Assert.ThrowsException <ArgumentNullException>(() => keys.Set(null));

            Assert.ThrowsException <ArgumentNullException>(() => keys.IsValidFor(null));
            Assert.ThrowsException <ArgumentNullException>(() => keys.IsMetadataValidFor(null));

            Assert.ThrowsException <ArgumentNullException>(() => keys.Save(null));

            Assert.ThrowsException <ArgumentNullException>(() => keys.Load(context, null));
            Assert.ThrowsException <ArgumentNullException>(() => keys.Load(null, new MemoryStream()));
            Assert.ThrowsException <ArgumentException>(() => keys.Load(context, new MemoryStream()));
            Assert.ThrowsException <ArgumentNullException>(() => keys.UnsafeLoad(null));
        }
コード例 #19
0
ファイル: RelinKeysTests.cs プロジェクト: jzehr/old-seal
        public void CreateNonEmptyRelinKeysTest()
        {
            SEALContext  context = GlobalContext.Context;
            KeyGenerator keygen  = new KeyGenerator(context);

            RelinKeys keys = keygen.RelinKeys(decompositionBitCount: 30);

            Assert.IsNotNull(keys);
            Assert.AreEqual(30, keys.DecompositionBitCount);
            Assert.AreEqual(1ul, keys.Size);

            RelinKeys copy = new RelinKeys(keys);

            Assert.IsNotNull(copy);
            Assert.AreEqual(30, copy.DecompositionBitCount);
            Assert.AreEqual(1ul, copy.Size);

            RelinKeys copy2 = new RelinKeys();

            copy2.Set(keys);
            Assert.IsNotNull(copy2);
            Assert.AreEqual(30, copy2.DecompositionBitCount);
            Assert.AreEqual(1ul, copy2.Size);
        }
コード例 #20
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");
        }
コード例 #21
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.
             */
            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.
             */
            SEALContext context = new SEALContext(parms);

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

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

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

            /*
             * To create CKKS plaintexts we need a special encoder: there is no other way
             * to create them. The IntegerEncoder and 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.
             */
            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.
             */
            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.
             */
            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'.
             */
        }
コード例 #22
0
        private static void ExampleBatchEncoder()
        {
            Utilities.PrintExampleBanner("Example: Encoders / Batch Encoder");

            /*
             * [BatchEncoder] (For BFV scheme only)
             *
             * Let N denote the PolyModulusDegree and T denote the PlainModulus. Batching
             * allows the BFV plaintext polynomials to be viewed as 2-by-(N/2) matrices, with
             * each element an integer modulo T. In the matrix view, encrypted operations act
             * element-wise on encrypted matrices, allowing the user to obtain speeds-ups of
             * several orders of magnitude in fully vectorizable computations. Thus, in all
             * but the simplest computations, batching should be the preferred method to use
             * with BFV, and when used properly will result in implementations outperforming
             * anything done with the IntegerEncoder.
             */
            EncryptionParameters parms = new EncryptionParameters(SchemeType.BFV);
            ulong polyModulusDegree    = 8192;

            parms.PolyModulusDegree = polyModulusDegree;
            parms.CoeffModulus      = CoeffModulus.BFVDefault(polyModulusDegree);

            /*
             * To enable batching, we need to set the plain_modulus to be a prime number
             * congruent to 1 modulo 2*PolyModulusDegree. Microsoft SEAL provides a helper
             * method for finding such a prime. In this example we create a 20-bit prime
             * that supports batching.
             */
            parms.PlainModulus = PlainModulus.Batching(polyModulusDegree, 20);

            SEALContext context = new SEALContext(parms);

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

            /*
             * We can verify that batching is indeed enabled by looking at the encryption
             * parameter qualifiers created by SEALContext.
             */
            var qualifiers = context.FirstContextData.Qualifiers;

            Console.WriteLine($"Batching enabled: {qualifiers.UsingBatching}");

            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);

            /*
             * Batching is done through an instance of the BatchEncoder class.
             */
            BatchEncoder batchEncoder = new BatchEncoder(context);

            /*
             * The total number of batching `slots' equals the PolyModulusDegree, N, and
             * these slots are organized into 2-by-(N/2) matrices that can be encrypted and
             * computed on. Each slot contains an integer modulo PlainModulus.
             */
            ulong slotCount = batchEncoder.SlotCount;
            ulong rowSize   = slotCount / 2;

            Console.WriteLine($"Plaintext matrix row size: {rowSize}");

            /*
             * The matrix plaintext is simply given to BatchEncoder as a flattened vector
             * of numbers. The first `rowSize' many numbers form the first row, and the
             * rest form the second row. Here we create the following matrix:
             *
             *  [ 0,  1,  2,  3,  0,  0, ...,  0 ]
             *  [ 4,  5,  6,  7,  0,  0, ...,  0 ]
             */
            ulong[] podMatrix = new ulong[slotCount];
            podMatrix[0]           = 0;
            podMatrix[1]           = 1;
            podMatrix[2]           = 2;
            podMatrix[3]           = 3;
            podMatrix[rowSize]     = 4;
            podMatrix[rowSize + 1] = 5;
            podMatrix[rowSize + 2] = 6;
            podMatrix[rowSize + 3] = 7;

            Console.WriteLine("Input plaintext matrix:");
            Utilities.PrintMatrix(podMatrix, (int)rowSize);

            /*
             * First we use BatchEncoder to encode the matrix into a plaintext polynomial.
             */
            Plaintext plainMatrix = new Plaintext();

            Utilities.PrintLine();
            Console.WriteLine("Encode plaintext matrix:");
            batchEncoder.Encode(podMatrix, plainMatrix);

            /*
             * We can instantly decode to verify correctness of the encoding. Note that no
             * encryption or decryption has yet taken place.
             */
            List <ulong> podResult = new List <ulong>();

            Console.WriteLine("    + Decode plaintext matrix ...... Correct.");
            batchEncoder.Decode(plainMatrix, podResult);
            Utilities.PrintMatrix(podResult, (int)rowSize);

            /*
             * Next we encrypt the encoded plaintext.
             */
            Ciphertext encryptedMatrix = new Ciphertext();

            Utilities.PrintLine();
            Console.WriteLine("Encrypt plainMatrix to encryptedMatrix.");
            encryptor.Encrypt(plainMatrix, encryptedMatrix);
            Console.WriteLine("    + Noise budget in encryptedMatrix: {0} bits",
                              decryptor.InvariantNoiseBudget(encryptedMatrix));

            /*
             * Operating on the ciphertext results in homomorphic operations being performed
             * simultaneously in all 8192 slots (matrix elements). To illustrate this, we
             * form another plaintext matrix
             *
             *  [ 1,  2,  1,  2,  1,  2, ..., 2 ]
             *  [ 1,  2,  1,  2,  1,  2, ..., 2 ]
             *
             * and encode it into a plaintext.
             */
            ulong[] podMatrix2 = new ulong[slotCount];
            for (ulong i = 0; i < slotCount; i++)
            {
                podMatrix2[i] = (i % 2) + 1;
            }
            Plaintext plainMatrix2 = new Plaintext();

            batchEncoder.Encode(podMatrix2, plainMatrix2);
            Console.WriteLine();
            Console.WriteLine("Second input plaintext matrix:");
            Utilities.PrintMatrix(podMatrix2, (int)rowSize);

            /*
             * We now add the second (plaintext) matrix to the encrypted matrix, and square
             * the sum.
             */
            Utilities.PrintLine();
            Console.WriteLine("Sum, square, and relinearize.");
            evaluator.AddPlainInplace(encryptedMatrix, plainMatrix2);
            evaluator.SquareInplace(encryptedMatrix);
            evaluator.RelinearizeInplace(encryptedMatrix, relinKeys);

            /*
             * How much noise budget do we have left?
             */
            Console.WriteLine("    + Noise budget in result: {0} bits",
                              decryptor.InvariantNoiseBudget(encryptedMatrix));

            /*
             * We decrypt and decompose the plaintext to recover the result as a matrix.
             */
            Plaintext plainResult = new Plaintext();

            Utilities.PrintLine();
            Console.WriteLine("Decrypt and decode result.");
            decryptor.Decrypt(encryptedMatrix, plainResult);
            batchEncoder.Decode(plainResult, podResult);
            Console.WriteLine("    + Result plaintext matrix ...... Correct.");
            Utilities.PrintMatrix(podResult, (int)rowSize);

            /*
             * Batching allows us to efficiently use the full plaintext polynomial when the
             * desired encrypted computation is highly parallelizable. However, it has not
             * solved the other problem mentioned in the beginning of this file: each slot
             * holds only an integer modulo plain_modulus, and unless plain_modulus is very
             * large, we can quickly encounter data type overflow and get unexpected results
             * when integer computations are desired. Note that overflow cannot be detected
             * in encrypted form. The CKKS scheme (and the CKKSEncoder) addresses the data
             * type overflow issue, but at the cost of yielding only approximate results.
             */
        }
コード例 #23
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();
        }
コード例 #24
0
        private static void BFVPerformanceTest(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;
            using Modulus plainModulus       = parms.PlainModulus;
            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 BatchEncoder batchEncoder = new BatchEncoder(context);

            /*
             * These will hold the total times used by each operation.
             */
            Stopwatch timeBatchSum             = new Stopwatch();
            Stopwatch timeUnbatchSum           = 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 timeRotateRowsOneStepSum = new Stopwatch();
            Stopwatch timeRotateRowsRandomSum  = new Stopwatch();
            Stopwatch timeRotateColumnsSum     = new Stopwatch();
            Stopwatch timeSerializeSum         = new Stopwatch();
            Stopwatch timeSerializeZLIBSum     = new Stopwatch();
            Stopwatch timeSerializeZSTDSum     = new Stopwatch();

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

            /*
             * Populate a vector of values to batch.
             */
            ulong slotCount = batchEncoder.SlotCount;

            ulong[] podValues = new ulong[slotCount];
            Random  rnd       = new Random();

            for (ulong i = 0; i < batchEncoder.SlotCount; i++)
            {
                podValues[i] = plainModulus.Reduce((ulong)rnd.Next());
            }

            Console.Write("Running tests ");
            for (int i = 0; i < count; i++)
            {
                /*
                 * [Batching]
                 * There is nothing unusual here. We batch our random plaintext matrix
                 * into the polynomial. Note how the plaintext we create is of the exactly
                 * right size so unnecessary reallocations are avoided.
                 */
                using Plaintext plain = new Plaintext(parms.PolyModulusDegree, 0);
                timeBatchSum.Start();
                batchEncoder.Encode(podValues, plain);
                timeBatchSum.Stop();

                /*
                 * [Unbatching]
                 * We unbatch what we just batched.
                 */
                List <ulong> podList = new List <ulong>((int)slotCount);
                timeUnbatchSum.Start();
                batchEncoder.Decode(plain, podList);
                timeUnbatchSum.Stop();
                if (!podList.SequenceEqual(podValues))
                {
                    throw new InvalidOperationException("Batch/unbatch failed. Something is wrong.");
                }

                /*
                 * [Encryption]
                 * We make sure our ciphertext is already allocated and large enough
                 * to hold the encryption with these encryption parameters. We encrypt
                 * our random batched matrix here.
                 */
                using Ciphertext encrypted = new Ciphertext(context);
                timeEncryptSum.Start();
                encryptor.Encrypt(plain, encrypted);
                timeEncryptSum.Stop();

                /*
                 * [Decryption]
                 * We decrypt what we just encrypted.
                 */
                using Plaintext plain2 = new Plaintext(polyModulusDegree, 0);
                timeDecryptSum.Start();
                decryptor.Decrypt(encrypted, plain2);
                timeDecryptSum.Stop();
                if (!plain2.Equals(plain))
                {
                    throw new InvalidOperationException("Encrypt/decrypt failed. Something is wrong.");
                }

                /*
                 * [Add]
                 * We create two ciphertexts and perform a few additions with them.
                 */
                using Plaintext plain1 = new Plaintext(parms.PolyModulusDegree, 0);
                for (ulong j = 0; j < batchEncoder.SlotCount; j++)
                {
                    podValues[j] = j;
                }
                batchEncoder.Encode(podValues, plain1);
                for (ulong j = 0; j < batchEncoder.SlotCount; j++)
                {
                    podValues[j] = j + 1;
                }
                batchEncoder.Encode(podValues, plain2);
                using Ciphertext encrypted1 = new Ciphertext(context);
                encryptor.Encrypt(plain1, encrypted1);
                using Ciphertext encrypted2 = new Ciphertext(context);
                encryptor.Encrypt(plain2, encrypted2);

                timeAddSum.Start();
                evaluator.AddInplace(encrypted1, encrypted1);
                evaluator.AddInplace(encrypted2, encrypted2);
                evaluator.AddInplace(encrypted1, encrypted2);
                timeAddSum.Stop();

                /*
                 * [Multiply]
                 * We multiply two ciphertexts. Since the size of the result will be 3,
                 * and will overwrite the first argument, we reserve first enough memory
                 * to avoid reallocating during multiplication.
                 */
                encrypted1.Reserve(3);
                timeMultiplySum.Start();
                evaluator.MultiplyInplace(encrypted1, encrypted2);
                timeMultiplySum.Stop();

                /*
                 * [Multiply Plain]
                 * We multiply a ciphertext with a random plaintext. Recall that
                 * MultiplyPlain does not change the size of the ciphertext so we use
                 * encrypted2 here.
                 */
                timeMultiplyPlainSum.Start();
                evaluator.MultiplyPlainInplace(encrypted2, plain);
                timeMultiplyPlainSum.Stop();

                /*
                 * [Square]
                 * We continue to use encrypted2. Now we square it; this should be
                 * faster than generic homomorphic multiplication.
                 */
                timeSquareSum.Start();
                evaluator.SquareInplace(encrypted2);
                timeSquareSum.Stop();

                if (context.UsingKeyswitching)
                {
                    /*
                     * [Relinearize]
                     * Time to get back to encrypted1. We now relinearize it back
                     * to size 2. Since the allocation is currently big enough to
                     * contain a ciphertext of size 3, no costly reallocations are
                     * needed in the process.
                     */
                    timeRelinearizeSum.Start();
                    evaluator.RelinearizeInplace(encrypted1, relinKeys);
                    timeRelinearizeSum.Stop();

                    /*
                     * [Rotate Rows One Step]
                     * We rotate matrix rows by one step left and measure the time.
                     */
                    timeRotateRowsOneStepSum.Start();
                    evaluator.RotateRowsInplace(encrypted, 1, galKeys);
                    evaluator.RotateRowsInplace(encrypted, -1, galKeys);
                    timeRotateRowsOneStepSum.Stop();

                    /*
                     * [Rotate Rows Random]
                     * We rotate matrix rows by a random number of steps. This is much more
                     * expensive than rotating by just one step.
                     */
                    int rowSize = (int)batchEncoder.SlotCount / 2;
                    // rowSize is always a power of 2.
                    int randomRotation = rnd.Next() & (rowSize - 1);
                    timeRotateRowsRandomSum.Start();
                    evaluator.RotateRowsInplace(encrypted, randomRotation, galKeys);
                    timeRotateRowsRandomSum.Stop();

                    /*
                     * [Rotate Columns]
                     * Nothing surprising here.
                     */
                    timeRotateColumnsSum.Start();
                    evaluator.RotateColumnsInplace(encrypted, galKeys);
                    timeRotateColumnsSum.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 avgBatch             = (int)(timeBatchSum.Elapsed.TotalMilliseconds * 1000 / count);
            int avgUnbatch           = (int)(timeUnbatchSum.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 avgRotateRowsOneStep = (int)(timeRotateRowsOneStepSum.Elapsed.TotalMilliseconds * 1000 / (2 * count));
            int avgRotateRowsRandom  = (int)(timeRotateRowsRandomSum.Elapsed.TotalMilliseconds * 1000 / count);
            int avgRotateColumns     = (int)(timeRotateColumnsSum.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 batch: {avgBatch} microseconds");
            Console.WriteLine($"Average unbatch: {avgUnbatch} 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 rotate rows one step: {avgRotateRowsOneStep} microseconds");
                Console.WriteLine($"Average rotate rows random: {avgRotateRowsRandom} microseconds");
                Console.WriteLine($"Average rotate columns: {avgRotateColumns} 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();
        }
コード例 #25
0
        private static void ExampleLevels()
        {
            Utilities.PrintExampleBanner("Example: Levels");

            /*
             * In this examples we describe the concept of `levels' in BFV and CKKS and the
             * related objects that represent them in Microsoft SEAL.
             *
             * In Microsoft SEAL a set of encryption parameters (excluding the random number
             * generator) is identified uniquely by a SHA-3 hash of the parameters. This
             * hash is called the `ParmsId' and can be easily accessed and printed at any
             * time. The hash will change as soon as any of the parameters is changed.
             *
             * When a SEALContext is created from a given EncryptionParameters instance,
             * Microsoft SEAL automatically creates a so-called `modulus switching chain',
             * which is a chain of other encryption parameters derived from the original set.
             * The parameters in the modulus switching chain are the same as the original
             * parameters with the exception that size of the coefficient modulus is
             * decreasing going down the chain. More precisely, each parameter set in the
             * chain attempts to remove the last coefficient modulus prime from the
             * previous set; this continues until the parameter set is no longer valid
             * (e.g., PlainModulus is larger than the remaining CoeffModulus). It is easy
             * to walk through the chain and access all the parameter sets. Additionally,
             * each parameter set in the chain has a `chain index' that indicates its
             * position in the chain so that the last set has index 0. We say that a set
             * of encryption parameters, or an object carrying those encryption parameters,
             * is at a higher level in the chain than another set of parameters if its the
             * chain index is bigger, i.e., it is earlier in the chain.
             *
             * Each set of parameters in the chain involves unique pre-computations performed
             * when the SEALContext is created, and stored in a SEALContext.ContextData
             * object. The chain is basically a linked list of SEALContext.ContextData
             * objects, and can easily be accessed through the SEALContext at any time. Each
             * node can be identified by the ParmsId of its specific encryption parameters
             * (PolyModulusDegree remains the same but CoeffModulus varies).
             */
            EncryptionParameters parms = new EncryptionParameters(SchemeType.BFV);
            ulong polyModulusDegree    = 8192;

            parms.PolyModulusDegree = polyModulusDegree;

            /*
             * In this example we use a custom CoeffModulus, consisting of 5 primes of
             * sizes 50, 30, 30, 50, and 50 bits. Note that this is still OK according to
             * the explanation in `1_BFV_Basics.cs'. Indeed,
             *
             *  CoeffModulus.MaxBitCount(polyModulusDegree)
             *
             * returns 218 (less than 50+30+30+50+50=210).
             *
             * Due to the modulus switching chain, the order of the 5 primes is significant.
             * The last prime has a special meaning and we call it the `special prime'. Thus,
             * the first parameter set in the modulus switching chain is the only one that
             * involves the special prime. All key objects, such as SecretKey, are created
             * at this highest level. All data objects, such as Ciphertext, can be only at
             * lower levels. The special modulus should be as large as the largest of the
             * other primes in the CoeffModulus, although this is not a strict requirement.
             *
             *       special prime +---------+
             |
             |                               v
             | CoeffModulus: { 50, 30, 30, 50, 50 }  +---+  Level 4 (all keys; `key level')
             |
             |
             |  CoeffModulus: { 50, 30, 30, 50 }  +---+  Level 3 (highest `data level')
             |
             |
             |      CoeffModulus: { 50, 30, 30 }  +---+  Level 2
             |
             |
             |          CoeffModulus: { 50, 30 }  +---+  Level 1
             |
             |
             |              CoeffModulus: { 50 }  +---+  Level 0 (lowest level)
             */
            parms.CoeffModulus = CoeffModulus.Create(
                polyModulusDegree, new int[] { 50, 30, 30, 50, 50 });

            /*
             * In this example the PlainModulus does not play much of a role; we choose
             * some reasonable value.
             */
            parms.PlainModulus = new SmallModulus(1 << 20);

            SEALContext context = new SEALContext(parms);

            Utilities.PrintParameters(context);

            /*
             * There are convenience method for accessing the SEALContext.ContextData for
             * some of the most important levels:
             *
             *  SEALContext.KeyContextData: access to key level ContextData
             *  SEALContext.FirstContextData: access to highest data level ContextData
             *  SEALContext.LastContextData: access to lowest level ContextData
             *
             * We iterate over the chain and print the ParmsId for each set of parameters.
             */
            Console.WriteLine();
            Utilities.PrintLine();
            Console.WriteLine("Print the modulus switching chain.");

            /*
             * First print the key level parameter information.
             */
            SEALContext.ContextData contextData = context.KeyContextData;
            Console.WriteLine("----> Level (chain index): {0} ...... KeyContextData",
                              contextData.ChainIndex);
            Console.WriteLine($"      ParmsId: {contextData.ParmsId}");
            Console.Write("      CoeffModulus primes: ");
            foreach (SmallModulus prime in contextData.Parms.CoeffModulus)
            {
                Console.Write($"{Utilities.ULongToString(prime.Value)} ");
            }
            Console.WriteLine();
            Console.WriteLine("\\");
            Console.Write(" \\--> ");

            /*
             * Next iterate over the remaining (data) levels.
             */
            contextData = context.FirstContextData;
            while (null != contextData)
            {
                Console.Write($"Level (chain index): {contextData.ChainIndex}");
                if (contextData.ParmsId.Equals(context.FirstParmsId))
                {
                    Console.WriteLine(" ...... FirstContextData");
                }
                else if (contextData.ParmsId.Equals(context.LastParmsId))
                {
                    Console.WriteLine(" ...... LastContextData");
                }
                else
                {
                    Console.WriteLine();
                }
                Console.WriteLine($"      ParmsId: {contextData.ParmsId}");
                Console.Write("      CoeffModulus primes: ");
                foreach (SmallModulus prime in contextData.Parms.CoeffModulus)
                {
                    Console.Write($"{Utilities.ULongToString(prime.Value)} ");
                }
                Console.WriteLine();
                Console.WriteLine("\\");
                Console.Write(" \\--> ");

                /*
                 * Step forward in the chain.
                 */
                contextData = contextData.NextContextData;
            }
            Console.WriteLine("End of chain reached");
            Console.WriteLine();

            /*
             * We create some keys and check that indeed they appear at the highest level.
             */
            KeyGenerator keygen     = new KeyGenerator(context);
            PublicKey    publicKey  = keygen.PublicKey;
            SecretKey    secretKey  = keygen.SecretKey;
            RelinKeys    relinKeys  = keygen.RelinKeys();
            GaloisKeys   galoisKeys = keygen.GaloisKeys();

            Utilities.PrintLine();
            Console.WriteLine("Print the parameter IDs of generated elements.");
            Console.WriteLine($"    + publicKey:  {publicKey.ParmsId}");
            Console.WriteLine($"    + secretKey:  {secretKey.ParmsId}");
            Console.WriteLine($"    + relinKeys:  {relinKeys.ParmsId}");
            Console.WriteLine($"    + galoisKeys: {galoisKeys.ParmsId}");

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

            /*
             * In the BFV scheme plaintexts do not carry a ParmsId, but ciphertexts do. Note
             * how the freshly encrypted ciphertext is at the highest data level.
             */
            Plaintext  plain     = new Plaintext("1x^3 + 2x^2 + 3x^1 + 4");
            Ciphertext encrypted = new Ciphertext();

            encryptor.Encrypt(plain, encrypted);
            Console.WriteLine($"    + plain:      {plain.ParmsId} (not set in BFV)");
            Console.WriteLine($"    + encrypted:  {encrypted.ParmsId}");
            Console.WriteLine();

            /*
             * `Modulus switching' is a technique of changing the ciphertext parameters down
             * in the chain. The function Evaluator.ModSwitchToNext always switches to the
             * next level down the chain, whereas Evaluator.ModSwitchTo switches to a parameter
             * set down the chain corresponding to a given ParmsId. However, it is impossible
             * to switch up in the chain.
             */
            Utilities.PrintLine();
            Console.WriteLine("Perform modulus switching on encrypted and print.");
            contextData = context.FirstContextData;
            Console.Write("----> ");
            while (null != contextData.NextContextData)
            {
                Console.WriteLine($"Level (chain index): {contextData.ChainIndex}");
                Console.WriteLine($"      ParmsId of encrypted: {contextData.ParmsId}");
                Console.WriteLine("      Noise budget at this level: {0} bits",
                                  decryptor.InvariantNoiseBudget(encrypted));
                Console.WriteLine("\\");
                Console.Write(" \\--> ");
                evaluator.ModSwitchToNextInplace(encrypted);
                contextData = contextData.NextContextData;
            }
            Console.WriteLine($"Level (chain index): {contextData.ChainIndex}");
            Console.WriteLine($"      ParmsId of encrypted: {contextData.ParmsId}");
            Console.WriteLine("      Noise budget at this level: {0} bits",
                              decryptor.InvariantNoiseBudget(encrypted));
            Console.WriteLine("\\");
            Console.Write(" \\--> ");
            Console.WriteLine("End of chain reached");
            Console.WriteLine();

            /*
             * At this point it is hard to see any benefit in doing this: we lost a huge
             * amount of noise budget (i.e., computational power) at each switch and seemed
             * to get nothing in return. Decryption still works.
             */
            Utilities.PrintLine();
            Console.WriteLine("Decrypt still works after modulus switching.");
            decryptor.Decrypt(encrypted, plain);
            Console.WriteLine($"    + Decryption of encrypted: {plain} ...... Correct.");
            Console.WriteLine();

            /*
             * However, there is a hidden benefit: the size of the ciphertext depends
             * linearly on the number of primes in the coefficient modulus. Thus, if there
             * is no need or intention to perform any further computations on a given
             * ciphertext, we might as well switch it down to the smallest (last) set of
             * parameters in the chain before sending it back to the secret key holder for
             * decryption.
             *
             * Also the lost noise budget is actually not as issue at all, if we do things
             * right, as we will see below.
             *
             * First we recreate the original ciphertext and perform some computations.
             */
            Console.WriteLine("Computation is more efficient with modulus switching.");
            Utilities.PrintLine();
            Console.WriteLine("Compute the fourth power.");
            encryptor.Encrypt(plain, encrypted);
            Console.WriteLine("    + Noise budget before squaring:         {0} bits",
                              decryptor.InvariantNoiseBudget(encrypted));
            evaluator.SquareInplace(encrypted);
            evaluator.RelinearizeInplace(encrypted, relinKeys);
            Console.WriteLine("    + Noise budget after squaring:          {0} bits",
                              decryptor.InvariantNoiseBudget(encrypted));

            /*
             * From the print-out we see that the noise budget after these computations is
             * just slightly below the level we would have in a fresh ciphertext after one
             * modulus switch (135 bits). Surprisingly, in this case modulus switching has
             * no effect at all on the noise budget.
             */
            evaluator.ModSwitchToNextInplace(encrypted);
            Console.WriteLine("    + Noise budget after modulus switching: {0} bits",
                              decryptor.InvariantNoiseBudget(encrypted));


            /*
             * This means that there is no harm at all in dropping some of the coefficient
             * modulus after doing enough computations. In some cases one might want to
             * switch to a lower level slightly earlier, actually sacrificing some of the
             * noise budget in the process, to gain computational performance from having
             * smaller parameters. We see from the print-out that the next modulus switch
             * should be done ideally when the noise budget is down to around 81 bits.
             */
            evaluator.SquareInplace(encrypted);
            evaluator.RelinearizeInplace(encrypted, relinKeys);
            Console.WriteLine("    + Noise budget after squaring:          {0} bits",
                              decryptor.InvariantNoiseBudget(encrypted));
            evaluator.ModSwitchToNextInplace(encrypted);
            Console.WriteLine("    + Noise budget after modulus switching: {0} bits",
                              decryptor.InvariantNoiseBudget(encrypted));

            /*
             * At this point the ciphertext still decrypts correctly, has very small size,
             * and the computation was as efficient as possible. Note that the decryptor
             * can be used to decrypt a ciphertext at any level in the modulus switching
             * chain.
             */
            decryptor.Decrypt(encrypted, plain);
            Console.WriteLine("    + Decryption of fourth power (hexadecimal) ...... Correct.");
            Console.WriteLine($"    {plain}");
            Console.WriteLine();

            /*
             * In BFV modulus switching is not necessary and in some cases the user might
             * not want to create the modulus switching chain, except for the highest two
             * levels. This can be done by passing a bool `false' to SEALContext constructor.
             */
            context = new SEALContext(parms, expandModChain: false);

            /*
             * We can check that indeed the modulus switching chain has been created only
             * for the highest two levels (key level and highest data level). The following
             * loop should execute only once.
             */
            Console.WriteLine("Optionally disable modulus switching chain expansion.");
            Utilities.PrintLine();
            Console.WriteLine("Print the modulus switching chain.");
            Console.Write("----> ");
            for (contextData = context.KeyContextData; null != contextData;
                 contextData = contextData.NextContextData)
            {
                Console.WriteLine($"Level (chain index): {contextData.ChainIndex}");
                Console.WriteLine($"      ParmsId of encrypted: {contextData.ParmsId}");
                Console.Write("      CoeffModulus primes: ");
                foreach (SmallModulus prime in contextData.Parms.CoeffModulus)
                {
                    Console.Write($"{Utilities.ULongToString(prime.Value)} ");
                }
                Console.WriteLine();
                Console.WriteLine("\\");
                Console.Write(" \\--> ");
            }
            Console.WriteLine("End of chain reached");
            Console.WriteLine();

            /*
             * It is very important to understand how this example works since in the CKKS
             * scheme modulus switching has a much more fundamental purpose and the next
             * examples will be difficult to understand unless these basic properties are
             * totally clear.
             */
        }
コード例 #26
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.
             */
        }
コード例 #27
0
ファイル: 1_BFV_Basics.cs プロジェクト: eshnil2000/bootcamp
        private static void ExampleBFVBasics()
        {
            Utilities.PrintExampleBanner("Example: BFV Basics");

            /*
             * In this example, we demonstrate performing simple computations (a polynomial
             * evaluation) on encrypted integers using the BFV encryption scheme.
             *
             * The first task is to set up an instance of the EncryptionParameters class.
             * It is critical to understand how the different parameters behave, how they
             * affect the encryption scheme, performance, and the security level. There are
             * three encryption parameters that are necessary to set:
             *
             *  - PolyModulusDegree (degree of polynomial modulus);
             *  - CoeffModulus ([ciphertext] coefficient modulus);
             *  - PlainModulus (plaintext modulus; only for the BFV scheme).
             *
             * The BFV scheme cannot perform arbitrary computations on encrypted data.
             * Instead, each ciphertext has a specific quantity called the `invariant noise
             * budget' -- or `noise budget' for short -- measured in bits. The noise budget
             * in a freshly encrypted ciphertext (initial noise budget) is determined by
             * the encryption parameters. Homomorphic operations consume the noise budget
             * at a rate also determined by the encryption parameters. In BFV the two basic
             * operations allowed on encrypted data are additions and multiplications, of
             * which additions can generally be thought of as being nearly free in terms of
             * noise budget consumption compared to multiplications. Since noise budget
             * consumption compounds in sequential multiplications, the most significant
             * factor in choosing appropriate encryption parameters is the multiplicative
             * depth of the arithmetic circuit that the user wants to evaluate on encrypted
             * data. Once the noise budget of a ciphertext reaches zero it becomes too
             * corrupted to be decrypted. Thus, it is essential to choose the parameters to
             * be large enough to support the desired computation; otherwise the result is
             * impossible to make sense of even with the secret key.
             */
            EncryptionParameters parms = new EncryptionParameters(SchemeType.BFV);

            /*
             * The first parameter we set is the degree of the `polynomial modulus'. This
             * must be a positive power of 2, representing the degree of a power-of-two
             * cyclotomic polynomial; it is not necessary to understand what this means.
             *
             * Larger PolyModulusDegree makes ciphertext sizes larger and all operations
             * slower, but enables more complicated encrypted computations. Recommended
             * values are 1024, 2048, 4096, 8192, 16384, 32768, but it is also possible
             * to go beyond this range.
             *
             * In this example we use a relatively small polynomial modulus. Anything
             * smaller than this will enable only very restricted encrypted computations.
             */
            ulong polyModulusDegree = 4096;

            parms.PolyModulusDegree = polyModulusDegree;

            /*
             * Next we set the [ciphertext] `coefficient modulus' (CoeffModulus). This
             * parameter is a large integer, which is a product of distinct prime numbers,
             * numbers, each represented by an instance of the SmallModulus class. The
             * bit-length of CoeffModulus means the sum of the bit-lengths of its prime
             * factors.
             *
             * A larger CoeffModulus implies a larger noise budget, hence more encrypted
             * computation capabilities. However, an upper bound for the total bit-length
             * of the CoeffModulus is determined by the PolyModulusDegree, as follows:
             *
             +----------------------------------------------------+
             | PolyModulusDegree   | max CoeffModulus bit-length  |
             +---------------------+------------------------------+
             | 1024                | 27                           |
             | 2048                | 54                           |
             | 4096                | 109                          |
             | 8192                | 218                          |
             | 16384               | 438                          |
             | 32768               | 881                          |
             +---------------------+------------------------------+
             |
             | These numbers can also be found in native/src/seal/util/hestdparms.h encoded
             | in the function SEAL_HE_STD_PARMS_128_TC, and can also be obtained from the
             | function
             |
             |  CoeffModulus.MaxBitCount(polyModulusDegree).
             |
             | For example, if PolyModulusDegree is 4096, the coeff_modulus could consist
             | of three 36-bit primes (108 bits).
             |
             | Microsoft SEAL comes with helper functions for selecting the CoeffModulus.
             | For new users the easiest way is to simply use
             |
             |  CoeffModulus.BFVDefault(polyModulusDegree),
             |
             | which returns IEnumerable<SmallModulus> consisting of a generally good choice
             | for the given PolyModulusDegree.
             */
            parms.CoeffModulus = CoeffModulus.BFVDefault(polyModulusDegree);

            /*
             * The plaintext modulus can be any positive integer, even though here we take
             * it to be a power of two. In fact, in many cases one might instead want it
             * to be a prime number; we will see this in later examples. The plaintext
             * modulus determines the size of the plaintext data type and the consumption
             * of noise budget in multiplications. Thus, it is essential to try to keep the
             * plaintext data type as small as possible for best performance. The noise
             * budget in a freshly encrypted ciphertext is
             *
             *  ~ log2(CoeffModulus/PlainModulus) (bits)
             *
             * and the noise budget consumption in a homomorphic multiplication is of the
             * form log2(PlainModulus) + (other terms).
             *
             * The plaintext modulus is specific to the BFV scheme, and cannot be set when
             * using the CKKS scheme.
             */
            parms.PlainModulus = new SmallModulus(1024);

            /*
             * Now that all parameters are set, we are ready to construct a SEALContext
             * object. This is a heavy class that checks the validity and properties of the
             * parameters we just set.
             */
            SEALContext context = new SEALContext(parms);

            /*
             * Print the parameters that we have chosen.
             */
            Utilities.PrintLine();
            Console.WriteLine("Set encryption parameters and print");
            Utilities.PrintParameters(context);

            Console.WriteLine();
            Console.WriteLine("~~~~~~ A naive way to calculate 4(x^2+1)(x+1)^2. ~~~~~~");

            /*
             * The encryption schemes in Microsoft SEAL are public key encryption schemes.
             * For users unfamiliar with this terminology, a public key encryption scheme
             * has a separate public key for encrypting data, and a separate secret key for
             * decrypting data. This way multiple parties can encrypt data using the same
             * shared public key, but only the proper recipient of the data can decrypt it
             * with the secret key.
             *
             * We are now ready to generate the secret and public keys. For this purpose
             * we need an instance of the KeyGenerator class. Constructing a KeyGenerator
             * automatically generates the public and secret key, which can immediately be
             * read to local variables.
             */
            KeyGenerator keygen    = new KeyGenerator(context);
            PublicKey    publicKey = keygen.PublicKey;
            SecretKey    secretKey = keygen.SecretKey;

            /*
             * To be able to encrypt we need to construct an instance of Encryptor. Note
             * that the Encryptor only requires the public key, as expected.
             */
            Encryptor encryptor = new Encryptor(context, publicKey);

            /*
             * Computations on the ciphertexts are performed with the Evaluator class. In
             * a real use-case the Evaluator would not be constructed by the same party
             * that holds the secret key.
             */
            Evaluator evaluator = new Evaluator(context);

            /*
             * We will of course want to decrypt our results to verify that everything worked,
             * so we need to also construct an instance of Decryptor. Note that the Decryptor
             * requires the secret key.
             */
            Decryptor decryptor = new Decryptor(context, secretKey);

            /*
             * As an example, we evaluate the degree 4 polynomial
             *
             *  4x^4 + 8x^3 + 8x^2 + 8x + 4
             *
             * over an encrypted x = 6. The coefficients of the polynomial can be considered
             * as plaintext inputs, as we will see below. The computation is done modulo the
             * plain_modulus 1024.
             *
             * While this examples is simple and easy to understand, it does not have much
             * practical value. In later examples we will demonstrate how to compute more
             * efficiently on encrypted integers and real or complex numbers.
             *
             * Plaintexts in the BFV scheme are polynomials of degree less than the degree
             * of the polynomial modulus, and coefficients integers modulo the plaintext
             * modulus. For readers with background in ring theory, the plaintext space is
             * the polynomial quotient ring Z_T[X]/(X^N + 1), where N is PolyModulusDegree
             * and T is PlainModulus.
             *
             * To get started, we create a plaintext containing the constant 6. For the
             * plaintext element we use a constructor that takes the desired polynomial as
             * a string with coefficients represented as hexadecimal numbers.
             */
            Utilities.PrintLine();
            int       x      = 6;
            Plaintext xPlain = new Plaintext(x.ToString());

            Console.WriteLine($"Express x = {x} as a plaintext polynomial 0x{xPlain}.");

            /*
             * We then encrypt the plaintext, producing a ciphertext.
             */
            Utilities.PrintLine();
            Ciphertext xEncrypted = new Ciphertext();

            Console.WriteLine("Encrypt xPlain to xEncrypted.");
            encryptor.Encrypt(xPlain, xEncrypted);

            /*
             * In Microsoft SEAL, a valid ciphertext consists of two or more polynomials
             * whose coefficients are integers modulo the product of the primes in the
             * coeff_modulus. The number of polynomials in a ciphertext is called its `size'
             * and is given by Ciphertext.Size. A freshly encrypted ciphertext always has
             * size 2.
             */
            Console.WriteLine($"    + size of freshly encrypted x: {xEncrypted.Size}");

            /*
             * There is plenty of noise budget left in this freshly encrypted ciphertext.
             */
            Console.WriteLine("    + noise budget in freshly encrypted x: {0} bits",
                              decryptor.InvariantNoiseBudget(xEncrypted));

            /*
             * We decrypt the ciphertext and print the resulting plaintext in order to
             * demonstrate correctness of the encryption.
             */
            Plaintext xDecrypted = new Plaintext();

            Console.Write("    + decryption of encrypted_x: ");
            decryptor.Decrypt(xEncrypted, xDecrypted);
            Console.WriteLine($"0x{xDecrypted} ...... Correct.");

            /*
             * When using Microsoft SEAL, it is typically advantageous to compute in a way
             * that minimizes the longest chain of sequential multiplications. In other
             * words, encrypted computations are best evaluated in a way that minimizes
             * the multiplicative depth of the computation, because the total noise budget
             * consumption is proportional to the multiplicative depth. For example, for
             * our example computation it is advantageous to factorize the polynomial as
             *
             *  4x^4 + 8x^3 + 8x^2 + 8x + 4 = 4(x + 1)^2 * (x^2 + 1)
             *
             * to obtain a simple depth 2 representation. Thus, we compute (x + 1)^2 and
             * (x^2 + 1) separately, before multiplying them, and multiplying by 4.
             *
             * First, we compute x^2 and add a plaintext "1". We can clearly see from the
             * print-out that multiplication has consumed a lot of noise budget. The user
             * can vary the plain_modulus parameter to see its effect on the rate of noise
             * budget consumption.
             */
            Utilities.PrintLine();
            Console.WriteLine("Compute xSqPlusOne (x^2+1).");
            Ciphertext xSqPlusOne = new Ciphertext();

            evaluator.Square(xEncrypted, xSqPlusOne);
            Plaintext plainOne = new Plaintext("1");

            evaluator.AddPlainInplace(xSqPlusOne, plainOne);

            /*
             * Encrypted multiplication results in the output ciphertext growing in size.
             * More precisely, if the input ciphertexts have size M and N, then the output
             * ciphertext after homomorphic multiplication will have size M+N-1. In this
             * case we perform a squaring, and observe both size growth and noise budget
             * consumption.
             */
            Console.WriteLine($"    + size of xSqPlusOne: {xSqPlusOne.Size}");
            Console.WriteLine("    + noise budget in xSqPlusOne: {0} bits",
                              decryptor.InvariantNoiseBudget(xSqPlusOne));

            /*
             * Even though the size has grown, decryption works as usual as long as noise
             * budget has not reached 0.
             */
            Plaintext decryptedResult = new Plaintext();

            Console.Write("    + decryption of xSqPlusOne: ");
            decryptor.Decrypt(xSqPlusOne, decryptedResult);
            Console.WriteLine($"0x{decryptedResult} ...... Correct.");

            /*
             * Next, we compute (x + 1)^2.
             */
            Utilities.PrintLine();
            Console.WriteLine("Compute xPlusOneSq ((x+1)^2).");
            Ciphertext xPlusOneSq = new Ciphertext();

            evaluator.AddPlain(xEncrypted, plainOne, xPlusOneSq);
            evaluator.SquareInplace(xPlusOneSq);
            Console.WriteLine($"    + size of xPlusOneSq: {xPlusOneSq.Size}");
            Console.WriteLine("    + noise budget in xPlusOneSq: {0} bits",
                              decryptor.InvariantNoiseBudget(xPlusOneSq));
            Console.Write("    + decryption of xPlusOneSq: ");
            decryptor.Decrypt(xPlusOneSq, decryptedResult);
            Console.WriteLine($"0x{decryptedResult} ...... Correct.");

            /*
             * Finally, we multiply (x^2 + 1) * (x + 1)^2 * 4.
             */
            Utilities.PrintLine();
            Console.WriteLine("Compute encryptedResult (4(x^2+1)(x+1)^2).");
            Ciphertext encryptedResult = new Ciphertext();
            Plaintext  plainFour       = new Plaintext("4");

            evaluator.MultiplyPlainInplace(xSqPlusOne, plainFour);
            evaluator.Multiply(xSqPlusOne, xPlusOneSq, encryptedResult);
            Console.WriteLine($"    + size of encrypted_result: {encryptedResult.Size}");
            Console.WriteLine("    + noise budget in encrypted_result: {0} bits",
                              decryptor.InvariantNoiseBudget(encryptedResult));
            Console.WriteLine("NOTE: Decryption can be incorrect if noise budget is zero.");

            Console.WriteLine();
            Console.WriteLine("~~~~~~ A better way to calculate 4(x^2+1)(x+1)^2. ~~~~~~");

            /*
             * Noise budget has reached 0, which means that decryption cannot be expected
             * to give the correct result. This is because both ciphertexts xSqPlusOne and
             * xPlusOneSq consist of 3 polynomials due to the previous squaring operations,
             * and homomorphic operations on large ciphertexts consume much more noise budget
             * than computations on small ciphertexts. Computing on smaller ciphertexts is
             * also computationally significantly cheaper.
             *
             * `Relinearization' is an operation that reduces the size of a ciphertext after
             * multiplication back to the initial size, 2. Thus, relinearizing one or both
             * input ciphertexts before the next multiplication can have a huge positive
             * impact on both noise growth and performance, even though relinearization has
             * a significant computational cost itself. It is only possible to relinearize
             * size 3 ciphertexts down to size 2, so often the user would want to relinearize
             * after each multiplication to keep the ciphertext sizes at 2.
             *
             * Relinearization requires special `relinearization keys', which can be thought
             * of as a kind of public key. Relinearization keys can easily be created with
             * the KeyGenerator.
             *
             * Relinearization is used similarly in both the BFV and the CKKS schemes, but
             * in this example we continue using BFV. We repeat our computation from before,
             * but this time relinearize after every multiplication.
             *
             * We use KeyGenerator.RelinKeys() to create relinearization keys.
             */
            Utilities.PrintLine();
            Console.WriteLine("Generate relinearization keys.");
            RelinKeys relinKeys = keygen.RelinKeys();

            /*
             * We now repeat the computation relinearizing after each multiplication.
             */
            Utilities.PrintLine();
            Console.WriteLine("Compute and relinearize xSquared (x^2),");
            Console.WriteLine(new string(' ', 13) + "then compute xSqPlusOne (x^2+1)");
            Ciphertext xSquared = new Ciphertext();

            evaluator.Square(xEncrypted, xSquared);
            Console.WriteLine($"    + size of xSquared: {xSquared.Size}");
            evaluator.RelinearizeInplace(xSquared, relinKeys);
            Console.WriteLine("    + size of xSquared (after relinearization): {0}",
                              xSquared.Size);
            evaluator.AddPlain(xSquared, plainOne, xSqPlusOne);
            Console.WriteLine("    + noise budget in xSqPlusOne: {0} bits",
                              decryptor.InvariantNoiseBudget(xSqPlusOne));
            Console.Write("    + decryption of xSqPlusOne: ");
            decryptor.Decrypt(xSqPlusOne, decryptedResult);
            Console.WriteLine($"0x{decryptedResult} ...... Correct.");

            Utilities.PrintLine();
            Ciphertext xPlusOne = new Ciphertext();

            Console.WriteLine("Compute xPlusOne (x+1),");
            Console.WriteLine(new string(' ', 13) +
                              "then compute and relinearize xPlusOneSq ((x+1)^2).");
            evaluator.AddPlain(xEncrypted, plainOne, xPlusOne);
            evaluator.Square(xPlusOne, xPlusOneSq);
            Console.WriteLine($"    + size of xPlusOneSq: {xPlusOneSq.Size}");
            evaluator.RelinearizeInplace(xPlusOneSq, relinKeys);
            Console.WriteLine("    + noise budget in xPlusOneSq: {0} bits",
                              decryptor.InvariantNoiseBudget(xPlusOneSq));
            Console.Write("    + decryption of xPlusOneSq: ");
            decryptor.Decrypt(xPlusOneSq, decryptedResult);
            Console.WriteLine($"0x{decryptedResult} ...... Correct.");

            Utilities.PrintLine();
            Console.WriteLine("Compute and relinearize encryptedResult (4(x^2+1)(x+1)^2).");
            evaluator.MultiplyPlainInplace(xSqPlusOne, plainFour);
            evaluator.Multiply(xSqPlusOne, xPlusOneSq, encryptedResult);
            Console.WriteLine($"    + size of encryptedResult: {encryptedResult.Size}");
            evaluator.RelinearizeInplace(encryptedResult, relinKeys);
            Console.WriteLine("    + size of encryptedResult (after relinearization): {0}",
                              encryptedResult.Size);
            Console.WriteLine("    + noise budget in encryptedResult: {0} bits",
                              decryptor.InvariantNoiseBudget(encryptedResult));

            Console.WriteLine();
            Console.WriteLine("NOTE: Notice the increase in remaining noise budget.");

            /*
             * Relinearization clearly improved our noise consumption. We have still plenty
             * of noise budget left, so we can expect the correct answer when decrypting.
             */
            Utilities.PrintLine();
            Console.WriteLine("Decrypt encrypted_result (4(x^2+1)(x+1)^2).");
            decryptor.Decrypt(encryptedResult, decryptedResult);
            Console.WriteLine("    + decryption of 4(x^2+1)(x+1)^2 = 0x{0} ...... Correct.",
                              decryptedResult);

            /*
             * For x=6, 4(x^2+1)(x+1)^2 = 7252. Since the plaintext modulus is set to 1024,
             * this result is computed in integers modulo 1024. Therefore the expected output
             * should be 7252 % 1024 == 84, or 0x54 in hexadecimal.
             */
        }
コード例 #28
0
 public Svc(double[][] vectors, double[][] coefficients, double[] intercepts, String kernel, double gamma,
            double coef0, ulong degree, int power, PublicKey publicKey, RelinKeys relinKeys,
            GaloisKeys galoisKeys, int batchSize, int featureSize) : this(vectors, coefficients, intercepts, kernel, gamma, coef0, degree, power, publicKey, null, relinKeys, galoisKeys, batchSize, featureSize)
 {
 }
コード例 #29
0
            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);
            }
コード例 #30
0
ファイル: Program.cs プロジェクト: salrashid123/fhe
        public void calculateDistance(string encryptedRiderXFile, string encryptedRiderYFile, string encryptedDriverXFile, string encryptedDriverYFile, string distanceFile)
        {
            using EncryptionParameters parms = new EncryptionParameters(SchemeType.BFV);
            ulong polyModulusDegree = 4096;

            parms.PolyModulusDegree = polyModulusDegree;
            parms.CoeffModulus      = CoeffModulus.BFVDefault(polyModulusDegree);
            parms.PlainModulus      = new Modulus(1024);

            using SEALContext context = new SEALContext(parms);

            using KeyGenerator keygen = new KeyGenerator(context);

            using PublicKey riderPub = new PublicKey();


            using Ciphertext xRiderEncrypted = new Ciphertext();
            using (var sr = new StreamReader(encryptedRiderXFile))
            {
                xRiderEncrypted.Load(context, sr.BaseStream);
            }

            using Ciphertext yRiderEncrypted = new Ciphertext();
            using (var sr = new StreamReader(encryptedRiderYFile))
            {
                yRiderEncrypted.Load(context, sr.BaseStream);
            }

            using Ciphertext xDriverEncrypted = new Ciphertext();
            using (var sr = new StreamReader(encryptedDriverXFile))
            {
                xDriverEncrypted.Load(context, sr.BaseStream);
            }

            using Ciphertext yDriverEncrypted = new Ciphertext();
            using (var sr = new StreamReader(encryptedDriverYFile))
            {
                yDriverEncrypted.Load(context, sr.BaseStream);
            }

            //Console.WriteLine("Calculate ( (x2-x1)^2 + (y2-y1)^2 )");

            using Evaluator evaluator    = new Evaluator(context);
            using IntegerEncoder encoder = new IntegerEncoder(context);

            using RelinKeys relinKeys = keygen.RelinKeysLocal();

            using Ciphertext X2MinusX1 = new Ciphertext();
            evaluator.Sub(xDriverEncrypted, xRiderEncrypted, X2MinusX1);          // (x2-x1)

            using Ciphertext Y2MinusY1 = new Ciphertext();
            evaluator.Sub(yDriverEncrypted, yRiderEncrypted, Y2MinusY1);          // (y2-y1)

            using Ciphertext X2MinusX1Squared = new Ciphertext();
            evaluator.Square(X2MinusX1, X2MinusX1Squared);                        // (x2-x1)^2
            //evaluator.RelinearizeInplace(X2MinusX1Squared, relinKeys);

            using Ciphertext Y2MinusY1Squared = new Ciphertext();
            evaluator.Square(Y2MinusY1, Y2MinusY1Squared);                        // (x2-x1)^2
            //evaluator.RelinearizeInplace(Y2MinusY1Squared, relinKeys);

            using Ciphertext X2MinusX1SquaredPlusY2MinusY1Squared = new Ciphertext();
            evaluator.Add(X2MinusX1Squared, Y2MinusY1Squared, X2MinusX1SquaredPlusY2MinusY1Squared);   // (x2-x1)^2 + (y2-y1)^2

            // using Ciphertext SquareRootOfX2MinusX1SquaredPlusY2MinusY1Squared = new Ciphertext();
            // decimal vIn = 0.5M;
            // ulong vOut = Convert.ToUInt64(vIn);
            // evaluator.Exponentiate(X2MinusX1SquaredPlusY2MinusY1Squared, vOut,relinKeys,SquareRootOfX2MinusX1SquaredPlusY2MinusY1Squared);

            var fileStream = File.Create(distanceFile);

            X2MinusX1SquaredPlusY2MinusY1Squared.Save(fileStream);
            fileStream.Close();
        }