public void EncodeLongTest() { EncryptionParameters parms = new EncryptionParameters(SchemeType.BFV); parms.PolyModulusDegree = 64; parms.CoeffModulus = CoeffModulus.Create(64, new int[] { 60 }); parms.PlainModulus = new SmallModulus(257); SEALContext context = new SEALContext(parms, expandModChain: false, secLevel: SecLevelType.None); BatchEncoder encoder = new BatchEncoder(context); Assert.AreEqual(64ul, encoder.SlotCount); List <long> plainList = new List <long>(); for (ulong i = 0; i < encoder.SlotCount; i++) { plainList.Add((long)i); } Plaintext plain = new Plaintext(); encoder.Encode(plainList, plain); List <long> plainList2 = new List <long>(); encoder.Decode(plain, plainList2); for (ulong i = 0; i < encoder.SlotCount; i++) { Assert.AreEqual(plainList[checked ((int)i)], plainList2[checked ((int)i)]); } for (ulong i = 0; i < encoder.SlotCount; i++) { plainList[checked ((int)i)] = 5; } encoder.Encode(plainList, plain); Assert.AreEqual("5", plain.ToString()); encoder.Decode(plain, plainList2); for (ulong i = 0; i < encoder.SlotCount; i++) { Assert.AreEqual(plainList[checked ((int)i)], plainList2[checked ((int)i)]); } List <long> shortList = new List <long>(); for (int i = 0; i < 20; i++) { shortList.Add((long)i); } encoder.Encode(shortList, plain); List <long> shortList2 = new List <long>(); encoder.Decode(plain, shortList2); Assert.AreEqual(20, shortList.Count); Assert.AreEqual(64, shortList2.Count); for (int i = 0; i < 20; i++) { Assert.AreEqual(shortList[i], shortList2[i]); } for (ulong i = 20; i < encoder.SlotCount; i++) { Assert.AreEqual(0L, shortList2[checked ((int)i)]); } }
/* * 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"); using EncryptionParameters parms = new EncryptionParameters(SchemeType.BFV); ulong polyModulusDegree = 8192; parms.PolyModulusDegree = polyModulusDegree; parms.CoeffModulus = CoeffModulus.BFVDefault(polyModulusDegree); parms.PlainModulus = PlainModulus.Batching(polyModulusDegree, 20); using SEALContext context = new SEALContext(parms); Utilities.PrintParameters(context); Console.WriteLine(); using KeyGenerator keygen = new KeyGenerator(context); using SecretKey secretKey = keygen.SecretKey; keygen.CreatePublicKey(out PublicKey publicKey); keygen.CreateRelinKeys(out RelinKeys relinKeys); using Encryptor encryptor = new Encryptor(context, publicKey); using Evaluator evaluator = new Evaluator(context); using Decryptor decryptor = new Decryptor(context, secretKey); using 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(); using Plaintext plainMatrix = new Plaintext(); Console.WriteLine("Encode and encrypt."); batchEncoder.Encode(podMatrix, plainMatrix); using 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. */ keygen.CreateGaloisKeys(out GaloisKeys 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, galoisKeys); using 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, galoisKeys); 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, galoisKeys); 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. */ }
/* * In `1_BFV_Basics.cs' we showed how to perform a very simple computation using the * BFV scheme. The computation was performed modulo the PlainModulus parameter, and * utilized only one coefficient from a BFV plaintext polynomial. This approach has * two notable problems: * * (1) Practical applications typically use integer or real number arithmetic, * not modular arithmetic; * (2) We used only one coefficient of the plaintext polynomial. This is really * wasteful, as the plaintext polynomial is large and will in any case be * encrypted in its entirety. * * For (1), one may ask why not just increase the PlainModulus parameter until no * overflow occurs, and the computations behave as in integer arithmetic. The problem * is that increasing PlainModulus increases noise budget consumption, and decreases * the initial noise budget too. * * In these examples we will discuss other ways of laying out data into plaintext * elements (encoding) that allow more computations without data type overflow, and * can allow the full plaintext polynomial to be utilized. */ private static void ExampleBatchEncoder() { Utilities.PrintExampleBanner("Example: Encoders / Batch Encoder"); /* * [BatchEncoder] (For BFV or BGV scheme) * * 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 without batching. * * In a later example, we will demonstrate how to use the BGV scheme. Batching * works similarly for the BGV scheme to this example for the BFV scheme. For * example, simply changing `SchemeType.BFV` into `SchemeType.BGV` can make * this example work for the BGV scheme. */ using 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); using 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. */ using var qualifiers = context.FirstContextData.Qualifiers; Console.WriteLine($"Batching enabled: {qualifiers.UsingBatching}"); using KeyGenerator keygen = new KeyGenerator(context); using SecretKey secretKey = keygen.SecretKey; keygen.CreatePublicKey(out PublicKey publicKey); keygen.CreateRelinKeys(out RelinKeys relinKeys); using Encryptor encryptor = new Encryptor(context, publicKey); using Evaluator evaluator = new Evaluator(context); using Decryptor decryptor = new Decryptor(context, secretKey); /* * Batching is done through an instance of the BatchEncoder class. */ using 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. */ using 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. */ using 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 & 1) + 1; } using 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. */ using 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. */ }
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); keygen.CreatePublicKey(out PublicKey publicKey); Encryptor encryptor = new Encryptor(context, 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.CreateGaloisKeys().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 })); } { EncryptionParameters parms = new EncryptionParameters(SchemeType.BGV) { 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); keygen.CreatePublicKey(out PublicKey publicKey); Encryptor encryptor = new Encryptor(context, 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.CreateGaloisKeys().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 })); } }
private static void BFVPerformanceTest(SEALContext context) { Stopwatch timer; Utilities.PrintParameters(context); Console.WriteLine(); 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; using PublicKey publicKey = keygen.PublicKey; Func <RelinKeys> GetRelinKeys = () => { if (context.UsingKeyswitching) { /* * Generate relinearization keys. */ Console.Write("Generating relinearization keys: "); timer = Stopwatch.StartNew(); RelinKeys result = keygen.RelinKeysLocal(); int micros = (int)(timer.Elapsed.TotalMilliseconds * 1000); Console.WriteLine($"Done [{micros} microseconds]"); return(result); } 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(); GaloisKeys result = keygen.GaloisKeysLocal(); int micros = (int)(timer.Elapsed.TotalMilliseconds * 1000); Console.WriteLine($"Done [{micros} microseconds]"); return(result); } 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); using 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. */ 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 Ciphertext encrypted1 = new Ciphertext(context); encryptor.Encrypt(encoder.Encode(i), encrypted1); using 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(); }
public BatchEncoder CreateBatchEncoder() { var batchEncoder = new BatchEncoder(SealContext); return(batchEncoder); }
/// <summary> /// Convert a Matrix to a twisted Ciphertext. /// Rows in the matrix are laid next to each other in a Plaintext and then encrypted. /// The second batching row is duplicate of the first one but rotated by eltSeparation /// </summary> /// <param name="matrix">Matrix to convert to Ciphertext</param> /// <param name="encryptor">Encryptor used to encrypt Plaintext data</param> /// <param name="encoder">BatchEncoder used to encode the matrix data</param> /// <returns>Encrypted matrix</returns> public static Ciphertext MatrixToTwistedCiphertext(int[,] matrix, Encryptor encryptor, BatchEncoder encoder) { int batchRowSize = (int)encoder.SlotCount / 2; int rows = matrix.GetLength(dimension: 0); int cols = matrix.GetLength(dimension: 1); int paddedColLength = FindNextPowerOfTwo((ulong)rows); int eltSeparation = batchRowSize / paddedColLength; long[] batchArray = new long[encoder.SlotCount]; for (int r = 0; r < rows; r++) { for (int c = 0; c < cols; c++) { batchArray[r * eltSeparation + c] = (long)matrix[r, c]; batchArray[batchRowSize + ((batchRowSize + (r - 1) * eltSeparation) % batchRowSize) + c] = (long)matrix[r, c]; } } Plaintext plain = new Plaintext(); encoder.Encode(batchArray, plain); Ciphertext result = new Ciphertext(); encryptor.Encrypt(plain, result); return(result); }
public void EncodeLongTest() { EncryptionParameters parms = new EncryptionParameters(SchemeType.BFV); parms.PolyModulusDegree = 64; List <SmallModulus> coeffModulus = new List <SmallModulus>(); coeffModulus.Add(DefaultParams.SmallMods60Bit(0)); parms.CoeffModulus = coeffModulus; parms.PlainModulus = new SmallModulus(257); SEALContext context = SEALContext.Create(parms); BatchEncoder encoder = new BatchEncoder(context); Assert.AreEqual(64ul, encoder.SlotCount); List <long> plainList = new List <long>(); for (ulong i = 0; i < encoder.SlotCount; i++) { plainList.Add((long)i); } Plaintext plain = new Plaintext(); encoder.Encode(plainList, plain); List <long> plainList2 = new List <long>(); encoder.Decode(plain, plainList2); for (ulong i = 0; i < encoder.SlotCount; i++) { Assert.AreEqual(plainList[(int)i], plainList2[(int)i]); } for (ulong i = 0; i < encoder.SlotCount; i++) { plainList[(int)i] = 5; } encoder.Encode(plainList, plain); Assert.AreEqual("5", plain.ToString()); encoder.Decode(plain, plainList2); for (ulong i = 0; i < encoder.SlotCount; i++) { Assert.AreEqual(plainList[(int)i], plainList2[(int)i]); } List <long> shortList = new List <long>(); for (int i = 0; i < 20; i++) { shortList.Add((long)i); } encoder.Encode(shortList, plain); List <long> shortList2 = new List <long>(); encoder.Decode(plain, shortList2); Assert.AreEqual(20, shortList.Count); Assert.AreEqual(64, shortList2.Count); for (int i = 0; i < 20; i++) { Assert.AreEqual(shortList[i], shortList2[i]); } for (ulong i = 20; i < encoder.SlotCount; i++) { Assert.AreEqual(0L, shortList2[(int)i]); } }
/// <summary> /// Set the indicated Matrix column as the coefficients of a Plaintext (in inverse order) /// and encrypt it. /// </summary> /// <param name="matrix">Matrix to get a column from</param> /// <param name="col">Column to encrypt</param> /// <param name="encryptor">Encryptor used to encrypt column data</param> /// <param name="encoder">BatchEncoder used to encode the matrix data</param> /// <returns>Encrypted inverted matrix column</returns> public static Ciphertext InvertedColumnToCiphertext(int[,] matrix, int col, Encryptor encryptor, BatchEncoder encoder) { int batchRowSize = (int)encoder.SlotCount / 2; int rows = matrix.GetLength(dimension: 0); int paddedLength = FindNextPowerOfTwo((ulong)rows); int eltSeparation = batchRowSize / paddedLength; long[] colToEncrypt = new long[batchRowSize]; for (int r = 0; r < rows; r++) { colToEncrypt[eltSeparation * r] = matrix[r, col]; } Plaintext plain = new Plaintext(); encoder.Encode(colToEncrypt, plain); Ciphertext result = new Ciphertext(); encryptor.Encrypt(plain, result); return(result); }
/// <summary> /// Set the indicated Matrix rows as the coefficients of Plaintexts and encrypt them. /// Two rows will always be encrypted into a single ciphertext into the two batching "rows". /// </summary> /// <param name="matrix">Matrix to get a row from</param> /// <param name="repl">How many times to replicate the row values</param> /// <param name="encryptor">Encryptor used to encrypt row data</param> /// <param name="encoder">BatchEncoder used to encode the matrix data</param> /// <returns>Encrypted matrix rows</returns> public static List <Ciphertext> RowsToCiphertexts(int[,] matrix, int repl, Encryptor encryptor, BatchEncoder encoder) { int batchRowCount = 2; int batchRowSize = (int)encoder.SlotCount / 2; int cols = matrix.GetLength(dimension: 1); int rows = matrix.GetLength(dimension: 0); int paddedLength = FindNextPowerOfTwo((ulong)cols); int eltSeparation = batchRowSize / paddedLength; if (repl < 0 || repl > eltSeparation) { throw new ArgumentException("repl out of bounds"); } List <Ciphertext> result = new List <Ciphertext>(); int r = 0; while (r < rows) { long[] batchArray = new long[encoder.SlotCount]; for (int batchRowIndex = 0; batchRowIndex < batchRowCount && r < rows; batchRowIndex++, r++) { for (int c = 0; c < cols; c++) { for (int j = 0; j < repl; j++) { batchArray[batchRowIndex * batchRowSize + eltSeparation * c + j] = matrix[r, c]; } } } Plaintext plain = new Plaintext(); encoder.Encode(batchArray, plain); Ciphertext newCipher = new Ciphertext(); encryptor.Encrypt(plain, newCipher); result.Add(newCipher); } return(result); }
/// <summary> /// Set the indicated Matrix row as the coefficients of a Plaintext and encrypt it. /// </summary> /// <param name="matrix">Matrix to get a row from</param> /// <param name="row">Row to encrypt</param> /// <param name="repl">How many times to replicate the row values</param> /// <param name="encryptor">Encryptor used to encrypt row data</param> /// <param name="encoder">BatchEncoder used to encode the matrix data</param> /// <returns>Encrypted matrix row</returns> public static Ciphertext RowToCiphertext(int[,] matrix, int row, int repl, Encryptor encryptor, BatchEncoder encoder) { int batchRowSize = (int)encoder.SlotCount / 2; int cols = matrix.GetLength(dimension: 1); int paddedLength = FindNextPowerOfTwo((ulong)cols); int eltSeparation = batchRowSize / paddedLength; if (repl < 0 || repl > eltSeparation) { throw new ArgumentException("repl out of bounds"); } long[] rowToEncrypt = new long[batchRowSize]; for (int c = 0; c < cols; c++) { for (int j = 0; j < repl; j++) { rowToEncrypt[eltSeparation * c + j] = matrix[row, c]; } } Plaintext plain = new Plaintext(); encoder.Encode(rowToEncrypt, plain); Ciphertext result = new Ciphertext(); encryptor.Encrypt(plain, result); return(result); }
private static void ExampleBGVBasics() { Utilities.PrintExampleBanner("Example: BGV Basics"); /* * As an example, we evaluate the degree 8 polynomial * * x^8 * * over an encrypted x over integers 1, 2, 3, 4. The coefficients of the * polynomial can be considered as plaintext inputs, as we will see below. The * computation is done modulo the plain_modulus 1032193. * * Computing over encrypted data in the BGV scheme is similar to that in BFV. * The purpose of this example is mainly to explain the differences between BFV * and BGV in terms of ciphertext coefficient modulus selection and noise control. * * Most of the following code are repeated from "BFV basics" and "encoders" examples. */ /* * Note that scheme_type is now "bgv". */ using EncryptionParameters parms = new EncryptionParameters(SchemeType.BGV); ulong polyModulusDegree = 8192; parms.PolyModulusDegree = polyModulusDegree; /* * We can certainly use BFVDefault coeff_modulus. In later parts of this example, * we will demonstrate how to choose coeff_modulus that is more useful in BGV. */ parms.CoeffModulus = CoeffModulus.BFVDefault(polyModulusDegree); parms.PlainModulus = PlainModulus.Batching(polyModulusDegree, 20); using SEALContext context = new SEALContext(parms); /* * Print the parameters that we have chosen. */ Utilities.PrintLine(); Console.WriteLine("Set encryption parameters and print"); Utilities.PrintParameters(context); using KeyGenerator keygen = new KeyGenerator(context); using SecretKey secretKey = keygen.SecretKey; keygen.CreatePublicKey(out PublicKey publicKey); keygen.CreateRelinKeys(out RelinKeys relinKeys); using Encryptor encryptor = new Encryptor(context, publicKey); using Evaluator evaluator = new Evaluator(context); using Decryptor decryptor = new Decryptor(context, secretKey); /* * Batching and slot operations are the same in BFV and BGV. */ using BatchEncoder batchEncoder = new BatchEncoder(context); ulong slotCount = batchEncoder.SlotCount; ulong rowSize = slotCount / 2; Console.WriteLine($"Plaintext matrix row size: {rowSize}"); /* * Here we create the following matrix: * [ 1, 2, 3, 4, 0, 0, ..., 0 ] * [ 0, 0, 0, 0, 0, 0, ..., 0 ] */ ulong[] podMatrix = new ulong[slotCount]; podMatrix[0] = 1; podMatrix[1] = 2; podMatrix[2] = 3; podMatrix[3] = 4; Console.WriteLine("Input plaintext matrix:"); Utilities.PrintMatrix(podMatrix, (int)rowSize); using Plaintext xPlain = new Plaintext(); Console.WriteLine("Encode plaintext matrix to xPlain:"); batchEncoder.Encode(podMatrix, xPlain); /* * Next we encrypt the encoded plaintext. */ using Ciphertext xEncrypted = new Ciphertext(); Utilities.PrintLine(); Console.WriteLine("Encrypt xPlain to xEncrypted."); encryptor.Encrypt(xPlain, xEncrypted); Console.WriteLine(" + noise budget in freshly encrypted x: {0} bits", decryptor.InvariantNoiseBudget(xEncrypted)); Console.WriteLine(); /* * Then we compute x^2. */ Utilities.PrintLine(); Console.WriteLine("Compute and relinearize xSquared (x^2),"); using 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); Console.WriteLine(" + noise budget in xSquared: {0} bits", decryptor.InvariantNoiseBudget(xSquared)); using Plaintext decryptedResult = new Plaintext(); decryptor.Decrypt(xSquared, decryptedResult); List <ulong> podResult = new List <ulong>(); batchEncoder.Decode(decryptedResult, podResult); Console.WriteLine(" + result plaintext matrix ...... Correct."); Utilities.PrintMatrix(podResult, (int)rowSize); /* * Next we compute x^4. */ Utilities.PrintLine(); Console.WriteLine("Compute and relinearize x4th (x^4),"); using Ciphertext x4th = new Ciphertext(); evaluator.Square(xSquared, x4th); Console.WriteLine($" + size of x4th: {x4th.Size}"); evaluator.RelinearizeInplace(x4th, relinKeys); Console.WriteLine(" + size of x4th (after relinearization): {0}", x4th.Size); Console.WriteLine(" + noise budget in x4th: {0} bits", decryptor.InvariantNoiseBudget(x4th)); decryptor.Decrypt(x4th, decryptedResult); batchEncoder.Decode(decryptedResult, podResult); Console.WriteLine(" + result plaintext matrix ...... Correct."); Utilities.PrintMatrix(podResult, (int)rowSize); /* * Last we compute x^8. We run out of noise budget. */ Utilities.PrintLine(); Console.WriteLine("Compute and relinearize x8th (x^8),"); using Ciphertext x8th = new Ciphertext(); evaluator.Square(x4th, x8th); Console.WriteLine($" + size of x8th: {x8th.Size}"); evaluator.RelinearizeInplace(x8th, relinKeys); Console.WriteLine(" + size of x8th (after relinearization): {0}", x8th.Size); Console.WriteLine(" + noise budget in x8th: {0} bits", decryptor.InvariantNoiseBudget(x8th)); Console.WriteLine("NOTE: Notice the increase in remaining noise budget."); Console.WriteLine(); Console.WriteLine("~~~~~~ Use modulus switching to calculate x^8. ~~~~~~"); /* * Noise budget has reached 0, which means that decryption cannot be expected * to give the correct result. BGV requires modulus switching to reduce noise * growth. In the following demonstration, we will insert a modulus switching * after each relinearization. */ Utilities.PrintLine(); Console.WriteLine("Encrypt xPlain to xEncrypted."); encryptor.Encrypt(xPlain, xEncrypted); Console.WriteLine(" + noise budget in freshly encrypted x: {0} bits", decryptor.InvariantNoiseBudget(xEncrypted)); Console.WriteLine(); /* * Then we compute x^2. */ Utilities.PrintLine(); Console.WriteLine("Compute and relinearize xSquared (x^2),"); Console.WriteLine(" + noise budget in xSquared (previously): {0} bits", decryptor.InvariantNoiseBudget(xSquared)); evaluator.Square(xEncrypted, xSquared); evaluator.RelinearizeInplace(xSquared, relinKeys); evaluator.ModSwitchToNextInplace(xSquared); Console.WriteLine(" + noise budget in xSquared (with modulus switching): {0} bits", decryptor.InvariantNoiseBudget(xSquared)); decryptor.Decrypt(xSquared, decryptedResult); batchEncoder.Decode(decryptedResult, podResult); Console.WriteLine(" + result plaintext matrix ...... Correct."); Utilities.PrintMatrix(podResult, (int)rowSize); /* * Next we compute x^4. */ Utilities.PrintLine(); Console.WriteLine("Compute and relinearize x4th (x^4),"); Console.WriteLine(" + noise budget in x4th (previously): {0} bits", decryptor.InvariantNoiseBudget(x4th)); evaluator.Square(xSquared, x4th); evaluator.RelinearizeInplace(x4th, relinKeys); evaluator.ModSwitchToNextInplace(x4th); Console.WriteLine(" + noise budget in x4th (with modulus switching): {0} bits", decryptor.InvariantNoiseBudget(x4th)); decryptor.Decrypt(x4th, decryptedResult); batchEncoder.Decode(decryptedResult, podResult); Console.WriteLine(" + result plaintext matrix ...... Correct."); Utilities.PrintMatrix(podResult, (int)rowSize); /* * Last we compute x^8. We still have budget left. */ Utilities.PrintLine(); Console.WriteLine("Compute and relinearize x8th (x^8),"); Console.WriteLine(" + noise budget in x8th (previously): {0} bits", decryptor.InvariantNoiseBudget(x8th)); evaluator.Square(x4th, x8th); evaluator.RelinearizeInplace(x8th, relinKeys); evaluator.ModSwitchToNextInplace(x8th); Console.WriteLine(" + noise budget in x8th (with modulus switching): {0} bits", decryptor.InvariantNoiseBudget(x8th)); decryptor.Decrypt(x8th, decryptedResult); batchEncoder.Decode(decryptedResult, podResult); Console.WriteLine(" + result plaintext matrix ...... Correct."); Utilities.PrintMatrix(podResult, (int)rowSize); /* * Although with modulus switching x_squared has less noise budget than before, * noise budget is consumed at a slower rate. To achieve the optimal consumption * rate of noise budget in an application, one needs to carefully choose the * location to insert modulus switching and manually choose coeff_modulus. */ }
private void btnCreate_Click(object sender, EventArgs e) { if (String.IsNullOrWhiteSpace(txtFilePath.Text)) { return; } lvBatchEncode.Items.Clear(); Running = true; /* * try * { * tabMain.AllowSelect = false; * this.btnCreate.Enabled = false; * AutoResetEvent finish = new AutoResetEvent(false); * Thread waitTime = new Thread(() => * { * DateTime dtStart = DateTime.Now; * this.Invoke(new MethodInvoker(() => * { * this.toolStripStatusLabel2.Text = "正在读取文件和生成二维码"; * })); * finish.WaitOne(); * DateTime dtFinish = DateTime.Now; * this.Invoke(new MethodInvoker(() => * { * this.toolStripStatusLabel2.Text = "生成完成,所用时间:" + ((int)(dtFinish - dtStart).TotalSeconds).ToString("d") + "秒"; + this.btnCreate.Enabled = true; + tabMain.AllowSelect = true; + Running = false; + })); + }); + waitTime.IsBackground = true; + waitTime.Name = "计时线程"; + waitTime.Start(); + + string filePath = txtFilePath.Text; + listFileReaded.Items.Clear(); + BatchEncode be = new BatchEncode(filePath, this); + Thread createThread = new Thread(() => + { + be.Start(); + finish.Set(); + }); + createThread.IsBackground = true; + createThread.Name = "生成主线程"; + createThread.Start(); + } + catch (Exception ex) + { + MessageBox.Show(ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); + } */ /* * string filePath = txtFilePath.Text; * string outDir = Path.GetDirectoryName(filePath) + "\\CreatedQRcode"; * toolStripStatusLabel2.Text = "正在读取文件和生成二维码"; * tabMain.AllowSelect = false; * btnCreate.Enabled = false; * * Task.Factory.StartNew(() => * { * TimeSpan timeSpan = BatchEncode(filePath, outDir); * this.Invoke(new MethodInvoker(() => * { * this.toolStripStatusLabel2.Text = string.Format("生成完成,所用时间:{0}秒", * timeSpan.TotalSeconds.ToString("2f")); * this.btnCreate.Enabled = true; * tabMain.AllowSelect = true; * Running = false; * })); * * }); */ string filePath = txtFilePath.Text; string outDir = Path.Combine(Path.GetDirectoryName(filePath), "CreatedQRcode"); BatchEncoder encoder = new BatchEncoder(filePath, outDir, (EventInfo eventInfo) => { BatchEncoder.ReadLineEventTarget target = eventInfo.Target as BatchEncoder.ReadLineEventTarget; ListViewItem item = new ListViewItem(new[] { target.LineIndex.ToString(), target.Text, "" }); AddItemForListView(lvBatchEncode, item); }, (EventInfo eventInfo) => { if (eventInfo.Type == EventInfo.EventType.OK) { BatchEncoder.EncodeLineToFileEventTarget target = eventInfo.Target as BatchEncoder.EncodeLineToFileEventTarget; SetCellForListView(lvBatchEncode, target.LineIndex, 2, "成功"); } else if (eventInfo.Type == EventInfo.EventType.ERROR) { } }); Task.Factory.StartNew(() => { Stopwatch watch = new Stopwatch(); watch.Start(); encoder.BatchEncode(false); watch.Stop(); toolStripStatusLabel2.Text = string.Format("生成完成,所用时间:{0}秒", watch.Elapsed.TotalSeconds.ToString("f3")); Running = false; }); }