Metadata-Version: 2.5
Name: clavium-q
Version: 0.1.0
Summary: SDK Python pour l'API CLAVIUM-Q / CERTROPI — clés post-quantiques (ML-KEM, SLH-DSA) DI-certifiées
Project-URL: Homepage, https://clavium-q.com
Project-URL: Documentation, https://docs.clavium-q.com
Project-URL: Repository, https://gitlab.com/mon-groupe4881614/clavium-q-python
Project-URL: Bug Tracker, https://gitlab.com/mon-groupe4881614/clavium-q-python/-/issues
Author-email: CERTROPI <sdk@certropi.com>
License: Proprietary
Keywords: certropi,clavium-q,cryptography,device-independent,fips203,fips205,kyber,ml-kem,post-quantum,slh-dsa
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Security :: Cryptography
Requires-Python: >=3.10
Requires-Dist: httpx>=0.27.0
Provides-Extra: dev
Requires-Dist: cryptography>=47.0.0; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
Requires-Dist: pytest>=8.0.0; extra == 'dev'
Requires-Dist: respx>=0.21.0; extra == 'dev'
Requires-Dist: ruff>=0.4.0; extra == 'dev'
Provides-Extra: verify
Requires-Dist: cryptography>=47.0.0; extra == 'verify'
Description-Content-Type: text/markdown

# clavium-q

SDK Python officiel pour l'API **CLAVIUM-Q / CERTROPI** — clés post-quantiques (ML-KEM FIPS 203, SLH-DSA FIPS 205) générées depuis une graine QRNG-DI certifiée Device-Independent.

Produit distinct d'[Alea-Q](https://pypi.org/project/alea-q/) — service séparé (`api.clavium-q.com`), clés `kg_silv_`/`kg_plat_`, pas de tier Ivory pour la PQC.

## Installation

```bash
pip install clavium-q

# Avec déchiffrement local des enveloppes post-quantiques
pip install "clavium-q[verify]"
```

## Démarrage rapide

```python
from clavium_q import ClaviumQClient

# Clé API dans le constructeur ou variable d'env CLAVIUM_Q_API_KEY
client = ClaviumQClient(api_key="kg_plat_xxx")

# ML-KEM (FIPS 203) — encapsulation de clé
kp = client.platinum.mlkem_keygen(param_set="ML_KEM_768")
print(kp.ek, kp.dk)

encaps = client.platinum.mlkem_encaps(ek=kp.ek)
print(encaps.shared_key, encaps.ciphertext)

# SLH-DSA (FIPS 205) — génération de clé, signature, vérification
sig_kp = client.silver.slhdsa_keygen(param_set="SLH_DSA_SHAKE_256s")
signed = client.silver.slhdsa_sign(sk=sig_kp.sk, message="document à signer")
verified = client.silver.slhdsa_verify(
    pk=sig_kp.pk, signature=signed.signature, message="document à signer",
)
print(verified.valid)  # True — ne lève pas d'exception si False
```

## Authentification

```python
# Option 1 — clé dans le constructeur
client = ClaviumQClient(api_key="kg_plat_xxx")

# Option 2 — variable d'environnement
import os
os.environ["CLAVIUM_Q_API_KEY"] = "kg_plat_xxx"
client = ClaviumQClient()
```

Le tier est détecté automatiquement depuis le préfixe de la clé (`kg_silv_` / `kg_plat_`) :

```python
client = ClaviumQClient(api_key="kg_plat_xxx")
print(client.tier)  # "platinum"
```

Provisioning : les clés `kg_*` sont attribuées manuellement — pas d'auto-inscription. Contactez le support CERTROPI pour un accès.

## Tiers disponibles

| Tier     | Source de la graine       | Certification       |
|----------|----------------------------|----------------------|
| Platinum | Ordinateur quantique réel  | Device-Independent   |
| Silver   | DRBG seedé quantique       | Seed quantique        |

Aucun tier gratuit/self-service pour la PQC (contrairement à Alea-Q).

## Post-quantique — ML-KEM (FIPS 203)

Disponible sur Silver et Platinum (`client.silver.*` / `client.platinum.*`, mêmes méthodes).

```python
kp = client.platinum.mlkem_keygen(param_set="ML_KEM_768")
print(kp.ek, kp.dk)

encaps = client.platinum.mlkem_encaps(ek=kp.ek)
print(encaps.shared_key, encaps.ciphertext)

# Decaps est une opération LOCALE (le serveur ne voit jamais dk) —
# nécessite l'extra 'verify' : pip install 'clavium-q[verify]'
from clavium_q import mlkem_decaps

shared_key = mlkem_decaps(kp.dk, encaps.ciphertext, param_set=kp.param_set)
assert shared_key.hex() == encaps.shared_key  # même secret des deux côtés
```

## Post-quantique — SLH-DSA (FIPS 205)

