> ## Documentation Index
> Fetch the complete documentation index at: https://veniceai-docs-revamp.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# TEE- & E2EE-Modelle

> Privacy-erweiterte KI mit Trusted Execution Environments und Ende-zu-Ende-Verschlüsselung

Venice bietet Privacy-erweiterte Modelle, die in Trusted Execution Environments (TEE) laufen und Ende-zu-Ende-Verschlüsselung (E2EE) unterstützen. Diese Modelle liefern kryptografische Garantien, dass deine Daten privat bleiben — selbst gegenüber Venice.

## Die Privacy-Stufen verstehen

| Typ      | Präfix   | Was es bedeutet                                                                                                                                            |
| -------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **TEE**  | `tee-*`  | Modell läuft in einer hardware-gesicherten Enklave. Venice kann nicht auf die Berechnung zugreifen. Du kannst das per Attestation verifizieren.            |
| **E2EE** | `e2ee-*` | Vollständige Ende-zu-Ende-Verschlüsselung. Deine Prompts werden clientseitig verschlüsselt, bevor sie gesendet werden. Nur die TEE kann sie entschlüsseln. |

<Info>
  E2EE-Modelle umfassen den TEE-Schutz plus clientseitige Verschlüsselung. TEE-Modelle bieten Enklaven-Sicherheit ohne clientseitige Verschlüsselung.
</Info>

## Verfügbare Modelle

<div id="tee-e2ee-models-placeholder">Loading...</div>

Die vollständige Liste mit Preisen und Kontext-Limits findest du auf der [Modelle-Seite](/models/overview).

## TEE-Modelle

TEE-Modelle laufen in hardware-gesicherten Enklaven (Intel TDX, NVIDIA Confidential Computing). Die Modellgewichte und deine Daten sind vor dem Host-System geschützt — einschließlich Venices Infrastruktur.

### Grundlegende Nutzung

TEE-Modelle funktionieren genau wie reguläre Modelle:

<CodeGroup>
  ```python Python theme={"dark"}
  from openai import OpenAI

  client = OpenAI(
      api_key="your-venice-api-key",
      base_url="https://api.venice.ai/api/v1"
  )

  response = client.chat.completions.create(
      model="tee-qwen3-5-122b-a10b",
      messages=[{"role": "user", "content": "Explain quantum computing"}]
  )

  print(response.choices[0].message.content)
  ```

  ```javascript Node.js theme={"dark"}
  import OpenAI from 'openai';

  const client = new OpenAI({
      apiKey: 'your-venice-api-key',
      baseURL: 'https://api.venice.ai/api/v1'
  });

  const response = await client.chat.completions.create({
      model: 'tee-qwen3-5-122b-a10b',
      messages: [{ role: 'user', content: 'Explain quantum computing' }]
  });

  console.log(response.choices[0].message.content);
  ```

  ```bash cURL theme={"dark"}
  curl https://api.venice.ai/api/v1/chat/completions \
    -H "Authorization: Bearer $API_KEY_VENICE" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "tee-qwen3-5-122b-a10b",
      "messages": [{"role": "user", "content": "Explain quantum computing"}]
    }'
  ```
</CodeGroup>

### TEE-Attestation verifizieren

Du kannst kryptografisch verifizieren, dass ein Modell in einer echten TEE läuft, indem du seinen Attestation-Report abrufst:

<CodeGroup>
  ```bash cURL theme={"dark"}
  # Eine zufällige Nonce erzeugen (verhindert Replay-Angriffe)
  NONCE=$(openssl rand -hex 16)

  # Attestation abrufen
  curl "https://api.venice.ai/api/v1/tee/attestation?model=tee-qwen3-5-122b-a10b&nonce=$NONCE" \
    -H "Authorization: Bearer $API_KEY_VENICE"
  ```

  ```python Python theme={"dark"}
  import secrets
  import requests

  nonce = secrets.token_hex(16)

  response = requests.get(
      f"https://api.venice.ai/api/v1/tee/attestation",
      params={"model": "tee-qwen3-5-122b-a10b", "nonce": nonce},
      headers={"Authorization": f"Bearer {api_key}"}
  )

  attestation = response.json()
  print(f"Verified: {attestation['verified']}")
  print(f"TEE Provider: {attestation['tee_provider']}")
  print(f"Model: {attestation['model']}")
  ```
</CodeGroup>

Die Attestation-Antwort enthält:

| Feld              | Beschreibung                                                                                                                                          |
| ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| `verified`        | Ob die Attestation die serverseitige Verifikation bestanden hat                                                                                       |
| `nonce`           | Deine Nonce, bestätigt Frische                                                                                                                        |
| `model`           | Die attestierte Modell-ID                                                                                                                             |
| `tee_provider`    | TEE-Provider-Kennung                                                                                                                                  |
| `intel_quote`     | Roher Intel-TDX-Quote (base64) für clientseitige Verifikation                                                                                         |
| `nvidia_payload`  | NVIDIA-GPU-Attestation-Daten (falls zutreffend)                                                                                                       |
| `signing_key`     | Öffentlicher Schlüssel zur Verifikation der Response-Signaturen (typischerweise für E2EE-Flows nötig; bei manchen reinen TEE-Modellen kann er fehlen) |
| `signing_address` | Aus dem Signing-Key abgeleitete Ethereum-Adresse                                                                                                      |

<Tip>
  In der Produktion die Attestation clientseitig verifizieren, indem du den Intel-TDX-Quote parst und die NVIDIA-Attestation prüfst.
</Tip>

<Note>
  Für die Verifikation reiner TEE-Modelle reichen `signing_address` und die serverseitigen Verifikationsfelder für Baseline-Attestation-Checks. Ein `signing_key` wird benötigt, wenn du clientseitige E2EE-Schlüsselverhandlung und strikte Key-Binding-Checks brauchst.
</Note>

### Response-Signaturen

TEE-Modelle können ihre Antworten signieren und so beweisen, dass die Ausgabe aus der attestierten Enklave stammt:

