signing¶
OpenPGP/WKD release signing and verification as a light, dependency-inverted Go library.
signing is the same trust model that backs gtb update, extracted so any
project can verify signed releases — or sign its own — without pulling in
the go-tool-base framework.
The light-footprint promise¶
The module graph is deliberately tiny. Outside its tests, go.mod declares
three dependencies:
go-crypto,
cockroachdb/errors, and
golang.org/x/crypto for the BLAKE2b
hash the minisign package needs. No cloud SDK, no web framework, no
go-tool-base — a guard test fails the build if one appears.
A verify-only consumer imports verify, and reaches all three. The direct
x/crypto requirement is minisign's BLAKE2b, but go-crypto's own OpenPGP
code pulls argon2, cast5, hkdf and sha3 out of the same module whether
minisign is imported or not.
Heavy or remote signing backends (AWS KMS, GCP, Azure, an HSM) are defined as an interface and injected by the consumer, so they never enter your dependency graph unless you opt in. See Why backends are injected.
The library leans on the standard library at every seam:
crypto.Signerfor keys (works with an in-memory RSA key or a remote KMS handle),*slog.Loggerfor logging (nildisables it),*http.Clientfor WKD fetches (niluses a stdlib client with a 30s timeout).
Who it is for¶
- Consumers verifying signed releases — e.g.
afmpegverifying the signedwasmrelease assets published byffmpeg-wasi. - Any non-framework Go project that wants release-asset integrity without adopting a CLI framework.
- Publishers signing their own release manifests via the reference
localbackend or a custom KMS/HSM backend. - Publishers whose consumers are Rust tools —
cargo-binstallandrtb-updateverify minisign signatures over individual artefacts, which theminisignpackage produces.
Verify a release in ten lines¶
priv, _ := rsa.GenerateKey(rand.Reader, 3072)
now := time.Unix(0, 0)
pub, _ := openpgpkey.ArmoredPublicKey(priv, "Release", "release@example.test", now)
manifest := []byte("sha256 ffmpeg.wasm 0xc0ffee\n")
sig, _ := openpgpkey.DetachSign(priv, pub, bytes.NewReader(manifest), now)
trust, _ := verify.LoadTrustSet(pub)
err := trust.VerifyManifestSignature(manifest, sig) // nil == verified
In production you embed the publisher's armoured public key at build time rather than generating one; the verification call is identical.
Where to go next¶
The documentation follows the Diátaxis framework:
- Tutorial — learning-oriented, start here:
- How-to guides — task-oriented recipes:
- Reference — every configuration field, error, limit and file format:
- Explanation — understanding-oriented background:
The generated Go API — signatures, doc comments and runnable Example tests —
lives on pkg.go.dev.
Each backend module has its own there too, for instance
signing-aws-kms.
Further reading¶
The blog carries a curated route through this subject: Signing your releases collects everything written about it, ordered so you can start at the beginning rather than newest-first.
Ask phpbotscout

He answers questions about the projects over on the Discord, citing the docs where they already cover it, and offering to raise an issue where they don't. Bring a bug, an idea, or a questionable engineering decision.