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

# Modelli TEE & E2EE

> AI con privacy migliorata grazie a Trusted Execution Environments e End-to-End Encryption

Venice offre modelli con privacy migliorata che vengono eseguiti in Trusted Execution Environments (TEE) e supportano l'End-to-End Encryption (E2EE). Questi modelli forniscono garanzie crittografiche che i tuoi dati rimangano privati, anche da Venice.

## Comprendere i livelli di privacy

| Tipo     | Prefisso | Cosa significa                                                                                                                     |
| -------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| **TEE**  | `tee-*`  | Il modello viene eseguito in un'enclave protetta hardware. Venice non può accedere al calcolo. Puoi verificarlo con l'attestation. |
| **E2EE** | `e2ee-*` | End-to-end encryption completa. I tuoi prompt vengono cifrati lato client prima di essere inviati. Solo il TEE può decifrarli.     |

<Info>
  I modelli E2EE includono la protezione TEE più la cifratura lato client. I modelli TEE forniscono la sicurezza dell'enclave senza richiedere la cifratura lato client.
</Info>

## Modelli disponibili

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

Consulta la [pagina Models](/overview/models) per l'elenco completo con prezzi e limiti di contesto.

## Modelli TEE

I modelli TEE vengono eseguiti all'interno di enclavi protette hardware (Intel TDX, NVIDIA Confidential Computing). I pesi del modello e i tuoi dati sono protetti dal sistema host, inclusa l'infrastruttura di Venice.

### Utilizzo di base

I modelli TEE funzionano esattamente come i modelli regolari:

<CodeGroup>
  ```python Python theme={"system"}
  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={"system"}
  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={"system"}
  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>

### Verifica dell'attestation TEE

Puoi verificare crittograficamente che un modello sia in esecuzione in un TEE genuino recuperando il suo report di attestation:

<CodeGroup>
  ```bash cURL theme={"system"}
  # Genera un nonce casuale (previene attacchi replay)
  NONCE=$(openssl rand -hex 16)

  # Recupera l'attestation
  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={"system"}
  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>

La risposta di attestation include:

| Campo             | Descrizione                                                                                                                                         |
| ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| `verified`        | Se l'attestation ha superato la verifica lato server                                                                                                |
| `nonce`           | Il tuo nonce, a conferma della freschezza                                                                                                           |
| `model`           | L'ID del modello attestato                                                                                                                          |
| `tee_provider`    | Identificatore del provider TEE                                                                                                                     |
| `intel_quote`     | Quote Intel TDX raw (base64) per la verifica lato client                                                                                            |
| `nvidia_payload`  | Dati di attestation NVIDIA GPU (se applicabile)                                                                                                     |
| `signing_key`     | Chiave pubblica per verificare le firme delle risposte (tipicamente richiesta per i flussi E2EE; può essere omessa per alcuni modelli TEE semplici) |
| `signing_address` | Indirizzo Ethereum derivato dalla chiave di firma                                                                                                   |

<Tip>
  Per l'uso in produzione, verifica l'attestation lato client effettuando il parsing del quote Intel TDX e controllando l'attestation NVIDIA.
</Tip>

<Note>
  Per la verifica di un modello TEE semplice, `signing_address` e i campi di verifica lato server sono sufficienti per i controlli di attestation di base. Una `signing_key` è richiesta quando hai bisogno del key agreement E2EE lato client e di controlli rigorosi di key-binding.
</Note>

### Firme delle risposte

I modelli TEE possono firmare le loro risposte, dimostrando che l'output proviene dall'enclave attestata:

<CodeGroup>
  ```bash cURL theme={"system"}
  # Dopo aver ottenuto un completion, verifica la firma
  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={"system"}
  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()
  # Verifica che la firma corrisponda al signing_address dall'attestation
  ```
</CodeGroup>

## Modelli E2EE

I modelli E2EE aggiungono la cifratura lato client sopra la protezione TEE. I tuoi prompt vengono cifrati prima di lasciare il tuo dispositivo, e solo il TEE può decifrarli.

Venice E2EE usa:

* **ECDH (Elliptic Curve Diffie-Hellman)** su secp256k1 per lo scambio di chiavi
* **HKDF-SHA256** per la derivazione delle chiavi
* **AES-256-GCM** per la cifratura simmetrica
* **TEE attestation** per verificare che il modello sia in esecuzione in un'enclave sicura

<Warning>
  E2EE richiede un'implementazione lato client. Gli esempi seguenti mostrano il protocollo completo.
</Warning>

