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个文件:
helib::PubKey
依赖于许多其他类使文件相当长。所有其他类都有通过的单元测试此外,我必须对该类进行微小的修改,以实现序列化。我公开了私人成员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;
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_);
}