scipr-lab / libsnark

C++ library for zkSNARKs
Other
1.81k stars 578 forks source link

Duplicate definitions of Fp_model static members when using libsnark.so #12

Open defuse opened 9 years ago

defuse commented 9 years ago

In algebra/fields/fp.hpp, the static members of the Fp_model template are declared as well as defined. This leads to a problem when we dynamically link against libsnark.so. We have code in the main executable which tries to access those static members, but when that code runs, it finds them all uninitialized, even though we've run the initialization method.

By #include-ing algebra/fields/fp.hpp in our code, the compiler seems to be creating another copy of all of the static members in our binary. Code in our binary therefore accesses its local copies, which are in the uninitialized state, i.e. num_bits is zero, because the init_alt_bn128_params() initializes the copy of the variable in libsnark.so, and not the copy in our binary.

Ideally, there should only be one copy of these variables in libsnark.so. Is there a trick to getting our code to use the ones inside libsnark.so instead of creating copies?

We are using gcc version 5.2.0.

The revision we are using is:

2474695678b3529841eced49ea97ca683e91996c

Could this have been fixed in a newer version?

nathan-at-least commented 9 years ago

Note, this blog post describes the same kind of issue and introduces a new C++0x language extension to address the issue:

Perhaps libsnark should use that mechanism?

daira commented 9 years ago

Ugh, how many hacky workarounds is C++ going to add in the language to address broken linker technology? :-/

madars commented 9 years ago

In libsnark each Fp_model<num_limbs, modulus> is used in conjunction with particular elliptic curve choices. Given this the following should work:

template<mp_size_t n, const bigint<n>& modulus>
extern size_t Fp_model<n, modulus>::num_bits

This would ensure that translation units for your executable won't declare their own copy of those symbols.

Of course, The amount of boilerplate can be reduced by an appropriate DECLARE_FP_MODEL_STATIC_MEMBERS(num_limbs, modulus) macro.

We rely on extern template anyway, so maybe solution based on that would be a better choice.

By the way, I was unable to exhibit the behavior you observe on my machine: all static members of template instantiations get "weak" bindings in libsnark.so so the dynamic linker should just DTRT. But that might just be an artifact of my setup (g++ 5.2.1 on Ubuntu wily).