Search code examples
c++serializationcryptographyntl

Is there a better way to serialize NTL ZZ?


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?


Solution

  • 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.