### Come funziona E2EE

<Steps>
  <Step title="Genera coppia di chiavi effimere">
    Il client genera una coppia di chiavi secp256k1 per questa sessione.
  </Step>

  <Step title="Recupera attestation TEE">
    Il client richiede `/api/v1/tee/attestation` e riceve la chiave pubblica del modello, le evidenze di attestation e il nonce.
  </Step>

  <Step title="Verifica attestation">
    Il client controlla la corrispondenza del nonce, che la modalità debug sia disabilitata e la validità dell'attestation.
  </Step>

  <Step title="Cifra messaggi">
    Il client cifra i prompt usando lo shared secret ECDH → HKDF → AES-GCM.
  </Step>

  <Step title="Invia richiesta">
    Il client invia la richiesta con gli header E2EE (`X-Venice-TEE-Client-Pub-Key`, `X-Venice-TEE-Model-Pub-Key`, `X-Venice-TEE-Signing-Algo`).
  </Step>

  <Step title="Elaborazione TEE">
    Il TEE decifra la richiesta, la elabora e cifra la risposta.
  </Step>

  <Step title="Decifra risposta">
    Il client riceve chunk cifrati e li decifra con la chiave privata.
  </Step>
</Steps>

### Prerequisiti

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

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

**Python:**

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

### Passo 1: Verifica il supporto E2EE del modello

Prima di tutto, verifica che il modello supporti E2EE controllando l'endpoint `/models`.

