Skip to main content

Official Python SDK for the Qpher Post-Quantum Cryptography API — ML-KEM-768 (FIPS 203) encryption, ML-DSA-65 (FIPS 204) digital signatures, and SLH-DSA (FIPS 205) hash-based signatures. Alternative to liboqs.

Project description

Qpher Python SDK

Official Python SDK for the Qpher Post-Quantum Cryptography API.

Installation

pip install qpher

Requirements

  • Python 3.9+

Quick Start

from qpher import Qpher

# Initialize the client
client = Qpher(api_key="qph_live_your_api_key")

# Encrypt data using Kyber768 KEM
result = client.kem.encrypt(
    plaintext=b"Hello, Quantum World!",
    key_version=1,
)
print(f"Ciphertext: {result.ciphertext.hex()}")

# Decrypt data
decrypted = client.kem.decrypt(
    ciphertext=result.ciphertext,
    key_version=result.key_version,
)
print(f"Plaintext: {decrypted.plaintext}")

# Sign a message using Dilithium3
sig_result = client.signatures.sign(
    message=b"Invoice #12345",
    key_version=1,
)
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_live_your_api_key",  # Required
    base_url="https://api.qpher.ai",  # Optional, default
    timeout=30,                        # Optional, seconds
    max_retries=3,                     # Optional
)

Note on step-up re-verification. Qpher's step-up re-verification (ADR-0047 §9.1) applies only to Portal JWT sessions, not to API-key authentication. SDK integrations that authenticate with an API key do not see the X-Step-Up-Token header requirement and will never receive an ERR_MFA_013 response. This is by design: API keys are the highest-trust credential and step-up as a second factor does not apply at the API-key tier.

KEM Operations (Kyber768)

Encrypt

result = client.kem.encrypt(
    plaintext=b"secret data",
    key_version=1,
    mode="standard",      # Optional: "standard" or "deterministic"
    salt=b"...",          # Required if mode="deterministic" (min 32 bytes)
)
# result.ciphertext: bytes
# result.key_version: int
# result.algorithm: str ("Kyber768")
# result.request_id: str

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

result = client.signatures.sign(
    message=b"document to sign",
    key_version=1,
)
# result.signature: bytes (3,293 bytes)
# result.key_version: int
# result.algorithm: str ("Dilithium3")
# result.request_id: str

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 or algorithm="Composite-ML-DSA" for hybrid signatures. Without the algorithm parameter, 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

Alternative to: liboqs, AWS KMS PQC, Google Cloud KMS PQC.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

qpher-1.3.0.tar.gz (39.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

qpher-1.3.0-py3-none-any.whl (34.1 kB view details)

Uploaded Python 3

File details

Details for the file qpher-1.3.0.tar.gz.

File metadata

  • Download URL: qpher-1.3.0.tar.gz
  • Upload date:
  • Size: 39.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for qpher-1.3.0.tar.gz
Algorithm Hash digest
SHA256 ac7e4d4d05463d9162322a43284437591c5a68ae10032163a9467a9a148d0a81
MD5 10069fe8bfbc33d28dfd8dafdccf9e7f
BLAKE2b-256 e8d56990fab3a0a66fd4a1ccc4eca1e7e52538b8605badd8a215e882539ffeca

See more details on using hashes here.

Provenance

The following attestation bundles were made for qpher-1.3.0.tar.gz:

Publisher: sdk-publish.yml on qpher/Qpher

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file qpher-1.3.0-py3-none-any.whl.

File metadata

  • Download URL: qpher-1.3.0-py3-none-any.whl
  • Upload date:
  • Size: 34.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for qpher-1.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 0853f769703e5990d00d1d245d87b78344100402db64251f95b8c2906655af5b
MD5 a23f385dc0ed205dbcb0b21605dd326a
BLAKE2b-256 25fb3673c7517c0c7455327e2b0e9f30ab59599a72293656e40ad2d2ce1d1bc8

See more details on using hashes here.

Provenance

The following attestation bundles were made for qpher-1.3.0-py3-none-any.whl:

Publisher: sdk-publish.yml on qpher/Qpher

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page