libsignal

package module
v0.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 1, 2026 License: AGPL-3.0 Imports: 0 Imported by: 0

README

libsignal-go

Go Reference CI compat Go Report Card Release

A pure-Go implementation of the Signal client protocol core, wire-compatible with signalapp/libsignal.

Independent fork — a community reimplementation, not affiliated with, endorsed by, or maintained by Signal Messenger LLC. Report issues and security vulnerabilities in this port to this repository (see SECURITY.md) — not to Signal.

libsignal-go is built entirely on the Go standard library and a small set of pure-Go cryptography dependencies. There is no cgo, C, or Rust in the shipped module — it builds with CGO_ENABLED=0 and cross-compiles like any ordinary Go package. The goal is byte-for-byte wire compatibility with the upstream Rust implementation for the client-side protocol surface, enforced by cross-implementation compatibility checks as required CI gates.

Status: mainline — the full client protocol is implemented and interop-verified byte-compatible with libsignal v0.96.4 (both roles), with account-key derivations and username-link support added in the 0.x line. Early development: the API may still change across 0.x releases; review the security posture before production use.

Status

The protocol is being implemented in phases. Each phase is one or more pull requests; compatibility is asserted incrementally as domains land.

This table tracks what has merged to the default branch.

Phase Scope Status
P1 Scaffold: Go module, CI, repository cleanup
P2 Crypto primitives, curve (X25519 / XEdDSA), address types
P3 KEM (Kyber1024), protobuf codegen, wire messages
P4 Compatibility harness: committed vectors + live Rust interop
P5 Ratchet keys, session state, stores
P6 PQXDH session builder + session cipher
P7 Groups: sender keys + group cipher
P8 Sealed sender v1/v2 + AES-256-GCM-SIV
P9 Fingerprints + API polish + scope matrix
P10 SPQR port + re-pin to mainline + full revalidation
P11 Cleanup: remove reference trees, final docs, v0.1.0

✅ merged to main. All 11 phases complete — tagged v0.1.0.

Compatibility staging

Wire compatibility is asserted against a pinned upstream tag, not a moving target, so that the interop gate is meaningful and reproducible.

  • Stage 1 (superseded): compatibility was bounded to the libsignal v0.91.0 protocol surface — the last upstream release before the Sparse Post-Quantum Ratchet (SPQR) was made mandatory for new sessions — while SPQR was being ported (P5–P9 ran against this pin).
  • Stage 2 (current): SPQR is ported (P10) and the compat harness is re-pinned to libsignal v0.96.4, the current upstream mainline release. The compatibility claim now covers the full current-mainline protocol surface, including SPQR-negotiated sessions (v0.96.4 requires SPQR — min_version: V1). The committed vectors are byte-identical across the re-pin (the protos, the spqr v1.5.1 pin, and libcrux-ml-kem 0.0.8 are unchanged from v0.91.0), and the live Rust↔Go interop passes both roles with SPQR on the wire.

The rationale, alternatives considered, and the exact pin boundary are recorded in decisions/0001-spqr-staged-compat.md. The v0.96.4 re-pin is recorded in decisions/0006-protocol-core-and-workflow-signal-split.md: the upstream patch-release changes since v0.96.0 are primarily net/client, language-bridge, and zkgroup API additions outside this module's protocol-core scope, with only an inactive ML-KEM-1024 metadata fix touching protocol code.

Upstream release monitoring

The scheduled upstream-pin workflow checks signalapp/libsignal releases weekly and opens a PR when the pinned Rust compat harness is behind. The PR updates compat/rust-harness, regenerates all committed vectors, and runs the live Rust-harness interop tests before enabling GitHub auto-merge. It requires a GH_MANAGEMENT_TOKEN secret with contents and pull-request write access so the generated PR triggers the required checks. A green PR is expected to merge automatically; a red PR is the manual porting queue for upstream compatibility changes.

The separate compat-drift workflow keeps watch on upstream main and files an informational issue when unreleased drift appears. It does not modify the pin and does not gate pull requests.

Scope matrix

The per-domain status of the client protocol surface. Implemented domains are wire-checked against upstream libsignal v0.96.4 (committed Rust-generated vectors plus live Rust↔Go interop, per the compatibility staging above). Staged domains are deferred to a named phase. Excluded domains are deliberate non-goals for this module.

