Code Monkey home page Code Monkey logo

seal's People

Contributors

0xflotus avatar alexanderviand avatar bastienvialla avatar cheney-w avatar chrdavis avatar codedust avatar dkaidalov avatar dnat112 avatar elkanatovey avatar fboemer avatar fionser avatar florentclmichel avatar gelilaseifu avatar haochenuw avatar haoxuan40404 avatar imadchabounia avatar jharrilim avatar jlhcrawford avatar joshbeal avatar kimlaine avatar kiromaru avatar lwhsu avatar marinthiercelin avatar microsoftopensource avatar msftgits avatar parsanoori avatar s0l0ist avatar saffahyjp avatar sivanov-work avatar youben11 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

seal's Issues

add_many and multiply_many API should be extended

add_many and multiply_many API should be extended by:

  • making these variadic (allow any number of input arguments);
  • adding support for C++ input iterators, e.g. could pass myvec.begin() and myvec.end() for the range to operate on.

Effectiveness of the Karatsuba multiplication in ciphertext multiplication.

Description

To multiply two size-2 ciphertext, (c0, c1) and (d0, d1), we compute three values c0*d0, c0*d1 + c1*d0 and c1*d1.

Current Status

  • Currently, SEAL uses Karatsuba to compute the second value as
    c0*d1 + c1*d0 = (c0 + d0) * (c1 + d1) - (c0*d0 + c1*d1)
    which save one multiplication as the cost of two more additions and one more subtraction, since the first and the third values are computed after all.

Observation

  • However, these multiplication, addition, subtraction are done over the finite field, i.e., mod p. I found the one more addition and subtraction of the Karatsuba method is somehow expensive, because it increases the mis-prediction of CPU instructions.

Simpler is Better

  • If we directly compute the second value c0 * d1 + c1 * d0, we actually only need one modulo reduction. Because the two multiplications can be done with lazy reduction.
  • I have do some experiences with NFLlib, can found that the naive method can be $10% -- 50%$ faster.

Noise Budget and Modulus Switching

Is it possible to get an estimation of noise budget without the decryptor (or the secret key)? For example, a noise heuristic that maintains the upper bound on current noise in a ciphertext.

Conventionally, modulus switching is primarily used to make the noise growth linear, as opposed to exponential. However, in the BFV examples, it has been introduced as a tool to shave off primes (thereby reducing the bitlength of coefficient modulus) and improve computational efficiency.
Does it help in reducing noise growth in the BFV scheme as well? Will I observe exponential growth in noise without (manually) switching modulus?

Substantially lower noise budget on fresh encryptions in 3.3.0

We are seeing fresh encryptions of ciphertexts with poly_modulus_degree 4096 and higher have much less noise budget in 3.3.0 than they did in 3.2.0. This contradicts what is in Changes.md ("Moreover, fresh ciphertexts now have a larger noise budget.") so I'm wondering this is working as intended or not.

To demonstrate, I wrote a short program that just follows the example code to make a fresh ciphertext using batching and print its noise budget:

#include "seal/seal.h"

using namespace std;
using namespace seal;

int main() {
#ifdef SEAL_VERSION
    cout << "Microsoft SEAL version: " << SEAL_VERSION << endl;
#endif

    vector<size_t> degrees = {4096, 8192, 16384, 32768};

    for (size_t i = 0; i < degrees.size(); i++) {
        size_t degree = degrees.at(i);

        EncryptionParameters parms(scheme_type::BFV);
        parms.set_poly_modulus_degree(degree);
        parms.set_coeff_modulus(DefaultParams::coeff_modulus_128(degree));
        parms.set_plain_modulus(65537);
        auto context = SEALContext::Create(parms);

        KeyGenerator keygen(context);
        auto public_key = keygen.public_key();
        auto secret_key = keygen.secret_key();

        Encryptor encryptor(context, public_key);
        Decryptor decryptor(context, secret_key);
        BatchEncoder batch_encoder(context);

        size_t slot_count = batch_encoder.slot_count();
        vector<uint64_t> data(slot_count);
			
        data.at(0) = 1ULL;

        Plaintext plaintext;
        Ciphertext ciphertext;

        batch_encoder.encode(data, plaintext);
        encryptor.encrypt(plaintext, ciphertext);

        cout << "Fresh encryption noise budget for degree " << degree << ": " << decryptor.invariant_noise_budget(ciphertext) << " bits." << endl;
    }
}

When I compile this sample code against SEAL 3.2.0 I get the output:

Microsoft SEAL version: 3.2.0
Fresh encryption noise budget for degree 4096: 79 bits.
Fresh encryption noise budget for degree 8192: 188 bits.
Fresh encryption noise budget for degree 16384: 407 bits.
Fresh encryption noise budget for degree 32768: 848 bits.

When I take the same code and compile against 3.3.0 (changing DefaultParams::coeff_modulus_128(degree) to CoeffModulus::BFVDefault(degree) following the updated example code) I get the following output:

Microsoft SEAL version: 3.3.0
Fresh encryption noise budget for degree 4096: 40 bits.
Fresh encryption noise budget for degree 8192: 142 bits.
Fresh encryption noise budget for degree 16384: 357 bits.
Fresh encryption noise budget for degree 32768: 794 bits.

The noise budget is much lower in all cases; for degree 4096 almost half the initial noise budget is lost.

Is there any way to restore the old noise budgets in 3.3.0? We are using SEAL at my organization and this issue makes it not worth it for us to upgrade from 3.2.0.

Context parameter values combination to operate on large integers

My configuration is as follows:

