Quick Start
===========

Create an HPKE instance
-----------------------

Use the main ``HPKE`` class with algorithm identifiers, or the convenience function
``create_hpke()`` for the default ciphersuite (X25519 + HKDF-SHA256 + AES-128-GCM):

.. code-block:: python

   from rfc9180 import HPKE, KEMID, KDFID, AEADID, create_hpke

   # Explicit ciphersuite
   hpke = HPKE(KEMID.DHKEM_X25519_HKDF_SHA256, KDFID.HKDF_SHA256, AEADID.AES_128_GCM)

   # Or defaults
   hpke = create_hpke()

Key generation and serialization
--------------------------------

.. code-block:: python

   # Generate recipient key pair
   skR, pkR = hpke.generate_key_pair()

   # Serialize for storage or transmission
   pk_bytes = hpke.serialize_public_key(pkR)
   sk_bytes = hpke.serialize_private_key(skR)

   # seal/open accept both bytes and key objects
   enc, ct = hpke.seal_base(pk_bytes, info, aad, pt)

Derive a key pair from a seed (deterministic key generation):

.. code-block:: python

   seed = b"your-32-byte-or-longer-secret-seed-material"
   skR, pkR = hpke.derive_key_pair(seed)

Single-shot encryption (Base mode)
----------------------------------

.. code-block:: python

   info = b"application-info"
   aad = b"additional-data"
   plaintext = b"secret message"

   enc, ciphertext = hpke.seal_base(pkR, info, aad, plaintext)
   decrypted = hpke.open_base(enc, skR, info, aad, ciphertext)
   assert decrypted == plaintext

Other single-shot modes
------------------------

**PSK mode** (pre-shared key; must have at least 32 bytes of entropy):

.. code-block:: python

   psk = b"pre-shared-key-with-sufficient-entropy"
   psk_id = b"psk-identifier"
   enc, ct = hpke.seal_psk(pkR, info, aad, pt, psk, psk_id)
   pt = hpke.open_psk(enc, skR, info, aad, ct, psk, psk_id)

**Auth mode** (sender authentication):

.. code-block:: python

   skS, pkS = hpke.generate_key_pair()
   enc, ct = hpke.seal_auth(pkR, info, aad, pt, skS)
   pt = hpke.open_auth(enc, skR, info, aad, ct, pkS)

**AuthPSK mode** (authenticated + pre-shared key):

.. code-block:: python

   enc, ct = hpke.seal_auth_psk(pkR, info, aad, pt, psk, psk_id, skS)
   pt = hpke.open_auth_psk(enc, skR, info, aad, ct, psk, psk_id, pkS)

Multi-shot (context) API
------------------------

Use the setup methods to get sender/recipient contexts, then seal/open multiple messages:

.. code-block:: python

   enc, ctx_sender = hpke.setup.setup_base_sender(pkR, info)
   ctx_recipient = hpke.setup.setup_base_recipient(enc, skR, info)

   ct1 = ctx_sender.seal(aad, b"message 1")
   ct2 = ctx_sender.seal(aad, b"message 2")

   pt1 = ctx_recipient.open(aad, ct1)
   pt2 = ctx_recipient.open(aad, ct2)

Secret export
-------------

Setup a context and export a secret (no encryption, just key agreement + export):

.. code-block:: python

   enc, ctx_sender = hpke.setup.setup_base_sender(pkR, info)
   secret = ctx_sender.export(b"exporter-context", 32)

   # Recipient side:
   ctx_recipient = hpke.setup.setup_base_recipient(enc, skR, info)
   secret = ctx_recipient.export(b"exporter-context", 32)

Message encoding helpers
------------------------

Encode/parse a self-describing wire format (header + enc + ct):

.. code-block:: python

   from rfc9180 import append_header, parse_header
   from rfc9180.constants import HPKEMode

   enc, ct = hpke.seal_base(pkR, info, aad, pt)
   msg = append_header(
       enc, ct,
       int(hpke.kem_id), int(hpke.kdf_id), int(hpke.aead_id),
       int(HPKEMode.MODE_BASE),
   )

   kem_id, kdf_id, aead_id, mode, enc2, ct2 = parse_header(msg, enc_len=hpke.kem.Nenc)
   pt2 = hpke.open_base(enc2, skR, info, aad, ct2)

Using different ciphersuites
-----------------------------

.. code-block:: python

   # ChaCha20-Poly1305 (no AES dependency)
   hpke_chacha = HPKE(
       KEMID.DHKEM_X25519_HKDF_SHA256,
       KDFID.HKDF_SHA256,
       AEADID.CHACHA20_POLY1305,
   )

   # P-256 for NIST compliance
   hpke_p256 = HPKE(
       KEMID.DHKEM_P256_HKDF_SHA256,
       KDFID.HKDF_SHA256,
       AEADID.AES_128_GCM,
   )

Using keys from JWK or PEM
--------------------------

.. code-block:: python

   from rfc9180 import HPKE, KEMKey, create_hpke

   hpke = create_hpke()

   # From JWK (JSON Web Key)
   jwk_dict = {"kty": "OKP", "crv": "X25519", "x": "base64url-public-key"}
   pkR = KEMKey.from_jwk(jwk_dict)
   enc, ct = hpke.seal_base(pkR, info, aad, pt)

   # From PEM
   pem_str = "-----BEGIN PUBLIC KEY-----\n..."
   pkR = KEMKey.from_pem(pem_str)

Error handling
--------------

.. code-block:: python

   from rfc9180.exceptions import (
       OpenError,
       MessageLimitReachedError,
       DeserializeError,
       DecapError,
   )

   try:
       pt = hpke.open_base(enc, skR, info, aad, ct)
   except OpenError:
       # Decryption failed (wrong key, tampered data, etc.)
       pass
   except DecapError:
       # Invalid encapsulated key or decapsulation failed
       pass

For full API details, see :doc:`api/index`. For more complete examples, see :doc:`examples`.