Domain Status Package Notes
X25519 ECDH + XEdDSA sign/verify ✅ implemented curve v0.96.4 vectors + interop
Kyber1024 KEM (encaps/decaps) ✅ implemented kem v0.96.4 decaps vectors + interop
Wire messages (Signal, PreKeySignal, SenderKey, SKDM) ✅ implemented protocol golden-byte vectors both directions
Symmetric primitives (AES-CBC/CTR/GCM, HKDF, HMAC) ✅ implemented internal/crypto internal building blocks
Double Ratchet keys + session state + stores ✅ implemented ratchet, session, stores KDF + state KATs
PQXDH session establishment + session cipher ✅ implemented session both roles, with/without one-time pre-key, interop
Group messaging (sender keys + group cipher) ✅ implemented groups SKDM + cipher, both directions, interop
Sealed sender v1 + v2 ✅ implemented sealedsender certificate chain + USMC + seal/decrypt, both versions, interop
AES-256-GCM-SIV (RFC 8452) ✅ implemented internal/crypto/gcmsiv nonce-misuse-resistant AEAD for sealed sender v2
Fingerprints (numeric + scannable) ✅ implemented fingerprint display + scannable byte-equal vs upstream
Sparse Post-Quantum Ratchet (SPQR) ✅ implemented spqr, internal/mlkem768incr, internal/spqr/chunked incremental ML-KEM-768 + GF(2^16) chunked transport + state machine, mixed into the session message keys; SPQR-negotiated interop both roles at v0.96.4
Account keys (entropy pool, SVR key, PIN hash, backup key derivations) ✅ implemented accountkeys v0.96.4 known vectors for account entropy, backup ID, PIN hash, and local PIN PHC
Username validation, candidates, and username links ✅ implemented usernames v0.96.4 username-link vectors; hash/proof deferred to zk/poksho phase
X3DH v3 session initiation ⛔ excluded v3 decrypt/state compat retained; v0.96.4 cannot initiate v3
ML-KEM-1024 activation ⛔ excluded wire type 0x0A parsing reserved only
zkgroup / zkcredential / poksho ⛔ excluded non-goal (server/credential surface)
username hash/proof, key transparency, SVR/svrb 🚧 deferred tracked in compat/coverage_manifest.json; account-key/SVR-key derivation remains vector-backed here, proof-system semantics move to encrypted-spaces-go
device transfer, media, message backup, net ⛔ excluded non-goal
incremental_mac, HPKE, session_cipher_legacy ⛔ excluded upstream test-only
Language bridges (Java / Swift / Node) ⛔ excluded deleted from this fork, not ported

Legend: ✅ implemented (v0.96.4 compat) · 🚧 staged to a later phase · ⛔ excluded (deliberate non-goal). FIPS certification and key-material zeroization guarantees beyond the documented Go posture are also out of scope.

No ⛔ row is a client-protocol gap. Every capability a Signal client needs to send and receive messages — 1:1 sessions (PQXDH), group messaging, sealed sender (v1 + v2), fingerprints, and the SPQR post-quantum ratchet — is ✅ implemented and interop-proven against mainline. The excluded rows are deliberate non-goals: server / credential / service surfaces (zkgroup, username hash/proof, key transparency, SVR), app- and transport-layer features (device transfer, media, message backup, net), upstream test-only code (incremental_mac, the HPKE test harness, session_cipher_legacy), language bindings (this module is the Go binding), or behaviors upstream v0.96.4 itself does not perform — v3 session initiation (v3 decrypt is retained) and ML-KEM-1024 activation (wire type 0x0A is reserved-only, exactly as in mainline).

Reference tree

