public void ExceptionsTest() { SEALContext context = GlobalContext.BFVContext; KeyGenerator keygen = new KeyGenerator(context); SecretKey secret = new SecretKey(); List <uint> elts = new List <uint> { 16385 }; List <uint> elts_null = null; List <int> steps = new List <int> { 4096 }; List <int> steps_null = null; Utilities.AssertThrows <ArgumentNullException>(() => keygen = new KeyGenerator(null)); Utilities.AssertThrows <ArgumentNullException>(() => keygen = new KeyGenerator(context, null)); Utilities.AssertThrows <ArgumentNullException>(() => keygen = new KeyGenerator(null, keygen.SecretKey)); Utilities.AssertThrows <ArgumentException>(() => keygen = new KeyGenerator(context, secret)); Utilities.AssertThrows <ArgumentNullException>(() => keygen.GaloisKeys(elts_null)); Utilities.AssertThrows <ArgumentException>(() => keygen.GaloisKeys(elts)); Utilities.AssertThrows <ArgumentNullException>(() => keygen.GaloisKeys(steps_null)); Utilities.AssertThrows <ArgumentException>(() => keygen.GaloisKeys(steps)); EncryptionParameters smallParms = new EncryptionParameters(SchemeType.CKKS); smallParms.PolyModulusDegree = 128; smallParms.CoeffModulus = CoeffModulus.Create(smallParms.PolyModulusDegree, new int[] { 60 }); context = new SEALContext(smallParms, true, SecLevelType.None); keygen = new KeyGenerator(context); Utilities.AssertThrows <InvalidOperationException>(() => keygen.RelinKeys()); Utilities.AssertThrows <InvalidOperationException>(() => keygen.GaloisKeys()); }
public void KeyStepTest() { EncryptionParameters parms = new EncryptionParameters(SchemeType.CKKS) { PolyModulusDegree = 64, CoeffModulus = new List <SmallModulus>() { DefaultParams.SmallMods60Bit(0) } }; SEALContext context = SEALContext.Create(parms); KeyGenerator keygen = new KeyGenerator(context); GaloisKeys keys = keygen.GaloisKeys(decompositionBitCount: 15, steps: new int[] { 1, 2, 3 }); Assert.IsNotNull(keys); Assert.AreEqual(15, keys.DecompositionBitCount); Assert.AreEqual(3ul, keys.Size); Assert.IsFalse(keys.HasKey(1)); Assert.IsTrue(keys.HasKey(3)); Assert.IsFalse(keys.HasKey(5)); Assert.IsFalse(keys.HasKey(7)); Assert.IsTrue(keys.HasKey(9)); Assert.IsFalse(keys.HasKey(11)); Assert.IsFalse(keys.HasKey(13)); Assert.IsFalse(keys.HasKey(15)); Assert.IsFalse(keys.HasKey(17)); Assert.IsFalse(keys.HasKey(19)); Assert.IsFalse(keys.HasKey(21)); Assert.IsFalse(keys.HasKey(23)); Assert.IsFalse(keys.HasKey(25)); Assert.IsTrue(keys.HasKey(27)); }
/// <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(); }
public void KeyTest() { SEALContext context = GlobalContext.BFVContext; KeyGenerator keygen = new KeyGenerator(context); GaloisKeys keys = keygen.GaloisKeys(); MemoryPoolHandle handle = keys.Pool; Assert.IsNotNull(keys); Assert.AreEqual(24ul, keys.Size); Assert.IsFalse(keys.HasKey(galoisElt: 1)); Assert.IsTrue(keys.HasKey(galoisElt: 3)); Assert.IsFalse(keys.HasKey(galoisElt: 5)); Assert.IsFalse(keys.HasKey(galoisElt: 7)); Assert.IsTrue(keys.HasKey(galoisElt: 9)); Assert.IsFalse(keys.HasKey(galoisElt: 11)); IEnumerable <PublicKey> key = keys.Key(3); Assert.AreEqual(4, key.Count()); IEnumerable <PublicKey> key2 = keys.Key(9); Assert.AreEqual(4, key2.Count()); Assert.IsTrue(handle.AllocByteCount > 0ul); }
public void KeyStepTest() { EncryptionParameters parms = new EncryptionParameters(SchemeType.CKKS) { PolyModulusDegree = 64, CoeffModulus = CoeffModulus.Create(64, new int[] { 60, 60 }) }; SEALContext context = new SEALContext(parms, expandModChain: false, secLevel: SecLevelType.None); KeyGenerator keygen = new KeyGenerator(context); GaloisKeys keys = keygen.GaloisKeys(steps: new int[] { 1, 2, 3 }); Assert.IsNotNull(keys); Assert.AreEqual(3ul, keys.Size); Assert.IsFalse(keys.HasKey(1)); Assert.IsTrue(keys.HasKey(3)); Assert.IsFalse(keys.HasKey(5)); Assert.IsFalse(keys.HasKey(7)); Assert.IsTrue(keys.HasKey(9)); Assert.IsFalse(keys.HasKey(11)); Assert.IsFalse(keys.HasKey(13)); Assert.IsFalse(keys.HasKey(15)); Assert.IsFalse(keys.HasKey(17)); Assert.IsFalse(keys.HasKey(19)); Assert.IsFalse(keys.HasKey(21)); Assert.IsFalse(keys.HasKey(23)); Assert.IsFalse(keys.HasKey(25)); Assert.IsTrue(keys.HasKey(27)); }
public void KeyTest() { SEALContext context = GlobalContext.Context; KeyGenerator keygen = new KeyGenerator(context); GaloisKeys keys = keygen.GaloisKeys(decompositionBitCount: 30); MemoryPoolHandle handle = keys.Pool; Assert.IsNotNull(keys); Assert.AreEqual(30, keys.DecompositionBitCount); Assert.AreEqual(22ul, keys.Size); Assert.IsFalse(keys.HasKey(galoisElt: 1)); Assert.IsTrue(keys.HasKey(galoisElt: 3)); Assert.IsFalse(keys.HasKey(galoisElt: 5)); Assert.IsFalse(keys.HasKey(galoisElt: 7)); Assert.IsTrue(keys.HasKey(galoisElt: 9)); Assert.IsFalse(keys.HasKey(galoisElt: 11)); IEnumerable <Ciphertext> key = keys.Key(3); Assert.AreEqual(2, key.Count()); IEnumerable <Ciphertext> key2 = keys.Key(9); Assert.AreEqual(2, key2.Count()); Assert.IsTrue(handle.AllocByteCount > 0ul); }
public void ScaleTest() { EncryptionParameters parms = new EncryptionParameters(SchemeType.CKKS) { PolyModulusDegree = 8, CoeffModulus = CoeffModulus.Create(8, new int[] { 40, 40, 40, 40 }) }; SEALContext context = new SEALContext(parms, expandModChain: true, secLevel: SecLevelType.None); KeyGenerator keygen = new KeyGenerator(context); GaloisKeys galoisKeys = keygen.GaloisKeys(); Encryptor encryptor = new Encryptor(context, keygen.PublicKey); Evaluator evaluator = new Evaluator(context); CKKSEncoder encoder = new CKKSEncoder(context); MemoryPoolHandle pool = MemoryManager.GetPool(MMProfOpt.ForceNew); Assert.AreEqual(0ul, pool.AllocByteCount); Ciphertext encrypted = new Ciphertext(pool); Plaintext plain = new Plaintext(); MemoryPoolHandle cipherPool = encrypted.Pool; Assert.IsNotNull(cipherPool); Assert.AreEqual(0ul, cipherPool.AllocByteCount); List <Complex> input = new List <Complex>() { new Complex(1, 1), new Complex(2, 2), new Complex(3, 3), new Complex(4, 4) }; double delta = Math.Pow(2, 70); encoder.Encode(input, context.FirstParmsId, delta, plain); encryptor.Encrypt(plain, encrypted); Assert.AreEqual(delta, encrypted.Scale, delta: Math.Pow(2, 60)); Ciphertext encrypted2 = new Ciphertext(); encrypted2.Set(encrypted); Assert.AreEqual(delta, encrypted2.Scale, delta: Math.Pow(2, 60)); evaluator.RescaleToNextInplace(encrypted); Assert.AreEqual(Math.Pow(2, 30), encrypted.Scale, delta: 10000); Assert.AreNotEqual(0ul, cipherPool.AllocByteCount); double newScale = Math.Pow(2, 10); encrypted.Scale = newScale; Assert.AreEqual(newScale, encrypted.Scale, delta: 100); }
/// <summary> /// Convert a GaloisKeys object to a Base64 string /// </summary> /// <param name="galk">GaloisKeys to convert</param> /// <returns>Base64 string representing the GaloisKeys</returns> public static string GaloisKeysToBase64(KeyGenerator keygen, List <int> rotations) { using (MemoryStream ms = new MemoryStream()) { // Saving directly to stream; this compresses the size in half keygen.GaloisKeys(rotations).Save(ms); byte[] bytes = ms.ToArray(); return(Convert.ToBase64String(bytes)); } }
public void SaveLoadTest() { SEALContext context = GlobalContext.Context; KeyGenerator keyGen = new KeyGenerator(context); GaloisKeys keys = keyGen.GaloisKeys(decompositionBitCount: 30); GaloisKeys other = new GaloisKeys(); Assert.IsNotNull(keys); Assert.AreEqual(30, keys.DecompositionBitCount); Assert.AreEqual(22ul, keys.Size); 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(22ul, other.Size); Assert.IsTrue(other.IsMetadataValidFor(context)); 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]); } } } }
public void SaveLoadTest() { SEALContext context = GlobalContext.BFVContext; KeyGenerator keyGen = new KeyGenerator(context); GaloisKeys keys = keyGen.GaloisKeys(); GaloisKeys other = new GaloisKeys(); Assert.IsNotNull(keys); Assert.AreEqual(24ul, keys.Size); using (MemoryStream ms = new MemoryStream()) { keys.Save(ms); ms.Seek(offset: 0, loc: SeekOrigin.Begin); other.Load(context, ms); } Assert.AreEqual(24ul, other.Size); Assert.IsTrue(ValCheck.IsValidFor(other, context)); 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.CoeffModCount, otherCipher.Data.CoeffModCount); ulong coeffCount = keysCipher.Data.Size * keysCipher.Data.PolyModulusDegree * keysCipher.Data.CoeffModCount; for (ulong k = 0; k < coeffCount; k++) { Assert.AreEqual(keysCipher.Data[k], otherCipher.Data[k]); } } } }
//private static bool _firstTime = true; //private static Decryptor _decryptor; public SecureSvc(int nRows, double[][] vectors, double[][] coefficients, double[] intercepts, String kernel, double gamma, double coef0, ulong degree , int power) { //this._nRows = nRows; this._vectors = vectors; this._coefficients = coefficients; this._intercepts = intercepts; this._kernel = Enum.Parse<Kernel>(kernel, true); this._gamma = gamma; this._coef0 = coef0; this._degree = degree; this._power = power; EncryptionParameters parms = new EncryptionParameters(SchemeType.CKKS); ulong polyModulusDegree = 16384; if (power >= 20 && power < 40 ) { parms.CoeffModulus = CoeffModulus.Create(polyModulusDegree, new int[] { 60, 20, 21, 22, 23, 24, 25, 26, 27, 60 }); } else if (power >= 40 && power < 60) { parms.CoeffModulus = CoeffModulus.Create(polyModulusDegree, new int[] { 60, 40, 40, 40, 40, 40, 40, 40 , 60 }); } else if (power == 60) { polyModulusDegree = 32768; parms.CoeffModulus = CoeffModulus.Create(polyModulusDegree, new int[] { 60, 60, 60, 60, 60, 60, 60, 60, 60 }); } parms.PolyModulusDegree = polyModulusDegree; _context = new SEALContext(parms); KeyGenerator keygen = new KeyGenerator(_context); _publicKey = keygen.PublicKey; _secretKey = keygen.SecretKey; _relinKeys = keygen.RelinKeys(); _galoisKeys = keygen.GaloisKeys(); _encryptor = new Encryptor(_context, _publicKey); _evaluator = new Evaluator(_context); _decryptor = new Decryptor(_context, _secretKey); _encoder = new CKKSEncoder(_context); }
public void CreateNonEmptyTest() { SEALContext context = GlobalContext.BFVContext; KeyGenerator keygen = new KeyGenerator(context); GaloisKeys keys = keygen.GaloisKeys(); Assert.IsNotNull(keys); Assert.AreEqual(24ul, keys.Size); GaloisKeys copy = new GaloisKeys(keys); Assert.IsNotNull(copy); Assert.AreEqual(24ul, copy.Size); }
public void KeyEltTest() { SEALContext context = GlobalContext.BFVContext; KeyGenerator keygen = new KeyGenerator(context); GaloisKeys keys = keygen.GaloisKeys(galoisElts: new ulong[] { 1, 3 }); Assert.IsNotNull(keys); Assert.AreEqual(2ul, keys.Size); Assert.IsTrue(keys.HasKey(1)); Assert.IsTrue(keys.HasKey(3)); Assert.IsFalse(keys.HasKey(5)); }
public void CreateNonEmptyTest() { SEALContext context = GlobalContext.Context; KeyGenerator keygen = new KeyGenerator(context); GaloisKeys keys = keygen.GaloisKeys(decompositionBitCount: 30); Assert.IsNotNull(keys); Assert.AreEqual(30, keys.DecompositionBitCount); Assert.AreEqual(22ul, keys.Size); GaloisKeys copy = new GaloisKeys(keys); Assert.IsNotNull(copy); Assert.AreEqual(30, copy.DecompositionBitCount); Assert.AreEqual(22ul, copy.Size); }
public void SetTest() { SEALContext context = GlobalContext.BFVContext; KeyGenerator keygen = new KeyGenerator(context); GaloisKeys keys = keygen.GaloisKeys(); Assert.IsNotNull(keys); Assert.AreEqual(24ul, keys.Size); GaloisKeys keys2 = new GaloisKeys(); Assert.IsNotNull(keys2); Assert.AreEqual(0ul, keys2.Size); keys2.Set(keys); Assert.AreNotSame(keys, keys2); Assert.AreEqual(24ul, keys2.Size); }
public void SetTest() { SEALContext context = GlobalContext.Context; KeyGenerator keygen = new KeyGenerator(context); GaloisKeys keys = keygen.GaloisKeys(decompositionBitCount: 30); Assert.IsNotNull(keys); Assert.AreEqual(30, keys.DecompositionBitCount); Assert.AreEqual(22ul, keys.Size); GaloisKeys keys2 = new GaloisKeys(); Assert.IsNotNull(keys2); Assert.AreEqual(0, keys2.DecompositionBitCount); Assert.AreEqual(0ul, keys2.Size); keys2.Set(keys); Assert.AreNotSame(keys, keys2); Assert.AreEqual(30, keys2.DecompositionBitCount); Assert.AreEqual(22ul, keys2.Size); }
private static void ExampleRotationCKKS() { Utilities.PrintExampleBanner("Example: Rotation / Rotation in CKKS"); EncryptionParameters parms = new EncryptionParameters(SchemeType.CKKS); ulong polyModulusDegree = 8192; parms.PolyModulusDegree = polyModulusDegree; parms.CoeffModulus = CoeffModulus.Create( polyModulusDegree, new int[] { 40, 40, 40, 40, 40 }); SEALContext context = new SEALContext(parms); Utilities.PrintParameters(context); Console.WriteLine(); KeyGenerator keygen = new KeyGenerator(context); PublicKey publicKey = keygen.PublicKey; SecretKey secretKey = keygen.SecretKey; RelinKeys relinKeys = keygen.RelinKeys(); GaloisKeys galKeys = keygen.GaloisKeys(); Encryptor encryptor = new Encryptor(context, publicKey); Evaluator evaluator = new Evaluator(context); Decryptor decryptor = new Decryptor(context, secretKey); CKKSEncoder ckksEncoder = new CKKSEncoder(context); ulong slotCount = ckksEncoder.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); double scale = Math.Pow(2.0, 50); Utilities.PrintLine(); Console.WriteLine("Encode and encrypt."); Plaintext plain = new Plaintext(); ckksEncoder.Encode(input, scale, plain); Ciphertext encrypted = new Ciphertext(); encryptor.Encrypt(plain, encrypted); Ciphertext rotated = new Ciphertext(); Utilities.PrintLine(); Console.WriteLine("Rotate 2 steps left."); evaluator.RotateVector(encrypted, 2, galKeys, rotated); Console.WriteLine(" + Decrypt and decode ...... Correct."); decryptor.Decrypt(encrypted, plain); List <double> result = new List <double>(); ckksEncoder.Decode(plain, result); Utilities.PrintVector(result, 3, 7); /* * With the CKKS scheme it is also possible to evaluate a complex conjugation on * a vector of encrypted complex numbers, using Evaluator.ComplexConjugate. This * is in fact a kind of rotation, and requires also Galois keys. */ }
private static void BFVPerformanceTest(SEALContext context) { Stopwatch timer; Utilities.PrintParameters(context); Console.WriteLine(); EncryptionParameters parms = context.FirstContextData.Parms; SmallModulus plainModulus = parms.PlainModulus; ulong polyModulusDegree = parms.PolyModulusDegree; Console.Write("Generating secret/public keys: "); KeyGenerator keygen = new KeyGenerator(context); Console.WriteLine("Done"); SecretKey secretKey = keygen.SecretKey; PublicKey publicKey = keygen.PublicKey; RelinKeys relinKeys = null; GaloisKeys galKeys = null; if (context.UsingKeyswitching) { /* * Generate relinearization keys. */ Console.Write("Generating relinearization keys: "); timer = Stopwatch.StartNew(); relinKeys = keygen.RelinKeys(); int micros = (int)(timer.Elapsed.TotalMilliseconds * 1000); Console.WriteLine($"Done [{micros} microseconds]"); if (!context.KeyContextData.Qualifiers.UsingBatching) { Console.WriteLine("Given encryption parameters do not support batching."); return; } /* * 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(); galKeys = keygen.GaloisKeys(); micros = (int)(timer.Elapsed.TotalMilliseconds * 1000); Console.WriteLine($"Done [{micros} microseconds]"); } Encryptor encryptor = new Encryptor(context, publicKey); Decryptor decryptor = new Decryptor(context, secretKey); Evaluator evaluator = new Evaluator(context); BatchEncoder batchEncoder = new BatchEncoder(context); IntegerEncoder encoder = new IntegerEncoder(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(); /* * 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] = (ulong)rnd.Next() % plainModulus.Value; } 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. */ 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. */ Ciphertext encrypted = new Ciphertext(context); timeEncryptSum.Start(); encryptor.Encrypt(plain, encrypted); timeEncryptSum.Stop(); /* * [Decryption] * We decrypt what we just encrypted. */ 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. */ Ciphertext encrypted1 = new Ciphertext(context); encryptor.Encrypt(encoder.Encode(i), encrypted1); Ciphertext encrypted2 = new Ciphertext(context); encryptor.Encrypt(encoder.Encode(i + 1), 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; int randomRotation = rnd.Next() % rowSize; timeRotateRowsRandomSum.Start(); evaluator.RotateRowsInplace(encrypted, randomRotation, galKeys); timeRotateRowsRandomSum.Stop(); /* * [Rotate Columns] * Nothing surprising here. */ timeRotateColumnsSum.Start(); evaluator.RotateColumnsInplace(encrypted, galKeys); timeRotateColumnsSum.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); 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.Out.Flush(); }
private static void CKKSPerformanceTest(SEALContext context) { Stopwatch timer; Utilities.PrintParameters(context); Console.WriteLine(); EncryptionParameters parms = context.FirstContextData.Parms; ulong polyModulusDegree = parms.PolyModulusDegree; Console.Write("Generating secret/public keys: "); KeyGenerator keygen = new KeyGenerator(context); Console.WriteLine("Done"); SecretKey secretKey = keygen.SecretKey; PublicKey publicKey = keygen.PublicKey; RelinKeys relinKeys = null; GaloisKeys galKeys = null; if (context.UsingKeyswitching) { /* * Generate relinearization keys. */ Console.Write("Generating relinearization keys: "); timer = Stopwatch.StartNew(); relinKeys = keygen.RelinKeys(); int micros = (int)(timer.Elapsed.TotalMilliseconds * 1000); Console.WriteLine($"Done [{micros} microseconds]"); if (!context.KeyContextData.Qualifiers.UsingBatching) { Console.WriteLine("Given encryption parameters do not support batching."); return; } /* * 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(); galKeys = keygen.GaloisKeys(); micros = (int)(timer.Elapsed.TotalMilliseconds * 1000); Console.WriteLine($"Done [{micros} microseconds]"); } Encryptor encryptor = new Encryptor(context, publicKey); Decryptor decryptor = new Decryptor(context, secretKey); Evaluator evaluator = new Evaluator(context); 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(); 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); 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] */ Ciphertext encrypted = new Ciphertext(context); timeEncryptSum.Start(); encryptor.Encrypt(plain, encrypted); timeEncryptSum.Stop(); /* * [Decryption] */ Plaintext plain2 = new Plaintext(polyModulusDegree, 0); timeDecryptSum.Start(); decryptor.Decrypt(encrypted, plain2); timeDecryptSum.Stop(); /* * [Add] */ Ciphertext encrypted1 = new Ciphertext(context); ckksEncoder.Encode(i + 1, plain); encryptor.Encrypt(plain, encrypted1); 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] */ int randomRotation = rnd.Next() % (int)ckksEncoder.SlotCount; timeRotateRandomSum.Start(); evaluator.RotateVectorInplace(encrypted, randomRotation, galKeys); timeRotateRandomSum.Stop(); /* * [Complex Conjugate] */ timeConjugateSum.Start(); evaluator.ComplexConjugateInplace(encrypted, galKeys); timeConjugateSum.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); 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.Out.Flush(); }
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. */ }
public void SeededKeyTest() { EncryptionParameters parms = new EncryptionParameters(SchemeType.BFV) { PolyModulusDegree = 8, PlainModulus = new Modulus(257), CoeffModulus = CoeffModulus.Create(8, new int[] { 40, 40 }) }; SEALContext context = new SEALContext(parms, expandModChain: false, secLevel: SecLevelType.None); KeyGenerator keygen = new KeyGenerator(context); Encryptor encryptor = new Encryptor(context, keygen.PublicKey); Decryptor decryptor = new Decryptor(context, keygen.SecretKey); Evaluator evaluator = new Evaluator(context); BatchEncoder encoder = new BatchEncoder(context); GaloisKeys galoisKeys = new GaloisKeys(); using (MemoryStream stream = new MemoryStream()) { keygen.GaloisKeys().Save(stream); stream.Seek(0, SeekOrigin.Begin); galoisKeys.Load(context, stream); } Plaintext plain = new Plaintext(); List <ulong> vec = new List <ulong> { 1, 2, 3, 4, 5, 6, 7, 8 }; encoder.Encode(vec, plain); Ciphertext encrypted = new Ciphertext(); Ciphertext encdest = new Ciphertext(); Plaintext plaindest = new Plaintext(); encryptor.Encrypt(plain, encrypted); evaluator.RotateColumns(encrypted, galoisKeys, encdest); decryptor.Decrypt(encdest, plaindest); encoder.Decode(plaindest, vec); Assert.IsTrue(AreCollectionsEqual(vec, new List <ulong> { 5, 6, 7, 8, 1, 2, 3, 4 })); evaluator.RotateRows(encdest, -1, galoisKeys, encrypted); decryptor.Decrypt(encrypted, plaindest); encoder.Decode(plaindest, vec); Assert.IsTrue(AreCollectionsEqual(vec, new List <ulong> { 8, 5, 6, 7, 4, 1, 2, 3 })); evaluator.RotateRowsInplace(encrypted, 2, galoisKeys); decryptor.Decrypt(encrypted, plaindest); encoder.Decode(plaindest, vec); Assert.IsTrue(AreCollectionsEqual(vec, new List <ulong> { 6, 7, 8, 5, 2, 3, 4, 1 })); evaluator.RotateColumnsInplace(encrypted, galoisKeys); decryptor.Decrypt(encrypted, plaindest); encoder.Decode(plaindest, vec); Assert.IsTrue(AreCollectionsEqual(vec, new List <ulong> { 2, 3, 4, 1, 6, 7, 8, 5 })); }
static async Task Main(string[] args) { Console.WriteLine("Secure Iris"); // Get Input from resource file or as args double[][] features; int numberOfFeatures = 4; int numOfRows = 0; // Option to load from args and not the whole dataset that is stored in resources if (args.Length >= numberOfFeatures) { numOfRows = args.Length / numberOfFeatures; // Features: features = new double[numOfRows][]; for (int i = 0; i < numOfRows; i++) { features[i] = new double[numberOfFeatures]; } for (int i = 0, l = args.Length; i < l; i++) { features[i / numberOfFeatures][i % numberOfFeatures] = Double.Parse(args[i]); } } else // load the whole dataset from resources { List <double[]> rows = new List <double[]>(); var bytes = Properties.Resources.iris; numOfRows = 0; features = SVCUtilities.SvcUtilities.LoadFeatures(bytes, numberOfFeatures, ref numOfRows); } Stopwatch clientStopwatch = new Stopwatch(); clientStopwatch.Start(); //svm algorithm parametrs calculated in python : training result double[][] vectors = new double[3][]; vectors[0] = new[] { 4.5, 2.3, 1.3, 0.3 }; vectors[1] = new[] { 5.1, 3.3, 1.7, 0.5 }; vectors[2] = new[] { 5.1, 2.5, 3.0, 1.1 }; double[][] coefficients = new double[1][]; coefficients[0] = new double[] { -0.07724840262003278, -0.6705185831514366, 0.7477669857714694 }; double[] intercepts = { 1.453766563649063 }; // SEAL parameters client side Console.WriteLine("SecureSVC : "); EncryptionParameters parms = new EncryptionParameters(SchemeType.CKKS); ulong polyModulusDegree = 16384; int power = 40; double scale = Math.Pow(2.0, power); 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; var context = new SEALContext(parms); // Key generation KeyGenerator keygen = new KeyGenerator(context); var publicKey = keygen.PublicKey; var secretKey = keygen.SecretKey; var relinKeys = keygen.RelinKeys(); var galoisKeys = keygen.GaloisKeys(); var encryptor = new Encryptor(context, publicKey); var decryptor = new Decryptor(context, secretKey); var encoder = new CKKSEncoder(context); clientStopwatch.Stop(); using (System.IO.StreamWriter file = new System.IO.StreamWriter( $@"{OutputDir}IrisLinearSecured_{IsParallel}_{DateTime.Now.Day}_{DateTime.Now.ToShortTimeString().ToString().Replace(":", "_")}.txt") ) { // Only CONCEPT demonstation how to parrallel all the computation on all machine cpu's // Though the parallel here is done on the client side , in "real life" this parallel mechanism // Should on the server side if (IsParallel) { int processorCount = Environment.ProcessorCount; Console.WriteLine("Number Of Logical Processors: {0}", processorCount); Svc[] machines = new Svc[processorCount]; Stopwatch[] innerProductStopwatchArr = new Stopwatch[processorCount]; Stopwatch[] negateStopwatchArr = new Stopwatch[processorCount]; Stopwatch[] degreeStopwatchArr = new Stopwatch[processorCount]; Stopwatch[] serverDecisionStopWatchArr = new Stopwatch[processorCount]; Result[] results = new Result[numOfRows]; Task[] tasks = new Task[processorCount]; for (int i = 0; i < processorCount; i++) { machines[i] = new Svc(vectors, coefficients, intercepts, "Linear", 0.25, 0.0, 3, 40, publicKey /*, secretKey*/, relinKeys, galoisKeys, 1, 4); innerProductStopwatchArr[i] = new Stopwatch(); negateStopwatchArr[i] = new Stopwatch(); degreeStopwatchArr[i] = new Stopwatch(); serverDecisionStopWatchArr[i] = new Stopwatch(); } Stopwatch totalTime = new Stopwatch(); totalTime.Start(); for (int i = 0; i < numOfRows;) { for (int j = 0; j < processorCount && i < numOfRows; j++) { var secureSvc = machines[i % processorCount]; var feature = features[i]; //Console.WriteLine($"\n\n $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$"); List <object> l = new List <object>(); l.Add(secureSvc); //0 l.Add(feature); //1 l.Add(i); //2 l.Add(encoder); //3 l.Add(encryptor); //4 l.Add(decryptor); //5 l.Add(innerProductStopwatchArr[i % processorCount]); l.Add(degreeStopwatchArr[i % processorCount]); l.Add(negateStopwatchArr[i % processorCount]); l.Add(serverDecisionStopWatchArr[i % processorCount]); l.Add(results); tasks[j] = new TaskFactory().StartNew(new Action <object>((test) => { List <object> l2 = (List <object>)test; SinglePredict((Svc)l2[0], (double[])l2[1], (int)l2[2], (CKKSEncoder)l2[3], (Encryptor)l2[4], (Decryptor)l2[5], (Stopwatch)l2[6], (Stopwatch)l2[7], (Stopwatch)l2[8], (Stopwatch)l2[9], scale, (Result[])l2[10]); }), l); i++; } await Task.WhenAll(tasks); } totalTime.Stop(); for (int i = 0; i < numOfRows; i++) { var result = results[i]; file.WriteLine($"{i} , {result.Estimation} , {result.TotalValue} "); } double innerProductTime = 0; double degreeTime = 0; double negateTime = 0; double serverTime = 0; for (int i = 0; i < processorCount; i++) { innerProductTime = innerProductStopwatchArr[i].ElapsedMilliseconds; degreeTime = degreeStopwatchArr[i].ElapsedMilliseconds; negateTime = negateStopwatchArr[i].ElapsedMilliseconds; serverTime = serverDecisionStopWatchArr[i].ElapsedMilliseconds; } file.WriteLine($" Client time : {clientStopwatch.ElapsedMilliseconds} ms "); file.WriteLine($" Total time for {numOfRows} samples : {totalTime.ElapsedMilliseconds} ms "); file.WriteLine($" Avg time : {totalTime.ElapsedMilliseconds * 1000 / numOfRows} microSec "); file.WriteLine($" Inner Product time for {numOfRows} samples : {innerProductTime} ms "); file.WriteLine($" Inner Product Avg time : {innerProductTime * 1000 / numOfRows} microSec "); file.WriteLine($" Degree time for {numOfRows} samples : {degreeTime} ms "); file.WriteLine($" Degree Avg time : {degreeTime * 1000 / numOfRows} microSec "); file.WriteLine($" Negate time for {numOfRows} samples : {negateTime} ms "); file.WriteLine($" Negate Avg time : {negateTime * 1000 / numOfRows} microSec "); file.WriteLine($" Decision time for {numOfRows} samples : {serverTime} ms "); file.WriteLine($" Decision Avg time : {serverTime * 1000 / numOfRows} microSec "); } else { //Initiate Stopwatch for performance measure Stopwatch innerProductStopwatch = new Stopwatch(); Stopwatch negateStopwatch = new Stopwatch(); Stopwatch degreeStopwatch = new Stopwatch(); Stopwatch serverDecisionStopWatch = new Stopwatch(); int featureSizeWithSpace = numberOfFeatures; int batchSize = 200; if (batchSize > 1) { featureSizeWithSpace = numberOfFeatures * 2; } Svc clf = new Svc(vectors, coefficients, intercepts, "Linear", 0.25, 0.0, 3, 40, publicKey /*, secretKey*/, relinKeys, galoisKeys, batchSize, featureSizeWithSpace); Stopwatch totalTime = new Stopwatch(); totalTime.Start(); int start = 0; //double[] batchFeatures = new double[batchSize * featureSizeWithSpace]; for (int i = 0; i < numOfRows;) { start = i; double finalResult = -10000; double[][] batchRows = new double[batchSize][]; for (int j = 0; j < batchSize && i < numOfRows; j++) { batchRows[j] = features[i]; i++; } double[] batchFeatures = GetBatchFeatures(batchRows, batchSize, numberOfFeatures, featureSizeWithSpace); var plaintexts = new Plaintext(); var featuresCiphertexts = new Ciphertext(); encoder.Encode(batchFeatures, scale, plaintexts); encryptor.Encrypt(plaintexts, featuresCiphertexts); //Server side start var cypherResult = clf.Predict(featuresCiphertexts, true, true, innerProductStopwatch, degreeStopwatch, negateStopwatch, serverDecisionStopWatch); // Server side end Plaintext plainResult = new Plaintext(); decryptor.Decrypt(cypherResult, plainResult); List <double> result = new List <double>(); encoder.Decode(plainResult, result); for (int j = 0; j < batchSize && start < numOfRows; j++) { finalResult = result[j * featureSizeWithSpace]; int estimation = finalResult > 0 ? 0 : 1; Console.WriteLine($"\n ************************************************"); Console.WriteLine($"SVC estimation{i} is : {estimation} , result : {finalResult}"); file.WriteLine($"{start} , {estimation} , {finalResult} "); Console.WriteLine($"************************************************ \n"); start++; } } totalTime.Stop(); file.WriteLine($" Client time : {clientStopwatch.ElapsedMilliseconds} ms "); file.WriteLine($" Total time for {numOfRows} samples : {totalTime.ElapsedMilliseconds} ms "); file.WriteLine($" Avg time : {totalTime.ElapsedMilliseconds * 1000 / numOfRows} microSec "); file.WriteLine($" Inner Product time for {numOfRows} samples : {innerProductStopwatch.ElapsedMilliseconds} ms "); file.WriteLine($" Inner Product Avg time : {innerProductStopwatch.ElapsedMilliseconds * 1000 / numOfRows} microSec "); file.WriteLine($" Degree time for {numOfRows} samples : {degreeStopwatch.ElapsedMilliseconds} ms "); file.WriteLine($" Degree Avg time : {degreeStopwatch.ElapsedMilliseconds * 1000 / numOfRows} microSec "); file.WriteLine($" Negate time for {numOfRows} samples : {negateStopwatch.ElapsedMilliseconds} ms "); file.WriteLine($" Negate Avg time : {negateStopwatch.ElapsedMilliseconds * 1000 / numOfRows} microSec "); file.WriteLine($" Decision time for {numOfRows} samples : {serverDecisionStopWatch.ElapsedMilliseconds} ms "); file.WriteLine($" Decision Avg time : {serverDecisionStopWatch.ElapsedMilliseconds * 1000 / numOfRows} microSec "); } } }
public void ScaleTest() { List <SmallModulus> coeffModulus = new List <SmallModulus>() { DefaultParams.SmallMods40Bit(0), DefaultParams.SmallMods40Bit(1), DefaultParams.SmallMods40Bit(2), DefaultParams.SmallMods40Bit(3) }; EncryptionParameters parms = new EncryptionParameters(SchemeType.CKKS) { CoeffModulus = coeffModulus, PolyModulusDegree = 8 }; SEALContext context = SEALContext.Create(parms); KeyGenerator keygen = new KeyGenerator(context); GaloisKeys galoisKeys = keygen.GaloisKeys(decompositionBitCount: 4); Encryptor encryptor = new Encryptor(context, keygen.PublicKey); Evaluator evaluator = new Evaluator(context); CKKSEncoder encoder = new CKKSEncoder(context); MemoryPoolHandle pool = MemoryManager.GetPool(MMProfOpt.ForceNew); Assert.AreEqual(0ul, pool.AllocByteCount); Ciphertext encrypted = new Ciphertext(pool); Plaintext plain = new Plaintext(); MemoryPoolHandle cipherPool = encrypted.Pool; Assert.IsNotNull(cipherPool); Assert.AreEqual(0ul, cipherPool.AllocByteCount); List <Complex> input = new List <Complex>() { new Complex(1, 1), new Complex(2, 2), new Complex(3, 3), new Complex(4, 4) }; double delta = Math.Pow(2, 70); encoder.Encode(input, parms.ParmsId, delta, plain); encryptor.Encrypt(plain, encrypted); Assert.AreEqual(delta, encrypted.Scale, delta: Math.Pow(2, 60)); Ciphertext encrypted2 = new Ciphertext(); encrypted2.Set(encrypted); Assert.AreEqual(delta, encrypted2.Scale, delta: Math.Pow(2, 60)); evaluator.RescaleToNextInplace(encrypted); Assert.AreEqual(Math.Pow(2, 30), encrypted.Scale, delta: 10000); Assert.AreNotEqual(0ul, cipherPool.AllocByteCount); double newScale = Math.Pow(2, 10); encrypted.Scale = newScale; Assert.AreEqual(newScale, encrypted.Scale, delta: 100); }
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(); var galoisKeys = keygen.GaloisKeys(); 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(); var featuresCiphertexts = new Ciphertext(); //Encode and encrypt features encoder.Encode(features, scale, plaintexts); encryptor.Encrypt(plaintexts, featuresCiphertexts); SvcUtilities.PrintScale(plaintexts, "featurePlaintext"); SvcUtilities.PrintScale(featuresCiphertexts, "featurefEncrypted"); // Handle SV var numOfrows = _vectors.Length; var numOfcolumns = _vectors[0].Length; int numOfRotations = (int)Math.Ceiling(Math.Log2(numOfcolumns)); //Console.WriteLine("********************************** : "+ numOfRotations); var svPlaintexts = new Plaintext[numOfrows]; //Encode SV for (int i = 0; i < numOfrows; i++) { //for (int j = 0; j < numOfcolumns; j++) //{ svPlaintexts[i] = new Plaintext(); encoder.Encode(_vectors[i], scale, svPlaintexts[i]); SvcUtilities.PrintScale(svPlaintexts[i], "supportVectorsPlaintext" + i); //} } // 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>(); evaluator.MultiplyPlain(featuresCiphertexts, svPlaintexts[i], sums[i]); for (int k = 1; k <= numOfRotations + 1 /*(int)encoder.SlotCount*/ / 2; k <<= 1) { Ciphertext tempCt = new Ciphertext(); evaluator.RotateVector(sums[i], k, galoisKeys, tempCt); evaluator.AddInplace(sums[i], tempCt); } kernels[i] = sums[i]; evaluator.NegateInplace(kernels[i]); if (useRelinearizeInplace) { evaluator.RelinearizeInplace(kernels[i], relinKeys); } if (useReScale) { evaluator.RescaleToNextInplace(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}IrisLinearBatch_IrisSecureSVC_total_{power}_{useRelinearizeInplace}_{useReScale}.txt", !_firstTime) ) { _firstTime = false; file.WriteLine($"{result[0]}"); } if (result[0] > 0) { return(0); } return(1); }
/* * Both the BFV scheme (with BatchEncoder) as well as the CKKS scheme support native * vectorized computations on encrypted numbers. In addition to computing slot-wise, * it is possible to rotate the encrypted vectors cyclically. */ private static void ExampleRotationBFV() { Utilities.PrintExampleBanner("Example: Rotation / Rotation in BFV"); EncryptionParameters parms = new EncryptionParameters(SchemeType.BFV); ulong polyModulusDegree = 8192; parms.PolyModulusDegree = polyModulusDegree; parms.CoeffModulus = CoeffModulus.BFVDefault(polyModulusDegree); parms.PlainModulus = PlainModulus.Batching(polyModulusDegree, 20); SEALContext context = new SEALContext(parms); Utilities.PrintParameters(context); 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); BatchEncoder batchEncoder = new BatchEncoder(context); ulong slotCount = batchEncoder.SlotCount; ulong rowSize = slotCount / 2; Console.WriteLine($"Plaintext matrix row size: {rowSize}"); 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); Console.WriteLine(); /* * First we use BatchEncoder to encode the matrix into a plaintext. We encrypt * the plaintext as usual. */ Utilities.PrintLine(); Plaintext plainMatrix = new Plaintext(); Console.WriteLine("Encode and encrypt."); batchEncoder.Encode(podMatrix, plainMatrix); Ciphertext encryptedMatrix = new Ciphertext(); encryptor.Encrypt(plainMatrix, encryptedMatrix); Console.WriteLine(" + Noise budget in fresh encryption: {0} bits", decryptor.InvariantNoiseBudget(encryptedMatrix)); Console.WriteLine(); /* * Rotations require yet another type of special key called `Galois keys'. These * are easily obtained from the KeyGenerator. */ GaloisKeys galKeys = keygen.GaloisKeys(); /* * Now rotate both matrix rows 3 steps to the left, decrypt, decode, and print. */ Utilities.PrintLine(); Console.WriteLine("Rotate rows 3 steps left."); evaluator.RotateRowsInplace(encryptedMatrix, 3, galKeys); Plaintext plainResult = new Plaintext(); Console.WriteLine(" + Noise budget after rotation: {0} bits", decryptor.InvariantNoiseBudget(encryptedMatrix)); Console.WriteLine(" + Decrypt and decode ...... Correct."); decryptor.Decrypt(encryptedMatrix, plainResult); List <ulong> podResult = new List <ulong>(); batchEncoder.Decode(plainResult, podResult); Utilities.PrintMatrix(podResult, (int)rowSize); /* * We can also rotate the columns, i.e., swap the rows. */ Utilities.PrintLine(); Console.WriteLine("Rotate columns."); evaluator.RotateColumnsInplace(encryptedMatrix, galKeys); Console.WriteLine(" + Noise budget after rotation: {0} bits", decryptor.InvariantNoiseBudget(encryptedMatrix)); Console.WriteLine(" + Decrypt and decode ...... Correct."); decryptor.Decrypt(encryptedMatrix, plainResult); batchEncoder.Decode(plainResult, podResult); Utilities.PrintMatrix(podResult, (int)rowSize); /* * Finally, we rotate the rows 4 steps to the right, decrypt, decode, and print. */ Utilities.PrintLine(); Console.WriteLine("Rotate rows 4 steps right."); evaluator.RotateRowsInplace(encryptedMatrix, -4, galKeys); Console.WriteLine(" + Noise budget after rotation: {0} bits", decryptor.InvariantNoiseBudget(encryptedMatrix)); Console.WriteLine(" + Decrypt and decode ...... Correct."); decryptor.Decrypt(encryptedMatrix, plainResult); batchEncoder.Decode(plainResult, podResult); Utilities.PrintMatrix(podResult, (int)rowSize); /* * Note that rotations do not consume any noise budget. However, this is only * the case when the special prime is at least as large as the other primes. The * same holds for relinearization. Microsoft SEAL does not require that the * special prime is of any particular size, so ensuring this is the case is left * for the user to do. */ }