rustpq / pqcrypto

Rust Post-Quantum cryptography
212 stars 38 forks source link

Linker error when using multiple pqcrypto crates #18

Closed marcbrevoort-cyberhive closed 3 years ago

marcbrevoort-cyberhive commented 3 years ago

When using several pqcrypto crates (for instance saber and classicmceliece), it turns out both have their own copy of pqclean/common/ which leads to linker errors such as

/home/mrjb/.cargo/registry/src/github.com-1ecc6299db9ec823/pqcrypto-saber-0.1.5/pqclean/common/sp800-185.c:149:
multiple definition of `cshake256'; /tmp/rustc6Aet9z/libpqcrypto_classicmceliece-4c301a36d4b2b76b.rlib(sp800-185.o):
/home/mrjb/.cargo/registry/src/github.com-1ecc6299db9ec823/pqcrypto-classicmceliece-0.1.1/pqclean/common/sp800-185.c:149: first defined here                  

No doubt in practice pqclean/common/sp800-185.c is identical for both crates but in theory they might not be. Is there a version where the bindings to pqclean/common are split out to a separate package?

thomwiggers commented 3 years ago

That's probably something I should fix by moving them to a shared crate. You could try to use the pqcrypto main crate, which has features nowadays to turn off algorithms.

marcbrevoort-cyberhive commented 3 years ago

Using the pqcrypto main crate, while I can manage to get things to compile, the linker yields the same sort of output as described above. This could be due to the project using further crypto libs, but Cargo.lock also suggests the pqcrypto master crate simply pulls in the other crates as dependencies:

[[package]]
name = "pqcrypto"
version = "0.12.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d3874384bf37d988b83f806d632e2f7fca69a8cd0338efaa64e8e7664573052"
dependencies = [
 "pqcrypto-classicmceliece",
 "pqcrypto-dilithium",
 "pqcrypto-falcon",
 "pqcrypto-frodo",
 "pqcrypto-hqc",
 "pqcrypto-kyber",
 "pqcrypto-ntru",
 "pqcrypto-rainbow",
 "pqcrypto-saber",
 "pqcrypto-sphincsplus",
 "pqcrypto-traits",
]

This suggests the same duplicate bindings still occur in that case, which would explain that behaviour (though I haven't 100% established a causal relationship in this instance).

thomwiggers commented 3 years ago

Interesting, I've used the pqcrypto crate without issue...

marcbrevoort-cyberhive commented 3 years ago

Interesting indeed. Have you used multiple algorithms at the same time? You mentioned a feature to turn off algorithms - how does one use that feature?

marcbrevoort-cyberhive commented 3 years ago

Turns out multiple pqcrypto crates isn't required; In an existing project, adding pqcrypto = { version = "0.12.2", features = [ "pqcrypto-saber" ] } to Cargo.toml and then adding a line use pqcrypto::kem::saber; is enough to make things blow up with a multitude of errors such as

/usr/bin/ld: /tmp/rustcnUlEqg/libpqcrypto_frodo-506a150556c3706e.rlib(aes.o): in function `aes192_ctx_release':
          /home/mrjb/.cargo/registry/src/github.com-1ecc6299db9ec823/pqcrypto-frodo-0.4.5/pqclean/common/aes.c:656: multiple definition of `aes192_ctx_release'; /tmp/rustcnUlEqg/libpqcrypto_sphincsplus-4222d08462d80d63.rlib(aes.o):/home/mrjb/.cargo/registry/src/github.com-1ecc6299db9ec823/pqcrypto-sphincsplus-0.5.2/pqclean/common/aes.c:656: first defined here

... which is interesting since I'm not using frodo or sphincsplus, so I'm not sure why it even wants to link them in.

Now if instead I just use

pqcrypto-traits = { version = "0.3.2" }
pqcrypto-saber = { version = "0.1.5" }

and use pqcrypto-saber in my code, things compile and link just fine. However the moment I add

pqcrypto-classicmceliece = { version = "0.1.1" }

and use pqcrypto_classicmceliece::mceliece460896::*; the linker breaks down with

          /usr/bin/ld: /tmp/rustcUYJYBi/libpqcrypto_saber-bb46a144ea0132aa.rlib(sp800-185.o): in function `cshake256':
          /home/mrjb/.cargo/registry/src/github.com-1ecc6299db9ec823/pqcrypto-saber-0.1.5/pqclean/common/sp800-185.c:149: multiple definition of `cshake256'; /tmp/rustcUYJYBi/libpqcrypto_classicmceliece-3b59f51fe6b11caf.rlib(sp800-185.o):/home/mrjb/.cargo/registry/src/github.com-1ecc6299db9ec823/pqcrypto-classicmceliece-0.1.1/pqclean/common/sp800-185.c:149: first defined here

(and many more like it, all clashes between saber and mceliece). I expect that if both packages depended on say, a pqcrypto_common crate for the pqclean/common stuff, there would be only one copy of each of any of the pqclean/common files and the error would not occur.

thomwiggers commented 3 years ago

You should also specify default-features = false

thomwiggers commented 3 years ago

I don't have time to work on this crate in the coming week or so; I hope to have a look (and sync with upstream PQClean again) afterwards.

In the mean time you might want to consider using the oqs crate anyway, it's a bit more polished.

marcbrevoort-cyberhive commented 3 years ago

The oqs crate seems to provide all I need and without linker issues - thanks for pointing me in that direction.