Skip to content

Instantly share code, notes, and snippets.

@giancarloGiuffra
Created May 21, 2020 18:14
Show Gist options
  • Save giancarloGiuffra/f7da5e7f856be6eb64a1069cc1afbf22 to your computer and use it in GitHub Desktop.
Save giancarloGiuffra/f7da5e7f856be6eb64a1069cc1afbf22 to your computer and use it in GitHub Desktop.
reprex for stackoverflow question https://stackoverflow.com/q/61895626/4970597
# the compiler: gcc for C program, define as g++ for C++
CC = g++
INCLUDEDIR = /usr/local/include
LIBDIR = /usr/local/helib_pack/lib
LIBS = -lntl -lhelib -lgmp -lboost_serialization
# compiler flags:
CFLAGS = -g -Wall -std=c++14 -I $(INCLUDEDIR)
TARGETS = test-serialization
DEPS = serialization.hpp
all: $(TARGETS)
test-serialization: test-serialization.o
$(TARGETS):
$(CC) -o $@ $^ $(CFLAGS) -Wl,-rpath,$(LIBDIR) -L $(LIBDIR) $(LIBS)
%.o: %.cpp $(DEPS)
$(CC) -c -o $@ $< $(CFLAGS)
clean:
$(RM) $(TARGETS) *.o
#ifndef EVOTING_SERIALIZATION_H
#define EVOTING_SERIALIZATION_H
#define BOOST_TEST_MODULE main
#include <helib/helib.h>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/split_free.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/test/included/unit_test.hpp>
#include <boost/serialization/map.hpp>
#include <boost/serialization/export.hpp>
#include <NTL/ZZ_limbs.h>
namespace boost{
namespace serialization{
/* helib::IndexSet */
template<class Archive>
void save(Archive & archive, const helib::IndexSet & index_set, const unsigned int version){
std::vector<long> elements;
for(long element = index_set.first(); element <= index_set.last(); element = index_set.next(element))
elements.push_back(element);
archive << elements;
}
template<class Archive>
void load(Archive & archive, helib::IndexSet & index_set, const unsigned int version){
std::vector<long> elements;
archive >> elements;
index_set = helib::IndexSet();
for(auto element : elements)
index_set.insert(element);
}
/* helib::SKHandle */
template<class Archive>
void save(Archive & archive, const helib::SKHandle & skhandle, const unsigned int version){
archive << skhandle.getPowerOfS();
archive << skhandle.getPowerOfX();
archive << skhandle.getSecretKeyID();
}
template<class Archive>
void load(Archive & archive, helib::SKHandle & skhandle, const unsigned int version){
long powerOfS, powerOfX, secretKeyID;
archive >> powerOfS;
archive >> powerOfX;
archive >> secretKeyID;
skhandle = helib::SKHandle(powerOfS, powerOfX, secretKeyID);
}
/* NTL::Vec<T> */
template<class Archive, typename T>
void save(Archive & archive, const NTL::Vec<T> & ntl_vector, const unsigned int version){
std::vector<T> elements;
for(auto it = ntl_vector.begin(); it != ntl_vector.end(); ++it)
elements.push_back(*it);
archive << elements;
}
template<class Archive, typename T>
void load(Archive & archive, NTL::Vec<T> & ntl_vector, const unsigned int version){
std::vector<T> elements;
archive >> elements;
for(auto element : elements)
ntl_vector.append(element);
}
template<class Archive, typename T>
void serialize(Archive & archive, NTL::Vec<T> & ntl_vector, const unsigned int version){
split_free(archive, ntl_vector, version);
}
/* helib::IndexMap<T> */
template<class Archive, typename T>
void save(Archive & archive, const helib::IndexMap<NTL::Vec<T>> & index_map, const unsigned int version){
auto index_set = index_map.getIndexSet();
std::map<long,NTL::Vec<T>> map;
for(auto index = index_set.first(); index <= index_set.last(); index = index_set.next(index))
map[index] = index_map[index];
archive << index_set;
archive << map;
}
template<class Archive, typename T>
void load(Archive & archive, helib::IndexMap<NTL::Vec<T>> & index_map, const unsigned int version){
helib::IndexSet index_set;
std::map<long,NTL::Vec<T>> map;
archive >> index_set;
archive >> map;
index_map.clear();
index_map.insert(index_set);
for(auto index = index_set.first(); index <= index_set.last(); index = index_set.next(index)){
index_map[index].QuickSetLength(map[index].length());
index_map[index] = map[index];
}
}
template<class Archive, typename T>
void serialize(Archive & archive, helib::IndexMap<NTL::Vec<T>> & index_map, const unsigned int version){
split_free(archive, index_map, version);
}
/* helib::DoubleCRT */
template<class Archive>
void save_construct_data(Archive & archive, const helib::DoubleCRT * polynomial, const unsigned int version){
NTL::ZZX polynomialZZX;
polynomial->toPoly(polynomialZZX);
auto context = polynomial->getContext();
archive << &context;
archive << polynomial->getIndexSet();
archive << polynomialZZX;
}
template<class Archive>
void load_construct_data(Archive & archive, helib::DoubleCRT * polynomial, const unsigned int version){
helib::Context * context = new helib::Context(2,3,1); //random numbers since there is no default constructor
helib::IndexSet index_set;
NTL::ZZX polynomialZZX;
archive >> context;
archive >> index_set;
archive >> polynomialZZX;
::new(polynomial)helib::DoubleCRT(polynomialZZX, *context, index_set);
}
template<class Archive>
void serialize(Archive & archive, helib::DoubleCRT & polynomial, const unsigned int version){}
/* helib::Context */
template<class Archive>
inline void save_construct_data(Archive & archive, const helib::Context * context, const unsigned int version){
archive << context->zMStar.getM();
archive << context->zMStar.getP();
archive << context->alMod.getR();
archive << context->smallPrimes;
archive << context->ctxtPrimes;
archive << context->specialPrimes;
archive << context->digits;
auto lastIndexPrime = context->allPrimes().last();
std::vector<long> primes(lastIndexPrime + 1);
for(auto index = context->smallPrimes.first(); index <= context->smallPrimes.last(); index = context->smallPrimes.next(index))
primes[index] = context->ithPrime(index);
for(auto index = context->ctxtPrimes.first(); index <= context->ctxtPrimes.last(); index = context->ctxtPrimes.next(index))
primes[index] = context->ithPrime(index);
for(auto index = context->specialPrimes.first(); index <= context->specialPrimes.last(); index = context->specialPrimes.next(index))
primes[index] = context->ithPrime(index);
archive << primes;
}
template<class Archive>
inline void load_construct_data(Archive & archive, helib::Context * context, const unsigned int version){
unsigned long m;
unsigned long p;
unsigned long r;
helib::IndexSet smallPrimes;
helib::IndexSet ctxtPrimes;
helib::IndexSet specialPrimes;
std::vector<helib::IndexSet> digits;
std::vector<long> primes;
archive >> m;
archive >> p;
archive >> r;
archive >> smallPrimes;
archive >> ctxtPrimes;
archive >> specialPrimes;
archive >> digits;
archive >> primes;
::new(context)helib::Context(m, p, r);
//restore smallPrimes
for(long index = smallPrimes.first(); index <= smallPrimes.last(); index = smallPrimes.next(index))
context->AddSmallPrime(primes[index]);
//restore ctxtPrimes
for(long index = ctxtPrimes.first(); index <= ctxtPrimes.last(); index = ctxtPrimes.next(index))
context->AddCtxtPrime(primes[index]);
//restore specialPrimes
for(long index = specialPrimes.first(); index <= specialPrimes.last(); index = specialPrimes.next(index))
context->AddSpecialPrime(primes[index]);
//restore digits
context->digits = digits;
//last operation made in buildModchain
endBuildModChain(*context);
}
template<class Archive>
void serialize(Archive & archive, helib::Context & context, const unsigned int version){}
/* NTL::ZZ */
template<class Archive>
void save(Archive & archive, const NTL::ZZ & big_integer, const unsigned int version){
archive << big_integer.size();
archive << boost::serialization::make_array(ZZ_limbs_get(big_integer), big_integer.size());
}
template<class Archive>
void load(Archive & archive, NTL::ZZ & big_integer, const unsigned int version){
long size;
NTL::ZZ_limb_t * pointer;
archive >> size;
archive >> boost::serialization::make_array(pointer, size);
ZZ_limbs_set(big_integer, pointer, size);
}
/* NTL::ZZX */
template<class Archive>
void save(Archive & archive, const NTL::ZZX & polynomial, const unsigned int version){
auto degree = NTL::deg(polynomial);
std::vector<NTL::ZZ> coefficients;
for(int term = 0; term <= degree; ++term)
coefficients.push_back(NTL::coeff(polynomial, term));
archive << coefficients;
}
template<class Archive>
void load(Archive & archive, NTL::ZZX & polynomial, const unsigned int version){
std::vector<NTL::ZZ> coefficients;
archive >> coefficients;
NTL::clear(polynomial);
for(int term = 0; term < coefficients.size(); ++term)
NTL::SetCoeff(polynomial, term, coefficients[term]);
}
/* NTL::xdouble */
template<class Archive>
void serialize(Archive & archive, NTL::xdouble & xdouble, const unsigned int version){
archive & xdouble.x;
archive & xdouble.e;
}
/* helib::KeySwitch */
template<class Archive>
void serialize(Archive & archive, helib::KeySwitch & keyswitch, const unsigned int version){
archive & keyswitch.fromKey;
archive & keyswitch.toKeyID;
archive & keyswitch.ptxtSpace;
archive & keyswitch.prgSeed;
archive & keyswitch.b;
}
template<class Archive>
void save(Archive & archive, const helib::PubKey & pubkey, const unsigned int version){
BOOST_TEST_MESSAGE("inside save_construct_data");
archive << &(pubkey.context);
archive << pubkey.skBounds;
archive << pubkey.keySwitching;
archive << pubkey.keySwitchMap;
archive << pubkey.KS_strategy;
archive << pubkey.recryptKeyID;
}
template<class Archive>
void load_construct_data(Archive & archive, helib::PubKey * pubkey, const unsigned int version){
helib::Context * context = new helib::Context(2,3,1); //random numbers since there is no default constructor
BOOST_TEST_MESSAGE("deserializing context");
archive >> context;
std::vector<double> skBounds;
std::vector<helib::KeySwitch> keySwitching;
std::vector<std::vector<long>> keySwitchMap;
NTL::Vec<long> KS_strategy;
long recryptKeyID;
BOOST_TEST_MESSAGE("deserializing skbounds");
archive >> skBounds;
BOOST_TEST_MESSAGE("deserializing keyswitching");
archive >> keySwitching;
BOOST_TEST_MESSAGE("deserializing keyswitchmap");
archive >> keySwitchMap;
BOOST_TEST_MESSAGE("deserializing KS_strategy");
archive >> KS_strategy;
BOOST_TEST_MESSAGE("deserializing recryptKeyID");
archive >> recryptKeyID;
BOOST_TEST_MESSAGE("new pubkey");
::new(pubkey)helib::PubKey(*context);
}
template<class Archive>
void serialize(Archive & archive, helib::PubKey & pubkey, const unsigned int version){
split_free(archive, pubkey, version);
}
template<class Archive>
void load(Archive & archive, helib::PubKey & pubkey, const unsigned int version){
}
}//namespace boost
}//namespace serialization
BOOST_SERIALIZATION_SPLIT_FREE(helib::IndexSet)
BOOST_SERIALIZATION_SPLIT_FREE(helib::SKHandle)
BOOST_SERIALIZATION_SPLIT_FREE(NTL::ZZ)
BOOST_SERIALIZATION_SPLIT_FREE(NTL::ZZX)
#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 helibTestContext(){
// Plaintext prime modulus
unsigned long p = 4999;
// Cyclotomic polynomial - defines phi(m)
unsigned long m = 32109;
// Hensel lifting (default = 1)
unsigned long r = 1;
// 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;
helib::Context context(m, p, r);
// 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 filename = "pubkey.serialized";
std::ofstream os(filename, std::ios::binary);
{
boost::archive::binary_oarchive oarchive(os);
oarchive << original_pubkey;
}
helib::PubKey * restored_pubkey = new helib::PubKey(helib::Context(2,3,1));
{
std::ifstream ifs(filename, std::ios::binary);
boost::archive::binary_iarchive iarchive(ifs);
BOOST_TEST_CHECKPOINT("calling deserialization");
iarchive >> restored_pubkey;
BOOST_TEST_CHECKPOINT("done with deserialization");
}
BOOST_TEST((restored_pubkey->context == original_pubkey.context));
BOOST_TEST((restored_pubkey->skBounds == original_pubkey.skBounds));
BOOST_TEST((restored_pubkey->keySwitching == original_pubkey.keySwitching));
BOOST_TEST((restored_pubkey->keySwitchMap == original_pubkey.keySwitchMap));
BOOST_TEST((restored_pubkey->KS_strategy == original_pubkey.KS_strategy));
BOOST_TEST((restored_pubkey->recryptKeyID == original_pubkey.recryptKeyID));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment