bug 1584401 - build osclientcerts in-tree on Windows r=jcj,kjacobs
☠☠ backed out by e22eaa8925b0 ☠ ☠
authorDana Keeler <dkeeler@mozilla.com>
Wed, 18 Sep 2019 10:27:50 -0700
changeset 498590 055ba7efc9cdbc1e7ad8e250b7573109302a48d8
parent 498589 e9e6c8d830a0f0885f04a198a96dfbe2aa81e960
child 498591 e22eaa8925b007a0e821825c80ff4de277ffc28d
push id114159
push usershindli@mozilla.com
push dateThu, 24 Oct 2019 09:49:00 +0000
treeherdermozilla-inbound@ba30626ccb8c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjcj, kjacobs
bugs1584401
milestone72.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
bug 1584401 - build osclientcerts in-tree on Windows r=jcj,kjacobs This adds a preliminary implementation of a PKCS#11 module that allows Firefox to access client certificates for TLS client authentication on Windows.
Cargo.lock
Cargo.toml
browser/installer/package-manifest.in
security/manager/ssl/moz.build
security/manager/ssl/osclientcerts/Cargo.toml
security/manager/ssl/osclientcerts/build.rs
security/manager/ssl/osclientcerts/dynamic-library/moz.build
security/manager/ssl/osclientcerts/dynamic-library/osclientcerts.symbols
security/manager/ssl/osclientcerts/dynamic-library/stub.cpp
security/manager/ssl/osclientcerts/moz.build
security/manager/ssl/osclientcerts/src/backend_windows.rs
security/manager/ssl/osclientcerts/src/lib.rs
security/manager/ssl/osclientcerts/src/manager.rs
security/manager/ssl/osclientcerts/src/util.rs
security/manager/ssl/osclientcerts/src/wrapper-windows.h
security/manager/ssl/osclientcerts/test/modulus.bin
security/manager/ssl/osclientcerts/test/rsa.bin
third_party/rust/libloading-0.4.3/.cargo-checksum.json
third_party/rust/libloading-0.4.3/Cargo.toml
third_party/rust/libloading-0.4.3/LICENSE
third_party/rust/libloading-0.4.3/README.mkd
third_party/rust/libloading-0.4.3/appveyor.yml
third_party/rust/libloading-0.4.3/build.rs
third_party/rust/libloading-0.4.3/src/changelog.rs
third_party/rust/libloading-0.4.3/src/lib.rs
third_party/rust/libloading-0.4.3/src/os/mod.rs
third_party/rust/libloading-0.4.3/src/os/unix/mod.rs
third_party/rust/libloading-0.4.3/src/os/windows/mod.rs
third_party/rust/libloading-0.4.3/src/test_helpers.rs
third_party/rust/libloading-0.4.3/src/util.rs
third_party/rust/libloading-0.4.3/tests/functions.rs
third_party/rust/libloading-0.4.3/tests/markers.rs
third_party/rust/libloading-0.4.3/tests/nagisa32.dll
third_party/rust/libloading-0.4.3/tests/nagisa64.dll
third_party/rust/libloading-0.4.3/tests/windows.rs
third_party/rust/num-bigint/.cargo-checksum.json
third_party/rust/num-bigint/Cargo.toml
third_party/rust/num-bigint/LICENSE-APACHE
third_party/rust/num-bigint/LICENSE-MIT
third_party/rust/num-bigint/README.md
third_party/rust/num-bigint/RELEASES.md
third_party/rust/num-bigint/benches/bigint.rs
third_party/rust/num-bigint/benches/factorial.rs
third_party/rust/num-bigint/benches/gcd.rs
third_party/rust/num-bigint/benches/shootout-pidigits.rs
third_party/rust/num-bigint/bors.toml
third_party/rust/num-bigint/ci/rustup.sh
third_party/rust/num-bigint/ci/test_full.sh
third_party/rust/num-bigint/src/algorithms.rs
third_party/rust/num-bigint/src/bigint.rs
third_party/rust/num-bigint/src/biguint.rs
third_party/rust/num-bigint/src/lib.rs
third_party/rust/num-bigint/src/macros.rs
third_party/rust/num-bigint/src/monty.rs
third_party/rust/num-bigint/src/tests/bigint.rs
third_party/rust/num-bigint/src/tests/biguint.rs
third_party/rust/num-bigint/tests/modpow.rs
third_party/rust/pkcs11/.cargo-checksum.json
third_party/rust/pkcs11/Cargo.toml
third_party/rust/pkcs11/LICENSE
third_party/rust/pkcs11/NOTICE
third_party/rust/pkcs11/README.md
third_party/rust/pkcs11/rustfmt.toml
third_party/rust/pkcs11/src/errors.rs
third_party/rust/pkcs11/src/functions.rs
third_party/rust/pkcs11/src/lib.rs
third_party/rust/pkcs11/src/tests.rs
third_party/rust/pkcs11/src/types.rs
third_party/rust/rand-0.4.6/.cargo-checksum.json
third_party/rust/rand-0.4.6/CHANGELOG.md
third_party/rust/rand-0.4.6/Cargo.toml
third_party/rust/rand-0.4.6/LICENSE-APACHE
third_party/rust/rand-0.4.6/LICENSE-MIT
third_party/rust/rand-0.4.6/README.md
third_party/rust/rand-0.4.6/appveyor.yml
third_party/rust/rand-0.4.6/benches/bench.rs
third_party/rust/rand-0.4.6/benches/distributions/exponential.rs
third_party/rust/rand-0.4.6/benches/distributions/gamma.rs
third_party/rust/rand-0.4.6/benches/distributions/mod.rs
third_party/rust/rand-0.4.6/benches/distributions/normal.rs
third_party/rust/rand-0.4.6/benches/generators.rs
third_party/rust/rand-0.4.6/benches/misc.rs
third_party/rust/rand-0.4.6/src/distributions/exponential.rs
third_party/rust/rand-0.4.6/src/distributions/gamma.rs
third_party/rust/rand-0.4.6/src/distributions/mod.rs
third_party/rust/rand-0.4.6/src/distributions/normal.rs
third_party/rust/rand-0.4.6/src/distributions/range.rs
third_party/rust/rand-0.4.6/src/distributions/ziggurat_tables.rs
third_party/rust/rand-0.4.6/src/jitter.rs
third_party/rust/rand-0.4.6/src/lib.rs
third_party/rust/rand-0.4.6/src/os.rs
third_party/rust/rand-0.4.6/src/prng/chacha.rs
third_party/rust/rand-0.4.6/src/prng/isaac.rs
third_party/rust/rand-0.4.6/src/prng/isaac64.rs
third_party/rust/rand-0.4.6/src/prng/mod.rs
third_party/rust/rand-0.4.6/src/prng/xorshift.rs
third_party/rust/rand-0.4.6/src/rand_impls.rs
third_party/rust/rand-0.4.6/src/read.rs
third_party/rust/rand-0.4.6/src/reseeding.rs
third_party/rust/rand-0.4.6/src/seq.rs
third_party/rust/rand-0.4.6/utils/ziggurat_tables.py
third_party/rust/rustc-serialize/.cargo-checksum.json
third_party/rust/rustc-serialize/Cargo.toml
third_party/rust/rustc-serialize/LICENSE-APACHE
third_party/rust/rustc-serialize/LICENSE-MIT
third_party/rust/rustc-serialize/README.md
third_party/rust/rustc-serialize/appveyor.yml
third_party/rust/rustc-serialize/benches/base64.rs
third_party/rust/rustc-serialize/benches/hex.rs
third_party/rust/rustc-serialize/benches/json.rs
third_party/rust/rustc-serialize/src/base64.rs
third_party/rust/rustc-serialize/src/collection_impls.rs
third_party/rust/rustc-serialize/src/hex.rs
third_party/rust/rustc-serialize/src/json.rs
third_party/rust/rustc-serialize/src/lib.rs
third_party/rust/rustc-serialize/src/serialize.rs
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1564,16 +1564,26 @@ name = "libdbus-sys"
 version = "0.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "libloading"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "libloading"
 version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "cc 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)",
  "winapi 0.3.6 (git+https://github.com/froydnj/winapi-rs?branch=aarch64)",
 ]
 
 [[package]]
@@ -2024,16 +2034,27 @@ dependencies = [
 [[package]]
 name = "nsstring-gtest"
 version = "0.1.0"
 dependencies = [
  "nsstring 0.1.0",
 ]
 
 [[package]]
+name = "num-bigint"
+version = "0.1.44"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
 name = "num-derive"
 version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
@@ -2102,16 +2123,30 @@ source = "registry+https://github.com/ru
 name = "ordered-float"
 version = "1.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
+name = "osclientcerts-static"
+version = "0.1.4"
+dependencies = [
+ "bindgen 0.51.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "pkcs11 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.6 (git+https://github.com/froydnj/winapi-rs?branch=aarch64)",
+]
+
+[[package]]
 name = "owning_ref"
 version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -2205,16 +2240,25 @@ dependencies = [
 name = "phf_shared"
 version = "0.7.24"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "siphasher 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
+name = "pkcs11"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "libloading 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-bigint 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
 name = "pkg-config"
 version = "0.3.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "plain"
 version = "0.2.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2334,16 +2378,28 @@ name = "quote"
 version = "1.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "rand"
+version = "0.4.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.6 (git+https://github.com/froydnj/winapi-rs?branch=aarch64)",
+]
+
+[[package]]
+name = "rand"
 version = "0.6.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
  "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2599,16 +2655,21 @@ source = "registry+https://github.com/ru
 name = "rustc-hash"
 version = "1.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
+name = "rustc-serialize"
+version = "0.3.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
 name = "rustc_version"
 version = "0.2.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -3932,16 +3993,17 @@ dependencies = [
 "checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358"
 "checksum itoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c069bbec61e1ca5a596166e55dfe4773ff745c3d16b700013bcaff9a6df2c682"
 "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
 "checksum khronos_api 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc"
 "checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1"
 "checksum lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f"
 "checksum libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)" = "d44e80633f007889c7eff624b709ab43c92d708caad982295768a7b13ca3b5eb"
 "checksum libdbus-sys 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "18cb88963258d00f4962205dbb5933d82780d9962c8c8a064b651d2ad7189210"
+"checksum libloading 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fd38073de8f7965d0c17d30546d4bb6da311ab428d1c7a3fc71dff7f9d4979b9"
 "checksum libloading 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3ad660d7cb8c5822cd83d10897b0f1f1526792737a179e73896152f85b88c2"
 "checksum libudev 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ea626d3bdf40a1c5aee3bcd4f40826970cae8d80a8fec934c82a63840094dcfe"
 "checksum libz-sys 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "2eb5e43362e38e2bca2fd5f5134c4d4564a23a5c28e9b95411652021a8675ebe"
 "checksum line-wrap 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f30344350a2a51da54c1d53be93fade8a237e545dbcc4bdbe635413f2117cab9"
 "checksum linked-hash-map 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "70fb39025bc7cdd76305867c4eccf2f2dcf6e9a57f5b21a93e1c2d86cd03ec9e"
 "checksum lmdb-rkv 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "605061e5465304475be2041f19967a900175ea1b6d8f47fbab84a84fb8c48452"
 "checksum lmdb-rkv-sys 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e4b19a1fdf5b74bc802cc9aa7c0c86a775e8b872ba9d5a4e606ffc5d076953"
 "checksum lock_api 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f8912e782533a93a167888781b836336a6ca5da6175c05944c86cf28c31104dc"
@@ -3965,16 +4027,17 @@ dependencies = [
 "checksum moz_cbor 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20c82a57087fd5990d7122dbff1607c3b20c3d2958e9d9ad9765aab415e2c91c"
 "checksum mp4parse_fallible 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6626c2aef76eb8f984eef02e475883d3fe9112e114720446c5810fc5f045cd30"
 "checksum msdos_time 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "aad9dfe950c057b1bfe9c1f2aa51583a8468ef2a5baba2ebbe06d775efeb7729"
 "checksum murmurhash3 0.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a2983372caf4480544083767bf2d27defafe32af49ab4df3a0b7fc90793a3664"
 "checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88"
 "checksum new_debug_unreachable 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0cdc457076c78ab54d5e0d6fa7c47981757f1e34dc39ff92787f217dede586c4"
 "checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2"
 "checksum nom 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9c349f68f25f596b9f44cf0e7c69752a5c633b0550c3ff849518bfba0233774a"
+"checksum num-bigint 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)" = "e63899ad0da84ce718c14936262a41cee2c79c981fc0a0e7c7beb47d5a07e8c1"
 "checksum num-derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0c8b15b261814f992e33760b1fca9fe8b693d8a65299f20c9901688636cfb746"
 "checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea"
 "checksum num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "af3fdbbc3291a5464dc57b03860ec37ca6bf915ed6ee385e7c6c052c422b2124"
 "checksum num-rational 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4e96f040177bb3da242b5b1ecf3f54b5d5af3efbbfb18608977a5d2767b22f10"
 "checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1"
 "checksum num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "514f0d73e64be53ff320680ca671b64fe3fb91da01e1ae2ddc99eb51d453b20d"
 "checksum object 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "81afbc5773e99efe9533d8a539dfac37e531dcd0f4eeb41584bae03ccf76d4c2"
 "checksum once_cell 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "891f486f630e5c5a4916c7e16c4b24a53e78c860b646e9f8e005e4f16847bfed"
@@ -3985,29 +4048,31 @@ dependencies = [
 "checksum parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252"
 "checksum parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b"
 "checksum peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
 "checksum percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
 "checksum phf 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)" = "b3da44b85f8e8dfaec21adae67f95d93244b2ecf6ad2a692320598dcc8e6dd18"
 "checksum phf_codegen 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)" = "b03e85129e324ad4166b06b2c7491ae27fe3ec353af72e72cd1654c7225d517e"
 "checksum phf_generator 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)" = "09364cc93c159b8b06b1f4dd8a4398984503483891b0c26b867cf431fb132662"
 "checksum phf_shared 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)" = "234f71a15de2288bcb7e3b6515828d22af7ec8598ee6d24c3b526fa0a80b67a0"
+"checksum pkcs11 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff403ab0d15638fc795f4e2122e77e007fdcf17db7fee38f225f173c6e4cc1c3"
 "checksum pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3a8b4c6b8165cd1a1cd4b9b120978131389f64bdaf456435caa41e630edba903"
 "checksum plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6"
 "checksum plane-split 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ffe16a646a08f4b4dd74035b9ff8e378eb1a4012a74f14f5889e7001cdbece33"
 "checksum plist 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31850d149352e2b75f0e4b206045ee3775076c422892328343beca48a2b5cf17"
 "checksum png 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8422b27bb2c013dd97b9aef69e161ce262236f49aaf46a0489011c8ff0264602"
 "checksum podio 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e5422a1ee1bc57cc47ae717b0137314258138f38fd5f3cea083f43a9725383a0"
 "checksum precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
 "checksum proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)" = "4d317f9caece796be1980837fd5cb3dfec5613ebdb04ad0956deea83ce168915"
 "checksum proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "90cf5f418035b98e655e9cdb225047638296b862b42411c4e45bb88d700f7fc0"
 "checksum procedural-masquerade 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9f566249236c6ca4340f7ca78968271f0ed2b0f234007a61b66f9ecd0af09260"
 "checksum quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eda5fe9b71976e62bc81b781206aaa076401769b2143379d3eb2118388babac4"
 "checksum quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cdd8e04bd9c52e0342b406469d494fcb033be4bdbe5c606016defbb1681411e1"
 "checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
+"checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293"
 "checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"
 "checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"
 "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
 "checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0"
 "checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4"
 "checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08"
 "checksum rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b"
 "checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071"
@@ -4026,16 +4091,17 @@ dependencies = [
 "checksum rkv 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9aab7c645d32e977e186448b0a5c2c3139a91a7f630cfd8a8c314d1d145e78bf"
 "checksum ron 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "da06feaa07f69125ab9ddc769b11de29090122170b402547f64b86fe16ebc399"
 "checksum runloop 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d79b4b604167921892e84afbbaad9d5ad74e091bf6c511d9dbfb0593f09fabd"
 "checksum rust-argon2 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4ca4eaef519b494d1f2848fc602d18816fed808a981aedf4f1f00ceb7c9d32cf"
 "checksum rust-ini 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8a654c5bda722c699be6b0fe4c0d90de218928da5b724c3e467fc48865c37263"
 "checksum rust_cascade 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f3fe4900d38dab1ad21a515e44687dd0711e6b0ec5b214a3b1aa8857343bcf3a"
 "checksum rustc-demangle 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "76d7ba1feafada44f2d38eed812bd2489a03c0f5abb975799251518b68848649"
 "checksum rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7540fc8b0c49f096ee9c961cda096467dce8084bec6bdca2fc83895fd9b28cb8"
+"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
 "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
 "checksum ryu 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "fd0568787116e13c652377b6846f5931454a363a8fdf8ae50463ee40935b278b"
 "checksum safemem 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8dca453248a96cb0749e36ccdfe2b0b4e54a61bfef89fb97ec621eb8e0a93dd9"
 "checksum same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cfb6eded0b06a0b512c8ddbcf04089138c9b4362c2f696f3c3d76039d68f3637"
 "checksum scoped-tls 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2"
 "checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d"
 "checksum scroll 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2f84d114ef17fd144153d608fba7c446b0145d038985e7a8cc5d08bb0ce20383"
 "checksum scroll_derive 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)" = "8f1aa96c45e7f5a91cb7fabe7b279f02fea7126239fc40b732316e8b6a2d0fcb"
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -5,16 +5,17 @@
 # and do not need to be listed here. Their external dependencies are vendored
 # into `third_party/rust` by `mach vendor rust`.
 members = [
   "js/src",
   "js/src/rust",
   "js/src/wasm/cranelift",
   "js/rust",
   "js/src/frontend/binast", # Code generator.
+  "security/manager/ssl/osclientcerts",
   "testing/geckodriver",
   "toolkit/crashreporter/rust",
   "toolkit/library/gtest/rust",
   "toolkit/library/rust/",
 ]
 
 # Excluded crates may be built as dependencies, but won't be considered members
 # of the workspace and their dev-dependencies won't be included.
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -366,16 +366,20 @@ bin/libfreebl_64int_3.so
 @BINPATH@/@DLL_PREFIX@smime3@DLL_SUFFIX@
 @BINPATH@/@DLL_PREFIX@ssl3@DLL_SUFFIX@
 #endif
 @BINPATH@/@DLL_PREFIX@softokn3@DLL_SUFFIX@
 #endif
 @RESPATH@/chrome/pippki@JAREXT@
 @RESPATH@/chrome/pippki.manifest
 
+#if defined(XP_WIN)
+@BINPATH@/@DLL_PREFIX@osclientcerts@DLL_SUFFIX@
+#endif
+
 ; For process sandboxing
 #if defined(MOZ_SANDBOX)
 #if defined(XP_LINUX)
 @BINPATH@/@DLL_PREFIX@mozsandbox@DLL_SUFFIX@
 #endif
 #endif
 
 ; [Updater]
--- a/security/manager/ssl/moz.build
+++ b/security/manager/ssl/moz.build
@@ -1,14 +1,17 @@
 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
+if CONFIG['OS_ARCH'] == 'WINNT':
+    DIRS += [ 'osclientcerts' ]
+
 TEST_DIRS += [ 'tests' ]
 
 XPIDL_SOURCES += [
     'nsIASN1Object.idl',
     'nsIASN1PrintableItem.idl',
     'nsIASN1Sequence.idl',
     'nsIBadCertListener2.idl',
     'nsICertificateDialogs.idl',
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/osclientcerts/Cargo.toml
@@ -0,0 +1,26 @@
+[package]
+name = "osclientcerts-static"
+version = "0.1.4"
+authors = ["Dana Keeler <dkeeler@mozilla.com>"]
+edition = "2018"
+description = "Platform-specific support for client authentication certificates in Firefox"
+repository = "https://github.com/mozkeeler/osclientcerts"
+license = "MPL-2.0"
+
+[dependencies]
+byteorder = "1.3"
+env_logger = {version = "0.6", default-features = false } # disable `regex` to reduce code size
+lazy_static = "1"
+log = "0.4"
+pkcs11 = "0.4"
+sha2 = "0.8"
+
+[target."cfg(target_os = \"windows\")".dependencies.winapi]
+version = "0.3"
+features = ["wincrypt"]
+
+[build-dependencies]
+bindgen = {version = "0.51.1", default-features = false} # disable `logging` to reduce code size
+
+[lib]
+crate-type = ["staticlib"]
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/osclientcerts/build.rs
@@ -0,0 +1,24 @@
+/* -*- Mode: rust; rust-indent-offset: 4 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#[cfg(target_os = "windows")]
+use bindgen;
+
+use std::env;
+#[cfg(target_os = "windows")]
+use std::path::PathBuf;
+
+#[cfg(target_os = "windows")]
+fn main() {
+    let bindings = bindgen::Builder::default()
+        .header("src/wrapper-windows.h")
+        .whitelist_function("NCryptSignHash")
+        .generate()
+        .expect("Unable to generate bindings");
+    let out_path = PathBuf::from(env::var("OUT_DIR").expect("OUT_DIR unset?"));
+    bindings
+        .write_to_file(out_path.join("bindings.rs"))
+        .expect("Couldn't write bindings");
+}
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/osclientcerts/dynamic-library/moz.build
@@ -0,0 +1,27 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+USE_LIBS += ['osclientcerts-static']
+
+UNIFIED_SOURCES += [
+    'stub.cpp',
+]
+
+if CONFIG['OS_ARCH'] == 'WINNT':
+    OS_LIBS += [
+        'crypt32',
+        'kernel32',
+        'ncrypt',
+        'userenv',
+        'ws2_32',
+    ]
+
+SharedLibrary('osclientcerts')
+
+NoVisibilityFlags()
+SYMBOLS_FILE = 'osclientcerts.symbols'
+
+NO_PGO = True
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/osclientcerts/dynamic-library/osclientcerts.symbols
@@ -0,0 +1,1 @@
+C_GetFunctionList
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/osclientcerts/dynamic-library/stub.cpp
@@ -0,0 +1,8 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// This is an intentionally empty file. It is necessary for the build system to
+// successfully convert a static rust library into a dynamic library on
+// Windows.
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/osclientcerts/moz.build
@@ -0,0 +1,9 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+DIRS += [ 'dynamic-library' ]
+
+RustLibrary('osclientcerts-static')
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/osclientcerts/src/backend_windows.rs
@@ -0,0 +1,600 @@
+/* -*- Mode: rust; rust-indent-offset: 4 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#![allow(non_camel_case_types)]
+include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
+
+use pkcs11::types::*;
+use sha2::{Digest, Sha256};
+use std::convert::TryInto;
+use std::ffi::{CStr, CString};
+use std::ops::Deref;
+use std::slice;
+use winapi::shared::bcrypt::*;
+use winapi::um::ncrypt::*;
+use winapi::um::wincrypt::*;
+
+use crate::util::*;
+
+/// Given a `CERT_INFO`, tries to return the bytes of the subject distinguished name as formatted by
+/// `CertNameToStrA` using the flag `CERT_SIMPLE_NAME_STR`. This is used as the label for the
+/// certificate.
+fn get_cert_subject_dn(cert_info: &CERT_INFO) -> Result<Vec<u8>, ()> {
+    let mut cert_info_subject = cert_info.Subject;
+    let subject_dn_len = unsafe {
+        CertNameToStrA(
+            X509_ASN_ENCODING,
+            &mut cert_info_subject,
+            CERT_SIMPLE_NAME_STR,
+            std::ptr::null_mut(),
+            0,
+        )
+    };
+    // subject_dn_len includes the terminating null byte.
+    let mut subject_dn_string_bytes: Vec<u8> = vec![0; subject_dn_len as usize];
+    let subject_dn_len = unsafe {
+        CertNameToStrA(
+            X509_ASN_ENCODING,
+            &mut cert_info_subject,
+            CERT_SIMPLE_NAME_STR,
+            subject_dn_string_bytes.as_mut_ptr() as *mut i8,
+            subject_dn_string_bytes.len().try_into().map_err(|_| ())?,
+        )
+    };
+    if subject_dn_len as usize != subject_dn_string_bytes.len() {
+        return Err(());
+    }
+    Ok(subject_dn_string_bytes)
+}
+
+/// Represents a certificate for which there exists a corresponding private key.
+pub struct Cert {
+    /// PKCS #11 object class. Will be `CKO_CERTIFICATE`.
+    class: Vec<u8>,
+    /// Whether or not this is on a token. Will be `CK_TRUE`.
+    token: Vec<u8>,
+    /// An identifier unique to this certificate. Must be the same as the ID for the private key.
+    id: Vec<u8>,
+    /// The bytes of a human-readable label for this certificate. Will be the subject DN.
+    label: Vec<u8>,
+    /// The DER bytes of the certificate.
+    value: Vec<u8>,
+    /// The DER bytes of the issuer distinguished name of the certificate.
+    issuer: Vec<u8>,
+    /// The DER bytes of the serial number of the certificate.
+    serial_number: Vec<u8>,
+    /// The DER bytes of the subject distinguished name of the certificate.
+    subject: Vec<u8>,
+}
+
+impl Cert {
+    fn new(cert: PCCERT_CONTEXT) -> Result<Cert, ()> {
+        let cert = unsafe { &*cert };
+        let cert_info = unsafe { &*cert.pCertInfo };
+        let value =
+            unsafe { slice::from_raw_parts(cert.pbCertEncoded, cert.cbCertEncoded as usize) };
+        let value = value.to_vec();
+        let id = Sha256::digest(&value).to_vec();
+        let label = get_cert_subject_dn(&cert_info)?;
+        let issuer = unsafe {
+            slice::from_raw_parts(cert_info.Issuer.pbData, cert_info.Issuer.cbData as usize)
+        };
+        let issuer = issuer.to_vec();
+        let serial_number = unsafe {
+            slice::from_raw_parts(
+                cert_info.SerialNumber.pbData,
+                cert_info.SerialNumber.cbData as usize,
+            )
+        };
+        let serial_number = serial_number.to_vec();
+        let subject = unsafe {
+            slice::from_raw_parts(cert_info.Subject.pbData, cert_info.Subject.cbData as usize)
+        };
+        let subject = subject.to_vec();
+        Ok(Cert {
+            class: serialize_uint(CKO_CERTIFICATE)?,
+            token: serialize_uint(CK_TRUE)?,
+            id,
+            label,
+            value,
+            issuer,
+            serial_number,
+            subject,
+        })
+    }
+
+    fn class(&self) -> &[u8] {
+        &self.class
+    }
+
+    fn token(&self) -> &[u8] {
+        &self.token
+    }
+
+    pub fn id(&self) -> &[u8] {
+        &self.id
+    }
+
+    fn label(&self) -> &[u8] {
+        &self.label
+    }
+
+    fn value(&self) -> &[u8] {
+        &self.value
+    }
+
+    fn issuer(&self) -> &[u8] {
+        &self.issuer
+    }
+
+    fn serial_number(&self) -> &[u8] {
+        &self.serial_number
+    }
+
+    fn subject(&self) -> &[u8] {
+        &self.subject
+    }
+
+    fn matches(&self, attrs: &[(CK_ATTRIBUTE_TYPE, Vec<u8>)]) -> bool {
+        for (attr_type, attr_value) in attrs {
+            let comparison = match *attr_type {
+                CKA_CLASS => self.class(),
+                CKA_TOKEN => self.token(),
+                CKA_LABEL => self.label(),
+                CKA_ID => self.id(),
+                CKA_VALUE => self.value(),
+                CKA_ISSUER => self.issuer(),
+                CKA_SERIAL_NUMBER => self.serial_number(),
+                CKA_SUBJECT => self.subject(),
+                _ => return false,
+            };
+            if attr_value.as_slice() != comparison {
+                return false;
+            }
+        }
+        true
+    }
+
+    fn get_attribute(&self, attribute: CK_ATTRIBUTE_TYPE) -> Option<&[u8]> {
+        let result = match attribute {
+            CKA_CLASS => self.class(),
+            CKA_TOKEN => self.token(),
+            CKA_LABEL => self.label(),
+            CKA_ID => self.id(),
+            CKA_VALUE => self.value(),
+            CKA_ISSUER => self.issuer(),
+            CKA_SERIAL_NUMBER => self.serial_number(),
+            CKA_SUBJECT => self.subject(),
+            _ => return None,
+        };
+        Some(result)
+    }
+}
+
+struct CertContext(PCCERT_CONTEXT);
+
+// TODO: CERT_CONTEXT may not be thread-safe (unclear) (but in any case we're protected by the mutex
+// on the manager, so this should be ok?)
+unsafe impl Send for CertContext {}
+unsafe impl Sync for CertContext {}
+
+impl CertContext {
+    fn new(cert: PCCERT_CONTEXT) -> CertContext {
+        CertContext(unsafe { CertDuplicateCertificateContext(cert) })
+    }
+}
+
+impl Drop for CertContext {
+    fn drop(&mut self) {
+        unsafe {
+            CertFreeCertificateContext(self.0);
+        }
+    }
+}
+
+impl Deref for CertContext {
+    type Target = PCCERT_CONTEXT;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+struct NCryptKeyHandle(NCRYPT_KEY_HANDLE);
+
+impl NCryptKeyHandle {
+    fn from_cert(cert: &CertContext) -> Result<NCryptKeyHandle, ()> {
+        let mut key_handle = 0;
+        let mut key_spec = 0;
+        let mut must_free = 0;
+        unsafe {
+            if CryptAcquireCertificatePrivateKey(
+                **cert,
+                CRYPT_ACQUIRE_ONLY_NCRYPT_KEY_FLAG, // currently we only support CNG
+                std::ptr::null_mut(),
+                &mut key_handle,
+                &mut key_spec,
+                &mut must_free,
+            ) != 1
+            {
+                return Err(());
+            }
+        }
+        if key_spec != CERT_NCRYPT_KEY_SPEC {
+            error!("CryptAcquireCertificatePrivateKey returned non-ncrypt handle");
+            return Err(());
+        }
+        if must_free == 0 {
+            error!("CryptAcquireCertificatePrivateKey returned shared key handle");
+            return Err(());
+        }
+        Ok(NCryptKeyHandle(key_handle as NCRYPT_KEY_HANDLE))
+    }
+}
+
+impl Drop for NCryptKeyHandle {
+    fn drop(&mut self) {
+        unsafe {
+            NCryptFreeObject(self.0 as NCRYPT_HANDLE);
+        }
+    }
+}
+
+impl Deref for NCryptKeyHandle {
+    type Target = NCRYPT_KEY_HANDLE;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+/// A helper enum to identify a private key's type. We support EC and RSA.
+#[derive(Debug)]
+pub enum KeyType {
+    EC,
+    RSA,
+}
+
+/// Represents a private key for which there exists a corresponding certificate.
+pub struct Key {
+    /// A handle on the OS mechanism that represents the certificate for this key.
+    cert: CertContext,
+    /// PKCS #11 object class. Will be `CKO_PRIVATE_KEY`.
+    class: Vec<u8>,
+    /// Whether or not this is on a token. Will be `CK_TRUE`.
+    token: Vec<u8>,
+    /// An identifier unique to this key. Must be the same as the ID for the certificate.
+    id: Vec<u8>,
+    /// Whether or not this key is "private" (can it be exported?). Will be CK_TRUE (it can't be
+    /// exported).
+    private: Vec<u8>,
+    /// PKCS #11 key type. Will be `CKK_EC` for EC, and `CKK_RSA` for RSA.
+    key_type: Vec<u8>,
+    /// If this is an RSA key, this is the value of the modulus as an unsigned integer.
+    modulus: Option<Vec<u8>>,
+    /// If this is an EC key, this is the DER bytes of the OID identifying the curve the key is on.
+    ec_params: Option<Vec<u8>>,
+    /// An enum identifying this key's type.
+    key_type_enum: KeyType,
+}
+
+impl Key {
+    fn new(cert_context: PCCERT_CONTEXT) -> Result<Key, ()> {
+        let cert = unsafe { *cert_context };
+        let cert_der =
+            unsafe { slice::from_raw_parts(cert.pbCertEncoded, cert.cbCertEncoded as usize) };
+        let id = Sha256::digest(cert_der).to_vec();
+        let id = id.to_vec();
+        let cert_info = unsafe { &*cert.pCertInfo };
+        let mut modulus = None;
+        let mut ec_params = None;
+        let spki = &cert_info.SubjectPublicKeyInfo;
+        let algorithm_oid = unsafe { CStr::from_ptr(spki.Algorithm.pszObjId) }
+            .to_str()
+            .map_err(|_| ())?;
+        let (key_type_enum, key_type_attribute) = if algorithm_oid == szOID_RSA_RSA {
+            if spki.PublicKey.cUnusedBits != 0 {
+                return Err(());
+            }
+            let public_key_bytes = unsafe {
+                std::slice::from_raw_parts(spki.PublicKey.pbData, spki.PublicKey.cbData as usize)
+            };
+            let modulus_value = read_rsa_modulus(public_key_bytes)?;
+            modulus = Some(modulus_value);
+            (KeyType::RSA, CKK_RSA)
+        } else if algorithm_oid == szOID_ECC_PUBLIC_KEY {
+            let params = &spki.Algorithm.Parameters;
+            ec_params = Some(
+                unsafe { std::slice::from_raw_parts(params.pbData, params.cbData as usize) }
+                    .to_vec(),
+            );
+            (KeyType::EC, CKK_EC)
+        } else {
+            return Err(());
+        };
+        Ok(Key {
+            cert: CertContext::new(cert_context),
+            class: serialize_uint(CKO_PRIVATE_KEY)?,
+            token: serialize_uint(CK_TRUE)?,
+            id,
+            private: serialize_uint(CK_TRUE)?,
+            key_type: serialize_uint(key_type_attribute)?,
+            modulus,
+            ec_params,
+            key_type_enum,
+        })
+    }
+
+    fn class(&self) -> &[u8] {
+        &self.class
+    }
+
+    fn token(&self) -> &[u8] {
+        &self.token
+    }
+
+    pub fn id(&self) -> &[u8] {
+        &self.id
+    }
+
+    fn private(&self) -> &[u8] {
+        &self.private
+    }
+
+    fn key_type(&self) -> &[u8] {
+        &self.key_type
+    }
+
+    fn modulus(&self) -> Option<&[u8]> {
+        match &self.modulus {
+            Some(modulus) => Some(modulus.as_slice()),
+            None => None,
+        }
+    }
+
+    fn ec_params(&self) -> Option<&[u8]> {
+        match &self.ec_params {
+            Some(ec_params) => Some(ec_params.as_slice()),
+            None => None,
+        }
+    }
+
+    fn matches(&self, attrs: &[(CK_ATTRIBUTE_TYPE, Vec<u8>)]) -> bool {
+        for (attr_type, attr_value) in attrs {
+            let comparison = match *attr_type {
+                CKA_CLASS => self.class(),
+                CKA_TOKEN => self.token(),
+                CKA_ID => self.id(),
+                CKA_PRIVATE => self.private(),
+                CKA_KEY_TYPE => self.key_type(),
+                CKA_MODULUS => {
+                    if let Some(modulus) = self.modulus() {
+                        modulus
+                    } else {
+                        return false;
+                    }
+                }
+                CKA_EC_PARAMS => {
+                    if let Some(ec_params) = self.ec_params() {
+                        ec_params
+                    } else {
+                        return false;
+                    }
+                }
+                _ => return false,
+            };
+            if attr_value.as_slice() != comparison {
+                return false;
+            }
+        }
+        true
+    }
+
+    fn get_attribute(&self, attribute: CK_ATTRIBUTE_TYPE) -> Option<&[u8]> {
+        match attribute {
+            CKA_CLASS => Some(self.class()),
+            CKA_TOKEN => Some(self.token()),
+            CKA_ID => Some(self.id()),
+            CKA_PRIVATE => Some(self.private()),
+            CKA_KEY_TYPE => Some(self.key_type()),
+            CKA_MODULUS => self.modulus(),
+            CKA_EC_PARAMS => self.ec_params(),
+            _ => None,
+        }
+    }
+
+    pub fn get_signature_length(&self, data: &[u8]) -> Result<usize, ()> {
+        match self.sign_internal(data, false) {
+            Ok(dummy_signature_bytes) => Ok(dummy_signature_bytes.len()),
+            Err(()) => Err(()),
+        }
+    }
+
+    pub fn sign(&self, data: &[u8]) -> Result<Vec<u8>, ()> {
+        self.sign_internal(data, true)
+    }
+
+    /// data: the data to sign
+    /// do_signature: if true, actually perform the signature. Otherwise, return a `Vec<u8>` of the
+    /// length the signature would be, if performed.
+    fn sign_internal(&self, data: &[u8], do_signature: bool) -> Result<Vec<u8>, ()> {
+        // Acquiring a handle on the key can cause the OS to show some UI to the user, so we do this
+        // as late as possible (i.e. here).
+        let key = NCryptKeyHandle::from_cert(&self.cert)?;
+        // This only applies to RSA.
+        let mut padding_info = BCRYPT_PKCS1_PADDING_INFO {
+            // Because the hash algorithm is encoded in `data`, we don't have to (and don't want to)
+            // specify a particular algorithm here.
+            pszAlgId: std::ptr::null(),
+        };
+        let (padding_info_ptr, flags) = match self.key_type_enum {
+            KeyType::EC => (std::ptr::null_mut(), 0),
+            KeyType::RSA => (
+                &mut padding_info as *mut BCRYPT_PKCS1_PADDING_INFO,
+                NCRYPT_PAD_PKCS1_FLAG,
+            ),
+        };
+        let mut data = data.to_vec();
+        let mut signature_len = 0;
+        // We call NCryptSignHash twice: the first time to get the size of the buffer we need to
+        // allocate and then again to actually sign the data.
+        let status = unsafe {
+            NCryptSignHash(
+                *key,
+                padding_info_ptr as *mut std::ffi::c_void,
+                data.as_mut_ptr(),
+                data.len().try_into().map_err(|_| ())?,
+                std::ptr::null_mut(),
+                0,
+                &mut signature_len,
+                flags,
+            )
+        };
+        // 0 is "ERROR_SUCCESS" (but "ERROR_SUCCESS" is unsigned, whereas SECURITY_STATUS is signed)
+        if status != 0 {
+            error!(
+                "NCryptSignHash failed trying to get signature buffer length, {}",
+                status
+            );
+            return Err(());
+        }
+        let mut signature = vec![0; signature_len as usize];
+        if !do_signature {
+            return Ok(signature);
+        }
+        let mut final_signature_len = signature_len;
+        let status = unsafe {
+            NCryptSignHash(
+                *key,
+                padding_info_ptr as *mut std::ffi::c_void,
+                data.as_mut_ptr(),
+                data.len().try_into().map_err(|_| ())?,
+                signature.as_mut_ptr(),
+                signature_len,
+                &mut final_signature_len,
+                flags,
+            )
+        };
+        if status != 0 {
+            error!("NCryptSignHash failed signing data {}", status);
+            return Err(());
+        }
+        if final_signature_len != signature_len {
+            error!(
+                "NCryptSignHash: inconsistent signature lengths? {} != {}",
+                final_signature_len, signature_len
+            );
+            return Err(());
+        }
+        Ok(signature)
+    }
+}
+
+/// A helper enum that represents the two types of PKCS #11 objects we support: certificates and
+/// keys.
+pub enum Object {
+    Cert(Cert),
+    Key(Key),
+}
+
+impl Object {
+    pub fn matches(&self, attrs: &[(CK_ATTRIBUTE_TYPE, Vec<u8>)]) -> bool {
+        match self {
+            Object::Cert(cert) => cert.matches(attrs),
+            Object::Key(key) => key.matches(attrs),
+        }
+    }
+
+    pub fn get_attribute(&self, attribute: CK_ATTRIBUTE_TYPE) -> Option<&[u8]> {
+        match self {
+            Object::Cert(cert) => cert.get_attribute(attribute),
+            Object::Key(key) => key.get_attribute(attribute),
+        }
+    }
+}
+
+struct CertStore {
+    handle: HCERTSTORE,
+}
+
+impl Drop for CertStore {
+    fn drop(&mut self) {
+        if !self.handle.is_null() {
+            unsafe {
+                CertCloseStore(self.handle, 0);
+            }
+        }
+    }
+}
+
+impl Deref for CertStore {
+    type Target = HCERTSTORE;
+
+    fn deref(&self) -> &Self::Target {
+        &self.handle
+    }
+}
+
+impl CertStore {
+    fn new(handle: HCERTSTORE) -> CertStore {
+        CertStore { handle }
+    }
+}
+
+/// Attempts to enumerate certificates with private keys exposed by the OS. Currently only looks in
+/// the "My" cert store of the current user. In the future this may look in more locations.
+pub fn list_objects() -> Vec<Object> {
+    let mut objects = Vec::new();
+    let location_flags = CERT_SYSTEM_STORE_CURRENT_USER // TODO: loop over multiple locations
+        | CERT_STORE_OPEN_EXISTING_FLAG
+        | CERT_STORE_READONLY_FLAG;
+    let store_name = match CString::new("My") {
+        Ok(store_name) => store_name,
+        Err(null_error) => {
+            error!("CString::new given input with a null byte: {}", null_error);
+            return objects;
+        }
+    };
+    let store = CertStore::new(unsafe {
+        CertOpenStore(
+            CERT_STORE_PROV_SYSTEM_REGISTRY_A,
+            0,
+            0,
+            location_flags,
+            store_name.as_ptr() as *const winapi::ctypes::c_void,
+        )
+    });
+    if store.is_null() {
+        error!("CertOpenStore failed");
+        return objects;
+    }
+    let mut cert_context: PCCERT_CONTEXT = std::ptr::null_mut();
+    loop {
+        cert_context = unsafe {
+            CertFindCertificateInStore(
+                *store,
+                X509_ASN_ENCODING,
+                CERT_FIND_HAS_PRIVATE_KEY,
+                CERT_FIND_ANY,
+                std::ptr::null_mut(),
+                cert_context,
+            )
+        };
+        if cert_context.is_null() {
+            break;
+        }
+        let cert = match Cert::new(cert_context) {
+            Ok(cert) => cert,
+            Err(()) => continue,
+        };
+        let key = match Key::new(cert_context) {
+            Ok(key) => key,
+            Err(()) => continue,
+        };
+        objects.push(Object::Cert(cert));
+        objects.push(Object::Key(key));
+    }
+    objects
+}
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/osclientcerts/src/lib.rs
@@ -0,0 +1,1013 @@
+/* -*- Mode: rust; rust-indent-offset: 4 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#![allow(non_snake_case)]
+
+extern crate byteorder;
+extern crate env_logger;
+#[macro_use]
+extern crate lazy_static;
+#[macro_use]
+extern crate log;
+extern crate pkcs11;
+extern crate sha2;
+#[cfg(target_os = "windows")]
+extern crate winapi;
+
+use pkcs11::types::*;
+use std::sync::Mutex;
+
+#[cfg(target_os = "windows")]
+mod backend_windows;
+mod manager;
+mod util;
+
+use manager::Manager;
+
+lazy_static! {
+    /// The singleton `Manager` that handles state with respect to PKCS #11. Only one thread may
+    /// use it at a time.
+    static ref MANAGER: Mutex<Manager> = {
+        env_logger::init();
+        Mutex::new(Manager::new())
+    };
+}
+
+macro_rules! try_to_get_manager {
+    () => {
+        match MANAGER.lock() {
+            Ok(manager) => manager,
+            Err(poison_error) => {
+                error!(
+                    "previous thread panicked acquiring manager lock: {}",
+                    poison_error
+                );
+                return CKR_DEVICE_ERROR;
+            }
+        }
+    };
+}
+
+/// This gets called to initialize the module. For this implementation, this consists of
+/// instantiating the `Manager`.
+extern "C" fn C_Initialize(_pInitArgs: CK_C_INITIALIZE_ARGS_PTR) -> CK_RV {
+    // Getting the manager initializes our logging, so do it first.
+    let _manager = try_to_get_manager!();
+    debug!("C_Initialize: CKR_OK");
+    CKR_OK
+}
+
+extern "C" fn C_Finalize(_pReserved: CK_VOID_PTR) -> CK_RV {
+    debug!("C_Finalize: CKR_OK");
+    CKR_OK
+}
+
+// The specification mandates that these strings be padded with spaces to the appropriate length.
+// Since the length of fixed-size arrays in rust is part of the type, the compiler enforces that
+// these byte strings are of the correct length.
+const MANUFACTURER_ID_BYTES: &[u8; 32] = b"Mozilla Corporation             ";
+const LIBRARY_DESCRIPTION_BYTES: &[u8; 32] = b"OS Client Cert Module           ";
+
+/// This gets called to gather some information about the module. In particular, this implementation
+/// supports (portions of) cryptoki (PKCS #11) version 2.2.
+extern "C" fn C_GetInfo(pInfo: CK_INFO_PTR) -> CK_RV {
+    if pInfo.is_null() {
+        error!("C_GetInfo: CKR_ARGUMENTS_BAD");
+        return CKR_ARGUMENTS_BAD;
+    }
+    debug!("C_GetInfo: CKR_OK");
+    let mut info = CK_INFO::default();
+    info.cryptokiVersion.major = 2;
+    info.cryptokiVersion.minor = 2;
+    info.manufacturerID = *MANUFACTURER_ID_BYTES;
+    info.libraryDescription = *LIBRARY_DESCRIPTION_BYTES;
+    unsafe {
+        *pInfo = info;
+    }
+    CKR_OK
+}
+
+/// This module only has one slot. Its ID is 1.
+const SLOT_ID: CK_SLOT_ID = 1;
+
+/// This gets called twice: once with a null `pSlotList` to get the number of slots (returned via
+/// `pulCount`) and a second time to get the ID for each slot.
+extern "C" fn C_GetSlotList(
+    _tokenPresent: CK_BBOOL,
+    pSlotList: CK_SLOT_ID_PTR,
+    pulCount: CK_ULONG_PTR,
+) -> CK_RV {
+    if pulCount.is_null() {
+        error!("C_GetSlotList: CKR_ARGUMENTS_BAD");
+        return CKR_ARGUMENTS_BAD;
+    }
+    unsafe {
+        *pulCount = 1;
+    }
+    if !pSlotList.is_null() {
+        let slotCount = unsafe { *pulCount };
+        if slotCount < 1 {
+            error!("C_GetSlotList: CKR_BUFFER_TOO_SMALL");
+            return CKR_BUFFER_TOO_SMALL;
+        }
+        unsafe {
+            *pSlotList = SLOT_ID;
+        }
+    };
+    debug!("C_GetSlotList: CKR_OK");
+    CKR_OK
+}
+
+const SLOT_DESCRIPTION_BYTES: &[u8; 64] =
+    b"OS Client Cert Slot                                             ";
+
+/// This gets called to obtain information about slots. In this implementation, the token is always
+/// present in the slot.
+extern "C" fn C_GetSlotInfo(slotID: CK_SLOT_ID, pInfo: CK_SLOT_INFO_PTR) -> CK_RV {
+    if slotID != SLOT_ID || pInfo.is_null() {
+        error!("C_GetSlotInfo: CKR_ARGUMENTS_BAD");
+        return CKR_ARGUMENTS_BAD;
+    }
+    let slot_info = CK_SLOT_INFO {
+        slotDescription: *SLOT_DESCRIPTION_BYTES,
+        manufacturerID: *MANUFACTURER_ID_BYTES,
+        flags: CKF_TOKEN_PRESENT,
+        hardwareVersion: CK_VERSION::default(),
+        firmwareVersion: CK_VERSION::default(),
+    };
+    unsafe {
+        *pInfo = slot_info;
+    }
+    debug!("C_GetSlotInfo: CKR_OK");
+    CKR_OK
+}
+
+const TOKEN_LABEL_BYTES: &[u8; 32] = b"OS Client Cert Token            ";
+const TOKEN_MODEL_BYTES: &[u8; 16] = b"osclientcerts   ";
+const TOKEN_SERIAL_NUMBER_BYTES: &[u8; 16] = b"0000000000000000";
+
+/// This gets called to obtain some information about tokens. This implementation only has one slot,
+/// so it only has one token. This information is primarily for display purposes.
+extern "C" fn C_GetTokenInfo(slotID: CK_SLOT_ID, pInfo: CK_TOKEN_INFO_PTR) -> CK_RV {
+    if slotID != SLOT_ID || pInfo.is_null() {
+        error!("C_GetTokenInfo: CKR_ARGUMENTS_BAD");
+        return CKR_ARGUMENTS_BAD;
+    }
+    let mut token_info = CK_TOKEN_INFO::default();
+    token_info.label = *TOKEN_LABEL_BYTES;
+    token_info.manufacturerID = *MANUFACTURER_ID_BYTES;
+    token_info.model = *TOKEN_MODEL_BYTES;
+    token_info.serialNumber = *TOKEN_SERIAL_NUMBER_BYTES;
+    unsafe {
+        *pInfo = token_info;
+    }
+    debug!("C_GetTokenInfo: CKR_OK");
+    CKR_OK
+}
+
+/// This gets called to determine what mechanisms a slot supports. This implementation does not
+/// support any mechanisms.
+extern "C" fn C_GetMechanismList(
+    slotID: CK_SLOT_ID,
+    pMechanismList: CK_MECHANISM_TYPE_PTR,
+    pulCount: CK_ULONG_PTR,
+) -> CK_RV {
+    if slotID != SLOT_ID || pulCount.is_null() {
+        error!("C_GetMechanismList: CKR_ARGUMENTS_BAD");
+        return CKR_ARGUMENTS_BAD;
+    }
+    if pMechanismList.is_null() {
+        unsafe {
+            *pulCount = 0;
+        }
+    }
+    debug!("C_GetMechanismList: CKR_OK");
+    CKR_OK
+}
+
+extern "C" fn C_GetMechanismInfo(
+    _slotID: CK_SLOT_ID,
+    _type: CK_MECHANISM_TYPE,
+    _pInfo: CK_MECHANISM_INFO_PTR,
+) -> CK_RV {
+    error!("C_GetMechanismInfo: CKR_FUNCTION_NOT_SUPPORTED");
+    CKR_FUNCTION_NOT_SUPPORTED
+}
+
+extern "C" fn C_InitToken(
+    _slotID: CK_SLOT_ID,
+    _pPin: CK_UTF8CHAR_PTR,
+    _ulPinLen: CK_ULONG,
+    _pLabel: CK_UTF8CHAR_PTR,
+) -> CK_RV {
+    error!("C_InitToken: CKR_FUNCTION_NOT_SUPPORTED");
+    CKR_FUNCTION_NOT_SUPPORTED
+}
+
+extern "C" fn C_InitPIN(
+    _hSession: CK_SESSION_HANDLE,
+    _pPin: CK_UTF8CHAR_PTR,
+    _ulPinLen: CK_ULONG,
+) -> CK_RV {
+    error!("C_InitPIN: CKR_FUNCTION_NOT_SUPPORTED");
+    CKR_FUNCTION_NOT_SUPPORTED
+}
+
+extern "C" fn C_SetPIN(
+    _hSession: CK_SESSION_HANDLE,
+    _pOldPin: CK_UTF8CHAR_PTR,
+    _ulOldLen: CK_ULONG,
+    _pNewPin: CK_UTF8CHAR_PTR,
+    _ulNewLen: CK_ULONG,
+) -> CK_RV {
+    error!("C_SetPIN: CKR_FUNCTION_NOT_SUPPORTED");
+    CKR_FUNCTION_NOT_SUPPORTED
+}
+
+/// This gets called to create a new session. This module defers to the `Manager` to implement this.
+extern "C" fn C_OpenSession(
+    slotID: CK_SLOT_ID,
+    _flags: CK_FLAGS,
+    _pApplication: CK_VOID_PTR,
+    _Notify: CK_NOTIFY,
+    phSession: CK_SESSION_HANDLE_PTR,
+) -> CK_RV {
+    if slotID != SLOT_ID || phSession.is_null() {
+        error!("C_OpenSession: CKR_ARGUMENTS_BAD");
+        return CKR_ARGUMENTS_BAD;
+    }
+    let mut manager = try_to_get_manager!();
+    let session_handle = manager.open_session();
+    unsafe {
+        *phSession = session_handle;
+    }
+    debug!("C_OpenSession: CKR_OK");
+    CKR_OK
+}
+
+/// This gets called to close a session. This is proxied to the `Manager`.
+extern "C" fn C_CloseSession(hSession: CK_SESSION_HANDLE) -> CK_RV {
+    let mut manager = try_to_get_manager!();
+    if manager.close_session(hSession).is_err() {
+        error!("C_CloseSession: CKR_SESSION_HANDLE_INVALID");
+        return CKR_SESSION_HANDLE_INVALID;
+    }
+    debug!("C_CloseSession: CKR_OK");
+    CKR_OK
+}
+
+/// This gets called to close all open sessions at once. This is proxied to the `Manager`.
+extern "C" fn C_CloseAllSessions(slotID: CK_SLOT_ID) -> CK_RV {
+    if slotID != SLOT_ID {
+        error!("C_CloseAllSessions: CKR_ARGUMENTS_BAD");
+        return CKR_ARGUMENTS_BAD;
+    }
+    let mut manager = try_to_get_manager!();
+    manager.close_all_sessions();
+    debug!("C_CloseAllSessions: CKR_OK");
+    CKR_OK
+}
+
+extern "C" fn C_GetSessionInfo(_hSession: CK_SESSION_HANDLE, _pInfo: CK_SESSION_INFO_PTR) -> CK_RV {
+    error!("C_GetSessionInfo: CKR_FUNCTION_NOT_SUPPORTED");
+    CKR_FUNCTION_NOT_SUPPORTED
+}
+
+extern "C" fn C_GetOperationState(
+    _hSession: CK_SESSION_HANDLE,
+    _pOperationState: CK_BYTE_PTR,
+    _pulOperationStateLen: CK_ULONG_PTR,
+) -> CK_RV {
+    error!("C_GetOperationState: CKR_FUNCTION_NOT_SUPPORTED");
+    CKR_FUNCTION_NOT_SUPPORTED
+}
+
+extern "C" fn C_SetOperationState(
+    _hSession: CK_SESSION_HANDLE,
+    _pOperationState: CK_BYTE_PTR,
+    _ulOperationStateLen: CK_ULONG,
+    _hEncryptionKey: CK_OBJECT_HANDLE,
+    _hAuthenticationKey: CK_OBJECT_HANDLE,
+) -> CK_RV {
+    error!("C_SetOperationState: CKR_FUNCTION_NOT_SUPPORTED");
+    CKR_FUNCTION_NOT_SUPPORTED
+}
+
+extern "C" fn C_Login(
+    _hSession: CK_SESSION_HANDLE,
+    _userType: CK_USER_TYPE,
+    _pPin: CK_UTF8CHAR_PTR,
+    _ulPinLen: CK_ULONG,
+) -> CK_RV {
+    error!("C_Login: CKR_FUNCTION_NOT_SUPPORTED");
+    CKR_FUNCTION_NOT_SUPPORTED
+}
+
+/// This gets called to log out and drop any authenticated resources. Because this module does not
+/// hold on to authenticated resources, this module "implements" this by doing nothing and
+/// returning a success result.
+extern "C" fn C_Logout(_hSession: CK_SESSION_HANDLE) -> CK_RV {
+    debug!("C_Logout: CKR_OK");
+    CKR_OK
+}
+
+extern "C" fn C_CreateObject(
+    _hSession: CK_SESSION_HANDLE,
+    _pTemplate: CK_ATTRIBUTE_PTR,
+    _ulCount: CK_ULONG,
+    _phObject: CK_OBJECT_HANDLE_PTR,
+) -> CK_RV {
+    error!("C_CreateObject: CKR_FUNCTION_NOT_SUPPORTED");
+    CKR_FUNCTION_NOT_SUPPORTED
+}
+
+extern "C" fn C_CopyObject(
+    _hSession: CK_SESSION_HANDLE,
+    _hObject: CK_OBJECT_HANDLE,
+    _pTemplate: CK_ATTRIBUTE_PTR,
+    _ulCount: CK_ULONG,
+    _phNewObject: CK_OBJECT_HANDLE_PTR,
+) -> CK_RV {
+    error!("C_CopyObject: CKR_FUNCTION_NOT_SUPPORTED");
+    CKR_FUNCTION_NOT_SUPPORTED
+}
+
+extern "C" fn C_DestroyObject(_hSession: CK_SESSION_HANDLE, _hObject: CK_OBJECT_HANDLE) -> CK_RV {
+    error!("C_DestroyObject: CKR_FUNCTION_NOT_SUPPORTED");
+    CKR_FUNCTION_NOT_SUPPORTED
+}
+
+extern "C" fn C_GetObjectSize(
+    _hSession: CK_SESSION_HANDLE,
+    _hObject: CK_OBJECT_HANDLE,
+    _pulSize: CK_ULONG_PTR,
+) -> CK_RV {
+    error!("C_GetObjectSize: CKR_FUNCTION_NOT_SUPPORTED");
+    CKR_FUNCTION_NOT_SUPPORTED
+}
+
+/// This gets called to obtain the values of a number of attributes of an object identified by the
+/// given handle. This module implements this by requesting the object from the `Manager` and
+/// attempting to get the value of each attribute. If a specified attribute is not defined on the
+/// object, the length of that attribute is set to -1 to indicate that it is not available.
+/// This gets called twice: once to obtain the lengths of the attributes and again to get the
+/// values.
+extern "C" fn C_GetAttributeValue(
+    _hSession: CK_SESSION_HANDLE,
+    hObject: CK_OBJECT_HANDLE,
+    pTemplate: CK_ATTRIBUTE_PTR,
+    ulCount: CK_ULONG,
+) -> CK_RV {
+    if pTemplate.is_null() {
+        error!("C_GetAttributeValue: CKR_ARGUMENTS_BAD");
+        return CKR_ARGUMENTS_BAD;
+    }
+    let mut manager = try_to_get_manager!();
+    let object = match manager.get_object(hObject) {
+        Ok(object) => object,
+        Err(()) => {
+            error!("C_GetAttributeValue: CKR_ARGUMENTS_BAD");
+            return CKR_ARGUMENTS_BAD;
+        }
+    };
+    for i in 0..ulCount {
+        let mut attr = unsafe { &mut *pTemplate.offset(i as isize) };
+        if let Some(attr_value) = object.get_attribute(attr.attrType) {
+            if attr.pValue.is_null() {
+                attr.ulValueLen = attr_value.len() as CK_ULONG;
+            } else {
+                let ptr: *mut u8 = attr.pValue as *mut u8;
+                if attr_value.len() != attr.ulValueLen as usize {
+                    error!("C_GetAttributeValue: incorrect attr size");
+                    return CKR_ARGUMENTS_BAD;
+                }
+                unsafe {
+                    std::ptr::copy_nonoverlapping(attr_value.as_ptr(), ptr, attr_value.len());
+                }
+            }
+        } else {
+            attr.ulValueLen = (0 - 1) as CK_ULONG;
+        }
+    }
+    debug!("C_GetAttributeValue: CKR_OK");
+    CKR_OK
+}
+
+extern "C" fn C_SetAttributeValue(
+    _hSession: CK_SESSION_HANDLE,
+    _hObject: CK_OBJECT_HANDLE,
+    _pTemplate: CK_ATTRIBUTE_PTR,
+    _ulCount: CK_ULONG,
+) -> CK_RV {
+    error!("C_SetAttributeValue: CKR_FUNCTION_NOT_SUPPORTED");
+    CKR_FUNCTION_NOT_SUPPORTED
+}
+
+/// This gets called to initialize a search for objects matching a given list of attributes. This
+/// module implements this by gathering the attributes and passing them to the `Manager` to start
+/// the search.
+extern "C" fn C_FindObjectsInit(
+    hSession: CK_SESSION_HANDLE,
+    pTemplate: CK_ATTRIBUTE_PTR,
+    ulCount: CK_ULONG,
+) -> CK_RV {
+    if pTemplate.is_null() {
+        error!("C_FindObjectsInit: CKR_ARGUMENTS_BAD");
+        return CKR_ARGUMENTS_BAD;
+    }
+    let mut attrs = Vec::new();
+    info!("C_FindObjectsInit:");
+    for i in 0..ulCount {
+        let attr = unsafe { &*pTemplate.offset(i as isize) };
+        info!("  {:?}", attr);
+        let slice = unsafe {
+            std::slice::from_raw_parts(attr.pValue as *const u8, attr.ulValueLen as usize)
+        };
+        attrs.push((attr.attrType, slice.to_owned()));
+    }
+    let mut manager = try_to_get_manager!();
+    match manager.start_search(hSession, &attrs) {
+        Ok(()) => {}
+        Err(()) => {
+            error!("C_FindObjectsInit: CKR_ARGUMENTS_BAD");
+            return CKR_ARGUMENTS_BAD;
+        }
+    }
+    debug!("C_FindObjectsInit: CKR_OK");
+    CKR_OK
+}
+
+/// This gets called after `C_FindObjectsInit` to get the results of a search. This module
+/// implements this by looking up the search in the `Manager` and copying out the matching object
+/// handles.
+extern "C" fn C_FindObjects(
+    hSession: CK_SESSION_HANDLE,
+    phObject: CK_OBJECT_HANDLE_PTR,
+    ulMaxObjectCount: CK_ULONG,
+    pulObjectCount: CK_ULONG_PTR,
+) -> CK_RV {
+    if phObject.is_null() || pulObjectCount.is_null() || ulMaxObjectCount == 0 {
+        error!("C_FindObjects: CKR_ARGUMENTS_BAD");
+        return CKR_ARGUMENTS_BAD;
+    }
+    let mut manager = try_to_get_manager!();
+    let handles = match manager.search(hSession, ulMaxObjectCount as usize) {
+        Ok(handles) => handles,
+        Err(()) => {
+            error!("C_FindObjects: CKR_ARGUMENTS_BAD");
+            return CKR_ARGUMENTS_BAD;
+        }
+    };
+    debug!("C_FindObjects: found handles {:?}", handles);
+    if handles.len() > ulMaxObjectCount as usize {
+        error!("C_FindObjects: manager returned too many handles");
+        return CKR_DEVICE_ERROR;
+    }
+    unsafe {
+        *pulObjectCount = handles.len() as CK_ULONG;
+    }
+    for (index, handle) in handles.iter().enumerate() {
+        if index < ulMaxObjectCount as usize {
+            unsafe {
+                *(phObject.add(index)) = *handle;
+            }
+        }
+    }
+    debug!("C_FindObjects: CKR_OK");
+    CKR_OK
+}
+
+/// This gets called after `C_FindObjectsInit` and `C_FindObjects` to finish a search. The module
+/// tells the `Manager` to clear the search.
+extern "C" fn C_FindObjectsFinal(hSession: CK_SESSION_HANDLE) -> CK_RV {
+    let mut manager = try_to_get_manager!();
+    // It would be an error if there were no search for this session, but we can be permissive here.
+    manager.clear_search(hSession);
+    debug!("C_FindObjectsFinal: CKR_OK");
+    CKR_OK
+}
+
+extern "C" fn C_EncryptInit(
+    _hSession: CK_SESSION_HANDLE,
+    _pMechanism: CK_MECHANISM_PTR,
+    _hKey: CK_OBJECT_HANDLE,
+) -> CK_RV {
+    error!("C_EncryptInit: CKR_FUNCTION_NOT_SUPPORTED");
+    CKR_FUNCTION_NOT_SUPPORTED
+}
+
+extern "C" fn C_Encrypt(
+    _hSession: CK_SESSION_HANDLE,
+    _pData: CK_BYTE_PTR,
+    _ulDataLen: CK_ULONG,
+    _pEncryptedData: CK_BYTE_PTR,
+    _pulEncryptedDataLen: CK_ULONG_PTR,
+) -> CK_RV {
+    error!("C_Encrypt: CKR_FUNCTION_NOT_SUPPORTED");
+    CKR_FUNCTION_NOT_SUPPORTED
+}
+
+extern "C" fn C_EncryptUpdate(
+    _hSession: CK_SESSION_HANDLE,
+    _pPart: CK_BYTE_PTR,
+    _ulPartLen: CK_ULONG,
+    _pEncryptedPart: CK_BYTE_PTR,
+    _pulEncryptedPartLen: CK_ULONG_PTR,
+) -> CK_RV {
+    error!("C_EncryptUpdate: CKR_FUNCTION_NOT_SUPPORTED");
+    CKR_FUNCTION_NOT_SUPPORTED
+}
+
+extern "C" fn C_EncryptFinal(
+    _hSession: CK_SESSION_HANDLE,
+    _pLastEncryptedPart: CK_BYTE_PTR,
+    _pulLastEncryptedPartLen: CK_ULONG_PTR,
+) -> CK_RV {
+    error!("C_EncryptFinal: CKR_FUNCTION_NOT_SUPPORTED");
+    CKR_FUNCTION_NOT_SUPPORTED
+}
+
+extern "C" fn C_DecryptInit(
+    _hSession: CK_SESSION_HANDLE,
+    _pMechanism: CK_MECHANISM_PTR,
+    _hKey: CK_OBJECT_HANDLE,
+) -> CK_RV {
+    error!("C_DecryptInit: CKR_FUNCTION_NOT_SUPPORTED");
+    CKR_FUNCTION_NOT_SUPPORTED
+}
+
+extern "C" fn C_Decrypt(
+    _hSession: CK_SESSION_HANDLE,
+    _pEncryptedData: CK_BYTE_PTR,
+    _ulEncryptedDataLen: CK_ULONG,
+    _pData: CK_BYTE_PTR,
+    _pulDataLen: CK_ULONG_PTR,
+) -> CK_RV {
+    error!("C_Decrypt: CKR_FUNCTION_NOT_SUPPORTED");
+    CKR_FUNCTION_NOT_SUPPORTED
+}
+
+extern "C" fn C_DecryptUpdate(
+    _hSession: CK_SESSION_HANDLE,
+    _pEncryptedPart: CK_BYTE_PTR,
+    _ulEncryptedPartLen: CK_ULONG,
+    _pPart: CK_BYTE_PTR,
+    _pulPartLen: CK_ULONG_PTR,
+) -> CK_RV {
+    error!("C_DecryptUpdate: CKR_FUNCTION_NOT_SUPPORTED");
+    CKR_FUNCTION_NOT_SUPPORTED
+}
+
+extern "C" fn C_DecryptFinal(
+    _hSession: CK_SESSION_HANDLE,
+    _pLastPart: CK_BYTE_PTR,
+    _pulLastPartLen: CK_ULONG_PTR,
+) -> CK_RV {
+    error!("C_DecryptFinal: CKR_FUNCTION_NOT_SUPPORTED");
+    CKR_FUNCTION_NOT_SUPPORTED
+}
+
+extern "C" fn C_DigestInit(_hSession: CK_SESSION_HANDLE, _pMechanism: CK_MECHANISM_PTR) -> CK_RV {
+    error!("C_DigestInit: CKR_FUNCTION_NOT_SUPPORTED");
+    CKR_FUNCTION_NOT_SUPPORTED
+}
+
+extern "C" fn C_Digest(
+    _hSession: CK_SESSION_HANDLE,
+    _pData: CK_BYTE_PTR,
+    _ulDataLen: CK_ULONG,
+    _pDigest: CK_BYTE_PTR,
+    _pulDigestLen: CK_ULONG_PTR,
+) -> CK_RV {
+    error!("C_Digest: CKR_FUNCTION_NOT_SUPPORTED");
+    CKR_FUNCTION_NOT_SUPPORTED
+}
+
+extern "C" fn C_DigestUpdate(
+    _hSession: CK_SESSION_HANDLE,
+    _pPart: CK_BYTE_PTR,
+    _ulPartLen: CK_ULONG,
+) -> CK_RV {
+    error!("C_DigestUpdate: CKR_FUNCTION_NOT_SUPPORTED");
+    CKR_FUNCTION_NOT_SUPPORTED
+}
+
+extern "C" fn C_DigestKey(_hSession: CK_SESSION_HANDLE, _hKey: CK_OBJECT_HANDLE) -> CK_RV {
+    error!("C_DigestKey: CKR_FUNCTION_NOT_SUPPORTED");
+    CKR_FUNCTION_NOT_SUPPORTED
+}
+
+extern "C" fn C_DigestFinal(
+    _hSession: CK_SESSION_HANDLE,
+    _pDigest: CK_BYTE_PTR,
+    _pulDigestLen: CK_ULONG_PTR,
+) -> CK_RV {
+    error!("C_DigestFinal: CKR_FUNCTION_NOT_SUPPORTED");
+    CKR_FUNCTION_NOT_SUPPORTED
+}
+
+/// This gets called to set up a sign operation. The module essentially defers to the `Manager`.
+extern "C" fn C_SignInit(
+    hSession: CK_SESSION_HANDLE,
+    pMechanism: CK_MECHANISM_PTR,
+    hKey: CK_OBJECT_HANDLE,
+) -> CK_RV {
+    if pMechanism.is_null() {
+        error!("C_SignInit: CKR_ARGUMENTS_BAD");
+        return CKR_ARGUMENTS_BAD;
+    }
+    // pMechanism generally appears to be empty (just mechanism is set).
+    // Presumably we should validate the mechanism against hKey, but the specification doesn't
+    // actually seem to require this.
+    debug!("C_SignInit: mechanism is {:?}", unsafe { *pMechanism });
+    let mut manager = try_to_get_manager!();
+    match manager.start_sign(hSession, hKey) {
+        Ok(()) => {}
+        Err(()) => {
+            error!("C_SignInit: CKR_GENERAL_ERROR");
+            return CKR_GENERAL_ERROR;
+        }
+    };
+    debug!("C_SignInit: CKR_OK");
+    CKR_OK
+}
+
+/// NSS calls this after `C_SignInit` (there are more ways in the PKCS #11 specification to sign
+/// data, but this is the only way supported by this module). The module essentially defers to the
+/// `Manager` and copies out the resulting signature.
+extern "C" fn C_Sign(
+    hSession: CK_SESSION_HANDLE,
+    pData: CK_BYTE_PTR,
+    ulDataLen: CK_ULONG,
+    pSignature: CK_BYTE_PTR,
+    pulSignatureLen: CK_ULONG_PTR,
+) -> CK_RV {
+    if pData.is_null() || pulSignatureLen.is_null() {
+        error!("C_Sign: CKR_ARGUMENTS_BAD");
+        return CKR_ARGUMENTS_BAD;
+    }
+    let data = unsafe { std::slice::from_raw_parts(pData, ulDataLen as usize) };
+    if pSignature.is_null() {
+        let manager = try_to_get_manager!();
+        match manager.get_signature_length(hSession, data) {
+            Ok(signature_length) => unsafe {
+                *pulSignatureLen = signature_length as CK_ULONG;
+            },
+            Err(()) => {
+                error!("C_Sign: get_signature_length failed");
+                return CKR_GENERAL_ERROR;
+            }
+        }
+    } else {
+        let mut manager = try_to_get_manager!();
+        match manager.sign(hSession, data) {
+            Ok(signature) => {
+                let signature_capacity = unsafe { *pulSignatureLen } as usize;
+                if signature_capacity < signature.len() {
+                    error!("C_Sign: CKR_ARGUMENTS_BAD");
+                    return CKR_ARGUMENTS_BAD;
+                }
+                let ptr: *mut u8 = pSignature as *mut u8;
+                unsafe {
+                    std::ptr::copy_nonoverlapping(signature.as_ptr(), ptr, signature.len());
+                    *pulSignatureLen = signature.len() as CK_ULONG;
+                }
+            }
+            Err(()) => {
+                error!("C_Sign: sign failed");
+                return CKR_GENERAL_ERROR;
+            }
+        }
+    }
+    debug!("C_Sign: CKR_OK");
+    CKR_OK
+}
+
+extern "C" fn C_SignUpdate(
+    _hSession: CK_SESSION_HANDLE,
+    _pPart: CK_BYTE_PTR,
+    _ulPartLen: CK_ULONG,
+) -> CK_RV {
+    error!("C_SignUpdate: CKR_FUNCTION_NOT_SUPPORTED");
+    CKR_FUNCTION_NOT_SUPPORTED
+}
+
+extern "C" fn C_SignFinal(
+    _hSession: CK_SESSION_HANDLE,
+    _pSignature: CK_BYTE_PTR,
+    _pulSignatureLen: CK_ULONG_PTR,
+) -> CK_RV {
+    error!("C_SignFinal: CKR_FUNCTION_NOT_SUPPORTED");
+    CKR_FUNCTION_NOT_SUPPORTED
+}
+
+extern "C" fn C_SignRecoverInit(
+    _hSession: CK_SESSION_HANDLE,
+    _pMechanism: CK_MECHANISM_PTR,
+    _hKey: CK_OBJECT_HANDLE,
+) -> CK_RV {
+    error!("C_SignRecoverInit: CKR_FUNCTION_NOT_SUPPORTED");
+    CKR_FUNCTION_NOT_SUPPORTED
+}
+
+extern "C" fn C_SignRecover(
+    _hSession: CK_SESSION_HANDLE,
+    _pData: CK_BYTE_PTR,
+    _ulDataLen: CK_ULONG,
+    _pSignature: CK_BYTE_PTR,
+    _pulSignatureLen: CK_ULONG_PTR,
+) -> CK_RV {
+    error!("C_SignRecover: CKR_FUNCTION_NOT_SUPPORTED");
+    CKR_FUNCTION_NOT_SUPPORTED
+}
+
+extern "C" fn C_VerifyInit(
+    _hSession: CK_SESSION_HANDLE,
+    _pMechanism: CK_MECHANISM_PTR,
+    _hKey: CK_OBJECT_HANDLE,
+) -> CK_RV {
+    error!("C_VerifyInit: CKR_FUNCTION_NOT_SUPPORTED");
+    CKR_FUNCTION_NOT_SUPPORTED
+}
+
+extern "C" fn C_Verify(
+    _hSession: CK_SESSION_HANDLE,
+    _pData: CK_BYTE_PTR,
+    _ulDataLen: CK_ULONG,
+    _pSignature: CK_BYTE_PTR,
+    _ulSignatureLen: CK_ULONG,
+) -> CK_RV {
+    error!("C_Verify: CKR_FUNCTION_NOT_SUPPORTED");
+    CKR_FUNCTION_NOT_SUPPORTED
+}
+
+extern "C" fn C_VerifyUpdate(
+    _hSession: CK_SESSION_HANDLE,
+    _pPart: CK_BYTE_PTR,
+    _ulPartLen: CK_ULONG,
+) -> CK_RV {
+    error!("C_VerifyUpdate: CKR_FUNCTION_NOT_SUPPORTED");
+    CKR_FUNCTION_NOT_SUPPORTED
+}
+
+extern "C" fn C_VerifyFinal(
+    _hSession: CK_SESSION_HANDLE,
+    _pSignature: CK_BYTE_PTR,
+    _ulSignatureLen: CK_ULONG,
+) -> CK_RV {
+    error!("C_VerifyFinal: CKR_FUNCTION_NOT_SUPPORTED");
+    CKR_FUNCTION_NOT_SUPPORTED
+}
+
+extern "C" fn C_VerifyRecoverInit(
+    _hSession: CK_SESSION_HANDLE,
+    _pMechanism: CK_MECHANISM_PTR,
+    _hKey: CK_OBJECT_HANDLE,
+) -> CK_RV {
+    error!("C_VerifyRecoverInit: CKR_FUNCTION_NOT_SUPPORTED");
+    CKR_FUNCTION_NOT_SUPPORTED
+}
+
+extern "C" fn C_VerifyRecover(
+    _hSession: CK_SESSION_HANDLE,
+    _pSignature: CK_BYTE_PTR,
+    _ulSignatureLen: CK_ULONG,
+    _pData: CK_BYTE_PTR,
+    _pulDataLen: CK_ULONG_PTR,
+) -> CK_RV {
+    error!("C_VerifyRecover: CKR_FUNCTION_NOT_SUPPORTED");
+    CKR_FUNCTION_NOT_SUPPORTED
+}
+
+extern "C" fn C_DigestEncryptUpdate(
+    _hSession: CK_SESSION_HANDLE,
+    _pPart: CK_BYTE_PTR,
+    _ulPartLen: CK_ULONG,
+    _pEncryptedPart: CK_BYTE_PTR,
+    _pulEncryptedPartLen: CK_ULONG_PTR,
+) -> CK_RV {
+    error!("C_DigestEncryptUpdate: CKR_FUNCTION_NOT_SUPPORTED");
+    CKR_FUNCTION_NOT_SUPPORTED
+}
+
+extern "C" fn C_DecryptDigestUpdate(
+    _hSession: CK_SESSION_HANDLE,
+    _pEncryptedPart: CK_BYTE_PTR,
+    _ulEncryptedPartLen: CK_ULONG,
+    _pPart: CK_BYTE_PTR,
+    _pulPartLen: CK_ULONG_PTR,
+) -> CK_RV {
+    error!("C_DecryptDigestUpdate: CKR_FUNCTION_NOT_SUPPORTED");
+    CKR_FUNCTION_NOT_SUPPORTED
+}
+
+extern "C" fn C_SignEncryptUpdate(
+    _hSession: CK_SESSION_HANDLE,
+    _pPart: CK_BYTE_PTR,
+    _ulPartLen: CK_ULONG,
+    _pEncryptedPart: CK_BYTE_PTR,
+    _pulEncryptedPartLen: CK_ULONG_PTR,
+) -> CK_RV {
+    error!("C_SignEncryptUpdate: CKR_FUNCTION_NOT_SUPPORTED");
+    CKR_FUNCTION_NOT_SUPPORTED
+}
+
+extern "C" fn C_DecryptVerifyUpdate(
+    _hSession: CK_SESSION_HANDLE,
+    _pEncryptedPart: CK_BYTE_PTR,
+    _ulEncryptedPartLen: CK_ULONG,
+    _pPart: CK_BYTE_PTR,
+    _pulPartLen: CK_ULONG_PTR,
+) -> CK_RV {
+    error!("C_DecryptVerifyUpdate: CKR_FUNCTION_NOT_SUPPORTED");
+    CKR_FUNCTION_NOT_SUPPORTED
+}
+
+extern "C" fn C_GenerateKey(
+    _hSession: CK_SESSION_HANDLE,
+    _pMechanism: CK_MECHANISM_PTR,
+    _pTemplate: CK_ATTRIBUTE_PTR,
+    _ulCount: CK_ULONG,
+    _phKey: CK_OBJECT_HANDLE_PTR,
+) -> CK_RV {
+    error!("C_GenerateKey: CKR_FUNCTION_NOT_SUPPORTED");
+    CKR_FUNCTION_NOT_SUPPORTED
+}
+
+extern "C" fn C_GenerateKeyPair(
+    _hSession: CK_SESSION_HANDLE,
+    _pMechanism: CK_MECHANISM_PTR,
+    _pPublicKeyTemplate: CK_ATTRIBUTE_PTR,
+    _ulPublicKeyAttributeCount: CK_ULONG,
+    _pPrivateKeyTemplate: CK_ATTRIBUTE_PTR,
+    _ulPrivateKeyAttributeCount: CK_ULONG,
+    _phPublicKey: CK_OBJECT_HANDLE_PTR,
+    _phPrivateKey: CK_OBJECT_HANDLE_PTR,
+) -> CK_RV {
+    error!("C_GenerateKeyPair: CKR_FUNCTION_NOT_SUPPORTED");
+    CKR_FUNCTION_NOT_SUPPORTED
+}
+
+extern "C" fn C_WrapKey(
+    _hSession: CK_SESSION_HANDLE,
+    _pMechanism: CK_MECHANISM_PTR,
+    _hWrappingKey: CK_OBJECT_HANDLE,
+    _hKey: CK_OBJECT_HANDLE,
+    _pWrappedKey: CK_BYTE_PTR,
+    _pulWrappedKeyLen: CK_ULONG_PTR,
+) -> CK_RV {
+    error!("C_WrapKey: CKR_FUNCTION_NOT_SUPPORTED");
+    CKR_FUNCTION_NOT_SUPPORTED
+}
+
+extern "C" fn C_UnwrapKey(
+    _hSession: CK_SESSION_HANDLE,
+    _pMechanism: CK_MECHANISM_PTR,
+    _hUnwrappingKey: CK_OBJECT_HANDLE,
+    _pWrappedKey: CK_BYTE_PTR,
+    _ulWrappedKeyLen: CK_ULONG,
+    _pTemplate: CK_ATTRIBUTE_PTR,
+    _ulAttributeCount: CK_ULONG,
+    _phKey: CK_OBJECT_HANDLE_PTR,
+) -> CK_RV {
+    error!("C_UnwrapKey: CKR_FUNCTION_NOT_SUPPORTED");
+    CKR_FUNCTION_NOT_SUPPORTED
+}
+
+extern "C" fn C_DeriveKey(
+    _hSession: CK_SESSION_HANDLE,
+    _pMechanism: CK_MECHANISM_PTR,
+    _hBaseKey: CK_OBJECT_HANDLE,
+    _pTemplate: CK_ATTRIBUTE_PTR,
+    _ulAttributeCount: CK_ULONG,
+    _phKey: CK_OBJECT_HANDLE_PTR,
+) -> CK_RV {
+    error!("C_DeriveKey: CKR_FUNCTION_NOT_SUPPORTED");
+    CKR_FUNCTION_NOT_SUPPORTED
+}
+
+extern "C" fn C_SeedRandom(
+    _hSession: CK_SESSION_HANDLE,
+    _pSeed: CK_BYTE_PTR,
+    _ulSeedLen: CK_ULONG,
+) -> CK_RV {
+    error!("C_SeedRandom: CKR_FUNCTION_NOT_SUPPORTED");
+    CKR_FUNCTION_NOT_SUPPORTED
+}
+
+extern "C" fn C_GenerateRandom(
+    _hSession: CK_SESSION_HANDLE,
+    _RandomData: CK_BYTE_PTR,
+    _ulRandomLen: CK_ULONG,
+) -> CK_RV {
+    error!("C_GenerateRandom: CKR_FUNCTION_NOT_SUPPORTED");
+    CKR_FUNCTION_NOT_SUPPORTED
+}
+
+extern "C" fn C_GetFunctionStatus(_hSession: CK_SESSION_HANDLE) -> CK_RV {
+    error!("C_GetFunctionStatus: CKR_FUNCTION_NOT_SUPPORTED");
+    CKR_FUNCTION_NOT_SUPPORTED
+}
+
+extern "C" fn C_CancelFunction(_hSession: CK_SESSION_HANDLE) -> CK_RV {
+    error!("C_CancelFunction: CKR_FUNCTION_NOT_SUPPORTED");
+    CKR_FUNCTION_NOT_SUPPORTED
+}
+
+extern "C" fn C_WaitForSlotEvent(
+    _flags: CK_FLAGS,
+    _pSlot: CK_SLOT_ID_PTR,
+    _pRserved: CK_VOID_PTR,
+) -> CK_RV {
+    error!("C_WaitForSlotEvent: CKR_FUNCTION_NOT_SUPPORTED");
+    CKR_FUNCTION_NOT_SUPPORTED
+}
+
+/// To be a valid PKCS #11 module, this list of functions must be supported. At least cryptoki 2.2
+/// must be supported for this module to work in NSS.
+static mut FUNCTION_LIST: CK_FUNCTION_LIST = CK_FUNCTION_LIST {
+    version: CK_VERSION { major: 2, minor: 2 },
+    C_Initialize: Some(C_Initialize),
+    C_Finalize: Some(C_Finalize),
+    C_GetInfo: Some(C_GetInfo),
+    C_GetFunctionList: None,
+    C_GetSlotList: Some(C_GetSlotList),
+    C_GetSlotInfo: Some(C_GetSlotInfo),
+    C_GetTokenInfo: Some(C_GetTokenInfo),
+    C_GetMechanismList: Some(C_GetMechanismList),
+    C_GetMechanismInfo: Some(C_GetMechanismInfo),
+    C_InitToken: Some(C_InitToken),
+    C_InitPIN: Some(C_InitPIN),
+    C_SetPIN: Some(C_SetPIN),
+    C_OpenSession: Some(C_OpenSession),
+    C_CloseSession: Some(C_CloseSession),
+    C_CloseAllSessions: Some(C_CloseAllSessions),
+    C_GetSessionInfo: Some(C_GetSessionInfo),
+    C_GetOperationState: Some(C_GetOperationState),
+    C_SetOperationState: Some(C_SetOperationState),
+    C_Login: Some(C_Login),
+    C_Logout: Some(C_Logout),
+    C_CreateObject: Some(C_CreateObject),
+    C_CopyObject: Some(C_CopyObject),
+    C_DestroyObject: Some(C_DestroyObject),
+    C_GetObjectSize: Some(C_GetObjectSize),
+    C_GetAttributeValue: Some(C_GetAttributeValue),
+    C_SetAttributeValue: Some(C_SetAttributeValue),
+    C_FindObjectsInit: Some(C_FindObjectsInit),
+    C_FindObjects: Some(C_FindObjects),
+    C_FindObjectsFinal: Some(C_FindObjectsFinal),
+    C_EncryptInit: Some(C_EncryptInit),
+    C_Encrypt: Some(C_Encrypt),
+    C_EncryptUpdate: Some(C_EncryptUpdate),
+    C_EncryptFinal: Some(C_EncryptFinal),
+    C_DecryptInit: Some(C_DecryptInit),
+    C_Decrypt: Some(C_Decrypt),
+    C_DecryptUpdate: Some(C_DecryptUpdate),
+    C_DecryptFinal: Some(C_DecryptFinal),
+    C_DigestInit: Some(C_DigestInit),
+    C_Digest: Some(C_Digest),
+    C_DigestUpdate: Some(C_DigestUpdate),
+    C_DigestKey: Some(C_DigestKey),
+    C_DigestFinal: Some(C_DigestFinal),
+    C_SignInit: Some(C_SignInit),
+    C_Sign: Some(C_Sign),
+    C_SignUpdate: Some(C_SignUpdate),
+    C_SignFinal: Some(C_SignFinal),
+    C_SignRecoverInit: Some(C_SignRecoverInit),
+    C_SignRecover: Some(C_SignRecover),
+    C_VerifyInit: Some(C_VerifyInit),
+    C_Verify: Some(C_Verify),
+    C_VerifyUpdate: Some(C_VerifyUpdate),
+    C_VerifyFinal: Some(C_VerifyFinal),
+    C_VerifyRecoverInit: Some(C_VerifyRecoverInit),
+    C_VerifyRecover: Some(C_VerifyRecover),
+    C_DigestEncryptUpdate: Some(C_DigestEncryptUpdate),
+    C_DecryptDigestUpdate: Some(C_DecryptDigestUpdate),
+    C_SignEncryptUpdate: Some(C_SignEncryptUpdate),
+    C_DecryptVerifyUpdate: Some(C_DecryptVerifyUpdate),
+    C_GenerateKey: Some(C_GenerateKey),
+    C_GenerateKeyPair: Some(C_GenerateKeyPair),
+    C_WrapKey: Some(C_WrapKey),
+    C_UnwrapKey: Some(C_UnwrapKey),
+    C_DeriveKey: Some(C_DeriveKey),
+    C_SeedRandom: Some(C_SeedRandom),
+    C_GenerateRandom: Some(C_GenerateRandom),
+    C_GetFunctionStatus: Some(C_GetFunctionStatus),
+    C_CancelFunction: Some(C_CancelFunction),
+    C_WaitForSlotEvent: Some(C_WaitForSlotEvent),
+};
+
+/// This is the only function this module exposes. NSS calls it to obtain the list of functions
+/// comprising this module.
+#[no_mangle]
+pub extern "C" fn C_GetFunctionList(ppFunctionList: CK_FUNCTION_LIST_PTR_PTR) -> CK_RV {
+    if ppFunctionList.is_null() {
+        return CKR_ARGUMENTS_BAD;
+    }
+    unsafe {
+        *ppFunctionList = &mut FUNCTION_LIST;
+    }
+    CKR_OK
+}
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/osclientcerts/src/manager.rs
@@ -0,0 +1,221 @@
+/* -*- Mode: rust; rust-indent-offset: 4 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+use pkcs11::types::*;
+use std::collections::{BTreeMap, BTreeSet};
+
+#[cfg(target_os = "windows")]
+use crate::backend_windows as backend;
+use backend::*;
+
+/// The `Manager` keeps track of the state of this module with respect to the PKCS #11
+/// specification. This includes what sessions are open, which search and sign operations are
+/// ongoing, and what objects are known and by what handle.
+pub struct Manager {
+    /// A set of sessions. Sessions can be created (opened) and later closed.
+    sessions: BTreeSet<CK_SESSION_HANDLE>,
+    /// A map of searches to PKCS #11 object handles that match those searches.
+    searches: BTreeMap<CK_SESSION_HANDLE, Vec<CK_OBJECT_HANDLE>>,
+    /// A map of sign operations to the object handle being used by each one.
+    signs: BTreeMap<CK_SESSION_HANDLE, CK_OBJECT_HANDLE>,
+    /// A map of object handles to the underlying objects.
+    objects: BTreeMap<CK_OBJECT_HANDLE, Object>,
+    /// A set of certificate identifiers (not the same as handles).
+    cert_ids: BTreeSet<Vec<u8>>,
+    /// A set of key identifiers (not the same as handles). For each id in this set, there should be
+    /// a corresponding identical id in the `cert_ids` set, and vice-versa.
+    key_ids: BTreeSet<Vec<u8>>,
+    /// The next session handle to hand out.
+    next_session: CK_SESSION_HANDLE,
+    /// The next object handle to hand out.
+    next_handle: CK_OBJECT_HANDLE,
+}
+
+impl Manager {
+    pub fn new() -> Manager {
+        let mut manager = Manager {
+            sessions: BTreeSet::new(),
+            searches: BTreeMap::new(),
+            signs: BTreeMap::new(),
+            objects: BTreeMap::new(),
+            cert_ids: BTreeSet::new(),
+            key_ids: BTreeSet::new(),
+            next_session: 1,
+            next_handle: 1,
+        };
+        manager.find_new_objects();
+        manager
+    }
+
+    /// When a new `Manager` is created and when a new session is opened, this searches for
+    /// certificates and keys to expose. We de-duplicate previously-found certificates and keys by
+    /// keeping track of their IDs.
+    fn find_new_objects(&mut self) {
+        let objects = list_objects();
+        debug!("found {} objects", objects.len());
+        for object in objects {
+            match &object {
+                Object::Cert(cert) => {
+                    if self.cert_ids.contains(cert.id()) {
+                        continue;
+                    }
+                    self.cert_ids.insert(cert.id().to_vec());
+                    let handle = self.get_next_handle();
+                    self.objects.insert(handle, object);
+                }
+                Object::Key(key) => {
+                    if self.key_ids.contains(key.id()) {
+                        continue;
+                    }
+                    self.key_ids.insert(key.id().to_vec());
+                    let handle = self.get_next_handle();
+                    self.objects.insert(handle, object);
+                }
+            }
+        }
+    }
+
+    pub fn open_session(&mut self) -> CK_SESSION_HANDLE {
+        self.find_new_objects();
+        let next_session = self.next_session;
+        self.next_session += 1;
+        self.sessions.insert(next_session);
+        next_session
+    }
+
+    pub fn close_session(&mut self, session: CK_SESSION_HANDLE) -> Result<(), ()> {
+        if self.sessions.remove(&session) {
+            Ok(())
+        } else {
+            Err(())
+        }
+    }
+
+    pub fn close_all_sessions(&mut self) {
+        self.sessions.clear();
+    }
+
+    fn get_next_handle(&mut self) -> CK_OBJECT_HANDLE {
+        let next_handle = self.next_handle;
+        self.next_handle += 1;
+        next_handle
+    }
+
+    /// PKCS #11 specifies that search operations happen in three phases: setup, get any matches
+    /// (this part may be repeated if the caller uses a small buffer), and end. This implementation
+    /// does all of the work up front and gathers all matching objects during setup and retains them
+    /// until they are retrieved and consumed via `search`.
+    pub fn start_search(
+        &mut self,
+        session: CK_SESSION_HANDLE,
+        attrs: &[(CK_ATTRIBUTE_TYPE, Vec<u8>)],
+    ) -> Result<(), ()> {
+        if self.searches.contains_key(&session) {
+            return Err(());
+        }
+        let mut handles = Vec::new();
+        for (handle, object) in &self.objects {
+            if object.matches(attrs) {
+                handles.push(*handle);
+            }
+        }
+        self.searches.insert(session, handles);
+        Ok(())
+    }
+
+    /// Given a session and a maximum number of object handles to return, attempts to retrieve up to
+    /// that many objects from the corresponding search. Updates the search so those objects are not
+    /// returned repeatedly. `max_objects` must be non-zero.
+    pub fn search(
+        &mut self,
+        session: CK_SESSION_HANDLE,
+        max_objects: usize,
+    ) -> Result<Vec<CK_OBJECT_HANDLE>, ()> {
+        if max_objects == 0 {
+            return Err(());
+        }
+        match self.searches.get_mut(&session) {
+            Some(search) => {
+                let split_at = if max_objects >= search.len() {
+                    0
+                } else {
+                    search.len() - max_objects
+                };
+                let to_return = search.split_off(split_at);
+                if to_return.len() > max_objects {
+                    error!(
+                        "search trying to return too many handles: {} > {}",
+                        to_return.len(),
+                        max_objects
+                    );
+                    return Err(());
+                }
+                Ok(to_return)
+            }
+            None => Err(()),
+        }
+    }
+
+    pub fn clear_search(&mut self, session: CK_SESSION_HANDLE) {
+        self.searches.remove(&session);
+    }
+
+    pub fn get_object(&mut self, object_handle: CK_OBJECT_HANDLE) -> Result<&Object, ()> {
+        match self.objects.get(&object_handle) {
+            Some(object) => Ok(object),
+            None => Err(()),
+        }
+    }
+
+    /// The way NSS uses PKCS #11 to sign data happens in two phases: setup and sign. This
+    /// implementation makes a note of which key is to be used (if it exists) during setup. When the
+    /// caller finishes with the sign operation, this implementation retrieves the key handle and
+    /// performs the signature.
+    pub fn start_sign(
+        &mut self,
+        session: CK_SESSION_HANDLE,
+        key_handle: CK_OBJECT_HANDLE,
+    ) -> Result<(), ()> {
+        if self.signs.contains_key(&session) {
+            return Err(());
+        }
+        match self.objects.get(&key_handle) {
+            Some(Object::Key(_)) => {}
+            _ => return Err(()),
+        };
+        self.signs.insert(session, key_handle);
+        Ok(())
+    }
+
+    pub fn get_signature_length(
+        &self,
+        session: CK_SESSION_HANDLE,
+        data: &[u8],
+    ) -> Result<usize, ()> {
+        let key_handle = match self.signs.get(&session) {
+            Some(key_handle) => key_handle,
+            None => return Err(()),
+        };
+        let key = match self.objects.get(&key_handle) {
+            Some(Object::Key(key)) => key,
+            _ => return Err(()),
+        };
+        key.get_signature_length(data)
+    }
+
+    pub fn sign(&mut self, session: CK_SESSION_HANDLE, data: &[u8]) -> Result<Vec<u8>, ()> {
+        // Performing the signature (via C_Sign, which is the only way we support) finishes the sign
+        // operation, so it needs to be removed here.
+        let key_handle = match self.signs.remove(&session) {
+            Some(key_handle) => key_handle,
+            None => return Err(()),
+        };
+        let key = match self.objects.get(&key_handle) {
+            Some(Object::Key(key)) => key,
+            _ => return Err(()),
+        };
+        key.sign(data)
+    }
+}
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/osclientcerts/src/util.rs
@@ -0,0 +1,287 @@
+/* -*- Mode: rust; rust-indent-offset: 4 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+use byteorder::{BigEndian, NativeEndian, ReadBytesExt, WriteBytesExt};
+use std::convert::TryInto;
+
+// This is a helper function to take a value and lay it out in memory how
+// PKCS#11 is expecting it.
+pub fn serialize_uint<T: TryInto<u64>>(value: T) -> Result<Vec<u8>, ()> {
+    let value_size = std::mem::size_of::<T>();
+    let mut value_buf = Vec::with_capacity(value_size);
+    let value_as_u64 = value.try_into().map_err(|_| ())?;
+    value_buf
+        .write_uint::<NativeEndian>(value_as_u64, value_size)
+        .map_err(|_| ())?;
+    Ok(value_buf)
+}
+
+/// Given a slice of DER bytes representing an RSA public key, extracts the bytes of the modulus
+/// as an unsigned integer. Also verifies that the public exponent is present (again as an
+/// unsigned integer). Finally verifies that reading these values consumes the entirety of the
+/// slice.
+/// RSAPublicKey ::= SEQUENCE {
+///     modulus           INTEGER,  -- n
+///     publicExponent    INTEGER   -- e
+/// }
+pub fn read_rsa_modulus(public_key: &[u8]) -> Result<Vec<u8>, ()> {
+    let mut sequence = Sequence::new(public_key)?;
+    let modulus_value = sequence.read_unsigned_integer()?;
+    let _exponent = sequence.read_unsigned_integer()?;
+    if !sequence.at_end() {
+        return Err(());
+    }
+    Ok(modulus_value.to_vec())
+}
+
+/// Helper macro for reading some bytes from a slice while checking the slice is long enough.
+/// Returns a pair consisting of a slice of the bytes read and a slice of the rest of the bytes
+/// from the original slice.
+macro_rules! try_read_bytes {
+    ($data:ident, $len:expr) => {{
+        if $data.len() < $len {
+            return Err(());
+        }
+        $data.split_at($len)
+    }};
+}
+
+/// ASN.1 tag identifying an integer.
+const INTEGER: u8 = 0x02;
+/// ASN.1 tag identifying a sequence.
+const SEQUENCE: u8 = 0x10;
+/// ASN.1 tag modifier identifying an item as constructed.
+const CONSTRUCTED: u8 = 0x20;
+
+/// A helper struct for reading items from a DER SEQUENCE (in this case, all sequences are
+/// assumed to be CONSTRUCTED).
+struct Sequence<'a> {
+    /// The contents of the SEQUENCE.
+    contents: Der<'a>,
+}
+
+impl<'a> Sequence<'a> {
+    fn new(input: &'a [u8]) -> Result<Sequence<'a>, ()> {
+        let mut der = Der::new(input);
+        let sequence_bytes = der.read(SEQUENCE | CONSTRUCTED)?;
+        // We're assuming we want to consume the entire input for now.
+        if !der.at_end() {
+            return Err(());
+        }
+        Ok(Sequence {
+            contents: Der::new(sequence_bytes),
+        })
+    }
+
+    // TODO: we're not exhaustively validating this integer
+    fn read_unsigned_integer(&mut self) -> Result<&'a [u8], ()> {
+        let bytes = self.contents.read(INTEGER)?;
+        if bytes.is_empty() {
+            return Err(());
+        }
+        // There may be a leading zero (we should also check that the first bit
+        // of the rest of the integer is set).
+        if bytes[0] == 0 && bytes.len() > 1 {
+            let (_, integer) = bytes.split_at(1);
+            Ok(integer)
+        } else {
+            Ok(bytes)
+        }
+    }
+
+    fn at_end(&self) -> bool {
+        self.contents.at_end()
+    }
+}
+
+/// A helper struct for reading DER data. The contents are treated like a cursor, so its position
+/// is updated as data is read.
+struct Der<'a> {
+    contents: &'a [u8],
+}
+
+impl<'a> Der<'a> {
+    fn new(contents: &'a [u8]) -> Der<'a> {
+        Der { contents }
+    }
+
+    // In theory, a caller could encounter an error and try another operation, in which case we may
+    // be in an inconsistent state. As long as this implementation isn't exposed to code that would
+    // use it incorrectly (i.e. it stays in this module and we only expose a stateless API), it
+    // should be safe.
+    fn read(&mut self, tag: u8) -> Result<&'a [u8], ()> {
+        let contents = self.contents;
+        let (tag_read, rest) = try_read_bytes!(contents, 1);
+        if tag_read[0] != tag {
+            return Err(());
+        }
+        let (length1, rest) = try_read_bytes!(rest, 1);
+        let (length, to_read_from) = if length1[0] < 0x80 {
+            (length1[0] as usize, rest)
+        } else if length1[0] == 0x81 {
+            let (length, rest) = try_read_bytes!(rest, 1);
+            if length[0] < 0x80 {
+                return Err(());
+            }
+            (length[0] as usize, rest)
+        } else if length1[0] == 0x82 {
+            let (lengths, rest) = try_read_bytes!(rest, 2);
+            let length = (&mut &lengths[..])
+                .read_u16::<BigEndian>()
+                .map_err(|_| ())?;
+            if length < 256 {
+                return Err(());
+            }
+            (length as usize, rest)
+        } else {
+            return Err(());
+        };
+        let (contents, rest) = try_read_bytes!(to_read_from, length);
+        self.contents = rest;
+        Ok(contents)
+    }
+
+    fn at_end(&self) -> bool {
+        self.contents.is_empty()
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn der_test_empty_input() {
+        let input = Vec::new();
+        let mut der = Der::new(&input);
+        assert!(der.read(INTEGER).is_err());
+    }
+
+    #[test]
+    fn der_test_no_length() {
+        let input = vec![INTEGER];
+        let mut der = Der::new(&input);
+        assert!(der.read(INTEGER).is_err());
+    }
+
+    #[test]
+    fn der_test_empty_sequence() {
+        let input = vec![SEQUENCE, 0];
+        let mut der = Der::new(&input);
+        let read_result = der.read(SEQUENCE);
+        assert!(read_result.is_ok());
+        let sequence_bytes = read_result.unwrap();
+        assert_eq!(sequence_bytes.len(), 0);
+        assert!(der.at_end());
+    }
+
+    #[test]
+    fn der_test_not_at_end() {
+        let input = vec![SEQUENCE, 0, 1];
+        let mut der = Der::new(&input);
+        let read_result = der.read(SEQUENCE);
+        assert!(read_result.is_ok());
+        let sequence_bytes = read_result.unwrap();
+        assert_eq!(sequence_bytes.len(), 0);
+        assert!(!der.at_end());
+    }
+
+    #[test]
+    fn der_test_wrong_tag() {
+        let input = vec![SEQUENCE, 0];
+        let mut der = Der::new(&input);
+        assert!(der.read(INTEGER).is_err());
+    }
+
+    #[test]
+    fn der_test_truncated_two_byte_length() {
+        let input = vec![SEQUENCE, 0x81];
+        let mut der = Der::new(&input);
+        assert!(der.read(SEQUENCE).is_err());
+    }
+
+    #[test]
+    fn der_test_truncated_three_byte_length() {
+        let input = vec![SEQUENCE, 0x82, 1];
+        let mut der = Der::new(&input);
+        assert!(der.read(SEQUENCE).is_err());
+    }
+
+    #[test]
+    fn der_test_truncated_data() {
+        let input = vec![SEQUENCE, 20, 1];
+        let mut der = Der::new(&input);
+        assert!(der.read(SEQUENCE).is_err());
+    }
+
+    #[test]
+    fn der_test_sequence() {
+        let input = vec![
+            SEQUENCE, 20, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 0, 0,
+        ];
+        let mut der = Der::new(&input);
+        let result = der.read(SEQUENCE);
+        assert!(result.is_ok());
+        assert_eq!(
+            result.unwrap(),
+            [1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 0, 0]
+        );
+        assert!(der.at_end());
+    }
+
+    #[test]
+    fn der_test_not_shortest_two_byte_length_encoding() {
+        let input = vec![SEQUENCE, 0x81, 1, 1];
+        let mut der = Der::new(&input);
+        assert!(der.read(SEQUENCE).is_err());
+    }
+
+    #[test]
+    fn der_test_not_shortest_three_byte_length_encoding() {
+        let input = vec![SEQUENCE, 0x82, 0, 1, 1];
+        let mut der = Der::new(&input);
+        assert!(der.read(SEQUENCE).is_err());
+    }
+
+    #[test]
+    fn der_test_indefinite_length_unsupported() {
+        let input = vec![SEQUENCE, 0x80, 1, 2, 3, 0x00, 0x00];
+        let mut der = Der::new(&input);
+        assert!(der.read(SEQUENCE).is_err());
+    }
+
+    #[test]
+    fn der_test_input_too_long() {
+        // This isn't valid DER (the contents of the SEQUENCE are truncated), but it demonstrates
+        // that we don't try to read too much if we're given a long length (and also that we don't
+        // support lengths 2^16 and up).
+        let input = vec![SEQUENCE, 0x83, 0x01, 0x00, 0x01, 1, 1, 1, 1];
+        let mut der = Der::new(&input);
+        assert!(der.read(SEQUENCE).is_err());
+    }
+
+    #[test]
+    fn empty_input_fails() {
+        let empty = Vec::new();
+        assert!(read_rsa_modulus(&empty).is_err());
+        assert!(read_ec_sig_point(&empty).is_err());
+    }
+
+    #[test]
+    fn empty_sequence_fails() {
+        let empty = vec![SEQUENCE | CONSTRUCTED];
+        assert!(read_rsa_modulus(&empty).is_err());
+        assert!(read_ec_sig_point(&empty).is_err());
+    }
+
+    #[test]
+    fn test_read_rsa_modulus() {
+        let rsa_key = include_bytes!("../test/rsa.bin");
+        let result = read_rsa_modulus(rsa_key);
+        assert!(result.is_ok());
+        let modulus = result.unwrap();
+        assert_eq!(modulus, include_bytes!("../test/modulus.bin").to_vec());
+    }
+}
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/osclientcerts/src/wrapper-windows.h
@@ -0,0 +1,6 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include <Windows.h>
+#include <ncrypt.h>
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/osclientcerts/test/modulus.bin
@@ -0,0 +1,2 @@
+QDAn6=<5JhWl${%nkZukjdqzZE$~Ci8 ) I۹Lkl~i:*Ap
f+$}ayW=;H7ӈC'UfZ~/:{$la[u1ݴ%	h{/"oi㴊a&%N6$,/1I#rQ1
+5
\ No newline at end of file
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..93ededb8276f99197e850461bc81f16ec58d271e
GIT binary patch
literal 270
zc$@(a0rCDYf&mHwf&l>lx`<JzM2;5LLH%yFhz2$gJv<ZH>f|*_wCwe0S8ODE!N(=2
z;MgC%v782*ZW@O2YvQk3b!%#5aR_>)TBk*a_Z-zEoC1E$L;N0T&^RC|ldB-ZN#xtP
zOu}ny4(%0!5AlAjX&SN90y>K-LGGt;;13Or{bma*uq2YCeYuEXd62PJkUi2n#o)L|
zAE-Ceh(qru7T8s{W?HI#0+25{dk}yIB+MLam#vmzTesqt62NsaqYRPVw95DVtsN!P
z3GcZV4yS10vwJThZ)xMSij`p<?k3hHovV=uPBzONBm^wK7K<<C@sF7oF}Sn-NhA7l
UQN%IT1FYH@3N`JG0s{d60j39gqyPW_
new file mode 100644
--- /dev/null
+++ b/third_party/rust/libloading-0.4.3/.cargo-checksum.json
@@ -0,0 +1,1 @@
+{"files":{"Cargo.toml":"e3db29aefcf98671c707fab96d5d5b1964b79734faeea0d8dc6d94ef7d8fbaef","LICENSE":"b29f8b01452350c20dd1af16ef83b598fea3053578ccc1c7a0ef40e57be2620f","README.mkd":"34dc610b01f8c3e56d95de1972120ca0d53cee787f636a3ce96526ab343878b5","appveyor.yml":"8382c7f1769f6cf78029a221058c4d73f35a48308b5dfc38d875facabec1c139","build.rs":"b0cab713feb1fa86fec27af607272f2964e79cca6637ae837a1dfd9d88b67dd4","src/changelog.rs":"f0cf85f7de1c9807941bb832b2827f26efff8ec8bef14a38153c3f6c9a5831b5","src/lib.rs":"baa087dec7103adafc8c548e3baa1167af6d6d6be13a147fb19b880743f67182","src/os/mod.rs":"51d733e5522dacd6069642ad66aa6d7acf6c82950c934eb040e8dfd112e6d610","src/os/unix/mod.rs":"2af876458bf0012f7c0a06e8e976aff897410e22f3776c34ab1f2aa79fbd59aa","src/os/windows/mod.rs":"06ba72c9140c063696a579df2e57532fa3e470584fa304608a4268e6ba4ff8ad","src/test_helpers.rs":"3a55052e8cd5231e97d9282b43398c2f144c57ced2d2df64bde7f482f5c778e7","src/util.rs":"0b0155448a26db4b00b2a6ca129e0e1f6f75870c56c9777d262941818c7581b7","tests/functions.rs":"4633f3673db6a5b3623ea8927b13314c25502c9fbb63bb17a5a35650ea489012","tests/markers.rs":"8e9c1b883404d9190e4f23ed39b3d6cbbccb3a07883f733b04aed4357b9c6aca","tests/nagisa32.dll":"5c69b2bd9c8a6ad04165c221075fc9fade1dd66ca697399ace528a5a62328e36","tests/nagisa64.dll":"e20b95e3036f3289421abd100760874d4f455afd33c3b5b64fec56b191f7d477","tests/windows.rs":"7711dfe19062d91356cd127546542b1b6e13aeef76ad3098f32c8a6ae319b66a"},"package":"fd38073de8f7965d0c17d30546d4bb6da311ab428d1c7a3fc71dff7f9d4979b9"}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/third_party/rust/libloading-0.4.3/Cargo.toml
@@ -0,0 +1,29 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g. crates.io) dependencies
+#
+# If you believe there's an error in this file please file an
+# issue against the rust-lang/cargo repository. If you're
+# editing this file be aware that the upstream Cargo.toml
+# will likely look very different (and much more reasonable)
+
+[package]
+name = "libloading"
+version = "0.4.3"
+authors = ["Simonas Kazlauskas <libloading@kazlauskas.me>"]
+build = "build.rs"
+description = "A safer binding to platform’s dynamic library loading utilities"
+documentation = "https://docs.rs/libloading/"
+keywords = ["dlopen", "load", "shared", "dylib"]
+license = "ISC"
+repository = "https://github.com/nagisa/rust_libloading/"
+[dependencies.lazy_static]
+version = "1"
+[target."cfg(windows)".dependencies.kernel32-sys]
+version = "0.2"
+
+[target."cfg(windows)".dependencies.winapi]
+version = "0.2"
new file mode 100644
--- /dev/null
+++ b/third_party/rust/libloading-0.4.3/LICENSE
@@ -0,0 +1,12 @@
+Copyright © 2015, Simonas Kazlauskas
+
+Permission to use, copy, modify, and/or distribute this software for any purpose with or without
+fee is hereby granted, provided that the above copyright notice and this permission notice appear
+in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
new file mode 100644
--- /dev/null
+++ b/third_party/rust/libloading-0.4.3/README.mkd
@@ -0,0 +1,27 @@
+# libloading [![Travis CI][tcii]][tci] [![Appveyor CI][acii]][aci]
+
+[tcii]: https://travis-ci.org/nagisa/rust_libloading.svg?branch=master
+[tci]: https://travis-ci.org/nagisa/rust_libloading
+[acii]: https://ci.appveyor.com/api/projects/status/cnncnu58qcxb1ikf/branch/master?svg=true
+[aci]: https://ci.appveyor.com/project/nagisa/rust-libloading
+
+A memory-safer wrapper around system dynamic library loading primitives. The most important safety
+guarantee by this library is prevention of dangling-`Symbol`s that may occur after a `Library` is
+unloaded.
+
+Using this library allows loading dynamic libraries (also known as shared libraries) as well as use
+functions and static variables these libraries contain.
+
+* [Documentation][docs]
+* [Changelog][changelog]
+
+[docs]: https://docs.rs/libloading/
+[changelog]: https://docs.rs/libloading/*/libloading/changelog/index.html
+
+libloading is distributed under ISC (MIT-like) license.
+
+---
+
+Note, that this library is not a drop-in replacement for the deprecated `dynamic_lib`. Many
+dubious APIs (notably, library search path modification) were prunned and string arguments
+take types that match conventions and system APIs better.
new file mode 100644
--- /dev/null
+++ b/third_party/rust/libloading-0.4.3/appveyor.yml
@@ -0,0 +1,19 @@
+environment:
+  matrix:
+  - TARGET: nightly-x86_64-pc-windows-msvc
+  - TARGET: nightly-i686-pc-windows-msvc
+  - TARGET: nightly-x86_64-pc-windows-gnu
+  - TARGET: nightly-i686-pc-windows-gnu
+  - TARGET: 1.14.0-x86_64-pc-windows-msvc
+  - TARGET: 1.14.0-i686-pc-windows-msvc
+  - TARGET: 1.14.0-x86_64-pc-windows-gnu
+  - TARGET: 1.14.0-i686-pc-windows-gnu
+install:
+  - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-${env:TARGET}.exe" -FileName "rust.exe"
+  - ps: .\rust.exe /VERYSILENT /NORESTART /DIR="C:\rust" | Out-Null
+  - ps: $env:PATH="$env:PATH;C:\rust\bin"
+  - rustc -vV
+  - cargo -vV
+build: off
+test_script:
+  - cargo test
new file mode 100644
--- /dev/null
+++ b/third_party/rust/libloading-0.4.3/build.rs
@@ -0,0 +1,23 @@
+use std::io::Write;
+use std::env;
+
+fn main(){
+    let target_os = env::var("CARGO_CFG_TARGET_OS");
+    match target_os.as_ref().map(|x| &**x) {
+        Ok("linux") | Ok("android") => println!("cargo:rustc-link-lib=dl"),
+        Ok("freebsd") | Ok("dragonfly") => println!("cargo:rustc-link-lib=c"),
+        // netbsd claims dl* will be available to any dynamically linked binary, but I haven’t
+        // found any libraries that have to be linked to on other platforms.
+        // What happens if the executable is not linked up dynamically?
+        Ok("openbsd") | Ok("bitrig") | Ok("netbsd") | Ok("macos") | Ok("ios") => {}
+        Ok("solaris") => {}
+        // dependencies come with winapi
+        Ok("windows") => {}
+        tos => {
+            writeln!(::std::io::stderr(),
+                     "Building for an unknown target_os=`{:?}`!\nPlease report an issue ",
+                     tos).expect("could not report the error");
+            ::std::process::exit(0xfc);
+        }
+    }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/libloading-0.4.3/src/changelog.rs
@@ -0,0 +1,79 @@
+//! Project changelog
+
+/// Release 0.4.3 (2017-12-07)
+///
+/// * Bump lazy-static dependency to `^1.0`
+/// * `cargo test --release` now works when testing libloading.
+pub mod r0_4_3 {}
+
+
+/// Release 0.4.2 (2017-09-24)
+///
+/// * Improved error and race-condition handling on Windows;
+/// * Improved documentation about thread-safety of Library;
+/// * Added `Symbol::<Option<T>::lift_option() -> Option<Symbol<T>>` convenience method.
+pub mod r0_4_2 {}
+
+
+/// Release 0.4.1 (2017-08-29)
+///
+/// * Solaris support
+pub mod r0_4_1 {}
+
+/// Release 0.4.0 (2017-05-01)
+///
+/// * Remove build-time dependency on target_build_utils (and by extension serde/phf);
+/// * Require at least version 1.14.0 of rustc to build;
+///   * Actually, it is cargo which has to be more recent here. The one shipped with rustc 1.14.0
+///     is what’s being required from now on.
+pub mod r0_4_0 {}
+
+/// Release 0.3.4 (2017-03-25)
+///
+/// * Remove rogue println!
+pub mod r0_3_4 {}
+
+/// Release 0.3.3 (2017-03-25)
+///
+/// * Panics when `Library::get` is called for incompatibly sized type such as named function
+///   types (which are zero-sized).
+pub mod r0_3_3 {}
+
+/// Release 0.3.2 (2017-02-10)
+///
+/// * Minimum version required is now rustc 1.12.0;
+/// * Updated dependency versions (most notably target_build_utils to 0.3.0)
+pub mod r0_3_2 {}
+
+/// Release 0.3.1 (2016-10-01)
+///
+/// * `Symbol<T>` and `os::*::Symbol<T>` now implement `Send` where `T: Send`;
+/// * `Symbol<T>` and `os::*::Symbol<T>` now implement `Sync` where `T: Sync`;
+/// * `Library` and `os::*::Library` now implement `Sync` (they were `Send` in 0.3.0 already).
+pub mod r0_3_1 {}
+
+/// Release 0.3.0 (2016-07-27)
+///
+/// * Greatly improved documentation, especially around platform-specific behaviours;
+/// * Improved test suite by building our own library to test against;
+/// * All `Library`-ies now implement `Send`.
+/// * Added `impl From<os::platform::Library> for Library` and `impl From<Library> for
+/// os::platform::Library` allowing wrapping and extracting the platform-specific library handle;
+/// * Added methods to wrap (`Symbol::from_raw`) and unwrap (`Symbol::into_raw`) the safe `Symbol`
+/// wrapper into unsafe `os::platform::Symbol`.
+///
+/// The last two additions focus on not restricting potential usecases of this library, allowing
+/// users of the library to circumvent safety checks if need be.
+///
+/// ## Beaking Changes
+///
+/// `Library::new` defaults to `RTLD_NOW` instead of `RTLD_LAZY` on UNIX for more consistent
+/// cross-platform behaviour. If a library loaded with `Library::new` had any linking errors, but
+/// unresolved references weren’t forced to be resolved, the library would’ve “just worked”,
+/// whereas now the call to `Library::new` will return an error signifying presence of such error.
+///
+/// ## os::platform
+/// * Added `os::unix::Library::open` which allows specifying arbitrary flags (e.g. `RTLD_LAZY`);
+/// * Added `os::windows::Library::get_ordinal` which allows finding a function or variable by its
+/// ordinal number;
+pub mod r0_3_0 {}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/libloading-0.4.3/src/lib.rs
@@ -0,0 +1,314 @@
+//! A memory-safer wrapper around system dynamic library loading primitives.
+//!
+//! Using this library allows loading [dynamic libraries](struct.Library.html) (also known as
+//! shared libraries) as well as use functions and static variables these libraries contain.
+//!
+//! While the library does expose a cross-platform interface to load a library and find stuff
+//! inside it, little is done to paper over the platform differences, especially where library
+//! loading is involved. The documentation for each function will attempt to document such
+//! differences on the best-effort basis.
+//!
+//! Less safe, platform specific bindings are also available. See the
+//! [`os::platform`](os/index.html) module for details.
+//!
+//! # Usage
+//!
+//! Add dependency to this library to your `Cargo.toml`:
+//!
+//! ```toml
+//! [dependencies]
+//! libloading = "0.4"
+//! ```
+//!
+//! Then inside your project
+//!
+//! ```no_run
+//! extern crate libloading as lib;
+//!
+//! fn call_dynamic() -> lib::Result<u32> {
+//!     let lib = lib::Library::new("/path/to/liblibrary.so")?;
+//!     unsafe {
+//!         let func: lib::Symbol<unsafe extern fn() -> u32> = lib.get(b"my_func")?;
+//!         Ok(func())
+//!     }
+//! }
+//! ```
+//!
+//! The compiler will ensure that the loaded `function` will not outlive the `Library` it comes
+//! from, preventing a common cause of undefined behaviour and memory safety problems.
+use std::ffi::OsStr;
+use std::fmt;
+use std::ops;
+use std::marker;
+
+#[cfg(unix)]
+#[macro_use]
+extern crate lazy_static;
+
+#[cfg(unix)]
+use self::os::unix as imp;
+#[cfg(windows)]
+use self::os::windows as imp;
+
+pub mod os;
+pub mod changelog;
+mod util;
+
+pub type Result<T> = ::std::io::Result<T>;
+
+/// A loaded dynamic library.
+pub struct Library(imp::Library);
+
+impl Library {
+    /// Find and load a dynamic library.
+    ///
+    /// The `filename` argument may be any of:
+    ///
+    /// * A library filename;
+    /// * Absolute path to the library;
+    /// * Relative (to the current working directory) path to the library.
+    ///
+    /// ## Thread-safety
+    ///
+    /// The implementation strives to be as MT-safe as sanely possible, however due to certain
+    /// error-handling related resources not always being safe, this library is not MT-safe either.
+    ///
+    /// * On Windows Vista and earlier error handling falls back to [`SetErrorMode`], which is not
+    ///   MT-safe. MT-scenarios involving this function may cause a traditional data race;
+    /// * On some UNIX targets `dlerror` might not be MT-safe, resulting in garbage error messages
+    ///   in certain MT-scenarios.
+    ///
+    /// [`SetErrorMode`]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms680621(v=vs.85).aspx
+    ///
+    /// Calling this function from multiple threads is not safe if used in conjunction with
+    /// path-less filename and library search path is modified (`SetDllDirectory` function on
+    /// Windows, `{DY,}LD_LIBRARY_PATH` environment variable on UNIX).
+    ///
+    /// ## Platform-specific behaviour
+    ///
+    /// When a plain library filename is supplied, locations where library is searched for is
+    /// platform specific and cannot be adjusted in a portable manner.
+    ///
+    /// ### Windows
+    ///
+    /// If the `filename` specifies a library filename without path and with extension omitted,
+    /// `.dll` extension is implicitly added. This behaviour may be suppressed by appending a
+    /// trailing `.` to the `filename`.
+    ///
+    /// If the library contains thread local variables (MSVC’s `_declspec(thread)`, Rust’s
+    /// `#[thread_local]` attributes), loading the library will fail on versions prior to Windows
+    /// Vista.
+    ///
+    /// ## Tips
+    ///
+    /// Distributing your dynamic libraries under a filename common to all platforms (e.g.
+    /// `awesome.module`) allows to avoid code which has to account for platform’s conventional
+    /// library filenames.
+    ///
+    /// Strive to specify absolute or relative path to your library, unless system-wide libraries
+    /// are being loaded.  Platform-dependent library search locations combined with various quirks
+    /// related to path-less filenames may cause flaky code.
+    ///
+    /// ## Examples
+    ///
+    /// ```no_run
+    /// # use ::libloading::Library;
+    /// // Any of the following are valid.
+    /// let _ = Library::new("/path/to/awesome.module").unwrap();
+    /// let _ = Library::new("../awesome.module").unwrap();
+    /// let _ = Library::new("libsomelib.so.1").unwrap();
+    /// ```
+    pub fn new<P: AsRef<OsStr>>(filename: P) -> Result<Library> {
+        imp::Library::new(filename).map(From::from)
+    }
+
+    /// Get a pointer to function or static variable by symbol name.
+    ///
+    /// The `symbol` may not contain any null bytes, with an exception of last byte. A null
+    /// terminated `symbol` may avoid a string allocation in some cases.
+    ///
+    /// Symbol is interpreted as-is; no mangling is done. This means that symbols like `x::y` are
+    /// most likely invalid.
+    ///
+    /// ## Unsafety
+    ///
+    /// Pointer to a value of arbitrary type is returned. Using a value with wrong type is
+    /// undefined.
+    ///
+    /// ## Platform-specific behaviour
+    ///
+    /// On Linux and Windows, a TLS variable acts just like any regular static variable. OS X uses
+    /// some sort of lazy initialization scheme, which makes loading TLS variables this way
+    /// impossible. Using a TLS variable loaded this way on OS X is undefined behaviour.
+    ///
+    /// ## Examples
+    ///
+    /// Given a loaded library:
+    ///
+    /// ```no_run
+    /// # use ::libloading::Library;
+    /// let lib = Library::new("/path/to/awesome.module").unwrap();
+    /// ```
+    ///
+    /// Loading and using a function looks like this:
+    ///
+    /// ```no_run
+    /// # use ::libloading::{Library, Symbol};
+    /// # let lib = Library::new("/path/to/awesome.module").unwrap();
+    /// unsafe {
+    ///     let awesome_function: Symbol<unsafe extern fn(f64) -> f64> =
+    ///         lib.get(b"awesome_function\0").unwrap();
+    ///     awesome_function(0.42);
+    /// }
+    /// ```
+    ///
+    /// A static variable may also be loaded and inspected:
+    ///
+    /// ```no_run
+    /// # use ::libloading::{Library, Symbol};
+    /// # let lib = Library::new("/path/to/awesome.module").unwrap();
+    /// unsafe {
+    ///     let awesome_variable: Symbol<*mut f64> = lib.get(b"awesome_variable\0").unwrap();
+    ///     **awesome_variable = 42.0;
+    /// };
+    /// ```
+    pub unsafe fn get<'lib, T>(&'lib self, symbol: &[u8]) -> Result<Symbol<'lib, T>> {
+        self.0.get(symbol).map(|from| Symbol::from_raw(from, self))
+    }
+}
+
+impl fmt::Debug for Library {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        self.0.fmt(f)
+    }
+}
+
+impl From<imp::Library> for Library {
+    fn from(lib: imp::Library) -> Library {
+        Library(lib)
+    }
+}
+
+impl From<Library> for imp::Library {
+    fn from(lib: Library) -> imp::Library {
+        lib.0
+    }
+}
+
+unsafe impl Send for Library {}
+unsafe impl Sync for Library {}
+
+/// Symbol from a library.
+///
+/// This type is a safeguard against using dynamically loaded symbols after a `Library` is
+/// unloaded. Primary method to create an instance of a `Symbol` is via `Library::get`.
+///
+/// Due to implementation of the `Deref` trait, an instance of `Symbol` may be used as if it was a
+/// function or variable directly, without taking care to “extract” function or variable manually
+/// most of the time.
+///
+/// See [`Library::get`] for details.
+///
+/// [`Library::get`]: ./struct.Library.html#method.get
+pub struct Symbol<'lib, T: 'lib> {
+    inner: imp::Symbol<T>,
+    pd: marker::PhantomData<&'lib T>
+}
+
+impl<'lib, T> Symbol<'lib, T> {
+    /// Extract the wrapped `os::platform::Symbol`.
+    ///
+    /// ## Unsafety
+    /// Using this function relinquishes all the lifetime guarantees. It is up to programmer to
+    /// ensure the resulting `Symbol` is not used past the lifetime of the `Library` this symbol
+    /// was loaded from.
+    ///
+    /// ## Examples
+    ///
+    /// ```no_run
+    /// # use ::libloading::{Library, Symbol};
+    /// let lib = Library::new("/path/to/awesome.module").unwrap();
+    /// unsafe {
+    ///     let symbol: Symbol<*mut u32> = lib.get(b"symbol\0").unwrap();
+    ///     let symbol = symbol.into_raw();
+    /// }
+    /// ```
+    pub unsafe fn into_raw(self) -> imp::Symbol<T> {
+        self.inner
+    }
+
+    /// Wrap the `os::platform::Symbol` into this safe wrapper.
+    ///
+    /// Note that, in order to create association between the symbol and the library this symbol
+    /// came from, this function requires reference to the library provided.
+    ///
+    /// ## Unsafety
+    ///
+    /// It is invalid to provide a reference to any other value other than the library the `sym`
+    /// was loaded from. Doing so invalidates any lifetime guarantees.
+    ///
+    /// ## Examples
+    ///
+    /// ```no_run
+    /// # use ::libloading::{Library, Symbol};
+    /// let lib = Library::new("/path/to/awesome.module").unwrap();
+    /// unsafe {
+    ///     let symbol: Symbol<*mut u32> = lib.get(b"symbol\0").unwrap();
+    ///     let symbol = symbol.into_raw();
+    ///     let symbol = Symbol::from_raw(symbol, &lib);
+    /// }
+    /// ```
+    pub unsafe fn from_raw<L>(sym: imp::Symbol<T>, _: &'lib L) -> Symbol<'lib, T> {
+        Symbol {
+            inner: sym,
+            pd: marker::PhantomData
+        }
+    }
+}
+
+impl<'lib, T> Symbol<'lib, Option<T>> {
+    /// Lift Option out of the symbol.
+    ///
+    /// ## Examples
+    ///
+    /// ```no_run
+    /// # use ::libloading::{Library, Symbol};
+    /// let lib = Library::new("/path/to/awesome.module").unwrap();
+    /// unsafe {
+    ///     let symbol: Symbol<Option<*mut u32>> = lib.get(b"symbol\0").unwrap();
+    ///     let symbol: Symbol<*mut u32> = symbol.lift_option().expect("static is not null");
+    /// }
+    /// ```
+    pub fn lift_option(self) -> Option<Symbol<'lib, T>> {
+        self.inner.lift_option().map(|is| Symbol {
+            inner: is,
+            pd: marker::PhantomData,
+        })
+    }
+}
+
+impl<'lib, T> Clone for Symbol<'lib, T> {
+    fn clone(&self) -> Symbol<'lib, T> {
+        Symbol {
+            inner: self.inner.clone(),
+            pd: marker::PhantomData
+        }
+    }
+}
+
+// FIXME: implement FnOnce for callable stuff instead.
+impl<'lib, T> ops::Deref for Symbol<'lib, T> {
+    type Target = T;
+    fn deref(&self) -> &T {
+        ops::Deref::deref(&self.inner)
+    }
+}
+
+impl<'lib, T> fmt::Debug for Symbol<'lib, T> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        self.inner.fmt(f)
+    }
+}
+
+unsafe impl<'lib, T: Send> Send for Symbol<'lib, T> {}
+unsafe impl<'lib, T: Sync> Sync for Symbol<'lib, T> {}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/libloading-0.4.3/src/os/mod.rs
@@ -0,0 +1,45 @@
+//! Unsafe, platform specific bindings to dynamic library loading facilities.
+//!
+//! These modules expose more extensive, powerful, less principled bindings to the dynamic
+//! library loading facilities. Use of these bindings come at the cost of less (in most cases,
+//! none at all) safety guarantees, which are provided by the top-level bindings.
+//!
+//! # Examples
+//!
+//! Using these modules will likely involve conditional compilation:
+//!
+//! ```ignore
+//! # extern crate libloading;
+//! #[cfg(unix)]
+//! use libloading::os::unix::*;
+//! #[cfg(windows)]
+//! use libloading::os::windows::*;
+//! ```
+
+macro_rules! unix {
+    ($item: item) => {
+        /// UNIX implementation of dynamic library loading.
+        ///
+        /// This module should be expanded with more UNIX-specific functionality in the future.
+        $item
+    }
+}
+
+macro_rules! windows {
+    ($item: item) => {
+        /// Windows implementation of dynamic library loading.
+        ///
+        /// This module should be expanded with more Windows-specific functionality in the future.
+        $item
+    }
+}
+
+#[cfg(unix)]
+unix!(pub mod unix;);
+#[cfg(unix)]
+windows!(pub mod windows {});
+
+#[cfg(windows)]
+windows!(pub mod windows;);
+#[cfg(windows)]
+unix!(pub mod unix {});
new file mode 100644
--- /dev/null
+++ b/third_party/rust/libloading-0.4.3/src/os/unix/mod.rs
@@ -0,0 +1,285 @@
+use util::{ensure_compatible_types, cstr_cow_from_bytes};
+
+use std::ffi::{CStr, OsStr};
+use std::{fmt, io, marker, mem, ptr};
+use std::os::raw;
+use std::os::unix::ffi::OsStrExt;
+use std::sync::Mutex;
+
+lazy_static! {
+    static ref DLERROR_MUTEX: Mutex<()> = Mutex::new(());
+}
+
+// libdl is crazy.
+//
+// First of all, whole error handling scheme in libdl is done via setting and querying some global
+// state, therefore it is not safe to use libdl in MT-capable environment at all. Only in POSIX
+// 2008+TC1 a thread-local state was allowed, which for our purposes is way too late.
+fn with_dlerror<T, F>(closure: F) -> Result<T, Option<io::Error>>
+where F: FnOnce() -> Option<T> {
+    // We will guard all uses of libdl library with our own mutex. This makes libdl
+    // safe to use in MT programs provided the only way a program uses libdl is via this library.
+    let _lock = DLERROR_MUTEX.lock();
+    // While we could could call libdl here to clear the previous error value, only the dlsym
+    // depends on it being cleared beforehand and only in some cases too. We will instead clear the
+    // error inside the dlsym binding instead.
+    //
+    // In all the other cases, clearing the error here will only be hiding misuse of these bindings
+    // or the libdl.
+    closure().ok_or_else(|| unsafe {
+        // This code will only get executed if the `closure` returns `None`.
+        let error = dlerror();
+        if error.is_null() {
+            // In non-dlsym case this may happen when there’re bugs in our bindings or there’s
+            // non-libloading user of libdl; possibly in another thread.
+            None
+        } else {
+            // You can’t even rely on error string being static here; call to subsequent dlerror
+            // may invalidate or overwrite the error message. Why couldn’t they simply give up the
+            // ownership over the message?
+            // TODO: should do locale-aware conversion here. OTOH Rust doesn’t seem to work well in
+            // any system that uses non-utf8 locale, so I doubt there’s a problem here.
+            let message = CStr::from_ptr(error).to_string_lossy().into_owned();
+            Some(io::Error::new(io::ErrorKind::Other, message))
+            // Since we do a copy of the error string above, maybe we should call dlerror again to
+            // let libdl know it may free its copy of the string now?
+        }
+    })
+}
+
+/// A platform-specific equivalent of the cross-platform `Library`.
+pub struct Library {
+    handle: *mut raw::c_void
+}
+
+unsafe impl Send for Library {}
+
+// That being said... this section in the volume 2 of POSIX.1-2008 states:
+//
+// > All functions defined by this volume of POSIX.1-2008 shall be thread-safe, except that the
+// > following functions need not be thread-safe.
+//
+// With notable absence of any dl* function other than dlerror in the list. By “this volume”
+// I suppose they refer precisely to the “volume 2”. dl* family of functions are specified
+// by this same volume, so the conclusion is indeed that dl* functions are required by POSIX
+// to be thread-safe. Great!
+//
+// See for more details:
+//
+//  * https://github.com/nagisa/rust_libloading/pull/17
+//  * http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_09_01
+unsafe impl Sync for Library {}
+
+impl Library {
+    /// Find and load a shared library (module).
+    ///
+    /// Locations where library is searched for is platform specific and can’t be adjusted
+    /// portably.
+    ///
+    /// Corresponds to `dlopen(filename, RTLD_NOW)`.
+    #[inline]
+    pub fn new<P: AsRef<OsStr>>(filename: P) -> ::Result<Library> {
+        Library::open(Some(filename), RTLD_NOW)
+    }
+
+    /// Load the dynamic libraries linked into main program.
+    ///
+    /// This allows retrieving symbols from any **dynamic** library linked into the program,
+    /// without specifying the exact library.
+    ///
+    /// Corresponds to `dlopen(NULL, RTLD_NOW)`.
+    #[inline]
+    pub fn this() -> Library {
+        Library::open(None::<&OsStr>, RTLD_NOW).unwrap()
+    }
+
+    /// Find and load a shared library (module).
+    ///
+    /// Locations where library is searched for is platform specific and can’t be adjusted
+    /// portably.
+    ///
+    /// If the `filename` is None, null pointer is passed to `dlopen`.
+    ///
+    /// Corresponds to `dlopen(filename, flags)`.
+    pub fn open<P>(filename: Option<P>, flags: raw::c_int) -> ::Result<Library>
+    where P: AsRef<OsStr> {
+        let filename = match filename {
+            None => None,
+            Some(ref f) => Some(try!(cstr_cow_from_bytes(f.as_ref().as_bytes()))),
+        };
+        with_dlerror(move || {
+            let result = unsafe {
+                let r = dlopen(match filename {
+                    None => ptr::null(),
+                    Some(ref f) => f.as_ptr()
+                }, flags);
+                // ensure filename lives until dlopen completes
+                drop(filename);
+                r
+            };
+            if result.is_null() {
+                None
+            } else {
+                Some(Library {
+                    handle: result
+                })
+            }
+        }).map_err(|e| e.unwrap_or_else(||
+            panic!("dlopen failed but dlerror did not report anything")
+        ))
+    }
+
+    /// Get a pointer to function or static variable by symbol name.
+    ///
+    /// The `symbol` may not contain any null bytes, with an exception of last byte. A null
+    /// terminated `symbol` may avoid a string allocation in some cases.
+    ///
+    /// Symbol is interpreted as-is; no mangling is done. This means that symbols like `x::y` are
+    /// most likely invalid.
+    ///
+    /// ## Unsafety
+    ///
+    /// Pointer to a value of arbitrary type is returned. Using a value with wrong type is
+    /// undefined.
+    ///
+    /// ## Platform-specific behaviour
+    ///
+    /// OS X uses some sort of lazy initialization scheme, which makes loading TLS variables
+    /// impossible. Using a TLS variable loaded this way on OS X is undefined behaviour.
+    pub unsafe fn get<T>(&self, symbol: &[u8]) -> ::Result<Symbol<T>> {
+        ensure_compatible_types::<T, *mut raw::c_void>();
+        let symbol = try!(cstr_cow_from_bytes(symbol));
+        // `dlsym` may return nullptr in two cases: when a symbol genuinely points to a null
+        // pointer or the symbol cannot be found. In order to detect this case a double dlerror
+        // pattern must be used, which is, sadly, a little bit racy.
+        //
+        // We try to leave as little space as possible for this to occur, but we can’t exactly
+        // fully prevent it.
+        match with_dlerror(|| {
+            dlerror();
+            let symbol = dlsym(self.handle, symbol.as_ptr());
+            if symbol.is_null() {
+                None
+            } else {
+                Some(Symbol {
+                    pointer: symbol,
+                    pd: marker::PhantomData
+                })
+            }
+        }) {
+            Err(None) => Ok(Symbol {
+                pointer: ptr::null_mut(),
+                pd: marker::PhantomData
+            }),
+            Err(Some(e)) => Err(e),
+            Ok(x) => Ok(x)
+        }
+    }
+}
+
+impl Drop for Library {
+    fn drop(&mut self) {
+        with_dlerror(|| if unsafe { dlclose(self.handle) } == 0 {
+            Some(())
+        } else {
+            None
+        }).unwrap();
+    }
+}
+
+impl fmt::Debug for Library {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.write_str(&format!("Library@{:p}", self.handle))
+    }
+}
+
+/// Symbol from a library.
+///
+/// A major difference compared to the cross-platform `Symbol` is that this does not ensure the
+/// `Symbol` does not outlive `Library` it comes from.
+pub struct Symbol<T> {
+    pointer: *mut raw::c_void,
+    pd: marker::PhantomData<T>
+}
+
+impl<T> Symbol<Option<T>> {
+    /// Lift Option out of the symbol.
+    pub fn lift_option(self) -> Option<Symbol<T>> {
+        if self.pointer.is_null() {
+            None
+        } else {
+            Some(Symbol {
+                pointer: self.pointer,
+                pd: marker::PhantomData,
+            })
+        }
+    }
+}
+
+unsafe impl<T: Send> Send for Symbol<T> {}
+unsafe impl<T: Sync> Sync for Symbol<T> {}
+
+impl<T> Clone for Symbol<T> {
+    fn clone(&self) -> Symbol<T> {
+        Symbol { ..*self }
+    }
+}
+
+impl<T> ::std::ops::Deref for Symbol<T> {
+    type Target = T;
+    fn deref(&self) -> &T {
+        unsafe {
+            // Additional reference level for a dereference on `deref` return value.
+            mem::transmute(&self.pointer)
+        }
+    }
+}
+
+impl<T> fmt::Debug for Symbol<T> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        unsafe {
+            let mut info: DlInfo = mem::uninitialized();
+            if dladdr(self.pointer, &mut info) != 0 {
+                if info.dli_sname.is_null() {
+                    f.write_str(&format!("Symbol@{:p} from {:?}",
+                                         self.pointer,
+                                         CStr::from_ptr(info.dli_fname)))
+                } else {
+                    f.write_str(&format!("Symbol {:?}@{:p} from {:?}",
+                                         CStr::from_ptr(info.dli_sname), self.pointer,
+                                         CStr::from_ptr(info.dli_fname)))
+                }
+            } else {
+                f.write_str(&format!("Symbol@{:p}", self.pointer))
+            }
+        }
+    }
+}
+
+// Platform specific things
+
+extern {
+    fn dlopen(filename: *const raw::c_char, flags: raw::c_int) -> *mut raw::c_void;
+    fn dlclose(handle: *mut raw::c_void) -> raw::c_int;
+    fn dlsym(handle: *mut raw::c_void, symbol: *const raw::c_char) -> *mut raw::c_void;
+    fn dlerror() -> *mut raw::c_char;
+    fn dladdr(addr: *mut raw::c_void, info: *mut DlInfo) -> raw::c_int;
+}
+
+#[cfg(not(target_os="android"))]
+const RTLD_NOW: raw::c_int = 2;
+#[cfg(target_os="android")]
+const RTLD_NOW: raw::c_int = 0;
+
+#[repr(C)]
+struct DlInfo {
+  dli_fname: *const raw::c_char,
+  dli_fbase: *mut raw::c_void,
+  dli_sname: *const raw::c_char,
+  dli_saddr: *mut raw::c_void
+}
+
+#[test]
+fn this() {
+    Library::this();
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/libloading-0.4.3/src/os/windows/mod.rs
@@ -0,0 +1,284 @@
+extern crate winapi;
+extern crate kernel32;
+
+use util::{ensure_compatible_types, cstr_cow_from_bytes};
+
+use std::ffi::{OsStr, OsString};
+use std::{fmt, io, marker, mem, ptr};
+use std::os::windows::ffi::{OsStrExt, OsStringExt};
+use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering};
+
+
+/// A platform-specific equivalent of the cross-platform `Library`.
+pub struct Library(winapi::HMODULE);
+
+unsafe impl Send for Library {}
+// Now, this is sort-of-tricky. MSDN documentation does not really make any claims as to safety of
+// the Win32 APIs. Sadly, whomever I asked, even current and former Microsoft employees, couldn’t
+// say for sure, whether the Win32 APIs used to implement `Library` are thread-safe or not.
+//
+// My investigation ended up with a question about thread-safety properties of the API involved
+// being sent to an internal (to MS) general question mailing-list. The conclusion of the mail is
+// as such:
+//
+// * Nobody inside MS (at least out of all the people who have seen the question) knows for
+//   sure either;
+// * However, the general consensus between MS developers is that one can rely on the API being
+//   thread-safe. In case it is not thread-safe it should be considered a bug on the Windows
+//   part. (NB: bugs filled at https://connect.microsoft.com/ against Windows Server)
+unsafe impl Sync for Library {}
+
+impl Library {
+    /// Find and load a shared library (module).
+    ///
+    /// Corresponds to `LoadLibraryW(filename)`.
+    #[inline]
+    pub fn new<P: AsRef<OsStr>>(filename: P) -> ::Result<Library> {
+        let wide_filename: Vec<u16> = filename.as_ref().encode_wide().chain(Some(0)).collect();
+        let _guard = ErrorModeGuard::new();
+
+        let ret = with_get_last_error(|| {
+            // Make sure no winapi calls as a result of drop happen inside this closure, because
+            // otherwise that might change the return value of the GetLastError.
+            let handle = unsafe { kernel32::LoadLibraryW(wide_filename.as_ptr()) };
+            if handle.is_null()  {
+                None
+            } else {
+                Some(Library(handle))
+            }
+        }).map_err(|e| e.unwrap_or_else(||
+            panic!("LoadLibraryW failed but GetLastError did not report the error")
+        ));
+
+        drop(wide_filename); // Drop wide_filename here to ensure it doesn’t get moved and dropped
+                             // inside the closure by mistake. See comment inside the closure.
+        ret
+    }
+
+    /// Get a pointer to function or static variable by symbol name.
+    ///
+    /// The `symbol` may not contain any null bytes, with an exception of last byte. A null
+    /// terminated `symbol` may avoid a string allocation in some cases.
+    ///
+    /// Symbol is interpreted as-is; no mangling is done. This means that symbols like `x::y` are
+    /// most likely invalid.
+    ///
+    /// ## Unsafety
+    ///
+    /// Pointer to a value of arbitrary type is returned. Using a value with wrong type is
+    /// undefined.
+    pub unsafe fn get<T>(&self, symbol: &[u8]) -> ::Result<Symbol<T>> {
+        ensure_compatible_types::<T, winapi::FARPROC>();
+        let symbol = try!(cstr_cow_from_bytes(symbol));
+        with_get_last_error(|| {
+            let symbol = kernel32::GetProcAddress(self.0, symbol.as_ptr());
+            if symbol.is_null() {
+                None
+            } else {
+                Some(Symbol {
+                    pointer: symbol,
+                    pd: marker::PhantomData
+                })
+            }
+        }).map_err(|e| e.unwrap_or_else(||
+            panic!("GetProcAddress failed but GetLastError did not report the error")
+        ))
+    }
+
+    /// Get a pointer to function or static variable by ordinal number.
+    ///
+    /// ## Unsafety
+    ///
+    /// Pointer to a value of arbitrary type is returned. Using a value with wrong type is
+    /// undefined.
+    pub unsafe fn get_ordinal<T>(&self, ordinal: winapi::WORD) -> ::Result<Symbol<T>> {
+        ensure_compatible_types::<T, winapi::FARPROC>();
+        with_get_last_error(|| {
+            let ordinal = ordinal as usize as *mut _;
+            let symbol = kernel32::GetProcAddress(self.0, ordinal);
+            if symbol.is_null() {
+                None
+            } else {
+                Some(Symbol {
+                    pointer: symbol,
+                    pd: marker::PhantomData
+                })
+            }
+        }).map_err(|e| e.unwrap_or_else(||
+            panic!("GetProcAddress failed but GetLastError did not report the error")
+        ))
+    }
+}
+
+impl Drop for Library {
+    fn drop(&mut self) {
+        with_get_last_error(|| {
+            if unsafe { kernel32::FreeLibrary(self.0) == 0 } {
+                None
+            } else {
+                Some(())
+            }
+        }).unwrap()
+    }
+}
+
+impl fmt::Debug for Library {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        unsafe {
+            let mut buf: [winapi::WCHAR; 1024] = mem::uninitialized();
+            let len = kernel32::GetModuleFileNameW(self.0,
+                                                   (&mut buf[..]).as_mut_ptr(), 1024) as usize;
+            if len == 0 {
+                f.write_str(&format!("Library@{:p}", self.0))
+            } else {
+                let string: OsString = OsString::from_wide(&buf[..len]);
+                f.write_str(&format!("Library@{:p} from {:?}", self.0, string))
+            }
+        }
+    }
+}
+
+/// Symbol from a library.
+///
+/// A major difference compared to the cross-platform `Symbol` is that this does not ensure the
+/// `Symbol` does not outlive `Library` it comes from.
+pub struct Symbol<T> {
+    pointer: winapi::FARPROC,
+    pd: marker::PhantomData<T>
+}
+
+impl<T> Symbol<Option<T>> {
+    /// Lift Option out of the symbol.
+    pub fn lift_option(self) -> Option<Symbol<T>> {
+        if self.pointer.is_null() {
+            None
+        } else {
+            Some(Symbol {
+                pointer: self.pointer,
+                pd: marker::PhantomData,
+            })
+        }
+    }
+}
+
+unsafe impl<T: Send> Send for Symbol<T> {}
+unsafe impl<T: Sync> Sync for Symbol<T> {}
+
+impl<T> Clone for Symbol<T> {
+    fn clone(&self) -> Symbol<T> {
+        Symbol { ..*self }
+    }
+}
+
+impl<T> ::std::ops::Deref for Symbol<T> {
+    type Target = T;
+    fn deref(&self) -> &T {
+        unsafe {
+            // Additional reference level for a dereference on `deref` return value.
+            mem::transmute(&self.pointer)
+        }
+    }
+}
+
+impl<T> fmt::Debug for Symbol<T> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.write_str(&format!("Symbol@{:p}", self.pointer))
+    }
+}
+
+
+static USE_ERRORMODE: AtomicBool = ATOMIC_BOOL_INIT;
+struct ErrorModeGuard(winapi::DWORD);
+
+impl ErrorModeGuard {
+    fn new() -> Option<ErrorModeGuard> {
+        const SEM_FAILCE: winapi::DWORD = 1;
+        unsafe {
+            if !USE_ERRORMODE.load(Ordering::Acquire) {
+                let mut previous_mode = 0;
+                let success = kernel32::SetThreadErrorMode(SEM_FAILCE, &mut previous_mode) != 0;
+                if !success && kernel32::GetLastError() == winapi::ERROR_CALL_NOT_IMPLEMENTED {
+                    USE_ERRORMODE.store(true, Ordering::Release);
+                } else if !success {
+                    // SetThreadErrorMode failed with some other error? How in the world is it
+                    // possible for what is essentially a simple variable swap to fail?
+                    // For now we just ignore the error -- the worst that can happen here is
+                    // the previous mode staying on and user seeing a dialog error on older Windows
+                    // machines.
+                    return None;
+                } else if previous_mode == SEM_FAILCE {
+                    return None;
+                } else {
+                    return Some(ErrorModeGuard(previous_mode));
+                }
+            }
+            match kernel32::SetErrorMode(SEM_FAILCE) {
+                SEM_FAILCE => {
+                    // This is important to reduce racy-ness when this library is used on multiple
+                    // threads. In particular this helps with following race condition:
+                    //
+                    // T1: SetErrorMode(SEM_FAILCE)
+                    // T2: SetErrorMode(SEM_FAILCE)
+                    // T1: SetErrorMode(old_mode) # not SEM_FAILCE
+                    // T2: SetErrorMode(SEM_FAILCE) # restores to SEM_FAILCE on drop
+                    //
+                    // This is still somewhat racy in a sense that T1 might resture the error
+                    // mode before T2 finishes loading the library, but that is less of a
+                    // concern – it will only end up in end user seeing a dialog.
+                    //
+                    // Also, SetErrorMode itself is probably not an atomic operation.
+                    None
+                }
+                a => Some(ErrorModeGuard(a))
+            }
+        }
+    }
+}
+
+impl Drop for ErrorModeGuard {
+    fn drop(&mut self) {
+        unsafe {
+            if !USE_ERRORMODE.load(Ordering::Relaxed) {
+                kernel32::SetThreadErrorMode(self.0, ptr::null_mut());
+            } else {
+                kernel32::SetErrorMode(self.0);
+            }
+        }
+    }
+}
+
+fn with_get_last_error<T, F>(closure: F) -> Result<T, Option<io::Error>>
+where F: FnOnce() -> Option<T> {
+    closure().ok_or_else(|| {
+        let error = unsafe { kernel32::GetLastError() };
+        if error == 0 {
+            None
+        } else {
+            Some(io::Error::from_raw_os_error(error as i32))
+        }
+    })
+}
+
+#[test]
+fn works_getlasterror() {
+    let lib = Library::new("kernel32.dll").unwrap();
+    let gle: Symbol<unsafe extern "system" fn() -> winapi::DWORD> = unsafe {
+        lib.get(b"GetLastError").unwrap()
+    };
+    unsafe {
+        kernel32::SetLastError(42);
+        assert_eq!(kernel32::GetLastError(), gle())
+    }
+}
+
+#[test]
+fn works_getlasterror0() {
+    let lib = Library::new("kernel32.dll").unwrap();
+    let gle: Symbol<unsafe extern "system" fn() -> winapi::DWORD> = unsafe {
+        lib.get(b"GetLastError\0").unwrap()
+    };
+    unsafe {
+        kernel32::SetLastError(42);
+        assert_eq!(kernel32::GetLastError(), gle())
+    }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/libloading-0.4.3/src/test_helpers.rs
@@ -0,0 +1,49 @@
+//! This is a separate file containing helpers for tests of this library. It is built into a
+//! dynamic library by the build.rs script.
+#![crate_type="dylib"] // FIXME: should become a cdylib in due time
+#![cfg_attr(test_nightly, feature(thread_local))]
+
+#[no_mangle]
+pub static mut TEST_STATIC_U32: u32 = 0;
+
+#[no_mangle]
+pub static mut TEST_STATIC_PTR: *mut () = 0 as *mut _;
+
+#[cfg(test_nightly)]
+#[thread_local]
+#[no_mangle]
+pub static mut TEST_THREAD_LOCAL: u32 = 0;
+
+#[no_mangle]
+pub extern "C" fn test_identity_u32(x: u32) -> u32 {
+    x
+}
+
+#[repr(C)]
+pub struct S {
+    a: u64,
+    b: u32,
+    c: u16,
+    d: u8
+}
+
+#[no_mangle]
+pub extern "C" fn test_identity_struct(x: S) -> S {
+    x
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn test_get_static_u32() -> u32 {
+    TEST_STATIC_U32
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn test_check_static_ptr() -> bool {
+    TEST_STATIC_PTR == (&mut TEST_STATIC_PTR as *mut *mut _ as *mut _)
+}
+
+#[cfg(test_nightly)]
+#[no_mangle]
+pub unsafe extern "C" fn test_get_thread_local() -> u32 {
+    TEST_THREAD_LOCAL
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/libloading-0.4.3/src/util.rs
@@ -0,0 +1,61 @@
+use std::ffi::{CStr, CString, NulError, FromBytesWithNulError};
+use std::borrow::Cow;
+use std::os::raw;
+
+#[derive(Debug)]
+pub struct NullError;
+
+impl From<NulError> for NullError {
+    fn from(_: NulError) -> NullError {
+        NullError
+    }
+}
+
+impl From<FromBytesWithNulError> for NullError {
+    fn from(_: FromBytesWithNulError) -> NullError {
+        NullError
+    }
+}
+
+impl From<NullError> for ::std::io::Error {
+    fn from(e: NullError) -> ::std::io::Error {
+        ::std::io::Error::new(::std::io::ErrorKind::Other, format!("{}", e))
+    }
+}
+
+impl ::std::error::Error for NullError {
+    fn description(&self) -> &str { "non-final null byte found" }
+}
+
+impl ::std::fmt::Display for NullError {
+    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
+        write!(f, "non-final null byte found")
+    }
+}
+
+/// Checks for last byte and avoids alocatting if its zero.
+///
+/// Non-last null bytes still result in an error.
+pub fn cstr_cow_from_bytes<'a>(slice: &'a [u8]) -> Result<Cow<'a, CStr>, NullError> {
+    static ZERO: raw::c_char = 0;
+    Ok(match slice.last() {
+        // Slice out of 0 elements
+        None => unsafe { Cow::Borrowed(CStr::from_ptr(&ZERO)) },
+        // Slice with trailing 0
+        Some(&0) => Cow::Borrowed(try!(CStr::from_bytes_with_nul(slice))),
+        // Slice with no trailing 0
+        Some(_) => Cow::Owned(try!(CString::new(slice))),
+    })
+}
+
+#[inline]
+pub fn ensure_compatible_types<T, E>() {
+    #[cold]
+    #[inline(never)]
+    fn dopanic() {
+        panic!("value of requested type cannot be dynamically loaded");
+    }
+    if ::std::mem::size_of::<T>() != ::std::mem::size_of::<E>() {
+        dopanic()
+    }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/libloading-0.4.3/tests/functions.rs
@@ -0,0 +1,151 @@
+extern crate libloading;
+use libloading::{Symbol, Library};
+
+const LIBPATH: &'static str = concat!(env!("OUT_DIR"), "/libtest_helpers.dll");
+
+fn make_helpers() {
+    static ONCE: ::std::sync::Once = ::std::sync::ONCE_INIT;
+    ONCE.call_once(|| {
+        let mut outpath = String::from(if let Some(od) = option_env!("OUT_DIR") { od } else { return });
+        let rustc = option_env!("RUSTC").unwrap_or_else(|| { "rustc".into() });
+        outpath.push_str(&"/libtest_helpers.dll"); // extension for windows required, POSIX does not care.
+        let _ = ::std::process::Command::new(rustc)
+            .arg("src/test_helpers.rs")
+            .arg("-o")
+            .arg(outpath)
+            .arg("-O")
+            .output()
+            .expect("could not compile the test helpers!");
+    });
+}
+
+#[test]
+fn test_id_u32() {
+    make_helpers();
+    let lib = Library::new(LIBPATH).unwrap();
+    unsafe {
+        let f: Symbol<unsafe extern fn(u32) -> u32> = lib.get(b"test_identity_u32\0").unwrap();
+        assert_eq!(42, f(42));
+    }
+}
+
+#[repr(C)]
+#[derive(Clone,Copy,PartialEq,Debug)]
+struct S {
+    a: u64,
+    b: u32,
+    c: u16,
+    d: u8
+}
+
+#[test]
+fn test_id_struct() {
+    make_helpers();
+    let lib = Library::new(LIBPATH).unwrap();
+    unsafe {
+        let f: Symbol<unsafe extern fn(S) -> S> = lib.get(b"test_identity_struct\0").unwrap();
+        assert_eq!(S { a: 1, b: 2, c: 3, d: 4 }, f(S { a: 1, b: 2, c: 3, d: 4 }));
+    }
+}
+
+#[test]
+fn test_0_no_0() {
+    make_helpers();
+    let lib = Library::new(LIBPATH).unwrap();
+    unsafe {
+        let f: Symbol<unsafe extern fn(S) -> S> = lib.get(b"test_identity_struct\0").unwrap();
+        let f2: Symbol<unsafe extern fn(S) -> S> = lib.get(b"test_identity_struct").unwrap();
+        assert_eq!(*f, *f2);
+    }
+}
+
+#[test]
+fn wrong_name_fails() {
+    Library::new(concat!(env!("OUT_DIR"), "/libtest_help")).err().unwrap();
+}
+
+#[test]
+fn missing_symbol_fails() {
+    make_helpers();
+    let lib = Library::new(LIBPATH).unwrap();
+    unsafe {
+        lib.get::<*mut ()>(b"test_does_not_exist").err().unwrap();
+        lib.get::<*mut ()>(b"test_does_not_exist\0").err().unwrap();
+    }
+}
+
+#[test]
+fn interior_null_fails() {
+    make_helpers();
+    let lib = Library::new(LIBPATH).unwrap();
+    unsafe {
+        lib.get::<*mut ()>(b"test_does\0_not_exist").err().unwrap();
+        lib.get::<*mut ()>(b"test\0_does_not_exist\0").err().unwrap();
+    }
+}
+
+#[test]
+#[should_panic]
+fn test_incompatible_type() {
+    make_helpers();
+    let lib = Library::new(LIBPATH).unwrap();
+    unsafe {
+        let _ = lib.get::<()>(b"test_identity_u32\0");
+    }
+}
+
+#[test]
+#[should_panic]
+fn test_incompatible_type_named_fn() {
+    make_helpers();
+    unsafe fn get<'a, T>(l: &'a Library, _: T) -> libloading::Result<Symbol<'a, T>> {
+        l.get::<T>(b"test_identity_u32\0")
+    }
+    let lib = Library::new(LIBPATH).unwrap();
+    unsafe {
+        let _ = get(&lib, test_incompatible_type_named_fn);
+    }
+}
+
+#[test]
+fn test_static_u32() {
+    make_helpers();
+    let lib = Library::new(LIBPATH).unwrap();
+    unsafe {
+        let var: Symbol<*mut u32> = lib.get(b"TEST_STATIC_U32\0").unwrap();
+        **var = 42;
+        let help: Symbol<unsafe extern fn() -> u32> = lib.get(b"test_get_static_u32\0").unwrap();
+        assert_eq!(42, help());
+    }
+}
+
+#[test]
+fn test_static_ptr() {
+    make_helpers();
+    let lib = Library::new(LIBPATH).unwrap();
+    unsafe {
+        let var: Symbol<*mut *mut ()> = lib.get(b"TEST_STATIC_PTR\0").unwrap();
+        **var = *var as *mut _;
+        let works: Symbol<unsafe extern fn() -> bool> =
+            lib.get(b"test_check_static_ptr\0").unwrap();
+        assert!(works());
+    }
+}
+
+#[cfg(any(windows, target_os="linux"))]
+#[cfg(test_nightly)]
+#[test]
+fn test_tls_static() {
+    make_helpers();
+    let lib = Library::new(LIBPATH).unwrap();
+    unsafe {
+        let var: Symbol<*mut u32> = lib.get(b"TEST_THREAD_LOCAL\0").unwrap();
+        **var = 84;
+        let help: Symbol<unsafe extern fn() -> u32> = lib.get(b"test_get_thread_local\0").unwrap();
+        assert_eq!(84, help());
+    }
+    ::std::thread::spawn(move || unsafe {
+        let help: Symbol<unsafe extern fn() -> u32> = lib.get(b"test_get_thread_local\0").unwrap();
+        assert_eq!(0, help());
+    }).join().unwrap();
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/libloading-0.4.3/tests/markers.rs
@@ -0,0 +1,79 @@
+extern crate libloading;
+
+#[cfg(test)]
+fn assert_send<T: Send>() {}
+#[cfg(test)]
+fn assert_sync<T: Sync>() {}
+
+#[test]
+fn check_library_send() {
+    assert_send::<libloading::Library>();
+}
+
+#[cfg(unix)]
+#[test]
+fn check_unix_library_send() {
+    assert_send::<libloading::os::unix::Library>();
+}
+
+#[cfg(windows)]
+#[test]
+fn check_windows_library_send() {
+    assert_send::<libloading::os::windows::Library>();
+}
+
+#[test]
+fn check_library_sync() {
+    assert_sync::<libloading::Library>();
+}
+
+#[cfg(unix)]
+#[test]
+fn check_unix_library_sync() {
+    assert_sync::<libloading::os::unix::Library>();
+}
+
+#[cfg(windows)]
+#[test]
+fn check_windows_library_sync() {
+    assert_sync::<libloading::os::windows::Library>();
+}
+
+#[test]
+fn check_symbol_send() {
+    assert_send::<libloading::Symbol<fn() -> ()>>();
+    // assert_not_send::<libloading::Symbol<*const ()>>();
+}
+
+#[cfg(unix)]
+#[test]
+fn check_unix_symbol_send() {
+    assert_send::<libloading::os::unix::Symbol<fn() -> ()>>();
+    // assert_not_send::<libloading::os::unix::Symbol<*const ()>>();
+}
+
+#[cfg(windows)]
+#[test]
+fn check_windows_symbol_send() {
+    assert_send::<libloading::os::windows::Symbol<fn() -> ()>>();
+}
+
+#[test]
+fn check_symbol_sync() {
+    assert_sync::<libloading::Symbol<fn() -> ()>>();
+    // assert_not_sync::<libloading::Symbol<*const ()>>();
+}
+
+#[cfg(unix)]
+#[test]
+fn check_unix_symbol_sync() {
+    assert_sync::<libloading::os::unix::Symbol<fn() -> ()>>();
+    // assert_not_sync::<libloading::os::unix::Symbol<*const ()>>();
+}
+
+#[cfg(windows)]
+#[test]
+fn check_windows_symbol_sync() {
+    assert_sync::<libloading::os::windows::Symbol<fn() -> ()>>();
+    // assert_not_sync::<libloading::os::windows::Symbol<*const ()>>();
+}
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0a6218ade9c051e3ebc34c5ad4a687c44263fb33
GIT binary patch
literal 3072
zc%1W%n!v!!z`(!)#Q*;@FzjG}00#!b0Hl^reit9Z7S6MZI~aY=Du!fa7Aq7K<);@V
z<|-s7=H=y=C?usS6qV*FWacTj_y;TG=BK3U@$z!1K+X8bYJ7KVN^Bnt-?ohG-vXv%
zp>#Z$4$4f<0LjDb4sc~)@L^<O2>dZK947XFfk}~@k&l6a3CLlCh;a!32@qBQa|OU`
zCb%@5W(a@=0$AFC6|6}Bq6I=jjRBhDK}6Vq0+5FRVy_G_>WKt;C8-r9Kw1RmASQ&n
zVE|}lf?iQdVo4$c!wIMWa+n}F(LoQQ3?gL!RmXv$?torVYEFJK)K3mjbzB(goXGdt
zC>RJ3+Wlq+Fx~}X4+B}o2OMG#@eH(+Mgg4xtPJG^;shYhPyk{!O!*+7I3oiBdjR=9
zKpX(Xpt2|)L^I?ire_u>8XM`Q<m51vXXd5kmls0~5`dIj;4(}lHxDeP04bhe<rS=a
z)k}r&L2gNa%d1pXRiz}QgY+3d$}Cv<H44ZBNu_ytl>_aFQ7~{o08*#37!0&SM!`S;
E07?yPMF0Q*
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..bacaa4b969411958776c0aad5a848114b1b7bf51
GIT binary patch
literal 2560
zc%1W%n!v!!z`(!)#Q*;@FzjG}00#!b0Hl^reit9Z7S6MZI~aY=Du!fa7Aq7K<);@V
z<|-s7=H=y=C?usS6qV*FWacTj_y;TG=BK3U@$z!1K+X8bYJ7KVN^Bnt-?ohG-vXv%
zp>#Z$4$4f<0LjDb4sc~)NNHncF#a(!947XGK}ms|iI0JS3F;vr5D)+nU}gg&1C$Mv
zXM^g2(O?fl^)N9cFv2v!C`>+tsi45X;6X%K!2wXc3@Pdf0KJmbiV`5L0&@_O-;u0L
z&?`zwEJ<WwH~|#^t7Ah|=Kw@{5M>Z41E@L<40Q*n=!H=*fWV`d^`|@o!{IYf;M3`%
zBGDP5BH+>Kqr$NRlw}SNv>QhOZ2_zd<ptsdAkI(#Vm3_qAfPxXLBOyFknaP;0YD5Y
zd*VSfLtbKfW^tmKiC#)h4nuinUP^v>G1MRdNI3;Avs7~Pz+wuJ;s{ng!OBy;R0tpB
mmIS!GN>x==N>VyVp8=$df|XaJfIN^?nwM8O(2f`d0|o$Zo^Q4Q
new file mode 100644
--- /dev/null
+++ b/third_party/rust/libloading-0.4.3/tests/windows.rs
@@ -0,0 +1,56 @@
+#![cfg(windows)]
+extern crate libloading;
+use libloading::os::windows::*;
+use std::ffi::CStr;
+
+// The ordinal DLL contains exactly one function (other than DllMain, that is) with ordinal number
+// 1. This function has the sugnature `fn() -> *const c_char` and returns a string "bunny\0" (in
+// reference to WindowsBunny).
+//
+// Both x86_64 and x86 versions of the .dll are functionally the same. Ideally we would compile the
+// dlls with well known ordinals from our own testing helpers library, but rustc does not allow
+// specifying a custom .def file (https://github.com/rust-lang/rust/issues/35089)
+//
+// The DLLs were kindly compiled by WindowsBunny (aka. @retep998).
+
+#[cfg(target_arch="x86")]
+fn load_ordinal_lib() -> Library {
+    Library::new("tests/nagisa32.dll").expect("nagisa32.dll")
+}
+
+#[cfg(target_arch="x86_64")]
+fn load_ordinal_lib() -> Library {
+    Library::new("tests/nagisa64.dll").expect("nagisa64.dll")
+}
+
+#[cfg(any(target_arch="x86", target_arch="x86_64"))]
+#[test]
+fn test_ordinal() {
+    let lib = load_ordinal_lib();
+    unsafe {
+        let windows: Symbol<unsafe fn() -> *const i8> = lib.get_ordinal(1).expect("function");
+        assert_eq!(CStr::from_ptr(windows()).to_bytes(), b"bunny");
+    }
+}
+
+#[cfg(any(target_arch="x86", target_arch="x86_64"))]
+#[test]
+fn test_ordinal_missing_fails() {
+    let lib = load_ordinal_lib();
+    unsafe {
+        let r: Result<Symbol<unsafe fn() -> *const i8>, _> = lib.get_ordinal(2);
+        r.err().unwrap();
+        let r: Result<Symbol<unsafe fn() -> *const i8>, _> = lib.get_ordinal(!0);
+        r.err().unwrap();
+    }
+}
+
+#[test]
+fn test_new_kernel23() {
+    Library::new("kernel23").err().unwrap();
+}
+
+#[test]
+fn test_new_kernel32_no_ext() {
+    Library::new("kernel32").unwrap();
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/num-bigint/.cargo-checksum.json
@@ -0,0 +1,1 @@
+{"files":{"Cargo.toml":"c366b169296b5639dc6a208154c1650928171039335967a32cccbb495f430a46","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","README.md":"4e91d304e421fe6c8307312ef5420459fbf6b466c20ba827453f53e5ad8af2b2","RELEASES.md":"802a9d92097422fa89b12f65407af793578d5789a126875b2c9675091f8949cf","benches/bigint.rs":"e62ad970f1cf33c44a5a6ac6ac035059c4bd8416bbad1ddf3d8cfbef4f80b9a0","benches/factorial.rs":"67e50bca067764c5d9dfd2e2bbb75835087437c509b73d6206bbe5c6f797f469","benches/gcd.rs":"4d4ec3ef7bfc7a04867713f68d91f595030c188af6f5144224471d64b8bc3cab","benches/shootout-pidigits.rs":"a071146410ed87dd5ccc8ec1d6fd84e454146a8b067ec0825f397400c9f707e3","bors.toml":"1c81ede536a37edd30fe4e622ff0531b25372403ac9475a5d6c50f14156565a2","ci/rustup.sh":"d746c6b56162295462759a44803c8db9d78ec5b96f78814de149cddd3726ee85","ci/test_full.sh":"02101eb79026a9edc7dc257d5793fd85880a86e0fa888491caf1d571654ad51d","src/algorithms.rs":"640e974a76b3b8c3da4a5f55aada828b9cf3888ab6ccb4c71e0e04f52d96f029","src/bigint.rs":"a23460bd5dfb5743df0609db2b21152c388bba7b826abcba336648b04e6e5e55","src/biguint.rs":"e10b53f100bc63496f0adbbf13dba5fabbbacea621406f0f837d1605e2ca5f2d","src/lib.rs":"44d89304877858812cbce8e3db43d189a9776910955b6888b8322cb9ad1dfe12","src/macros.rs":"68831bd0165ddfd46d39ed69ef9cbce2ae7116872e59cd2b798562f0b72cbafb","src/monty.rs":"408d3871716537ab8726b5da0deb81dcb8782a73500f0c75039be552a5b50414","src/tests/bigint.rs":"fd1e6170cb217ccbf078574d02ade1c19c1d48c5e675f0bcd3584fc54083f0b7","src/tests/biguint.rs":"797a2409dd2e35b1ac794789300bcad19c9fde7633b115b811f6a2a10ced2a3b","tests/modpow.rs":"81c5e53ff27a9bc1b7ef0fd5375c408cf8621b40f0d36a4cc30b4df9656187d8"},"package":"e63899ad0da84ce718c14936262a41cee2c79c981fc0a0e7c7beb47d5a07e8c1"}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/third_party/rust/num-bigint/Cargo.toml
@@ -0,0 +1,62 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g. crates.io) dependencies
+#
+# If you believe there's an error in this file please file an
+# issue against the rust-lang/cargo repository. If you're
+# editing this file be aware that the upstream Cargo.toml
+# will likely look very different (and much more reasonable)
+
+[package]
+name = "num-bigint"
+version = "0.1.44"
+authors = ["The Rust Project Developers"]
+description = "Big integer implementation for Rust"
+homepage = "https://github.com/rust-num/num-bigint"
+documentation = "https://docs.rs/num-bigint"
+readme = "README.md"
+keywords = ["mathematics", "numerics", "bignum"]
+categories = ["algorithms", "data-structures", "science"]
+license = "MIT/Apache-2.0"
+repository = "https://github.com/rust-num/num-bigint"
+
+[[bench]]
+name = "bigint"
+
+[[bench]]
+name = "factorial"
+
+[[bench]]
+name = "gcd"
+
+[[bench]]
+name = "shootout-pidigits"
+harness = false
+[dependencies.num-integer]
+version = "0.1.36"
+default-features = false
+
+[dependencies.num-traits]
+version = "0.2.0"
+features = ["std"]
+default-features = false
+
+[dependencies.rand]
+version = ">= 0.3.14, < 0.5.0"
+optional = true
+
+[dependencies.rustc-serialize]
+version = "0.3.19"
+optional = true
+
+[dependencies.serde]
+version = ">= 0.7.0, < 0.9.0"
+optional = true
+[dev-dependencies.rand]
+version = ">= 0.3.14, < 0.5.0"
+
+[features]
+default = ["rand", "rustc-serialize"]
new file mode 100644
--- /dev/null
+++ b/third_party/rust/num-bigint/LICENSE-APACHE
@@ -0,0 +1,201 @@
+                              Apache License
+                        Version 2.0, January 2004
+                     http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+   "License" shall mean the terms and conditions for use, reproduction,
+   and distribution as defined by Sections 1 through 9 of this document.
+
+   "Licensor" shall mean the copyright owner or entity authorized by
+   the copyright owner that is granting the License.
+
+   "Legal Entity" shall mean the union of the acting entity and all
+   other entities that control, are controlled by, or are under common
+   control with that entity. For the purposes of this definition,
+   "control" means (i) the power, direct or indirect, to cause the
+   direction or management of such entity, whether by contract or
+   otherwise, or (ii) ownership of fifty percent (50%) or more of the
+   outstanding shares, or (iii) beneficial ownership of such entity.
+
+   "You" (or "Your") shall mean an individual or Legal Entity
+   exercising permissions granted by this License.
+
+   "Source" form shall mean the preferred form for making modifications,
+   including but not limited to software source code, documentation
+   source, and configuration files.
+
+   "Object" form shall mean any form resulting from mechanical
+   transformation or translation of a Source form, including but
+   not limited to compiled object code, generated documentation,
+   and conversions to other media types.
+
+   "Work" shall mean the work of authorship, whether in Source or
+   Object form, made available under the License, as indicated by a
+   copyright notice that is included in or attached to the work
+   (an example is provided in the Appendix below).
+
+   "Derivative Works" shall mean any work, whether in Source or Object
+   form, that is based on (or derived from) the Work and for which the
+   editorial revisions, annotations, elaborations, or other modifications
+   represent, as a whole, an original work of authorship. For the purposes
+   of this License, Derivative Works shall not include works that remain
+   separable from, or merely link (or bind by name) to the interfaces of,
+   the Work and Derivative Works thereof.
+
+   "Contribution" shall mean any work of authorship, including
+   the original version of the Work and any modifications or additions
+   to that Work or Derivative Works thereof, that is intentionally
+   submitted to Licensor for inclusion in the Work by the copyright owner
+   or by an individual or Legal Entity authorized to submit on behalf of
+   the copyright owner. For the purposes of this definition, "submitted"
+   means any form of electronic, verbal, or written communication sent
+   to the Licensor or its representatives, including but not limited to
+   communication on electronic mailing lists, source code control systems,
+   and issue tracking systems that are managed by, or on behalf of, the
+   Licensor for the purpose of discussing and improving the Work, but
+   excluding communication that is conspicuously marked or otherwise
+   designated in writing by the copyright owner as "Not a Contribution."
+
+   "Contributor" shall mean Licensor and any individual or Legal Entity
+   on behalf of whom a Contribution has been received by Licensor and
+   subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   copyright license to reproduce, prepare Derivative Works of,
+   publicly display, publicly perform, sublicense, and distribute the
+   Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   (except as stated in this section) patent license to make, have made,
+   use, offer to sell, sell, import, and otherwise transfer the Work,
+   where such license applies only to those patent claims licensable
+   by such Contributor that are necessarily infringed by their
+   Contribution(s) alone or by combination of their Contribution(s)
+   with the Work to which such Contribution(s) was submitted. If You
+   institute patent litigation against any entity (including a
+   cross-claim or counterclaim in a lawsuit) alleging that the Work
+   or a Contribution incorporated within the Work constitutes direct
+   or contributory patent infringement, then any patent licenses
+   granted to You under this License for that Work shall terminate
+   as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+   Work or Derivative Works thereof in any medium, with or without
+   modifications, and in Source or Object form, provided that You
+   meet the following conditions:
+
+   (a) You must give any other recipients of the Work or
+       Derivative Works a copy of this License; and
+
+   (b) You must cause any modified files to carry prominent notices
+       stating that You changed the files; and
+
+   (c) You must retain, in the Source form of any Derivative Works
+       that You distribute, all copyright, patent, trademark, and
+       attribution notices from the Source form of the Work,
+       excluding those notices that do not pertain to any part of
+       the Derivative Works; and
+
+   (d) If the Work includes a "NOTICE" text file as part of its
+       distribution, then any Derivative Works that You distribute must
+       include a readable copy of the attribution notices contained
+       within such NOTICE file, excluding those notices that do not
+       pertain to any part of the Derivative Works, in at least one
+       of the following places: within a NOTICE text file distributed
+       as part of the Derivative Works; within the Source form or
+       documentation, if provided along with the Derivative Works; or,
+       within a display generated by the Derivative Works, if and
+       wherever such third-party notices normally appear. The contents
+       of the NOTICE file are for informational purposes only and
+       do not modify the License. You may add Your own attribution
+       notices within Derivative Works that You distribute, alongside
+       or as an addendum to the NOTICE text from the Work, provided
+       that such additional attribution notices cannot be construed
+       as modifying the License.
+
+   You may add Your own copyright statement to Your modifications and
+   may provide additional or different license terms and conditions
+   for use, reproduction, or distribution of Your modifications, or
+   for any such Derivative Works as a whole, provided Your use,
+   reproduction, and distribution of the Work otherwise complies with
+   the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+   any Contribution intentionally submitted for inclusion in the Work
+   by You to the Licensor shall be under the terms and conditions of
+   this License, without any additional terms or conditions.
+   Notwithstanding the above, nothing herein shall supersede or modify
+   the terms of any separate license agreement you may have executed
+   with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+   names, trademarks, service marks, or product names of the Licensor,
+   except as required for reasonable and customary use in describing the
+   origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+   agreed to in writing, Licensor provides the Work (and each
+   Contributor provides its Contributions) on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+   implied, including, without limitation, any warranties or conditions
+   of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+   PARTICULAR PURPOSE. You are solely responsible for determining the
+   appropriateness of using or redistributing the Work and assume any
+   risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+   whether in tort (including negligence), contract, or otherwise,
+   unless required by applicable law (such as deliberate and grossly
+   negligent acts) or agreed to in writing, shall any Contributor be
+   liable to You for damages, including any direct, indirect, special,
+   incidental, or consequential damages of any character arising as a
+   result of this License or out of the use or inability to use the
+   Work (including but not limited to damages for loss of goodwill,
+   work stoppage, computer failure or malfunction, or any and all
+   other commercial damages or losses), even if such Contributor
+   has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+   the Work or Derivative Works thereof, You may choose to offer,
+   and charge a fee for, acceptance of support, warranty, indemnity,
+   or other liability obligations and/or rights consistent with this
+   License. However, in accepting such obligations, You may act only
+   on Your own behalf and on Your sole responsibility, not on behalf
+   of any other Contributor, and only if You agree to indemnify,
+   defend, and hold each Contributor harmless for any liability
+   incurred by, or claims asserted against, such Contributor by reason
+   of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+   To apply the Apache License to your work, attach the following
+   boilerplate notice, with the fields enclosed by brackets "[]"
+   replaced with your own identifying information. (Don't include
+   the brackets!)  The text should be enclosed in the appropriate
+   comment syntax for the file format. We also recommend that a
+   file or class name and description of purpose be included on the
+   same "printed page" as the copyright notice for easier
+   identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+	http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
new file mode 100644
--- /dev/null
+++ b/third_party/rust/num-bigint/LICENSE-MIT
@@ -0,0 +1,25 @@
+Copyright (c) 2014 The Rust Project Developers
+
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
new file mode 100644
--- /dev/null
+++ b/third_party/rust/num-bigint/README.md
@@ -0,0 +1,52 @@
+# num-bigint
+
+[![crate](https://img.shields.io/crates/v/num-bigint.svg)](https://crates.io/crates/num-bigint)
+[![documentation](https://docs.rs/num-bigint/badge.svg)](https://docs.rs/num-bigint)
+![minimum rustc 1.8](https://img.shields.io/badge/rustc-1.8+-red.svg)
+[![Travis status](https://travis-ci.org/rust-num/num-bigint.svg?branch=master)](https://travis-ci.org/rust-num/num-bigint)
+
+Big integer types for Rust, `BigInt` and `BigUint`.
+
+## Usage
+
+Add this to your `Cargo.toml`:
+
+```toml
+[dependencies]
+num-bigint = "0.1"
+```
+
+and this to your crate root:
+
+```rust
+extern crate num_bigint;
+```
+
+## Releases
+
+Release notes are available in [RELEASES.md](RELEASES.md).
+
+## Compatibility
+
+The `num-bigint` crate is tested for rustc 1.8 and greater.
+
+## Alternatives
+
+While `num-bigint` strives for good performance in pure Rust code, other
+crates may offer better performance with different trade-offs.  The following
+table offers a brief comparison to a few alternatives.
+
+| Crate            | License        | Min rustc | Implementation |
+| :--------------- | :------------- | :-------- | :------------- |
+| **`num-bigint`** | MIT/Apache-2.0 | 1.8       | pure rust |
+| [`ramp`]         | Apache-2.0     | nightly   | rust and inline assembly |
+| [`rug`]          | LGPL-3.0+      | 1.18      | bundles [GMP] via [`gmp-mpfr-sys`] |
+| [`rust-gmp`]     | MIT            | stable?   | links to [GMP] |
+| [`apint`]        | MIT/Apache-2.0 | nightly   | pure rust (unfinished) |
+
+[GMP]: https://gmplib.org/
+[`gmp-mpfr-sys`]: https://crates.io/crates/gmp-mpfr-sys
+[`rug`]: https://crates.io/crates/rug
+[`rust-gmp`]: https://crates.io/crates/rust-gmp
+[`ramp`]: https://crates.io/crates/ramp
+[`apint`]: https://crates.io/crates/apint
new file mode 100644
--- /dev/null
+++ b/third_party/rust/num-bigint/RELEASES.md
@@ -0,0 +1,41 @@
+# Release 0.1.44
+
+- [Division with single-digit divisors is now much faster.][42]
+- The README now compares [`ramp`, `rug`, `rust-gmp`][20], and [`apint`][21].
+
+**Contributors**: @cuviper, @Robbepop
+
+[20]: https://github.com/rust-num/num-bigint/pull/20
+[21]: https://github.com/rust-num/num-bigint/pull/21
+[42]: https://github.com/rust-num/num-bigint/pull/42
+
+# Release 0.1.43
+
+- [The new `BigInt::modpow`][18] performs signed modular exponentiation, using
+  the existing `BigUint::modpow` and rounding negatives similar to `mod_floor`.
+
+**Contributors**: @cuviper
+
+[18]: https://github.com/rust-num/num-bigint/pull/18
+
+# Release 0.1.42
+
+- [num-bigint now has its own source repository][num-356] at [rust-num/num-bigint][home].
+- [`lcm` now avoids creating a large intermediate product][num-350].
+- [`gcd` now uses Stein's algorithm][15] with faster shifts instead of division.
+- [`rand` support is now extended to 0.4][11] (while still allowing 0.3).
+
+**Contributors**: @cuviper, @Emerentius, @ignatenkobrain, @mhogrefe
+
+[home]: https://github.com/rust-num/num-bigint
+[num-350]: https://github.com/rust-num/num/pull/350
+[num-356]: https://github.com/rust-num/num/pull/356
+[11]: https://github.com/rust-num/num-bigint/pull/11
+[15]: https://github.com/rust-num/num-bigint/pull/15
+
+
+# Prior releases
+
+No prior release notes were kept.  Thanks all the same to the many
+contributors that have made this crate what it is!
+
new file mode 100644
--- /dev/null
+++ b/third_party/rust/num-bigint/benches/bigint.rs
@@ -0,0 +1,294 @@
+#![feature(test)]
+
+extern crate test;
+extern crate num_bigint;
+extern crate num_traits;
+extern crate rand;
+
+use std::mem::replace;
+use test::Bencher;
+use num_bigint::{BigInt, BigUint, RandBigInt};
+use num_traits::{Zero, One, FromPrimitive, Num};
+use rand::{SeedableRng, StdRng};
+
+fn get_rng() -> StdRng {
+    let seed: &[_] = &[1, 2, 3, 4];
+    SeedableRng::from_seed(seed)
+}
+
+fn multiply_bench(b: &mut Bencher, xbits: usize, ybits: usize) {
+    let mut rng = get_rng();
+    let x = rng.gen_bigint(xbits);
+    let y = rng.gen_bigint(ybits);
+
+    b.iter(|| &x * &y);
+}
+
+fn divide_bench(b: &mut Bencher, xbits: usize, ybits: usize) {
+    let mut rng = get_rng();
+    let x = rng.gen_bigint(xbits);
+    let y = rng.gen_bigint(ybits);
+
+    b.iter(|| &x / &y);
+}
+
+fn factorial(n: usize) -> BigUint {
+    let mut f: BigUint = One::one();
+    for i in 1..(n+1) {
+        let bu: BigUint = FromPrimitive::from_usize(i).unwrap();
+        f = f * bu;
+    }
+    f
+}
+
+/// Compute Fibonacci numbers
+fn fib(n: usize) -> BigUint {
+    let mut f0: BigUint = Zero::zero();
+    let mut f1: BigUint = One::one();
+    for _ in 0..n {
+        let f2 = f0 + &f1;
+        f0 = replace(&mut f1, f2);
+    }
+    f0
+}
+
+/// Compute Fibonacci numbers with two ops per iteration
+/// (add and subtract, like issue #200)
+fn fib2(n: usize) -> BigUint {
+    let mut f0: BigUint = Zero::zero();
+    let mut f1: BigUint = One::one();
+    for _ in 0..n {
+        f1 = f1 + &f0;
+        f0 = &f1 - f0;
+    }
+    f0
+}
+
+#[bench]
+fn multiply_0(b: &mut Bencher) {
+    multiply_bench(b, 1 << 8, 1 << 8);
+}
+
+#[bench]
+fn multiply_1(b: &mut Bencher) {
+    multiply_bench(b, 1 << 8, 1 << 16);
+}
+
+#[bench]
+fn multiply_2(b: &mut Bencher) {
+    multiply_bench(b, 1 << 16, 1 << 16);
+}
+
+#[bench]
+fn multiply_3(b: &mut Bencher) {
+    multiply_bench(b, 1 << 16, 1 << 17);
+}
+
+#[bench]
+fn divide_0(b: &mut Bencher) {
+    divide_bench(b, 1 << 8, 1 << 6);
+}
+
+#[bench]
+fn divide_1(b: &mut Bencher) {
+    divide_bench(b, 1 << 12, 1 << 8);
+}
+
+#[bench]
+fn divide_2(b: &mut Bencher) {
+    divide_bench(b, 1 << 16, 1 << 12);
+}
+
+#[bench]
+fn factorial_100(b: &mut Bencher) {
+    b.iter(|| factorial(100));
+}
+
+#[bench]
+fn fib_100(b: &mut Bencher) {
+    b.iter(|| fib(100));
+}
+
+#[bench]
+fn fib_1000(b: &mut Bencher) {
+    b.iter(|| fib(1000));
+}
+
+#[bench]
+fn fib_10000(b: &mut Bencher) {
+    b.iter(|| fib(10000));
+}
+
+#[bench]
+fn fib2_100(b: &mut Bencher) {
+    b.iter(|| fib2(100));
+}
+
+#[bench]
+fn fib2_1000(b: &mut Bencher) {
+    b.iter(|| fib2(1000));
+}
+
+#[bench]
+fn fib2_10000(b: &mut Bencher) {
+    b.iter(|| fib2(10000));
+}
+
+#[bench]
+fn fac_to_string(b: &mut Bencher) {
+    let fac = factorial(100);
+    b.iter(|| fac.to_string());
+}
+
+#[bench]
+fn fib_to_string(b: &mut Bencher) {
+    let fib = fib(100);
+    b.iter(|| fib.to_string());
+}
+
+fn to_str_radix_bench(b: &mut Bencher, radix: u32) {
+    let mut rng = get_rng();
+    let x = rng.gen_bigint(1009);
+    b.iter(|| x.to_str_radix(radix));
+}
+
+#[bench]
+fn to_str_radix_02(b: &mut Bencher) {
+    to_str_radix_bench(b, 2);
+}
+
+#[bench]
+fn to_str_radix_08(b: &mut Bencher) {
+    to_str_radix_bench(b, 8);
+}
+
+#[bench]
+fn to_str_radix_10(b: &mut Bencher) {
+    to_str_radix_bench(b, 10);
+}
+
+#[bench]
+fn to_str_radix_16(b: &mut Bencher) {
+    to_str_radix_bench(b, 16);
+}
+
+#[bench]
+fn to_str_radix_36(b: &mut Bencher) {
+    to_str_radix_bench(b, 36);
+}
+
+fn from_str_radix_bench(b: &mut Bencher, radix: u32) {
+    let mut rng = get_rng();
+    let x = rng.gen_bigint(1009);
+    let s = x.to_str_radix(radix);
+    assert_eq!(x, BigInt::from_str_radix(&s, radix).unwrap());
+    b.iter(|| BigInt::from_str_radix(&s, radix));
+}
+
+#[bench]
+fn from_str_radix_02(b: &mut Bencher) {
+    from_str_radix_bench(b, 2);
+}
+
+#[bench]
+fn from_str_radix_08(b: &mut Bencher) {
+    from_str_radix_bench(b, 8);
+}
+
+#[bench]
+fn from_str_radix_10(b: &mut Bencher) {
+    from_str_radix_bench(b, 10);
+}
+
+#[bench]
+fn from_str_radix_16(b: &mut Bencher) {
+    from_str_radix_bench(b, 16);
+}
+
+#[bench]
+fn from_str_radix_36(b: &mut Bencher) {
+    from_str_radix_bench(b, 36);
+}
+
+#[bench]
+fn shl(b: &mut Bencher) {
+    let n = BigUint::one() << 1000;
+    b.iter(|| {
+        let mut m = n.clone();
+        for i in 0..50 {
+            m = m << i;
+        }
+    })
+}
+
+#[bench]
+fn shr(b: &mut Bencher) {
+    let n = BigUint::one() << 2000;
+    b.iter(|| {
+        let mut m = n.clone();
+        for i in 0..50 {
+            m = m >> i;
+        }
+    })
+}
+
+#[bench]
+fn hash(b: &mut Bencher) {
+    use std::collections::HashSet;
+    let mut rng = get_rng();
+    let v: Vec<BigInt> = (1000..2000).map(|bits| rng.gen_bigint(bits)).collect();
+    b.iter(|| {
+        let h: HashSet<&BigInt> = v.iter().collect();
+        assert_eq!(h.len(), v.len());
+    });
+}
+
+#[bench]
+fn pow_bench(b: &mut Bencher) {
+    b.iter(|| {
+        let upper = 100_usize;
+        for i in 2..upper + 1 {
+            for j in 2..upper + 1 {
+                let i_big = BigUint::from_usize(i).unwrap();
+                num_traits::pow(i_big, j);
+            }
+        }
+    });
+}
+
+
+/// This modulus is the prime from the 2048-bit MODP DH group:
+/// https://tools.ietf.org/html/rfc3526#section-3
+const RFC3526_2048BIT_MODP_GROUP: &'static str = "\
+    FFFFFFFF_FFFFFFFF_C90FDAA2_2168C234_C4C6628B_80DC1CD1\
+    29024E08_8A67CC74_020BBEA6_3B139B22_514A0879_8E3404DD\
+    EF9519B3_CD3A431B_302B0A6D_F25F1437_4FE1356D_6D51C245\
+    E485B576_625E7EC6_F44C42E9_A637ED6B_0BFF5CB6_F406B7ED\
+    EE386BFB_5A899FA5_AE9F2411_7C4B1FE6_49286651_ECE45B3D\
+    C2007CB8_A163BF05_98DA4836_1C55D39A_69163FA8_FD24CF5F\
+    83655D23_DCA3AD96_1C62F356_208552BB_9ED52907_7096966D\
+    670C354E_4ABC9804_F1746C08_CA18217C_32905E46_2E36CE3B\
+    E39E772C_180E8603_9B2783A2_EC07A28F_B5C55DF0_6F4C52C9\
+    DE2BCBF6_95581718_3995497C_EA956AE5_15D22618_98FA0510\
+    15728E5A_8AACAA68_FFFFFFFF_FFFFFFFF";
+
+#[bench]
+fn modpow(b: &mut Bencher) {
+    let mut rng = get_rng();
+    let base = rng.gen_biguint(2048);
+    let e = rng.gen_biguint(2048);
+    let m = BigUint::from_str_radix(RFC3526_2048BIT_MODP_GROUP, 16).unwrap();
+
+    b.iter(|| base.modpow(&e, &m));
+}
+
+#[bench]
+fn modpow_even(b: &mut Bencher) {
+    let mut rng = get_rng();
+    let base = rng.gen_biguint(2048);
+    let e = rng.gen_biguint(2048);
+    // Make the modulus even, so monty (base-2^32) doesn't apply.
+    let m = BigUint::from_str_radix(RFC3526_2048BIT_MODP_GROUP, 16).unwrap() - 1u32;
+
+    b.iter(|| base.modpow(&e, &m));
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/num-bigint/benches/factorial.rs
@@ -0,0 +1,35 @@
+#![feature(test)]
+
+extern crate num_bigint;
+extern crate num_traits;
+extern crate test;
+
+use num_bigint::BigUint;
+use num_traits::One;
+use std::ops::{Div, Mul};
+use test::Bencher;
+
+#[bench]
+fn factorial_mul_biguint(b: &mut Bencher) {
+    b.iter(|| (1u32..1000).map(BigUint::from).fold(BigUint::one(), Mul::mul));
+}
+
+#[bench]
+fn factorial_mul_u32(b: &mut Bencher) {
+    b.iter(|| (1u32..1000).fold(BigUint::one(), Mul::mul));
+}
+
+// The division test is inspired by this blog comparison:
+// <https://tiehuis.github.io/big-integers-in-zig#division-test-single-limb>
+
+#[bench]
+fn factorial_div_biguint(b: &mut Bencher) {
+    let n: BigUint = (1u32..1000).fold(BigUint::one(), Mul::mul);
+    b.iter(|| (1u32..1000).rev().map(BigUint::from).fold(n.clone(), Div::div));
+}
+
+#[bench]
+fn factorial_div_u32(b: &mut Bencher) {
+    let n: BigUint = (1u32..1000).fold(BigUint::one(), Mul::mul);
+    b.iter(|| (1u32..1000).rev().fold(n.clone(), Div::div));
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/num-bigint/benches/gcd.rs
@@ -0,0 +1,84 @@
+#![feature(test)]
+
+extern crate test;
+extern crate num_bigint;
+extern crate num_integer;
+extern crate num_traits;
+extern crate rand;
+
+use test::Bencher;
+use num_bigint::{BigUint, RandBigInt};
+use num_integer::Integer;
+use num_traits::Zero;
+use rand::{SeedableRng, StdRng};
+
+fn get_rng() -> StdRng {
+    let seed: &[_] = &[1, 2, 3, 4];
+    SeedableRng::from_seed(seed)
+}
+
+fn bench(b: &mut Bencher, bits: usize, gcd: fn(&BigUint, &BigUint) -> BigUint) {
+    let mut rng = get_rng();
+    let x = rng.gen_biguint(bits);
+    let y = rng.gen_biguint(bits);
+
+    assert_eq!(euclid(&x, &y), x.gcd(&y));
+
+    b.iter(|| gcd(&x, &y));
+}
+
+
+fn euclid(x: &BigUint, y: &BigUint) -> BigUint {
+    // Use Euclid's algorithm
+    let mut m = x.clone();
+    let mut n = y.clone();
+    while !m.is_zero() {
+        let temp = m;
+        m = n % &temp;
+        n = temp;
+    }
+    return n;
+}
+
+#[bench]
+fn gcd_euclid_0064(b: &mut Bencher) {
+    bench(b, 64, euclid);
+}
+
+#[bench]
+fn gcd_euclid_0256(b: &mut Bencher) {
+    bench(b, 256, euclid);
+}
+
+#[bench]
+fn gcd_euclid_1024(b: &mut Bencher) {
+    bench(b, 1024, euclid);
+}
+
+#[bench]
+fn gcd_euclid_4096(b: &mut Bencher) {
+    bench(b, 4096, euclid);
+}
+
+
+// Integer for BigUint now uses Stein for gcd
+
+#[bench]
+fn gcd_stein_0064(b: &mut Bencher) {
+    bench(b, 64, BigUint::gcd);
+}
+
+#[bench]
+fn gcd_stein_0256(b: &mut Bencher) {
+    bench(b, 256, BigUint::gcd);
+}
+
+#[bench]
+fn gcd_stein_1024(b: &mut Bencher) {
+    bench(b, 1024, BigUint::gcd);
+}
+
+#[bench]
+fn gcd_stein_4096(b: &mut Bencher) {
+    bench(b, 4096, BigUint::gcd);
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/num-bigint/benches/shootout-pidigits.rs
@@ -0,0 +1,134 @@
+// The Computer Language Benchmarks Game
+// http://benchmarksgame.alioth.debian.org/
+//
+// contributed by the Rust Project Developers
+
+// Copyright (c) 2013-2014 The Rust Project Developers
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+// - Redistributions of source code must retain the above copyright
+//   notice, this list of conditions and the following disclaimer.
+//
+// - Redistributions in binary form must reproduce the above copyright
+//   notice, this list of conditions and the following disclaimer in
+//   the documentation and/or other materials provided with the
+//   distribution.
+//
+// - Neither the name of "The Computer Language Benchmarks Game" nor
+//   the name of "The Computer Language Shootout Benchmarks" nor the
+//   names of its contributors may be used to endorse or promote
+//   products derived from this software without specific prior
+//   written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+// OF THE POSSIBILITY OF SUCH DAMAGE.
+
+extern crate num_bigint;
+extern crate num_integer;
+extern crate num_traits;
+
+use std::str::FromStr;
+use std::io;
+
+use num_bigint::BigInt;
+use num_integer::Integer;
+use num_traits::{FromPrimitive, ToPrimitive, One, Zero};
+
+struct Context {
+    numer: BigInt,
+    accum: BigInt,
+    denom: BigInt,
+}
+
+impl Context {
+    fn new() -> Context {
+        Context {
+            numer: One::one(),
+            accum: Zero::zero(),
+            denom: One::one(),
+        }
+    }
+
+    fn from_i32(i: i32) -> BigInt {
+        FromPrimitive::from_i32(i).unwrap()
+    }
+
+    fn extract_digit(&self) -> i32 {
+        if self.numer > self.accum {return -1;}
+        let (q, r) =
+            (&self.numer * Context::from_i32(3) + &self.accum)
+            .div_rem(&self.denom);
+        if r + &self.numer >= self.denom {return -1;}
+        q.to_i32().unwrap()
+    }
+
+    fn next_term(&mut self, k: i32) {
+        let y2 = Context::from_i32(k * 2 + 1);
+        self.accum = (&self.accum + (&self.numer << 1)) * &y2;
+        self.numer = &self.numer * Context::from_i32(k);
+        self.denom = &self.denom * y2;
+    }
+
+    fn eliminate_digit(&mut self, d: i32) {
+        let d = Context::from_i32(d);
+        let ten = Context::from_i32(10);
+        self.accum = (&self.accum - &self.denom * d) * &ten;
+        self.numer = &self.numer * ten;
+    }
+}
+
+fn pidigits(n: isize, out: &mut io::Write) -> io::Result<()> {
+    let mut k = 0;
+    let mut context = Context::new();
+
+    for i in 1..(n+1) {
+        let mut d;
+        loop {
+            k += 1;
+            context.next_term(k);
+            d = context.extract_digit();
+            if d != -1 {break;}
+        }
+
+        try!(write!(out, "{}", d));
+        if i % 10 == 0 { try!(write!(out, "\t:{}\n", i)); }
+
+        context.eliminate_digit(d);
+    }
+
+    let m = n % 10;
+    if m != 0 {
+        for _ in m..10 { try!(write!(out, " ")); }
+        try!(write!(out, "\t:{}\n", n));
+    }
+    Ok(())
+}
+
+const DEFAULT_DIGITS: isize = 512;
+
+fn main() {
+    let args = std::env::args().collect::<Vec<_>>();
+    let n = if args.len() < 2 {
+        DEFAULT_DIGITS
+    } else if args[1] == "--bench" {
+        return pidigits(DEFAULT_DIGITS, &mut std::io::sink()).unwrap()
+    } else {
+        FromStr::from_str(&args[1]).unwrap()
+    };
+    pidigits(n, &mut std::io::stdout()).unwrap();
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/num-bigint/bors.toml
@@ -0,0 +1,3 @@
+status = [
+  "continuous-integration/travis-ci/push",
+]
new file mode 100644
--- /dev/null
+++ b/third_party/rust/num-bigint/ci/rustup.sh
@@ -0,0 +1,19 @@
+#!/bin/sh
+# Use rustup to locally run the same suite of tests as .travis.yml.
+# (You should first install/update 1.8.0, stable, beta, and nightly.)
+
+set -ex
+
+export TRAVIS_RUST_VERSION
+for TRAVIS_RUST_VERSION in 1.8.0 stable beta nightly; do
+    run="rustup run $TRAVIS_RUST_VERSION"
+    if [ "$TRAVIS_RUST_VERSION" = 1.8.0 ]; then
+      # rand 0.3.22 started depending on rand 0.4, which requires rustc 1.15
+      # manually hacking the lockfile due to the limitations of cargo#2773
+      $run cargo generate-lockfile
+      $run sed -i -e 's/"rand 0.[34].[0-9]\+/"rand 0.3.20/' Cargo.lock
+      $run sed -i -e '/^name = "rand"/,/^$/s/version = "0.3.[0-9]\+"/version = "0.3.20"/' Cargo.lock
+    fi
+    $run cargo build --verbose
+    $run $PWD/ci/test_full.sh
+done
new file mode 100644
--- /dev/null
+++ b/third_party/rust/num-bigint/ci/test_full.sh
@@ -0,0 +1,23 @@
+#!/bin/bash
+
+set -ex
+
+echo Testing num-bigint on rustc ${TRAVIS_RUST_VERSION}
+
+# num-bigint should build and test everywhere.
+cargo build --verbose
+cargo test --verbose
+
+# It should build with minimal features too.
+cargo build --no-default-features
+cargo test --no-default-features
+
+# Each isolated feature should also work everywhere.
+for feature in rand rustc-serialize serde; do
+  cargo build --verbose --no-default-features --features="$feature"
+  cargo test --verbose --no-default-features --features="$feature"
+done
+
+# Downgrade serde and build test the 0.7.0 channel as well
+cargo update -p serde --precise 0.7.0
+cargo build --verbose --no-default-features --features "serde"
new file mode 100644
--- /dev/null
+++ b/third_party/rust/num-bigint/src/algorithms.rs
@@ -0,0 +1,665 @@
+use std::borrow::Cow;
+use std::cmp;
+use std::cmp::Ordering::{self, Less, Greater, Equal};
+use std::iter::repeat;
+use std::mem;
+use traits;
+use traits::{Zero, One};
+
+use biguint::BigUint;
+
+use bigint::BigInt;
+use bigint::Sign;
+use bigint::Sign::{Minus, NoSign, Plus};
+
+#[allow(non_snake_case)]
+pub mod big_digit {
+    /// A `BigDigit` is a `BigUint`'s composing element.
+    pub type BigDigit = u32;
+
+    /// A `DoubleBigDigit` is the internal type used to do the computations.  Its
+    /// size is the double of the size of `BigDigit`.
+    pub type DoubleBigDigit = u64;
+
+    pub const ZERO_BIG_DIGIT: BigDigit = 0;
+
+    // `DoubleBigDigit` size dependent
+    pub const BITS: usize = 32;
+
+    pub const BASE: DoubleBigDigit = 1 << BITS;
+    const LO_MASK: DoubleBigDigit = (-1i32 as DoubleBigDigit) >> BITS;
+
+    #[inline]
+    fn get_hi(n: DoubleBigDigit) -> BigDigit {
+        (n >> BITS) as BigDigit
+    }
+    #[inline]
+    fn get_lo(n: DoubleBigDigit) -> BigDigit {
+        (n & LO_MASK) as BigDigit
+    }
+
+    /// Split one `DoubleBigDigit` into two `BigDigit`s.
+    #[inline]
+    pub fn from_doublebigdigit(n: DoubleBigDigit) -> (BigDigit, BigDigit) {
+        (get_hi(n), get_lo(n))
+    }
+
+    /// Join two `BigDigit`s into one `DoubleBigDigit`
+    #[inline]
+    pub fn to_doublebigdigit(hi: BigDigit, lo: BigDigit) -> DoubleBigDigit {
+        (lo as DoubleBigDigit) | ((hi as DoubleBigDigit) << BITS)
+    }
+}
+
+use big_digit::{BigDigit, DoubleBigDigit};
+
+// Generic functions for add/subtract/multiply with carry/borrow:
+
+// Add with carry:
+#[inline]
+fn adc(a: BigDigit, b: BigDigit, carry: &mut BigDigit) -> BigDigit {
+    let (hi, lo) = big_digit::from_doublebigdigit((a as DoubleBigDigit) + (b as DoubleBigDigit) +
+                                                  (*carry as DoubleBigDigit));
+
+    *carry = hi;
+    lo
+}
+
+// Subtract with borrow:
+#[inline]
+fn sbb(a: BigDigit, b: BigDigit, borrow: &mut BigDigit) -> BigDigit {
+    let (hi, lo) = big_digit::from_doublebigdigit(big_digit::BASE + (a as DoubleBigDigit) -
+                                                  (b as DoubleBigDigit) -
+                                                  (*borrow as DoubleBigDigit));
+    // hi * (base) + lo == 1*(base) + ai - bi - borrow
+    // => ai - bi - borrow < 0 <=> hi == 0
+    *borrow = (hi == 0) as BigDigit;
+    lo
+}
+
+#[inline]
+pub fn mac_with_carry(a: BigDigit, b: BigDigit, c: BigDigit, carry: &mut BigDigit) -> BigDigit {
+    let (hi, lo) = big_digit::from_doublebigdigit((a as DoubleBigDigit) +
+                                                  (b as DoubleBigDigit) * (c as DoubleBigDigit) +
+                                                  (*carry as DoubleBigDigit));
+    *carry = hi;
+    lo
+}
+
+#[inline]
+pub fn mul_with_carry(a: BigDigit, b: BigDigit, carry: &mut BigDigit) -> BigDigit {
+    let (hi, lo) = big_digit::from_doublebigdigit((a as DoubleBigDigit) * (b as DoubleBigDigit) +
+                                                  (*carry as DoubleBigDigit));
+
+    *carry = hi;
+    lo
+}
+
+/// Divide a two digit numerator by a one digit divisor, returns quotient and remainder:
+///
+/// Note: the caller must ensure that both the quotient and remainder will fit into a single digit.
+/// This is _not_ true for an arbitrary numerator/denominator.
+///
+/// (This function also matches what the x86 divide instruction does).
+#[inline]
+fn div_wide(hi: BigDigit, lo: BigDigit, divisor: BigDigit) -> (BigDigit, BigDigit) {
+    debug_assert!(hi < divisor);
+
+    let lhs = big_digit::to_doublebigdigit(hi, lo);
+    let rhs = divisor as DoubleBigDigit;
+    ((lhs / rhs) as BigDigit, (lhs % rhs) as BigDigit)
+}
+
+pub fn div_rem_digit(mut a: BigUint, b: BigDigit) -> (BigUint, BigDigit) {
+    let mut rem = 0;
+
+    for d in a.data.iter_mut().rev() {
+        let (q, r) = div_wide(rem, *d, b);
+        *d = q;
+        rem = r;
+    }
+
+    (a.normalized(), rem)
+}
+
+// Only for the Add impl:
+#[inline]
+pub fn __add2(a: &mut [BigDigit], b: &[BigDigit]) -> BigDigit {
+    debug_assert!(a.len() >= b.len());
+
+    let mut carry = 0;
+    let (a_lo, a_hi) = a.split_at_mut(b.len());
+
+    for (a, b) in a_lo.iter_mut().zip(b) {
+        *a = adc(*a, *b, &mut carry);
+    }
+
+    if carry != 0 {
+        for a in a_hi {
+            *a = adc(*a, 0, &mut carry);
+            if carry == 0 { break }
+        }
+    }
+
+    carry
+}
+
+/// /Two argument addition of raw slices:
+/// a += b
+///
+/// The caller _must_ ensure that a is big enough to store the result - typically this means
+/// resizing a to max(a.len(), b.len()) + 1, to fit a possible carry.
+pub fn add2(a: &mut [BigDigit], b: &[BigDigit]) {
+    let carry = __add2(a, b);
+
+    debug_assert!(carry == 0);
+}
+
+pub fn sub2(a: &mut [BigDigit], b: &[BigDigit]) {
+    let mut borrow = 0;
+
+    let len = cmp::min(a.len(), b.len());
+    let (a_lo, a_hi) = a.split_at_mut(len);
+    let (b_lo, b_hi) = b.split_at(len);
+
+    for (a, b) in a_lo.iter_mut().zip(b_lo) {
+        *a = sbb(*a, *b, &mut borrow);
+    }
+
+    if borrow != 0 {
+        for a in a_hi {
+            *a = sbb(*a, 0, &mut borrow);
+            if borrow == 0 { break }
+        }
+    }
+
+    // note: we're _required_ to fail on underflow
+    assert!(borrow == 0 && b_hi.iter().all(|x| *x == 0),
+            "Cannot subtract b from a because b is larger than a.");
+}
+
+pub fn sub2rev(a: &[BigDigit], b: &mut [BigDigit]) {
+    debug_assert!(b.len() >= a.len());
+
+    let mut borrow = 0;
+
+    let len = cmp::min(a.len(), b.len());
+    let (a_lo, a_hi) = a.split_at(len);
+    let (b_lo, b_hi) = b.split_at_mut(len);
+
+    for (a, b) in a_lo.iter().zip(b_lo) {
+        *b = sbb(*a, *b, &mut borrow);
+    }
+
+    assert!(a_hi.is_empty());
+
+    // note: we're _required_ to fail on underflow
+    assert!(borrow == 0 && b_hi.iter().all(|x| *x == 0),
+            "Cannot subtract b from a because b is larger than a.");
+}
+
+pub fn sub_sign(a: &[BigDigit], b: &[BigDigit]) -> (Sign, BigUint) {
+    // Normalize:
+    let a = &a[..a.iter().rposition(|&x| x != 0).map_or(0, |i| i + 1)];
+    let b = &b[..b.iter().rposition(|&x| x != 0).map_or(0, |i| i + 1)];
+
+    match cmp_slice(a, b) {
+        Greater => {
+            let mut a = a.to_vec();
+            sub2(&mut a, b);
+            (Plus, BigUint::new(a))
+        }
+        Less => {
+            let mut b = b.to_vec();
+            sub2(&mut b, a);
+            (Minus, BigUint::new(b))
+        }
+        _ => (NoSign, Zero::zero()),
+    }
+}
+
+/// Three argument multiply accumulate:
+/// acc += b * c
+pub fn mac_digit(acc: &mut [BigDigit], b: &[BigDigit], c: BigDigit) {
+    if c == 0 {
+        return;
+    }
+
+    let mut carry = 0;
+    let (a_lo, a_hi) = acc.split_at_mut(b.len());
+
+    for (a, &b) in a_lo.iter_mut().zip(b) {
+        *a = mac_with_carry(*a, b, c, &mut carry);
+    }
+
+    let mut a = a_hi.iter_mut();
+    while carry != 0 {
+        let a = a.next().expect("carry overflow during multiplication!");
+        *a = adc(*a, 0, &mut carry);
+    }
+}
+
+/// Three argument multiply accumulate:
+/// acc += b * c
+fn mac3(acc: &mut [BigDigit], b: &[BigDigit], c: &[BigDigit]) {
+    let (x, y) = if b.len() < c.len() {
+        (b, c)
+    } else {
+        (c, b)
+    };
+
+    // We use three algorithms for different input sizes.
+    //
+    // - For small inputs, long multiplication is fastest.
+    // - Next we use Karatsuba multiplication (Toom-2), which we have optimized
+    //   to avoid unnecessary allocations for intermediate values.
+    // - For the largest inputs we use Toom-3, which better optimizes the
+    //   number of operations, but uses more temporary allocations.
+    //
+    // The thresholds are somewhat arbitrary, chosen by evaluating the results
+    // of `cargo bench --bench bigint multiply`.
+
+    if x.len() <= 32 {
+        // Long multiplication:
+        for (i, xi) in x.iter().enumerate() {
+            mac_digit(&mut acc[i..], y, *xi);
+        }
+    } else if x.len() <= 256 {
+        /*
+         * Karatsuba multiplication:
+         *
+         * The idea is that we break x and y up into two smaller numbers that each have about half
+         * as many digits, like so (note that multiplying by b is just a shift):
+         *
+         * x = x0 + x1 * b
+         * y = y0 + y1 * b
+         *
+         * With some algebra, we can compute x * y with three smaller products, where the inputs to
+         * each of the smaller products have only about half as many digits as x and y:
+         *
+         * x * y = (x0 + x1 * b) * (y0 + y1 * b)
+         *
+         * x * y = x0 * y0
+         *       + x0 * y1 * b
+         *       + x1 * y0 * b
+         *       + x1 * y1 * b^2
+         *
+         * Let p0 = x0 * y0 and p2 = x1 * y1:
+         *
+         * x * y = p0
+         *       + (x0 * y1 + x1 * y0) * b
+         *       + p2 * b^2
+         *
+         * The real trick is that middle term:
+         *
+         *         x0 * y1 + x1 * y0
+         *
+         *       = x0 * y1 + x1 * y0 - p0 + p0 - p2 + p2
+         *
+         *       = x0 * y1 + x1 * y0 - x0 * y0 - x1 * y1 + p0 + p2
+         *
+         * Now we complete the square:
+         *
+         *       = -(x0 * y0 - x0 * y1 - x1 * y0 + x1 * y1) + p0 + p2
+         *
+         *       = -((x1 - x0) * (y1 - y0)) + p0 + p2
+         *
+         * Let p1 = (x1 - x0) * (y1 - y0), and substitute back into our original formula:
+         *
+         * x * y = p0
+         *       + (p0 + p2 - p1) * b
+         *       + p2 * b^2
+         *
+         * Where the three intermediate products are:
+         *
+         * p0 = x0 * y0
+         * p1 = (x1 - x0) * (y1 - y0)
+         * p2 = x1 * y1
+         *
+         * In doing the computation, we take great care to avoid unnecessary temporary variables
+         * (since creating a BigUint requires a heap allocation): thus, we rearrange the formula a
+         * bit so we can use the same temporary variable for all the intermediate products:
+         *
+         * x * y = p2 * b^2 + p2 * b
+         *       + p0 * b + p0
+         *       - p1 * b
+         *
+         * The other trick we use is instead of doing explicit shifts, we slice acc at the
+         * appropriate offset when doing the add.
+         */
+
+        /*
+         * When x is smaller than y, it's significantly faster to pick b such that x is split in
+         * half, not y:
+         */
+        let b = x.len() / 2;
+        let (x0, x1) = x.split_at(b);
+        let (y0, y1) = y.split_at(b);
+
+        /*
+         * We reuse the same BigUint for all the intermediate multiplies and have to size p
+         * appropriately here: x1.len() >= x0.len and y1.len() >= y0.len():
+         */
+        let len = x1.len() + y1.len() + 1;
+        let mut p = BigUint { data: vec![0; len] };
+
+        // p2 = x1 * y1
+        mac3(&mut p.data[..], x1, y1);
+
+        // Not required, but the adds go faster if we drop any unneeded 0s from the end:
+        p.normalize();
+
+        add2(&mut acc[b..],        &p.data[..]);
+        add2(&mut acc[b * 2..],    &p.data[..]);
+
+        // Zero out p before the next multiply:
+        p.data.truncate(0);
+        p.data.extend(repeat(0).take(len));
+
+        // p0 = x0 * y0
+        mac3(&mut p.data[..], x0, y0);
+        p.normalize();
+
+        add2(&mut acc[..],         &p.data[..]);
+        add2(&mut acc[b..],        &p.data[..]);
+
+        // p1 = (x1 - x0) * (y1 - y0)
+        // We do this one last, since it may be negative and acc can't ever be negative:
+        let (j0_sign, j0) = sub_sign(x1, x0);
+        let (j1_sign, j1) = sub_sign(y1, y0);
+
+        match j0_sign * j1_sign {
+            Plus    => {
+                p.data.truncate(0);
+                p.data.extend(repeat(0).take(len));
+
+                mac3(&mut p.data[..], &j0.data[..], &j1.data[..]);
+                p.normalize();
+
+                sub2(&mut acc[b..], &p.data[..]);
+            },
+            Minus   => {
+                mac3(&mut acc[b..], &j0.data[..], &j1.data[..]);
+            },
+            NoSign  => (),
+        }
+
+    } else {
+        // Toom-3 multiplication:
+        //
+        // Toom-3 is like Karatsuba above, but dividing the inputs into three parts.
+        // Both are instances of Toom-Cook, using `k=3` and `k=2` respectively.
+        //
+        // FIXME: It would be nice to have comments breaking down the operations below.
+
+        let i = y.len()/3 + 1;
+
+        let x0_len = cmp::min(x.len(), i);
+        let x1_len = cmp::min(x.len() - x0_len, i);
+
+        let y0_len = i;
+        let y1_len = cmp::min(y.len() - y0_len, i);
+
+        let x0 = BigInt::from_slice(Plus, &x[..x0_len]);
+        let x1 = BigInt::from_slice(Plus, &x[x0_len..x0_len + x1_len]);
+        let x2 = BigInt::from_slice(Plus, &x[x0_len + x1_len..]);
+
+        let y0 = BigInt::from_slice(Plus, &y[..y0_len]);
+        let y1 = BigInt::from_slice(Plus, &y[y0_len..y0_len + y1_len]);
+        let y2 = BigInt::from_slice(Plus, &y[y0_len + y1_len..]);
+
+        let p = &x0 + &x2;
+        let q = &y0 + &y2;
+
+        let p2 = &p - &x1;
+        let q2 = &q - &y1;
+
+        let r0 = &x0 * &y0;
+        let r4 = &x2 * &y2;
+        let r1 = (p + x1) * (q + y1);
+        let r2 = &p2 * &q2;
+        let r3 = ((p2 + x2)*2 - x0) * ((q2 + y2)*2 - y0);
+
+        let mut comp3: BigInt = (r3 - &r1) / 3;
+        let mut comp1: BigInt = (r1 - &r2) / 2;
+        let mut comp2: BigInt = r2 - &r0;
+        comp3 = (&comp2 - comp3)/2 + &r4*2;
+        comp2 = comp2 + &comp1 - &r4;
+        comp1 = comp1 - &comp3;
+
+        let result = r0 + (comp1 << 32*i) + (comp2 << 2*32*i) + (comp3 << 3*32*i) + (r4 << 4*32*i);
+        let result_pos = result.to_biguint().unwrap();
+        add2(&mut acc[..], &result_pos.data);
+    }
+}
+
+pub fn mul3(x: &[BigDigit], y: &[BigDigit]) -> BigUint {
+    let len = x.len() + y.len() + 1;
+    let mut prod = BigUint { data: vec![0; len] };
+
+    mac3(&mut prod.data[..], x, y);
+    prod.normalized()
+}
+
+pub fn scalar_mul(a: &mut [BigDigit], b: BigDigit) -> BigDigit {
+    let mut carry = 0;
+    for a in a.iter_mut() {
+        *a = mul_with_carry(*a, b, &mut carry);
+    }
+    carry
+}
+
+pub fn div_rem(u: &BigUint, d: &BigUint) -> (BigUint, BigUint) {
+    if d.is_zero() {
+        panic!()
+    }
+    if u.is_zero() {
+        return (Zero::zero(), Zero::zero());
+    }
+    if d.data == [1] {
+        return (u.clone(), Zero::zero());
+    }
+    if d.data.len() == 1 {
+        let (div, rem) = div_rem_digit(u.clone(), d.data[0]);
+        return (div, rem.into());
+    }
+
+    // Required or the q_len calculation below can underflow:
+    match u.cmp(d) {
+        Less => return (Zero::zero(), u.clone()),
+        Equal => return (One::one(), Zero::zero()),
+        Greater => {} // Do nothing
+    }
+
+    // This algorithm is from Knuth, TAOCP vol 2 section 4.3, algorithm D:
+    //
+    // First, normalize the arguments so the highest bit in the highest digit of the divisor is
+    // set: the main loop uses the highest digit of the divisor for generating guesses, so we
+    // want it to be the largest number we can efficiently divide by.
+    //
+    let shift = d.data.last().unwrap().leading_zeros() as usize;
+    let mut a = u << shift;
+    let b = d << shift;
+
+    // The algorithm works by incrementally calculating "guesses", q0, for part of the
+    // remainder. Once we have any number q0 such that q0 * b <= a, we can set
+    //
+    //     q += q0
+    //     a -= q0 * b
+    //
+    // and then iterate until a < b. Then, (q, a) will be our desired quotient and remainder.
+    //
+    // q0, our guess, is calculated by dividing the last few digits of a by the last digit of b
+    // - this should give us a guess that is "close" to the actual quotient, but is possibly
+    // greater than the actual quotient. If q0 * b > a, we simply use iterated subtraction
+    // until we have a guess such that q0 * b <= a.
+    //
+
+    let bn = *b.data.last().unwrap();
+    let q_len = a.data.len() - b.data.len() + 1;
+    let mut q = BigUint { data: vec![0; q_len] };
+
+    // We reuse the same temporary to avoid hitting the allocator in our inner loop - this is
+    // sized to hold a0 (in the common case; if a particular digit of the quotient is zero a0
+    // can be bigger).
+    //
+    let mut tmp = BigUint { data: Vec::with_capacity(2) };
+
+    for j in (0..q_len).rev() {
+        /*
+         * When calculating our next guess q0, we don't need to consider the digits below j
+         * + b.data.len() - 1: we're guessing digit j of the quotient (i.e. q0 << j) from
+         * digit bn of the divisor (i.e. bn << (b.data.len() - 1) - so the product of those
+         * two numbers will be zero in all digits up to (j + b.data.len() - 1).
+         */
+        let offset = j + b.data.len() - 1;
+        if offset >= a.data.len() {
+            continue;
+        }
+
+        /* just avoiding a heap allocation: */
+        let mut a0 = tmp;
+        a0.data.truncate(0);
+        a0.data.extend(a.data[offset..].iter().cloned());
+
+        /*
+         * q0 << j * big_digit::BITS is our actual quotient estimate - we do the shifts
+         * implicitly at the end, when adding and subtracting to a and q. Not only do we
+         * save the cost of the shifts, the rest of the arithmetic gets to work with
+         * smaller numbers.
+         */
+        let (mut q0, _) = div_rem_digit(a0, bn);
+        let mut prod = &b * &q0;
+
+        while cmp_slice(&prod.data[..], &a.data[j..]) == Greater {
+            let one: BigUint = One::one();
+            q0 = q0 - one;
+            prod = prod - &b;
+        }
+
+        add2(&mut q.data[j..], &q0.data[..]);
+        sub2(&mut a.data[j..], &prod.data[..]);
+        a.normalize();
+
+        tmp = q0;
+    }
+
+    debug_assert!(a < b);
+
+    (q.normalized(), a >> shift)
+}
+
+/// Find last set bit
+/// fls(0) == 0, fls(u32::MAX) == 32
+pub fn fls<T: traits::PrimInt>(v: T) -> usize {
+    mem::size_of::<T>() * 8 - v.leading_zeros() as usize
+}
+
+pub fn ilog2<T: traits::PrimInt>(v: T) -> usize {
+    fls(v) - 1
+}
+
+#[inline]
+pub fn biguint_shl(n: Cow<BigUint>, bits: usize) -> BigUint {
+    let n_unit = bits / big_digit::BITS;
+    let mut data = match n_unit {
+        0 => n.into_owned().data,
+        _ => {
+            let len = n_unit + n.data.len() + 1;
+            let mut data = Vec::with_capacity(len);
+            data.extend(repeat(0).take(n_unit));
+            data.extend(n.data.iter().cloned());
+            data
+        }
+    };
+
+    let n_bits = bits % big_digit::BITS;
+    if n_bits > 0 {
+        let mut carry = 0;
+        for elem in data[n_unit..].iter_mut() {
+            let new_carry = *elem >> (big_digit::BITS - n_bits);
+            *elem = (*elem << n_bits) | carry;
+            carry = new_carry;
+        }
+        if carry != 0 {
+            data.push(carry);
+        }
+    }
+
+    BigUint::new(data)
+}
+
+#[inline]
+pub fn biguint_shr(n: Cow<BigUint>, bits: usize) -> BigUint {
+    let n_unit = bits / big_digit::BITS;
+    if n_unit >= n.data.len() {
+        return Zero::zero();
+    }
+    let mut data = match n {
+        Cow::Borrowed(n) => n.data[n_unit..].to_vec(),
+        Cow::Owned(mut n) => {
+            n.data.drain(..n_unit);
+            n.data
+        }
+    };
+
+    let n_bits = bits % big_digit::BITS;
+    if n_bits > 0 {
+        let mut borrow = 0;
+        for elem in data.iter_mut().rev() {
+            let new_borrow = *elem << (big_digit::BITS - n_bits);
+            *elem = (*elem >> n_bits) | borrow;
+            borrow = new_borrow;
+        }
+    }
+
+    BigUint::new(data)
+}
+
+pub fn cmp_slice(a: &[BigDigit], b: &[BigDigit]) -> Ordering {
+    debug_assert!(a.last() != Some(&0));
+    debug_assert!(b.last() != Some(&0));
+
+    let (a_len, b_len) = (a.len(), b.len());
+    if a_len < b_len {
+        return Less;
+    }
+    if a_len > b_len {
+        return Greater;
+    }
+
+    for (&ai, &bi) in a.iter().rev().zip(b.iter().rev()) {
+        if ai < bi {
+            return Less;
+        }
+        if ai > bi {
+            return Greater;
+        }
+    }
+    return Equal;
+}
+
+#[cfg(test)]
+mod algorithm_tests {
+    use {BigDigit, BigUint, BigInt};
+    use Sign::Plus;
+    use traits::Num;
+
+    #[test]
+    fn test_sub_sign() {
+        use super::sub_sign;
+
+        fn sub_sign_i(a: &[BigDigit], b: &[BigDigit]) -> BigInt {
+            let (sign, val) = sub_sign(a, b);
+            BigInt::from_biguint(sign, val)
+        }
+
+        let a = BigUint::from_str_radix("265252859812191058636308480000000", 10).unwrap();
+        let b = BigUint::from_str_radix("26525285981219105863630848000000", 10).unwrap();
+        let a_i = BigInt::from_biguint(Plus, a.clone());
+        let b_i = BigInt::from_biguint(Plus, b.clone());
+
+        assert_eq!(sub_sign_i(&a.data[..], &b.data[..]), &a_i - &b_i);
+        assert_eq!(sub_sign_i(&b.data[..], &a.data[..]), &b_i - &a_i);
+    }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/num-bigint/src/bigint.rs
@@ -0,0 +1,1795 @@
+use std::default::Default;
+use std::ops::{Add, Div, Mul, Neg, Rem, Shl, Shr, Sub, Not};
+use std::str::{self, FromStr};
+use std::fmt;
+use std::cmp::Ordering::{self, Less, Greater, Equal};
+use std::{i64, u64};
+#[allow(unused_imports)]
+use std::ascii::AsciiExt;
+
+#[cfg(feature = "serde")]
+use serde;
+
+// Some of the tests of non-RNG-based functionality are randomized using the
+// RNG-based functionality, so the RNG-based functionality needs to be enabled
+// for tests.
+#[cfg(any(feature = "rand", test))]
+use rand::Rng;
+
+use integer::Integer;
+use traits::{ToPrimitive, FromPrimitive, Num, CheckedAdd, CheckedSub,
+             CheckedMul, CheckedDiv, Signed, Zero, One};
+
+use self::Sign::{Minus, NoSign, Plus};
+
+use super::ParseBigIntError;
+use super::big_digit;
+use super::big_digit::{BigDigit, DoubleBigDigit};
+use biguint;
+use biguint::to_str_radix_reversed;
+use biguint::BigUint;
+
+use UsizePromotion;
+use IsizePromotion;
+
+#[cfg(test)]
+#[path = "tests/bigint.rs"]
+mod bigint_tests;
+
+/// A Sign is a `BigInt`'s composing element.
+#[derive(PartialEq, PartialOrd, Eq, Ord, Copy, Clone, Debug, Hash)]
+#[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))]
+pub enum Sign {
+    Minus,
+    NoSign,
+    Plus,
+}
+
+impl Neg for Sign {
+    type Output = Sign;
+
+    /// Negate Sign value.
+    #[inline]
+    fn neg(self) -> Sign {
+        match self {
+            Minus => Plus,
+            NoSign => NoSign,
+            Plus => Minus,
+        }
+    }
+}
+
+impl Mul<Sign> for Sign {
+    type Output = Sign;
+
+    #[inline]
+    fn mul(self, other: Sign) -> Sign {
+        match (self, other) {
+            (NoSign, _) | (_, NoSign) => NoSign,
+            (Plus, Plus) | (Minus, Minus) => Plus,
+            (Plus, Minus) | (Minus, Plus) => Minus,
+        }
+    }
+}
+
+#[cfg(feature = "serde")]
+impl serde::Serialize for Sign {
+    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
+        where S: serde::Serializer
+    {
+        match *self {
+            Sign::Minus => (-1i8).serialize(serializer),
+            Sign::NoSign => 0i8.serialize(serializer),
+            Sign::Plus => 1i8.serialize(serializer),
+        }
+    }
+}
+
+#[cfg(feature = "serde")]
+impl serde::Deserialize for Sign {
+    fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error>
+        where D: serde::Deserializer
+    {
+        use serde::de::Error;
+
+        let sign: i8 = try!(serde::Deserialize::deserialize(deserializer));
+        match sign {
+            -1 => Ok(Sign::Minus),
+            0 => Ok(Sign::NoSign),
+            1 => Ok(Sign::Plus),
+            _ => Err(D::Error::invalid_value("sign must be -1, 0, or 1")),
+        }
+    }
+}
+
+/// A big signed integer type.
+#[derive(Clone, Debug, Hash)]
+#[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))]
+pub struct BigInt {
+    sign: Sign,
+    data: BigUint,
+}
+
+impl PartialEq for BigInt {
+    #[inline]
+    fn eq(&self, other: &BigInt) -> bool {
+        self.cmp(other) == Equal
+    }
+}
+
+impl Eq for BigInt {}
+
+impl PartialOrd for BigInt {
+    #[inline]
+    fn partial_cmp(&self, other: &BigInt) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+impl Ord for BigInt {
+    #[inline]
+    fn cmp(&self, other: &BigInt) -> Ordering {
+        let scmp = self.sign.cmp(&other.sign);
+        if scmp != Equal {
+            return scmp;
+        }
+
+        match self.sign {
+            NoSign => Equal,
+            Plus => self.data.cmp(&other.data),
+            Minus => other.data.cmp(&self.data),
+        }
+    }
+}
+
+impl Default for BigInt {
+    #[inline]
+    fn default() -> BigInt {
+        Zero::zero()
+    }
+}
+
+impl fmt::Display for BigInt {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.pad_integral(!self.is_negative(), "", &self.data.to_str_radix(10))
+    }
+}
+
+impl fmt::Binary for BigInt {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.pad_integral(!self.is_negative(), "0b", &self.data.to_str_radix(2))
+    }
+}
+
+impl fmt::Octal for BigInt {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.pad_integral(!self.is_negative(), "0o", &self.data.to_str_radix(8))
+    }
+}
+
+impl fmt::LowerHex for BigInt {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.pad_integral(!self.is_negative(), "0x", &self.data.to_str_radix(16))
+    }
+}
+
+impl fmt::UpperHex for BigInt {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.pad_integral(!self.is_negative(),
+                       "0x",
+                       &self.data.to_str_radix(16).to_ascii_uppercase())
+    }
+}
+
+impl FromStr for BigInt {
+    type Err = ParseBigIntError;
+
+    #[inline]
+    fn from_str(s: &str) -> Result<BigInt, ParseBigIntError> {
+        BigInt::from_str_radix(s, 10)
+    }
+}
+
+impl Num for BigInt {
+    type FromStrRadixErr = ParseBigIntError;
+
+    /// Creates and initializes a BigInt.
+    #[inline]
+    fn from_str_radix(mut s: &str, radix: u32) -> Result<BigInt, ParseBigIntError> {
+        let sign = if s.starts_with('-') {
+            let tail = &s[1..];
+            if !tail.starts_with('+') {
+                s = tail
+            }
+            Minus
+        } else {
+            Plus
+        };
+        let bu = try!(BigUint::from_str_radix(s, radix));
+        Ok(BigInt::from_biguint(sign, bu))
+    }
+}
+
+impl Shl<usize> for BigInt {
+    type Output = BigInt;
+
+    #[inline]
+    fn shl(self, rhs: usize) -> BigInt {
+        (&self) << rhs
+    }
+}
+
+impl<'a> Shl<usize> for &'a BigInt {
+    type Output = BigInt;
+
+    #[inline]
+    fn shl(self, rhs: usize) -> BigInt {
+        BigInt::from_biguint(self.sign, &self.data << rhs)
+    }
+}
+
+impl Shr<usize> for BigInt {
+    type Output = BigInt;
+
+    #[inline]
+    fn shr(self, rhs: usize) -> BigInt {
+        BigInt::from_biguint(self.sign, self.data >> rhs)
+    }
+}
+
+impl<'a> Shr<usize> for &'a BigInt {
+    type Output = BigInt;
+
+    #[inline]
+    fn shr(self, rhs: usize) -> BigInt {
+        BigInt::from_biguint(self.sign, &self.data >> rhs)
+    }
+}
+
+impl Zero for BigInt {
+    #[inline]
+    fn zero() -> BigInt {
+        BigInt::from_biguint(NoSign, Zero::zero())
+    }
+
+    #[inline]
+    fn is_zero(&self) -> bool {
+        self.sign == NoSign
+    }
+}
+
+impl One for BigInt {
+    #[inline]
+    fn one() -> BigInt {
+        BigInt::from_biguint(Plus, One::one())
+    }
+}
+
+impl Signed for BigInt {
+    #[inline]
+    fn abs(&self) -> BigInt {
+        match self.sign {
+            Plus | NoSign => self.clone(),
+            Minus => BigInt::from_biguint(Plus, self.data.clone()),
+        }
+    }
+
+    #[inline]
+    fn abs_sub(&self, other: &BigInt) -> BigInt {
+        if *self <= *other {
+            Zero::zero()
+        } else {
+            self - other
+        }
+    }
+
+    #[inline]
+    fn signum(&self) -> BigInt {
+        match self.sign {
+            Plus => BigInt::from_biguint(Plus, One::one()),
+            Minus => BigInt::from_biguint(Minus, One::one()),
+            NoSign => Zero::zero(),
+        }
+    }
+
+    #[inline]
+    fn is_positive(&self) -> bool {
+        self.sign == Plus
+    }
+
+    #[inline]
+    fn is_negative(&self) -> bool {
+        self.sign == Minus
+    }
+}
+
+// A convenience method for getting the absolute value of an i32 in a u32.
+#[inline]
+fn i32_abs_as_u32(a: i32) -> u32 {
+    if a == i32::min_value() {
+        a as u32
+    } else {
+        a.abs() as u32
+    }
+}
+
+// A convenience method for getting the absolute value of an i64 in a u64.
+#[inline]
+fn i64_abs_as_u64(a: i64) -> u64 {
+    if a == i64::min_value() {
+        a as u64
+    } else {
+        a.abs() as u64
+    }
+}
+
+// We want to forward to BigUint::add, but it's not clear how that will go until
+// we compare both sign and magnitude.  So we duplicate this body for every
+// val/ref combination, deferring that decision to BigUint's own forwarding.
+macro_rules! bigint_add {
+    ($a:expr, $a_owned:expr, $a_data:expr, $b:expr, $b_owned:expr, $b_data:expr) => {
+        match ($a.sign, $b.sign) {
+            (_, NoSign) => $a_owned,
+            (NoSign, _) => $b_owned,
+            // same sign => keep the sign with the sum of magnitudes
+            (Plus, Plus) | (Minus, Minus) =>
+                BigInt::from_biguint($a.sign, $a_data + $b_data),
+            // opposite signs => keep the sign of the larger with the difference of magnitudes
+            (Plus, Minus) | (Minus, Plus) =>
+                match $a.data.cmp(&$b.data) {
+                    Less => BigInt::from_biguint($b.sign, $b_data - $a_data),
+                    Greater => BigInt::from_biguint($a.sign, $a_data - $b_data),
+                    Equal => Zero::zero(),
+                },
+        }
+    };
+}
+
+impl<'a, 'b> Add<&'b BigInt> for &'a BigInt {
+    type Output = BigInt;
+
+    #[inline]
+    fn add(self, other: &BigInt) -> BigInt {
+        bigint_add!(self,
+                    self.clone(),
+                    &self.data,
+                    other,
+                    other.clone(),
+                    &other.data)
+    }
+}
+
+impl<'a> Add<BigInt> for &'a BigInt {
+    type Output = BigInt;
+
+    #[inline]
+    fn add(self, other: BigInt) -> BigInt {
+        bigint_add!(self, self.clone(), &self.data, other, other, other.data)
+    }
+}
+
+impl<'a> Add<&'a BigInt> for BigInt {
+    type Output = BigInt;
+
+    #[inline]
+    fn add(self, other: &BigInt) -> BigInt {
+        bigint_add!(self, self, self.data, other, other.clone(), &other.data)
+    }
+}
+
+impl Add<BigInt> for BigInt {
+    type Output = BigInt;
+
+    #[inline]
+    fn add(self, other: BigInt) -> BigInt {
+        bigint_add!(self, self, self.data, other, other, other.data)
+    }
+}
+
+promote_all_scalars!(impl Add for BigInt, add);
+forward_all_scalar_binop_to_val_val_commutative!(impl Add<BigDigit> for BigInt, add);
+forward_all_scalar_binop_to_val_val_commutative!(impl Add<DoubleBigDigit> for BigInt, add);
+
+impl Add<BigDigit> for BigInt {
+    type Output = BigInt;
+
+    #[inline]
+    fn add(self, other: BigDigit) -> BigInt {
+        match self.sign {
+            NoSign => From::from(other),
+            Plus => BigInt::from_biguint(Plus, self.data + other),
+            Minus =>
+                match self.data.cmp(&From::from(other)) {
+                    Equal => Zero::zero(),
+                    Less => BigInt::from_biguint(Plus, other - self.data),
+                    Greater => BigInt::from_biguint(Minus, self.data - other),
+                }
+        }
+    }
+}
+
+impl Add<DoubleBigDigit> for BigInt {
+    type Output = BigInt;
+
+    #[inline]
+    fn add(self, other: DoubleBigDigit) -> BigInt {
+        match self.sign {
+            NoSign => From::from(other),
+            Plus => BigInt::from_biguint(Plus, self.data + other),
+            Minus =>
+                match self.data.cmp(&From::from(other)) {
+                    Equal => Zero::zero(),
+                    Less => BigInt::from_biguint(Plus, other - self.data),
+                    Greater => BigInt::from_biguint(Minus, self.data - other),
+                }
+        }
+    }
+}
+
+forward_all_scalar_binop_to_val_val_commutative!(impl Add<i32> for BigInt, add);
+forward_all_scalar_binop_to_val_val_commutative!(impl Add<i64> for BigInt, add);
+
+impl Add<i32> for BigInt {
+    type Output = BigInt;
+
+    #[inline]
+    fn add(self, other: i32) -> BigInt {
+        if other >= 0 {
+            self + other as u32
+        } else {
+            self - i32_abs_as_u32(other)
+        }
+    }
+}
+
+impl Add<i64> for BigInt {
+    type Output = BigInt;
+
+    #[inline]
+    fn add(self, other: i64) -> BigInt {
+        if other >= 0 {
+            self + other as u64
+        } else {
+            self - i64_abs_as_u64(other)
+        }
+    }
+}
+
+// We want to forward to BigUint::sub, but it's not clear how that will go until
+// we compare both sign and magnitude.  So we duplicate this body for every
+// val/ref combination, deferring that decision to BigUint's own forwarding.
+macro_rules! bigint_sub {
+    ($a:expr, $a_owned:expr, $a_data:expr, $b:expr, $b_owned:expr, $b_data:expr) => {
+        match ($a.sign, $b.sign) {
+            (_, NoSign) => $a_owned,
+            (NoSign, _) => -$b_owned,
+            // opposite signs => keep the sign of the left with the sum of magnitudes
+            (Plus, Minus) | (Minus, Plus) =>
+                BigInt::from_biguint($a.sign, $a_data + $b_data),
+            // same sign => keep or toggle the sign of the left with the difference of magnitudes
+            (Plus, Plus) | (Minus, Minus) =>
+                match $a.data.cmp(&$b.data) {
+                    Less => BigInt::from_biguint(-$a.sign, $b_data - $a_data),
+                    Greater => BigInt::from_biguint($a.sign, $a_data - $b_data),
+                    Equal => Zero::zero(),
+                },
+        }
+    };
+}
+
+impl<'a, 'b> Sub<&'b BigInt> for &'a BigInt {
+    type Output = BigInt;
+
+    #[inline]
+    fn sub(self, other: &BigInt) -> BigInt {
+        bigint_sub!(self,
+                    self.clone(),
+                    &self.data,
+                    other,
+                    other.clone(),
+                    &other.data)
+    }
+}
+
+impl<'a> Sub<BigInt> for &'a BigInt {
+    type Output = BigInt;
+
+    #[inline]
+    fn sub(self, other: BigInt) -> BigInt {
+        bigint_sub!(self, self.clone(), &self.data, other, other, other.data)
+    }
+}
+
+impl<'a> Sub<&'a BigInt> for BigInt {
+    type Output = BigInt;
+
+    #[inline]
+    fn sub(self, other: &BigInt) -> BigInt {
+        bigint_sub!(self, self, self.data, other, other.clone(), &other.data)
+    }
+}
+
+impl Sub<BigInt> for BigInt {
+    type Output = BigInt;
+
+    #[inline]
+    fn sub(self, other: BigInt) -> BigInt {
+        bigint_sub!(self, self, self.data, other, other, other.data)
+    }
+}
+
+promote_all_scalars!(impl Sub for BigInt, sub);
+forward_all_scalar_binop_to_val_val!(impl Sub<BigDigit> for BigInt, sub);
+forward_all_scalar_binop_to_val_val!(impl Sub<DoubleBigDigit> for BigInt, sub);
+
+impl Sub<BigDigit> for BigInt {
+    type Output = BigInt;
+
+    #[inline]
+    fn sub(self, other: BigDigit) -> BigInt {
+        match self.sign {
+            NoSign => BigInt::from_biguint(Minus, From::from(other)),
+            Minus => BigInt::from_biguint(Minus, self.data + other),
+            Plus =>
+                match self.data.cmp(&From::from(other)) {
+                    Equal => Zero::zero(),
+                    Greater => BigInt::from_biguint(Plus, self.data - other),
+                    Less => BigInt::from_biguint(Minus, other - self.data),
+                }
+        }
+    }
+}
+
+impl Sub<BigInt> for BigDigit {
+    type Output = BigInt;
+
+    #[inline]
+    fn sub(self, other: BigInt) -> BigInt {
+        -(other - self)
+    }
+}
+
+impl Sub<DoubleBigDigit> for BigInt {
+    type Output = BigInt;
+
+    #[inline]
+    fn sub(self, other: DoubleBigDigit) -> BigInt {
+        match self.sign {
+            NoSign => BigInt::from_biguint(Minus, From::from(other)),
+            Minus => BigInt::from_biguint(Minus, self.data + other),
+            Plus =>
+                match self.data.cmp(&From::from(other)) {
+                    Equal => Zero::zero(),
+                    Greater => BigInt::from_biguint(Plus, self.data - other),
+                    Less => BigInt::from_biguint(Minus, other - self.data),
+                }
+        }
+    }
+}
+
+impl Sub<BigInt> for DoubleBigDigit {
+    type Output = BigInt;
+
+    #[inline]
+    fn sub(self, other: BigInt) -> BigInt {
+        -(other - self)
+    }
+}
+
+forward_all_scalar_binop_to_val_val!(impl Sub<i32> for BigInt, sub);
+forward_all_scalar_binop_to_val_val!(impl Sub<i64> for BigInt, sub);
+
+impl Sub<i32> for BigInt {
+    type Output = BigInt;
+
+    #[inline]
+    fn sub(self, other: i32) -> BigInt {
+        if other >= 0 {
+            self - other as u32
+        } else {
+            self + i32_abs_as_u32(other)
+        }
+    }
+}
+
+impl Sub<BigInt> for i32 {
+    type Output = BigInt;
+
+    #[inline]
+    fn sub(self, other: BigInt) -> BigInt {
+        if self >= 0 {
+            self as u32 - other
+        } else {
+            -other - i32_abs_as_u32(self)
+        }
+    }
+}
+
+impl Sub<i64> for BigInt {
+    type Output = BigInt;
+
+    #[inline]
+    fn sub(self, other: i64) -> BigInt {
+        if other >= 0 {
+            self - other as u64
+        } else {
+            self + i64_abs_as_u64(other)
+        }
+    }
+}
+
+impl Sub<BigInt> for i64 {
+    type Output = BigInt;
+
+    #[inline]
+    fn sub(self, other: BigInt) -> BigInt {
+        if self >= 0 {
+            self as u64 - other
+        } else {
+            -other - i64_abs_as_u64(self)
+        }
+    }
+}
+
+forward_all_binop_to_ref_ref!(impl Mul for BigInt, mul);
+
+impl<'a, 'b> Mul<&'b BigInt> for &'a BigInt {
+    type Output = BigInt;
+
+    #[inline]
+    fn mul(self, other: &BigInt) -> BigInt {
+        BigInt::from_biguint(self.sign * other.sign, &self.data * &other.data)
+    }
+}
+
+promote_all_scalars!(impl Mul for BigInt, mul);
+forward_all_scalar_binop_to_val_val_commutative!(impl Mul<BigDigit> for BigInt, mul);
+forward_all_scalar_binop_to_val_val_commutative!(impl Mul<DoubleBigDigit> for BigInt, mul);
+
+impl Mul<BigDigit> for BigInt {
+    type Output = BigInt;
+
+    #[inline]
+    fn mul(self, other: BigDigit) -> BigInt {
+        BigInt::from_biguint(self.sign, self.data * other)
+    }
+}
+
+impl Mul<DoubleBigDigit> for BigInt {
+    type Output = BigInt;
+
+    #[inline]
+    fn mul(self, other: DoubleBigDigit) -> BigInt {
+        BigInt::from_biguint(self.sign, self.data * other)
+    }
+}
+
+forward_all_scalar_binop_to_val_val_commutative!(impl Mul<i32> for BigInt, mul);
+forward_all_scalar_binop_to_val_val_commutative!(impl Mul<i64> for BigInt, mul);
+
+impl Mul<i32> for BigInt {
+    type Output = BigInt;
+
+    #[inline]
+    fn mul(self, other: i32) -> BigInt {
+        if other >= 0 {
+            self * other as u32
+        } else {
+            -(self * i32_abs_as_u32(other))
+        }
+    }
+}
+
+impl Mul<i64> for BigInt {
+    type Output = BigInt;
+
+    #[inline]
+    fn mul(self, other: i64) -> BigInt {
+        if other >= 0 {
+            self * other as u64
+        } else {
+            -(self * i64_abs_as_u64(other))
+        }
+    }
+}
+
+forward_all_binop_to_ref_ref!(impl Div for BigInt, div);
+
+impl<'a, 'b> Div<&'b BigInt> for &'a BigInt {
+    type Output = BigInt;
+
+    #[inline]
+    fn div(self, other: &BigInt) -> BigInt {
+        let (q, _) = self.div_rem(other);
+        q
+    }
+}
+
+promote_all_scalars!(impl Div for BigInt, div);
+forward_all_scalar_binop_to_val_val!(impl Div<BigDigit> for BigInt, div);
+forward_all_scalar_binop_to_val_val!(impl Div<DoubleBigDigit> for BigInt, div);
+
+impl Div<BigDigit> for BigInt {
+    type Output = BigInt;
+
+    #[inline]
+    fn div(self, other: BigDigit) -> BigInt {
+        BigInt::from_biguint(self.sign, self.data / other)
+    }
+}
+
+impl Div<BigInt> for BigDigit {
+    type Output = BigInt;
+
+    #[inline]
+    fn div(self, other: BigInt) -> BigInt {
+        BigInt::from_biguint(other.sign, self / other.data)
+    }
+}
+
+impl Div<DoubleBigDigit> for BigInt {
+    type Output = BigInt;
+
+    #[inline]
+    fn div(self, other: DoubleBigDigit) -> BigInt {
+        BigInt::from_biguint(self.sign, self.data / other)
+    }
+}
+
+impl Div<BigInt> for DoubleBigDigit {
+    type Output = BigInt;
+
+    #[inline]
+    fn div(self, other: BigInt) -> BigInt {
+        BigInt::from_biguint(other.sign, self / other.data)
+    }
+}
+
+forward_all_scalar_binop_to_val_val!(impl Div<i32> for BigInt, div);
+forward_all_scalar_binop_to_val_val!(impl Div<i64> for BigInt, div);
+
+impl Div<i32> for BigInt {
+    type Output = BigInt;
+
+    #[inline]
+    fn div(self, other: i32) -> BigInt {
+        if other >= 0 {
+            self / other as u32
+        } else {
+            -(self / i32_abs_as_u32(other))
+        }
+    }
+}
+
+impl Div<BigInt> for i32 {
+    type Output = BigInt;
+
+    #[inline]
+    fn div(self, other: BigInt) -> BigInt {
+        if self >= 0 {
+            self as u32 / other
+        } else {
+            -(i32_abs_as_u32(self) / other)
+        }
+    }
+}
+
+impl Div<i64> for BigInt {
+    type Output = BigInt;
+
+    #[inline]
+    fn div(self, other: i64) -> BigInt {
+        if other >= 0 {
+            self / other as u64
+        } else {
+            -(self / i64_abs_as_u64(other))
+        }
+    }
+}
+
+impl Div<BigInt> for i64 {
+    type Output = BigInt;
+
+    #[inline]
+    fn div(self, other: BigInt) -> BigInt {
+        if self >= 0 {
+            self as u64 / other
+        } else {
+            -(i64_abs_as_u64(self) / other)
+        }
+    }
+}
+
+forward_all_binop_to_ref_ref!(impl Rem for BigInt, rem);
+
+impl<'a, 'b> Rem<&'b BigInt> for &'a BigInt {
+    type Output = BigInt;
+
+    #[inline]
+    fn rem(self, other: &BigInt) -> BigInt {
+        let (_, r) = self.div_rem(other);
+        r
+    }
+}
+
+promote_all_scalars!(impl Rem for BigInt, rem);
+forward_all_scalar_binop_to_val_val!(impl Rem<BigDigit> for BigInt, rem);
+forward_all_scalar_binop_to_val_val!(impl Rem<DoubleBigDigit> for BigInt, rem);
+
+impl Rem<BigDigit> for BigInt {
+    type Output = BigInt;
+
+    #[inline]
+    fn rem(self, other: BigDigit) -> BigInt {
+        BigInt::from_biguint(self.sign, self.data % other)
+    }
+}
+
+impl Rem<BigInt> for BigDigit {
+    type Output = BigInt;
+
+    #[inline]
+    fn rem(self, other: BigInt) -> BigInt {
+        BigInt::from_biguint(Plus, self % other.data)
+    }
+}
+
+impl Rem<DoubleBigDigit> for BigInt {
+    type Output = BigInt;
+
+    #[inline]
+    fn rem(self, other: DoubleBigDigit) -> BigInt {
+        BigInt::from_biguint(self.sign, self.data % other)
+    }
+}
+
+impl Rem<BigInt> for DoubleBigDigit {
+    type Output = BigInt;
+
+    #[inline]
+    fn rem(self, other: BigInt) -> BigInt {
+        BigInt::from_biguint(Plus, self % other.data)
+    }
+}
+
+forward_all_scalar_binop_to_val_val!(impl Rem<i32> for BigInt, rem);
+forward_all_scalar_binop_to_val_val!(impl Rem<i64> for BigInt, rem);
+
+impl Rem<i32> for BigInt {
+    type Output = BigInt;
+
+    #[inline]
+    fn rem(self, other: i32) -> BigInt {
+        if other >= 0 {
+            self % other as u32
+        } else {
+            self % i32_abs_as_u32(other)
+        }
+    }
+}
+
+impl Rem<BigInt> for i32 {
+    type Output = BigInt;
+
+    #[inline]
+    fn rem(self, other: BigInt) -> BigInt {
+        if self >= 0 {
+            self as u32 % other
+        } else {
+            -(i32_abs_as_u32(self) % other)
+        }
+    }
+}
+
+impl Rem<i64> for BigInt {
+    type Output = BigInt;
+
+    #[inline]
+    fn rem(self, other: i64) -> BigInt {
+        if other >= 0 {
+            self % other as u64
+        } else {
+            self % i64_abs_as_u64(other)
+        }
+    }
+}
+
+impl Rem<BigInt> for i64 {
+    type Output = BigInt;
+
+    #[inline]
+    fn rem(self, other: BigInt) -> BigInt {
+        if self >= 0 {
+            self as u64 % other
+        } else {
+            -(i64_abs_as_u64(self) % other)
+        }
+    }
+}
+
+impl Neg for BigInt {
+    type Output = BigInt;
+
+    #[inline]
+    fn neg(mut self) -> BigInt {
+        self.sign = -self.sign;
+        self
+    }
+}
+
+impl<'a> Neg for &'a BigInt {
+    type Output = BigInt;
+
+    #[inline]
+    fn neg(self) -> BigInt {
+        -self.clone()
+    }
+}
+
+impl CheckedAdd for BigInt {
+    #[inline]
+    fn checked_add(&self, v: &BigInt) -> Option<BigInt> {
+        return Some(self.add(v));
+    }
+}
+
+impl CheckedSub for BigInt {
+    #[inline]
+    fn checked_sub(&self, v: &BigInt) -> Option<BigInt> {
+        return Some(self.sub(v));
+    }
+}
+
+impl CheckedMul for BigInt {
+    #[inline]
+    fn checked_mul(&self, v: &BigInt) -> Option<BigInt> {
+        return Some(self.mul(v));
+    }
+}
+
+impl CheckedDiv for BigInt {
+    #[inline]
+    fn checked_div(&self, v: &BigInt) -> Option<BigInt> {
+        if v.is_zero() {
+            return None;
+        }
+        return Some(self.div(v));
+    }
+}
+
+impl Integer for BigInt {
+    #[inline]
+    fn div_rem(&self, other: &BigInt) -> (BigInt, BigInt) {
+        // r.sign == self.sign
+        let (d_ui, r_ui) = self.data.div_mod_floor(&other.data);
+        let d = BigInt::from_biguint(self.sign, d_ui);
+        let r = BigInt::from_biguint(self.sign, r_ui);
+        if other.is_negative() {
+            (-d, r)
+        } else {
+            (d, r)
+        }
+    }
+
+    #[inline]
+    fn div_floor(&self, other: &BigInt) -> BigInt {
+        let (d, _) = self.div_mod_floor(other);
+        d
+    }
+
+    #[inline]
+    fn mod_floor(&self, other: &BigInt) -> BigInt {
+        let (_, m) = self.div_mod_floor(other);
+        m
+    }
+
+    fn div_mod_floor(&self, other: &BigInt) -> (BigInt, BigInt) {
+        // m.sign == other.sign
+        let (d_ui, m_ui) = self.data.div_rem(&other.data);
+        let d = BigInt::from_biguint(Plus, d_ui);
+        let m = BigInt::from_biguint(Plus, m_ui);
+        let one: BigInt = One::one();
+        match (self.sign, other.sign) {
+            (_, NoSign) => panic!(),
+            (Plus, Plus) | (NoSign, Plus) => (d, m),
+            (Plus, Minus) | (NoSign, Minus) => {
+                if m.is_zero() {
+                    (-d, Zero::zero())
+                } else {
+                    (-d - one, m + other)
+                }
+            }
+            (Minus, Plus) => {
+                if m.is_zero() {
+                    (-d, Zero::zero())
+                } else {
+                    (-d - one, other - m)
+                }
+            }
+            (Minus, Minus) => (d, -m),
+        }
+    }
+
+    /// Calculates the Greatest Common Divisor (GCD) of the number and `other`.
+    ///
+    /// The result is always positive.
+    #[inline]
+    fn gcd(&self, other: &BigInt) -> BigInt {
+        BigInt::from_biguint(Plus, self.data.gcd(&other.data))
+    }
+
+    /// Calculates the Lowest Common Multiple (LCM) of the number and `other`.
+    #[inline]
+    fn lcm(&self, other: &BigInt) -> BigInt {
+        BigInt::from_biguint(Plus, self.data.lcm(&other.data))
+    }
+
+    /// Deprecated, use `is_multiple_of` instead.
+    #[inline]
+    fn divides(&self, other: &BigInt) -> bool {
+        return self.is_multiple_of(other);
+    }
+
+    /// Returns `true` if the number is a multiple of `other`.
+    #[inline]
+    fn is_multiple_of(&self, other: &BigInt) -> bool {
+        self.data.is_multiple_of(&other.data)
+    }
+
+    /// Returns `true` if the number is divisible by `2`.
+    #[inline]
+    fn is_even(&self) -> bool {
+        self.data.is_even()
+    }
+
+    /// Returns `true` if the number is not divisible by `2`.
+    #[inline]
+    fn is_odd(&self) -> bool {
+        self.data.is_odd()
+    }
+}
+
+impl ToPrimitive for BigInt {
+    #[inline]
+    fn to_i64(&self) -> Option<i64> {
+        match self.sign {
+            Plus => self.data.to_i64(),
+            NoSign => Some(0),
+            Minus => {
+                self.data.to_u64().and_then(|n| {
+                    let m: u64 = 1 << 63;
+                    if n < m {
+                        Some(-(n as i64))
+                    } else if n == m {
+                        Some(i64::MIN)
+                    } else {
+                        None
+                    }
+                })
+            }
+        }
+    }
+
+    #[inline]
+    fn to_u64(&self) -> Option<u64> {
+        match self.sign {
+            Plus => self.data.to_u64(),
+            NoSign => Some(0),
+            Minus => None,
+        }
+    }
+
+    #[inline]
+    fn to_f32(&self) -> Option<f32> {
+        self.data.to_f32().map(|n| {
+            if self.sign == Minus {
+                -n
+            } else {
+                n
+            }
+        })
+    }
+
+    #[inline]
+    fn to_f64(&self) -> Option<f64> {
+        self.data.to_f64().map(|n| {
+            if self.sign == Minus {
+                -n
+            } else {
+                n
+            }
+        })
+    }
+}
+
+impl FromPrimitive for BigInt {
+    #[inline]
+    fn from_i64(n: i64) -> Option<BigInt> {
+        Some(BigInt::from(n))
+    }
+
+    #[inline]
+    fn from_u64(n: u64) -> Option<BigInt> {
+        Some(BigInt::from(n))
+    }
+
+    #[inline]
+    fn from_f64(n: f64) -> Option<BigInt> {
+        if n >= 0.0 {
+            BigUint::from_f64(n).map(|x| BigInt::from_biguint(Plus, x))
+        } else {
+            BigUint::from_f64(-n).map(|x| BigInt::from_biguint(Minus, x))
+        }
+    }
+}
+
+impl From<i64> for BigInt {
+    #[inline]
+    fn from(n: i64) -> Self {
+        if n >= 0 {
+            BigInt::from(n as u64)
+        } else {
+            let u = u64::MAX - (n as u64) + 1;
+            BigInt {
+                sign: Minus,
+                data: BigUint::from(u),
+            }
+        }
+    }
+}
+
+macro_rules! impl_bigint_from_int {
+    ($T:ty) => {
+        impl From<$T> for BigInt {
+            #[inline]
+            fn from(n: $T) -> Self {
+                BigInt::from(n as i64)
+            }
+        }
+    }
+}
+
+impl_bigint_from_int!(i8);
+impl_bigint_from_int!(i16);
+impl_bigint_from_int!(i32);
+impl_bigint_from_int!(isize);
+
+impl From<u64> for BigInt {
+    #[inline]
+    fn from(n: u64) -> Self {
+        if n > 0 {
+            BigInt {
+                sign: Plus,
+                data: BigUint::from(n),
+            }
+        } else {
+            BigInt::zero()
+        }
+    }
+}
+
+macro_rules! impl_bigint_from_uint {
+    ($T:ty) => {
+        impl From<$T> for BigInt {
+            #[inline]
+            fn from(n: $T) -> Self {
+                BigInt::from(n as u64)
+            }
+        }
+    }
+}
+
+impl_bigint_from_uint!(u8);
+impl_bigint_from_uint!(u16);
+impl_bigint_from_uint!(u32);
+impl_bigint_from_uint!(usize);
+
+impl From<BigUint> for BigInt {
+    #[inline]
+    fn from(n: BigUint) -> Self {
+        if n.is_zero() {
+            BigInt::zero()
+        } else {
+            BigInt {
+                sign: Plus,
+                data: n,
+            }
+        }
+    }
+}
+
+#[cfg(feature = "serde")]
+impl serde::Serialize for BigInt {
+    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
+        where S: serde::Serializer
+    {
+        (self.sign, &self.data).serialize(serializer)
+    }
+}
+
+#[cfg(feature = "serde")]
+impl serde::Deserialize for BigInt {
+    fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error>
+        where D: serde::Deserializer
+    {
+        let (sign, data) = try!(serde::Deserialize::deserialize(deserializer));
+        Ok(BigInt {
+            sign: sign,
+            data: data,
+        })
+    }
+}
+
+/// A generic trait for converting a value to a `BigInt`.
+pub trait ToBigInt {
+    /// Converts the value of `self` to a `BigInt`.
+    fn to_bigint(&self) -> Option<BigInt>;
+}
+
+impl ToBigInt for BigInt {
+    #[inline]
+    fn to_bigint(&self) -> Option<BigInt> {
+        Some(self.clone())
+    }
+}
+
+impl ToBigInt for BigUint {
+    #[inline]
+    fn to_bigint(&self) -> Option<BigInt> {
+        if self.is_zero() {
+            Some(Zero::zero())
+        } else {
+            Some(BigInt {
+                sign: Plus,
+                data: self.clone(),
+            })
+        }
+    }
+}
+
+impl biguint::ToBigUint for BigInt {
+    #[inline]
+    fn to_biguint(&self) -> Option<BigUint> {
+        match self.sign() {
+            Plus    => Some(self.data.clone()),
+            NoSign  => Some(Zero::zero()),
+            Minus   => None,
+        }
+    }
+}
+
+macro_rules! impl_to_bigint {
+    ($T:ty, $from_ty:path) => {
+        impl ToBigInt for $T {
+            #[inline]
+            fn to_bigint(&self) -> Option<BigInt> {
+                $from_ty(*self)
+            }
+        }
+    }
+}
+
+impl_to_bigint!(isize, FromPrimitive::from_isize);
+impl_to_bigint!(i8, FromPrimitive::from_i8);
+impl_to_bigint!(i16, FromPrimitive::from_i16);
+impl_to_bigint!(i32, FromPrimitive::from_i32);
+impl_to_bigint!(i64, FromPrimitive::from_i64);
+impl_to_bigint!(usize, FromPrimitive::from_usize);
+impl_to_bigint!(u8, FromPrimitive::from_u8);
+impl_to_bigint!(u16, FromPrimitive::from_u16);
+impl_to_bigint!(u32, FromPrimitive::from_u32);
+impl_to_bigint!(u64, FromPrimitive::from_u64);
+impl_to_bigint!(f32, FromPrimitive::from_f32);
+impl_to_bigint!(f64, FromPrimitive::from_f64);
+
+pub trait RandBigInt {
+    /// Generate a random `BigUint` of the given bit size.
+    fn gen_biguint(&mut self, bit_size: usize) -> BigUint;
+
+    /// Generate a random BigInt of the given bit size.
+    fn gen_bigint(&mut self, bit_size: usize) -> BigInt;
+
+    /// Generate a random `BigUint` less than the given bound. Fails
+    /// when the bound is zero.
+    fn gen_biguint_below(&mut self, bound: &BigUint) -> BigUint;
+
+    /// Generate a random `BigUint` within the given range. The lower
+    /// bound is inclusive; the upper bound is exclusive. Fails when
+    /// the upper bound is not greater than the lower bound.
+    fn gen_biguint_range(&mut self, lbound: &BigUint, ubound: &BigUint) -> BigUint;
+
+    /// Generate a random `BigInt` within the given range. The lower
+    /// bound is inclusive; the upper bound is exclusive. Fails when
+    /// the upper bound is not greater than the lower bound.
+    fn gen_bigint_range(&mut self, lbound: &BigInt, ubound: &BigInt) -> BigInt;
+}
+
+#[cfg(any(feature = "rand", test))]
+impl<R: Rng> RandBigInt for R {
+    fn gen_biguint(&mut self, bit_size: usize) -> BigUint {
+        let (digits, rem) = bit_size.div_rem(&big_digit::BITS);
+        let mut data = Vec::with_capacity(digits + 1);
+        for _ in 0..digits {
+            data.push(self.gen());
+        }
+        if rem > 0 {
+            let final_digit: BigDigit = self.gen();
+            data.push(final_digit >> (big_digit::BITS - rem));
+        }
+        BigUint::new(data)
+    }
+
+    fn gen_bigint(&mut self, bit_size: usize) -> BigInt {
+        // Generate a random BigUint...
+        let biguint = self.gen_biguint(bit_size);
+        // ...and then randomly assign it a Sign...
+        let sign = if biguint.is_zero() {
+            // ...except that if the BigUint is zero, we need to try
+            // again with probability 0.5. This is because otherwise,
+            // the probability of generating a zero BigInt would be
+            // double that of any other number.
+            if self.gen() {
+                return self.gen_bigint(bit_size);
+            } else {
+                NoSign
+            }
+        } else if self.gen() {
+            Plus
+        } else {
+            Minus
+        };
+        BigInt::from_biguint(sign, biguint)
+    }
+
+    fn gen_biguint_below(&mut self, bound: &BigUint) -> BigUint {
+        assert!(!bound.is_zero());
+        let bits = bound.bits();
+        loop {
+            let n = self.gen_biguint(bits);
+            if n < *bound {
+                return n;
+            }
+        }
+    }
+
+    fn gen_biguint_range(&mut self, lbound: &BigUint, ubound: &BigUint) -> BigUint {
+        assert!(*lbound < *ubound);
+        return lbound + self.gen_biguint_below(&(ubound - lbound));
+    }
+
+    fn gen_bigint_range(&mut self, lbound: &BigInt, ubound: &BigInt) -> BigInt {
+        assert!(*lbound < *ubound);
+        let delta = (ubound - lbound).to_biguint().unwrap();
+        return lbound + self.gen_biguint_below(&delta).to_bigint().unwrap();
+    }
+}
+
+impl BigInt {
+    /// Creates and initializes a BigInt.
+    ///
+    /// The digits are in little-endian base 2<sup>32</sup>.
+    #[inline]
+    pub fn new(sign: Sign, digits: Vec<BigDigit>) -> BigInt {
+        BigInt::from_biguint(sign, BigUint::new(digits))
+    }
+
+    /// Creates and initializes a `BigInt`.
+    ///
+    /// The digits are in little-endian base 2<sup>32</sup>.
+    #[inline]
+    pub fn from_biguint(mut sign: Sign, mut data: BigUint) -> BigInt {
+        if sign == NoSign {
+            data.assign_from_slice(&[]);
+        } else if data.is_zero() {
+            sign = NoSign;
+        }
+
+        BigInt {
+            sign: sign,
+            data: data,
+        }
+    }
+
+    /// Creates and initializes a `BigInt`.
+    #[inline]
+    pub fn from_slice(sign: Sign, slice: &[BigDigit]) -> BigInt {
+        BigInt::from_biguint(sign, BigUint::from_slice(slice))
+    }
+
+    /// Reinitializes a `BigInt`.
+    #[inline]
+    pub fn assign_from_slice(&mut self, sign: Sign, slice: &[BigDigit]) {
+        if sign == NoSign {
+            self.data.assign_from_slice(&[]);
+            self.sign = NoSign;
+        } else {
+            self.data.assign_from_slice(slice);
+            self.sign = match self.data.is_zero() {
+                true => NoSign,
+                false => sign,
+            }
+        }
+    }
+
+    /// Creates and initializes a `BigInt`.
+    ///
+    /// The bytes are in big-endian byte order.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use num_bigint::{BigInt, Sign};
+    ///
+    /// assert_eq!(BigInt::from_bytes_be(Sign::Plus, b"A"),
+    ///            BigInt::parse_bytes(b"65", 10).unwrap());
+    /// assert_eq!(BigInt::from_bytes_be(Sign::Plus, b"AA"),
+    ///            BigInt::parse_bytes(b"16705", 10).unwrap());
+    /// assert_eq!(BigInt::from_bytes_be(Sign::Plus, b"AB"),
+    ///            BigInt::parse_bytes(b"16706", 10).unwrap());
+    /// assert_eq!(BigInt::from_bytes_be(Sign::Plus, b"Hello world!"),
+    ///            BigInt::parse_bytes(b"22405534230753963835153736737", 10).unwrap());
+    /// ```
+    #[inline]
+    pub fn from_bytes_be(sign: Sign, bytes: &[u8]) -> BigInt {
+        BigInt::from_biguint(sign, BigUint::from_bytes_be(bytes))
+    }
+
+    /// Creates and initializes a `BigInt`.
+    ///
+    /// The bytes are in little-endian byte order.
+    #[inline]
+    pub fn from_bytes_le(sign: Sign, bytes: &[u8]) -> BigInt {
+        BigInt::from_biguint(sign, BigUint::from_bytes_le(bytes))
+    }
+
+    /// Creates and initializes a `BigInt` from an array of bytes in
+    /// two's complement binary representation.
+    ///
+    /// The digits are in big-endian base 2<sup>8</sup>.
+    #[inline]
+    pub fn from_signed_bytes_be(digits: &[u8]) -> BigInt {
+        let sign = match digits.first() {
+            Some(v) if *v > 0x7f => Sign::Minus,
+            Some(_) => Sign::Plus,
+            None => return BigInt::zero(),
+        };
+
+        if sign == Sign::Minus {
+            // two's-complement the content to retrieve the magnitude
+            let mut digits = Vec::from(digits);
+            twos_complement_be(&mut digits);
+            BigInt::from_biguint(sign, BigUint::from_bytes_be(&*digits))
+        } else {
+            BigInt::from_biguint(sign, BigUint::from_bytes_be(digits))
+        }
+    }
+
+    /// Creates and initializes a `BigInt` from an array of bytes in two's complement.
+    ///
+    /// The digits are in little-endian base 2<sup>8</sup>.
+    #[inline]
+    pub fn from_signed_bytes_le(digits: &[u8]) -> BigInt {
+        let sign = match digits.last() {
+            Some(v) if *v > 0x7f => Sign::Minus,
+            Some(_) => Sign::Plus,
+            None => return BigInt::zero(),
+        };
+
+        if sign == Sign::Minus {
+            // two's-complement the content to retrieve the magnitude
+            let mut digits = Vec::from(digits);
+            twos_complement_le(&mut digits);
+            BigInt::from_biguint(sign, BigUint::from_bytes_le(&*digits))
+        } else {
+            BigInt::from_biguint(sign, BigUint::from_bytes_le(digits))
+        }
+    }
+
+    /// Creates and initializes a `BigInt`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use num_bigint::{BigInt, ToBigInt};
+    ///
+    /// assert_eq!(BigInt::parse_bytes(b"1234", 10), ToBigInt::to_bigint(&1234));
+    /// assert_eq!(BigInt::parse_bytes(b"ABCD", 16), ToBigInt::to_bigint(&0xABCD));
+    /// assert_eq!(BigInt::parse_bytes(b"G", 16), None);
+    /// ```
+    #[inline]
+    pub fn parse_bytes(buf: &[u8], radix: u32) -> Option<BigInt> {
+        str::from_utf8(buf).ok().and_then(|s| BigInt::from_str_radix(s, radix).ok())
+    }
+
+    /// Creates and initializes a `BigInt`. Each u8 of the input slice is
+    /// interpreted as one digit of the number
+    /// and must therefore be less than `radix`.
+    ///
+    /// The bytes are in big-endian byte order.
+    /// `radix` must be in the range `2...256`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use num_bigint::{BigInt, Sign};
+    ///
+    /// let inbase190 = vec![15, 33, 125, 12, 14];
+    /// let a = BigInt::from_radix_be(Sign::Minus, &inbase190, 190).unwrap();
+    /// assert_eq!(a.to_radix_be(190), (Sign:: Minus, inbase190));
+    /// ```
+    pub fn from_radix_be(sign: Sign, buf: &[u8], radix: u32) -> Option<BigInt> {
+        BigUint::from_radix_be(buf, radix).map(|u| BigInt::from_biguint(sign, u))
+    }
+
+    /// Creates and initializes a `BigInt`. Each u8 of the input slice is
+    /// interpreted as one digit of the number
+    /// and must therefore be less than `radix`.
+    ///
+    /// The bytes are in little-endian byte order.
+    /// `radix` must be in the range `2...256`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use num_bigint::{BigInt, Sign};
+    ///
+    /// let inbase190 = vec![14, 12, 125, 33, 15];
+    /// let a = BigInt::from_radix_be(Sign::Minus, &inbase190, 190).unwrap();
+    /// assert_eq!(a.to_radix_be(190), (Sign::Minus, inbase190));
+    /// ```
+    pub fn from_radix_le(sign: Sign, buf: &[u8], radix: u32) -> Option<BigInt> {
+        BigUint::from_radix_le(buf, radix).map(|u| BigInt::from_biguint(sign, u))
+    }
+
+    /// Returns the sign and the byte representation of the `BigInt` in big-endian byte order.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use num_bigint::{ToBigInt, Sign};
+    ///
+    /// let i = -1125.to_bigint().unwrap();
+    /// assert_eq!(i.to_bytes_be(), (Sign::Minus, vec![4, 101]));
+    /// ```
+    #[inline]
+    pub fn to_bytes_be(&self) -> (Sign, Vec<u8>) {
+        (self.sign, self.data.to_bytes_be())
+    }
+
+    /// Returns the sign and the byte representation of the `BigInt` in little-endian byte order.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use num_bigint::{ToBigInt, Sign};
+    ///
+    /// let i = -1125.to_bigint().unwrap();
+    /// assert_eq!(i.to_bytes_le(), (Sign::Minus, vec![101, 4]));
+    /// ```
+    #[inline]
+    pub fn to_bytes_le(&self) -> (Sign, Vec<u8>) {
+        (self.sign, self.data.to_bytes_le())
+    }
+
+    /// Returns the two's complement byte representation of the `BigInt` in big-endian byte order.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use num_bigint::ToBigInt;
+    ///
+    /// let i = -1125.to_bigint().unwrap();
+    /// assert_eq!(i.to_signed_bytes_be(), vec![251, 155]);
+    /// ```
+    #[inline]
+    pub fn to_signed_bytes_be(&self) -> Vec<u8> {
+        let mut bytes = self.data.to_bytes_be();
+        let first_byte = bytes.first().map(|v| *v).unwrap_or(0);
+        if first_byte > 0x7f && !(first_byte == 0x80 && bytes.iter().skip(1).all(Zero::is_zero)) {
+            // msb used by magnitude, extend by 1 byte
+            bytes.insert(0, 0);
+        }
+        if self.sign == Sign::Minus {
+            twos_complement_be(&mut bytes);
+        }
+        bytes
+    }
+
+    /// Returns the two's complement byte representation of the `BigInt` in little-endian byte order.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use num_bigint::ToBigInt;
+    ///
+    /// let i = -1125.to_bigint().unwrap();
+    /// assert_eq!(i.to_signed_bytes_le(), vec![155, 251]);
+    /// ```
+    #[inline]
+    pub fn to_signed_bytes_le(&self) -> Vec<u8> {
+        let mut bytes = self.data.to_bytes_le();
+        let last_byte = bytes.last().map(|v| *v).unwrap_or(0);
+        if last_byte > 0x7f && !(last_byte == 0x80 && bytes.iter().rev().skip(1).all(Zero::is_zero)) {
+            // msb used by magnitude, extend by 1 byte
+            bytes.push(0);
+        }
+        if self.sign == Sign::Minus {
+            twos_complement_le(&mut bytes);
+        }
+        bytes
+    }
+
+    /// Returns the integer formatted as a string in the given radix.
+    /// `radix` must be in the range `2...36`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use num_bigint::BigInt;
+    ///
+    /// let i = BigInt::parse_bytes(b"ff", 16).unwrap();
+    /// assert_eq!(i.to_str_radix(16), "ff");
+    /// ```
+    #[inline]
+    pub fn to_str_radix(&self, radix: u32) -> String {
+        let mut v = to_str_radix_reversed(&self.data, radix);
+
+        if self.is_negative() {
+            v.push(b'-');
+        }
+
+        v.reverse();
+        unsafe { String::from_utf8_unchecked(v) }
+    }
+
+    /// Returns the integer in the requested base in big-endian digit order.
+    /// The output is not given in a human readable alphabet but as a zero
+    /// based u8 number.
+    /// `radix` must be in the range `2...256`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use num_bigint::{BigInt, Sign};
+    ///
+    /// assert_eq!(BigInt::from(-0xFFFFi64).to_radix_be(159),
+    ///            (Sign::Minus, vec![2, 94, 27]));
+    /// // 0xFFFF = 65535 = 2*(159^2) + 94*159 + 27
+    /// ```
+    #[inline]
+    pub fn to_radix_be(&self, radix: u32) -> (Sign, Vec<u8>) {
+        (self.sign, self.data.to_radix_be(radix))
+    }
+
+    /// Returns the integer in the requested base in little-endian digit order.
+    /// The output is not given in a human readable alphabet but as a zero
+    /// based u8 number.
+    /// `radix` must be in the range `2...256`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use num_bigint::{BigInt, Sign};
+    ///
+    /// assert_eq!(BigInt::from(-0xFFFFi64).to_radix_le(159),
+    ///            (Sign::Minus, vec![27, 94, 2]));
+    /// // 0xFFFF = 65535 = 27 + 94*159 + 2*(159^2)
+    /// ```
+    #[inline]
+    pub fn to_radix_le(&self, radix: u32) -> (Sign, Vec<u8>) {
+        (self.sign, self.data.to_radix_le(radix))
+    }
+
+    /// Returns the sign of the `BigInt` as a `Sign`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use num_bigint::{ToBigInt, Sign};
+    ///
+    /// assert_eq!(ToBigInt::to_bigint(&1234).unwrap().sign(), Sign::Plus);
+    /// assert_eq!(ToBigInt::to_bigint(&-4321).unwrap().sign(), Sign::Minus);
+    /// assert_eq!(ToBigInt::to_bigint(&0).unwrap().sign(), Sign::NoSign);
+    /// ```
+    #[inline]
+    pub fn sign(&self) -> Sign {
+        self.sign
+    }
+
+    /// Determines the fewest bits necessary to express the `BigInt`,
+    /// not including the sign.
+    #[inline]
+    pub fn bits(&self) -> usize {
+        self.data.bits()
+    }
+
+    /// Converts this `BigInt` into a `BigUint`, if it's not negative.
+    #[inline]
+    pub fn to_biguint(&self) -> Option<BigUint> {
+        match self.sign {
+            Plus => Some(self.data.clone()),
+            NoSign => Some(Zero::zero()),
+            Minus => None,
+        }
+    }
+
+    #[inline]
+    pub fn checked_add(&self, v: &BigInt) -> Option<BigInt> {
+        return Some(self.add(v));
+    }
+
+    #[inline]
+    pub fn checked_sub(&self, v: &BigInt) -> Option<BigInt> {
+        return Some(self.sub(v));
+    }
+
+    #[inline]
+    pub fn checked_mul(&self, v: &BigInt) -> Option<BigInt> {
+        return Some(self.mul(v));
+    }
+
+    #[inline]
+    pub fn checked_div(&self, v: &BigInt) -> Option<BigInt> {
+        if v.is_zero() {
+            return None;
+        }
+        return Some(self.div(v));
+    }
+
+    /// Returns `(self ^ exponent) mod modulus`
+    ///
+    /// Note that this rounds like `mod_floor`, not like the `%` operator,
+    /// which makes a difference when given a negative `self` or `modulus`.
+    /// The result will be in the interval `[0, modulus)` for `modulus > 0`,
+    /// or in the interval `(modulus, 0]` for `modulus < 0`
+    ///
+    /// Panics if the exponent is negative or the modulus is zero.
+    pub fn modpow(&self, exponent: &Self, modulus: &Self) -> Self {
+        assert!(!exponent.is_negative(), "negative exponentiation is not supported!");
+        assert!(!modulus.is_zero(), "divide by zero!");
+
+        let result = self.data.modpow(&exponent.data, &modulus.data);
+        if result.is_zero() {
+            return BigInt::zero();
+        }
+
+        // The sign of the result follows the modulus, like `mod_floor`.
+        let (sign, mag) = match (self.is_negative(), modulus.is_negative()) {
+            (false, false) => (Plus, result),
+            (true, false) => (Plus, &modulus.data - result),
+            (false, true) => (Minus, &modulus.data - result),
+            (true, true) => (Minus, result),
+        };
+        BigInt::from_biguint(sign, mag)
+    }
+}
+
+/// Perform in-place two's complement of the given binary representation,
+/// in little-endian byte order.
+#[inline]
+fn twos_complement_le(digits: &mut [u8]) {
+    twos_complement(digits)
+}
+
+/// Perform in-place two's complement of the given binary representation
+/// in big-endian byte order.
+#[inline]
+fn twos_complement_be(digits: &mut [u8]) {
+    twos_complement(digits.iter_mut().rev())
+}
+
+/// Perform in-place two's complement of the given digit iterator
+/// starting from the least significant byte.
+#[inline]
+fn twos_complement<'a, I>(digits: I)
+    where I: IntoIterator<Item = &'a mut u8>
+{
+    let mut carry = true;
+    for d in digits {
+        *d = d.not();
+        if carry {
+            *d = d.wrapping_add(1);
+            carry = d.is_zero();
+        }
+    }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/num-bigint/src/biguint.rs
@@ -0,0 +1,2275 @@
+use std::borrow::Cow;
+use std::default::Default;
+use std::iter::repeat;
+use std::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Rem, Shl, Shr, Sub,
+               AddAssign, BitAndAssign, BitOrAssign, BitXorAssign, DivAssign,
+               MulAssign, RemAssign, ShlAssign, ShrAssign, SubAssign};
+use std::str::{self, FromStr};
+use std::fmt;
+use std::cmp;
+use std::mem;
+use std::cmp::Ordering::{self, Less, Greater, Equal};
+use std::{f32, f64};
+use std::{u8, u64};
+#[allow(unused_imports)]
+use std::ascii::AsciiExt;
+
+#[cfg(feature = "serde")]
+use serde;
+
+use integer::Integer;
+use traits::{ToPrimitive, FromPrimitive, Float, Num, Unsigned, CheckedAdd, CheckedSub, CheckedMul,
+             CheckedDiv, Zero, One};
+
+#[path = "algorithms.rs"]
+mod algorithms;
+#[path = "monty.rs"]
+mod monty;
+pub use self::algorithms::big_digit;
+pub use self::big_digit::{BigDigit, DoubleBigDigit, ZERO_BIG_DIGIT};
+
+use self::algorithms::{mac_with_carry, mul3, scalar_mul, div_rem, div_rem_digit};
+use self::algorithms::{__add2, add2, sub2, sub2rev};
+use self::algorithms::{biguint_shl, biguint_shr};
+use self::algorithms::{cmp_slice, fls, ilog2};
+use self::monty::monty_modpow;
+
+use UsizePromotion;
+
+use ParseBigIntError;
+
+#[cfg(test)]
+#[path = "tests/biguint.rs"]
+mod biguint_tests;
+
+/// A big unsigned integer type.
+///
+/// A `BigUint`-typed value `BigUint { data: vec!(a, b, c) }` represents a number
+/// `(a + b * big_digit::BASE + c * big_digit::BASE^2)`.
+#[derive(Clone, Debug, Hash)]
+#[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))]
+pub struct BigUint {
+    data: Vec<BigDigit>,
+}
+
+impl PartialEq for BigUint {
+    #[inline]
+    fn eq(&self, other: &BigUint) -> bool {
+        match self.cmp(other) {
+            Equal => true,
+            _ => false,
+        }
+    }
+}
+impl Eq for BigUint {}
+
+impl PartialOrd for BigUint {
+    #[inline]
+    fn partial_cmp(&self, other: &BigUint) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+impl Ord for BigUint {
+    #[inline]
+    fn cmp(&self, other: &BigUint) -> Ordering {
+        cmp_slice(&self.data[..], &other.data[..])
+    }
+}
+
+impl Default for BigUint {
+    #[inline]
+    fn default() -> BigUint {
+        Zero::zero()
+    }
+}
+
+impl fmt::Display for BigUint {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.pad_integral(true, "", &self.to_str_radix(10))
+    }
+}
+
+impl fmt::LowerHex for BigUint {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.pad_integral(true, "0x", &self.to_str_radix(16))
+    }
+}
+
+impl fmt::UpperHex for BigUint {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.pad_integral(true, "0x", &self.to_str_radix(16).to_ascii_uppercase())
+    }
+}
+
+impl fmt::Binary for BigUint {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.pad_integral(true, "0b", &self.to_str_radix(2))
+    }
+}
+
+impl fmt::Octal for BigUint {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.pad_integral(true, "0o", &self.to_str_radix(8))
+    }
+}
+
+impl FromStr for BigUint {
+    type Err = ParseBigIntError;
+
+    #[inline]
+    fn from_str(s: &str) -> Result<BigUint, ParseBigIntError> {
+        BigUint::from_str_radix(s, 10)
+    }
+}
+
+// Convert from a power of two radix (bits == ilog2(radix)) where bits evenly divides
+// BigDigit::BITS
+fn from_bitwise_digits_le(v: &[u8], bits: usize) -> BigUint {
+    debug_assert!(!v.is_empty() && bits <= 8 && big_digit::BITS % bits == 0);
+    debug_assert!(v.iter().all(|&c| (c as BigDigit) < (1 << bits)));
+
+    let digits_per_big_digit = big_digit::BITS / bits;
+
+    let data = v.chunks(digits_per_big_digit)
+                .map(|chunk| {
+                    chunk.iter().rev().fold(0, |acc, &c| (acc << bits) | c as BigDigit)
+                })
+                .collect();
+
+    BigUint::new(data)
+}
+
+// Convert from a power of two radix (bits == ilog2(radix)) where bits doesn't evenly divide
+// BigDigit::BITS
+fn from_inexact_bitwise_digits_le(v: &[u8], bits: usize) -> BigUint {
+    debug_assert!(!v.is_empty() && bits <= 8 && big_digit::BITS % bits != 0);
+    debug_assert!(v.iter().all(|&c| (c as BigDigit) < (1 << bits)));
+
+    let big_digits = (v.len() * bits + big_digit::BITS - 1) / big_digit::BITS;
+    let mut data = Vec::with_capacity(big_digits);
+
+    let mut d = 0;
+    let mut dbits = 0; // number of bits we currently have in d
+
+    // walk v accumululating bits in d; whenever we accumulate big_digit::BITS in d, spit out a
+    // big_digit:
+    for &c in v {
+        d |= (c as BigDigit) << dbits;
+        dbits += bits;
+
+        if dbits >= big_digit::BITS {
+            data.push(d);
+            dbits -= big_digit::BITS;
+            // if dbits was > big_digit::BITS, we dropped some of the bits in c (they couldn't fit
+            // in d) - grab the bits we lost here:
+            d = (c as BigDigit) >> (bits - dbits);
+        }
+    }
+
+    if dbits > 0 {
+        debug_assert!(dbits < big_digit::BITS);
+        data.push(d as BigDigit);
+    }
+
+    BigUint::new(data)
+}
+
+// Read little-endian radix digits
+fn from_radix_digits_be(v: &[u8], radix: u32) -> BigUint {
+    debug_assert!(!v.is_empty() && !radix.is_power_of_two());
+    debug_assert!(v.iter().all(|&c| (c as u32) < radix));
+
+    // Estimate how big the result will be, so we can pre-allocate it.
+    let bits = (radix as f64).log2() * v.len() as f64;
+    let big_digits = (bits / big_digit::BITS as f64).ceil();
+    let mut data = Vec::with_capacity(big_digits as usize);
+
+    let (base, power) = get_radix_base(radix);
+    let radix = radix as BigDigit;
+
+    let r = v.len() % power;
+    let i = if r == 0 {
+        power
+    } else {
+        r
+    };
+    let (head, tail) = v.split_at(i);
+
+    let first = head.iter().fold(0, |acc, &d| acc * radix + d as BigDigit);
+    data.push(first);
+
+    debug_assert!(tail.len() % power == 0);
+    for chunk in tail.chunks(power) {
+        if data.last() != Some(&0) {
+            data.push(0);
+        }
+
+        let mut carry = 0;
+        for d in data.iter_mut() {
+            *d = mac_with_carry(0, *d, base, &mut carry);
+        }
+        debug_assert!(carry == 0);
+
+        let n = chunk.iter().fold(0, |acc, &d| acc * radix + d as BigDigit);
+        add2(&mut data, &[n]);
+    }
+
+    BigUint::new(data)
+}
+
+impl Num for BigUint {
+    type FromStrRadixErr = ParseBigIntError;
+
+    /// Creates and initializes a `BigUint`.
+    fn from_str_radix(s: &str, radix: u32) -> Result<BigUint, ParseBigIntError> {
+        assert!(2 <= radix && radix <= 36, "The radix must be within 2...36");
+        let mut s = s;
+        if s.starts_with('+') {
+            let tail = &s[1..];
+            if !tail.starts_with('+') {
+                s = tail
+            }
+        }
+
+        if s.is_empty() {
+            // create ParseIntError::Empty
+            let e = u64::from_str_radix(s, radix).unwrap_err();
+            return Err(e.into());
+        }
+
+        if s.starts_with('_') {
+            // Must lead with a real digit!
+            // create ParseIntError::InvalidDigit
+            let e = u64::from_str_radix(s, radix).unwrap_err();
+            return Err(e.into());
+        }
+
+        // First normalize all characters to plain digit values
+        let mut v = Vec::with_capacity(s.len());
+        for b in s.bytes() {
+            let d = match b {
+                b'0'...b'9' => b - b'0',
+                b'a'...b'z' => b - b'a' + 10,
+                b'A'...b'Z' => b - b'A' + 10,
+                b'_' => continue,
+                _ => u8::MAX,
+            };
+            if d < radix as u8 {
+                v.push(d);
+            } else {
+                // create ParseIntError::InvalidDigit
+                // Include the previous character for context.
+                let i = cmp::max(v.len(), 1) - 1;
+                let e = u64::from_str_radix(&s[i..], radix).unwrap_err();
+                return Err(e.into());
+            }
+        }
+
+        let res = if radix.is_power_of_two() {
+            // Powers of two can use bitwise masks and shifting instead of multiplication
+            let bits = ilog2(radix);
+            v.reverse();
+            if big_digit::BITS % bits == 0 {
+                from_bitwise_digits_le(&v, bits)
+            } else {
+                from_inexact_bitwise_digits_le(&v, bits)
+            }
+        } else {
+            from_radix_digits_be(&v, radix)
+        };
+        Ok(res)
+    }
+}
+
+forward_all_binop_to_val_ref_commutative!(impl BitAnd for BigUint, bitand);
+forward_val_assign!(impl BitAndAssign for BigUint, bitand_assign);
+
+impl<'a> BitAnd<&'a BigUint> for BigUint {
+    type Output = BigUint;
+
+    #[inline]
+    fn bitand(mut self, other: &BigUint) -> BigUint {
+        self &= other;
+        self
+    }
+}
+impl<'a> BitAndAssign<&'a BigUint> for BigUint {
+    #[inline]
+    fn bitand_assign(&mut self, other: &BigUint) {
+        for (ai, &bi) in self.data.iter_mut().zip(other.data.iter()) {
+            *ai &= bi;
+        }
+        self.data.truncate(other.data.len());
+        self.normalize();
+    }
+}
+
+forward_all_binop_to_val_ref_commutative!(impl BitOr for BigUint, bitor);
+forward_val_assign!(impl BitOrAssign for BigUint, bitor_assign);
+
+impl<'a> BitOr<&'a BigUint> for BigUint {
+    type Output = BigUint;
+
+    fn bitor(mut self, other: &BigUint) -> BigUint {
+        self |= other;
+        self
+    }
+}
+impl<'a> BitOrAssign<&'a BigUint> for BigUint {
+    #[inline]
+    fn bitor_assign(&mut self, other: &BigUint) {
+        for (ai, &bi) in self.data.iter_mut().zip(other.data.iter()) {
+            *ai |= bi;
+        }
+        if other.data.len() > self.data.len() {
+            let extra = &other.data[self.data.len()..];
+            self.data.extend(extra.iter().cloned());
+        }
+    }
+}
+
+forward_all_binop_to_val_ref_commutative!(impl BitXor for BigUint, bitxor);
+forward_val_assign!(impl BitXorAssign for BigUint, bitxor_assign);
+
+impl<'a> BitXor<&'a BigUint> for BigUint {
+    type Output = BigUint;
+
+    fn bitxor(mut self, other: &BigUint) -> BigUint {
+        self ^= other;
+        self
+    }
+}
+impl<'a> BitXorAssign<&'a BigUint> for BigUint {
+    #[inline]
+    fn bitxor_assign(&mut self, other: &BigUint) {
+        for (ai, &bi) in self.data.iter_mut().zip(other.data.iter()) {
+            *ai ^= bi;
+        }
+        if other.data.len() > self.data.len() {
+            let extra = &other.data[self.data.len()..];
+            self.data.extend(extra.iter().cloned());
+        }
+        self.normalize();
+    }
+}
+
+impl Shl<usize> for BigUint {
+    type Output = BigUint;
+
+    #[inline]
+    fn shl(self, rhs: usize) -> BigUint {
+        biguint_shl(Cow::Owned(self), rhs)
+    }
+}
+impl<'a> Shl<usize> for &'a BigUint {
+    type Output = BigUint;
+
+    #[inline]
+    fn shl(self, rhs: usize) -> BigUint {
+        biguint_shl(Cow::Borrowed(self), rhs)
+    }
+}
+
+impl ShlAssign<usize> for BigUint {
+    #[inline]
+    fn shl_assign(&mut self, rhs: usize) {
+        *self = biguint_shl(Cow::Borrowed(&*self), rhs);
+    }
+}
+
+impl Shr<usize> for BigUint {
+    type Output = BigUint;
+
+    #[inline]
+    fn shr(self, rhs: usize) -> BigUint {
+        biguint_shr(Cow::Owned(self), rhs)
+    }
+}
+impl<'a> Shr<usize> for &'a BigUint {
+    type Output = BigUint;
+
+    #[inline]
+    fn shr(self, rhs: usize) -> BigUint {
+        biguint_shr(Cow::Borrowed(self), rhs)
+    }
+}
+
+impl ShrAssign<usize> for BigUint {
+    #[inline]
+    fn shr_assign(&mut self, rhs: usize) {
+        let n = mem::replace(self, BigUint::zero());
+        *self = n >> rhs;
+    }
+}
+
+impl Zero for BigUint {
+    #[inline]
+    fn zero() -> BigUint {
+        BigUint::new(Vec::new())
+    }
+
+    #[inline]
+    fn is_zero(&self) -> bool {
+        self.data.is_empty()
+    }
+}
+
+impl One for BigUint {
+    #[inline]
+    fn one() -> BigUint {
+        BigUint::new(vec![1])
+    }
+}
+
+impl Unsigned for BigUint {}
+
+forward_all_binop_to_val_ref_commutative!(impl Add for BigUint, add);
+forward_val_assign!(impl AddAssign for BigUint, add_assign);
+
+impl<'a> Add<&'a BigUint> for BigUint {
+    type Output = BigUint;
+
+    fn add(mut self, other: &BigUint) -> BigUint {
+        self += other;
+        self
+    }
+}
+impl<'a> AddAssign<&'a BigUint> for BigUint {
+    #[inline]
+    fn add_assign(&mut self, other: &BigUint) {
+        if self.data.len() < other.data.len() {
+            let extra = other.data.len() - self.data.len();
+            self.data.extend(repeat(0).take(extra));
+        }
+
+        let carry = __add2(&mut self.data[..], &other.data[..]);
+        if carry != 0 {
+            self.data.push(carry);
+        }
+    }
+}
+
+promote_unsigned_scalars!(impl Add for BigUint, add);
+promote_unsigned_scalars_assign!(impl AddAssign for BigUint, add_assign);
+forward_all_scalar_binop_to_val_val_commutative!(impl Add<BigDigit> for BigUint, add);
+forward_all_scalar_binop_to_val_val_commutative!(impl Add<DoubleBigDigit> for BigUint, add);
+
+impl Add<BigDigit> for BigUint {
+    type Output = BigUint;
+
+    #[inline]
+    fn add(mut self, other: BigDigit) -> BigUint {
+        self += other;
+        self
+    }
+}
+impl AddAssign<BigDigit> for BigUint {
+    #[inline]
+    fn add_assign(&mut self, other: BigDigit) {
+        if other != 0 {
+            if self.data.len() == 0 {
+                self.data.push(0);
+            }
+
+            let carry = __add2(&mut self.data, &[other]);
+            if carry != 0 {
+                self.data.push(carry);
+            }
+        }
+    }
+}
+
+impl Add<DoubleBigDigit> for BigUint {
+    type Output = BigUint;
+
+    #[inline]
+    fn add(mut self, other: DoubleBigDigit) -> BigUint {
+        self += other;
+        self
+    }
+}
+impl AddAssign<DoubleBigDigit> for BigUint {
+    #[inline]
+    fn add_assign(&mut self, other: DoubleBigDigit) {
+        let (hi, lo) = big_digit::from_doublebigdigit(other);
+        if hi == 0 {
+            *self += lo;
+        } else {
+            while self.data.len() < 2 {
+                self.data.push(0);
+            }
+
+            let carry = __add2(&mut self.data, &[lo, hi]);
+            if carry != 0 {
+                self.data.push(carry);
+            }
+        }
+    }
+}
+
+forward_val_val_binop!(impl Sub for BigUint, sub);
+forward_ref_ref_binop!(impl Sub for BigUint, sub);
+forward_val_assign!(impl SubAssign for BigUint, sub_assign);
+
+impl<'a> Sub<&'a BigUint> for BigUint {
+    type Output = BigUint;
+
+    fn sub(mut self, other: &BigUint) -> BigUint {
+        self -= other;
+        self
+    }
+}
+impl<'a> SubAssign<&'a BigUint> for BigUint {
+    fn sub_assign(&mut self, other: &'a BigUint) {
+        sub2(&mut self.data[..], &other.data[..]);
+        self.normalize();
+    }
+}
+
+impl<'a> Sub<BigUint> for &'a BigUint {
+    type Output = BigUint;
+
+    fn sub(self, mut other: BigUint) -> BigUint {
+        if other.data.len() < self.data.len() {
+            let extra = self.data.len() - other.data.len();
+            other.data.extend(repeat(0).take(extra));
+        }
+
+        sub2rev(&self.data[..], &mut other.data[..]);
+        other.normalized()
+    }
+}
+
+promote_unsigned_scalars!(impl Sub for BigUint, sub);
+promote_unsigned_scalars_assign!(impl SubAssign for BigUint, sub_assign);
+forward_all_scalar_binop_to_val_val!(impl Sub<BigDigit> for BigUint, sub);
+forward_all_scalar_binop_to_val_val!(impl Sub<DoubleBigDigit> for BigUint, sub);
+
+impl Sub<BigDigit> for BigUint {
+    type Output = BigUint;
+
+    #[inline]
+    fn sub(mut self, other: BigDigit) -> BigUint {
+        self -= other;
+        self
+    }
+}
+impl SubAssign<BigDigit> for BigUint {
+    fn sub_assign(&mut self, other: BigDigit) {
+        sub2(&mut self.data[..], &[other]);
+        self.normalize();
+    }
+}
+
+impl Sub<BigUint> for BigDigit {
+    type Output = BigUint;
+
+    #[inline]
+    fn sub(self, mut other: BigUint) -> BigUint {
+        if other.data.len() == 0 {
+            other.data.push(0);
+        }
+
+        sub2rev(&[self], &mut other.data[..]);
+        other.normalized()
+    }
+}
+
+impl Sub<DoubleBigDigit> for BigUint {
+    type Output = BigUint;
+
+    #[inline]
+    fn sub(mut self, other: DoubleBigDigit) -> BigUint {
+        self -= other;
+        self
+    }
+}
+impl SubAssign<DoubleBigDigit> for BigUint {
+    fn sub_assign(&mut self, other: DoubleBigDigit) {
+        let (hi, lo) = big_digit::from_doublebigdigit(other);
+        sub2(&mut self.data[..], &[lo, hi]);
+        self.normalize();
+    }
+}
+
+impl Sub<BigUint> for DoubleBigDigit {
+    type Output = BigUint;
+
+    #[inline]
+    fn sub(self, mut other: BigUint) -> BigUint {
+        while other.data.len() < 2 {
+            other.data.push(0);
+        }
+
+        let (hi, lo) = big_digit::from_doublebigdigit(self);
+        sub2rev(&[lo, hi], &mut other.data[..]);
+        other.normalized()
+    }
+}
+
+forward_all_binop_to_ref_ref!(impl Mul for BigUint, mul);
+forward_val_assign!(impl MulAssign for BigUint, mul_assign);
+
+impl<'a, 'b> Mul<&'b BigUint> for &'a BigUint {
+    type Output = BigUint;
+
+    #[inline]
+    fn mul(self, other: &BigUint) -> BigUint {
+        mul3(&self.data[..], &other.data[..])
+    }
+}
+impl<'a> MulAssign<&'a BigUint> for BigUint {
+    #[inline]
+    fn mul_assign(&mut self, other: &'a BigUint) {
+        *self = &*self * other
+    }
+}
+
+promote_unsigned_scalars!(impl Mul for BigUint, mul);
+promote_unsigned_scalars_assign!(impl MulAssign for BigUint, mul_assign);
+forward_all_scalar_binop_to_val_val_commutative!(impl Mul<BigDigit> for BigUint, mul);
+forward_all_scalar_binop_to_val_val_commutative!(impl Mul<DoubleBigDigit> for BigUint, mul);
+
+impl Mul<BigDigit> for BigUint {
+    type Output = BigUint;
+
+    #[inline]
+    fn mul(mut self, other: BigDigit) -> BigUint {
+        self *= other;
+        self
+    }
+}
+impl MulAssign<BigDigit> for BigUint {
+    #[inline]
+    fn mul_assign(&mut self, other: BigDigit) {
+        if other == 0 {
+            self.data.clear();
+        } else {
+            let carry = scalar_mul(&mut self.data[..], other);
+            if carry != 0 {
+                self.data.push(carry);
+            }
+        }
+    }
+}
+
+impl Mul<DoubleBigDigit> for BigUint {
+    type Output = BigUint;
+
+    #[inline]
+    fn mul(mut self, other: DoubleBigDigit) -> BigUint {
+        self *= other;
+        self
+    }
+}
+impl MulAssign<DoubleBigDigit> for BigUint {
+    #[inline]
+    fn mul_assign(&mut self, other: DoubleBigDigit) {
+        if other == 0 {
+            self.data.clear();
+        } else if other <= BigDigit::max_value() as DoubleBigDigit {
+            *self *= other as BigDigit
+        } else {
+            let (hi, lo) = big_digit::from_doublebigdigit(other);
+            *self = mul3(&self.data[..], &[lo, hi])
+        }
+    }
+}
+
+forward_all_binop_to_ref_ref!(impl Div for BigUint, div);
+forward_val_assign!(impl DivAssign for BigUint, div_assign);
+
+impl<'a, 'b> Div<&'b BigUint> for &'a BigUint {
+    type Output = BigUint;
+
+    #[inline]
+    fn div(self, other: &BigUint) -> BigUint {
+        let (q, _) = self.div_rem(other);
+        q
+    }
+}
+impl<'a> DivAssign<&'a BigUint> for BigUint {
+    #[inline]
+    fn div_assign(&mut self, other: &'a BigUint) {
+        *self = &*self / other;
+    }
+}
+
+promote_unsigned_scalars!(impl Div for BigUint, div);
+promote_unsigned_scalars_assign!(impl DivAssign for BigUint, div_assign);
+forward_all_scalar_binop_to_val_val!(impl Div<BigDigit> for BigUint, div);
+forward_all_scalar_binop_to_val_val!(impl Div<DoubleBigDigit> for BigUint, div);
+
+impl Div<BigDigit> for BigUint {
+    type Output = BigUint;
+
+    #[inline]
+    fn div(self, other: BigDigit) -> BigUint {
+        let (q, _) = div_rem_digit(self, other);
+        q
+    }
+}
+impl DivAssign<BigDigit> for BigUint {
+    #[inline]
+    fn div_assign(&mut self, other: BigDigit) {
+        *self = &*self / other;
+    }
+}
+
+impl Div<BigUint> for BigDigit {
+    type Output = BigUint;
+
+    #[inline]
+    fn div(self, other: BigUint) -> BigUint {
+        match other.data.len() {
+            0 => panic!(),
+            1 => From::from(self / other.data[0]),
+            _ => Zero::zero(),
+        }
+    }
+}
+
+impl Div<DoubleBigDigit> for BigUint {
+    type Output = BigUint;
+
+    #[inline]
+    fn div(self, other: DoubleBigDigit) -> BigUint {
+        let (q, _) = self.div_rem(&From::from(other));
+        q
+    }
+}
+impl DivAssign<DoubleBigDigit> for BigUint {
+    #[inline]
+    fn div_assign(&mut self, other: DoubleBigDigit) {
+        *self = &*self / other;
+    }
+}
+
+impl Div<BigUint> for DoubleBigDigit {
+    type Output = BigUint;
+
+    #[inline]
+    fn div(self, other: BigUint) -> BigUint {
+        match other.data.len() {
+            0 => panic!(),
+            1 => From::from(self / other.data[0] as u64),
+            2 => From::from(self / big_digit::to_doublebigdigit(other.data[1], other.data[0])),
+            _ => Zero::zero(),
+        }
+    }
+}
+
+forward_all_binop_to_ref_ref!(impl Rem for BigUint, rem);
+forward_val_assign!(impl RemAssign for BigUint, rem_assign);
+
+impl<'a, 'b> Rem<&'b BigUint> for &'a BigUint {
+    type Output = BigUint;
+
+    #[inline]
+    fn rem(self, other: &BigUint) -> BigUint {
+        let (_, r) = self.div_rem(other);
+        r
+    }
+}
+impl<'a> RemAssign<&'a BigUint> for BigUint {
+    #[inline]
+    fn rem_assign(&mut self, other: &BigUint) {
+        *self = &*self % other;
+    }
+}
+
+promote_unsigned_scalars!(impl Rem for BigUint, rem);
+promote_unsigned_scalars_assign!(impl RemAssign for BigUint, rem_assign);
+forward_all_scalar_binop_to_val_val!(impl Rem<BigDigit> for BigUint, rem);
+forward_all_scalar_binop_to_val_val!(impl Rem<DoubleBigDigit> for BigUint, rem);
+
+impl Rem<BigDigit> for BigUint {
+    type Output = BigUint;
+
+    #[inline]
+    fn rem(self, other: BigDigit) -> BigUint {
+        let (_, r) = div_rem_digit(self, other);
+        From::from(r)
+    }
+}
+impl RemAssign<BigDigit> for BigUint {
+    #[inline]
+    fn rem_assign(&mut self, other: BigDigit) {
+        *self = &*self % other;
+    }
+}
+
+impl Rem<BigUint> for BigDigit {
+    type Output = BigUint;
+
+    #[inline]
+    fn rem(mut self, other: BigUint) -> BigUint {
+        self %= other;
+        From::from(self)
+    }
+}
+
+macro_rules! impl_rem_assign_scalar {
+    ($scalar:ty, $to_scalar:ident) => {
+        forward_val_assign_scalar!(impl RemAssign for BigUint, $scalar, rem_assign);
+        impl<'a> RemAssign<&'a BigUint> for $scalar {
+            #[inline]
+            fn rem_assign(&mut self, other: &BigUint) {
+                *self = match other.$to_scalar() {
+                    None => *self,
+                    Some(0) => panic!(),
+                    Some(v) => *self % v
+                };
+            }
+        }
+    }
+}
+// we can scalar %= BigUint for any scalar, including signed types
+impl_rem_assign_scalar!(usize, to_usize);
+impl_rem_assign_scalar!(u64, to_u64);
+impl_rem_assign_scalar!(u32, to_u32);
+impl_rem_assign_scalar!(u16, to_u16);
+impl_rem_assign_scalar!(u8, to_u8);
+impl_rem_assign_scalar!(isize, to_isize);
+impl_rem_assign_scalar!(i64, to_i64);
+impl_rem_assign_scalar!(i32, to_i32);
+impl_rem_assign_scalar!(i16, to_i16);
+impl_rem_assign_scalar!(i8, to_i8);
+
+impl Rem<DoubleBigDigit> for BigUint {
+    type Output = BigUint;
+
+    #[inline]
+    fn rem(self, other: DoubleBigDigit) -> BigUint {
+        let (_, r) = self.div_rem(&From::from(other));
+        r
+    }
+}
+impl RemAssign<DoubleBigDigit> for BigUint {
+    #[inline]
+    fn rem_assign(&mut self, other: DoubleBigDigit) {
+        *self = &*self % other;
+    }
+}
+
+impl Rem<BigUint> for DoubleBigDigit {
+    type Output = BigUint;
+
+    #[inline]
+    fn rem(mut self, other: BigUint) -> BigUint {
+        self %= other;
+        From::from(self)
+    }
+}
+
+impl Neg for BigUint {
+    type Output = BigUint;
+
+    #[inline]
+    fn neg(self) -> BigUint {
+        panic!()
+    }
+}
+
+impl<'a> Neg for &'a BigUint {
+    type Output = BigUint;
+
+    #[inline]
+    fn neg(self) -> BigUint {
+        panic!()
+    }
+}
+
+impl CheckedAdd for BigUint {
+    #[inline]
+    fn checked_add(&self, v: &BigUint) -> Option<BigUint> {
+        return Some(self.add(v));
+    }
+}
+
+impl CheckedSub for BigUint {
+    #[inline]
+    fn checked_sub(&self, v: &BigUint) -> Option<BigUint> {
+        match self.cmp(v) {
+            Less => None,
+            Equal => Some(Zero::zero()),
+            Greater => Some(self.sub(v)),
+        }
+    }
+}
+
+impl CheckedMul for BigUint {
+    #[inline]
+    fn checked_mul(&self, v: &BigUint) -> Option<BigUint> {
+        return Some(self.mul(v));
+    }
+}
+
+impl CheckedDiv for BigUint {
+    #[inline]
+    fn checked_div(&self, v: &BigUint) -> Option<BigUint> {
+        if v.is_zero() {
+            return None;
+        }
+        return Some(self.div(v));
+    }
+}
+
+impl Integer for BigUint {
+    #[inline]
+    fn div_rem(&self, other: &BigUint) -> (BigUint, BigUint) {
+        div_rem(self, other)
+    }
+
+    #[inline]
+    fn div_floor(&self, other: &BigUint) -> BigUint {
+        let (d, _) = div_rem(self, other);
+        d
+    }
+
+    #[inline]
+    fn mod_floor(&self, other: &BigUint) -> BigUint {
+        let (_, m) = div_rem(self, other);
+        m
+    }
+
+    #[inline]
+    fn div_mod_floor(&self, other: &BigUint) -> (BigUint, BigUint) {
+        div_rem(self, other)
+    }
+
+    /// Calculates the Greatest Common Divisor (GCD) of the number and `other`.
+    ///
+    /// The result is always positive.
+    #[inline]
+    fn gcd(&self, other: &Self) -> Self {
+        // Stein's algorithm
+        if self.is_zero() {
+            return other.clone();
+        }
+        if other.is_zero() {
+            return self.clone();
+        }
+        let mut m = self.clone();
+        let mut n = other.clone();
+
+        // find common factors of 2
+        let shift = cmp::min(
+            n.trailing_zeros(),
+            m.trailing_zeros()
+        );
+
+        // divide m and n by 2 until odd
+        // m inside loop
+        n >>= n.trailing_zeros();
+
+        while !m.is_zero() {
+            m >>= m.trailing_zeros();
+            if n > m { mem::swap(&mut n, &mut m) }
+            m -= &n;
+        }
+
+        n << shift
+    }
+
+    /// Calculates the Lowest Common Multiple (LCM) of the number and `other`.
+    #[inline]
+    fn lcm(&self, other: &BigUint) -> BigUint {
+        self / self.gcd(other) * other
+    }
+
+    /// Deprecated, use `is_multiple_of` instead.
+    #[inline]
+    fn divides(&self, other: &BigUint) -> bool {
+        self.is_multiple_of(other)
+    }
+
+    /// Returns `true` if the number is a multiple of `other`.
+    #[inline]
+    fn is_multiple_of(&self, other: &BigUint) -> bool {
+        (self % other).is_zero()
+    }
+
+    /// Returns `true` if the number is divisible by `2`.
+    #[inline]
+    fn is_even(&self) -> bool {
+        // Considering only the last digit.
+        match self.data.first() {
+            Some(x) => x.is_even(),
+            None => true,
+        }
+    }
+
+    /// Returns `true` if the number is not divisible by `2`.
+    #[inline]
+    fn is_odd(&self) -> bool {
+        !self.is_even()
+    }
+}
+
+fn high_bits_to_u64(v: &BigUint) -> u64 {
+    match v.data.len() {
+        0   => 0,
+        1   => v.data[0] as u64,
+        _   => {
+            let mut bits = v.bits();
+            let mut ret = 0u64;
+            let mut ret_bits = 0;
+
+            for d in v.data.iter().rev() {
+                let digit_bits = (bits - 1) % big_digit::BITS + 1;
+                let bits_want = cmp::min(64 - ret_bits, digit_bits);
+
+                if bits_want != 64 {
+                    ret <<= bits_want;
+                }
+                ret      |= *d as u64 >> (digit_bits - bits_want);
+                ret_bits += bits_want;
+                bits     -= bits_want;
+
+                if ret_bits == 64 {
+                    break;
+                }
+            }
+
+            ret
+        }
+    }
+}
+
+impl ToPrimitive for BigUint {
+    #[inline]
+    fn to_i64(&self) -> Option<i64> {
+        self.to_u64().and_then(|n| {
+            // If top bit of u64 is set, it's too large to convert to i64.
+            if n >> 63 == 0 {
+                Some(n as i64)
+            } else {
+                None
+            }
+        })
+    }
+
+    #[inline]
+    fn to_u64(&self) -> Option<u64> {
+        let mut ret: u64 = 0;
+        let mut bits = 0;
+
+        for i in self.data.iter() {
+            if bits >= 64 {
+                return None;
+            }
+
+            ret += (*i as u64) << bits;
+            bits += big_digit::BITS;
+        }
+
+        Some(ret)
+    }
+
+    #[inline]
+    fn to_f32(&self) -> Option<f32> {
+        let mantissa = high_bits_to_u64(self);
+        let exponent = self.bits() - fls(mantissa);
+
+        if exponent > f32::MAX_EXP as usize {
+            None
+        } else {
+            let ret = (mantissa as f32) * 2.0f32.powi(exponent as i32);
+            if ret.is_infinite() {
+                None
+            } else {
+                Some(ret)
+            }
+        }
+    }
+
+    #[inline]
+    fn to_f64(&self) -> Option<f64> {
+        let mantissa = high_bits_to_u64(self);
+        let exponent = self.bits() - fls(mantissa);
+
+        if exponent > f64::MAX_EXP as usize {
+            None
+        } else {
+            let ret = (mantissa as f64) * 2.0f64.powi(exponent as i32);
+            if ret.is_infinite() {
+                None
+            } else {
+                Some(ret)
+            }
+        }
+    }
+}
+
+impl FromPrimitive for BigUint {
+    #[inline]
+    fn from_i64(n: i64) -> Option<BigUint> {
+        if n >= 0 {
+            Some(BigUint::from(n as u64))
+        } else {
+            None
+        }
+    }
+
+    #[inline]
+    fn from_u64(n: u64) -> Option<BigUint> {
+        Some(BigUint::from(n))
+    }
+
+    #[inline]
+    fn from_f64(mut n: f64) -> Option<BigUint> {
+        // handle NAN, INFINITY, NEG_INFINITY
+        if !n.is_finite() {
+            return None;
+        }
+
+        // match the rounding of casting from float to int
+        n = n.trunc();
+
+        // handle 0.x, -0.x
+        if n.is_zero() {
+            return Some(BigUint::zero());
+        }
+
+        let (mantissa, exponent, sign) = Float::integer_decode(n);
+
+        if sign == -1 {
+            return None;
+        }
+
+        let mut ret = BigUint::from(mantissa);
+        if exponent > 0 {
+            ret = ret << exponent as usize;
+        } else if exponent < 0 {
+            ret = ret >> (-exponent) as usize;
+        }
+        Some(ret)
+    }
+}
+
+impl From<u64> for BigUint {
+    #[inline]
+    fn from(mut n: u64) -> Self {
+        let mut ret: BigUint = Zero::zero();
+
+        while n != 0 {
+            ret.data.push(n as BigDigit);
+            // don't overflow if BITS is 64:
+            n = (n >> 1) >> (big_digit::BITS - 1);
+        }
+
+        ret
+    }
+}
+
+macro_rules! impl_biguint_from_uint {
+    ($T:ty) => {
+        impl From<$T> for BigUint {
+            #[inline]
+            fn from(n: $T) -> Self {
+                BigUint::from(n as u64)
+            }
+        }
+    }
+}
<