Seule la génération de clé (`slhdsa_keygen()`) consomme une graine QRNG-DI. `slhdsa_sign()` / `slhdsa_verify()` sont des opérations crypto pures côté serveur sur des clés déjà fournies par le client — chaque appel fait un round-trip réseau, mais aucun des deux n'entame de quota d'entropie.

```python
sig_kp = client.platinum.slhdsa_keygen(param_set="SLH_DSA_SHAKE_256s")
print(sig_kp.sk, sig_kp.pk)

signed = client.platinum.slhdsa_sign(
    sk=sig_kp.sk,
    message="document à signer",
    param_set="SLH_DSA_SHAKE_256s",
)
print(signed.signature, signed.sig_size)

verified = client.platinum.slhdsa_verify(
    pk=sig_kp.pk,
    signature=signed.signature,
    message="document à signer",
    param_set="SLH_DSA_SHAKE_256s",
)
print(verified.valid)
```

### Fichiers volumineux (`sign_file` / `verify_file`)

`message`/`message_b64` sont bornés en taille (protection mémoire) — pour un fichier volumineux, utiliser les variantes multipart :

```python
with open("document.pdf", "rb") as f:
    signed = client.platinum.slhdsa_sign_file(sk=sig_kp.sk, file=f, filename="document.pdf")

with open("document.pdf", "rb") as f:
    verified = client.platinum.slhdsa_verify_file(
        pk=sig_kp.pk, signature=signed.signature, file=f, filename="document.pdf",
    )
```

## Livraison sécurisée de clé privée (Platinum, `recipient_pk`)

Pour ne jamais faire transiter une clé privée en clair, `mlkem_keygen()` et `slhdsa_keygen()` acceptent (Platinum uniquement) un `recipient_pk` — la clé privée générée revient alors enveloppée (ML-KEM + AES-256-GCM + signature SLH-DSA) dans `.envelope` au lieu d'être renvoyée en clair dans `.dk` / `.sk` :

```python
import base64
from clavium_q import mlkem_decaps

kp = client.platinum.slhdsa_keygen(recipient_pk=my_mlkem_pubkey_hex)
if kp.envelope:
    # kp.sk est vide — la clé réelle est dans kp.envelope["encrypted_payload"],
    # chiffrée pour my_mlkem_pubkey_hex. my_mlkem_dk = dk ML-KEM du
    # destinataire (généré localement, jamais transmis au serveur) — la
    # décapsulation reste locale, le serveur ne voit jamais ni my_mlkem_dk
    # ni le secret déchiffré.
    #
    # ATTENTION : les champs de l'enveloppe (ciphertext, encrypted_payload,
    # nonce, signature, certropi_pk) sont en BASE64 — contrairement à
    # dk/ek/shared_key (mlkem_keygen()/mlkem_encaps()) qui sont en HEX.
    ciphertext = base64.b64decode(kp.envelope["ciphertext"])
    shared_key = mlkem_decaps(my_mlkem_dk, ciphertext, param_set="ML_KEM_768")
    # shared_key (32 octets) est la clé AES-256-GCM utilisée pour chiffrer
    # kp.envelope["encrypted_payload"] (nonce en base64 lui aussi) —
    # déchiffrement AES-GCM restant à la charge de l'appelant, non fourni
    # par ce SDK à ce jour.
```

## Context manager

```python
with ClaviumQClient(api_key="kg_plat_xxx") as client:
    kp = client.platinum.mlkem_keygen()
```

## Client asynchrone

```python
import asyncio
from clavium_q import AsyncClaviumQClient

async def main():
    async with AsyncClaviumQClient(api_key="kg_plat_xxx") as client:
        kp = await client.platinum.mlkem_keygen()
        print(kp.ek, kp.dk)

asyncio.run(main())
```

## Gestion des erreurs

```python
from clavium_q import ClaviumQClient
from clavium_q.exceptions import AuthenticationError, BackendUnavailable, PermissionError

client = ClaviumQClient()

try:
    kp = client.platinum.mlkem_keygen()
except BackendUnavailable as e:
    print(f"Source d'entropie indisponible — réessayer dans {e.retry_after}s")
except AuthenticationError:
    print("Clé API invalide")
except PermissionError:
    print("Tier insuffisant, ou abonnement suspendu/expiré")
```

## Configuration

| Variable d'env        | Description                              | Défaut                        |
|------------------------|-------------------------------------------|-------------------------------|
| `CLAVIUM_Q_API_KEY`    | Clé API                                   | —                              |
| `CLAVIUM_Q_BASE_URL`   | URL de base de l'API                      | `https://api.clavium-q.com`    |
| `CLAVIUM_Q_TIMEOUT`    | Timeout HTTP en secondes                  | `60`                           |

## Développement

```bash
pip install -e ".[dev]"

# Suite de tests (mock HTTP via respx — aucun accès réseau requis)
pytest

# Tests contre l'API réelle (marqués `smoke`, nécessitent CLAVIUM_Q_API_KEY
# et un accès réseau — exclus par défaut)
pytest -m smoke
```

## Licence

Propriétaire — CERTROPI © 2026
