private static bool EncodeString(string s, Span <byte> buffer, out int length, bool lowercase) { const int toLowerMask = 0x20; int i = 0; length = 0; if (buffer.Length == 0) { return(false); } buffer[0] = 0; if (!IntegerEncoder.Encode(s.Length, 7, buffer, out int nameLength)) { return(false); } i += nameLength; // TODO: use huffman encoding for (int j = 0; j < s.Length; j++) { if (i >= buffer.Length) { return(false); } buffer[i++] = (byte)(s[j] | (lowercase ? toLowerMask : 0)); } length = i; return(true); }
public static void ExampleParameterSelection() { PrintExampleBanner("Example: Automatic Parameter Selection"); /* * Here we demonstrate the automatic parameter selection tool. Suppose we want to find parameters * that are optimized in a way that allows us to evaluate the polynomial 42x^3-27x+1. We need to know * the size of the input data, so let's assume that x is an integer with base-3 representation of length * at most 10. */ Console.Write("Finding optimized parameters for computing 42x^3-27x+1 ... "); var chooserEncoder = new ChooserEncoder(); var chooserEvaluator = new ChooserEvaluator(); /* * First create a ChooserPoly representing the input data. You can think of this modeling a freshly * encrypted cipheretext of a plaintext polynomial with length at most 10 coefficients, where the * coefficients have absolute value at most 1. */ var cinput = new ChooserPoly(10, 1); // Compute the first term var ccubedInput = chooserEvaluator.Exponentiate(cinput, 3); var cterm1 = chooserEvaluator.MultiplyPlain(ccubedInput, chooserEncoder.Encode(42)); // Compute the second term var cterm2 = chooserEvaluator.MultiplyPlain(cinput, chooserEncoder.Encode(27)); // Subtract the first two terms var csum12 = chooserEvaluator.Sub(cterm1, cterm2); // Add the constant term 1 var cresult = chooserEvaluator.AddPlain(csum12, chooserEncoder.Encode(1)); // To find an optimized set of parameters, we use ChooserEvaluator.SelectParameters(...). var optimalParms = new EncryptionParameters(); chooserEvaluator.SelectParameters(new List <ChooserPoly> { cresult }, 0, optimalParms); // We still need to validate the returned parameters optimalParms.Validate(); Console.WriteLine("done."); // Let's print these to see what was recommended Console.WriteLine("Selected parameters:"); Console.WriteLine("{{ poly_modulus: {0}", optimalParms.PolyModulus); Console.WriteLine("{{ coeff_modulus: {0}", optimalParms.CoeffModulus); Console.WriteLine("{{ plain_modulus: {0}", optimalParms.PlainModulus.ToDecimalString()); Console.WriteLine("{{ decomposition_bit_count: {0}", optimalParms.DecompositionBitCount); Console.WriteLine("{{ noise_standard_deviation: {0}", optimalParms.NoiseStandardDeviation); Console.WriteLine("{{ noise_max_deviation: {0}", optimalParms.NoiseMaxDeviation); // Let's try to actually perform the homomorphic computation using the recommended parameters. // Generate keys. Console.WriteLine("Generating keys ..."); var generator = new KeyGenerator(optimalParms); /* * Need to generate one evaluation key because below we will use Evaluator.Exponentiate(...), * which relinearizes after every multiplication it performs (see ExampleRelinearization() * for more details. */ generator.Generate(1); Console.WriteLine("... key generation completed"); var publicKey = generator.PublicKey; var secretKey = generator.SecretKey; var evaluationKeys = generator.EvaluationKeys; // Create the encoding/encryption tools var encoder = new IntegerEncoder(optimalParms.PlainModulus, 3); var encryptor = new Encryptor(optimalParms, publicKey); var evaluator = new Evaluator(optimalParms, evaluationKeys); var decryptor = new Decryptor(optimalParms, secretKey); // Now perform the computations on real encrypted data. const int inputValue = 12345; var plainInput = encoder.Encode(inputValue); Console.WriteLine("Encoded {0} as polynomial {1}", inputValue, plainInput); Console.Write("Encrypting ... "); var input = encryptor.Encrypt(plainInput); Console.WriteLine("done."); // Compute the first term Console.Write("Computing first term ... "); var cubedInput = evaluator.Exponentiate(input, 3); var term1 = evaluator.MultiplyPlain(cubedInput, encoder.Encode(42)); Console.WriteLine("done."); // Compute the second term Console.Write("Computing second term ... "); var term2 = evaluator.MultiplyPlain(input, encoder.Encode(27)); Console.WriteLine("done."); // Subtract the first two terms Console.Write("Subtracting first two terms ... "); var sum12 = evaluator.Sub(term1, term2); Console.WriteLine("done."); // Add the constant term 1 Console.Write("Adding one ... "); var result = evaluator.AddPlain(sum12, encoder.Encode(1)); Console.WriteLine("done."); // Decrypt and decode Console.Write("Decrypting ... "); var plainResult = decryptor.Decrypt(result); Console.WriteLine("done."); // Finally print the result Console.WriteLine("Polynomial 42x^3-27x+1 evaluated at x=12345: {0}", encoder.DecodeInt64(plainResult)); // How much noise budget are we left with? Console.WriteLine("Noise budget in result: {0} bits", decryptor.InvariantNoiseBudget(result)); }
public static void ExampleBasics() { PrintExampleBanner("Example: Basics"); /* * In this example we demonstrate using some of the basic arithmetic operations on integers. * * SEAL uses the Fan-Vercauteren (FV) homomorphic encryption scheme. We refer to * https://eprint.iacr.org/2012/144 for full details on how the FV scheme works. */ // Create encryption parameters. var parms = new EncryptionParameters(); /* * First choose the polynomial modulus. This must be a power-of-2 cyclotomic polynomial, * i.e. a polynomial of the form "1x^(power-of-2) + 1". We recommend using polynomials of * degree at least 1024. */ parms.SetPolyModulus("1x^2048 + 1"); /* * Next we choose the coefficient modulus. SEAL comes with default values for the coefficient * modulus for some of the most reasonable choices of PolyModulus. They are as follows: * * /----------------------------------------------------------------------\ | PolyModulus | default CoeffModulus | security | | -------------|--------------------------------------------|----------| | 1x^2048 + 1 | 2^60 - 2^14 + 1 (60 bits) | 119 bit | | 1x^4096 + 1 | 2^116 - 2^18 + 1 (116 bits) | 122 bit | | 1x^8192 + 1 | 2^226 - 2^26 + 1 (226 bits) | 124 bit | | 1x^16384 + 1 | 2^435 - 2^33 + 1 (435 bits) | 130 bit | | 1x^32768 + 1 | 2^889 - 2^54 - 2^53 - 2^52 + 1 (889 bits) | 127 bit | \----------------------------------------------------------------------/ | | These can be conveniently accessed using ChooserEvaluator.DefaultParameterOptions, which returns | the above list of options as a Dictionary, keyed by the degree of the polynomial modulus. The security | levels are estimated based on https://eprint.iacr.org/2015/046 and https://eprint.iacr.org/2017/047. | We strongly recommend that the user consult an expert in the security of RLWE-based cryptography to | estimate the security of a particular choice of parameters. | | The user can also easily choose their custom coefficient modulus. For best performance, it should | be a prime of the form 2^A - B, where B is congruent to 1 modulo 2*degree(PolyModulus), and as small | as possible. Roughly speaking, When the rest of the parameters are held fixed, increasing CoeffModulus | decreases the security level. Thus we would not recommend using a value for CoeffModulus much larger | than those listed above (the defaults). In general, we highly recommend the user to consult with an expert | in the security of RLWE-based cryptography when selecting their parameters to ensure an appropriate level | of security. | | The size of CoeffModulus affects the total noise budget that a freshly encrypted ciphertext has. More | precisely, every ciphertext starts with a certain amount of noise budget, which is consumed in homomorphic | operations - in particular in multiplication. Once the noise budget reaches 0, the ciphertext becomes | impossible to decrypt. The total noise budget in a freshly encrypted ciphertext is very roughly given by | log2(CoeffModulus/PlainModulus), so increasing coeff_modulus will allow the user to perform more | homomorphic operations on the ciphertexts without corrupting them. However, we must again warn that | increasing CoeffModulus has a strong negative effect on the security level. */ parms.SetCoeffModulus(ChooserEvaluator.DefaultParameterOptions[2048]); /* * Now we set the plaintext modulus. This can be any positive integer, even though here we take it to be a * power of two. A larger plaintext modulus causes the noise to grow faster in homomorphic multiplication, * and also lowers the maximum amount of noise in ciphertexts that the system can tolerate (see above). * On the other hand, a larger plaintext modulus typically allows for better homomorphic integer arithmetic, * although this depends strongly on which encoder is used to encode integers into plaintext polynomials. */ parms.SetPlainModulus(1 << 8); /* * Once all parameters are set, we need to call EncryptionParameters::validate(), which evaluates the * properties of the parameters, their validity for homomorphic encryption, and performs some important * pre-computation. */ parms.Validate(); /* * Plaintext elements in the FV scheme are polynomials (represented by the Plaintext class) with coefficients * integers modulo PlainModulus. To encrypt for example integers instead, one must use an "encoding scheme", * i.e. a specific way of representing integers as such polynomials. SEAL comes with a few basic encoders: * * IntegerEncoder: * Given an integer base b, encodes integers as plaintext polynomials in the following way. First, a base-b * expansion of the integer is computed. This expansion uses a "balanced" set of representatives of integers * modulo b as the coefficients. Namely, when b is off the coefficients are integers between -(b-1)/2 and * (b-1)/2. When b is even, the integers are between -b/2 and (b-1)/2, except when b is two and the usual * binary expansion is used (coefficients 0 and 1). Decoding amounts to evaluating the polynomial at x=b. * For example, if b=2, the integer 26 = 2^4 + 2^3 + 2^1 is encoded as the polynomial 1x^4 + 1x^3 + 1x^1. * When b=3, 26 = 3^3 - 3^0 is encoded as the polynomial 1x^3 - 1. In reality, coefficients of polynomials * are always unsigned integers, and in this case are stored as their smallest non-negative representatives * modulo plain_modulus. To create an integer encoder with a base b, use IntegerEncoder(PlainModulus, b). * If no b is given to the constructor, the default value of b=2 is used. * * FractionalEncoder: * Encodes fixed-precision rational numbers as follows. First expand the number in a given base b, possibly * truncating an infinite fractional part to finite precision, e.g. 26.75 = 2^4 + 2^3 + 2^1 + 2^(-1) + 2^(-2) * when b=2. For the sake of the example, suppose PolyModulus is 1x^1024 + 1. Next represent the integer part * of the number in the same way as in IntegerEncoder (with b=2 here). Finally, represent the fractional part * in the leading coefficients of the polynomial, but when doing so invert the signs of the coefficients. So * in this example we would represent 26.75 as the polynomial -1x^1023 - 1x^1022 + 1x^4 + 1x^3 + 1x^1. The * negative coefficients of the polynomial will again be represented as their negatives modulo PlainModulus. * * PolyCRTBuilder: * If PolyModulus is 1x^N + 1, PolyCRTBuilder allows "batching" of N plaintext integers modulo plain_modulus * into one plaintext polynomial, where homomorphic operations can be carried out very efficiently in a SIMD * manner by operating on such a "composed" plaintext or ciphertext polynomials. For full details on this very * powerful technique we recommend https://eprint.iacr.org/2012/565.pdf and https://eprint.iacr.org/2011/133. * * A crucial fact to understand is that when homomorphic operations are performed on ciphertexts, they will * carry over to the underlying plaintexts, and as a result of additions and multiplications the coefficients * in the plaintext polynomials will increase from what they originally were in freshly encoded polynomials. * This becomes a problem when the coefficients reach the size of PlainModulus, in which case they will get * automatically reduced modulo PlainModulus, and might render the underlying plaintext polynomial impossible * to be correctly decoded back into an integer or rational number. Therefore, it is typically crucial to * have a good sense of how large the coefficients will grow in the underlying plaintext polynomials when * homomorphic computations are carried out on the ciphertexts, and make sure that PlainModulus is chosen to * be at least as large as this number. * * Here we choose to create an IntegerEncoder with base b=2. */ var encoder = new IntegerEncoder(parms.PlainModulus); // Encode two integers as polynomials. const int value1 = 5; const int value2 = -7; var encoded1 = encoder.Encode(value1); var encoded2 = encoder.Encode(value2); Console.WriteLine("Encoded {0} as polynomial {1}", value1, encoded1); Console.WriteLine("Encoded {0} as polynomial {1}", value2, encoded2); // Generate keys. Console.WriteLine("Generating keys ..."); var generator = new KeyGenerator(parms); generator.Generate(); Console.WriteLine("... key generation completed"); var publicKey = generator.PublicKey; var secretKey = generator.SecretKey; // Encrypt values. Console.WriteLine("Encrypting values..."); var encryptor = new Encryptor(parms, publicKey); var encrypted1 = encryptor.Encrypt(encoded1); var encrypted2 = encryptor.Encrypt(encoded2); // Perform arithmetic on encrypted values. Console.WriteLine("Performing arithmetic on ecrypted numbers ..."); var evaluator = new Evaluator(parms); Console.WriteLine("Performing homomorphic negation ..."); var encryptedNegated1 = evaluator.Negate(encrypted1); Console.WriteLine("Performing homomorphic addition ..."); var encryptedSum = evaluator.Add(encrypted1, encrypted2); Console.WriteLine("Performing homomorphic subtraction ..."); var encryptedDiff = evaluator.Sub(encrypted1, encrypted2); Console.WriteLine("Performing homomorphic multiplication ..."); var encryptedProduct = evaluator.Multiply(encrypted1, encrypted2); // Decrypt results. Console.WriteLine("Decrypting results ..."); var decryptor = new Decryptor(parms, secretKey); var decrypted1 = decryptor.Decrypt(encrypted1); var decrypted2 = decryptor.Decrypt(encrypted2); var decryptedNegated1 = decryptor.Decrypt(encryptedNegated1); var decryptedSum = decryptor.Decrypt(encryptedSum); var decryptedDiff = decryptor.Decrypt(encryptedDiff); var decryptedProduct = decryptor.Decrypt(encryptedProduct); // Decode results. var decoded1 = encoder.DecodeInt32(decrypted1); var decoded2 = encoder.DecodeInt32(decrypted2); var decodedNegated1 = encoder.DecodeInt32(decryptedNegated1); var decodedSum = encoder.DecodeInt32(decryptedSum); var decodedDiff = encoder.DecodeInt32(decryptedDiff); var decodedProduct = encoder.DecodeInt32(decryptedProduct); // Display results. Console.WriteLine("Original = {0}; after encryption/decryption = {1}", value1, decoded1); Console.WriteLine("Original = {0}; after encryption/decryption = {1}", value2, decoded2); Console.WriteLine("Encrypted negate of {0} = {1}", value1, decodedNegated1); Console.WriteLine("Encrypted addition of {0} and {1} = {2}", value1, value2, decodedSum); Console.WriteLine("Encrypted subtraction of {0} and {1} = {2}", value1, value2, decodedDiff); Console.WriteLine("Encrypted multiplication of {0} and {1} = {2}", value1, value2, decodedProduct); // How much noise budget did we use in these operations? Console.WriteLine("Noise budget in encryption of {0}: {1} bits", value1, decryptor.InvariantNoiseBudget(encrypted1)); Console.WriteLine("Noise budget in encryption of {0}: {1} bits", value2, decryptor.InvariantNoiseBudget(encrypted2)); Console.WriteLine("Noise budget in sum: {0} bits", decryptor.InvariantNoiseBudget(encryptedSum)); Console.WriteLine("Noise budget in product: {0} bits", decryptor.InvariantNoiseBudget(encryptedProduct)); }
public static bool EncodeValueString(ReadOnlySpan <string> values, string?separator, Encoding?valueEncoding, Span <byte> buffer, out int length) { if (values.Length == 1) { return(EncodeValueString(values[0], valueEncoding, buffer, out length)); } if (values.Length == 0) { // TODO: this will be called with a string array from HttpHeaderCollection. Can we ever get a 0-length array from that? Assert if not. return(EncodeValueString(string.Empty, valueEncoding: null, buffer, out length)); } if (buffer.Length > 0) { Debug.Assert(separator != null); int valueLength; if (valueEncoding is null || ReferenceEquals(valueEncoding, Encoding.Latin1)) { valueLength = separator.Length * (values.Length - 1); foreach (string part in values) { valueLength += part.Length; } } else { valueLength = valueEncoding.GetByteCount(separator) * (values.Length - 1); foreach (string part in values) { valueLength += valueEncoding.GetByteCount(part); } } buffer[0] = 0; if (IntegerEncoder.Encode(valueLength, 7, buffer, out int nameLength)) { buffer = buffer.Slice(nameLength); if (buffer.Length >= valueLength) { if (valueEncoding is null) { string value = values[0]; EncodeValueStringPart(value, buffer); buffer = buffer.Slice(value.Length); for (int i = 1; i < values.Length; i++) { EncodeValueStringPart(separator, buffer); buffer = buffer.Slice(separator.Length); value = values[i]; EncodeValueStringPart(value, buffer); buffer = buffer.Slice(value.Length); } } else { int written = valueEncoding.GetBytes(values[0], buffer); buffer = buffer.Slice(written); for (int i = 1; i < values.Length; i++) { written = valueEncoding.GetBytes(separator, buffer); buffer = buffer.Slice(written); written = valueEncoding.GetBytes(values[i], buffer); buffer = buffer.Slice(written); } } length = nameLength + valueLength; return(true); } } }
/* * 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 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)}"); }
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; // 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(); } /* * 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 List <List <Ciphertext> > calculateWeightedSum(Model selectedModel, Query query) { int precision = selectedModel.Precision; //extract public key and encryption parameters from query //PublicKey publicKey = query.publicKey; List <List <Ciphertext> > encryptFeatureValues = query.encryptedFeatureValues; //extract model weights from Model object List <double[]> weights = selectedModel.Weights; int N_features = selectedModel.N_weights; //initialize integer encoder, encryptor, and evaluator IntegerEncoder encoder = new IntegerEncoder(_contextManager.Context); //Encryptor encryptor = new Encryptor(_contextManager.Context, publicKey); Evaluator evaluator = new Evaluator(_contextManager.Context); List <List <Ciphertext> > weightedSums = new List <List <Ciphertext> >(); //holds encrypted weighted sums for all classes for all samples int sampleIndex = 0; foreach (List <Ciphertext> sample in encryptFeatureValues) //for each sample in encrypted values { if (sample.Count != N_features) { HttpResponseException errorResponse = new HttpResponseException(); errorResponse.Status = 404; errorResponse.Value = "Sample " + sampleIndex.ToString() + " has " + sample.Count.ToString() + " features but " + N_features.ToString() + " expected"; throw errorResponse; } List <Ciphertext> sampleWeightedSums = new List <Ciphertext>(); //holds encrypted weighted sums for all classes for this sample foreach (double[] classWeights in weights) //for each class //for each sample, calculate the encrypted weighted feature value and store it in weightedFeatures { List <Ciphertext> weightedFeatures = new List <Ciphertext>(); for (int i = 0; i < sample.Count; i++) { Ciphertext curFeature = sample[i]; long curWeight = (long)(classWeights[i] * precision); if (curWeight == 0) { continue; } Plaintext scaledWeight = encoder.Encode(curWeight); Ciphertext weightedFeature = new Ciphertext(); evaluator.MultiplyPlain(curFeature, scaledWeight, weightedFeature); weightedFeatures.Add(weightedFeature); } //calculate encrypted weighted sum and append it to sampleWeightedSums Ciphertext weightedSum = new Ciphertext(); evaluator.AddMany(weightedFeatures, weightedSum); sampleWeightedSums.Add(weightedSum); //deallocate variables weightedFeatures = null; GC.Collect(); } weightedSums.Add(sampleWeightedSums); sampleIndex++; } return(weightedSums); //replace with return weighted sums }
public void EncodeTest() { EncryptionParameters parms = new EncryptionParameters(SchemeType.BFV) { PlainModulus = new SmallModulus(1024) }; SEALContext context = SEALContext.Create(parms); IntegerEncoder encoder = new IntegerEncoder(context); Plaintext plain = encoder.Encode(10); Assert.IsNotNull(plain); Assert.AreEqual(4ul, plain.CoeffCount); Assert.AreEqual(0ul, plain[0]); Assert.AreEqual(1ul, plain[1]); Assert.AreEqual(0ul, plain[2]); Assert.AreEqual(1ul, plain[3]); plain = encoder.Encode(13u); Assert.AreEqual(4ul, plain.CoeffCount); Assert.AreEqual(1ul, plain[0]); Assert.AreEqual(0ul, plain[1]); Assert.AreEqual(1ul, plain[2]); Assert.AreEqual(1ul, plain[3]); plain = encoder.Encode(20L); Assert.AreEqual(5ul, plain.CoeffCount); Assert.AreEqual(0ul, plain[0]); Assert.AreEqual(0ul, plain[1]); Assert.AreEqual(1ul, plain[2]); Assert.AreEqual(0ul, plain[3]); Assert.AreEqual(1ul, plain[4]); plain = encoder.Encode(15ul); Assert.AreEqual(4ul, plain.CoeffCount); Assert.AreEqual(1ul, plain[0]); Assert.AreEqual(1ul, plain[1]); Assert.AreEqual(1ul, plain[2]); Assert.AreEqual(1ul, plain[3]); BigUInt bui = new BigUInt("AB"); plain = encoder.Encode(bui); Assert.AreEqual(8ul, plain.CoeffCount); Assert.AreEqual(1ul, plain[0]); Assert.AreEqual(1ul, plain[1]); Assert.AreEqual(0ul, plain[2]); Assert.AreEqual(1ul, plain[3]); Assert.AreEqual(0ul, plain[4]); Assert.AreEqual(1ul, plain[5]); Assert.AreEqual(0ul, plain[6]); Assert.AreEqual(1ul, plain[7]); Plaintext plain2 = new Plaintext(); encoder.Encode(10, plain2); Assert.AreEqual(4ul, plain2.CoeffCount); Assert.AreEqual(0ul, plain2[0]); Assert.AreEqual(1ul, plain2[1]); Assert.AreEqual(0ul, plain2[2]); Assert.AreEqual(1ul, plain2[3]); encoder.Encode(13u, plain2); Assert.AreEqual(4ul, plain2.CoeffCount); Assert.AreEqual(1ul, plain2[0]); Assert.AreEqual(0ul, plain2[1]); Assert.AreEqual(1ul, plain2[2]); Assert.AreEqual(1ul, plain2[3]); encoder.Encode(20L, plain2); Assert.AreEqual(5ul, plain2.CoeffCount); Assert.AreEqual(0ul, plain2[0]); Assert.AreEqual(0ul, plain2[1]); Assert.AreEqual(1ul, plain2[2]); Assert.AreEqual(0ul, plain2[3]); Assert.AreEqual(1ul, plain2[4]); encoder.Encode(15ul, plain2); Assert.AreEqual(4ul, plain2.CoeffCount); Assert.AreEqual(1ul, plain2[0]); Assert.AreEqual(1ul, plain2[1]); Assert.AreEqual(1ul, plain2[2]); Assert.AreEqual(1ul, plain2[3]); encoder.Encode(bui, plain2); Assert.AreEqual(8ul, plain2.CoeffCount); Assert.AreEqual(1ul, plain2[0]); Assert.AreEqual(1ul, plain2[1]); Assert.AreEqual(0ul, plain2[2]); Assert.AreEqual(1ul, plain2[3]); Assert.AreEqual(0ul, plain2[4]); Assert.AreEqual(1ul, plain2[5]); Assert.AreEqual(0ul, plain2[6]); Assert.AreEqual(1ul, plain2[7]); }
public void EncodeTest() { IntegerEncoder encoder = new IntegerEncoder(GlobalContext.BFVContext); Plaintext plain = encoder.Encode(10); Assert.IsNotNull(plain); Assert.AreEqual(4ul, plain.CoeffCount); Assert.AreEqual(0ul, plain[0]); Assert.AreEqual(1ul, plain[1]); Assert.AreEqual(0ul, plain[2]); Assert.AreEqual(1ul, plain[3]); plain = encoder.Encode(13u); Assert.AreEqual(4ul, plain.CoeffCount); Assert.AreEqual(1ul, plain[0]); Assert.AreEqual(0ul, plain[1]); Assert.AreEqual(1ul, plain[2]); Assert.AreEqual(1ul, plain[3]); plain = encoder.Encode(20L); Assert.AreEqual(5ul, plain.CoeffCount); Assert.AreEqual(0ul, plain[0]); Assert.AreEqual(0ul, plain[1]); Assert.AreEqual(1ul, plain[2]); Assert.AreEqual(0ul, plain[3]); Assert.AreEqual(1ul, plain[4]); plain = encoder.Encode(15ul); Assert.AreEqual(4ul, plain.CoeffCount); Assert.AreEqual(1ul, plain[0]); Assert.AreEqual(1ul, plain[1]); Assert.AreEqual(1ul, plain[2]); Assert.AreEqual(1ul, plain[3]); BigUInt bui = new BigUInt("AB"); plain = encoder.Encode(bui); Assert.AreEqual(8ul, plain.CoeffCount); Assert.AreEqual(1ul, plain[0]); Assert.AreEqual(1ul, plain[1]); Assert.AreEqual(0ul, plain[2]); Assert.AreEqual(1ul, plain[3]); Assert.AreEqual(0ul, plain[4]); Assert.AreEqual(1ul, plain[5]); Assert.AreEqual(0ul, plain[6]); Assert.AreEqual(1ul, plain[7]); Plaintext plain2 = new Plaintext(); encoder.Encode(10, plain2); Assert.AreEqual(4ul, plain2.CoeffCount); Assert.AreEqual(0ul, plain2[0]); Assert.AreEqual(1ul, plain2[1]); Assert.AreEqual(0ul, plain2[2]); Assert.AreEqual(1ul, plain2[3]); encoder.Encode(13u, plain2); Assert.AreEqual(4ul, plain2.CoeffCount); Assert.AreEqual(1ul, plain2[0]); Assert.AreEqual(0ul, plain2[1]); Assert.AreEqual(1ul, plain2[2]); Assert.AreEqual(1ul, plain2[3]); encoder.Encode(20L, plain2); Assert.AreEqual(5ul, plain2.CoeffCount); Assert.AreEqual(0ul, plain2[0]); Assert.AreEqual(0ul, plain2[1]); Assert.AreEqual(1ul, plain2[2]); Assert.AreEqual(0ul, plain2[3]); Assert.AreEqual(1ul, plain2[4]); encoder.Encode(15ul, plain2); Assert.AreEqual(4ul, plain2.CoeffCount); Assert.AreEqual(1ul, plain2[0]); Assert.AreEqual(1ul, plain2[1]); Assert.AreEqual(1ul, plain2[2]); Assert.AreEqual(1ul, plain2[3]); encoder.Encode(bui, plain2); Assert.AreEqual(8ul, plain2.CoeffCount); Assert.AreEqual(1ul, plain2[0]); Assert.AreEqual(1ul, plain2[1]); Assert.AreEqual(0ul, plain2[2]); Assert.AreEqual(1ul, plain2[3]); Assert.AreEqual(0ul, plain2[4]); Assert.AreEqual(1ul, plain2[5]); Assert.AreEqual(0ul, plain2[6]); Assert.AreEqual(1ul, plain2[7]); }