intel / pailliercryptolib

Intel Paillier Cryptosystem Library is an open-source library which provides accelerated performance of a partial homomorphic encryption (HE), named Paillier cryptosystem, by utilizing Intel® IPP-Crypto on AVX512IFMA instructions. Intel Paillier Cryptosystem Library is certified for ISO compliance.
Apache License 2.0
70 stars 18 forks source link

Want to know how to serialize and deserialize public key correctly #60

Closed cgair closed 1 year ago

cgair commented 1 year ago

I'm on branch ipcl_v2.0.0 and wanna do serialization and deserialization. I wrote somethig like this,( remove the private keyword)

#include <cereal/archives/json.hpp>
#include <fstream>
  {
  std::ofstream os("key.json");
  cereal::JSONOutputArchive archive(os); // Create an output archive

    key.pub_key.save(archive, 1);
  } // archive goes out of scope, ensuring all contents are flushed

  {
    std::ifstream is("key.json");
    cereal::JSONInputArchive archive(is); // Create an input archive

    ipcl::PublicKey newpk = ipcl::PublicKey(1, 2048);

    newpk.load(archive, 1);

    std::vector<uint32_t> n(num_total);

    for (int i = 0; i < num_total; i++) {
      n[i] = i;
    }

    ipcl::PlainText pt = ipcl::PlainText(n);
    ipcl::CipherText ct = newpk.encrypt(pt);

}

but after I loads the public key and do encryption, I got:

malloc(): invalid size (unsorted) and I got the backtrace:

malloc(): corrupted top size
malloc(): corrupted top size
malloc(): corrupted top size

Thread 1 "example_encrypt" received signal SIGABRT, Aborted.
__GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
50      ../sysdeps/unix/sysv/linux/raise.c: No such file or directory.
(gdb) bt
#0  __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
#1  0x00007ffff7bc6859 in __GI_abort () at abort.c:79
#2  0x00007ffff7c3126e in __libc_message (action=action@entry=do_abort, fmt=fmt@entry=0x7ffff7d5b298 "%s\n") at ../sysdeps/posix/libc_fatal.c:155
#3  0x00007ffff7c392fc in malloc_printerr (str=str@entry=0x7ffff7d59569 "malloc(): corrupted top size") at malloc.c:5347
#4  0x00007ffff7c3c6ba in _int_malloc (av=av@entry=0x7ffff7d90b80 <main_arena>, bytes=bytes@entry=144) at malloc.c:4107
#5  0x00007ffff7c3e299 in __GI___libc_malloc (bytes=144) at malloc.c:3066
#6  0x00007ffff7e5a1f4 in __cxa_allocate_exception () from /lib/x86_64-linux-gnu/libstdc++.so.6
#7  0x00007ffff7fade8e in ipcl::ippMBModExpWrapper(std::vector<BigNumber, std::allocator<BigNumber> > const&, std::vector<BigNumber, std::allocator<BigNumber> > const&, std::vector<BigNumber, std::allocator<BigNumber> > const&) [clone ._omp_fn.0] [clone .cold] ()
   from /opt/intel/ipcl/lib/ipcl/libipcl.so.2.0.0
#8  0x00007ffff7b4f8e6 in GOMP_parallel () from /lib/x86_64-linux-gnu/libgomp.so.1
#9  0x00007ffff7fb8c71 in ipcl::ippModExp(std::vector<BigNumber, std::allocator<BigNumber> > const&, std::vector<BigNumber, std::allocator<BigNumber> > const&, std::vector<BigNumber, std::allocator<BigNumber> > const&) () from /opt/intel/ipcl/lib/ipcl/libipcl.so.2.0.0
#10 0x00007ffff7fb8db2 in ipcl::modExp(std::vector<BigNumber, std::allocator<BigNumber> > const&, std::vector<BigNumber, std::allocator<BigNumber> > const&, std::vector<BigNumber, std::allocator<BigNumber> > const&) () from /opt/intel/ipcl/lib/ipcl/libipcl.so.2.0.0
#11 0x00007ffff7fb32dc in ipcl::PublicKey::getDJNObfuscator(unsigned long) const () from /opt/intel/ipcl/lib/ipcl/libipcl.so.2.0.0
#12 0x00007ffff7fb3930 in ipcl::PublicKey::applyObfuscator(std::vector<BigNumber, std::allocator<BigNumber> >&) const () from /opt/intel/ipcl/lib/ipcl/libipcl.so.2.0.0
#13 0x00007ffff7fb3bbc in ipcl::PublicKey::raw_encrypt(std::vector<BigNumber, std::allocator<BigNumber> > const&, bool) const () from /opt/intel/ipcl/lib/ipcl/libipcl.so.2.0.0
#14 0x00007ffff7fb3d44 in ipcl::PublicKey::encrypt(ipcl::PlainText const&, bool) const () from /opt/intel/ipcl/lib/ipcl/libipcl.so.2.0.0
#15 0x0000555555557d40 in main ()

