> ## 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 模型

> 采用可信执行环境与端到端加密的隐私增强 AI

Venice 提供运行在可信执行环境（TEE）中并支持端到端加密（E2EE）的隐私增强模型。这些模型为您的数据保密提供了密码学保证——即使是 Venice 也无法访问。

## 了解隐私级别

| 类型       | 前缀       | 含义                                                          |
| -------- | -------- | ----------------------------------------------------------- |
| **TEE**  | `tee-*`  | 模型在硬件安全 enclave 中运行。Venice 无法访问运算过程。您可以通过证明（attestation）验证。 |
| **E2EE** | `e2ee-*` | 完整的端到端加密。您的 prompt 在发送前会在客户端加密。只有 TEE 能够解密。                 |

<Info>
  E2EE 模型在 TEE 保护之上加入了客户端加密。TEE 模型提供 enclave 安全性，无需客户端加密。
</Info>

## 可用模型

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

查看[模型页面](/models/overview)获取包含定价和上下文限制的完整列表。

## TEE 模型

TEE 模型在硬件安全 enclave（Intel TDX、NVIDIA Confidential Computing）中运行。模型权重和您的数据受到保护，不会被主机系统访问——包括 Venice 的基础设施。

### 基础用法

TEE 模型的使用方式与常规模型完全相同：

<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 证明

您可以通过获取模型的证明报告，以密码学方式验证模型正在真实的 TEE 中运行：

<CodeGroup>
  ```bash cURL theme={"dark"}
  # Generate a random nonce (prevents replay attacks)
  NONCE=$(openssl rand -hex 16)

  # Fetch 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={"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>

证明响应包含：

| 字段                | 说明                                      |
| ----------------- | --------------------------------------- |
| `verified`        | 证明是否通过了服务端验证                            |
| `nonce`           | 您的 nonce，用于确认新鲜性                        |
| `model`           | 被证明的模型 ID                               |
| `tee_provider`    | TEE 提供商标识符                              |
| `intel_quote`     | 用于客户端验证的原始 Intel TDX quote（base64）      |
| `nvidia_payload`  | NVIDIA GPU 证明数据（如适用）                    |
| `signing_key`     | 用于验证响应签名的公钥（通常 E2EE 流程必需；某些纯 TEE 模型可省略） |
| `signing_address` | 从签名密钥派生的以太坊地址                           |

<Tip>
  在生产用途中，请在客户端通过解析 Intel TDX quote 并检查 NVIDIA 证明来验证证明。
</Tip>

<Note>
  对于纯 TEE 模型验证，`signing_address` 和服务端验证字段足以进行基础证明检查。当您需要客户端 E2EE 密钥协商和严格的密钥绑定检查时，需要 `signing_key`。
</Note>

### 响应签名

TEE 模型可以对其响应进行签名，证明输出来自被证明的 enclave：

<CodeGroup>
  ```bash cURL theme={"dark"}
  # After getting a completion, verify the signature
  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()
  # Verify signature matches the signing_address from attestation
  ```
</CodeGroup>

## E2EE 模型

E2EE 模型在 TEE 保护之上增加了客户端加密。您的 prompt 在离开设备之前被加密，只有 TEE 能够解密。

Venice E2EE 使用：

* **ECDH（椭圆曲线 Diffie-Hellman）** 基于 secp256k1 进行密钥交换
* **HKDF-SHA256** 用于密钥派生
* **AES-256-GCM** 用于对称加密
* **TEE 证明**用于验证模型运行在安全 enclave 中

<Warning>
  E2EE 需要客户端实现。下面的示例展示了完整协议。
</Warning>

### E2EE 的工作方式

<Steps>
  <Step title="生成临时密钥对">
    客户端为此会话生成 secp256k1 密钥对。
  </Step>

  <Step title="获取 TEE 证明">
    客户端请求 `/api/v1/tee/attestation` 并接收模型的公钥、证明证据和 nonce。
  </Step>

  <Step title="验证证明">
    客户端检查 nonce 匹配、debug 模式被禁用以及证明有效性。
  </Step>

  <Step title="加密消息">
    客户端使用 ECDH 共享秘密 → HKDF → AES-GCM 加密 prompt。
  </Step>

  <Step title="发送请求">
    客户端发送带 E2EE 头部（`X-Venice-TEE-Client-Pub-Key`、`X-Venice-TEE-Model-Pub-Key`、`X-Venice-TEE-Signing-Algo`）的请求。
  </Step>

  <Step title="TEE 处理">
    TEE 解密请求、处理它并加密响应。
  </Step>

  <Step title="解密响应">
    客户端接收加密的 chunk 并使用私钥解密。
  </Step>
</Steps>

### 前置条件

**JavaScript（Node.js ESM）：**

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

**Python：**

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

### 步骤 1：检查模型 E2EE 支持

首先，通过检查 `/models` 端点验证模型是否支持 E2EE。

<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)
  }

  // Example usage
  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')
      ]

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

### 步骤 2：生成临时密钥对

为每个会话生成新的密钥对。私钥应仅保留在内存中，并在使用后安全清零。

<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'), // Uncompressed format (65 bytes hex)
    }
  }

  // Security: Zero-fill private key when done
  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()

      # Get uncompressed public key (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 chars
      }
  ```
