Qpher Python SDK
Official Python SDK for the Qpher Post-Quantum Cryptography API.
Installation
python -m venv .venv && source .venv/bin/activate # recommended; avoids "externally-managed-environment" errors
pip install qpher
Requirements
- Python 3.9+
Quick Start
Get a free API key (no credit card): https://portal.qpher.ai/register
from qpher import Qpher
# Initialize the client
client = Qpher(api_key="qph_your_api_key")
# Encrypt data using Kyber768 KEM.
# key_version is optional — omit it and the server uses your active key.
result = client.kem.encrypt(
plaintext=b"Hello, Quantum World!",
)
print(f"Ciphertext: {result.ciphertext.hex()}")
# Decrypt data — decrypt always needs the exact key_version that encrypted it.
decrypted = client.kem.decrypt(
ciphertext=result.ciphertext,
key_version=result.key_version,
)
print(f"Plaintext: {decrypted.plaintext}")
# Sign a message using Dilithium3 (key_version optional — defaults to active key).
sig_result = client.signatures.sign(
message=b"Invoice #12345",
)
print(f"Signature: {sig_result.signature.hex()}")
# Verify a signature
verify_result = client.signatures.verify(
message=b"Invoice #12345",
signature=sig_result.signature,
key_version=sig_result.key_version,
)
print(f"Valid: {verify_result.valid}")
API Reference
Client Initialization
from qpher import Qpher
client = Qpher(
api_key="qph_your_api_key", # Required
base_url="https://api.qpher.ai", # Optional, default
timeout=30, # Optional, seconds
max_retries=3, # Optional
)
Some operations require MFA step-up re-verification — see https://docs.qpher.ai/security/mfa
KEM Operations (Kyber768)
Encrypt
key_version is optional. Omit it and the server encrypts with your tenant's
active key; the resolved version is returned on result.key_version.
result = client.kem.encrypt(
plaintext=b"secret data",
mode="standard", # Optional: "standard" or "deterministic"
salt=b"...", # Required if mode="deterministic" (min 32 bytes)
)
# result.ciphertext: bytes
# result.key_version: int (the server-resolved active version)
# result.algorithm: str ("Kyber768")
# result.request_id: str
# To pin a specific version instead, pass key_version explicitly:
result = client.kem.encrypt(plaintext=b"secret data", key_version=5)
Decrypt
result = client.kem.decrypt(
ciphertext=encrypted_data,
key_version=1,
)
# result.plaintext: bytes
# result.key_version: int
# result.algorithm: str
# result.request_id: str
Signature Operations (Dilithium3)
Sign
key_version is optional. Omit it and the server signs with your tenant's
active key; the resolved version is returned on result.key_version.
result = client.signatures.sign(
message=b"document to sign",
)
# result.signature: bytes (3,293 bytes)
# result.key_version: int (the server-resolved active version)
# result.algorithm: str ("Dilithium3")
# result.request_id: str
# To pin a specific version instead, pass key_version explicitly:
result = client.signatures.sign(message=b"document to sign", key_version=5)
Verify
result = client.signatures.verify(
message=b"document to sign",
signature=signature_bytes,
key_version=1,
)
# result.valid: bool
# result.key_version: int
# result.algorithm: str
# result.request_id: str
Post-Quantum Hash-Based Signatures (SLH-DSA / FIPS 205)
Qpher implements FIPS 205 algorithms (SLH-DSA, also known as SPHINCS+), NIST-standardised hash-based signatures. SLH-DSA derives its security from cryptographic hash functions only, providing a conservative alternative to lattice-based signatures like ML-DSA (Dilithium3) for long-term archival and high-assurance workloads.
| Algorithm value | NIST Level | Signature size | Use case |
|---|---|---|---|
SLH-DSA-SHA2-128s |
1 | ~7.9 KB | Small signatures; slower signing |
SLH-DSA-SHA2-128f |
1 | ~17 KB | Faster signing for high-throughput |
SLH-DSA-SHA2-192s |
3 | ~16 KB | Recommended for long-term archive (30+ years) |
SLH-DSA-SHA2-256s |
5 | ~29 KB | Highest security; sovereign / compliance use |
Pass the algorithm value through the existing sign / verify API:
result = client.signatures.sign(
message=b"contract.pdf bytes",
key_version=1,
algorithm="SLH-DSA-SHA2-192s",
)
# result.signature: bytes (~16 KB for SHA2-192s)
# result.algorithm: str ("SLH-DSA-SHA2-192s")
verified = client.signatures.verify(
message=b"contract.pdf bytes",
signature=result.signature,
key_version=1,
algorithm="SLH-DSA-SHA2-192s",
)
# verified.valid: bool
Plan gating: SLH-DSA requires Personal+ plan. See https://qpher.ai/pricing.
Feature flag: SLH-DSA is shipped in this SDK release; the backend
launch is gated behind a per-request feature flag (SLH_DSA_ENABLED)
until the public launch date. Customers who pass SLH-DSA values today
get 503 ERR_SIG_022 — this is the expected transitional behaviour.
Key Management
Generate Key
result = client.keys.generate(algorithm="Kyber768")
# result.key_version: int
# result.algorithm: str
# result.status: str ("active")
# result.public_key: bytes
# result.created_at: str
Rotate Key
result = client.keys.rotate(algorithm="Kyber768")
# result.key_version: int (new)
# result.old_key_version: int
# result.algorithm: str
# result.public_key: bytes
Get Active Key
key_info = client.keys.get_active(algorithm="Kyber768")
# key_info.key_version: int
# key_info.algorithm: str
# key_info.status: str
# key_info.public_key: bytes
# key_info.created_at: str
List Keys
result = client.keys.list(
algorithm="Kyber768", # Optional filter
status="active", # Optional filter: "active", "retired", "archived"
)
# result.keys: List[KeyInfo]
# result.total: int
Retire Key
result = client.keys.retire(algorithm="Kyber768", key_version=1)
# result.key_version: int
# result.status: str ("retired")
Error Handling
from qpher import (
Qpher,
QpherError,
AuthenticationError,
ValidationError,
NotFoundError,
RateLimitError,
)
try:
result = client.kem.encrypt(plaintext=b"data", key_version=99)
except NotFoundError as e:
print(f"Key not found: {e.message}")
print(f"Error code: {e.error_code}")
print(f"Request ID: {e.request_id}")
except RateLimitError as e:
print("Rate limit exceeded, please retry later")
except AuthenticationError as e:
print("Invalid API key")
except ValidationError as e:
print(f"Invalid input: {e.message}")
except QpherError as e:
print(f"API error: {e.message}")
Error Types
| Exception | HTTP Status | Description |
|---|---|---|
AuthenticationError |
401 | Invalid or missing API key |
ValidationError |
400 | Invalid request parameters |
ForbiddenError |
403 | Operation not allowed |
NotFoundError |
404 | Resource not found |
RateLimitError |
429 | Rate limit exceeded |
ServerError |
500+ | Server-side errors |
TimeoutError |
504 | Request timed out |
ConnectionError |
503 | Connection failed |
Supported Algorithms
| Algorithm | Type | Security Level |
|---|---|---|
| Kyber768 (ML-KEM-768) | KEM (Encryption) | NIST Level 3 |
| Dilithium3 (ML-DSA-65) | Digital Signatures | NIST Level 3 |
| X-Wing (X25519 + ML-KEM-768) | Hybrid KEM | NIST Level 3 |
| Composite ML-DSA (ECDSA P-256 + ML-DSA-65) | Hybrid Signatures | NIST Level 3 |
| SLH-DSA-SHA2-128s/128f (SPHINCS+) | Hash-Based Signatures (FIPS 205) | NIST Level 1 |
| SLH-DSA-SHA2-192s | Hash-Based Signatures (FIPS 205) | NIST Level 3 |
| SLH-DSA-SHA2-256s | Hash-Based Signatures (FIPS 205) | NIST Level 5 |
Hybrid Mode (Pro/Enterprise plans): Pass
algorithm="X-Wing"for hybrid KEM oralgorithm="Composite-ML-DSA"for hybrid signatures. Without thealgorithmparameter, PQC-only algorithms are used (backward-compatible).Hybrid mode combines PQC with classical cryptography for defense-in-depth: if a lattice cryptanalysis breakthrough weakens ML-KEM or ML-DSA, the classical component (X25519 / ECDSA) still protects your data.
License
MIT License - see LICENSE for details.
Links
- Qpher Website
- API Documentation
- API Reference
- Code Examples
- GitHub Repository
- FIPS 203 — ML-KEM (Kyber768)
- FIPS 204 — ML-DSA (Dilithium3)
Alternative to: liboqs, AWS KMS PQC, Google Cloud KMS PQC.
Release files for qpher 1.4.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| qpher-1.4.0.tar.gz | 40.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| qpher-1.4.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 74.5 kB
Release files / qpher-1.4.0.tar.gz
| Download URL | qpher-1.4.0.tar.gz |
|---|---|
| Size | 40.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
da945bae3b84642932012ccf06ae47a3cf9fff45bd75f2af6e5b60d4e6bdf027
|
|
BLAKE2b-256 checksum How to use checksums |
ed3093da54703ac8a6a446d34f63cfe3cdd0399512ac192eb938c3205979c340
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jun 23, 2026.
Transparency logRelease files / qpher-1.4.0-py3-none-any.whl
| Download URL | qpher-1.4.0-py3-none-any.whl |
|---|---|
| Size | 34.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
5c05eb4e3bdb749ef9fc618f89a43cfa84365c8df99cf86fa5db452a18a96593
|
|
BLAKE2b-256 checksum How to use checksums |
3ed7b5d4ce3202cb9ea74a82a0cf27f52471acd4f412160d9ebc7cdff5be81fa
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jun 23, 2026.
Transparency log