During development the upstream Rust sources lived under rust/ as a read-only behavioral reference snapshot: every crypto constant, KDF info string, version byte, MAC layout, and proto field number in the Go code was traced to a cited line in that tree and locked by a vector test. The rust/ snapshot (along with the root Cargo manifests and rust-toolchain) was removed at v0.1.0, now that the Go implementation is self-sufficient — git history preserves it, and the provenance comments in the Go sources (// ported from rust/protocol/src/…) still point into that history. Wire compatibility is no longer asserted against an in-tree snapshot but against the compat harness (compat/rust-harness/), which pins upstream libsignal remotely by tag and remains in the repo.

Installation

go get github.com/GoCodeAlone/libsignal-go

Requires Go 1.26 or newer. The module pins toolchain go1.26.4; a matching toolchain is fetched automatically by the go command if your local toolchain is older.

Usage

Runnable examples live alongside the packages they document (Go renders them in go doc and runs them under go test):

Browse the full API with:

go doc github.com/GoCodeAlone/libsignal-go
go doc github.com/GoCodeAlone/libsignal-go/session

Development

CGO_ENABLED=0 go build ./...   # build (no cgo, ever)
go vet ./...
gofmt -l .                     # must print nothing
go test -race ./...
golangci-lint run              # lint (config in .golangci.yml)

CI runs these checks on Linux and macOS; the cross-implementation compatibility suite becomes a required gate from P4 onward. A single required status check named go gates merges to main.

Cryptography notice

This distribution includes cryptographic software. The country in which you currently reside may have restrictions on the import, possession, use, and/or re-export to another country of encryption software. Before using any encryption software, please check your country's laws, regulations, and policies concerning the import, possession, or use, and re-export of encryption software. See https://www.wassenaar.org/ for more information.

License

Copyright the libsignal-go contributors. Portions derived from signalapp/libsignal, Copyright 2020-2026 Signal Messenger, LLC.

Licensed under the GNU Affero General Public License v3.0 (AGPL-3.0). See LICENSE for the full text, or https://www.gnu.org/licenses/agpl-3.0.html.

Documentation

Overview

Package libsignal is a pure-Go implementation of the Signal client protocol core, wire-compatible with signalapp/libsignal.

The implementation contains no cgo, C, or Rust: it is built entirely on the Go standard library and a small set of pure-Go cryptography dependencies. It targets the client-side protocol surface (curve and KEM primitives, wire messages, the Double Ratchet session, group sender keys, sealed sender, and fingerprints). Server-only and out-of-scope domains (zkgroup, usernames, key transparency, SVR, device transfer, media, and message backup) are not implemented; see the README scope matrix for the authoritative list.

Compatibility staging

Wire compatibility is asserted against a pinned upstream tag rather than a moving target. Until the Sparse Post-Quantum Ratchet (SPQR) phase lands, compatibility claims are bounded to the libsignal v0.91.0 protocol surface; once SPQR is ported the compat harness is re-pinned to the current upstream mainline. This staging and its rationale are recorded in decisions/0001-spqr-staged-compat.md.

License

Licensed under the GNU Affero General Public License v3.0 (AGPL-3.0). See the LICENSE file at the repository root.

Directories

Path Synopsis
Package accountkeys implements Signal account-level key derivations.
Package accountkeys implements Signal account-level key derivations.
Package address provides types identifying an individual Signal client instance: service IDs (ACI/PNI), device IDs, and protocol addresses.
Package address provides types identifying an individual Signal client instance: service IDs (ACI/PNI), device IDs, and protocol addresses.
Package curve implements the Curve25519 (Djb) key types used by the Signal protocol: X25519 key agreement and the 33-byte serialized public-key wire format.
Package curve implements the Curve25519 (Djb) key types used by the Signal protocol: X25519 key agreement and the 33-byte serialized public-key wire format.
Package fingerprint implements Signal's safety-number fingerprints: the numeric DisplayableFingerprint (a 60-digit human-comparable string) and the ScannableFingerprint (a protobuf for QR-code comparison).
Package fingerprint implements Signal's safety-number fingerprints: the numeric DisplayableFingerprint (a 60-digit human-comparable string) and the ScannableFingerprint (a protobuf for QR-code comparison).
Package groups implements Signal's sender-key (group messaging) state: the per-sender SenderKeyState/SenderKeyRecord and the sender-key distribution message (SKDM) create/process flow.
Package groups implements Signal's sender-key (group messaging) state: the per-sender SenderKeyState/SenderKeyRecord and the sender-key distribution message (SKDM) create/process flow.
internal
crypto
Package crypto provides thin, allocation-conscious wrappers over the Go standard library's symmetric primitives, with an error taxonomy and semantics mirroring upstream signalapp/libsignal (rust/crypto and rust/protocol/src/crypto.rs).
Package crypto provides thin, allocation-conscious wrappers over the Go standard library's symmetric primitives, with an error taxonomy and semantics mirroring upstream signalapp/libsignal (rust/crypto and rust/protocol/src/crypto.rs).
crypto/gcmsiv
Package gcmsiv implements AES-256-GCM-SIV, the nonce-misuse-resistant AEAD of RFC 8452.
Package gcmsiv implements AES-256-GCM-SIV, the nonce-misuse-resistant AEAD of RFC 8452.
mlkem768incr
Package mlkem768incr implements the INCREMENTAL ML-KEM-768 key encapsulation used by Signal's Sparse Post-Quantum Ratchet (SPQR), as a pure-Go port (no cgo) of the libcrux-ml-kem 0.0.8 `incremental` API that SPQR v1.5.1 depends on.
Package mlkem768incr implements the INCREMENTAL ML-KEM-768 key encapsulation used by Signal's Sparse Post-Quantum Ratchet (SPQR), as a pure-Go port (no cgo) of the libcrux-ml-kem 0.0.8 `incremental` API that SPQR v1.5.1 depends on.
spqr/chunked
Package chunked implements the SPQR chunked-transport erasure code: a GF(2^16) Reed-Solomon-style fountain code (gf.go + polynomial.go) that ships a message as a stream of fixed 32-byte chunks reconstructible from any sufficient subset.
Package chunked implements the SPQR chunked-transport erasure code: a GF(2^16) Reed-Solomon-style fountain code (gf.go + polynomial.go) that ships a message as a stream of fixed 32-byte chunks reconstructible from any sufficient subset.
Package kem implements key encapsulation mechanisms (KEMs) for the Signal protocol.
Package kem implements key encapsulation mechanisms (KEMs) for the Signal protocol.
Package proto contains the Signal protocol wire, storage, service, sealed sender, and fingerprint message definitions, ported verbatim (field numbers and types) from upstream libsignal's rust/protocol/src/proto/*.proto.
Package proto contains the Signal protocol wire, storage, service, sealed sender, and fingerprint message definitions, ported verbatim (field numbers and types) from upstream libsignal's rust/protocol/src/proto/*.proto.
Package protocol implements the Signal wire message types: the versioned, length-checked binary encodings of SignalMessage, PreKeySignalMessage, and the group/plaintext message forms.
Package protocol implements the Signal wire message types: the versioned, length-checked binary encodings of SignalMessage, PreKeySignalMessage, and the group/plaintext message forms.
Package ratchet implements the Double Ratchet key schedule: the chain-key step, message-key derivation, root-key/DH ratchet step, and the PQXDH master secret.
Package ratchet implements the Double Ratchet key schedule: the chain-key step, message-key derivation, root-key/DH ratchet step, and the PQXDH master secret.
Package sealedsender implements Signal's sealed sender certificates and message content (the UnidentifiedSenderMessageContent, "USMC"), a pure-Go port of rust/protocol/src/sealed_sender.rs validated against upstream libsignal v0.91.0.
Package sealedsender implements Signal's sealed sender certificates and message content (the UnidentifiedSenderMessageContent, "USMC"), a pure-Go port of rust/protocol/src/sealed_sender.rs validated against upstream libsignal v0.91.0.
Package session models the Double Ratchet session state and the PQXDH establishment + message cipher: SessionState (a thin wrapper over the generated proto.SessionStructure), SessionRecord (the current state plus a bounded list of archived states), ProcessPreKeyBundle / InitializeBobSession (handshake), and Encrypt / Decrypt (the message cipher).
Package session models the Double Ratchet session state and the PQXDH establishment + message cipher: SessionState (a thin wrapper over the generated proto.SessionStructure), SessionRecord (the current state plus a bounded list of archived states), ProcessPreKeyBundle / InitializeBobSession (handshake), and Encrypt / Decrypt (the message cipher).
Package spqr implements Signal's Sparse Post-Quantum Ratchet (SPQR), the Stage-2 post-quantum layer that augments the Double Ratchet with chunked ML-KEM-768 key agreement.
Package spqr implements Signal's Sparse Post-Quantum Ratchet (SPQR), the Stage-2 post-quantum layer that augments the Double Ratchet with chunked ML-KEM-768 key agreement.
Package stores defines the storage interfaces the Signal protocol drives against — the identity, pre-key, signed-pre-key, Kyber-pre-key, session, and sender-key stores — and is a pure-Go port of rust/protocol/src/storage/traits.rs.
Package stores defines the storage interfaces the Signal protocol drives against — the identity, pre-key, signed-pre-key, Kyber-pre-key, session, and sender-key stores — and is a pure-Go port of rust/protocol/src/storage/traits.rs.
inmem
Package inmem provides in-memory implementations of the storage interfaces in the stores package.
Package inmem provides in-memory implementations of the storage interfaces in the stores package.
Package usernames implements Signal username validation and username links.
Package usernames implements Signal username validation and username links.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL