signalapp/libsignal: the Rust core behind Signal, and what it takes to build it
Home to the Signal Protocol as well as other cryptographic primitives which make Signal possible.
At a glance
- What is it?
- libsignal packages the Signal Protocol and Signal's supporting cryptographic primitives as Rust crates with Java, Swift and TypeScript bridges. It is built for Signal's own clients and servers, and the README says use outside of Signal is unsupported.
- Who is it for?
- Adopt libsignal only if you are working on Signal's own clients or servers, or you need the exact protocol and group-credential primitives the README lists and can accept that all APIs are subject to change without notice. Do not adopt it as a general-purpose messaging library for a product that is not Signal; the README states that use outside of Signal is unsupported.
- Can I use it commercially?
- Yes, with strict conditions. AGPL-3.0 is a network copyleft licence: if people use a modified version over a network, for example as a hosted service, you must offer them its source code under the same licence.
- Is it still maintained?
- Yes. The repository last received commits 7 days ago.
- What is it written in?
- Mainly Rust, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
What libsignal is for, and who it is not for
libsignal holds platform-agnostic APIs used by the official Signal clients and servers. The README lists what lives inside: libsignal-protocol, which implements the Signal protocol including the Double Ratchet algorithm and replaces libsignal-protocol-java and libsignal-metadata-java; signal-crypto with primitives such as AES-GCM; device-transfer for device-to-device transfer; attest for remote attestation of SGX enclaves and server-side HSMs; zkgroup for zero-knowledge groups; zkcredential, an abstraction for the zero-knowledge credentials behind zkgroup based on the paper "The Signal Private Group System"; poksho for zero-knowledge proofs; account-keys for using PINs as passwords in Secure Value Recovery; usernames for username generation, hashing and proofs; and media utilities.
The intended consumer is narrow. The README says the repository is used by the Signal client apps (Android, iOS and Desktop) as well as server-side, and then states plainly that use outside of Signal is unsupported. If you are evaluating this as a drop-in encrypted messaging layer for your own product, that sentence is the answer. The products of the repository are the Java, Swift and TypeScript libraries that wrap the Rust implementations, and the README warns that all APIs and implementations are subject to change without notice, as are the JNI, C and Node add-on bridge layers. Backwards-incompatible changes to the Java, Swift, TypeScript and non-bridge Rust APIs are reflected in the version number on a best-effort basis, which is a weaker promise than a stability guarantee.
How the Rust workspace and the three bridges fit together
The architecture is one Rust workspace with language bridges on top. Cargo.toml defines the members, and they map closely to the README's feature list: rust/protocol, rust/crypto, rust/device-transfer, rust/attest, rust/zkgroup, rust/zkcredential, rust/poksho, rust/account-keys, rust/usernames, rust/media, plus rust/message-backup, rust/net and rust/keytrans. The bridge crates sit under rust/bridge: ffi and ffi/native_swift for Swift, jni and jni/native_kt for Java and Android, and node and node/native_ts for TypeScript.
A detail worth noticing is that the workspace splits members from default-members. The default set is crypto, device-transfer, media, message-backup, account-keys, poksho, protocol, usernames, zkcredential and zkgroup. The bridge crates, attest, keytrans and the net crates are members but not defaults, so a plain cargo build at the root does not compile them. That is a deliberate narrowing: the protocol and credential crates are the ones you can build without pulling in the platform toolchains. The workspace also sets resolver = "2" with the comment that this keeps dev-dependency features from leaking into products, and pins version 0.103.0, license AGPL-3.0-only and rust-version 1.93.1. Bridge code is generated, not hand-written: the justfile exposes generate-jni, generate-ffi and generate-node, combined under generate-bridge, and the README notes that when exposing new APIs to Java you must also run rust/bridge/jni/bin/gen_java_decl.py, which requires the cbindgen tool.
Installing the toolchain and running a first Rust build
The README is explicit that building anything in the repository requires Rust plus recent versions of Clang, libclang, CMake, Make, protoc, Python 3.9 or newer, and git. On a Debian-like system it gives this apt command:
apt-get install clang libclang-dev cmake make protobuf-compiler libprotobuf-dev python3 gitOn macOS the README points to a best-effort maintained setup script:
bin/mac_setup.shWith the system packages in place, the first real use is the basic protocol libraries. The build uses a specific version of the Rust stable compiler, downloaded automatically by cargo, so the pinned rust-toolchain file governs the build rather than whatever stable you have installed:
cargo build
cargo testExpect a long first compile, because the default-members list covers the protocol, crypto, credential and media crates. If you need the extra Rust tools the repository uses, the README warns to install them from cargo rather than a system package manager, since package managers sometimes ship outdated versions that break the build, especially cbindgen. The commands it gives read the pinned versions out of files in the repository:
cargo +stable install --version "$(cat acknowledgments/cargo-about-version)" --locked cargo-about
cargo +stable install --version "$(cat .taplo-cli-version)" --locked taplo-cli
cargo +stable install cargo-fuzzFor Android the README adds a JDK (officially supported version is JDK 21), the Android NDK/SDK, and the four Android targets via rustup. The Java build then runs from the java directory, where ./gradlew test runs the tests and ./gradlew build produces AAR outputs. A Docker-based build system is also available in that directory through make.
Consuming the published Java packages from Maven
If you do not want to build from source, Signal publishes Java packages under the names org.signal:libsignal-server, org.signal:libsignal-client and org.signal:libsignal-android. According to the README, libsignal-client and libsignal-server contain native libraries for Debian-flavored x86_64 Linux, Windows x86_64, and macOS on x86_64 and arm64. libsignal-android contains native libraries for armeabi-v7a, arm64-v8a, x86 and x86_64. They live in a Maven repository at https://build-artifacts.signal.org/libraries/maven/, and the README gives this repositories entry:
maven {
name = "SignalBuildArtifacts"
// The "uri()" part is only necessary for Kotlin Gradle; Groovy Gradle accepts a bare string here.
url = uri("https://build-artifacts.signal.org/libraries/maven/")
}The README notes that older builds were published to Maven Central instead, so an older build script may still resolve from there. It also states that when building for Android you need both libsignal-android and libsignal-client, though the sentence is cut off in the README text, so check the current file before wiring up a dependency. The practical constraint here is platform coverage: the published native libraries are a fixed set of targets, and anything outside that set means building the bridges yourself.
Where libsignal is the wrong tool
The clearest limitation is stated by the project itself: use outside of Signal is unsupported. That is not a documentation gap you can work around. Combined with the warning that all APIs and implementations are subject to change without notice, it means a downstream product cannot treat these crates as a stable dependency surface. A version bump can change the Java, Swift, TypeScript or non-bridge Rust API, and the README only promises that such changes will be reflected in the version number on a best-effort basis, including increases to the minimum supported tools versions. A minimum Rust version or JDK bump in a patch release is a real upgrade cost for anyone pinning the library.
The build itself is another boundary. There is no published Rust crate on crates.io mentioned in the README; the distributed artifacts are the Java, Swift and TypeScript libraries. Building the bridges requires the full toolchain: Clang, libclang, CMake, protoc, Python, plus a JDK and the Android NDK/SDK for Android, and generating bridge code requires cbindgen and the gen_java_decl.py script. If your team wants a small dependency with no native toolchain, this is not it. And if you need a messaging protocol you can modify and ship under your own terms, the AGPL-3.0-only licence in Cargo.toml is a constraint you have to examine before writing code against it.
libsignal compared with libsignal-protocol-java
The README names the predecessor directly: libsignal-protocol implements the Signal protocol and is described as a replacement for libsignal-protocol-java and libsignal-metadata-java. The difference in approach is the implementation language and the layering. The older Java libraries implemented the protocol in Java. libsignal implements it in Rust and exposes Java, Swift and TypeScript libraries that wrap the Rust code through JNI, FFI and a Node add-on. That gives one protocol implementation shared across Android, iOS, Desktop and server-side code instead of separate per-platform implementations, which is the reason the repository exists in this shape.
The trade is that the Java surface is now a generated bridge rather than the implementation. Adding an API to Java means touching Rust and then running rust/bridge/jni/bin/gen_java_decl.py, which needs cbindgen. The README also warns that the JNI, C and Node add-on bridge layers can change without notice, so the bridge is the least stable part of the stack. If you are migrating from libsignal-protocol-java, the migration is not a rename: you are moving to a Rust-backed library with a different build and a different release cadence.
Licence terms and what an upgrade actually costs
Cargo.toml declares the workspace package licence as AGPL-3.0-only, and the repository carries a LICENSE file at the top level. AGPL-3.0 is a strong copyleft licence with a network-use clause, so the terms that apply to a service built on this code differ from those of a permissive licence. That is a question for your own counsel, not something the README answers, and the README's statement that use outside of Signal is unsupported sits alongside the licence rather than replacing it.
On maintenance, the repository is not archived, and the last push was on 2026-09-18. Releases move quickly: v0.103.0 on 2026-09-18, v0.102.3 on 2026-09-15, v0.102.2 on 2026-09-10. Three releases in nine days is a fast cadence, and it matches the README's warning about changes without notice. For an adopter, the cost is not just rebuilding. It is tracking the pinned rust-version (1.93.1 in Cargo.toml), the pinned toolchain in rust-toolchain, the nightly version in .nightly-rust-version, and the tool versions read from .taplo-cli-version and acknowledgments/cargo-about-version. The justfile provides install-stable and install-nightly recipes that read those files, which is the intended way to keep a local environment aligned with the repository. Acknowledgment files are also generated and checked, via generate-acknowledgments and check-acknowledgments, so a dependency change can require regenerating them.
Editorial conclusion
Adopt libsignal only if you are working on Signal's own clients or servers, or you need the exact protocol and group-credential primitives the README lists and can accept that all APIs are subject to change without notice. Do not adopt it as a general-purpose messaging library for a product that is not Signal; the README states that use outside of Signal is unsupported. Before committing, verify that your toolchain matches the pinned versions: rust-version 1.93.1 in Cargo.toml, JDK 21 for Android builds, Python 3.9 or newer, and the bridge generation step for whichever language you expose. Then run cargo build and cargo test in the workspace and confirm the crates you actually need are in default-members.
Frequently asked questions
How do I install libsignal and build it from source?
You need Rust plus Clang, libclang, CMake, Make, protoc, Python 3.9 or newer and git; on Debian-like systems the README gives an apt-get command for those packages, and on macOS it points to bin/mac_setup.sh. From there, cargo build and cargo test build and test the basic protocol libraries, with the Rust stable version downloaded automatically by cargo.
How do I use libsignal in a project?
The README says the products of the repository are the Java, Swift and TypeScript libraries that wrap the underlying Rust implementations, and that it is used by the Signal client apps and server-side. It also states that use outside of Signal is unsupported, so there is no documented general-purpose integration path for other products.
What is the libsignal alternative if I cannot use it?
The README frames libsignal-protocol as a replacement for libsignal-protocol-java and libsignal-metadata-java, so those older Java libraries are the predecessor rather than a drop-in substitute. It does not name any other alternative project.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/signalapp-libsignal)
Community notes