<CodeGroup>
  ```bash cURL theme={"dark"}
  # Nach einer Completion die Signatur verifizieren
  curl "https://api.venice.ai/api/v1/tee/signature?model=tee-qwen3-5-122b-a10b&request_id=chatcmpl-abc123" \
    -H "Authorization: Bearer $API_KEY_VENICE"
  ```

  ```python Python theme={"dark"}
  response = requests.get(
      f"https://api.venice.ai/api/v1/tee/signature",
      params={"model": "tee-qwen3-5-122b-a10b", "request_id": completion_id},
      headers={"Authorization": f"Bearer {api_key}"}
  )

  signature = response.json()
  # Prüfen, ob Signatur zur signing_address aus der Attestation passt
  ```
</CodeGroup>

## E2EE-Modelle

E2EE-Modelle fügen dem TEE-Schutz clientseitige Verschlüsselung hinzu. Deine Prompts werden verschlüsselt, bevor sie dein Gerät verlassen, und nur die TEE kann sie entschlüsseln.

Venice E2EE verwendet:

* **ECDH (Elliptic Curve Diffie-Hellman)** auf secp256k1 für Schlüsselaustausch
* **HKDF-SHA256** für Schlüsselableitung
* **AES-256-GCM** für symmetrische Verschlüsselung
* **TEE-Attestation**, um zu verifizieren, dass das Modell in einer sicheren Enklave läuft

<Warning>
  E2EE erfordert eine clientseitige Implementierung. Die Beispiele unten zeigen das vollständige Protokoll.
</Warning>

### Wie E2EE funktioniert

<Steps>
  <Step title="Ephemeren Schlüsselpaar generieren">
    Der Client erzeugt ein secp256k1-Schlüsselpaar für diese Session.
  </Step>

  <Step title="TEE-Attestation abrufen">
    Der Client fragt `/api/v1/tee/attestation` an und erhält den Public Key des Modells, Attestation-Evidence und eine Nonce.
  </Step>

  <Step title="Attestation verifizieren">
    Der Client prüft Nonce-Übereinstimmung, deaktivierten Debug-Modus und Attestation-Gültigkeit.
  </Step>

  <Step title="Nachrichten verschlüsseln">
    Der Client verschlüsselt die Prompts mittels ECDH-Shared-Secret → HKDF → AES-GCM.
  </Step>

  <Step title="Request senden">
    Der Client sendet den Request mit E2EE-Headern (`X-Venice-TEE-Client-Pub-Key`, `X-Venice-TEE-Model-Pub-Key`, `X-Venice-TEE-Signing-Algo`).
  </Step>

  <Step title="TEE-Processing">
    Die TEE entschlüsselt den Request, verarbeitet ihn und verschlüsselt die Antwort.
  </Step>

  <Step title="Response entschlüsseln">
    Der Client erhält verschlüsselte Chunks und entschlüsselt sie mit dem Private Key.
  </Step>
</Steps>

### Voraussetzungen

**JavaScript (Node.js ESM):**

```bash theme={"dark"}
npm install elliptic @noble/ciphers @noble/hashes
```

**Python:**

```bash theme={"dark"}
pip install cryptography ecdsa requests
```

### Schritt 1: E2EE-Support des Modells prüfen

Zuerst über den `/models`-Endpoint prüfen, ob das Modell E2EE unterstützt.

<CodeGroup>
  ```javascript JavaScript theme={"dark"}
  async function getE2EEModels(apiKey) {
    const response = await fetch('https://api.venice.ai/api/v1/models', {
      headers: { Authorization: `Bearer ${apiKey}` },
    })
    const { data } = await response.json()

    return data.filter(model => model.model_spec?.capabilities?.supportsE2EE === true)
  }

  // Beispielnutzung
  const models = await getE2EEModels('your-api-key')
  console.log('E2EE Models:', models.map(m => m.id))
  // Output: ['e2ee-qwen3-5-122b-a10b', 'e2ee-glm-5', ...]
  ```

  ```python Python theme={"dark"}
  import requests

  def get_e2ee_models(api_key: str) -> list:
      """Get list of models that support E2EE."""
      response = requests.get(
          'https://api.venice.ai/api/v1/models',
          headers={'Authorization': f'Bearer {api_key}'}
      )
      models = response.json()['data']

      return [
          model for model in models
          if model.get('model_spec', {}).get('capabilities', {}).get('supportsE2EE')
      ]

  # Beispielnutzung
  models = get_e2ee_models('your-api-key')
  print('E2EE Models:', [m['id'] for m in models])
  ```
</CodeGroup>

### Schritt 2: Ephemeres Schlüsselpaar generieren

Pro Session ein neues Schlüsselpaar generieren. Der Private Key sollte nur im Memory gehalten und nach Gebrauch sicher genullt werden.

<CodeGroup>
  ```javascript JavaScript theme={"dark"}
  import { ec as EC } from 'elliptic'

  function generateEphemeralKeyPair() {
    const ec = new EC('secp256k1')
    const keyPair = ec.genKeyPair()

    return {
      privateKey: new Uint8Array(keyPair.getPrivate().toArray('be', 32)),
      publicKeyHex: keyPair.getPublic('hex'), // Unkomprimiertes Format (65 Bytes hex)
    }
  }

  // Sicherheit: Private Key nach Gebrauch nullen
  function zeroFill(arr) {
    arr.fill(0)
  }
  ```

  ```python Python theme={"dark"}
  from ecdsa import SECP256k1, SigningKey
  import secrets

  def generate_ephemeral_key_pair():
      """Generate ephemeral secp256k1 key pair for E2EE session."""
      private_key = SigningKey.generate(curve=SECP256k1)
      public_key = private_key.get_verifying_key()

      # Unkomprimiertes Public Key holen (04 || x || y)
      public_key_bytes = b'\x04' + public_key.to_string()

      return {
          'private_key': private_key.to_string(),  # 32 Bytes
          'public_key_hex': public_key_bytes.hex()  # 130 Hex-Zeichen
      }
  ```
</CodeGroup>

#### Validierungs-Helpers

Verwende diese Helper-Funktionen, um Schlüssel und verschlüsselten Content vor dem Senden zu validieren.

