danieltorres
danieltorres

Reputation: 370

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;
}

Upvotes: 2

Views: 2371

Answers (1)

Deduplicator
Deduplicator

Reputation: 45654

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.

Upvotes: 3

Related Questions