<CodeGroup>
  ```javascript JavaScript theme={"system"}
  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)
  }

  // Esempio d'uso
  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={"system"}
  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')
      ]

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

### Passo 2: Genera una coppia di chiavi effimere

Genera una nuova coppia di chiavi per ogni sessione. La chiave privata deve essere mantenuta solo in memoria e azzerata in modo sicuro dopo l'uso.

<CodeGroup>
  ```javascript JavaScript theme={"system"}
  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'), // Formato non compresso (65 byte hex)
    }
  }

  // Sicurezza: azzera la chiave privata quando hai finito
  function zeroFill(arr) {
    arr.fill(0)
  }
  ```

  ```python Python theme={"system"}
  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()

      # Get uncompressed public key (04 || x || y)
      public_key_bytes = b'\x04' + public_key.to_string()

      return {
          'private_key': private_key.to_string(),  # 32 byte
          'public_key_hex': public_key_bytes.hex()  # 130 caratteri hex
      }
  ```
</CodeGroup>

#### Helper di validazione

Usa queste funzioni helper per validare le chiavi e i contenuti cifrati prima di inviare le richieste.

<CodeGroup>
  ```javascript JavaScript theme={"system"}
  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) {
    // Minimo: ephemeral_pub (65) + nonce (12) + tag (16) = 93 byte = 186 caratteri hex
    return s.length >= 186 && /^[0-9a-fA-F]+$/.test(s)
  }
  ```

  ```python Python theme={"system"}
  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 chars
      return len(s) >= 186 and all(c in '0123456789abcdefABCDEF' for c in s)
  ```
</CodeGroup>

### Passo 3: Recupera e verifica l'attestation TEE

L'attestation dimostra che il modello è in esecuzione in un TEE genuino. Verifica sempre l'attestation prima di fidarti della chiave pubblica del modello.

<Info>
  **Importante: lunghezza del nonce** - Il nonce del client deve essere di **32 byte (64 caratteri hex)**. Alcuni provider TEE richiedono esattamente 32 byte e rifiuteranno nonce più corti.
</Info>

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

  async function fetchAndVerifyAttestation(modelId, apiKey) {
    // Genera nonce client per la protezione contro replay (32 byte = 64 caratteri hex)
    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()

    // Verifica attestation
    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')
    }

    // Ottieni la chiave pubblica del modello per la cifratura
    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={"system"}
  import secrets
  import requests

  def fetch_and_verify_attestation(model_id: str, api_key: str) -> dict:
      """Fetch and verify TEE attestation for a model."""
      # Generate client nonce for replay protection (32 bytes = 64 hex chars)
      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()

      # Verify attestation
      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')

      # Get model's public key for encryption
      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>

### Passo 4: Cifra i messaggi

Cifra i messaggi user e system prima di inviarli. Solo i messaggi con ruolo `user` e `system` devono essere cifrati.

<Warning>
  Quando gli header E2EE sono presenti, **tutti** i messaggi con ruolo `user` e `system` devono essere cifrati. L'invio di qualsiasi contenuto in chiaro in questi ruoli produrrà un errore "Encrypted field is not valid hex".
</Warning>

<CodeGroup>
  ```javascript JavaScript theme={"system"}
  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')

    // Normalizza la chiave pubblica (aggiungi il prefisso 04 se necessario)
    let normalizedKey = modelPublicKeyHex
    if (!normalizedKey.startsWith('04') && normalizedKey.length === 128) {
      normalizedKey = '04' + normalizedKey
    }

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

    // Genera una coppia di chiavi effimere per questo messaggio
    const ephemeralKeyPair = ec.genKeyPair()

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

    // Deriva la chiave AES usando HKDF
    const aesKey = hkdf(sha256, sharedSecretBytes, undefined, HKDF_INFO, 32)

    // Genera un nonce casuale
    const nonce = crypto.randomBytes(12)

    // Cifra con AES-GCM
    const cipher = gcm(aesKey, nonce)
    const encrypted = cipher.encrypt(new TextEncoder().encode(plaintext))

    // Ottieni la chiave pubblica effimera (non compressa)
    const ephemeralPublic = new Uint8Array(ephemeralKeyPair.getPublic(false, 'array'))

    // Combina: ephemeral_public (65 byte) + nonce (12 byte) + 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={"system"}
  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."""
      # Normalize public key
      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)

      # Parse model's public key (skip 04 prefix)
      model_verifying_key = VerifyingKey.from_string(
          model_public_key_bytes[1:],
          curve=SECP256k1
      )

      # Generate ephemeral key pair for this message
      ephemeral_private = SigningKey.generate(curve=SECP256k1)
      ephemeral_public = ephemeral_private.get_verifying_key()

      # ECDH: compute shared secret
      shared_point = model_verifying_key.pubkey.point * ephemeral_private.privkey.secret_multiplier
      shared_secret = shared_point.x().to_bytes(32, 'big')

      # Derive AES key using HKDF
      hkdf = HKDF(
          algorithm=hashes.SHA256(),
          length=32,
          salt=None,
          info=HKDF_INFO,
      )
      aes_key = hkdf.derive(shared_secret)

      # Generate random nonce
      nonce = os.urandom(12)

      # Encrypt with AES-GCM
      aesgcm = AESGCM(aes_key)
      ciphertext = aesgcm.encrypt(nonce, plaintext.encode('utf-8'), None)

      # Get ephemeral public key (uncompressed: 04 || x || y)
      ephemeral_public_bytes = b'\x04' + ephemeral_public.to_string()

      # Combine: 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>

### Passo 5: Invia la richiesta con gli header E2EE

Includi gli header richiesti per abilitare l'elaborazione E2EE.

| Header                        | Descrizione                                                        |
| ----------------------------- | ------------------------------------------------------------------ |
| `X-Venice-TEE-Client-Pub-Key` | La tua chiave pubblica effimera (hex non compresso, 130 caratteri) |
| `X-Venice-TEE-Model-Pub-Key`  | Chiave pubblica del modello dall'attestation                       |
| `X-Venice-TEE-Signing-Algo`   | Sempre `ecdsa`                                                     |

<CodeGroup>
  ```javascript JavaScript theme={"system"}
  async function sendE2EERequest(messages, model, e2eeContext, apiKey) {
    // Cifra i messaggi
    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',
        // Header E2EE
        '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 richiede lo streaming
      }),
    })

    return response
  }
  ```

  ```python Python theme={"system"}
  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."""
      # Encrypt messages
      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 headers
              '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 requires streaming
          },
          stream=True
      )

      return response
  ```
</CodeGroup>

### Passo 6: Decifra i chunk della risposta

Le risposte dei modelli E2EE sono chunk cifrati codificati in hex. Decifra ogni chunk usando la tua chiave privata.

<CodeGroup>
  ```javascript JavaScript theme={"system"}
  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) {
    // Minimo: ephemeral_pub (65) + nonce (12) + tag (16) = 93 byte = 186 caratteri hex
    if (s.length < 186) return false
    return /^[0-9a-fA-F]+$/.test(s)
  }

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

    // Effettua il parsing dei componenti
    const serverEphemeralPubKey = raw.slice(0, 65)
    const nonce = raw.slice(65, 65 + 12)
    const ciphertext = raw.slice(65 + 12)

    // ECDH con la chiave effimera del server
    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))

    // Deriva la chiave AES
    const aesKey = hkdf(sha256, sharedSecretBytes, undefined, HKDF_INFO, 32)

    // Decifra
    const cipher = gcm(aesKey, nonce)
    const plaintext = cipher.decrypt(ciphertext)

    return new TextDecoder().decode(plaintext)
  }

  // Elabora la risposta in streaming
  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) // Output in tempo reale
          } else if (content) {
            fullContent += content
            process.stdout.write(content)
          }
        } catch (e) {
          // Salta i chunk malformati
        }
      }
    }

    return fullContent
  }
  ```

  ```python Python theme={"system"}
  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)

      # Parse components
      server_ephemeral_pub = raw[:65]
      nonce = raw[65:77]
      ciphertext = raw[77:]

      # Parse server's ephemeral public key (skip 04 prefix)
      server_verifying_key = VerifyingKey.from_string(
          server_ephemeral_pub[1:],
          curve=SECP256k1
      )

      # Reconstruct client's private key
      client_signing_key = SigningKey.from_string(client_private_key, curve=SECP256k1)

      # ECDH: compute shared secret
      shared_point = server_verifying_key.pubkey.point * client_signing_key.privkey.secret_multiplier
      shared_secret = shared_point.x().to_bytes(32, 'big')

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

      # Decrypt
      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)  # Real-time output
              elif content:
                  full_content += content
                  print(content, end='', flush=True)
          except json.JSONDecodeError:
              pass

      print()  # Final newline
      return full_content
  ```
</CodeGroup>

### Esempio completo funzionante

<Tabs>
  <Tab title="JavaScript">
    ```javascript theme={"system"}
    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() {
      // Passo 1: Genera coppia di chiavi effimere
      console.log('🔑 Generating ephemeral key pair...');
      const ec = new EC('secp256k1');
      const keyPair = ec.genKeyPair();
      const clientPublicKeyHex = keyPair.getPublic('hex');

      // Passo 2: Recupera e verifica l'attestation
      console.log('🔍 Fetching TEE attestation...');
      const clientNonce = crypto.randomBytes(32).toString('hex'); // 32 byte richiesti
      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');

      // Passo 3: Cifra il messaggio
      console.log('🔐 Encrypting message...');
      const plaintext = 'What is 2+2? Answer briefly.';

      // Normalizza ed effettua il parsing della chiave pubblica del modello
      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 }];

      // Passo 4: Invia richiesta E2EE
      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 }),
      });

      // Passo 5: Decifra la risposta
      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) {
              // Decifra
              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={"system"}
    #!/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():
        # Step 1: Generate ephemeral key pair
        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()

        # Step 2: Fetch and verify attestation
        print('🔍 Fetching TEE attestation...')
        client_nonce = secrets.token_hex(32)  # 32 bytes required
        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")})')

        # Step 3: Encrypt message
        print('🔐 Encrypting message...')
        plaintext = 'What is 2+2? Answer briefly.'

        # Normalize public key
        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')

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

        # Encrypt
        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}]

        # Step 4: Send E2EE request
        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
        )

        # Step 5: Decrypt response
        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

                # Check if encrypted
                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>