<CodeGroup>
  ```javascript JavaScript theme={"dark"}
  function validateClientPubkey(pubkeyHex) {
    if (pubkeyHex.length !== 130 || !pubkeyHex.startsWith('04')) {
      throw new Error(`Client pubkey must be 130 hex chars starting with '04' (got ${pubkeyHex.length})`)
    }
  }

  function isValidEncrypted(s) {
    // Minimum: ephemeral_pub (65) + nonce (12) + tag (16) = 93 Bytes = 186 Hex-Zeichen
    return s.length >= 186 && /^[0-9a-fA-F]+$/.test(s)
  }
  ```

  ```python Python theme={"dark"}
  def validate_client_pubkey(pubkey_hex: str) -> None:
      """Validate client public key format."""
      if len(pubkey_hex) != 130 or not pubkey_hex.startswith('04'):
          raise ValueError(f"Client pubkey must be 130 hex chars starting with '04' (got {len(pubkey_hex)})")

  def is_valid_encrypted(s: str) -> bool:
      """Check if string is valid hex-encrypted content."""
      # Minimum: ephemeral_pub (65) + nonce (12) + tag (16) = 93 Bytes = 186 Hex-Zeichen
      return len(s) >= 186 and all(c in '0123456789abcdefABCDEF' for c in s)
  ```
</CodeGroup>

### Schritt 3: TEE-Attestation abrufen und verifizieren

Die Attestation beweist, dass das Modell in einer echten TEE läuft. Immer die Attestation verifizieren, bevor du dem Public Key des Modells vertraust.

<Info>
  **Wichtig: Nonce-Länge** — Die Client-Nonce muss **32 Bytes (64 Hex-Zeichen)** lang sein. Manche TEE-Provider verlangen exakt 32 Bytes und lehnen kürzere Nonces ab.
</Info>

