C++ 使用二进制存档的boost序列化时出错

C++ 使用二进制存档的boost序列化时出错,c++,c++11,boost-serialization,ntl,helib,C++,C++11,Boost Serialization,Ntl,Helib,从boost::archive::binary\u iarchive读取变量时出现以下错误: test-serialization(9285,0x11c62fdc0) malloc: can't allocate region *** mach_vm_map(size=18014398509486080) failed (error code=3) test-serialization(9285,0x11c62fdc0) malloc: *** set a breakpoint in mallo

boost::archive::binary\u iarchive
读取变量时出现以下错误:

test-serialization(9285,0x11c62fdc0) malloc: can't allocate region
*** mach_vm_map(size=18014398509486080) failed (error code=3)
test-serialization(9285,0x11c62fdc0) malloc: *** set a breakpoint in malloc_error_break to debug
我的序列化和反序列化代码是:

模板
无效保存(存档和存档,常量helib::PubKey和PubKey,常量unsigned int版本){
BOOST_TEST_消息(“内部保存构造数据”);
存档键切换;
BOOST_TEST_消息(“反序列化键开关映射”);
存档>>按键开关图;
BOOST_TEST_消息(“反序列化KS_策略”);
档案>>KS_战略;
BOOST_TEST_消息(“反序列化重新加密密钥ID”);
存档>>重新加密密钥ID;
BOOST_TEST_消息(“新公钥”);
::new(pubkey)helib::pubkey(*上下文);
//TODO:完成
}
模板
void序列化(存档和存档,helib::PubKey和PubKey,常量unsigned int版本){
免费拆分(存档、公开密钥、版本);
}
模板
无效加载(存档和存档,helib::PubKey和PubKey,常量未签名整数版本){
}
调用代码的测试如下所示:

BOOST\u AUTO\u TEST\u案例(序列化\u公钥)
{
自动上下文=helibTestContext();
helib::SecKey secret_key(上下文);
secret_key.GenSecKey();
//计算我们需要的密钥切换矩阵
helib::addSome1dMatrix(密钥);
//设置密钥(向上转换:SecKey是PubKey的子类)
const helib::PubKey和original_PubKey=secret_key;
std::string filename=“pubkey.serialized”;
流操作系统的std::of(文件名,std::ios::binary);
{
boost::archive::binary_oarchive oarchive(操作系统);
oarchive>恢复的公共密钥;
BOOST_TEST_CHECKPOINT(“通过反序列化完成”);
//测试已完成
}
}
考虑事项:

  • 序列化在
    boost::archive::text\u-oarchive
    boost::archive::binary\u-oarchive
    中都能正常工作。他们分别创建了4600万和2100万个文件(我知道很大)

  • 使用
    boost::archive::text\u iarchive的反序列化在执行
    archive>>键切换时基本停止进程自动终止。这实际上是档案中最大的部分

  • 我决定尝试使用
    boost::archive::binary\u iarchive
    ,因为该文件的大小只有原来的一半,但我得到了开头显示的错误。从存档执行第一次读取时出错:
    archive>>上下文

  • 输入和输出之间的不对称(
    save
    load\u construct\u data
    )是因为我找不到另一种方法来避免实现派生类
    helib::PubKey
    的序列化。使用指向
    helib::PubKey
    的指针给了我编译错误,要求对派生类进行序列化。如果还有别的办法,我洗耳恭听

  • 谢谢你的帮助

    更新

    我正在为加密库中的某些类实现反序列化,因为我需要通过网络发送密文。其中一个类是
    helib::PubKey
    。我正在使用用于实现的。我创建了一个用于提供评论中建议的reprex的。共有3个文件:

  • serialization.hpp,它包含序列化实现。不幸的是,
    helib::PubKey
    依赖于许多其他类使文件相当长。所有其他类都有通过的单元测试此外,我必须对该类进行微小的修改,以实现序列化。我公开了私人成员
  • test-serialization.cpp,它包含单元测试
  • Makefile。运行make创建可执行测试序列化
    vector
    再次罢工

    它实际上是在我的测试盒上分配0x1ffffff20000位(即144比特)。这直接来自IndexSet::resize()

    现在我对HElib使用
    std::vector
    有一些严重的问题(似乎使用类似
    boost::icl::interval\u set
    的东西会更好)。

    嗯。这是一场白费力气的追逐(IndexSet序列化可以大大改进)。但是,真正的问题是,您没有进行反序列化,因为您没有在序列化时反序列化相同的类型

    您序列化了一个
    PubKey
    ,但试图反序列化为
    PubKey*
    。哦

    除此之外,还有很多问题:

    • 您必须修改库以使私有成员公开。这很容易违反ODR(使类布局不兼容)

    • 您似乎将上下文视为一种“动态”资源,它将参与其中。这可能是一个可行的办法。但是你必须考虑所有权

      看来你还没那么做。例如,
      DoublCRT
      load\u construct\u data
      中的行是明确的内存泄漏:

      helib::Context * context = new helib::Context(2,3,1);
      
      你从不使用它,也从不释放它。事实上,您只需使用反序列化实例覆盖它,该实例可能是所有者,也可能不是所有者。第二十二条军规

      对于
      PubKey
      ,在
      load\u construct\u data
      中也会发生完全相同的情况

    • 更糟糕的是,在
      save\u construct\u data
      中,您完全无偿地为每个
      SecKey
      中的每个
      DoubleCRT
      复制上下文对象:

       auto context = polynomial->getContext();
       archive << &context;
      
      如您所见,它们返回拥有的指针。你应该一直在用它们。也许即使有了内置的序列化,我也会在这里绊倒

    是时候重组了 我会使用HElib中的序列化代码(因为,为什么要重新发明轮子并制造大量的bug呢?)。如果您坚持与Boost Serialization集成,您就可以吃蛋糕了:

    template <class Archive> void save(Archive& archive, const helib::PubKey& pubkey, unsigned) {
        using V = std::vector<char>;
        using D = iostreams::back_insert_device<V>;
        V data;
        {
            D dev(data);
            iostreams::stream_buffer<D> sbuf(dev);
            std::ostream os(&sbuf); // expose as std::ostream
            helib::writePubKeyBinary(os, pubkey);
        }
        archive << data;
    }
    
    template <class Archive> void load(Archive& archive, helib::PubKey& pubkey, unsigned) {
        std::vector<char> data;
        archive >> data;
        using S = iostreams::array_source;
        S source(data.data(), data.size());
        iostreams::stream_buffer<S> sbuf(source);
        {
            std::istream is(&sbuf); // expose as std::istream
            helib::readPubKeyBinary(is, pubkey);
        }
    }
    
    这对我来说是优雅的

    完整列表 我克隆了一个新的要点,其中包括以下更改集:

    0079c07 Make it compile locally
    b3b2cf1 Squelch the warnings
    011b589 Endof investigations, regroup time
    
    f4d79a6 Reimplemented using HElib binary IO
    a403e97 Bitwise reproducible outputs
    
    只有最后两次提交包含与实际修复相关的更改

    我将在这里列出完整的代码,以供后人参考。有许多微妙的问题
    namespace helib { // leverage ADL
        template <class A> void save(A& ar, const Context& o, unsigned) {
            Blob data = to_blob(o, writeContextBinary);
            ar << data;
        }
        template <class A> void load(A& ar, Context& o, unsigned) {
            Blob data;
            ar >> data;
            from_blob(data, o, readContextBinary);
        }
        template <class A> void save(A& ar, const PubKey& o, unsigned) {
            Blob data = to_blob(o, writePubKeyBinary);
            ar << data;
        }
        template <class A> void load(A& ar, PubKey& o, unsigned) {
            Blob data;
            ar >> data;
            from_blob(data, o, readPubKeyBinary);
        }
    }
    
    0079c07 Make it compile locally
    b3b2cf1 Squelch the warnings
    011b589 Endof investigations, regroup time
    
    f4d79a6 Reimplemented using HElib binary IO
    a403e97 Bitwise reproducible outputs
    
    #ifndef EVOTING_SERIALIZATION_H
    #define EVOTING_SERIALIZATION_H
    
    #define BOOST_TEST_MODULE main
    #include <helib/helib.h>
    #include <boost/serialization/split_free.hpp>
    #include <boost/serialization/vector.hpp>
    #include <boost/iostreams/stream_buffer.hpp>
    #include <boost/iostreams/device/back_inserter.hpp>
    #include <boost/iostreams/device/array.hpp>
    
    namespace /* file-static */ {
        using Blob = std::vector<char>;
    
        template <typename T, typename F>
        Blob to_blob(const T& object, F writer) {
            using D = boost::iostreams::back_insert_device<Blob>;
            Blob data;
            {
                D dev(data);
                boost::iostreams::stream_buffer<D> sbuf(dev);
                std::ostream os(&sbuf); // expose as std::ostream
                writer(os, object);
            }
            return data;
        }
    
        template <typename T, typename F>
        void from_blob(Blob const& data, T& object, F reader) {
            boost::iostreams::stream_buffer<boost::iostreams::array_source>
                sbuf(data.data(), data.size());
            std::istream is(&sbuf); // expose as std::istream
            reader(is, object);
        }
    }
    
    namespace helib { // leverage ADL
        template <class A> void save(A& ar, const Context& o, unsigned) {
            Blob data = to_blob(o, writeContextBinary);
            ar << data;
        }
        template <class A> void load(A& ar, Context& o, unsigned) {
            Blob data;
            ar >> data;
            from_blob(data, o, readContextBinary);
        }
        template <class A> void save(A& ar, const PubKey& o, unsigned) {
            Blob data = to_blob(o, writePubKeyBinary);
            ar << data;
        }
        template <class A> void load(A& ar, PubKey& o, unsigned) {
            Blob data;
            ar >> data;
            from_blob(data, o, readPubKeyBinary);
        }
    }
    
    BOOST_SERIALIZATION_SPLIT_FREE(helib::Context)
    BOOST_SERIALIZATION_SPLIT_FREE(helib::PubKey)
    #endif //EVOTING_SERIALIZATION_H
    
    #define BOOST_TEST_MODULE main
    #include <boost/test/included/unit_test.hpp>
    #include <helib/helib.h>
    #include <fstream>
    #include "serialization.hpp"
    #include <boost/archive/text_oarchive.hpp>
    #include <boost/archive/text_iarchive.hpp>
    #include <boost/archive/binary_oarchive.hpp>
    #include <boost/archive/binary_iarchive.hpp>
    
    helib::Context helibTestMinimalContext(){
      // Plaintext prime modulus
      unsigned long p = 4999;
      // Cyclotomic polynomial - defines phi(m)
      unsigned long m = 32109;
      // Hensel lifting (default = 1)
      unsigned long r = 1;
      return helib::Context(m, p, r);
    }
    
    helib::Context helibTestContext(){
      auto context = helibTestMinimalContext();
    
      // Number of bits of the modulus chain
      unsigned long bits = 300;
      // Number of columns of Key-Switching matix (default = 2 or 3)
      unsigned long c = 2;
    
      // Modify the context, adding primes to the modulus chain
      buildModChain(context, bits, c);
      return context;
    }
    
    BOOST_AUTO_TEST_CASE(serialization_pubkey) {
        auto context = helibTestContext();
        helib::SecKey secret_key(context);
        secret_key.GenSecKey();
        // Compute key-switching matrices that we need
        helib::addSome1DMatrices(secret_key);
        // Set the secret key (upcast: SecKey is a subclass of PubKey)
        const helib::PubKey& original_pubkey = secret_key;
    
        std::string const filename = "pubkey.serialized";
    
        {
            std::ofstream os(filename, std::ios::binary);
            boost::archive::binary_oarchive oarchive(os);
            oarchive << context << original_pubkey;
        }
        {
            // just checking reproducible output
            std::ofstream os(filename + ".2", std::ios::binary);
            boost::archive::binary_oarchive oarchive(os);
            oarchive << context << original_pubkey;
        }
    
        // reading back to independent instances of Context/PubKey
        {
            // NOTE: if you start from something rogue, it will fail with PAlgebra mismatch.
            helib::Context surrogate = helibTestMinimalContext();
    
            std::ifstream ifs(filename, std::ios::binary);
            boost::archive::binary_iarchive iarchive(ifs);
            iarchive >> surrogate;
    
            // we CAN test that the contexts end up matching
            BOOST_TEST((context == surrogate));
    
            helib::SecKey independent(surrogate);
            helib::PubKey& indep_pk = independent;
            iarchive >> indep_pk;
            // private again, as it should be, but to understand the relation:
            // BOOST_TEST((&independent.context == &surrogate));
    
            // The library's operator== compares the reference, so it would say "not equal"
            BOOST_TEST((indep_pk != original_pubkey));
            {
                // just checking reproducible output
                std::ofstream os(filename + ".3", std::ios::binary);
                boost::archive::binary_oarchive oarchive(os);
                oarchive << surrogate << indep_pk;
            }
        }
    
        // doing it the other way (sharing the context):
        {
            helib::PubKey restored_pubkey(context);
            {
                std::ifstream ifs(filename, std::ios::binary);
                boost::archive::binary_iarchive iarchive(ifs);
                iarchive >> context >> restored_pubkey;
            }
            // now `operator==` confirms equality
            BOOST_TEST((restored_pubkey == original_pubkey));
    
            {
                // just checking reproducible output
                std::ofstream os(filename + ".4", std::ios::binary);
                boost::archive::binary_oarchive oarchive(os);
                oarchive << context << restored_pubkey;
            }
        }
    }
    
    time ./test-serialization -l all -r detailed
    Running 1 test case...
    Entering test module "main"
    test-serialization.cpp(34): Entering test case "serialization_pubkey"
    test-serialization.cpp(61): info: check (context == surrogate) has passed
    test-serialization.cpp(70): info: check (indep_pk != original_pubkey) has passed
    test-serialization.cpp(82): info: check (restored_pubkey == original_pubkey) has passed
    test-serialization.cpp(34): Leaving test case "serialization_pubkey"; testing time: 36385217us
    Leaving test module "main"; testing time: 36385273us
    
    Test module "main" has passed with:
      1 test case out of 1 passed
      3 assertions out of 3 passed
    
      Test case "serialization_pubkey" has passed with:
        3 assertions out of 3 passed
    
    real    0m36,698s
    user    0m35,558s
    sys     0m0,850s
    
    sha256sum pubkey.serialized*
    66b95adbd996b100bff58774e066e7a309e70dff7cbbe08b5c77b9fa0f63c97f  pubkey.serialized
    66b95adbd996b100bff58774e066e7a309e70dff7cbbe08b5c77b9fa0f63c97f  pubkey.serialized.2
    66b95adbd996b100bff58774e066e7a309e70dff7cbbe08b5c77b9fa0f63c97f  pubkey.serialized.3
    66b95adbd996b100bff58774e066e7a309e70dff7cbbe08b5c77b9fa0f63c97f  pubkey.serialized.4
    
    template<class Archive>
        void save(Archive & archive, const helib::IndexSet & index_set, const unsigned int version){
            std::vector<bool> elements;
            elements.resize(index_set.last()-index_set.first()+1);
            for (auto n : index_set)
                elements[n-index_set.first()] = true;
            archive << index_set.first() << elements;
        }
    
    template<class Archive>
        void load(Archive & archive, helib::IndexSet & index_set, const unsigned int version){
            long first_ = 0;
            std::vector<bool> elements;
            archive >> first_ >> elements;
            index_set.clear();
            for (size_t n = 0; n < elements.size(); ++n) {
                if (elements[n])
                    index_set.insert(n+first_);
            }
        }
    
    template<class Archive>
        void save(Archive & archive, const helib::IndexSet & index_set, const unsigned int version){
            boost::dynamic_bitset<> elements;
            elements.resize(index_set.last()-index_set.first()+1);
            for (auto n : index_set)
                elements.set(n-index_set.first());
            archive << index_set.first() << elements;
        }
    
    template<class Archive>
        void load(Archive & archive, helib::IndexSet & index_set, const unsigned int version) {
            long first_ = 0;
            boost::dynamic_bitset<> elements;
            archive >> first_ >> elements;
            index_set.clear();
            for (size_t n = elements.find_first(); n != -1; n = elements.find_next(n))
                index_set.insert(n+first_);
        }