what did I miss?

cgair commented 1 year ago

Is there anyone can help? I'm really in a hurry

justalittlenoob commented 1 year ago

Hi @cgair
First of all, there's a problem with the way you make a PublicKey object.

ipcl::PublicKey newpk = ipcl::PublicKey(1, 2048);

The 1st parameter should be n in Pailler scheme. The number 1 is not satisfying the condition. The detail info about how to make a n is there https://github.com/intel/pailliercryptolib/blob/34f11cdf6758b8fe61a5c88331902f031567d6b6/ipcl/keygen.cpp#L92-L117

cgair commented 1 year ago

Oh I see, thanks!@justalittlenoob What's more I'm trying to restore a CipherText from a vector, i.e., using constructor CipherText(const PublicKey& pk, const std::vector<uint32_t>& n_v); the procedure is as following:

  ipcl::KeyPair key = ipcl::generateKeypair(2048, true);
  std::vector<uint32_t> x(1);
  ipcl::PlainText pt_x = ipcl::PlainText(x);
  ipcl::CipherText ct_x = key.pub_key.encrypt(pt_x);
  std::vector<uint32_t> v = dt_add_ctx_cty.getElementVec(0);
  ipcl::CipherText ct_xx =   ipcl::CipherText(key.pub_key, v);

Unfortunately, it seems that I've missed something because when decrypting it I got some wrong result.

justalittlenoob commented 1 year ago

Hi @cgair
The information you provided is too little. I don't know how dt_add_ctx_cty was calculated. If you want to calculate CT+PT, you can refer to these two examples example 1: https://github.com/intel/pailliercryptolib/blob/34f11cdf6758b8fe61a5c88331902f031567d6b6/test/test_ops.cpp#L208
example 2: https://github.com/intel/pailliercryptolib/blob/34f11cdf6758b8fe61a5c88331902f031567d6b6/test/test_ops.cpp#L248

cgair commented 1 year ago

Well, or I should put it in this way: I try

  std::vector<uint32_t> n = {13};
  ipcl::PlainText pt_n1 = ipcl::PlainText(n);
  ipcl::CipherText ct_n1 = key.pub_key.encrypt(pt_n1);
  BigNumber ct_bg = ct_n1.getElement(0);
  // get hex string
  std::string s;
  ct_bg.num2hex(s);
  std::vector<char> chars(s.begin(), s.end());
  char *c = &chars[0];
  BigNumber ct_bgg2 = BigNumber(c);
  std::cout << "Construct BigBumber(from hex string):" << ct_bgg2 << std::endl;
  assert (ct_bg == ct_bgg2);

but the assertion failed, I was wondering what was going wrong?

cgair commented 1 year ago

@justalittlenoob BigNumber's save and load function works fine(aka I can restore a serialized BigNumber correctly), so maybe there's something wrong in this function? https://github.com/intel/pailliercryptolib/blob/34f11cdf6758b8fe61a5c88331902f031567d6b6/ipcl/bignum.cpp#L67

justalittlenoob commented 1 year ago

Hi @cgair
Thank you for the detail info.

  1. The issue is fixed in PR #62 , please update the development branch and try it again.
  2. In the homomorphic encryption process, the ciphertext obtained each time is different because the encryption process is based on a random number. Therefore, encrypting the same number twice does not result in the same ciphertext. However, if the two different ciphertext can be decrypted to obtain the same plaintext, then the encryption process is normal. I have made a simple modification to your code, you can refer to it.
    
    std::vector<uint32_t> n = {13};
    ipcl::PlainText pt_n1 = ipcl::PlainText(n);
    ipcl::CipherText ct_n1 = key.pub_key.encrypt(pt_n1);
    BigNumber ct_bg = ct_n1.getElement(0);
    // get hex string
    std::string s;
    ct_bg.num2hex(s);
    // std::vector<char> chars(s.begin(), s.end());
    // char *c = &chars[0];
    const char* c = s.c_str();
    BigNumber ct_bgg2 = BigNumber(c);

ipcl::CipherText ct2(key.pub_key, ct_bgg2); ipcl::PlainText dt = key.priv_key.decrypt(ct2);

EXPECT_EQ(pt_n1.getElement(0), dt.getElement(0)); // ---> These two values are the same

xhuan28 commented 1 year ago

@cgair I wrote a unit test of public key serialization and deserialization for your reference(https://github.com/intel/pailliercryptolib/pull/63)

cgair commented 1 year ago

@xhuan28 thanks, this really help.

cgair commented 1 year ago

@justalittlenoob thanks for your help, I'm still unclear about some conceptions of paillier cryptolib ecosystem and will try to figure it out.