Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Why deserialization of CipherText is PlainText? #81

Open
lzjluzijie opened this issue Apr 12, 2024 · 6 comments
Open

Why deserialization of CipherText is PlainText? #81

lzjluzijie opened this issue Apr 12, 2024 · 6 comments

Comments

@lzjluzijie
Copy link

ipcl::PlainText ct_after;

If I change that PlainText to CipherText, there would have segmentation fault.

I think the test be something like this:

void testSerialize() {
  const uint32_t num_values = 100;
  auto keys = ipcl::generateKeypair(768);
  auto pk = keys.pub_key;
  auto sk = keys.priv_key;

  std::random_device dev;
  std::mt19937 rng(dev());
  std::uniform_int_distribution<std::mt19937::result_type> dist(0, UINT_MAX);
  std::vector<uint32_t> exp_value(num_values);
  for (int i = 1; i < num_values; i++) {
    exp_value[i] = dist(rng);
  }

  ipcl::PlainText pt = ipcl::PlainText(exp_value);
  ipcl::CipherText ct = pk.encrypt(pt);

  std::ostringstream os;
  ipcl::serializer::serialize(os, ct);
  ipcl::CipherText ct_after;
  std::istringstream is(os.str());
  ipcl::serializer::deserialize(is, ct_after);

  ipcl::PlainText pt_after = sk.decrypt(ct_after);
  for (int i = 0; i < num_values; i++) {
    std::vector<uint32_t> v = pt.getElementVec(i);
    std::vector<uint32_t> v_after = pt_after.getElementVec(i);

    if (v[0] != v_after[0]) {
      std::cerr << "Error: " << v[0] << " != " << v_after[0] << std::endl;
    }
  }
}

but it failed with segmentation fault

==10631== Invalid read of size 8
==10631==    at 0x4862245: ipcl::PublicKey::create(BigNumber const&, int, bool) (in /opt/intel/ipcl1/lib/ipcl/libipcl.so.2.0.0)
==10631==    by 0x4862553: ipcl::PublicKey::create(BigNumber const&, int, BigNumber const&, int) (in /opt/intel/ipcl1/lib/ipcl/libipcl.so.2.0.0)
==10631==    by 0x458354: load<cereal::PortableBinaryInputArchive> (pub_key.hpp:161)
==10631==    by 0x458354: member_load<cereal::PortableBinaryInputArchive, ipcl::PublicKey> (access.hpp:287)
==10631==    by 0x458354: processImpl<ipcl::PublicKey> (cereal.hpp:1058)
==10631==    by 0x458354: process<ipcl::PublicKey&> (cereal.hpp:853)
==10631==    by 0x458354: operator()<ipcl::PublicKey&> (cereal.hpp:730)
==10631==    by 0x458354: serialize<cereal::PortableBinaryInputArchive, ipcl::PublicKey&> (portable_binary.hpp:291)
==10631==    by 0x458354: processImpl<cereal::NameValuePair<ipcl::PublicKey&> > (cereal.hpp:925)
==10631==    by 0x458354: process<cereal::NameValuePair<ipcl::PublicKey&> > (cereal.hpp:853)
==10631==    by 0x458354: process<cereal::base_class<ipcl::BaseText>, cereal::NameValuePair<ipcl::PublicKey&> > (cereal.hpp:862)
==10631==    by 0x458354: operator()<cereal::base_class<ipcl::BaseText>, cereal::NameValuePair<ipcl::PublicKey&> > (cereal.hpp:730)
==10631==    by 0x458354: serialize<cereal::PortableBinaryInputArchive> (ciphertext.hpp:73)
==10631==    by 0x458354: member_serialize<cereal::PortableBinaryInputArchive, ipcl::CipherText> (access.hpp:275)
==10631==    by 0x458354: processImpl<ipcl::CipherText> (cereal.hpp:1038)
==10631==    by 0x458354: process<ipcl::CipherText&> (cereal.hpp:853)
==10631==    by 0x458354: operator()<ipcl::CipherText&> (cereal.hpp:730)
==10631==    by 0x458354: void ipcl::serializer::deserialize<ipcl::CipherText>(std::istream&, ipcl::CipherText&) (serialize.hpp:34)
==10631==    by 0x44D535: testSerialize() (test.cpp:437)
==10631==    by 0x40F57D: main (main.cpp:8)
==10631==  Address 0x18 is not stack'd, malloc'd or (recently) free'd
==10631==
==10631==
==10631== Process terminating with default action of signal 11 (SIGSEGV)
==10631==  Access not within mapped region at address 0x18
==10631==    at 0x4862245: ipcl::PublicKey::create(BigNumber const&, int, bool) (in /opt/intel/ipcl1/lib/ipcl/libipcl.so.2.0.0)
==10631==    by 0x4862553: ipcl::PublicKey::create(BigNumber const&, int, BigNumber const&, int) (in /opt/intel/ipcl1/lib/ipcl/libipcl.so.2.0.0)
==10631==    by 0x458354: load<cereal::PortableBinaryInputArchive> (pub_key.hpp:161)
==10631==    by 0x458354: member_load<cereal::PortableBinaryInputArchive, ipcl::PublicKey> (access.hpp:287)
==10631==    by 0x458354: processImpl<ipcl::PublicKey> (cereal.hpp:1058)
==10631==    by 0x458354: process<ipcl::PublicKey&> (cereal.hpp:853)
==10631==    by 0x458354: operator()<ipcl::PublicKey&> (cereal.hpp:730)
==10631==    by 0x458354: serialize<cereal::PortableBinaryInputArchive, ipcl::PublicKey&> (portable_binary.hpp:291)
==10631==    by 0x458354: processImpl<cereal::NameValuePair<ipcl::PublicKey&> > (cereal.hpp:925)
==10631==    by 0x458354: process<cereal::NameValuePair<ipcl::PublicKey&> > (cereal.hpp:853)
==10631==    by 0x458354: process<cereal::base_class<ipcl::BaseText>, cereal::NameValuePair<ipcl::PublicKey&> > (cereal.hpp:862)
==10631==    by 0x458354: operator()<cereal::base_class<ipcl::BaseText>, cereal::NameValuePair<ipcl::PublicKey&> > (cereal.hpp:730)
==10631==    by 0x458354: serialize<cereal::PortableBinaryInputArchive> (ciphertext.hpp:73)
==10631==    by 0x458354: member_serialize<cereal::PortableBinaryInputArchive, ipcl::CipherText> (access.hpp:275)
==10631==    by 0x458354: processImpl<ipcl::CipherText> (cereal.hpp:1038)
==10631==    by 0x458354: process<ipcl::CipherText&> (cereal.hpp:853)
==10631==    by 0x458354: operator()<ipcl::CipherText&> (cereal.hpp:730)
==10631==    by 0x458354: void ipcl::serializer::deserialize<ipcl::CipherText>(std::istream&, ipcl::CipherText&) (serialize.hpp:34)
==10631==    by 0x44D535: testSerialize() (test.cpp:437)
==10631==    by 0x40F57D: main (main.cpp:8)