seal::EncryptionParameters parms(scheme_type::BFV);
size_t poly_modulus_degree = 16384;
parms.set_poly_modulus_degree(poly_modulus_degree);
parms.set_coeff_modulus(CoeffModulus::BFVDefault(poly_modulus_degree));
parms.set_plain_modulus(256);

The results are accurate when computing encrypted integers with values lesser than 10.
If I go with even bigger integers say over 100, I get "plain is not valid for encryption parameters" for a simple operation like adding.

Typo

In the second CKKS example, the comment says We use a slightly smaller scale in this example. But it's still 2^60 like in the first one.

Regarding the new features of v3.3.0

Hi there,
The released new version (3.3.0) has some nice properties, but there are little explanations.

  1. What is the mathematical background of preserving the noise budget after relinearization and rotation operations?
  2. What is the exact definition of "special prime"? why using this special prime?
  3. The new version also brings larger noise budgets of fresh ciphertext, what is the basic idea behind that?

Looking forward to detailed explanations or references.

best

Noise budget above 0 in BFV example

Went through the bfv basics example, and came across this:

/*
Finally, we multiply (x^2 + 1) * (x + 1)^2 * 2.
*/
print_line(__LINE__);
cout << "Compute encrypted_result (2(x^2+1)(x+1)^2)." << endl;
Ciphertext encrypted_result;
Plaintext plain_two("2");
evaluator.multiply_plain_inplace(x_sq_plus_one, plain_two);
evaluator.multiply(x_sq_plus_one, x_plus_one_sq, encrypted_result);
cout << " + size of encrypted_result: " << encrypted_result.size() << endl;
cout << " + noise budget in encrypted_result: "
<< decryptor.invariant_noise_budget(encrypted_result) << " bits" << endl;
cout << "NOTE: Decryption can be incorrect if noise budget is zero." << endl;
cout << endl;
cout << "~~~~~~ A better way to calculate 2(x^2+1)(x+1)^2. ~~~~~~" << endl;
/*
Noise budget has reached 0, which means that decryption cannot be expected
to give the correct result. This is because both ciphertexts x_sq_plus_one
and x_plus_one_sq consist of 3 polynomials due to the previous squaring
operations, and homomorphic operations on large ciphertexts consume much more
noise budget than computations on small ciphertexts. Computing on smaller
ciphertexts is also computationally significantly cheaper.

To me the comment seems to suggest that the noise budget should be 0 when the operations are done. However when I'm running them the noise budget end up on 7 to 10 bits.

CUDA support

Is there any ongoing work to add CUDA support to SEAL? Would you expect to see a significant speedup with the way FHE is implemented in SEAL?

I want to get more slots in one ciphertext.Can i put the polyModulusDegree bigger than 32768?

I am sorry to bother you.
I'm just beginning to learn to use seal.When i try to let the polyModulusDegree greater than 32768,the program was incorrectly reported.Because i want to get more slots.
And i notice that "In Microsoft SEAL the degree of the polynomial modulus must be a power
of 2 (e.g. 1024, 2048, 4096, 8192, 16384, or 32768)."
Why the slots only the half of the polyModulusDegree?
Can i get more slots in one ciphertext?
Thank you!

Different results in Linux and macOS

I implemented the same code in both Linux and macOS, but the results are different. Here's a small example to show the difference: Just push back the value -11668621335293.000000 785 times into a vector, encrypt then decrypt the value, and the results are different between Linux and macOS. The Linux version resulted with a much larger fluctuation.

macOS version: 10.13.6
Linux version: Ubuntu 16.04.6 LTS

Scheme is CKKS, poly_modulus_degree 32768.

Here's the code (the utils.h is used for print_parameters and print_vector as in \examples):

#include <vector>
#include "utils.h"
#include "seal/seal.h"

using namespace std;
using namespace seal;

int main(){
    EncryptionParameters parms(scheme_type::CKKS);
    size_t poly_modulus_degree = 32768;
    parms.set_poly_modulus_degree(poly_modulus_degree);
    parms.set_coeff_modulus(CoeffModulus::Create(
        poly_modulus_degree, { 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60 }));
    double scale = pow(2.0, 360);
    auto context = SEALContext::Create(parms);
    print_parameters(context);
    
    KeyGenerator keygen(context);
    auto public_key = keygen.public_key();
    auto secret_key = keygen.secret_key();
    Encryptor encryptor(context, public_key);
    Decryptor decryptor(context, secret_key);
    CKKSEncoder encoder(context);

    vector<double> input_vector;
    for(int i = 0; i < 785; i++){
        input_vector.push_back(-11668621335293.000000);
    }

    Plaintext input_plain;
    encoder.encode(input_vector, scale, input_plain);
    Ciphertext input_cipher;
    encryptor.encrypt(input_plain, input_cipher);
    decryptor.decrypt(input_cipher, input_plain);
    encoder.decode(input_plain, input_vector);
    print_vector(input_vector);
    return 0;
}

The results from macOS:

/
| Encryption parameters :
|   scheme: CKKS
|   poly_modulus_degree: 32768
|   coeff_modulus size: 840 (60 + 60 + 60 + 60 + 60 + 60 + 60 + 60 + 60 + 60 + 60 + 60 + 60 + 60) bits
\

    [ -11668621335293.000, -11668621335293.002, -11668621335293.000, -11668621335293.000, ..., 0.000, -0.000, 0.001, 0.001 ]

The results from Linux:

/
| Encryption parameters :
|   scheme: CKKS
|   poly_modulus_degree: 32768
|   coeff_modulus size: 840 (60 + 60 + 60 + 60 + 60 + 60 + 60 + 60 + 60 + 60 + 60 + 60 + 60 + 60) bits
\

    [ -11668621335268.215, -11668621335271.973, -11668621335271.979, -11668621335279.500, ..., -0.342, -0.342, -0.029, 0.033 ]

What could cause this difference?

Accuracy along the output vector with CKKS

Regarding the use of CKKS without batching, I was wondering why I observe different accuracy along the output vector. I noticed on multiple examples that the first 3 or 4 values of the vector have less accuracy compared to the following ones.
Here is one example showing this behavior, I have as input 98.123456789, and I simply encrypt then decrypt it.

// Parameters
EncryptionParameters parms(scheme_type::CKKS);
size_t poly_modulus_degree = 8192;
parms.set_poly_modulus_degree(poly_modulus_degree);
parms.set_coeff_modulus(CoeffModulus::Create(poly_modulus_degree, { 40, 30, 30, 40 }));
double scale = pow(2.0, 30);

auto context = SEALContext::Create(parms);
KeyGenerator keygen(context);
auto public_key = keygen.public_key();
auto secret_key = keygen.secret_key();
auto relin_keys = keygen.relin_keys();
Encryptor encryptor(context, public_key);
Evaluator evaluator(context);
Decryptor decryptor(context, secret_key);
CKKSEncoder encoder(context);
size_t slot_count = encoder.slot_count();

Plaintext plain, plain_output;
Ciphertext cipher;
vector<double> res;

float val = 98.123456789;

// Encode then encrypt the value
encoder.encode(val, scale, plain);
encryptor.encrypt(plain, cipher);

// Decrypt then decode the cipher
decryptor.decrypt(cipher, plain_output);
encoder.decode(plain_output, res);

cout << "Result = " << endl;
std::cout << std::setprecision(20);
int acc;
for (std::size_t i = 0; i < 20; i++)
{
        std::cout << res[i];
        acc = (-1) * round(val>res[i] ? log2(val-res[i]) : log2(res[i]-val));
        std::cout << ", accuracy : " << acc << "\n";
}

This is the output I get:

Result = 
98.123208870796077008, accuracy : 12
98.123450072802540944, accuracy : 17
98.123455446539892932, accuracy : 18
98.12346096075420121, accuracy : 19
98.123461018082238638, accuracy : 19
98.123459733768370938, accuracy : 20
98.123459644911221744, accuracy : 20
98.123459607719823339, accuracy : 20
98.123458459306192481, accuracy : 21
98.123459128922007721, accuracy : 22
98.123459203155206865, accuracy : 21
98.123457288371128016, accuracy : 19
98.123459230694592748, accuracy : 21
98.123458432719559141, accuracy : 21
98.123458786141469545, accuracy : 24
98.123457520335165327, accuracy : 20
98.123459134442754248, accuracy : 22
98.123459030688607641, accuracy : 23
98.123459054974986771, accuracy : 22
98.123457867560333057, accuracy : 20

Can Relin & Galois Keys be exposed like the Public Key?

Not an issue, but is it safe to share Relin & Galois keys as you would with a public key?

I'm trying to share these keys to allow a 3rd party to perform relinearizations and galois vector rotations on ciphertexts, but I don't know if this is safe. What are the implications (if any) of exposing these keys publically?

BTW, great job on this library and the amazing documentation.

Thanks in advance!

reverse_bits template type - 32bits/64bits mismatch

I am currently working on making SEAL usable on ARM microcontrollers, and I discovered a bug related to the automatic selection of the 32bits/64bits variant of the reverse_bits function.

With GCC 7.3.1 and 8.2.1 for ARM processors, the 64 bits overload of the reverse_bits function is resolved instead of the 32bits one when called with a 32bits size_t argument (as is the case in the SmallNTT tables generation process, here). When the argument is instead a uint32_t there is no problem and the correct (32bits) overload is used.

The debugger output shows that the template<typename T, typename = std::enable_if<is_uint64_v<T>>> definition is resolved as <false, void> when the 64bits function is used with the 32bits argument.

This might also be a more general bug related to 32bits GCC, I am not proficient enough in C++ to understand the SFINAE issue here, and I would be really happy to understand why the overload resolution is incorrect.

For the records, I also tried compiling SEAL for the x86 architecture on Windows (using MSVC compiler), and I did not encounter any issue there).

I understand that microcontrollers are not the priority for SEAL, but I can say that I have successfully managed to encrypt a plaintext using the default parameters for a degree-1024 polynomial. To this end, I modified the reverse_bits overload resolution to make it more generic (I will propose a PR with my solution in a few minutes).

I open this issue to document the "bug", and to see if anyone with experience with GCC could explain the problem here.

data format

Could you tell me the format of publickey.save(), secretkey.save() and ciphertext.save(). There is no doc to explain these.

Regarding saving and loading of EncryptionParameters for CKKS scheme

In the void EncryptionParameters::Save(const EncryptionParameters &parms, ostream &stream) and EncryptionParameters EncryptionParameters::Load(istream &stream) functions, there is writing and reading of plain_modulus.

As the CKKS scheme does not require plain_modulus, an logic error "unsupported scheme" is thrown due to set_plain_modulus() when loading CKKS EncryptionParameters.

The checking of writing and saving of plain_modulus depending on scheme should be performed in Save() and Load() instead.

Thanks.

BFV binary decoding

Hi,

Binary decoding of integer 1 returns a negative value with IntegerEncoder in SEAL 3.2.

Example:

            EncryptionParameters parms(scheme_type::BFV);
            parms.set_poly_modulus_degree(8192);                       
            parms.set_coeff_modulus(DefaultParams::coeff_modulus_128(8192));
            parms.set_plain_modulus(2);
            auto context = SEALContext::Create(parms); 
            IntegerEncoder encoder(context);
            int32_t integer(1);
            Plaintext plaintext=encoder.encode(integer);
            cout << "encode = " << plaintext.to_string() <<endl ;
            cout << "decode = " << encoder.decode_int32(plaintext) << endl;
    }

To-be-confirmed fix:

Replace

bool coeff_is_negative = coeff >= coeff_neg_threshold_;

in file intencoder.cpp, line 183 by:

bool coeff_is_negative = coeff > coeff_neg_threshold_;

Thanks.

Can I build this project on Visual Studio 2019 ?

Can I build this project on Visual Studio 2019? What's kind modification I need to make, or it is not possible?

I tried on VS 2019 and this is what I got in out put:

1>------ Build started: Project: SEAL, Configuration: Debug x64 ------
1>Configure Microsoft SEAL through CMake
1>Configuring Microsoft SEAL through CMake
1>Found CMake at C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\cmake.exe
1>Running CMake configuration in C:\Users\RustedWizard\Downloads\SEAL-master\SEAL-master\native\src.config
1>Not searching for unused variables given on the command line.
1>CMake Error at CMakeLists.txt:6 (project):
1> Generator
1>
1> Visual Studio 15 2017
1>-- Configuring incomplete, errors occurred!
1>See also "C:/Users/RustedWizard/Downloads/SEAL-master/SEAL-master/native/src/.config/CMakeFiles/CMakeOutput.log".
1>
1> could not find any instance of Visual Studio.
1>
1>
1>
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\MSBuild\Microsoft\VC\v150\Microsoft.CppCommon.targets(128,5): error MSB3073: The command ""C:\Users\RustedWizard\Downloads\SEAL-master\SEAL-master\native\src\CMakeConfig.cmd" Debug "C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\Common7\IDE" "C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.16.27023\include;;C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.16.27023\atlmfc\include;;C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Auxiliary\VS\include;;C:\Program Files (x86)\Windows Kits\10\Include\10.0.16299.0\ucrt;;;C:\Program Files (x86)\Windows Kits\10\Include\10.0.16299.0\um;C:\Program Files (x86)\Windows Kits\10\Include\10.0.16299.0\shared;C:\Program Files (x86)\Windows Kits\10\Include\10.0.16299.0\winrt;C:\Program Files (x86)\Windows Kits\NETFXSDK\4.6.1\Include\um;C:\Program Files (x86)\Windows Kits\NETFXSDK\4.6.1\Include\um;"
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\MSBuild\Microsoft\VC\v150\Microsoft.CppCommon.targets(128,5): error MSB3073: :VCEnd" exited with code 1.
1>Done building project "SEAL.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

Also, I tried to modify the generator option in CmakeConfig.cmd to "%CMAKEPATH%" .. -G "Visual Studio 16 2019" and I got following output:

1>------ Build started: Project: SEAL, Configuration: Debug x64 ------
1>Configure Microsoft SEAL through CMake
1>Configuring Microsoft SEAL through CMake
1>Found CMake at C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\cmake.exe
1>Running CMake configuration in C:\Users\RustedWizard\Downloads\SEAL-master\SEAL-master\native\src.config
1>Not searching for unused variables given on the command line.
1>CMake Error : error : generator : Visual Studio 16 2019
1>Does not match the generator used previously: Visual Studio 15 2017
1>Either remove the CMakeCache.txt file and CMakeFiles directory or choose a different binary directory.
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\MSBuild\Microsoft\VC\v150\Microsoft.CppCommon.targets(128,5): error MSB3073: The command ""C:\Users\RustedWizard\Downloads\SEAL-master\SEAL-master\native\src\CMakeConfig.cmd" Debug "C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\Common7\IDE" "C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.16.27023\include;;C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.16.27023\atlmfc\include;;C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Auxiliary\VS\include;;C:\Program Files (x86)\Windows Kits\10\Include\10.0.16299.0\ucrt;;;C:\Program Files (x86)\Windows Kits\10\Include\10.0.16299.0\um;C:\Program Files (x86)\Windows Kits\10\Include\10.0.16299.0\shared;C:\Program Files (x86)\Windows Kits\10\Include\10.0.16299.0\winrt;C:\Program Files (x86)\Windows Kits\NETFXSDK\4.6.1\Include\um;C:\Program Files (x86)\Windows Kits\NETFXSDK\4.6.1\Include\um;"
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\MSBuild\Microsoft\VC\v150\Microsoft.CppCommon.targets(128,5): error MSB3073: :VCEnd" exited with code 1.
1>Done building project "SEAL.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

Regarding "scale of out bounds" error in SEAL 3.3 CKKS

Hi,

The following code is working fine in SEAL 3.2 CKKS:

    EncryptionParameters parms(scheme_type::CKKS);
    parms.set_poly_modulus_degree(8192);

    vector<SmallModulus> q_primes;
    q_primes.push_back(DefaultParams::small_mods_60bit(0));
    q_primes.push_back(DefaultParams::small_mods_60bit(1));
    parms.set_coeff_modulus(q_primes);

    auto context = SEALContext::Create(parms);
    CKKSEncoder encoder(context);
    auto scale = static_cast<double>(parms.coeff_modulus().back().value());
 
    vector<double> values(4096, 0);
    values[0] = 0.123;
    Plaintext plain_value;
    encoder.encode(values, scale, plain_value);

The equivalent code is throwing "scale of out bounds" error in SEAL 3.3 CKKS:

    EncryptionParameters parms(scheme_type::CKKS);
    parms.set_poly_modulus_degree(8192);

    vector<SmallModulus> q_primes = CoeffModulus::Create(8192, {60,60});
    parms.set_coeff_modulus(q_primes);

    auto context = SEALContext::Create(parms);
    CKKSEncoder encoder(context);
    auto scale = static_cast<double>(parms.coeff_modulus().back().value());

    vector<double> values(4096, 0);
    values[0] = 0.123;
    Plaintext plain_value;
    encoder.encode(values, scale, plain_value);

If scale is chosen less than 60 bit e.g. pow(2, 40), the encode() will proceed fine without error.

Is it an intended behavioural change in SEAL 3.3 compared to SEAL 3.2?

Is this related to the "special prime" being consumed?

In other words, the "special prime" is included in the overall loqQ but not being available for usage for encoding, encryption etc?

Thanks.

Serializing Public Key and Context

I understand that a Ciphertext can be serialized using the Ciphertext::save(std::ostream &) method. I also saw a test for the same. However, I did not see one for the keys or the context.
Are they serialized along with the ciphertext?
To encrypt a plaintext or perform operations on a ciphertext at a different machine, I will require context and the public key. Is there a procedure to serialize them?
Moreover, is there an example or a test that demonstrates this usecase (serializing various components of the scheme)?

A question about Creating a NuGet package

Creating a NuGet package
。。。。。。。
You will need to:

1.Compile binaries
i. native\src\SEAL.vcxproj
ii. dotnet\native\SEALNetNative.vcxproj
iii.dotnet\src\SEALNet.csproj
2.Download the NuGet command line tool
Run the command below to create NuGet package
Add NuGet package reference to your .NET projects

How should I compile binaries?Can you give me a lot of details?
Looking forward to your reply.

Add use_count for MemoryPoolHandle

Just a suggestion, it might help users for debugging memory issues if we can conveniently know how many objects are holding the shared ownership of the pool pointed by MemoryPoolHandle.

For example, add the following method to MemoryPoolHandle:

long int use_count() const noexcept { return pool_.use_count(); }

noise budget lower than expected for 3.3.1

It seems like for poly_modulus_degree equal to 16384 and a 40 bit plaintext modulus which enables batching, the noise budget of a encryption of zero is 340 bits but noise budget of a encryption of random vector with has only 310 bits of noise budget. The code below reproduces this issue.

#include "examples.h"

using namespace std;
using namespace seal;

void example_noise_budget()
{

    EncryptionParameters parms(scheme_type::BFV);


    size_t poly_modulus_degree = 16384;
    parms.set_poly_modulus_degree(poly_modulus_degree);


    parms.set_coeff_modulus(CoeffModulus::BFVDefault(poly_modulus_degree));


    parms.set_plain_modulus(PlainModulus::Batching(poly_modulus_degree, 40));


    auto context = SEALContext::Create(parms);

    print_line(__LINE__);
    cout << "Set encryption parameters and print" << endl;
    print_parameters(context);


    KeyGenerator keygen(context);
    PublicKey public_key = keygen.public_key();
    SecretKey secret_key = keygen.secret_key();

    Encryptor encryptor(context, public_key);


    Decryptor decryptor(context, secret_key);
    BatchEncoder batch_encoder(context);

    size_t slot_count = batch_encoder.slot_count();

   
    
    random_device rd;

    vector<uint64_t> data_1(slot_count, 0);
    vector<uint64_t> data_2(slot_count ,0); 
    for(size_t i =0; i < slot_count; i++){
	data_1[i] = rd() % parms.plain_modulus().value();
    }    


    Plaintext plain_1(parms.poly_modulus_degree(), 0);
    batch_encoder.encode(data_1, plain_1);

    Plaintext plain_2(parms.poly_modulus_degree(), 0);
    batch_encoder.encode(data_2, plain_2);

    Ciphertext encrypted_1(context);
    encryptor.encrypt(plain_1, encrypted_1);

    Ciphertext encrypted_2(context);
    encryptor.encrypt(plain_2, encrypted_2);


    cout << " noise budget of fresh encryption = "
        << decryptor.invariant_noise_budget(encrypted_1)  << endl;
    
    cout << " noise budget of fresh encryption of zero = " << decryptor.invariant_noise_budget(encrypted_2) << endl;  

}

Homomorphic operations on floating point numbers

Hello everyone

Is there any way of performing addition and multiplication over float? I noticed there is the CKKS encoder, but one aspect I didn't understand well is that it operates over a vector. I was wondering if there is a form of operating over two Cyphertexts instead of vectors. Does anyone have an example like this?

Best regards

Hints to circumvent scale out of bounds

Hello everyone :)

I have an application, in which I perform some homomorphic multiplications.
When I perform x2^2, x2x, and x2x3, the result is correct.
But when performing the last multiplication, x2*x7, the application simply breakes with the following error:

terminate called after throwing an instance of 'std::invalid_argument'
what(): scale out of bounds

This is the snippet code of function:
`
Ciphertext g(Ciphertext x, Evaluator* evaluator, RelinKeys relin_keys){

    Ciphertext x1 = x;
    Ciphertext x2 = x;
    (*evaluator).square_inplace(x2);
    (*evaluator).relinearize_inplace(x2, relin_keys);

    Ciphertext x3 = x2;
    (*evaluator).multiply_inplace(x3,x);
    (*evaluator).relinearize_inplace(x3, relin_keys);

    Ciphertext x5 = x2;
    (*evaluator).multiply_inplace(x5,x3);
    (*evaluator).relinearize_inplace(x5, relin_keys);

    Ciphertext x7 = x2;
    (*evaluator).multiply_inplace(x7,x5);
    (*evaluator).relinearize_inplace(x7, relin_keys);

    return x7;

}`

This is the vector I am trying:
vector<double> input{ 2.2 , 0, 1, -3, -0.5 };

And this is my setup:
`EncryptionParameters parms = createParameters();

    auto context = SEALContext::Create(parms);
    print_line(__LINE__);
    cout << "Set encryption parameters and print" << endl;
    print_parameters(context);
    cout << endl;

    KeyGenerator keygen(context);
    auto public_key = keygen.public_key();
    auto secret_key = keygen.secret_key();
    auto relin_keys = keygen.relin_keys();

    Encryptor encryptor(context, public_key);
    Evaluator evaluator(context);
    Decryptor decryptor(context, secret_key);

    CKKSEncoder encoder(context);

    size_t slot_count = encoder.slot_count();
    cout << "Number of slots: " << slot_count << endl;

    double scale = pow(2.0, 30);`

Could anyone point a direction for me to solve this issue?
Actually, I will need to perform lots of multiplications, and I was thinking that the relinearize function would allow me to lighten my polynomial so that it could handle several multiplications.

Best regards :)

Tests fail to link despite availability of libgtest.a

MacOS Mojave 10.14.2, Xcode-10.1.

I've modified tests/CMakeLists.txt this way:

diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index ae15119..7be1116 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -18,9 +18,11 @@ if(SEAL_ENFORCE_HE_STD_SECURITY)
 endif()
 
 # Import Google target_link_libraries
-find_library(GTEST gtest)
+find_library(GTEST gtest HINTS /opt/local/lib /opt/local)
 if (NOT GTEST)
     message(FATAL_ERROR "Failed to find Google Test library required for unit tests")
+else(NOT GTEST)
+    message("Found library at ${GTEST}")
 endif()
 
 # Link SEAL

Screen log is self-explanatory:

$ cmake ..
-- The CXX compiler identification is AppleClang 10.0.0.10001145
-- Check for working CXX compiler: /opt/local/bin/clang++
-- Check for working CXX compiler: /opt/local/bin/clang++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Looking for C++ include pthread.h
-- Looking for C++ include pthread.h - found
-- Looking for pthread_create
-- Looking for pthread_create - found
-- Found Threads: TRUE  
-- SEAL detected (version 3.1.0)
Found library at /opt/local/lib/libgtest.a
-- Configuring done
-- Generating done
-- Build files have been written to: /Users/ur20980/src/SEAL/tests/build
$ make
Scanning dependencies of target sealtest
[  2%] Building CXX object CMakeFiles/sealtest.dir/seal/testrunner.cpp.o
[  5%] Building CXX object CMakeFiles/sealtest.dir/seal/batchencoder.cpp.o
[  7%] Building CXX object CMakeFiles/sealtest.dir/seal/biguint.cpp.o
[ 10%] Building CXX object CMakeFiles/sealtest.dir/seal/ciphertext.cpp.o
[ 12%] Building CXX object CMakeFiles/sealtest.dir/seal/ckks.cpp.o
[ 15%] Building CXX object CMakeFiles/sealtest.dir/seal/context.cpp.o
[ 17%] Building CXX object CMakeFiles/sealtest.dir/seal/encoder.cpp.o
[ 20%] Building CXX object CMakeFiles/sealtest.dir/seal/encryptionparams.cpp.o
[ 23%] Building CXX object CMakeFiles/sealtest.dir/seal/encryptor.cpp.o
[ 25%] Building CXX object CMakeFiles/sealtest.dir/seal/evaluator.cpp.o
[ 28%] Building CXX object CMakeFiles/sealtest.dir/seal/galoiskeys.cpp.o
[ 30%] Building CXX object CMakeFiles/sealtest.dir/seal/intarray.cpp.o
[ 33%] Building CXX object CMakeFiles/sealtest.dir/seal/keygenerator.cpp.o
[ 35%] Building CXX object CMakeFiles/sealtest.dir/seal/memorymanager.cpp.o
[ 38%] Building CXX object CMakeFiles/sealtest.dir/seal/plaintext.cpp.o
[ 41%] Building CXX object CMakeFiles/sealtest.dir/seal/publickey.cpp.o
[ 43%] Building CXX object CMakeFiles/sealtest.dir/seal/randomgen.cpp.o
[ 46%] Building CXX object CMakeFiles/sealtest.dir/seal/relinkeys.cpp.o
[ 48%] Building CXX object CMakeFiles/sealtest.dir/seal/secretkey.cpp.o
[ 51%] Building CXX object CMakeFiles/sealtest.dir/seal/smallmodulus.cpp.o
[ 53%] Building CXX object CMakeFiles/sealtest.dir/seal/util/clipnormal.cpp.o
[ 56%] Building CXX object CMakeFiles/sealtest.dir/seal/util/common.cpp.o
[ 58%] Building CXX object CMakeFiles/sealtest.dir/seal/util/hash.cpp.o
[ 61%] Building CXX object CMakeFiles/sealtest.dir/seal/util/locks.cpp.o
[ 64%] Building CXX object CMakeFiles/sealtest.dir/seal/util/mempool.cpp.o
[ 66%] Building CXX object CMakeFiles/sealtest.dir/seal/util/numth.cpp.o
[ 69%] Building CXX object CMakeFiles/sealtest.dir/seal/util/polyarith.cpp.o
[ 71%] Building CXX object CMakeFiles/sealtest.dir/seal/util/polyarithmod.cpp.o
[ 74%] Building CXX object CMakeFiles/sealtest.dir/seal/util/polyarithsmallmod.cpp.o
[ 76%] Building CXX object CMakeFiles/sealtest.dir/seal/util/polycore.cpp.o
[ 79%] Building CXX object CMakeFiles/sealtest.dir/seal/util/randomtostd.cpp.o
[ 82%] Building CXX object CMakeFiles/sealtest.dir/seal/util/smallntt.cpp.o
[ 84%] Building CXX object CMakeFiles/sealtest.dir/seal/util/stringtouint64.cpp.o
[ 87%] Building CXX object CMakeFiles/sealtest.dir/seal/util/uint64tostring.cpp.o
[ 89%] Building CXX object CMakeFiles/sealtest.dir/seal/util/uintarith.cpp.o
[ 92%] Building CXX object CMakeFiles/sealtest.dir/seal/util/uintarithmod.cpp.o
[ 94%] Building CXX object CMakeFiles/sealtest.dir/seal/util/uintarithsmallmod.cpp.o
[ 97%] Building CXX object CMakeFiles/sealtest.dir/seal/util/uintcore.cpp.o
[100%] Linking CXX executable /Users/ur20980/src/SEAL/bin/sealtest
ld: library not found for -lgtest
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make[2]: *** [/Users/ur20980/src/SEAL/bin/sealtest] Error 1
make[1]: *** [CMakeFiles/sealtest.dir/all] Error 2
make: *** [all] Error 2
$ 

Implementing Halevi's RNS.

  • It seems the current SEAL implements Bajard et al. 's residue number system (RNS).
  • Halevi et al. has proposed an improved version for this, see Section 3.3
  • For the improved version, we can save one scalar-ciphertext multiplication in the relinearization.

How to Print Ciphertext ?

Hello, I need your help. Thank you!
I am learning the SEAL example. In example_basic_i(), use enoode.encode(value), we can get plain. And plain.to_string() can print the plaintext. After encrypting, we get encryptend1. I want to print encrypted1, but I can't find a method to print it.
Please help me, Thank you!

Amortizing operations when rotating a ciphertext multiple times

Hello! I am currently re-implementing the Gazelle protocol using SEAL. In the paper, they use a technique they deem 'rotation hoisting' (sec 5.5) , which is essentially amortizing the cost of certain repeated operations when rotating the same ciphertext multiple times.

I haven't looked to closely at how exactly SEAL does rotation under the hood, but before I do I was simply wondering:

  • Does SEAL already include this functionality?
  • If not, would it be feasible to implement this and how would I go about doing it?

Thanks for your time!

Possible inconsistent size reported for Plaintext in save_size

When serializing/deserializing Plaintexts, there was an inconsistent size estimation resulting from an improper type when computing ComprSizeEstimate.

Previously, when running the following code:

plaintext.h line ~572:

SEAL_NODISCARD inline std::streamoff save_size(
            compr_mode_type compr_mode) const
        {
            std::size_t members_size = Serialization::ComprSizeEstimate(
                util::add_safe(
                    sizeof(parms_id_),
                    sizeof(coeff_count_), // <--------------------- Offending member
                    sizeof(scale_),
                    util::safe_cast<std::size_t>(
                        data_.save_size(compr_mode_type::none))),
                compr_mode);
            std::cout << "Plaintext::save_size member_size (" << members_size << ")" <<std::endl;

            auto size = util::safe_cast<std::streamoff>(util::add_safe(
                    sizeof(Serialization::SEALHeader),
                    members_size
                ));
            std::cout << "Plaintext::save_size size (" << size << ")" <<std::endl;

            return size;
//            return util::safe_cast<std::streamoff>(util::add_safe(
//                sizeof(Serialization::SEALHeader),
//                members_size
//            ));
        }

Results in the incorrect member_size:

Plaintext::save_size member_size (32836)
Plaintext::save_size size (32852)

This, in turn, becomes an issue when deserializing a saved Plaintext stream where the stream.tellg() position calculation throws here:

serialization.cpp line ~657:

if (header.size != stream.tellg() - stream_start_pos)

Replacing it with the following:

SEAL_NODISCARD inline std::streamoff save_size(
            compr_mode_type compr_mode) const
        {
            std::size_t members_size = Serialization::ComprSizeEstimate(
                util::add_safe(
                    sizeof(parms_id_),
                    sizeof(uint64_t), // coeff_count_ <--------------------- Modified member
                    sizeof(scale_),
                    util::safe_cast<std::size_t>(
                        data_.save_size(compr_mode_type::none))),
                compr_mode);
            std::cout << "Plaintext::save_size member_size (" << members_size << ")" <<std::endl;

            auto size = util::safe_cast<std::streamoff>(util::add_safe(
                    sizeof(Serialization::SEALHeader),
                    members_size
                ));
            std::cout << "Plaintext::save_size size (" << size << ")" <<std::endl;

            return size;
//            return util::safe_cast<std::streamoff>(util::add_safe(
//                sizeof(Serialization::SEALHeader),
//                members_size
//            ));

Results in the correct member_size:

Plaintext::save_size member_size (32840)
Plaintext::save_size size (32856)

This change in Plaintext.h resembles the uint64_t setting for coeff_mod_count_ in Ciphertext.cpp.

Parameters to reproduce (pseudo code):

EncParms: {
    schemeType: BFV,
    polyModulusDegree: 4096,
    security: tc128,
    plainModulus: Batching(polyModulusDegree: 4096, bitsize: 20)
    coeffModulus: BFVDefault(polyModulusDegree: 4096,
          security: tc128)
}

Context: {
    expandModChain: true,
    security: tc128
}

Create a Plaintext and encode 4096 (max size of polyModulusDegree) misc values to it (within range)

Save the plaintext to a stream. (where the header size is computed incorrectly)

Attempt to load from the same stream. (where it throws during runtime)

Exception tests fail on VS2019, apparently Microsoft.VisualStudio.TestPlatform.Common.resources is not found

I realize this is not a supported configuration according to README.md, but maybe it's worth reporting since VS2019 is already very common and its community license more permissive than with VS2017. I'm on Windows 10 fi-FI with latest updates and SDKs and the project updated.

Apparently the issue is that file Microsoft.VisualStudio.TestPlatform.Common.resources is not found. I try to look deeper at this some point, but I wonder if anyone has pointers? Would it be OK to open an issue to track update to VS2019?

<edit: The update branch is at https://github.com/veikkoeeva/SEAL/tree/update-to-vs2019 .
<edit 2: There is a similar question at Visual Studio Developer Community, but the solution proposed there, adding a missing package, isn't the problem here.

Of the whole set two fails when run in VS2019, the stack I receive is

ExceptionsTest
Source: BatchEncoderTests.cs line: 219
Duration: 40 ms

Message:
Assert.ThrowsException failed. Threw exception FileNotFoundException, but exception ArgumentException was expected.
Exception Message: Could not load the specified file.
Stack Trace: at System.Runtime.Loader.AssemblyLoadContext.ResolveUsingEvent(AssemblyName assemblyName)
at System.Runtime.Loader.AssemblyLoadContext.ResolveUsingResolvingEvent(IntPtr gchManagedAssemblyLoadContext, AssemblyName assemblyName)
at Microsoft.Research.SEAL.NativeMethods.BatchEncoder_Encode(IntPtr thisptr, IntPtr plain, IntPtr pool)
at Microsoft.Research.SEAL.BatchEncoder.Encode(Plaintext plain, MemoryPoolHandle pool) in C:\projektit\SEAL\dotnet\src\BatchEncoder.cs:line 155
at SEALNetTest.BatchEncoderTests.<>c__DisplayClass4_0.b__6() in C:\projektit\SEAL\dotnet\tests\BatchEncoderTests.cs:line 249
at Microsoft.VisualStudio.TestTools.UnitTesting.Assert.ThrowsException[T](Action action, String message, Object[] parameters)
Stack Trace:
at BatchEncoderTests.ExceptionsTest() in BatchEncoderTests.cs line: 249

TheFailure

When debugging the tests, the actual error looks like
actualerror

and from there

$exception | {"Could not load the specified File.":"Microsoft.VisualStudio.TestPlatform.Common.resources"} | System.IO.FileNotFoundException

Support for hoisting in rotations

Hi folks. Is there any plan for, or existing work on, implementing hoisting in SEAL? That is, ordering the constituent parts of the rotation algorithm (for CRT batched plaintexts) so that some of those parts can be reused (instead of recalculated) in subsequent rotations? This is described in Section 5 of Faster Homomorphic Linear Transformations in HELib by Halevi and Shoup.

Hoisting would be very useful to me. I am considering implementing it myself, but (what I believe is) the relevant function is a bit... involved, so I don't want to dig in until I'm sure no one else has done it already.

Or perhaps there's a way to achieve hoisting with the current interface that I have missed? If so, please let me know!

Thanks in advance and thanks heaps for your work on SEAL.

CKKS default coeffmodulus

Hello,

I noticed there is a helper method CoeffModulus::BFVDefault which returns a good default vector of SmallModulus. Is there a way to generate the same for CKKS? If it will not be planned, how do you suggest to create a good vector of SmallModulus for the three security types (128, 192, 256) with say 4096, 8192, and 16384 poly modulus degrees?

Thank you!

Regarding CKKS decoding

Hi, there seems to be NAN returned during decoding of the CKKS scheme when the coefficient modulus is more than some multiples of small modulus prime.

Below is an example (20 50-bit small modulus) of just encoding and then decoding:
/ Encryption parameters:
| scheme: CKKS
| poly_modulus_degree: 8192
| coeff_modulus size: 1000 bits
\ noise_standard_deviation: 3.2

Number of slots: 4096
scale = 50 bits
Input vector:
[ 0.000, 1.100, 2.200, 3.300, ..., 0.000, 0.000, 0.000, 0.000 ]
decode output:
[ -nan, -nan, -nan, -nan, ..., -nan, -nan, -nan, -nan ]

Thanks.

Compiling SEAL with the -fPIC Flag

Is it possible to add an option when using CMake to create the libseal.a to pass some optional flags e.g the -fPIC flag? This will make libseal.a portable, which is important when building own libraries that link against libseal.a.

For now I'm changing the CMakeLists.txt of SEAL manually after each version update by adding the option set(CMAKE_POSITION_INDEPENDENT_CODE ON).

Regarding CoeffModulus::Create() for CKKS

The following 2 lines below both give a value of 60 using total_coeff_modulus_bit_count():

  1. <SmallModulus> q_primes = CoeffModulus::Create(8192, { 60});
    parms.set_coeff_modulus(q_primes);

  2. <SmallModulus> q_primes = CoeffModulus::Create(8192, { 60, 60});
    parms.set_coeff_modulus(q_primes);

Is it a bug? Thanks.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.