0

I'm currently using the NTL library to store big integers (NTL::ZZ). It looks like the only serialization way in lib is from ZZ to std::string (and std::string to ZZ for deserialization). But if I want to store and transfer a large number of integers, it becomes too slow. And the size of the transferred text is too large. Is there a better way to serialize and deserialize NTL::ZZ? such as binary?

Sqrelord
  • 3
  • 1

1 Answers1

0

It is easy to miss, but ZZ provides conversions to and from byte sequences:

void ZZFromBytes(ZZ& x, const unsigned char *p, long n);
ZZ ZZFromBytes(const unsigned char *p, long n);
// x = sum(p[i]*256^i, i=0..n-1). 
// NOTE: in the unusual event that a char is more than 8 bits, 
//       only the low order 8 bits of p[i] are used

void BytesFromZZ(unsigned char *p, const ZZ& a, long n);
// Computes p[0..n-1] such that abs(a) == sum(p[i]*256^i, i=0..n-1) mod 256^n.

long NumBytes(const ZZ& a);
long NumBytes(long a);

With simple length-prefix framing, you can thus have:

void writeZZ(ostream& os, const ZZ& a) {
  long size = htobe32(NumBytes(a));
  std::string buf(size, 0);
  BytesFromZZ(buf.data(), a, buf.size());
  os.write(&size, sizeof(long));
  os.write(buf.data(), buf.size());
}

ZZ readZZ(istream& is) {
  long size;
  is.read(&size, sizeof(long));
  size = be32toh(size);
  std::string buf(size, 0);
  is.read(buf.data(), size);
  return ZZFromBytes(buf.data(), size);
}

This can obviously be improved with error checking and by using a single thread-local buf instead of creating a fresh one every time.

Botje
  • 26,269
  • 3
  • 31
  • 41