# `MetamorphicCrypto.Hybrid`
[🔗](https://github.com/moss-piglet/metamorphic_crypto/blob/main/lib/metamorphic_crypto/hybrid.ex#L1)

ML-KEM-768 + X25519 hybrid post-quantum encryption.

Provides quantum-resistant key encapsulation by combining:

- **ML-KEM-768** (NIST FIPS 203) — lattice-based post-quantum KEM
- **X25519** — classical elliptic-curve Diffie-Hellman

The shared secrets from both KEMs are combined via SHA3-256 to derive the
final symmetric key, which encrypts the payload with XSalsa20-Poly1305.

## Ciphertext format (v2)

    0x02 || ML-KEM-768 ciphertext (1088 bytes) || X25519 ephemeral pk (32 bytes) || nonce (24 bytes) || secretbox ciphertext

## Key sizes

- Public key: 1216 bytes (ML-KEM ek 1184 + X25519 pk 32)
- Secret key: 32 bytes (root seed, expanded via SHAKE256)

## Usage

    {pk, sk} = MetamorphicCrypto.Hybrid.generate_keypair()

    {:ok, ct} = MetamorphicCrypto.Hybrid.seal("quantum-safe secret", pk)
    {:ok, "quantum-safe secret"} = MetamorphicCrypto.Hybrid.open(ct, sk)

# `generate_keypair`

```elixir
@spec generate_keypair() :: {String.t(), String.t()}
```

Generate a hybrid ML-KEM-768 + X25519 keypair.

Returns `{public_key_b64, secret_key_b64}`.

The public key is 1216 bytes (base64-encoded). The secret key is a 32-byte seed.

## Example

    {pk, sk} = MetamorphicCrypto.Hybrid.generate_keypair()

# `hybrid_ciphertext?`

```elixir
@spec hybrid_ciphertext?(ciphertext_b64 :: String.t()) :: boolean()
```

Check if a base64 ciphertext uses the hybrid v2 format.

## Example

    MetamorphicCrypto.Hybrid.hybrid_ciphertext?(ciphertext)
    #=> true

# `open`

```elixir
@spec open(ciphertext_b64 :: String.t(), secret_key_b64 :: String.t()) ::
  {:ok, String.t()} | {:error, String.t()}
```

Open a hybrid-sealed ciphertext, returning the decrypted UTF-8 string.

Returns `{:ok, plaintext}` or `{:error, reason}`.

## Example

    {pk, sk} = MetamorphicCrypto.Hybrid.generate_keypair()
    {:ok, ct} = MetamorphicCrypto.Hybrid.seal("hello PQ", pk)
    {:ok, "hello PQ"} = MetamorphicCrypto.Hybrid.open(ct, sk)

# `open_raw`

```elixir
@spec open_raw(ciphertext_b64 :: String.t(), secret_key_b64 :: String.t()) ::
  {:ok, String.t()} | {:error, String.t()}
```

Open a hybrid-sealed ciphertext, returning plaintext as base64.

Returns `{:ok, plaintext_b64}` or `{:error, reason}`.

# `seal`

```elixir
@spec seal(plaintext :: String.t(), public_key_b64 :: String.t()) ::
  {:ok, String.t()} | {:error, String.t()}
```

Seal a UTF-8 plaintext string using hybrid post-quantum encryption.

Returns `{:ok, ciphertext_b64}` or `{:error, reason}`.

## Example

    {pk, _sk} = MetamorphicCrypto.Hybrid.generate_keypair()
    {:ok, ct} = MetamorphicCrypto.Hybrid.seal("secret data", pk)

# `seal_raw`

```elixir
@spec seal_raw(plaintext_b64 :: String.t(), public_key_b64 :: String.t()) ::
  {:ok, String.t()} | {:error, String.t()}
```

Seal raw bytes (as base64) using hybrid post-quantum encryption.

Returns `{:ok, ciphertext_b64}` or `{:error, reason}`.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