</CodeGroup>

#### 验证辅助函数

在发送请求之前使用这些辅助函数验证密钥和加密内容。

<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 chars
    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 chars
      return len(s) >= 186 and all(c in '0123456789abcdefABCDEF' for c in s)
  ```
</CodeGroup>

### 步骤 3：获取并验证 TEE 证明

证明证明模型正在真实的 TEE 中运行。在信任模型的公钥之前，请始终验证证明。

<Info>
  **重要：Nonce 长度** - 客户端 nonce 必须是 **32 字节（64 个十六进制字符）**。某些 TEE 提供商要求恰好 32 字节，并会拒绝更短的 nonce。
</Info>

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

  async function fetchAndVerifyAttestation(modelId, apiKey) {
    // Generate client nonce for replay protection (32 bytes = 64 hex chars)
    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()

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

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

### 步骤 4：加密消息

在发送之前加密用户和系统消息。只有 `user` 和 `system` 角色的消息需要加密。

<Warning>
  当存在 E2EE 头部时，**所有** `user` 和 `system` 角色的消息都必须加密。在这些角色中发送任何明文内容将导致 "Encrypted field is not valid hex" 错误。
</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')

    // Normalize public key (add 04 prefix if needed)
    let normalizedKey = modelPublicKeyHex
    if (!normalizedKey.startsWith('04') && normalizedKey.length === 128) {
      normalizedKey = '04' + normalizedKey
    }

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

    // Generate ephemeral key pair for this message
    const ephemeralKeyPair = ec.genKeyPair()

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

    // Derive AES key using HKDF
    const aesKey = hkdf(sha256, sharedSecretBytes, undefined, HKDF_INFO, 32)

    // Generate random nonce
    const nonce = crypto.randomBytes(12)

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

    // Get ephemeral public key (uncompressed)
    const ephemeralPublic = new Uint8Array(ephemeralKeyPair.getPublic(false, 'array'))

    // Combine: 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."""
      # 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>

### 步骤 5：使用 E2EE 头部发送请求

包含所需的头部以启用 E2EE 处理。

| Header                        | 说明                      |
| ----------------------------- | ----------------------- |
| `X-Venice-TEE-Client-Pub-Key` | 您的临时公钥（未压缩十六进制，130 个字符） |
| `X-Venice-TEE-Model-Pub-Key`  | 来自证明的模型公钥               |
| `X-Venice-TEE-Signing-Algo`   | 始终为 `ecdsa`             |

<CodeGroup>
  ```javascript JavaScript theme={"dark"}
  async function sendE2EERequest(messages, model, e2eeContext, apiKey) {
    // Encrypt messages
    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 headers
        '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 requires 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."""
      # 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>

### 步骤 6：解密响应 chunk

来自 E2EE 模型的响应是十六进制编码的加密 chunk。使用您的私钥解密每个 chunk。

<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 chars
    if (s.length < 186) return false
    return /^[0-9a-fA-F]+$/.test(s)
  }

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

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

    // ECDH with server's ephemeral key
    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))

    // Derive AES key
    const aesKey = hkdf(sha256, sharedSecretBytes, undefined, HKDF_INFO, 32)

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

    return new TextDecoder().decode(plaintext)
  }

  // Process streaming response
  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) // Real-time output
          } else if (content) {
            fullContent += content
            process.stdout.write(content)
          }
        } catch (e) {
          // Skip malformed chunks
        }
      }
    }

    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)

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

### 完整工作示例

