public void DecodeTest() { EncryptionParameters parms = new EncryptionParameters(SchemeType.BFV) { PlainModulus = new SmallModulus(1024) }; SEALContext context = SEALContext.Create(parms); IntegerEncoder encoder = new IntegerEncoder(context); Plaintext plain = new Plaintext("0x^5 + 1x^4 + 1x^3 + 1x^1 + 0"); Assert.AreEqual(6ul, plain.CoeffCount); ulong resultU64 = encoder.DecodeUInt64(plain); Assert.AreEqual(26UL, resultU64); long resultI64 = encoder.DecodeInt64(plain); Assert.AreEqual(26L, resultI64); uint resultU32 = encoder.DecodeUInt32(plain); Assert.AreEqual(26U, resultU32); int resultI32 = encoder.DecodeInt32(plain); Assert.AreEqual(26, resultI32); BigUInt bui = encoder.DecodeBigUInt(plain); Assert.IsNotNull(bui); Assert.AreEqual(0, bui.CompareTo(26ul)); }
public void DecodeTest() { IntegerEncoder encoder = new IntegerEncoder(GlobalContext.BFVContext); Plaintext plain = new Plaintext("0x^5 + 1x^4 + 1x^3 + 1x^1 + 0"); Assert.AreEqual(6ul, plain.CoeffCount); ulong resultU64 = encoder.DecodeUInt64(plain); Assert.AreEqual(26UL, resultU64); long resultI64 = encoder.DecodeInt64(plain); Assert.AreEqual(26L, resultI64); uint resultU32 = encoder.DecodeUInt32(plain); Assert.AreEqual(26U, resultU32); int resultI32 = encoder.DecodeInt32(plain); Assert.AreEqual(26, resultI32); BigUInt bui = encoder.DecodeBigUInt(plain); Assert.IsNotNull(bui); Assert.AreEqual(0, bui.CompareTo(26ul)); }
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(); }
public int DecryptInt(Ciphertext EncryptedInteger) { //Takes in an encrypted Integer and Decrypts then Decodes to Int32. Plaintext plaintextOutput = new Plaintext(); decryptor.Decrypt(EncryptedInteger, plaintextOutput); //Decode the decrypted output. int intDecoded; intDecoded = encoder.DecodeInt32(plaintextOutput); return(intDecoded); }
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)); }
/* * 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)}"); }