### Limitazioni di E2EE

<Warning>
  E2EE ha alcuni vincoli dovuti ai requisiti di cifratura:
</Warning>

| Funzionalità             | Stato                                              |
| ------------------------ | -------------------------------------------------- |
| Streaming                | **Obbligatorio** (non-streaming non supportato)    |
| Ricerca web              | **Disabilitata** (esporrebbe il contenuto)         |
| Upload di file           | **Non supportato**                                 |
| Function calling         | **Non supportato**                                 |
| Prompt di sistema Venice | **Disabilitato** (deve essere cifrato lato client) |

### Best practice di sicurezza

1. **Genera nuove coppie di chiavi per ogni sessione** - Non riutilizzare chiavi effimere
2. **Azzera le chiavi private** - Cancella i byte della chiave privata dalla memoria quando hai finito
3. **Verifica l'attestation** - Controlla sempre `verified: true` e la corrispondenza del nonce
4. **Controlla la modalità debug** - Rifiuta le attestation da enclavi in debug
5. **Usa lo streaming** - E2EE richiede lo streaming per la corretta segmentazione della cifratura
6. **Gestisci gli errori con eleganza** - Non esporre errori di decifratura agli utenti
7. **Usa nonce da 32 byte** - I provider TEE richiedono esattamente 32 byte

## Best practice