<CodeGroup>
  ```javascript JavaScript theme={"dark"}
  import crypto from 'crypto'

  async function fetchAndVerifyAttestation(modelId, apiKey) {
    // Client-Nonce für Replay-Schutz generieren (32 Bytes = 64 Hex-Zeichen)
    const clientNonce = crypto.randomBytes(32).toString('hex')

    const response = await fetch(
      `https://api.venice.ai/api/v1/tee/attestation?model=${encodeURIComponent(modelId)}&nonce=${clientNonce}`,
      { headers: { Authorization: `Bearer ${apiKey}` } }
    )

    const attestation = await response.json()

    // Attestation verifizieren
    if (attestation.verified !== true) {
      throw new Error('TEE attestation verification failed on server')
    }

    if (attestation.nonce !== clientNonce) {
      throw new Error('Attestation nonce mismatch - possible replay attack')
    }

    // Public Key des Modells für Verschlüsselung holen
    const modelPublicKey = attestation.signing_key || attestation.signing_public_key
    if (!modelPublicKey) {
      throw new Error('No signing key in attestation response')
    }

    return {
      modelPublicKey,
      signingAddress: attestation.signing_address,
      attestation,
    }
  }
  ```

  ```python Python theme={"dark"}
  import secrets
  import requests

  def fetch_and_verify_attestation(model_id: str, api_key: str) -> dict:
      """Fetch and verify TEE attestation for a model."""
      # Client-Nonce für Replay-Schutz generieren (32 Bytes = 64 Hex-Zeichen)
      client_nonce = secrets.token_hex(32)

      response = requests.get(
          f'https://api.venice.ai/api/v1/tee/attestation',
          params={'model': model_id, 'nonce': client_nonce},
          headers={'Authorization': f'Bearer {api_key}'}
      )
      attestation = response.json()

      # Attestation verifizieren
      if attestation.get('verified') != True:
          raise ValueError('TEE attestation verification failed on server')

      if attestation.get('nonce') != client_nonce:
          raise ValueError('Attestation nonce mismatch - possible replay attack')

      # Public Key des Modells für Verschlüsselung holen
      model_public_key = attestation.get('signing_key') or attestation.get('signing_public_key')
      if not model_public_key:
          raise ValueError('No signing key in attestation response')

      return {
          'model_public_key': model_public_key,
          'signing_address': attestation.get('signing_address'),
          'attestation': attestation
      }
  ```
</CodeGroup>

### Schritt 4: Nachrichten verschlüsseln

User- und System-Nachrichten vor dem Senden verschlüsseln. Nur Nachrichten mit Rolle `user` und `system` müssen verschlüsselt werden.

<Warning>
  Wenn E2EE-Header gesetzt sind, müssen **alle** Nachrichten mit Rolle `user` und `system` verschlüsselt sein. Sendet du in diesen Rollen Klartext, gibt es einen „Encrypted field is not valid hex"-Fehler.
</Warning>

<CodeGroup>
  ```javascript JavaScript theme={"dark"}
  import { gcm } from '@noble/ciphers/aes.js'
  import { hkdf } from '@noble/hashes/hkdf.js'
  import { sha256 } from '@noble/hashes/sha2.js'
  import { ec as EC } from 'elliptic'
  import crypto from 'crypto'

  const HKDF_INFO = new TextEncoder().encode('ecdsa_encryption')

  function encryptMessage(plaintext, modelPublicKeyHex) {
    const ec = new EC('secp256k1')

    // Public Key normalisieren (04-Präfix ggf. ergänzen)
    let normalizedKey = modelPublicKeyHex
    if (!normalizedKey.startsWith('04') && normalizedKey.length === 128) {
      normalizedKey = '04' + normalizedKey
    }

    const modelPublicKey = ec.keyFromPublic(normalizedKey, 'hex')

    // Ephemeres Schlüsselpaar für diese Nachricht generieren
    const ephemeralKeyPair = ec.genKeyPair()

    // ECDH-Shared-Secret
    const sharedSecret = ephemeralKeyPair.derive(modelPublicKey.getPublic())
    const sharedSecretBytes = new Uint8Array(sharedSecret.toArray('be', 32))

    // AES-Key per HKDF ableiten
    const aesKey = hkdf(sha256, sharedSecretBytes, undefined, HKDF_INFO, 32)

    // Zufällige Nonce
    const nonce = crypto.randomBytes(12)

    // Mit AES-GCM verschlüsseln
    const cipher = gcm(aesKey, nonce)
    const encrypted = cipher.encrypt(new TextEncoder().encode(plaintext))

    // Ephemeren Public Key holen (unkomprimiert)
    const ephemeralPublic = new Uint8Array(ephemeralKeyPair.getPublic(false, 'array'))

    // Kombinieren: ephemeral_public (65 Bytes) + nonce (12 Bytes) + ciphertext
    const result = new Uint8Array(65 + 12 + encrypted.length)
    result.set(ephemeralPublic, 0)
    result.set(nonce, 65)
    result.set(encrypted, 65 + 12)

    return Buffer.from(result).toString('hex')
  }

  function encryptMessagesForE2EE(messages, modelPublicKey) {
    return messages.map(msg => {
      if (msg.role === 'user' || msg.role === 'system') {
        return {
          ...msg,
          content: encryptMessage(msg.content, modelPublicKey),
        }
      }
      return msg
    })
  }
  ```

  ```python Python theme={"dark"}
  from cryptography.hazmat.primitives.ciphers.aead import AESGCM
  from cryptography.hazmat.primitives.kdf.hkdf import HKDF
  from cryptography.hazmat.primitives import hashes
  from ecdsa import SECP256k1, VerifyingKey, SigningKey
  import os

  HKDF_INFO = b'ecdsa_encryption'

  def encrypt_message(plaintext: str, model_public_key_hex: str) -> str:
      """Encrypt a message using ECDH + HKDF + AES-GCM."""
      # Public Key normalisieren
      key_hex = model_public_key_hex
      if not key_hex.startswith('04') and len(key_hex) == 128:
          key_hex = '04' + key_hex

      model_public_key_bytes = bytes.fromhex(key_hex)

      # Public Key des Modells parsen (04-Präfix überspringen)
      model_verifying_key = VerifyingKey.from_string(
          model_public_key_bytes[1:],
          curve=SECP256k1
      )

      # Ephemeres Schlüsselpaar für diese Nachricht generieren
      ephemeral_private = SigningKey.generate(curve=SECP256k1)
      ephemeral_public = ephemeral_private.get_verifying_key()

      # ECDH: Shared-Secret berechnen
      shared_point = model_verifying_key.pubkey.point * ephemeral_private.privkey.secret_multiplier
      shared_secret = shared_point.x().to_bytes(32, 'big')

      # AES-Key per HKDF ableiten
      hkdf = HKDF(
          algorithm=hashes.SHA256(),
          length=32,
          salt=None,
          info=HKDF_INFO,
      )
      aes_key = hkdf.derive(shared_secret)

      # Zufällige Nonce
      nonce = os.urandom(12)

      # Mit AES-GCM verschlüsseln
      aesgcm = AESGCM(aes_key)
      ciphertext = aesgcm.encrypt(nonce, plaintext.encode('utf-8'), None)

      # Ephemeren Public Key holen (unkomprimiert: 04 || x || y)
      ephemeral_public_bytes = b'\x04' + ephemeral_public.to_string()

      # Kombinieren: ephemeral_public (65 Bytes) + nonce (12 Bytes) + ciphertext
      result = ephemeral_public_bytes + nonce + ciphertext

      return result.hex()

  def encrypt_messages_for_e2ee(messages: list, model_public_key: str) -> list:
      """Encrypt user and system messages."""
      encrypted_messages = []
      for msg in messages:
          if msg['role'] in ('user', 'system'):
              encrypted_messages.append({
                  **msg,
                  'content': encrypt_message(msg['content'], model_public_key)
              })
          else:
              encrypted_messages.append(msg)
      return encrypted_messages
  ```
</CodeGroup>

### Schritt 5: Request mit E2EE-Headern senden

Erforderliche Header setzen, um E2EE-Processing zu aktivieren.

| Header                        | Beschreibung                                                 |
| ----------------------------- | ------------------------------------------------------------ |
| `X-Venice-TEE-Client-Pub-Key` | Dein ephemerer Public Key (unkomprimiertes Hex, 130 Zeichen) |
| `X-Venice-TEE-Model-Pub-Key`  | Public Key des Modells aus der Attestation                   |
| `X-Venice-TEE-Signing-Algo`   | Immer `ecdsa`                                                |

<CodeGroup>
  ```javascript JavaScript theme={"dark"}
  async function sendE2EERequest(messages, model, e2eeContext, apiKey) {
    // Nachrichten verschlüsseln
    const encryptedMessages = encryptMessagesForE2EE(messages, e2eeContext.modelPublicKey)

    const response = await fetch('https://api.venice.ai/api/v1/chat/completions', {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${apiKey}`,
        'Content-Type': 'application/json',
        // E2EE-Header
        'X-Venice-TEE-Client-Pub-Key': e2eeContext.publicKeyHex,
        'X-Venice-TEE-Model-Pub-Key': e2eeContext.modelPublicKey,
        'X-Venice-TEE-Signing-Algo': 'ecdsa',
      },
      body: JSON.stringify({
        model,
        messages: encryptedMessages,
        stream: true, // E2EE benötigt Streaming
      }),
    })

    return response
  }
  ```

  ```python Python theme={"dark"}
  import requests

  def send_e2ee_request(
      messages: list,
      model: str,
      e2ee_context: dict,
      api_key: str
  ) -> requests.Response:
      """Send an E2EE-encrypted chat completion request."""
      # Nachrichten verschlüsseln
      encrypted_messages = encrypt_messages_for_e2ee(
          messages,
          e2ee_context['model_public_key']
      )

      response = requests.post(
          'https://api.venice.ai/api/v1/chat/completions',
          headers={
              'Authorization': f'Bearer {api_key}',
              'Content-Type': 'application/json',
              # E2EE-Header
              'X-Venice-TEE-Client-Pub-Key': e2ee_context['public_key_hex'],
              'X-Venice-TEE-Model-Pub-Key': e2ee_context['model_public_key'],
              'X-Venice-TEE-Signing-Algo': 'ecdsa'
          },
          json={
              'model': model,
              'messages': encrypted_messages,
              'stream': True  # E2EE benötigt Streaming
          },
          stream=True
      )

      return response
  ```
</CodeGroup>

### Schritt 6: Response-Chunks entschlüsseln

Antworten von E2EE-Modellen sind hex-kodierte verschlüsselte Chunks. Entschlüssele jeden Chunk mit deinem Private Key.

<CodeGroup>
  ```javascript JavaScript theme={"dark"}
  import { gcm } from '@noble/ciphers/aes.js'
  import { hkdf } from '@noble/hashes/hkdf.js'
  import { sha256 } from '@noble/hashes/sha2.js'
  import { ec as EC } from 'elliptic'

  const HKDF_INFO = new TextEncoder().encode('ecdsa_encryption')

  function hexToBytes(hex) {
    const h = hex.startsWith('0x') ? hex.slice(2) : hex
    const bytes = new Uint8Array(h.length / 2)
    for (let i = 0; i < bytes.length; i++) {
      bytes[i] = parseInt(h.substring(i * 2, i * 2 + 2), 16)
    }
    return bytes
  }

  function isHexEncrypted(s) {
    // Minimum: ephemeral_pub (65) + nonce (12) + tag (16) = 93 Bytes = 186 Hex-Zeichen
    if (s.length < 186) return false
    return /^[0-9a-fA-F]+$/.test(s)
  }

  function decryptChunk(ciphertextHex, clientPrivateKey) {
    const raw = hexToBytes(ciphertextHex)

    // Komponenten parsen
    const serverEphemeralPubKey = raw.slice(0, 65)
    const nonce = raw.slice(65, 65 + 12)
    const ciphertext = raw.slice(65 + 12)

    // ECDH mit dem ephemeren Schlüssel des Servers
    const ec = new EC('secp256k1')
    const clientKey = ec.keyFromPrivate(Buffer.from(clientPrivateKey))
    const serverKey = ec.keyFromPublic(Buffer.from(serverEphemeralPubKey))
    const sharedSecret = clientKey.derive(serverKey.getPublic())
    const sharedSecretBytes = new Uint8Array(sharedSecret.toArray('be', 32))

    // AES-Key ableiten
    const aesKey = hkdf(sha256, sharedSecretBytes, undefined, HKDF_INFO, 32)

    // Entschlüsseln
    const cipher = gcm(aesKey, nonce)
    const plaintext = cipher.decrypt(ciphertext)

    return new TextDecoder().decode(plaintext)
  }

  // Streaming-Response verarbeiten
  async function processE2EEStream(response, clientPrivateKey) {
    const reader = response.body.getReader()
    const decoder = new TextDecoder()
    let fullContent = ''

    while (true) {
      const { done, value } = await reader.read()
      if (done) break

      const text = decoder.decode(value)
      const lines = text.split('\n')

      for (const line of lines) {
        if (!line.startsWith('data: ')) continue
        const data = line.slice(6)
        if (data === '[DONE]') continue

        try {
          const chunk = JSON.parse(data)
          const content = chunk.choices?.[0]?.delta?.content

          if (content && isHexEncrypted(content)) {
            const decrypted = decryptChunk(content, clientPrivateKey)
            fullContent += decrypted
            process.stdout.write(decrypted) // Echtzeit-Ausgabe
          } else if (content) {
            fullContent += content
            process.stdout.write(content)
          }
        } catch (e) {
          // Fehlerhafte Chunks überspringen
        }
      }
    }

    return fullContent
  }
  ```

  ```python Python theme={"dark"}
  from cryptography.hazmat.primitives.ciphers.aead import AESGCM
  from cryptography.hazmat.primitives.kdf.hkdf import HKDF
  from cryptography.hazmat.primitives import hashes
  from ecdsa import SECP256k1, VerifyingKey, SigningKey
  import json
  import re

  HKDF_INFO = b'ecdsa_encryption'

  def is_hex_encrypted(s: str) -> bool:
      """Check if string looks like hex-encrypted content."""
      if len(s) < 186:  # Minimum: 65 + 12 + 16 = 93 Bytes = 186 Hex
          return False
      return bool(re.match(r'^[0-9a-fA-F]+$', s))

  def decrypt_chunk(ciphertext_hex: str, client_private_key: bytes) -> str:
      """Decrypt an E2EE response chunk."""
      raw = bytes.fromhex(ciphertext_hex)

      # Komponenten parsen
      server_ephemeral_pub = raw[:65]
      nonce = raw[65:77]
      ciphertext = raw[77:]

      # Ephemeren Public Key des Servers parsen (04-Präfix überspringen)
      server_verifying_key = VerifyingKey.from_string(
          server_ephemeral_pub[1:],
          curve=SECP256k1
      )

      # Private Key des Clients rekonstruieren
      client_signing_key = SigningKey.from_string(client_private_key, curve=SECP256k1)

      # ECDH: Shared-Secret berechnen
      shared_point = server_verifying_key.pubkey.point * client_signing_key.privkey.secret_multiplier
      shared_secret = shared_point.x().to_bytes(32, 'big')

      # AES-Key ableiten
      hkdf = HKDF(
          algorithm=hashes.SHA256(),
          length=32,
          salt=None,
          info=HKDF_INFO,
      )
      aes_key = hkdf.derive(shared_secret)

      # Entschlüsseln
      aesgcm = AESGCM(aes_key)
      plaintext = aesgcm.decrypt(nonce, ciphertext, None)

      return plaintext.decode('utf-8')

  def process_e2ee_stream(response, client_private_key: bytes) -> str:
      """Process streaming E2EE response."""
      full_content = ''

      for line in response.iter_lines():
          if not line:
              continue

          line_str = line.decode('utf-8')
          if not line_str.startswith('data: '):
              continue

          data = line_str[6:]
          if data == '[DONE]':
              continue

          try:
              chunk = json.loads(data)
              content = chunk.get('choices', [{}])[0].get('delta', {}).get('content', '')

              if content and is_hex_encrypted(content):
                  decrypted = decrypt_chunk(content, client_private_key)
                  full_content += decrypted
                  print(decrypted, end='', flush=True)  # Echtzeit-Ausgabe
              elif content:
                  full_content += content
                  print(content, end='', flush=True)
          except json.JSONDecodeError:
              pass

      print()  # Abschluss-Newline
      return full_content
  ```
</CodeGroup>

### Vollständiges funktionierendes Beispiel

<Tabs>
  <Tab title="JavaScript">
    ```javascript theme={"dark"}
    import elliptic from 'elliptic';
    import { gcm } from '@noble/ciphers/aes.js';
    import { hkdf } from '@noble/hashes/hkdf.js';
    import { sha256 } from '@noble/hashes/sha2.js';
    import crypto from 'crypto';

    const EC = elliptic.ec;

    const API_KEY = process.env.API_KEY_VENICE;
    const BASE_URL = 'https://api.venice.ai/api/v1';
    const MODEL = 'e2ee-qwen3-5-122b-a10b';
    const HKDF_INFO = new TextEncoder().encode('ecdsa_encryption');

    function hexToBytes(hex) {
      const bytes = new Uint8Array(hex.length / 2);
      for (let i = 0; i < bytes.length; i++) {
        bytes[i] = parseInt(hex.substring(i * 2, i * 2 + 2), 16);
      }
      return bytes;
    }

    async function main() {
      // Schritt 1: Ephemeres Schlüsselpaar generieren
      console.log('🔑 Generating ephemeral key pair...');
      const ec = new EC('secp256k1');
      const keyPair = ec.genKeyPair();
      const clientPublicKeyHex = keyPair.getPublic('hex');

      // Schritt 2: Attestation abrufen und verifizieren
      console.log('🔍 Fetching TEE attestation...');
      const clientNonce = crypto.randomBytes(32).toString('hex'); // 32 Bytes erforderlich
      const attestationRes = await fetch(
        `${BASE_URL}/tee/attestation?model=${MODEL}&nonce=${clientNonce}`,
        { headers: { Authorization: `Bearer ${API_KEY}` } }
      );
      const attestation = await attestationRes.json();

      if (attestation.verified !== true || attestation.nonce !== clientNonce) {
        throw new Error('Attestation verification failed');
      }

      const modelPublicKey = attestation.signing_key || attestation.signing_public_key;
      console.log('✅ TEE attestation verified');

      // Schritt 3: Nachricht verschlüsseln
      console.log('🔐 Encrypting message...');
      const plaintext = 'What is 2+2? Answer briefly.';

      // Public Key des Modells normalisieren und parsen
      let normalizedKey = modelPublicKey;
      if (!normalizedKey.startsWith('04') && normalizedKey.length === 128) {
        normalizedKey = '04' + normalizedKey;
      }

      const modelKey = ec.keyFromPublic(normalizedKey, 'hex');
      const ephemeralKeyPair = ec.genKeyPair();
      const sharedSecret = ephemeralKeyPair.derive(modelKey.getPublic());
      const sharedSecretBytes = new Uint8Array(sharedSecret.toArray('be', 32));
      const aesKey = hkdf(sha256, sharedSecretBytes, undefined, HKDF_INFO, 32);
      const nonce = crypto.randomBytes(12);
      const cipher = gcm(aesKey, nonce);
      const encrypted = cipher.encrypt(new TextEncoder().encode(plaintext));
      const ephemeralPublic = new Uint8Array(ephemeralKeyPair.getPublic(false, 'array'));

      const result = new Uint8Array(65 + 12 + encrypted.length);
      result.set(ephemeralPublic, 0);
      result.set(nonce, 65);
      result.set(encrypted, 77);

      const encryptedContent = Buffer.from(result).toString('hex');
      const messages = [{ role: 'user', content: encryptedContent }];

      // Schritt 4: E2EE-Request senden
      console.log('📤 Sending encrypted request...');
      const response = await fetch(`${BASE_URL}/chat/completions`, {
        method: 'POST',
        headers: {
          Authorization: `Bearer ${API_KEY}`,
          'Content-Type': 'application/json',
          'X-Venice-TEE-Client-Pub-Key': clientPublicKeyHex,
          'X-Venice-TEE-Model-Pub-Key': modelPublicKey,
          'X-Venice-TEE-Signing-Algo': 'ecdsa',
        },
        body: JSON.stringify({ model: MODEL, messages, stream: true }),
      });

      // Schritt 5: Antwort entschlüsseln
      console.log('📥 Decrypting response...\n');
      const reader = response.body.getReader();
      const decoder = new TextDecoder();

      while (true) {
        const { done, value } = await reader.read();
        if (done) break;

        const text = decoder.decode(value);
        for (const line of text.split('\n')) {
          if (!line.startsWith('data: ') || line.includes('[DONE]')) continue;

          try {
            const chunk = JSON.parse(line.slice(6));
            const content = chunk.choices?.[0]?.delta?.content;
            if (!content) continue;

            if (/^[0-9a-fA-F]+$/.test(content) && content.length >= 186) {
              // Entschlüsseln
              const raw = hexToBytes(content);
              const serverEphemeralPub = raw.slice(0, 65);
              const nonce = raw.slice(65, 77);
              const ciphertext = raw.slice(77);

              const serverKey = ec.keyFromPublic(Buffer.from(serverEphemeralPub));
              const sharedSecret = keyPair.derive(serverKey.getPublic());
              const aesKey = hkdf(sha256, new Uint8Array(sharedSecret.toArray('be', 32)), undefined, HKDF_INFO, 32);
              const cipher = gcm(aesKey, nonce);
              const plaintext = new TextDecoder().decode(cipher.decrypt(ciphertext));
              process.stdout.write(plaintext);
            } else {
              process.stdout.write(content);
            }
          } catch {}
        }
      }

      console.log('\n\n🔐 Response decrypted end-to-end');
    }

    main().catch(console.error);
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={"dark"}
    #!/usr/bin/env python3
    """Complete E2EE implementation example for Venice AI API."""

    import os
    import json
    import secrets
    import requests
    from cryptography.hazmat.primitives.ciphers.aead import AESGCM
    from cryptography.hazmat.primitives.kdf.hkdf import HKDF
    from cryptography.hazmat.primitives import hashes
    from ecdsa import SECP256k1, VerifyingKey, SigningKey

    API_KEY = os.environ.get('API_KEY_VENICE')
    BASE_URL = 'https://api.venice.ai/api/v1'
    MODEL = 'e2ee-qwen3-5-122b-a10b'
    HKDF_INFO = b'ecdsa_encryption'

    def main():
        # Schritt 1: Ephemeres Schlüsselpaar generieren
        print('🔑 Generating ephemeral key pair...')
        private_key = SigningKey.generate(curve=SECP256k1)
        public_key = private_key.get_verifying_key()
        client_public_key_hex = (b'\x04' + public_key.to_string()).hex()

        # Schritt 2: Attestation abrufen und verifizieren
        print('🔍 Fetching TEE attestation...')
        client_nonce = secrets.token_hex(32)  # 32 Bytes erforderlich
        attestation_res = requests.get(
            f'{BASE_URL}/tee/attestation',
            params={'model': MODEL, 'nonce': client_nonce},
            headers={'Authorization': f'Bearer {API_KEY}'},
            timeout=30
        )
        attestation = attestation_res.json()

        if attestation.get('verified') != True or attestation.get('nonce') != client_nonce:
            raise ValueError('Attestation verification failed')

        model_public_key = attestation.get('signing_key') or attestation.get('signing_public_key')
        print(f'✅ TEE attestation verified (provider: {attestation.get("tee_provider", "unknown")})')

        # Schritt 3: Nachricht verschlüsseln
        print('🔐 Encrypting message...')
        plaintext = 'What is 2+2? Answer briefly.'

        # Public Key normalisieren
        key_hex = model_public_key
        if not key_hex.startswith('04') and len(key_hex) == 128:
            key_hex = '04' + key_hex

        model_key_bytes = bytes.fromhex(key_hex)
        model_verifying_key = VerifyingKey.from_string(model_key_bytes[1:], curve=SECP256k1)

        # ECDH
        ephemeral_private = SigningKey.generate(curve=SECP256k1)
        ephemeral_public = ephemeral_private.get_verifying_key()
        shared_point = model_verifying_key.pubkey.point * ephemeral_private.privkey.secret_multiplier
        shared_secret = shared_point.x().to_bytes(32, 'big')

        # AES-Key ableiten
        hkdf = HKDF(algorithm=hashes.SHA256(), length=32, salt=None, info=HKDF_INFO)
        aes_key = hkdf.derive(shared_secret)

        # Verschlüsseln
        nonce = os.urandom(12)
        aesgcm = AESGCM(aes_key)
        ciphertext = aesgcm.encrypt(nonce, plaintext.encode('utf-8'), None)

        ephemeral_public_bytes = b'\x04' + ephemeral_public.to_string()
        result = ephemeral_public_bytes + nonce + ciphertext
        encrypted_content = result.hex()

        messages = [{'role': 'user', 'content': encrypted_content}]

        # Schritt 4: E2EE-Request senden
        print('📤 Sending encrypted request...')
        response = requests.post(
            f'{BASE_URL}/chat/completions',
            headers={
                'Authorization': f'Bearer {API_KEY}',
                'Content-Type': 'application/json',
                'X-Venice-TEE-Client-Pub-Key': client_public_key_hex,
                'X-Venice-TEE-Model-Pub-Key': model_public_key,
                'X-Venice-TEE-Signing-Algo': 'ecdsa'
            },
            json={'model': MODEL, 'messages': messages, 'stream': True},
            stream=True,
            timeout=60
        )

        # Schritt 5: Antwort entschlüsseln
        print('📥 Decrypting response...\n')

        for line in response.iter_lines():
            if not line:
                continue
            line_str = line.decode('utf-8')
            if not line_str.startswith('data: ') or '[DONE]' in line_str:
                continue

            try:
                chunk = json.loads(line_str[6:])
                content = chunk.get('choices', [{}])[0].get('delta', {}).get('content', '')
                if not content:
                    continue

                # Prüfen, ob verschlüsselt
                if len(content) >= 186 and all(c in '0123456789abcdefABCDEF' for c in content):
                    raw = bytes.fromhex(content)
                    server_ephemeral_pub = raw[:65]
                    nonce = raw[65:77]
                    ciphertext = raw[77:]

                    server_verifying_key = VerifyingKey.from_string(server_ephemeral_pub[1:], curve=SECP256k1)
                    shared_point = server_verifying_key.pubkey.point * private_key.privkey.secret_multiplier
                    shared_secret = shared_point.x().to_bytes(32, 'big')

                    hkdf = HKDF(algorithm=hashes.SHA256(), length=32, salt=None, info=HKDF_INFO)
                    aes_key = hkdf.derive(shared_secret)

                    aesgcm = AESGCM(aes_key)
                    plaintext = aesgcm.decrypt(nonce, ciphertext, None)
                    print(plaintext.decode('utf-8'), end='', flush=True)
                else:
                    print(content, end='', flush=True)
            except Exception:
                pass

        print('\n\n🔐 Response decrypted end-to-end')

    if __name__ == '__main__':
        main()
    ```
  </Tab>
</Tabs>

### E2EE-Einschränkungen

<Warning>
  E2EE hat einige Einschränkungen aufgrund der Verschlüsselungsanforderungen:
</Warning>

| Feature              | Status                                                   |
| -------------------- | -------------------------------------------------------- |
| Streaming            | **Pflicht** (Non-Streaming nicht unterstützt)            |
| Web Search           | **Deaktiviert** (würde Inhalte leaken)                   |
| Datei-Uploads        | **Nicht unterstützt**                                    |
| Function Calling     | **Nicht unterstützt**                                    |
| Venice-System-Prompt | **Deaktiviert** (muss clientseitig verschlüsselt werden) |

### Sicherheits-Best-Practices

1. **Pro Session neues Schlüsselpaar** — keine ephemeren Keys wiederverwenden
2. **Private Keys nullen** — Private-Key-Bytes nach Gebrauch aus dem Memory löschen
3. **Attestation verifizieren** — immer `verified: true` und Nonce-Match prüfen
4. **Debug-Modus prüfen** — Attestations von Debug-Enklaven ablehnen
5. **Streaming nutzen** — E2EE benötigt Streaming für korrektes Chunking
6. **Fehler sauber behandeln** — Decryption-Fehler nicht an Nutzer durchreichen
7. **32-Byte-Nonces nutzen** — TEE-Provider verlangen genau 32 Bytes

## Best Practices

<AccordionGroup>
  <Accordion title="In der Produktion immer Attestation verifizieren">
    Verlasse dich nicht nur auf das `verified: true`. Parse den Intel-TDX-Quote clientseitig und prüfe, dass die Messungen den erwarteten Werten entsprechen. Für NVIDIA-GPUs die Attestation über NVIDIAs Verifikationsdienst prüfen.
  </Accordion>

  <Accordion title="Frische Nonces verwenden">
    Für jede Attestation-Anfrage eine neue zufällige Nonce erzeugen. Das verhindert Replay-Angriffe, bei denen ein Angreifer eine veraltete Attestation ausliefern könnte.
  </Accordion>

  <Accordion title="Key-Binding prüfen">
    Der Signing-Key sollte an das TDX-`REPORTDATA`-Feld gebunden sein. Das beweist, dass der Schlüssel innerhalb der Enklave erzeugt wurde.
  </Accordion>

  <Accordion title="Debug-Modus prüfen">
    Sicherstellen, dass die TDX-Attestation keine Debug-Flags gesetzt hat. Eine Debug-Enklave kann inspiziert werden und sollte in der Produktion nicht vertraut werden.
  </Accordion>

  <Accordion title="Für E2EE unsere SDKs nutzen">
    E2EE erfordert sorgfältige kryptografische Implementierung. Nutze unsere offiziellen SDKs, statt das Protokoll selbst zu implementieren.
  </Accordion>
</AccordionGroup>

## Modell-Fähigkeiten prüfen

Du kannst über den Models-Endpoint prüfen, ob ein Modell TEE oder E2EE unterstützt:

<CodeGroup>
  ```bash cURL theme={"dark"}
  curl https://api.venice.ai/api/v1/models \
    -H "Authorization: Bearer $API_KEY_VENICE" | jq '.data[] | select(.model_spec.capabilities.supportsTeeAttestation == true or .model_spec.capabilities.supportsE2EE == true) | {id, tee: .model_spec.capabilities.supportsTeeAttestation, e2ee: .model_spec.capabilities.supportsE2EE}'
  ```

  ```python Python theme={"dark"}
  models = client.models.list()

  for model in models.data:
      caps = getattr(model, 'model_spec', {}).get('capabilities', {})
      if caps.get('supportsTeeAttestation') or caps.get('supportsE2EE'):
          print(f"{model.id}: TEE={caps.get('supportsTeeAttestation')}, E2EE={caps.get('supportsE2EE')}")
  ```
</CodeGroup>

## Fehlerbehandlung

| Fehler                                | Ursache                                         | Lösung                                         |
| ------------------------------------- | ----------------------------------------------- | ---------------------------------------------- |
| `TEE attestation verification failed` | Attestation hat die Validierung nicht bestanden | Erneut versuchen oder Support kontaktieren     |
| `Attestation nonce mismatch`          | Möglicher Replay-Angriff                        | Frische Nonce generieren                       |
| `TDX debug mode detected`             | Enklave ist im Debug-Modus                      | Nicht für Produktion verwenden                 |
| `Failed to decrypt field`             | E2EE-Decryption serverseitig fehlgeschlagen     | Eigene Verschlüsselungs-Implementierung prüfen |
| `E2EE requires streaming`             | Non-Streaming-Request an E2EE-Modell            | `stream: true` setzen                          |
| `Encrypted field is not valid hex`    | Klartext mit E2EE-Headern gesendet              | Alle User-/System-Nachrichten verschlüsseln    |
| `Invalid public key`                  | Falsches Key-Format                             | 130 Hex-Zeichen beginnend mit `04` verwenden   |

## Fehlerbehebung

<AccordionGroup>
  <Accordion title="502 Bad Gateway oder 'Nonce must be exactly 32 bytes'">
    Die Nonce-Länge ist falsch. TEE-Provider verlangen exakt **32 Bytes (64 Hex-Zeichen)**.

    * `crypto.randomBytes(32).toString('hex')` (JS) oder `secrets.token_hex(32)` (Python) verwenden
    * Häufiger Fehler: `secrets.token_hex(16)` erzeugt 32 Hex-Zeichen (16 Bytes), nicht 32 Bytes
  </Accordion>

  <Accordion title="Attestation-Verifikation fehlgeschlagen">
    * Prüfen, ob das Modell E2EE unterstützt (`supportsE2EE: true`)
    * API-Schlüssel-Gültigkeit und Zugriff auf das angeforderte Modell verifizieren
    * Netzwerkverbindung zur Venice-API prüfen
  </Accordion>

  <Accordion title="Decryption fehlgeschlagen">
    * Sicherstellen, dass derselbe Private Key verwendet wird, der den in den Headern gesendeten Public Key erzeugt hat
    * Prüfen, dass der Response-Content tatsächlich hex-kodiert ist (E2EE aktiv)
    * Verifizieren, dass der Model-Public-Key dem für die Verschlüsselung verwendeten entspricht
  </Accordion>

  <Accordion title="Encrypted field is not valid hex">
    * Alle `user`- und `system`-Nachrichten müssen verschlüsselt sein, wenn E2EE-Header vorhanden sind
    * Sicherstellen, dass der verschlüsselte Content die `isValidEncrypted()`-Validierung passiert (mindestens 186 Hex-Zeichen)
    * Prüfen, dass die Verschlüsselungs-Ausgabe lowercase-Hex ohne Präfixe ist
  </Accordion>

  <Accordion title="Invalid public key-Fehler">
    * Client-Public-Key muss exakt **130 Hex-Zeichen** sein und mit `04` beginnen
    * Das Helper-`validateClientPubkey()` vor dem Senden zur Formatprüfung verwenden
    * Sicherstellen, dass unkomprimiertes Public-Key-Format verwendet wird (65 Bytes = 130 Hex-Zeichen)
  </Accordion>

  <Accordion title="Model not found">
    * Modell-ID prüfen und sicherstellen, dass das Modell E2EE unterstützt
    * `/models`-Endpoint nutzen, um verfügbare E2EE-Modelle zu verifizieren
  </Accordion>
</AccordionGroup>

## Ressourcen

* [Intel TDX-Dokumentation](https://www.intel.com/content/www/us/en/developer/tools/trust-domain-extensions/documentation.html)
* [NVIDIA Confidential Computing](https://developer.nvidia.com/confidential-computing)
