Пример #1
0
        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);
        }
Пример #2
0
        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));
        }
Пример #3
0
        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));
        }
Пример #4
0
        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);
                    }
                }
            }
Пример #5
0
        /*
         * 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));
        }
Пример #6
0
        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)}");
        }
Пример #7
0
        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();
        }
Пример #8
0
        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
        }
Пример #9
0
        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]);
        }
Пример #10
0
        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]);
        }