<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() {
      // Step 1: Generate ephemeral key pair
      console.log('🔑 Generating ephemeral key pair...');
      const ec = new EC('secp256k1');
      const keyPair = ec.genKeyPair();
      const clientPublicKeyHex = keyPair.getPublic('hex');

      // Step 2: Fetch and verify attestation
      console.log('🔍 Fetching TEE attestation...');
      const clientNonce = crypto.randomBytes(32).toString('hex'); // 32 bytes required
      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');

      // Step 3: Encrypt message
      console.log('🔐 Encrypting message...');
      const plaintext = 'What is 2+2? Answer briefly.';

      // Normalize and parse model's public key
      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 }];

      // Step 4: Send E2EE request
      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 }),
      });

      // Step 5: Decrypt response
      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) {
              // Decrypt
              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():
        # 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>

### E2EE 限制

<Warning>
  由于加密要求，E2EE 存在一些限制：
</Warning>

| 功能               | 状态               |
| ---------------- | ---------------- |
| Streaming        | **必需**（不支持非流式）   |
| Web search       | **禁用**（会泄露内容）    |
| 文件上传             | **不支持**          |
| Function calling | **不支持**          |
| Venice 系统 prompt | **禁用**（必须在客户端加密） |

### 安全最佳实践

1. **每个会话生成新的密钥对** - 不要复用临时密钥
2. **清零私钥** - 使用完成后从内存中清除私钥字节
3. **验证证明** - 始终检查 `verified: true` 和 nonce 匹配
4. **检查 debug 模式** - 拒绝来自 debug enclave 的证明
5. **使用流式传输** - E2EE 需要流式传输以正确分块加密
6. **优雅处理错误** - 不要向用户暴露解密错误
7. **使用 32 字节 nonce** - TEE 提供商要求恰好 32 字节

## 最佳实践

<AccordionGroup>
  <Accordion title="生产环境中始终验证证明">
    不要仅信任 `verified: true` 响应。在客户端解析 Intel TDX quote 并验证测量值是否与预期值匹配。对于 NVIDIA GPU，通过 NVIDIA 的验证服务检查证明。
  </Accordion>

  <Accordion title="使用新鲜的 nonce">
    始终为每个证明请求生成新的随机 nonce。这可以防止攻击者提供过时证明的重放攻击。
  </Accordion>

  <Accordion title="验证密钥绑定">
    签名密钥应该绑定到 TDX REPORTDATA 字段。这证明密钥是在 enclave 内部生成的。
  </Accordion>

  <Accordion title="检查 debug 模式">
    验证 TDX 证明没有设置 debug 标志。debug enclave 可以被检查，不应被信任用于生产环境。
  </Accordion>

  <Accordion title="对 E2EE 使用我们的 SDK">
    E2EE 需要谨慎的密码学实现。请使用我们的官方 SDK 而不是自己实现协议。
  </Accordion>
</AccordionGroup>

## 检查模型能力

您可以通过 models 端点检查模型是否支持 TEE 或 E2EE：

<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>

## 错误处理

| 错误                                    | 原因                  | 解决方案                     |
| ------------------------------------- | ------------------- | ------------------------ |
| `TEE attestation verification failed` | 证明未通过验证             | 重试或联系支持                  |
| `Attestation nonce mismatch`          | 可能的重放攻击             | 生成新的 nonce               |
| `TDX debug mode detected`             | enclave 处于 debug 模式 | 不要用于生产环境                 |
| `Failed to decrypt field`             | E2EE 解密在服务端失败       | 检查您的加密实现                 |
| `E2EE requires streaming`             | 对 E2EE 模型发送非流式请求    | 设置 `stream: true`        |
| `Encrypted field is not valid hex`    | 与 E2EE 头部一起发送了明文    | 加密所有 user/system 消息      |
| `Invalid public key`                  | 错误的密钥格式             | 使用 130 个十六进制字符并以 `04` 开头 |

## 故障排查

<AccordionGroup>
  <Accordion title="502 Bad Gateway 或 'Nonce must be exactly 32 bytes'">
    nonce 长度不正确。TEE 提供商要求恰好 **32 字节（64 个十六进制字符）**。

    * 使用 `crypto.randomBytes(32).toString('hex')`（JS）或 `secrets.token_hex(32)`（Python）
    * 常见错误：`secrets.token_hex(16)` 产生 32 个十六进制字符（16 字节），而非 32 字节
  </Accordion>

  <Accordion title="证明验证失败">
    * 检查模型是否支持 E2EE（`supportsE2EE: true`）
    * 验证您的 API 密钥有效且可访问请求的模型
    * 验证到 Venice API 的网络连接
  </Accordion>

  <Accordion title="解密失败">
    * 确保您使用的是生成头部中发送的公钥的相同私钥
    * 检查响应内容是否确实是十六进制编码（E2EE 处于激活状态）
    * 验证模型公钥与用于加密的密钥匹配
  </Accordion>

  <Accordion title="Encrypted field is not valid hex">
    * 当存在 E2EE 头部时，所有 `user` 和 `system` 角色的消息都必须加密
    * 验证您的加密内容通过 `isValidEncrypted()` 验证（最少 186 个十六进制字符）
    * 检查加密输出是小写十六进制且没有任何前缀
  </Accordion>

  <Accordion title="无效公钥错误">
    * 客户端公钥必须恰好是以 `04` 开头的 **130 个十六进制字符**
    * 使用 `validateClientPubkey()` 辅助函数在发送前验证格式
    * 确保您使用未压缩的公钥格式（65 字节 = 130 个十六进制字符）
  </Accordion>

  <Accordion title="找不到模型">
    * 验证模型 ID 正确且模型支持 E2EE
    * 使用 `/models` 端点验证可用的 E2EE 模型
  </Accordion>
</AccordionGroup>

## 资源

* [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)
