Metadata-Version: 2.4
Name: iden-q-post-quantum
Version: 1.1.0
Summary: IdenQ post-quantum cryptography (cipher_payload v2, login_envelope v1, mldsa_signature v1) — generated from the IdenQ Crypto IR
License-Expression: LicenseRef-IdenQ-Proprietary
Requires-Python: <3.14,>=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
License-File: THIRD-PARTY-NOTICES.md
Requires-Dist: pydantic>=2.6
Requires-Dist: cryptography>=41.0.0
Requires-Dist: argon2-cffi>=23.1.0
Requires-Dist: kyber-py>=1.0.0
Requires-Dist: dilithium-py>=1.0.0
Provides-Extra: test
Requires-Dist: pytest>=7.0; extra == "test"
Dynamic: license-file

# `iden-q-post-quantum` (Python) — generated by iqcgen 1.1.0

**Do not edit these sources.** They are compiled from the IdenQ Crypto IR in
`specs/` and regenerated with `iqcgen generate`. Cross-language byte parity is
the property this package exists to guarantee; hand edits silently break it.

**Requires:** CPython 3.10-3.13 from source; the published wheel is bytecode, so one wheel per minor version.

```bash
pip install ./dist/python
```

## Passphrase-rooted hybrid post-quantum secret encryption (`cipher_payload` v2)

A passphrase is stretched with Argon2id into a master key; an ML-KEM-768 keypair is
derived deterministically from that master key (so nothing has to be stored or synced);
encapsulating to it yields a post-quantum shared secret which is mixed with a symmetric
KEK to wrap a random per-secret data key. An attacker needs the passphrase — breaking
ML-KEM alone, or recording traffic today to decrypt after a quantum computer exists,
does not help.

```python
from iden_q_post_quantum import (encrypt, decrypt)
```

- `encrypt(plaintext: string, passphrase: string)` — Encrypt a secret under a passphrase.
- `decrypt(payload: struct, passphrase: string)` — Decrypt a payload with the passphrase that produced it.

## Hybrid X25519 + ML-KEM-768 public-key envelope (`login_envelope` v1)

Seals a short credential to a recipient's static hybrid public key. Classical and post-
quantum defence in depth: an interceptor who strips TLS must break BOTH X25519 and ML-
KEM-768 to recover the key-encryption key, and neither alone is enough. The recipient
opens it with the matching private keys.

```python
from iden_q_post_quantum import (seal, unseal, derive_recipient_keys)
```

- `seal(plaintext: bytes, recipient_x_pk: bytes, recipient_mlkem_ek: bytes)` — Seal a plaintext to a recipient's static hybrid public key.
- `unseal(envelope: struct, x_sk: bytes, mlkem_dk: bytes)` — Open an envelope with the recipient's private keys.
- `derive_recipient_keys(seed: bytes)` — Derive a recipient key set deterministically from a 96-byte seed.

## ML-DSA-44 detached signature (`mldsa_signature` v1)

Post-quantum digital signatures (FIPS 204, ML-DSA-44). A signer derives a key pair
deterministically from a seed and signs a message; a verifier checks the signature
against the pinned public key and fails closed on anything that does not verify. Pure
ML-DSA with an empty context string, so the signing input is the message itself — the
shape a JWS `ML-DSA-44` assertion needs.

```python
from iden_q_post_quantum import (derive_signing_keys, sign, verify)
```

- `derive_signing_keys(seed: bytes)` — Derive a signing key pair deterministically from a 32-byte seed.
- `sign(sk: bytes, message: bytes)` — Sign a message with a signing key.
- `verify(signed: struct, pk: bytes)` — Verify a signed message against a pinned verification key.

## Licence

IdenQ Proprietary Licence. See `LICENSE` — this software is licensed, not sold.
Third-party components keep their own terms; see `THIRD-PARTY-NOTICES.md`.