the line test.cpp:437 is ipcl::PlainText pt_after = sk.decrypt(ct_after);. Did I make any mistake? Thank you!

@lzjluzijie
Copy link
Author

OK, I added a dummy values and init ct_after using ipcl::CipherText(pk, values), and the test passed. But is it the right way to use serialization?

void testSerialize() {
  const uint32_t num_values = 100;
  auto keys = ipcl::generateKeypair(768);
  auto pk = keys.pub_key;
  auto sk = keys.priv_key;

  std::random_device dev;
  std::mt19937 rng(dev());
  std::uniform_int_distribution<std::mt19937::result_type> dist(0, UINT_MAX);
  std::vector<uint32_t> exp_value(num_values);
  for (int i = 1; i < num_values; i++) {
    exp_value[i] = dist(rng);
  }

  ipcl::PlainText pt = ipcl::PlainText(exp_value);
  ipcl::CipherText ct = pk.encrypt(pt);

  std::ostringstream os;
  ipcl::serializer::serialize(os, ct);

  std::vector<uint32_t> values(num_values);
  ipcl::CipherText ct_after = ipcl::CipherText(pk, values);
  std::istringstream is(os.str());
  ipcl::serializer::deserialize(is, ct_after);

  ipcl::PlainText pt_after = sk.decrypt(ct_after);
  for (int i = 0; i < num_values; i++) {
    std::vector<uint32_t> v = pt.getElementVec(i);
    std::vector<uint32_t> v_after = pt_after.getElementVec(i);
    std::cout << v[0] << " " << v_after[0] << std::endl;

    if (v[0] != v_after[0]) {
      std::cerr << "Error: " << v[0] << " != " << v_after[0] << std::endl;
      exit(1);
    }
  }
}

@justalittlenoob
Copy link
Contributor

