Search code examples
c++gmp

How can I save a GMP mpz_t/mpz_class to vector<byte>?


I need to convert mpz_class types to vector<byte> and the other way around.
I implemented these two functions, but roundtrip conversion is broken.

typedef unsigned char byte;

std::vector<byte> mpz_to_vector(std::shared_ptr<mpz_class> x) {
    size_t size;
    byte *a = (byte *) mpz_export(NULL, &size, 1, 1, 1, 0,x->get_mpz_t());
    std::vector<byte> p(a,a+size);
    free(a);
    return p;
}

std::shared_ptr<mpz_class>vector_to_mpz(std::vector<byte> d) {
    mpz_class ptr;
    mpz_import(ptr.get_mpz_t(), d.size(), 1, sizeof(mpz_t), 1, 0, (void *) d.data());
    auto tmp = std::shared_ptr<mpz_class>(new mpz_class(ptr));
    return tmp;
}

Solution

  • Avoid dynamic allocations, especially the manual kind: Why is size a pointer to a dynamically allocated size_t?
    You don't need any temporary buffers, so remove them. The manual contains the proper algorithm for sizing the output buffer.
    Applying this, we get this exporter:

    std::vector<byte> mpz_to_vector(const mpz_t x) {
        size_t size = (mpz_sizeinbase (x, 2) + CHAR_BIT-1) / CHAR_BIT;
        std::vector<byte> v(size);
        mpz_export(&v[0], &size, 1, 1, 0, 0, x);
        v.resize(size);
        return v;
    }
    inline std::vector<byte> mpz_to_vector(std::shared_ptr<mpz_class>& x) {
        return mpz_to_vector(x->get_mpz_t());
    }
    

    The importer suffers from needless copying too.
    Still, the only error is providing wrong arguments to mpz_export.
    Correcting that all gives us:

    std::shared_ptr<mpz_class> vector_to_mpz(const std::vector<byte>& d) {
        auto p = make_shared<mpz_class>();
        mpz_import(p->get_mpz_t(), d.size(), 1, 1, 0, 0, &d[0]);
        return p;
    }
    

    BTW: I used make_shared, because that's more efficient on good implementations than doing so manually, and it enables exception safety.