<AccordionGroup>
  <Accordion title="Verifica sempre l'attestation in produzione">
    Non fidarti solo della risposta `verified: true`. Effettua il parsing del quote Intel TDX lato client e verifica che le misurazioni corrispondano ai valori attesi. Per le GPU NVIDIA, controlla l'attestation tramite il servizio di verifica NVIDIA.
  </Accordion>

  <Accordion title="Usa nonce freschi">
    Genera sempre un nuovo nonce casuale per ogni richiesta di attestation. Questo previene attacchi replay in cui un attaccante potrebbe servire un'attestation obsoleta.
  </Accordion>

  <Accordion title="Verifica il key binding">
    La chiave di firma dovrebbe essere legata al campo TDX REPORTDATA. Questo dimostra che la chiave è stata generata all'interno dell'enclave.
  </Accordion>

  <Accordion title="Controlla la modalità debug">
    Verifica che l'attestation TDX non abbia flag di debug impostati. Un'enclave in debug può essere ispezionata e non dovrebbe essere ritenuta affidabile per la produzione.
  </Accordion>

  <Accordion title="Usa i nostri SDK per E2EE">
    E2EE richiede un'implementazione crittografica attenta. Usa i nostri SDK ufficiali invece di implementare il protocollo da solo.
  </Accordion>
</AccordionGroup>

## Verifica delle capacità del modello

Puoi controllare se un modello supporta TEE o E2EE tramite l'endpoint models:

<CodeGroup>
  ```bash cURL theme={"system"}
  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={"system"}
  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>

## Gestione degli errori

| Errore                                | Causa                                        | Soluzione                                     |
| ------------------------------------- | -------------------------------------------- | --------------------------------------------- |
| `TEE attestation verification failed` | L'attestation non ha superato la validazione | Riprova o contatta il supporto                |
| `Attestation nonce mismatch`          | Possibile attacco replay                     | Genera un nonce fresco                        |
| `TDX debug mode detected`             | L'enclave è in modalità debug                | Non usare per produzione                      |
| `Failed to decrypt field`             | Decifratura E2EE fallita lato server         | Controlla la tua implementazione di cifratura |
| `E2EE requires streaming`             | Richiesta non-streaming a un modello E2EE    | Imposta `stream: true`                        |
| `Encrypted field is not valid hex`    | Testo in chiaro inviato con header E2EE      | Cifra tutti i messaggi user/system            |
| `Invalid public key`                  | Formato di chiave errato                     | Usa 130 caratteri hex che iniziano con `04`   |

## Troubleshooting

<AccordionGroup>
  <Accordion title="502 Bad Gateway o 'Nonce must be exactly 32 bytes'">
    La lunghezza del nonce non è corretta. I provider TEE richiedono esattamente **32 byte (64 caratteri hex)**.

    * Usa `crypto.randomBytes(32).toString('hex')` (JS) o `secrets.token_hex(32)` (Python)
    * Errore comune: `secrets.token_hex(16)` produce 32 caratteri hex (16 byte), non 32 byte
  </Accordion>

  <Accordion title="Verifica dell'attestation fallita">
    * Controlla che il modello supporti E2EE (`supportsE2EE: true`)
    * Verifica che la tua API key sia valida e abbia accesso al modello richiesto
    * Verifica la connettività di rete con l'API Venice
  </Accordion>

  <Accordion title="Decifratura fallita">
    * Assicurati di usare la stessa chiave privata che ha generato la chiave pubblica inviata negli header
    * Controlla che il contenuto della risposta sia effettivamente codificato in hex (E2EE attivo)
    * Verifica che la chiave pubblica del modello corrisponda a quella usata per la cifratura
  </Accordion>

  <Accordion title="Encrypted field is not valid hex">
    * Tutti i messaggi con ruolo `user` e `system` devono essere cifrati quando gli header E2EE sono presenti
    * Verifica che il tuo contenuto cifrato superi la validazione `isValidEncrypted()` (minimo 186 caratteri hex)
    * Controlla che l'output della cifratura sia hex minuscolo senza prefissi
  </Accordion>

  <Accordion title="Errori di Invalid public key">
    * La chiave pubblica del client deve essere esattamente **130 caratteri hex** che iniziano con `04`
    * Usa l'helper `validateClientPubkey()` per verificare il formato prima dell'invio
    * Assicurati di usare il formato di chiave pubblica non compressa (65 byte = 130 caratteri hex)
  </Accordion>

  <Accordion title="Modello non trovato">
    * Verifica che l'ID del modello sia corretto e che il modello supporti E2EE
    * Usa l'endpoint `/models` per verificare i modelli E2EE disponibili
  </Accordion>
</AccordionGroup>

## Risorse

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