Private Inferenz auf Venice mit Trusted Execution Environment (TEE)-Modellen und Ende-zu-Ende-Verschlüsselung — Prompts bleiben für den Host unlesbar.
Venice bietet Privacy-erweiterte Modelle, die in Trusted Execution Environments (TEE) laufen und Ende-zu-Ende-Verschlüsselung (E2EE) unterstützen. Diese Modelle liefern kryptografische Garantien, dass deine Daten privat bleiben — selbst gegenüber Venice.
Modell läuft in einer hardware-gesicherten Enklave. Venice kann nicht auf die Berechnung zugreifen. Du kannst das per Attestation verifizieren.
E2EE
e2ee-*
Vollständige Ende-zu-Ende-Verschlüsselung. Deine Prompts werden clientseitig verschlüsselt, bevor sie gesendet werden. Nur die TEE kann sie entschlüsseln.
E2EE-Modelle umfassen den TEE-Schutz plus clientseitige Verschlüsselung. TEE-Modelle bieten Enklaven-Sicherheit ohne clientseitige Verschlüsselung.
TEE-Modelle laufen in hardware-gesicherten Enklaven (Intel TDX, NVIDIA Confidential Computing). Die Modellgewichte und deine Daten sind vor dem Host-System geschützt — einschließlich Venices Infrastruktur.
Ob die Attestation die serverseitige Verifikation bestanden hat
nonce
Deine Nonce, bestätigt Frische
model
Die attestierte Modell-ID
tee_provider
TEE-Provider-Kennung
intel_quote
Roher Intel-TDX-Quote (base64) für clientseitige Verifikation
nvidia_payload
NVIDIA-GPU-Attestation-Daten (falls zutreffend)
signing_key
Öffentlicher Schlüssel zur Verifikation der Response-Signaturen (typischerweise für E2EE-Flows nötig; bei manchen reinen TEE-Modellen kann er fehlen)
signing_address
Aus dem Signing-Key abgeleitete Ethereum-Adresse
In der Produktion die Attestation clientseitig verifizieren, indem du den Intel-TDX-Quote parst und die NVIDIA-Attestation prüfst.
Für die Verifikation reiner TEE-Modelle reichen signing_address und die serverseitigen Verifikationsfelder für Baseline-Attestation-Checks. Ein signing_key wird benötigt, wenn du clientseitige E2EE-Schlüsselverhandlung und strikte Key-Binding-Checks brauchst.
TEE-Modelle können ihre Antworten signieren und so beweisen, dass die Ausgabe aus der attestierten Enklave stammt:
# Nach einer Completion die Signatur verifizierencurl "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()# Prüfen, ob Signatur zur signing_address aus der Attestation passt
E2EE-Modelle fügen dem TEE-Schutz clientseitige Verschlüsselung hinzu. Deine Prompts werden verschlüsselt, bevor sie dein Gerät verlassen, und nur die TEE kann sie entschlüsseln.Venice E2EE verwendet:
ECDH (Elliptic Curve Diffie-Hellman) auf secp256k1 für Schlüsselaustausch
HKDF-SHA256 für Schlüsselableitung
AES-256-GCM für symmetrische Verschlüsselung
TEE-Attestation, um zu verifizieren, dass das Modell in einer sicheren Enklave läuft
E2EE erfordert eine clientseitige Implementierung. Die Beispiele unten zeigen das vollständige Protokoll.
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') ]# Beispielnutzungmodels = get_e2ee_models('your-api-key')print('E2EE Models:', [m['id'] for m in models])
Verwende diese Helper-Funktionen, um Schlüssel und verschlüsselten Content vor dem Senden zu validieren.
function validateClientPubkey(pubkeyHex) { if (pubkeyHex.length !== 130 || !pubkeyHex.startsWith('04')) { throw new Error(`Client pubkey must be 130 hex chars starting with '04' (got ${pubkeyHex.length})`) }}function isValidEncrypted(s) { // Minimum: ephemeral_pub (65) + nonce (12) + tag (16) = 93 Bytes = 186 Hex-Zeichen return s.length >= 186 && /^[0-9a-fA-F]+$/.test(s)}
def validate_client_pubkey(pubkey_hex: str) -> None: """Validate client public key format.""" if len(pubkey_hex) != 130 or not pubkey_hex.startswith('04'): raise ValueError(f"Client pubkey must be 130 hex chars starting with '04' (got {len(pubkey_hex)})")def is_valid_encrypted(s: str) -> bool: """Check if string is valid hex-encrypted content.""" # Minimum: ephemeral_pub (65) + nonce (12) + tag (16) = 93 Bytes = 186 Hex-Zeichen return len(s) >= 186 and all(c in '0123456789abcdefABCDEF' for c in s)
Schritt 3: TEE-Attestation abrufen und verifizieren
Die Attestation beweist, dass das Modell in einer echten TEE läuft. Immer die Attestation verifizieren, bevor du dem Public Key des Modells vertraust.
Wichtig: Nonce-Länge — Die Client-Nonce muss 32 Bytes (64 Hex-Zeichen) lang sein. Manche TEE-Provider verlangen exakt 32 Bytes und lehnen kürzere Nonces ab.
import crypto from 'crypto'async function fetchAndVerifyAttestation(modelId, apiKey) { // Client-Nonce für Replay-Schutz generieren (32 Bytes = 64 Hex-Zeichen) const clientNonce = crypto.randomBytes(32).toString('hex') const response = await fetch( `https://api.venice.ai/api/v1/tee/attestation?model=${encodeURIComponent(modelId)}&nonce=${clientNonce}`, { headers: { Authorization: `Bearer ${apiKey}` } } ) const attestation = await response.json() // Attestation verifizieren if (attestation.verified !== true) { throw new Error('TEE attestation verification failed on server') } if (attestation.nonce !== clientNonce) { throw new Error('Attestation nonce mismatch - possible replay attack') } // Public Key des Modells für Verschlüsselung holen const modelPublicKey = attestation.signing_key || attestation.signing_public_key if (!modelPublicKey) { throw new Error('No signing key in attestation response') } return { modelPublicKey, signingAddress: attestation.signing_address, attestation, }}
import secretsimport requestsdef fetch_and_verify_attestation(model_id: str, api_key: str) -> dict: """Fetch and verify TEE attestation for a model.""" # Client-Nonce für Replay-Schutz generieren (32 Bytes = 64 Hex-Zeichen) client_nonce = secrets.token_hex(32) response = requests.get( f'https://api.venice.ai/api/v1/tee/attestation', params={'model': model_id, 'nonce': client_nonce}, headers={'Authorization': f'Bearer {api_key}'} ) attestation = response.json() # Attestation verifizieren if attestation.get('verified') != True: raise ValueError('TEE attestation verification failed on server') if attestation.get('nonce') != client_nonce: raise ValueError('Attestation nonce mismatch - possible replay attack') # Public Key des Modells für Verschlüsselung holen model_public_key = attestation.get('signing_key') or attestation.get('signing_public_key') if not model_public_key: raise ValueError('No signing key in attestation response') return { 'model_public_key': model_public_key, 'signing_address': attestation.get('signing_address'), 'attestation': attestation }
User- und System-Nachrichten vor dem Senden verschlüsseln. Nur Nachrichten mit Rolle user und system müssen verschlüsselt werden.
Wenn E2EE-Header gesetzt sind, müssen alle Nachrichten mit Rolle user und system verschlüsselt sein. Sendet du in diesen Rollen Klartext, gibt es einen „Encrypted field is not valid hex”-Fehler.
import { gcm } from '@noble/ciphers/aes.js'import { hkdf } from '@noble/hashes/hkdf.js'import { sha256 } from '@noble/hashes/sha2.js'import { ec as EC } from 'elliptic'import crypto from 'crypto'const HKDF_INFO = new TextEncoder().encode('ecdsa_encryption')function encryptMessage(plaintext, modelPublicKeyHex) { const ec = new EC('secp256k1') // Public Key normalisieren (04-Präfix ggf. ergänzen) let normalizedKey = modelPublicKeyHex if (!normalizedKey.startsWith('04') && normalizedKey.length === 128) { normalizedKey = '04' + normalizedKey } const modelPublicKey = ec.keyFromPublic(normalizedKey, 'hex') // Ephemeres Schlüsselpaar für diese Nachricht generieren const ephemeralKeyPair = ec.genKeyPair() // ECDH-Shared-Secret const sharedSecret = ephemeralKeyPair.derive(modelPublicKey.getPublic()) const sharedSecretBytes = new Uint8Array(sharedSecret.toArray('be', 32)) // AES-Key per HKDF ableiten const aesKey = hkdf(sha256, sharedSecretBytes, undefined, HKDF_INFO, 32) // Zufällige Nonce const nonce = crypto.randomBytes(12) // Mit AES-GCM verschlüsseln const cipher = gcm(aesKey, nonce) const encrypted = cipher.encrypt(new TextEncoder().encode(plaintext)) // Ephemeren Public Key holen (unkomprimiert) const ephemeralPublic = new Uint8Array(ephemeralKeyPair.getPublic(false, 'array')) // Kombinieren: ephemeral_public (65 Bytes) + nonce (12 Bytes) + ciphertext const result = new Uint8Array(65 + 12 + encrypted.length) result.set(ephemeralPublic, 0) result.set(nonce, 65) result.set(encrypted, 65 + 12) return Buffer.from(result).toString('hex')}function encryptMessagesForE2EE(messages, modelPublicKey) { return messages.map(msg => { if (msg.role === 'user' || msg.role === 'system') { return { ...msg, content: encryptMessage(msg.content, modelPublicKey), } } return msg })}
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.""" # Public Key normalisieren key_hex = model_public_key_hex if not key_hex.startswith('04') and len(key_hex) == 128: key_hex = '04' + key_hex model_public_key_bytes = bytes.fromhex(key_hex) # Public Key des Modells parsen (04-Präfix überspringen) model_verifying_key = VerifyingKey.from_string( model_public_key_bytes[1:], curve=SECP256k1 ) # Ephemeres Schlüsselpaar für diese Nachricht generieren ephemeral_private = SigningKey.generate(curve=SECP256k1) ephemeral_public = ephemeral_private.get_verifying_key() # ECDH: Shared-Secret berechnen shared_point = model_verifying_key.pubkey.point * ephemeral_private.privkey.secret_multiplier shared_secret = shared_point.x().to_bytes(32, 'big') # AES-Key per HKDF ableiten hkdf = HKDF( algorithm=hashes.SHA256(), length=32, salt=None, info=HKDF_INFO, ) aes_key = hkdf.derive(shared_secret) # Zufällige Nonce nonce = os.urandom(12) # Mit AES-GCM verschlüsseln aesgcm = AESGCM(aes_key) ciphertext = aesgcm.encrypt(nonce, plaintext.encode('utf-8'), None) # Ephemeren Public Key holen (unkomprimiert: 04 || x || y) ephemeral_public_bytes = b'\x04' + ephemeral_public.to_string() # Kombinieren: ephemeral_public (65 Bytes) + nonce (12 Bytes) + ciphertext result = ephemeral_public_bytes + nonce + ciphertext return result.hex()def encrypt_messages_for_e2ee(messages: list, model_public_key: str) -> list: """Encrypt user and system messages.""" encrypted_messages = [] for msg in messages: if msg['role'] in ('user', 'system'): encrypted_messages.append({ **msg, 'content': encrypt_message(msg['content'], model_public_key) }) else: encrypted_messages.append(msg) return encrypted_messages
Verlasse dich nicht nur auf das verified: true. Parse den Intel-TDX-Quote clientseitig und prüfe, dass die Messungen den erwarteten Werten entsprechen. Für NVIDIA-GPUs die Attestation über NVIDIAs Verifikationsdienst prüfen.
Frische Nonces verwenden
Für jede Attestation-Anfrage eine neue zufällige Nonce erzeugen. Das verhindert Replay-Angriffe, bei denen ein Angreifer eine veraltete Attestation ausliefern könnte.
Key-Binding prüfen
Der Signing-Key sollte an das TDX-REPORTDATA-Feld gebunden sein. Das beweist, dass der Schlüssel innerhalb der Enklave erzeugt wurde.
Debug-Modus prüfen
Sicherstellen, dass die TDX-Attestation keine Debug-Flags gesetzt hat. Eine Debug-Enklave kann inspiziert werden und sollte in der Produktion nicht vertraut werden.
Für E2EE unsere SDKs nutzen
E2EE erfordert sorgfältige kryptografische Implementierung. Nutze unsere offiziellen SDKs, statt das Protokoll selbst zu implementieren.
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')}")