public List <byte[]> AddVotes(List <PublicVote> publicVotes) { if (!publicVotes.Any()) { return(new List <byte[]>()); } var firstCandidateVotes = publicVotes[0].CandidateVotes; List <Ciphertext> aggregates = new List <Ciphertext>(); for (int i = 0; i < firstCandidateVotes.Count; i++) { aggregates.Add(homomorphicKeyManager.DeserializeCiphertext(firstCandidateVotes[i])); } for (int i = 1; i < publicVotes.Count; i++) { var vote = publicVotes[i]; for (int j = 0; j < vote.CandidateVotes.Count; j++) { var cipher = homomorphicKeyManager.DeserializeCiphertext(vote.CandidateVotes[j]); evaluator.AddInplace(aggregates[j], cipher); } } return(aggregates.Select(a => homomorphicKeyManager.SerializeCiphertext(a)).ToList()); }
static void Main(string[] args) { int votersCount = 10000; ulong keysize = 2048; int[] votes = createSampleVotes(votersCount, 1); #if (TEST) Console.WriteLine("votes=[{0}]", string.Join(", ", votes)); #endif Console.WriteLine("Sum of all votes = {0}", votes.Sum()); SEALContext context = createContext(keysize); IntegerEncoder encoder = new IntegerEncoder(context); KeyGenerator keygen = new KeyGenerator(context); PublicKey publicKey = keygen.PublicKey; SecretKey secretKey = keygen.SecretKey; Encryptor encryptor = new Encryptor(context, publicKey); Evaluator evaluator = new Evaluator(context); Decryptor decryptor = new Decryptor(context, secretKey); Ciphertext encryptedTotal = new Ciphertext(); encryptor.Encrypt(encoder.Encode(0), encryptedTotal); Ciphertext encrypted = new Ciphertext(); Console.WriteLine("-----------------------------------"); Console.WriteLine("Encoding the vote values ... "); Stopwatch sw = new Stopwatch(); sw.Start(); for (int i = 0; i < votes.Length; i++) { Plaintext plain = encoder.Encode(votes[i]); encryptor.Encrypt(plain, encrypted); #if (TEST) Console.WriteLine($"Noise budget in encrypted: {decryptor.InvariantNoiseBudget(encrypted)} bits"); Console.WriteLine($"Encoded {votes[i]} as polynomial {plain.ToString()}"); #endif evaluator.AddInplace(encryptedTotal, encrypted); } sw.Stop(); Console.WriteLine("Elapsed={0}", sw.Elapsed); Console.WriteLine("Done"); Console.WriteLine("-----------------------------------"); Plaintext plainResult = new Plaintext(); decryptor.Decrypt(encryptedTotal, plainResult); Console.Write($"Decrypting the result polynomial {plainResult.ToString()} ... "); Console.WriteLine("Done"); Console.WriteLine("-----------------------------------"); Console.WriteLine($"Decoded result: {encoder.DecodeInt32(plainResult)}"); Console.ReadLine(); }
//Function for calculating secured batched inner product private Ciphertext InnerProduct(Ciphertext featuresCiphertexts, Plaintext[] svPlaintexts, int i, Ciphertext[] sums, int numOfcolumnsCount, Ciphertext tempCt) { _evaluator.MultiplyPlain(featuresCiphertexts, svPlaintexts[i], sums[i]); int numOfRotations = (int)Math.Ceiling(Math.Log(numOfcolumnsCount, 2)); for (int k = 1, m = 1; m <= numOfRotations /*(int)encoder.SlotCount/2*/; k <<= 1, m++) { _evaluator.RotateVector(sums[i], k, _galoisKeys, tempCt); _evaluator.AddInplace(sums[i], tempCt); } var sum = sums[i]; return(sum); }
/* * 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 ExampleIntegerEncoder() { Utilities.PrintExampleBanner("Example: Encoders / Integer Encoder"); /* * [IntegerEncoder] (For BFV scheme only) * * The IntegerEncoder encodes integers to BFV plaintext polynomials as follows. * First, a binary expansion of the integer is computed. Next, a polynomial is * created with the bits as coefficients. For example, the integer * * 26 = 2^4 + 2^3 + 2^1 * * is encoded as the polynomial 1x^4 + 1x^3 + 1x^1. Conversely, plaintext * polynomials are decoded by evaluating them at x=2. For negative numbers the * IntegerEncoder simply stores all coefficients as either 0 or -1, where -1 is * represented by the unsigned integer PlainModulus - 1 in memory. * * Since encrypted computations operate on the polynomials rather than on the * encoded integers themselves, the polynomial coefficients will grow in the * course of such computations. For example, computing the sum of the encrypted * encoded integer 26 with itself will result in an encrypted polynomial with * larger coefficients: 2x^4 + 2x^3 + 2x^1. Squaring the encrypted encoded * integer 26 results also in increased coefficients due to cross-terms, namely, * * (1x^4 + 1x^3 + 1x^1)^2 = 1x^8 + 2x^7 + 1x^6 + 2x^5 + 2x^4 + 1x^2; * * further computations will quickly increase the coefficients much more. * Decoding will still work correctly in this case (evaluating the polynomial * at x=2), but since the coefficients of plaintext polynomials are really * integers modulo plain_modulus, implicit reduction modulo plain_modulus may * yield unexpected results. For example, adding 1x^4 + 1x^3 + 1x^1 to itself * plain_modulus many times will result in the constant polynomial 0, which is * clearly not equal to 26 * plain_modulus. It can be difficult to predict when * such overflow will take place especially when computing several sequential * multiplications. * * The IntegerEncoder is easy to understand and use for simple computations, * and can be a good tool to experiment with for users new to Microsoft SEAL. * However, advanced users will probably prefer more efficient approaches, * such as the BatchEncoder or the CKKSEncoder. */ EncryptionParameters parms = new EncryptionParameters(SchemeType.BFV); ulong polyModulusDegree = 4096; parms.PolyModulusDegree = polyModulusDegree; parms.CoeffModulus = CoeffModulus.BFVDefault(polyModulusDegree); /* * There is no hidden logic behind our choice of the plain_modulus. The only * thing that matters is that the plaintext polynomial coefficients will not * exceed this value at any point during our computation; otherwise the result * will be incorrect. */ parms.PlainModulus = new SmallModulus(512); SEALContext context = new SEALContext(parms); Utilities.PrintParameters(context); Console.WriteLine(); KeyGenerator keygen = new KeyGenerator(context); PublicKey publicKey = keygen.PublicKey; SecretKey secretKey = keygen.SecretKey; Encryptor encryptor = new Encryptor(context, publicKey); Evaluator evaluator = new Evaluator(context); Decryptor decryptor = new Decryptor(context, secretKey); /* * We create an IntegerEncoder. */ IntegerEncoder encoder = new IntegerEncoder(context); /* * First, we encode two integers as plaintext polynomials. Note that encoding * is not encryption: at this point nothing is encrypted. */ int value1 = 5; Plaintext plain1 = encoder.Encode(value1); Utilities.PrintLine(); Console.WriteLine($"Encode {value1} as polynomial {plain1} (plain1),"); int value2 = -7; Plaintext plain2 = encoder.Encode(value2); Console.WriteLine(new string(' ', 13) + $"Encode {value2} as polynomial {plain2} (plain2),"); /* * Now we can encrypt the plaintext polynomials. */ Ciphertext encrypted1 = new Ciphertext(); Ciphertext encrypted2 = new Ciphertext(); Utilities.PrintLine(); Console.WriteLine("Encrypt plain1 to encrypted1 and plain2 to encrypted2."); encryptor.Encrypt(plain1, encrypted1); encryptor.Encrypt(plain2, encrypted2); Console.WriteLine(" + Noise budget in encrypted1: {0} bits", decryptor.InvariantNoiseBudget(encrypted1)); Console.WriteLine(" + Noise budget in encrypted2: {0} bits", decryptor.InvariantNoiseBudget(encrypted2)); /* * As a simple example, we compute (-encrypted1 + encrypted2) * encrypted2. */ encryptor.Encrypt(plain2, encrypted2); Ciphertext encryptedResult = new Ciphertext(); Utilities.PrintLine(); Console.WriteLine("Compute encrypted_result = (-encrypted1 + encrypted2) * encrypted2."); evaluator.Negate(encrypted1, encryptedResult); evaluator.AddInplace(encryptedResult, encrypted2); evaluator.MultiplyInplace(encryptedResult, encrypted2); Console.WriteLine(" + Noise budget in encryptedResult: {0} bits", decryptor.InvariantNoiseBudget(encryptedResult)); Plaintext plainResult = new Plaintext(); Utilities.PrintLine(); Console.WriteLine("Decrypt encrypted_result to plain_result."); decryptor.Decrypt(encryptedResult, plainResult); /* * Print the result plaintext polynomial. The coefficients are not even close * to exceeding our plainModulus, 512. */ Console.WriteLine($" + Plaintext polynomial: {plainResult}"); /* * Decode to obtain an integer result. */ Utilities.PrintLine(); Console.WriteLine("Decode plain_result."); Console.WriteLine(" + Decoded integer: {0} ...... Correct.", encoder.DecodeInt32(plainResult)); }
private static void CKKSPerformanceTest(SEALContext context) { Stopwatch timer; Utilities.PrintParameters(context); Console.WriteLine(); bool hasZLIB = Serialization.IsSupportedComprMode(ComprModeType.ZLIB); bool hasZSTD = Serialization.IsSupportedComprMode(ComprModeType.ZSTD); using EncryptionParameters parms = context.FirstContextData.Parms; ulong polyModulusDegree = parms.PolyModulusDegree; Console.Write("Generating secret/public keys: "); using KeyGenerator keygen = new KeyGenerator(context); Console.WriteLine("Done"); using SecretKey secretKey = keygen.SecretKey; keygen.CreatePublicKey(out PublicKey publicKey); Func <RelinKeys> GetRelinKeys = () => { if (context.UsingKeyswitching) { /* * Generate relinearization keys. */ Console.Write("Generating relinearization keys: "); timer = Stopwatch.StartNew(); keygen.CreateRelinKeys(out RelinKeys relinKeys); int micros = (int)(timer.Elapsed.TotalMilliseconds * 1000); Console.WriteLine($"Done [{micros} microseconds]"); return(relinKeys); } else { return(null); } }; Func <GaloisKeys> GetGaloisKeys = () => { if (context.UsingKeyswitching) { if (!context.KeyContextData.Qualifiers.UsingBatching) { Console.WriteLine("Given encryption parameters do not support batching."); return(null); } /* * Generate Galois keys. In larger examples the Galois keys can use a lot of * memory, which can be a problem in constrained systems. The user should * try some of the larger runs of the test and observe their effect on the * memory pool allocation size. The key generation can also take a long time, * as can be observed from the print-out. */ Console.Write($"Generating Galois keys: "); timer = Stopwatch.StartNew(); keygen.CreateGaloisKeys(out GaloisKeys galoisKeys); int micros = (int)(timer.Elapsed.TotalMilliseconds * 1000); Console.WriteLine($"Done [{micros} microseconds]"); return(galoisKeys); } else { return(null); } }; using RelinKeys relinKeys = GetRelinKeys(); using GaloisKeys galKeys = GetGaloisKeys(); using Encryptor encryptor = new Encryptor(context, publicKey); using Decryptor decryptor = new Decryptor(context, secretKey); using Evaluator evaluator = new Evaluator(context); using CKKSEncoder ckksEncoder = new CKKSEncoder(context); Stopwatch timeEncodeSum = new Stopwatch(); Stopwatch timeDecodeSum = new Stopwatch(); Stopwatch timeEncryptSum = new Stopwatch(); Stopwatch timeDecryptSum = new Stopwatch(); Stopwatch timeAddSum = new Stopwatch(); Stopwatch timeMultiplySum = new Stopwatch(); Stopwatch timeMultiplyPlainSum = new Stopwatch(); Stopwatch timeSquareSum = new Stopwatch(); Stopwatch timeRelinearizeSum = new Stopwatch(); Stopwatch timeRescaleSum = new Stopwatch(); Stopwatch timeRotateOneStepSum = new Stopwatch(); Stopwatch timeRotateRandomSum = new Stopwatch(); Stopwatch timeConjugateSum = new Stopwatch(); Stopwatch timeSerializeSum = new Stopwatch(); Stopwatch timeSerializeZLIBSum = new Stopwatch(); Stopwatch timeSerializeZSTDSum = new Stopwatch(); Random rnd = new Random(); /* * How many times to run the test? */ int count = 10; /* * Populate a vector of floating-point values to batch. */ ulong slotCount = ckksEncoder.SlotCount; double[] podValues = new double[slotCount]; for (ulong i = 0; i < slotCount; i++) { podValues[i] = 1.001 * i; } Console.Write("Running tests "); for (int i = 0; i < count; i++) { /* * [Encoding] * For scale we use the square root of the last CoeffModulus prime * from parms. */ double scale = Math.Sqrt(parms.CoeffModulus.Last().Value); using Plaintext plain = new Plaintext(parms.PolyModulusDegree * (ulong)parms.CoeffModulus.Count(), 0); timeEncodeSum.Start(); ckksEncoder.Encode(podValues, scale, plain); timeEncodeSum.Stop(); /* * [Decoding] */ List <double> podList = new List <double>((int)slotCount); timeDecodeSum.Start(); ckksEncoder.Decode(plain, podList); timeDecodeSum.Stop(); /* * [Encryption] */ using Ciphertext encrypted = new Ciphertext(context); timeEncryptSum.Start(); encryptor.Encrypt(plain, encrypted); timeEncryptSum.Stop(); /* * [Decryption] */ using Plaintext plain2 = new Plaintext(polyModulusDegree, 0); timeDecryptSum.Start(); decryptor.Decrypt(encrypted, plain2); timeDecryptSum.Stop(); /* * [Add] */ using Ciphertext encrypted1 = new Ciphertext(context); ckksEncoder.Encode(i + 1, plain); encryptor.Encrypt(plain, encrypted1); using Ciphertext encrypted2 = new Ciphertext(context); ckksEncoder.Encode(i + 1, plain2); encryptor.Encrypt(plain2, encrypted2); timeAddSum.Start(); evaluator.AddInplace(encrypted1, encrypted2); evaluator.AddInplace(encrypted2, encrypted2); evaluator.AddInplace(encrypted1, encrypted2); timeAddSum.Stop(); /* * [Multiply] */ encrypted1.Reserve(3); timeMultiplySum.Start(); evaluator.MultiplyInplace(encrypted1, encrypted2); timeMultiplySum.Stop(); /* * [Multiply Plain] */ timeMultiplyPlainSum.Start(); evaluator.MultiplyPlainInplace(encrypted2, plain); timeMultiplyPlainSum.Stop(); /* * [Square] */ timeSquareSum.Start(); evaluator.SquareInplace(encrypted2); timeSquareSum.Stop(); if (context.UsingKeyswitching) { /* * [Relinearize] */ timeRelinearizeSum.Start(); evaluator.RelinearizeInplace(encrypted1, relinKeys); timeRelinearizeSum.Stop(); /* * [Rescale] */ timeRescaleSum.Start(); evaluator.RescaleToNextInplace(encrypted1); timeRescaleSum.Stop(); /* * [Rotate Vector] */ timeRotateOneStepSum.Start(); evaluator.RotateVectorInplace(encrypted, 1, galKeys); evaluator.RotateVectorInplace(encrypted, -1, galKeys); timeRotateOneStepSum.Stop(); /* * [Rotate Vector Random] */ // ckksEncoder.SlotCount is always a power of 2. int randomRotation = rnd.Next() & ((int)ckksEncoder.SlotCount - 1); timeRotateRandomSum.Start(); evaluator.RotateVectorInplace(encrypted, randomRotation, galKeys); timeRotateRandomSum.Stop(); /* * [Complex Conjugate] */ timeConjugateSum.Start(); evaluator.ComplexConjugateInplace(encrypted, galKeys); timeConjugateSum.Stop(); } /* * [Serialize Ciphertext] */ using MemoryStream stream = new MemoryStream(); timeSerializeSum.Start(); encrypted.Save(stream, ComprModeType.None); timeSerializeSum.Stop(); if (hasZLIB) { /* * [Serialize Ciphertext (ZLIB)] */ timeSerializeZLIBSum.Start(); encrypted.Save(stream, ComprModeType.ZLIB); timeSerializeZLIBSum.Stop(); } if (hasZSTD) { /* * [Serialize Ciphertext (Zstandard)] */ timeSerializeZSTDSum.Start(); encrypted.Save(stream, ComprModeType.ZSTD); timeSerializeZSTDSum.Stop(); } /* * Print a dot to indicate progress. */ Console.Write("."); Console.Out.Flush(); } Console.WriteLine(" Done"); Console.WriteLine(); Console.Out.Flush(); int avgEncode = (int)(timeEncodeSum.Elapsed.TotalMilliseconds * 1000 / count); int avgDecode = (int)(timeDecodeSum.Elapsed.TotalMilliseconds * 1000 / count); int avgEncrypt = (int)(timeEncryptSum.Elapsed.TotalMilliseconds * 1000 / count); int avgDecrypt = (int)(timeDecryptSum.Elapsed.TotalMilliseconds * 1000 / count); int avgAdd = (int)(timeAddSum.Elapsed.TotalMilliseconds * 1000 / (3 * count)); int avgMultiply = (int)(timeMultiplySum.Elapsed.TotalMilliseconds * 1000 / count); int avgMultiplyPlain = (int)(timeMultiplyPlainSum.Elapsed.TotalMilliseconds * 1000 / count); int avgSquare = (int)(timeSquareSum.Elapsed.TotalMilliseconds * 1000 / count); int avgRelinearize = (int)(timeRelinearizeSum.Elapsed.TotalMilliseconds * 1000 / count); int avgRescale = (int)(timeRescaleSum.Elapsed.TotalMilliseconds * 1000 / count); int avgRotateOneStep = (int)(timeRotateOneStepSum.Elapsed.TotalMilliseconds * 1000 / (2 * count)); int avgRotateRandom = (int)(timeRotateRandomSum.Elapsed.TotalMilliseconds * 1000 / count); int avgConjugate = (int)(timeConjugateSum.Elapsed.TotalMilliseconds * 1000 / count); int avgSerializeSum = (int)(timeSerializeSum.Elapsed.TotalMilliseconds * 1000 / count); int avgSerializeZLIBSum = (int)(timeSerializeZLIBSum.Elapsed.TotalMilliseconds * 1000 / count); int avgSerializeZSTDSum = (int)(timeSerializeZSTDSum.Elapsed.TotalMilliseconds * 1000 / count); Console.WriteLine($"Average encode: {avgEncode} microseconds"); Console.WriteLine($"Average decode: {avgDecode} microseconds"); Console.WriteLine($"Average encrypt: {avgEncrypt} microseconds"); Console.WriteLine($"Average decrypt: {avgDecrypt} microseconds"); Console.WriteLine($"Average add: {avgAdd} microseconds"); Console.WriteLine($"Average multiply: {avgMultiply} microseconds"); Console.WriteLine($"Average multiply plain: {avgMultiplyPlain} microseconds"); Console.WriteLine($"Average square: {avgSquare} microseconds"); if (context.UsingKeyswitching) { Console.WriteLine($"Average relinearize: {avgRelinearize} microseconds"); Console.WriteLine($"Average rescale: {avgRescale} microseconds"); Console.WriteLine($"Average rotate vector one step: {avgRotateOneStep} microseconds"); Console.WriteLine($"Average rotate vector random: {avgRotateRandom} microseconds"); Console.WriteLine($"Average complex conjugate: {avgConjugate} microseconds"); } Console.WriteLine($"Average serialize ciphertext: {avgSerializeSum} microseconds"); if (hasZLIB) { Console.WriteLine( $"Average compressed (ZLIB) serialize ciphertext: {avgSerializeZLIBSum} microseconds"); } if (hasZSTD) { Console.WriteLine( $"Average compressed (Zstandard) serialize ciphertext: {avgSerializeZSTDSum} microseconds"); } Console.Out.Flush(); }
private static void BFVPerformanceTest(SEALContext context) { Stopwatch timer; Utilities.PrintParameters(context); Console.WriteLine(); bool hasZLIB = Serialization.IsSupportedComprMode(ComprModeType.ZLIB); bool hasZSTD = Serialization.IsSupportedComprMode(ComprModeType.ZSTD); using EncryptionParameters parms = context.FirstContextData.Parms; using Modulus plainModulus = parms.PlainModulus; ulong polyModulusDegree = parms.PolyModulusDegree; Console.Write("Generating secret/public keys: "); using KeyGenerator keygen = new KeyGenerator(context); Console.WriteLine("Done"); using SecretKey secretKey = keygen.SecretKey; keygen.CreatePublicKey(out PublicKey publicKey); Func <RelinKeys> GetRelinKeys = () => { if (context.UsingKeyswitching) { /* * Generate relinearization keys. */ Console.Write("Generating relinearization keys: "); timer = Stopwatch.StartNew(); keygen.CreateRelinKeys(out RelinKeys relinKeys); int micros = (int)(timer.Elapsed.TotalMilliseconds * 1000); Console.WriteLine($"Done [{micros} microseconds]"); return(relinKeys); } else { return(null); } }; Func <GaloisKeys> GetGaloisKeys = () => { if (context.UsingKeyswitching) { if (!context.KeyContextData.Qualifiers.UsingBatching) { Console.WriteLine("Given encryption parameters do not support batching."); return(null); } /* * Generate Galois keys. In larger examples the Galois keys can use a lot of * memory, which can be a problem in constrained systems. The user should * try some of the larger runs of the test and observe their effect on the * memory pool allocation size. The key generation can also take a long time, * as can be observed from the print-out. */ Console.Write($"Generating Galois keys: "); timer = Stopwatch.StartNew(); keygen.CreateGaloisKeys(out GaloisKeys galoisKeys); int micros = (int)(timer.Elapsed.TotalMilliseconds * 1000); Console.WriteLine($"Done [{micros} microseconds]"); return(galoisKeys); } else { return(null); } }; using RelinKeys relinKeys = GetRelinKeys(); using GaloisKeys galKeys = GetGaloisKeys(); using Encryptor encryptor = new Encryptor(context, publicKey); using Decryptor decryptor = new Decryptor(context, secretKey); using Evaluator evaluator = new Evaluator(context); using BatchEncoder batchEncoder = new BatchEncoder(context); /* * These will hold the total times used by each operation. */ Stopwatch timeBatchSum = new Stopwatch(); Stopwatch timeUnbatchSum = new Stopwatch(); Stopwatch timeEncryptSum = new Stopwatch(); Stopwatch timeDecryptSum = new Stopwatch(); Stopwatch timeAddSum = new Stopwatch(); Stopwatch timeMultiplySum = new Stopwatch(); Stopwatch timeMultiplyPlainSum = new Stopwatch(); Stopwatch timeSquareSum = new Stopwatch(); Stopwatch timeRelinearizeSum = new Stopwatch(); Stopwatch timeRotateRowsOneStepSum = new Stopwatch(); Stopwatch timeRotateRowsRandomSum = new Stopwatch(); Stopwatch timeRotateColumnsSum = new Stopwatch(); Stopwatch timeSerializeSum = new Stopwatch(); Stopwatch timeSerializeZLIBSum = new Stopwatch(); Stopwatch timeSerializeZSTDSum = new Stopwatch(); /* * How many times to run the test? */ int count = 10; /* * Populate a vector of values to batch. */ ulong slotCount = batchEncoder.SlotCount; ulong[] podValues = new ulong[slotCount]; Random rnd = new Random(); for (ulong i = 0; i < batchEncoder.SlotCount; i++) { podValues[i] = plainModulus.Reduce((ulong)rnd.Next()); } Console.Write("Running tests "); for (int i = 0; i < count; i++) { /* * [Batching] * There is nothing unusual here. We batch our random plaintext matrix * into the polynomial. Note how the plaintext we create is of the exactly * right size so unnecessary reallocations are avoided. */ using Plaintext plain = new Plaintext(parms.PolyModulusDegree, 0); timeBatchSum.Start(); batchEncoder.Encode(podValues, plain); timeBatchSum.Stop(); /* * [Unbatching] * We unbatch what we just batched. */ List <ulong> podList = new List <ulong>((int)slotCount); timeUnbatchSum.Start(); batchEncoder.Decode(plain, podList); timeUnbatchSum.Stop(); if (!podList.SequenceEqual(podValues)) { throw new InvalidOperationException("Batch/unbatch failed. Something is wrong."); } /* * [Encryption] * We make sure our ciphertext is already allocated and large enough * to hold the encryption with these encryption parameters. We encrypt * our random batched matrix here. */ using Ciphertext encrypted = new Ciphertext(context); timeEncryptSum.Start(); encryptor.Encrypt(plain, encrypted); timeEncryptSum.Stop(); /* * [Decryption] * We decrypt what we just encrypted. */ using Plaintext plain2 = new Plaintext(polyModulusDegree, 0); timeDecryptSum.Start(); decryptor.Decrypt(encrypted, plain2); timeDecryptSum.Stop(); if (!plain2.Equals(plain)) { throw new InvalidOperationException("Encrypt/decrypt failed. Something is wrong."); } /* * [Add] * We create two ciphertexts and perform a few additions with them. */ using Plaintext plain1 = new Plaintext(parms.PolyModulusDegree, 0); for (ulong j = 0; j < batchEncoder.SlotCount; j++) { podValues[j] = j; } batchEncoder.Encode(podValues, plain1); for (ulong j = 0; j < batchEncoder.SlotCount; j++) { podValues[j] = j + 1; } batchEncoder.Encode(podValues, plain2); using Ciphertext encrypted1 = new Ciphertext(context); encryptor.Encrypt(plain1, encrypted1); using Ciphertext encrypted2 = new Ciphertext(context); encryptor.Encrypt(plain2, encrypted2); timeAddSum.Start(); evaluator.AddInplace(encrypted1, encrypted1); evaluator.AddInplace(encrypted2, encrypted2); evaluator.AddInplace(encrypted1, encrypted2); timeAddSum.Stop(); /* * [Multiply] * We multiply two ciphertexts. Since the size of the result will be 3, * and will overwrite the first argument, we reserve first enough memory * to avoid reallocating during multiplication. */ encrypted1.Reserve(3); timeMultiplySum.Start(); evaluator.MultiplyInplace(encrypted1, encrypted2); timeMultiplySum.Stop(); /* * [Multiply Plain] * We multiply a ciphertext with a random plaintext. Recall that * MultiplyPlain does not change the size of the ciphertext so we use * encrypted2 here. */ timeMultiplyPlainSum.Start(); evaluator.MultiplyPlainInplace(encrypted2, plain); timeMultiplyPlainSum.Stop(); /* * [Square] * We continue to use encrypted2. Now we square it; this should be * faster than generic homomorphic multiplication. */ timeSquareSum.Start(); evaluator.SquareInplace(encrypted2); timeSquareSum.Stop(); if (context.UsingKeyswitching) { /* * [Relinearize] * Time to get back to encrypted1. We now relinearize it back * to size 2. Since the allocation is currently big enough to * contain a ciphertext of size 3, no costly reallocations are * needed in the process. */ timeRelinearizeSum.Start(); evaluator.RelinearizeInplace(encrypted1, relinKeys); timeRelinearizeSum.Stop(); /* * [Rotate Rows One Step] * We rotate matrix rows by one step left and measure the time. */ timeRotateRowsOneStepSum.Start(); evaluator.RotateRowsInplace(encrypted, 1, galKeys); evaluator.RotateRowsInplace(encrypted, -1, galKeys); timeRotateRowsOneStepSum.Stop(); /* * [Rotate Rows Random] * We rotate matrix rows by a random number of steps. This is much more * expensive than rotating by just one step. */ int rowSize = (int)batchEncoder.SlotCount / 2; // rowSize is always a power of 2. int randomRotation = rnd.Next() & (rowSize - 1); timeRotateRowsRandomSum.Start(); evaluator.RotateRowsInplace(encrypted, randomRotation, galKeys); timeRotateRowsRandomSum.Stop(); /* * [Rotate Columns] * Nothing surprising here. */ timeRotateColumnsSum.Start(); evaluator.RotateColumnsInplace(encrypted, galKeys); timeRotateColumnsSum.Stop(); } /* * [Serialize Ciphertext] */ using MemoryStream stream = new MemoryStream(); timeSerializeSum.Start(); encrypted.Save(stream, ComprModeType.None); timeSerializeSum.Stop(); if (hasZLIB) { /* * [Serialize Ciphertext (ZLIB)] */ timeSerializeZLIBSum.Start(); encrypted.Save(stream, ComprModeType.ZLIB); timeSerializeZLIBSum.Stop(); } if (hasZSTD) { /* * [Serialize Ciphertext (Zstandard)] */ timeSerializeZSTDSum.Start(); encrypted.Save(stream, ComprModeType.ZSTD); timeSerializeZSTDSum.Stop(); } /* * Print a dot to indicate progress. */ Console.Write("."); Console.Out.Flush(); } Console.WriteLine(" Done"); Console.WriteLine(); Console.Out.Flush(); int avgBatch = (int)(timeBatchSum.Elapsed.TotalMilliseconds * 1000 / count); int avgUnbatch = (int)(timeUnbatchSum.Elapsed.TotalMilliseconds * 1000 / count); int avgEncrypt = (int)(timeEncryptSum.Elapsed.TotalMilliseconds * 1000 / count); int avgDecrypt = (int)(timeDecryptSum.Elapsed.TotalMilliseconds * 1000 / count); int avgAdd = (int)(timeAddSum.Elapsed.TotalMilliseconds * 1000 / (3 * count)); int avgMultiply = (int)(timeMultiplySum.Elapsed.TotalMilliseconds * 1000 / count); int avgMultiplyPlain = (int)(timeMultiplyPlainSum.Elapsed.TotalMilliseconds * 1000 / count); int avgSquare = (int)(timeSquareSum.Elapsed.TotalMilliseconds * 1000 / count); int avgRelinearize = (int)(timeRelinearizeSum.Elapsed.TotalMilliseconds * 1000 / count); int avgRotateRowsOneStep = (int)(timeRotateRowsOneStepSum.Elapsed.TotalMilliseconds * 1000 / (2 * count)); int avgRotateRowsRandom = (int)(timeRotateRowsRandomSum.Elapsed.TotalMilliseconds * 1000 / count); int avgRotateColumns = (int)(timeRotateColumnsSum.Elapsed.TotalMilliseconds * 1000 / count); int avgSerializeSum = (int)(timeSerializeSum.Elapsed.TotalMilliseconds * 1000 / count); int avgSerializeZLIBSum = (int)(timeSerializeZLIBSum.Elapsed.TotalMilliseconds * 1000 / count); int avgSerializeZSTDSum = (int)(timeSerializeZSTDSum.Elapsed.TotalMilliseconds * 1000 / count); Console.WriteLine($"Average batch: {avgBatch} microseconds"); Console.WriteLine($"Average unbatch: {avgUnbatch} microseconds"); Console.WriteLine($"Average encrypt: {avgEncrypt} microseconds"); Console.WriteLine($"Average decrypt: {avgDecrypt} microseconds"); Console.WriteLine($"Average add: {avgAdd} microseconds"); Console.WriteLine($"Average multiply: {avgMultiply} microseconds"); Console.WriteLine($"Average multiply plain: {avgMultiplyPlain} microseconds"); Console.WriteLine($"Average square: {avgSquare} microseconds"); if (context.UsingKeyswitching) { Console.WriteLine($"Average relinearize: {avgRelinearize} microseconds"); Console.WriteLine($"Average rotate rows one step: {avgRotateRowsOneStep} microseconds"); Console.WriteLine($"Average rotate rows random: {avgRotateRowsRandom} microseconds"); Console.WriteLine($"Average rotate columns: {avgRotateColumns} microseconds"); } Console.WriteLine($"Average serialize ciphertext: {avgSerializeSum} microseconds"); if (hasZLIB) { Console.WriteLine( $"Average compressed (ZLIB) serialize ciphertext: {avgSerializeZLIBSum} microseconds"); } if (hasZSTD) { Console.WriteLine( $"Average compressed (Zstandard) serialize ciphertext: {avgSerializeZSTDSum} microseconds"); } Console.Out.Flush(); }
private static void HomoExample() { EncryptionParameters parms = new EncryptionParameters(SchemeType.BFV); parms.PolyModulusDegree = 2048; parms.CoeffModulus = DefaultParams.CoeffModulus128(polyModulusDegree: 2048); parms.PlainModulus = new SmallModulus(1 << 8); SEALContext context = SEALContext.Create(parms); IntegerEncoder encoder = new IntegerEncoder(context); KeyGenerator keygen = new KeyGenerator(context); Microsoft.Research.SEAL.PublicKey publicKey = keygen.PublicKey; SecretKey secretKey = keygen.SecretKey; Encryptor encryptor = new Encryptor(context, publicKey); Evaluator evaluator = new Evaluator(context); Decryptor decryptor = new Decryptor(context, secretKey); int value1 = 5; Plaintext plain1 = encoder.Encode(value1); Console.WriteLine($"Encoded {value1} as polynomial {plain1.ToString()} (plain1)"); int value2 = -7; Plaintext plain2 = encoder.Encode(value2); Console.WriteLine($"Encoded {value2} as polynomial {plain2.ToString()} (plain2)"); Ciphertext encrypted1 = new Ciphertext(); Ciphertext encrypted2 = new Ciphertext(); Console.Write("Encrypting plain1: "); encryptor.Encrypt(plain1, encrypted1); Console.WriteLine("Done (encrypted1)"); Plaintext plainResult = new Plaintext(); decryptor.Decrypt(encrypted1, plainResult); Console.WriteLine(encoder.DecodeInt32(plainResult)); Console.Write("Encrypting plain2: "); encryptor.Encrypt(plain2, encrypted2); Console.WriteLine("Done (encrypted2)"); Console.WriteLine($"Noise budget in encrypted1: {decryptor.InvariantNoiseBudget(encrypted1)} bits"); Console.WriteLine($"Noise budget in encrypted2: {decryptor.InvariantNoiseBudget(encrypted2)} bits"); evaluator.NegateInplace(encrypted1); Console.WriteLine($"Noise budget in -encrypted1: {decryptor.InvariantNoiseBudget(encrypted1)} bits"); evaluator.AddInplace(encrypted1, encrypted2); Console.WriteLine($"Noise budget in -encrypted1 + encrypted2: {decryptor.InvariantNoiseBudget(encrypted1)} bits"); evaluator.MultiplyInplace(encrypted1, encrypted2); Console.WriteLine($"Noise budget in (-encrypted1 + encrypted2) * encrypted2: {decryptor.InvariantNoiseBudget(encrypted1)} bits"); plainResult = new Plaintext(); Console.Write("Decrypting result: "); decryptor.Decrypt(encrypted1, plainResult); Console.WriteLine("Done"); Console.WriteLine($"Plaintext polynomial: {plainResult.ToString()}"); Console.WriteLine($"Decoded integer: {encoder.DecodeInt32(plainResult)}"); }
public void TestLinearRegression_Encryption() { // these are the feature sets we will be encrypting and getting // the ML model results on. The plaintext versions of these values // should (in the encryped scheme) not be known by the evaluator double[][] testX = new double[6][]; testX[0] = new double[] { 43.45089541, 53.15091973, 53.07708932, 93.65456934, 65.23330105, 69.34856259, 62.91649012, 35.28814156, 108.1002775, 100.1735266 }; testX[1] = new double[] { 51.59952075, 99.48561775, 95.75948428, 126.6533636, 142.5235433, 90.97955769, 43.66586306, 85.31957886, 62.57644682, 66.12458533 }; testX[2] = new double[] { 94.77026243, 71.51229208, 85.33271407, 69.58347566, 107.8693045, 101.6701889, 89.88200921, 54.93440139, 105.5448532, 72.07947083 }; testX[3] = new double[] { 89.53820766, 100.199631, 86.19911875, 85.88717675, 33.92249944, 80.47113937, 65.34411148, 89.70004394, 75.00778202, 122.3514331 }; testX[4] = new double[] { 96.86101454, 97.54597612, 122.9960987, 86.1281547, 115.5539807, 107.888993, 65.51660154, 74.17007885, 48.04727402, 93.56952259 }; testX[5] = new double[] { 91.75121904, 121.2115065, 62.92763365, 99.4343452, 70.420912, 88.0580948, 71.82993308, 80.49171244, 87.11321454, 100.1459868 }; // setup the encryptor and other various components EncryptionParameters parms = new EncryptionParameters(SchemeType.CKKS); parms.PolyModulusDegree = 8192; parms.CoeffModulus = DefaultParams.CoeffModulus128(polyModulusDegree: 8192); SEALContext context = SEALContext.Create(parms); CKKSEncoder encoder = new CKKSEncoder(context); KeyGenerator keygen = new KeyGenerator(context); PublicKey publicKey = keygen.PublicKey; SecretKey secretKey = keygen.SecretKey; RelinKeys relinKeys = keygen.RelinKeys(decompositionBitCount: DefaultParams.DBCmax); Encryptor encryptor = new Encryptor(context, publicKey); Evaluator evaluator = new Evaluator(context); Decryptor decryptor = new Decryptor(context, secretKey); double scale = Math.Pow(2.0, 30); List <List <Ciphertext> > featureCiphers = new List <List <Ciphertext> >(); for (int i = 0; i < testX.Length; i++) { List <Ciphertext> curFeatureCiphers = new List <Ciphertext>(); foreach (var featureVal in testX[i]) { List <double> featureVector = new double[] { featureVal }.ToList(); Plaintext plain = new Plaintext(); encoder.Encode(featureVal, scale, plain); Ciphertext encrypted = new Ciphertext(); encryptor.Encrypt(plain, encrypted); curFeatureCiphers.Add(encrypted); } featureCiphers.Add(curFeatureCiphers); } // This is the 'evaluator' section // this is not a part of the client and would, in a cloud based solution, be run on the server // the server should not know the values of the input features, but it will do math on them // likewise, the client would not know the various weights and parameters, but will receive a result double[] weights_model = { 0.0921533, 0.14545279, 0.11066622, 0.06119513, 0.10041948, 0.19091597, 0.07359407, 0.04503237, 0.10848583, 0.10092494 }; double intercept_model = -2.484390163425502; double[] weights_groundTruth = { 0.1, 0.15, 0.1, 0.05, 0.1, 0.2, 0.05, 0.05, 0.1, 0.1 }; // we need to encode the weights/parameters/intercepts/etc. used by the model using the same public key as the client List <Ciphertext> weightsCTs = new List <Ciphertext>(); List <Ciphertext> scoreCTs = new List <Ciphertext>(); foreach (var weight in weights_model) { List <double> weightVector = new double[] { weight }.ToList(); List <double> scoreVector = new double[] { 0.0 }.ToList(); Plaintext weightPT = new Plaintext(); encoder.Encode(weight, scale, weightPT); Ciphertext weightCT = new Ciphertext(); encryptor.Encrypt(weightPT, weightCT); weightsCTs.Add(weightCT); } // next, we run the actual model's computation // linear regression is a basic dot product for (int i = 0; i < featureCiphers.Count(); i++) { List <Ciphertext> multResultCTs = new List <Ciphertext>(); for (var j = 0; j < weightsCTs.Count; j++) { Ciphertext multResultCT = new Ciphertext(); evaluator.Multiply(weightsCTs[j], featureCiphers[i][j], multResultCT); multResultCTs.Add(multResultCT); } Ciphertext dotProductResult = new Ciphertext(); evaluator.AddMany(multResultCTs, dotProductResult); Plaintext scorePT = new Plaintext(); encoder.Encode(intercept_model, dotProductResult.Scale, scorePT); Ciphertext scoreCT = new Ciphertext(); encryptor.Encrypt(scorePT, scoreCT); evaluator.AddInplace(scoreCT, dotProductResult); scoreCTs.Add(scoreCT); //evaluator.AddInplace(scoreCTs[i], interceptCT); } // we now have the encrypted version of the ML model. The below section is the client's again // in it, we decrypt the results given by the server using the private key generated previously List <List <double> > predictions = new List <List <double> >(); for (int i = 0; i < scoreCTs.Count; i++) { Plaintext plainResult = new Plaintext(); var encryptedResult = scoreCTs[i]; decryptor.Decrypt(encryptedResult, plainResult); List <double> result = new List <double>(); encoder.Decode(plainResult, result); predictions.Add(result); } // this is the output section. In practice, we would not have access to these values (as they represent the ground truth) // We are using them here merely to demonstrate that we can properly recover the proper ML model output double[] yGroundTruth = { 68.43881952, 87.75905253, 88.34053641, 83.87264322, 95.20322583, 89.61704108 }; double[] yTest = { 68.702934, 87.28860458, 88.40827187, 83.24001674, 94.53137951, 89.00229455 }; const double EPSILON = 1e-4; for (int i = 0; i < predictions.Count; i++) { var avgDecryption = predictions[i].Average(); var absDelta = Math.Abs(avgDecryption - yTest[i]); Assert.IsTrue(absDelta < EPSILON); } }
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); }
public int Predict(double[] features, bool useRelinearizeInplace,bool useReScale,out double finalResult) { Console.WriteLine(); ulong slotCount = _encoder.SlotCount; //Console.WriteLine($"Number of slots: {slotCount}"); var featuresLength = features.Length; var plaintexts = new Plaintext(); var featuresCiphertexts = new Ciphertext(); Stopwatch clientStopwatch = new Stopwatch(); clientStopwatch.Start(); //Encode and encrypt features double scale = Math.Pow(2.0, _power); _encoder.Encode(features, scale, plaintexts); _encryptor.Encrypt(plaintexts, featuresCiphertexts); SvcUtilities.PrintScale(plaintexts, "featurePlaintext"); SvcUtilities.PrintScale(featuresCiphertexts, "featurefEncrypted"); clientStopwatch.Stop(); Stopwatch serverInitStopwatch = new Stopwatch(); serverInitStopwatch.Start(); // Handle SV var numOfrowsCount = _vectors.Length; var numOfcolumnsCount = _vectors[0].Length; var svPlaintexts = new Plaintext[numOfrowsCount]; //Encode SV var sums = new Ciphertext[numOfrowsCount]; for (int i = 0; i < numOfrowsCount; i++) { svPlaintexts[i] = new Plaintext(); _encoder.Encode(_vectors[i], scale, svPlaintexts[i]); SvcUtilities.PrintScale(svPlaintexts[i], "supportVectorsPlaintext"+i); sums[i] = new Ciphertext(); } var kernels = new Ciphertext[numOfrowsCount]; var decisionsArr = new Ciphertext[numOfrowsCount]; var coefArr = new Plaintext [numOfrowsCount]; for (int i = 0; i < numOfrowsCount; i++) { kernels[i] = new Ciphertext(); decisionsArr[i] = new Ciphertext(); coefArr[i] = new Plaintext(); } Plaintext gamaPlaintext= new Plaintext(); _encoder.Encode(_gamma, scale, gamaPlaintext); Ciphertext tempCt = new Ciphertext(); serverInitStopwatch.Stop(); Stopwatch innerProductStopwatch = new Stopwatch(); Stopwatch negateStopwatch = new Stopwatch(); Stopwatch degreeStopwatch = new Stopwatch(); // Level 1 for (int i = 0; i < numOfrowsCount; i++) { //Console.WriteLine(i); //inner product innerProductStopwatch.Start(); _evaluator.MultiplyPlain(featuresCiphertexts, svPlaintexts[i],sums[i]); int numOfRotations = (int)Math.Ceiling(Math.Log2(numOfcolumnsCount)); for (int k = 1,m=1; m <= numOfRotations/*(int)encoder.SlotCount/2*/; k <<= 1,m++) { _evaluator.RotateVector(sums[i], k, _galoisKeys, tempCt); _evaluator.AddInplace(sums[i], tempCt); } innerProductStopwatch.Stop(); kernels[i] = sums[i]; SvcUtilities.PrintCyprherText(_decryptor, kernels[i], _encoder, $"inner product TotalValue {i}" ); SvcUtilities.PrintScale(kernels[i], "0. kernels" + i); if (useRelinearizeInplace) { _evaluator.RelinearizeInplace(kernels[i], _relinKeys); } if (useReScale) { _evaluator.RescaleToNextInplace(kernels[i]); } SvcUtilities.PrintScale(kernels[i], "1. kernels" + i); kernels[i].Scale = scale; if(_kernel == Kernel.Poly) { if (useReScale) { ParmsId lastParmsId = kernels[i].ParmsId; _evaluator.ModSwitchToInplace(gamaPlaintext, lastParmsId); } _evaluator.MultiplyPlainInplace(kernels[i], gamaPlaintext); SvcUtilities.PrintScale(kernels[i], "2. kernels" + i); if (useRelinearizeInplace) { _evaluator.RelinearizeInplace(kernels[i], _relinKeys); } if (useReScale) { _evaluator.RescaleToNextInplace(kernels[i]); } SvcUtilities.PrintScale(kernels[i], "3. kernels" + i); if (Math.Abs(_coef0) > 0) { Plaintext coef0Plaintext = new Plaintext(); _encoder.Encode(_coef0, kernels[i].Scale, coef0Plaintext); if (useReScale) { ParmsId lastParmsId = kernels[i].ParmsId; _evaluator.ModSwitchToInplace(coef0Plaintext, lastParmsId); } //kernels[i].Scale = coef0Plaintext.Scale; _evaluator.AddPlainInplace(kernels[i], coef0Plaintext); } SvcUtilities.PrintScale(kernels[i], "4. kernels" + i); degreeStopwatch.Start(); var kernel = new Ciphertext(kernels[i]); for (int d = 0; d < (int)_degree-1; d++) { kernel.Scale = kernels[i].Scale; if (useReScale) { ParmsId lastParmsId = kernels[i].ParmsId; _evaluator.ModSwitchToInplace(kernel, lastParmsId); } _evaluator.MultiplyInplace(kernels[i], kernel); SvcUtilities.PrintScale(kernels[i], d + " 5. kernels" + i); if (useRelinearizeInplace) { _evaluator.RelinearizeInplace(kernels[i], _relinKeys); } if (useReScale) { _evaluator.RescaleToNextInplace(kernels[i]); } SvcUtilities.PrintScale(kernels[i], d + " rescale 6. kernels" + i); } SvcUtilities.PrintScale(kernels[i], "7. kernels" + i); degreeStopwatch.Stop(); } negateStopwatch.Start(); _evaluator.NegateInplace(kernels[i]); negateStopwatch.Stop(); SvcUtilities.PrintScale(kernels[i], "8. kernel"+i); SvcUtilities.PrintCyprherText(_decryptor, kernels[i], _encoder, "kernel"+i); } Stopwatch serverDecisionStopWatch = new Stopwatch(); serverDecisionStopWatch.Start(); // Encode coefficients : ParmsId! , scale! double scale2 = Math.Pow(2.0, _power); if (useReScale) { scale2 = kernels[0].Scale; } for (int i = 0; i < numOfrowsCount; i++) { _encoder.Encode(_coefficients[0][i], scale2, coefArr[i]); SvcUtilities.PrintScale(coefArr[i], "coefPlainText"+i); } if (useReScale) { for (int i = 0; i < numOfrowsCount; i++) { ParmsId lastParmsId = kernels[i].ParmsId; _evaluator.ModSwitchToInplace(coefArr[i], lastParmsId); } } // Level 2 // Calculate decisionArr for (int i = 0; i < numOfrowsCount; 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); //================================================================= SvcUtilities.PrintScale(decisionTotal, "decisionTotal"); //Level 3 List<double> result = SvcUtilities.PrintCyprherText(_decryptor, decisionTotal, _encoder, "finalTotal",true); serverDecisionStopWatch.Stop(); Console.WriteLine($"client Init elapsed {clientStopwatch.ElapsedMilliseconds} ms"); Console.WriteLine($"server Init elapsed {serverInitStopwatch.ElapsedMilliseconds} ms"); Console.WriteLine($"server innerProductStopwatch elapsed {innerProductStopwatch.ElapsedMilliseconds} ms"); Console.WriteLine($"server negateStopwatch elapsed {negateStopwatch.ElapsedMilliseconds} ms"); Console.WriteLine($"server degreeStopwatch elapsed {degreeStopwatch.ElapsedMilliseconds} ms"); Console.WriteLine($"server Decision elapsed {serverDecisionStopWatch.ElapsedMilliseconds} ms"); finalResult = result[0]; if (result[0] > 0) { return 0; } return 1; }