PyNaCl

Python bindings to libsodium for authenticated encryption, digital signatures, hashing, and password-based key derivation

Library
PyPI
v1.6.2
1,204stars
Apache License 2.0

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
66/100Good
Development Activity68
Maintenance28
Community80
Maturity60
Momentum28

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
85/100Excellent
Architecture85
Code Quality92
Innovation78
Learning Curve85

PyNaCl provides Python bindings to libsodium, the widely audited fork of Daniel J. Bernstein’s NaCl (Networking and Cryptography library). Rather than exposing libsodium’s full C API directly, PyNaCl wraps it in a set of high-level, misuse-resistant classes — Box and SealedBox for public-key encryption, SecretBox for symmetric encryption, SigningKey/VerifyKey for Ed25519 signatures, and pwhash for Argon2/scrypt password hashing — alongside a lower-level nacl.bindings module that exposes the underlying crypto_* primitives nearly one-to-one for callers who need direct control.

The library builds and statically bundles its own copy of libsodium’s C source via a custom setup.py/build_clib step, with an option to link against a system-installed libsodium instead. This makes PyNaCl one of the primary cryptography building blocks in the Python ecosystem — it backs tools ranging from SSH and messaging clients to web frameworks needing authenticated encryption, and is maintained by the Python Cryptographic Authority (PyCA), the same group behind the cryptography package.

What You Get

  • High-level Box and SecretBox classes for public-key and secret-key authenticated encryption using Curve25519/XSalsa20-Poly1305 and XSalsa20-Poly1305 respectively
  • Ed25519 digital signatures via SigningKey and VerifyKey for signing and verifying messages
  • Password-based key derivation and hashing through nacl.pwhash (Argon2i, Argon2id, scrypt)
  • A low-level nacl.bindings module exposing libsodium’s crypto_* primitives directly for advanced use cases
  • Bundled, statically-built libsodium C library with an option to link against a system install

Common Use Cases

  • Encrypting messages between two parties who exchange public keys, using Box for authenticated public-key encryption
  • Signing and verifying API payloads or software releases with Ed25519 signatures
  • Hashing and verifying user passwords with Argon2id via nacl.pwhash
  • Building higher-level secure messaging or token systems on top of SecretBox symmetric encryption

Under The Hood

Architecture The src/nacl package is organized as a thin high-level wrapper (public.py: Box/SealedBox/PrivateKey/PublicKey, secret.py: SecretBox, signing.py: SigningKey/VerifyKey, hash.py, the pwhash/ subpackage) built atop nacl.bindings, a lower module that maps closely to the underlying C library’s crypto_* functions generated via cffi against a statically-built (or system) libsodium. Build-time compilation is handled by a custom setup.py with build_clib/build_ext overrides that vendor src/libsodium (a copy of the upstream libsodium C library) and compile it before cffi links against it, with environment variables available to redirect this to a system-installed copy or a minimal build. This is a clean two-layer design: a stable C-binding layer that rarely changes shape, and a small, misuse-resistant Pythonic API layer that composes those bindings into safe higher-level primitives, validating key sizes, handling encoding via a pluggable Encoder protocol, and raising typed exceptions on misuse.

Tech Stack The project targets Python 3.8+ and PyPy 3, alongside the vendored libsodium C library it compiles from source via custom setuptools command overrides. C-to-Python bridging uses cffi rather than ctypes or a conventional C extension. Build orchestration runs through nox across a wide matrix of Python versions, PyPy, and free-threaded Python, plus bundled/system/minimal libsodium install modes. Testing relies on pytest with pytest-cov, pytest-xdist, and hypothesis for property-based test vectors. Documentation is built with Sphinx and hosted on Read the Docs, and type checking runs via mypy in a strict configuration.

Code Quality The tests/ directory pairs one test file per public module (test_box.py, test_secret.py, test_signing.py, test_hash.py, test_pwhash.py, test_bindings.py, and more) with known-answer test vectors and hypothesis-driven property tests, run across the full CI matrix. Error handling is explicit and typed through a small nacl.exceptions hierarchy (CryptoError, BadSignatureError, TypeError, ValueError), raised deliberately on malformed input rather than left to propagate unclear failures. Naming mirrors libsodium’s own crypto_* conventions in the bindings layer, with idiomatic PascalCase classes in the high-level API. The project runs mypy in strict mode as a dedicated CI session, loosened only where cffi’s untyped C bindings make full strictness impractical, and lints with ruff. CI runs the full test matrix plus dedicated docs, meta, and mypy sessions on every push and pull request.

API Design PyNaCl’s central design decision is to preserve NaCl/libsodium’s “hard to use insecurely” philosophy in Python rather than add abstraction on top of it: high-level classes accept exactly the inputs libsodium’s authenticated-encryption primitives expect, validate sizes eagerly, and default to a pluggable Encoder so encoding never silently corrupts key material. The API surface is deliberately small — a handful of classes plus pwhash functions — mapped closely to libsodium’s own primitive names, keeping a developer’s mental model in sync with the underlying cryptography instead of hiding it. Getting started requires almost no boilerplate, and the library ships extensive docstrings with runnable doctest examples for nearly every public method. Its differentiation from lower-level bindings is entirely in this ergonomic layer, not in novel cryptographic primitives — it wraps libsodium rather than inventing new schemes.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search