OK, I added a dummy values and init ct_after using ipcl::CipherText(pk, values), and the test passed. But is it the right way to use serialization?

void testSerialize() {
  const uint32_t num_values = 100;
  auto keys = ipcl::generateKeypair(768);
  auto pk = keys.pub_key;
  auto sk = keys.priv_key;

  std::random_device dev;
  std::mt19937 rng(dev());
  std::uniform_int_distribution<std::mt19937::result_type> dist(0, UINT_MAX);
  std::vector<uint32_t> exp_value(num_values);
  for (int i = 1; i < num_values; i++) {
    exp_value[i] = dist(rng);
  }

  ipcl::PlainText pt = ipcl::PlainText(exp_value);
  ipcl::CipherText ct = pk.encrypt(pt);

  std::ostringstream os;
  ipcl::serializer::serialize(os, ct);

  std::vector<uint32_t> values(num_values);
  ipcl::CipherText ct_after = ipcl::CipherText(pk, values);
  std::istringstream is(os.str());
  ipcl::serializer::deserialize(is, ct_after);

  ipcl::PlainText pt_after = sk.decrypt(ct_after);
  for (int i = 0; i < num_values; i++) {
    std::vector<uint32_t> v = pt.getElementVec(i);
    std::vector<uint32_t> v_after = pt_after.getElementVec(i);
    std::cout << v[0] << " " << v_after[0] << std::endl;

    if (v[0] != v_after[0]) {
      std::cerr << "Error: " << v[0] << " != " << v_after[0] << std::endl;
      exit(1);
    }
  }
}

I think this is correct.
There is ciphertext serialization test, you can refer to it.

TEST(SerialTest, CipherText) {

@lzjluzijie
Copy link
Author

OK, I added a dummy values and init ct_after using ipcl::CipherText(pk, values), and the test passed. But is it the right way to use serialization?

void testSerialize() {
  const uint32_t num_values = 100;
  auto keys = ipcl::generateKeypair(768);
  auto pk = keys.pub_key;
  auto sk = keys.priv_key;

  std::random_device dev;
  std::mt19937 rng(dev());
  std::uniform_int_distribution<std::mt19937::result_type> dist(0, UINT_MAX);
  std::vector<uint32_t> exp_value(num_values);
  for (int i = 1; i < num_values; i++) {
    exp_value[i] = dist(rng);
  }

  ipcl::PlainText pt = ipcl::PlainText(exp_value);
  ipcl::CipherText ct = pk.encrypt(pt);

  std::ostringstream os;
  ipcl::serializer::serialize(os, ct);

  std::vector<uint32_t> values(num_values);
  ipcl::CipherText ct_after = ipcl::CipherText(pk, values);
  std::istringstream is(os.str());
  ipcl::serializer::deserialize(is, ct_after);

  ipcl::PlainText pt_after = sk.decrypt(ct_after);
  for (int i = 0; i < num_values; i++) {
    std::vector<uint32_t> v = pt.getElementVec(i);
    std::vector<uint32_t> v_after = pt_after.getElementVec(i);
    std::cout << v[0] << " " << v_after[0] << std::endl;

    if (v[0] != v_after[0]) {
      std::cerr << "Error: " << v[0] << " != " << v_after[0] << std::endl;
      exit(1);
    }
  }
}

I think this is correct. There is ciphertext serialization test, you can refer to it.

TEST(SerialTest, CipherText) {

But why ct_after has type PlainText?

ipcl::PlainText ct_after;

@justalittlenoob
Copy link
Contributor

This is a good question. To be honest, it is possible to use types PlainText or CipherText in this place, because they both inherit from BaseText. The real place for serialization is in BaseText.
For the convenience of initialization, we chosen to use PlainText. Of course, you can change this line to something like:
std::vector<uint32_t> zero(num_values, 0);
ipcl::CipherText ct_after(keys.pub_key, zero);
the results will be the same. If you think this is easier to understand.

@lzjluzijie
Copy link
Author

Thank you. So the initialization ipcl::CipherText ct_after(keys.pub_key, zero) is not encryption using pub_key?

@justalittlenoob
Copy link
Contributor

Thank you. So the initialization ipcl::CipherText ct_after(keys.pub_key, zero) is not encryption using pub_key?

If you initialize a ciphertext directly, then the 2nd parameter should be the corresponding ciphertext (encrypted).
PlainText and CipherText are essentially containers. Store content through a vector. It does not care whether the stored content is encrypted or unencrypted.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants