Exécutez une inférence privée sur Venice avec les modèles TEE et le chiffrement de bout en bout qui rendent vos prompts illisibles pour l’hôte.
Venice propose des modèles à confidentialité renforcée qui s’exécutent dans des Trusted Execution Environments (TEE) et prennent en charge le chiffrement de bout en bout (E2EE). Ces modèles offrent des garanties cryptographiques que vos données restent privées — même vis-à-vis de Venice.
Le modèle s’exécute dans une enclave sécurisée matériellement. Venice ne peut pas accéder au calcul. Vous pouvez le vérifier par attestation.
E2EE
e2ee-*
Chiffrement de bout en bout complet. Vos prompts sont chiffrés côté client avant l’envoi. Seul le TEE peut les déchiffrer.
Les modèles E2EE incluent la protection TEE plus le chiffrement côté client. Les modèles TEE fournissent la sécurité de l’enclave sans nécessiter de chiffrement côté client.
Les modèles TEE s’exécutent à l’intérieur d’enclaves sécurisées matériellement (Intel TDX, NVIDIA Confidential Computing). Les poids du modèle et vos données sont protégés du système hôte — y compris l’infrastructure de Venice.
Indique si l’attestation a passé la vérification côté serveur
nonce
Votre nonce, confirmant la fraîcheur
model
L’ID du modèle attesté
tee_provider
Identifiant du fournisseur TEE
intel_quote
Quote Intel TDX brut (base64) pour vérification côté client
nvidia_payload
Données d’attestation GPU NVIDIA (le cas échéant)
signing_key
Clé publique pour vérifier les signatures de réponse (généralement requise pour les flux E2EE ; peut être omise pour certains modèles TEE simples)
signing_address
Adresse Ethereum dérivée de la clé de signature
Pour un usage en production, vérifiez l’attestation côté client en parsant le quote Intel TDX et en vérifiant l’attestation NVIDIA.
Pour la vérification d’un modèle TEE simple, signing_address et les champs de vérification côté serveur suffisent pour des contrôles d’attestation de base. Une signing_key est requise lorsque vous avez besoin d’un accord de clé E2EE côté client et de contrôles stricts de liaison de clé.
Les modèles TEE peuvent signer leurs réponses, prouvant que la sortie provient de l’enclave attestée :
# Après avoir obtenu une completion, vérifier la signaturecurl "https://api.venice.ai/api/v1/tee/signature?model=tee-qwen3-5-122b-a10b&request_id=chatcmpl-abc123" \ -H "Authorization: Bearer $API_KEY_VENICE"
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()# Vérifier que la signature correspond à signing_address de l'attestation
Les modèles E2EE ajoutent un chiffrement côté client par-dessus la protection TEE. Vos prompts sont chiffrés avant de quitter votre appareil, et seul le TEE peut les déchiffrer.L’E2EE Venice utilise :
ECDH (Elliptic Curve Diffie-Hellman) sur secp256k1 pour l’échange de clés
HKDF-SHA256 pour la dérivation de clés
AES-256-GCM pour le chiffrement symétrique
Attestation TEE pour vérifier que le modèle s’exécute dans une enclave sécurisée
L’E2EE nécessite une implémentation côté client. Les exemples ci-dessous montrent le protocole complet.
import requestsdef 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') ]# Exemple d'utilisationmodels = get_e2ee_models('your-api-key')print('E2EE Models:', [m['id'] for m in models])
Générez une nouvelle paire de clés pour chaque session. La clé privée doit rester en mémoire uniquement et être effacée de manière sécurisée après usage.
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'), // Format non compressé (65 octets hex) }}// Sécurité : remplir la clé privée de zéros une fois terminéfunction zeroFill(arr) { arr.fill(0)}
Utilisez ces fonctions helper pour valider les clés et le contenu chiffré avant d’envoyer les requêtes.
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 octets = 186 caractères hex return s.length >= 186 && /^[0-9a-fA-F]+$/.test(s)}
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 octets = 186 caractères hex return len(s) >= 186 and all(c in '0123456789abcdefABCDEF' for c in s)
L’attestation prouve que le modèle s’exécute dans un véritable TEE. Vérifiez toujours l’attestation avant de faire confiance à la clé publique du modèle.
Important : longueur du nonce — Le nonce client doit faire 32 octets (64 caractères hex). Certains fournisseurs TEE exigent exactement 32 octets et rejettent les nonces plus courts.
import crypto from 'crypto'async function fetchAndVerifyAttestation(modelId, apiKey) { // Générer un nonce client pour la protection anti-rejeu (32 octets = 64 caractères 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() // Vérifier l'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') } // Obtenir la clé publique du modèle pour le chiffrement 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, }}
import secretsimport requestsdef fetch_and_verify_attestation(model_id: str, api_key: str) -> dict: """Fetch and verify TEE attestation for a model.""" # Générer un nonce client pour la protection anti-rejeu (32 octets = 64 caractères hex) 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() # Vérifier l'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') # Obtenir la clé publique du modèle pour le chiffrement 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 }
Chiffrez les messages utilisateur et système avant l’envoi. Seuls les messages des rôles user et system doivent être chiffrés.
Lorsque les en-têtes E2EE sont présents, tous les messages des rôles user et system doivent être chiffrés. Envoyer du contenu en clair dans ces rôles entraînera une erreur « Encrypted field is not valid hex ».
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') // Normaliser la clé publique (ajouter le préfixe 04 si nécessaire) let normalizedKey = modelPublicKeyHex if (!normalizedKey.startsWith('04') && normalizedKey.length === 128) { normalizedKey = '04' + normalizedKey } const modelPublicKey = ec.keyFromPublic(normalizedKey, 'hex') // Générer une paire de clés éphémères pour ce message const ephemeralKeyPair = ec.genKeyPair() // Secret partagé ECDH const sharedSecret = ephemeralKeyPair.derive(modelPublicKey.getPublic()) const sharedSecretBytes = new Uint8Array(sharedSecret.toArray('be', 32)) // Dériver la clé AES via HKDF const aesKey = hkdf(sha256, sharedSecretBytes, undefined, HKDF_INFO, 32) // Générer un nonce aléatoire const nonce = crypto.randomBytes(12) // Chiffrer avec AES-GCM const cipher = gcm(aesKey, nonce) const encrypted = cipher.encrypt(new TextEncoder().encode(plaintext)) // Obtenir la clé publique éphémère (non compressée) const ephemeralPublic = new Uint8Array(ephemeralKeyPair.getPublic(false, 'array')) // Combiner : ephemeral_public (65 octets) + nonce (12 octets) + 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 })}
from cryptography.hazmat.primitives.ciphers.aead import AESGCMfrom cryptography.hazmat.primitives.kdf.hkdf import HKDFfrom cryptography.hazmat.primitives import hashesfrom ecdsa import SECP256k1, VerifyingKey, SigningKeyimport osHKDF_INFO = b'ecdsa_encryption'def encrypt_message(plaintext: str, model_public_key_hex: str) -> str: """Encrypt a message using ECDH + HKDF + AES-GCM.""" # Normaliser la clé publique 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) # Parser la clé publique du modèle (sauter le préfixe 04) model_verifying_key = VerifyingKey.from_string( model_public_key_bytes[1:], curve=SECP256k1 ) # Générer une paire de clés éphémères pour ce message ephemeral_private = SigningKey.generate(curve=SECP256k1) ephemeral_public = ephemeral_private.get_verifying_key() # ECDH : calculer le secret partagé shared_point = model_verifying_key.pubkey.point * ephemeral_private.privkey.secret_multiplier shared_secret = shared_point.x().to_bytes(32, 'big') # Dériver la clé AES via HKDF hkdf = HKDF( algorithm=hashes.SHA256(), length=32, salt=None, info=HKDF_INFO, ) aes_key = hkdf.derive(shared_secret) # Générer un nonce aléatoire nonce = os.urandom(12) # Chiffrer avec AES-GCM aesgcm = AESGCM(aes_key) ciphertext = aesgcm.encrypt(nonce, plaintext.encode('utf-8'), None) # Obtenir la clé publique éphémère (non compressée : 04 || x || y) ephemeral_public_bytes = b'\x04' + ephemeral_public.to_string() # Combiner : ephemeral_public (65 octets) + nonce (12 octets) + 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
Ne vous contentez pas de faire confiance à la réponse verified: true. Parsez le quote Intel TDX côté client et vérifiez que les mesures correspondent aux valeurs attendues. Pour les GPU NVIDIA, vérifiez l’attestation via le service de vérification de NVIDIA.
Utilisez des nonces frais
Générez toujours un nouveau nonce aléatoire pour chaque requête d’attestation. Cela empêche les attaques par rejeu, où un attaquant pourrait servir une attestation périmée.
Vérifiez la liaison de clé
La clé de signature doit être liée au champ REPORTDATA de TDX. Cela prouve que la clé a été générée à l’intérieur de l’enclave.
Cherchez le mode debug
Vérifiez que l’attestation TDX n’a pas de flags debug activés. Une enclave en debug peut être inspectée et ne doit pas être considérée comme fiable pour la production.
Utilisez nos SDKs pour l'E2EE
L’E2EE nécessite une implémentation cryptographique minutieuse. Utilisez nos SDK officiels plutôt que d’implémenter le protocole vous-même.
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')}")