Bundle combinations
The native libraries that power Tetherand's hops are grouped into six independent bundles. Each release includes every possible combination of these bundles as its own zip file, with paired SHA-256 + SHA3-256 sidecars, so users can pick the slimmest bundle that gives them what they want.
The six groups
| Group | Contents | Approximate size |
|---|---|---|
wg | libtetherand_wg.so (WireGuard via BoringTun) | ~2.7 MB |
tor | libtetherand_tor.so (embedded Arti) | ~9.0 MB |
nym | libtetherand_nym.so (Nym mixnet JNI surface) | ~600 KB |
pt | libtetherand_pt.so (obfs4 + meek + webtunnel inline) | ~2.7 MB |
pts | libconjure_client.so (and snowflake once upstream catches up) | ~16 MB |
sdr | librtlsdr.so + libhackrf.so + libusb1.0.so | ~1.0 MB |
Six independent groups means 26 = 64 combinations including the empty one.
Naming
Each combination zip is named with its group codes sorted alphabetically and joined with +:
tetherand-libs-none.zip # empty (manifest only)
tetherand-libs-wg.zip # WG only
tetherand-libs-tor+wg.zip # WG + Tor
tetherand-libs-nym+pt+pts+sdr+tor+wg.zip # everything
What's inside a zip
$ unzip -l tetherand-libs-tor+wg.zip
Archive: tetherand-libs-tor+wg.zip
Length Date Time Name
--------- ---------- ----- ----
420 01-01-2026 00:00 MANIFEST.txt
2677840 01-01-2026 00:00 lib/arm64-v8a/libtetherand_pt.so
9472040 01-01-2026 00:00 lib/arm64-v8a/libtetherand_tor.so
The MANIFEST.txt lists which groups are present, the on-device target path (lib/arm64-v8a/<file>), and per-file SHA-256 hashes. Each zip also has its own .sha256 and .sha3-256 sidecar files covering the zip as a whole.
Picking the right bundle
Use the smallest bundle that contains every hop you intend to configure. As a rough guide:
- Just want to reverse-tether and use WireGuard —
wg. - Plus Tor (with bundled obfs4/meek/webtunnel bridges) —
wg+tor+pt. - Plus snowflake/conjure pluggable transports —
wg+tor+pt+pts. - Plus the Nym mixnet —
nym+pt+pts+tor+wg. - Plus SDR detection —
nym+pt+pts+sdr+tor+wg. - Verification-of-absence artefact only —
none.
The empty bundle (tetherand-libs-none.zip) is included so a verifier can prove that a given hash corresponds to an explicit "this contains nothing" state. Useful for build reproducibility checks where the verifier wants to confirm the bundle script's behaviour on edge cases.
Master index
dist/bundles/COMBOSUMS.txt lists every combination zip with both its SHA-256 and SHA3-256:
SHA256 <hex> tetherand-libs-none.zip
SHA3-256 <hex> tetherand-libs-none.zip
SHA256 <hex> tetherand-libs-wg.zip
SHA3-256 <hex> tetherand-libs-wg.zip
…
Use this for batch verification — awk + shasum -a 256 -c to walk the whole list.
Installing a custom bundle
To use a bundle other than the full one, take the empty APK from a custom build (make apk after deleting unwanted .so files from android/app/src/main/jniLibs/arm64-v8a/) and extract the chosen combination zip into the same lib/arm64-v8a/ directory:
unzip -o tetherand-libs-tor+wg.zip -d android/app/src/main/jniLibs/
make apk
This regenerates the APK with the desired native libraries and emits fresh hash sidecars covering the new contents.
Why so many combinations
Each native library has independent integrity properties: a compromised libtetherand_tor.so doesn't tell you anything about the state of libtetherand_nym.so. Publishing all combinations means a user who only wants Tor can verify against the wg+tor+pt combo and not be exposed to a hypothetical issue in Nym or SDR libraries they don't plan to use. The "all combinations" approach defends against trojaned-library substitution attacks under a different threat model than the unified APK does.