IBM / fhe-toolkit-linux

IBM Fully Homomorphic Encryption Toolkit For Linux. This toolkit is a Linux based Docker container that demonstrates computing on encrypted data without decrypting it! The toolkit ships with two demos including a fully encrypted Machine Learning inference with a Neural Network and a Privacy-Preserving key-value search.
MIT License
1.43k stars 157 forks source link

Question about sending BinaryIO of context and pubKey to another party #175

Open DylanWangWQF opened 3 years ago

DylanWangWQF commented 3 years ago

Hi, @boland25 @deanthomasson . I have a question: when I generate a new context by reading from stringstream, these two context should be equal. But if I encrypt the vector using the oldContext.publickey, then decrypt it using the newContext.seckey. It failed due to different context. Could you give me some suggestions?

context.writeTo(ss);
Context newContext = Context::readFrom(ss);
cout << "Context isEqual: " << (newContext == meta.data->context) << endl; // result:1

SecKey secret_key(newContext);
secret_key.GenSecKey();
addSome1DMatrices(secret_key);
const PubKey& public_key = secret_key;
const helib::EncryptedArray& newEa = newContext.getEA();

cout << "PublicKey isEqual: " << (public_key == meta.data->publicKey) << endl; // result:0

vector<long> inputtest(256);
    for (long i = 0; i< 256; i++) {
        inputtest[i] = i;
    }

// oldContext.publicKey
Ctxt inputCtxt(meta.data->publicKey);
ea.encrypt(inputCtxt, meta.data->publicKey, inputtest);

//newContext.seckey
vector<long> outputtest1;
newEa.decrypt(inputCtxt, secret_key, outputtest1); // error: cannot decrypt due to different context
DylanWangWQF commented 3 years ago

Due to some reasons, write to file and read from file is not considered.

boland25 commented 3 years ago

@DylanWangWQF I would have to try this out myself, but if I remember right, you can't mix and match contexts. if you use the old context instead, does it work?

DylanWangWQF commented 3 years ago

@boland25 Sure, If I use the same context, it will work; But If I want to send thecontext, pk, sk to another trusted party, I have to write the context to stringstream and another party read from stringstream to get this context, right? We can see that the new and old context is equal according to the code

cout << "Context isEqual: " << (newContext == meta.data->context) << endl; // result:1

So, it seems that the generated pk and sk using these new and old context cannot be used to encrypt and decrypt.

DylanWangWQF commented 3 years ago

@boland25 @deanthomasson I'm thinking of another question about alpine-based HElib. could you help me understand it?

HElib is usually built against GLIBC, while Alpine Linux is based on the MUSL C library.

And for fhe-toolkit-linux project, it shows that we can successfully run helib in the alpine container. Why? (I'm doing some experiments with HElib in MUSL-based environment).

Thanks in advance!

boland25 commented 3 years ago

@DylanWangWQF I have not dug deep enough into the Alpine docker implementation of it as that was done by another team member but its building off of cmake and using the gcc compiler. There must be some sort of wrapper that is done under the hood that makes it happen, but I am not sure of this completely.

As for your bug, I have someone working on this to try and re-create it, and should have an answer to you shortly. Thanks for your patience!

DylanWangWQF commented 3 years ago

@boland25 Got it, looking forward to it! Many thanks for your reply!

boland25 commented 3 years ago

@DylanWangWQF can you please provide the source code that you were using where you ran into the issue so we can re-create?

DylanWangWQF commented 3 years ago

Hi, @boland25 Here is the test code, I remove other codes: https://github.com/DylanWangWQF/hetest It should return the context dismatch error.

For the current version of HElib, we cannot do like this: new Context(m,p,r), new Seckey(*context), etc..So how should we manage the used memory after running the code?

In the traditional way, we can new/delete or malloc/free to free memory.

But now, I don't understand the way of releasing memory since we must build the context using the contextbuilder() (no other choices). In addition, there are embedded class objects (like PAlgebra zMStar, PAlgebraMod alMod, etc..) when building context. Considering my design, I want to utilize the heap memory as much as possible and free the memory by myself.

Sry for my noise.

boland25 commented 3 years ago

@DylanWangWQF thanks for sending that over. I have someone working on re-creating your test. Bear with us, as he is only on the project part time so will take a bit to get a response. In regard to your last question, have you checked out the tutorial folder? There are a few different tutorials in there that might help, and you can use HEContext like this.... shared_ptr<HeContext> hePtr = HelibContext::create(HELIB_CKKS_8192);. When you are done using it, its a shared_ptr so you can just delete the object or remove it once its out of scope.

DylanWangWQF commented 3 years ago

@boland25 Many thanks for your reply! Here is another example to help us understand the issue.

    Context* activeTContext;
    unique_ptr<SecKey> activeSecKey;
    unique_ptr<PubKey> activePubKey;

void test::testStruct(){
    unsigned long p = 127;
    // Cyclotomic polynomial - defines phi(m)
    unsigned long m = 12800;
    // Hensel lifting (default = 1)
    unsigned long r = 1;
    // Number of bits of the modulus chain
    unsigned long bits = 119;
    // Number of columns of Key-Switching matrix (default = 2 or 3)
    unsigned long c = 2;

    std::cout << "Initialising context object..." << std::endl;
    helib::Context context = helib::ContextBuilder<helib::BGV>()
                                .m(m)
                                .p(p)
                                .r(r)
                                .bits(bits)
                                .c(c)
                                .build();
    helib::SecKey secret_key(context);
    secret_key.GenSecKey();
    helib::addSome1DMatrices(secret_key);
    const helib::PubKey& public_key = secret_key;

    stringstream ss;
    context.writeTo(ss);

    activeTContext = Context::readPtrFrom(ss);
    activeTContext->printout();

    // new generated pk and sk
    activeSecKey = make_unique<SecKey>(*activeTContext);
    activeSecKey->GenSecKey();
    addSome1DMatrices(*activeSecKey);
    activePubKey = make_unique<PubKey>(*activeSecKey);

    encryptt(*activeTContext, *activePubKey, *activeSecKey); // this works
    //  encryptt(*activeTContext, *activePubKey, secret_key); fail due to context dismatch
// or  encryptt(*activeTContext, public_key, *activeSecKey);  fail due to context dismatch
}

void test::encryptt(const Context& con, const PubKey& pk, const SecKey& sk){
    vector<long> inputtest(256);
    for (long i = 0; i< 256; i++) {
        inputtest[i] = i % 2;
    }
    cout << inputtest << endl;

    Ctxt ct(pk);

    vector<long> outputtest;
    con.getEA().encrypt(ct, pk, inputtest);
    stringstream css;
    ct.writeTo(css);

    string s1 = css.str();
    uint8_t* c1 = (uint8_t*)s1.c_str();
    uint8_t* c2 = nullptr;
    stringstream ess;
    string s2 = string(c1, c1 + s1.size());
    ess << s2;
    Ctxt newct = Ctxt::readFrom(ess, pk);

    con.getEA().decrypt(newct, sk, outputtest);
    cout << outputtest << endl;
}