Venice 提供运行在可信执行环境(TEE)中并支持端到端加密(E2EE)的隐私增强模型。这些模型为您的数据保密提供了密码学保证——即使是 Venice 也无法访问。
了解隐私级别
类型 前缀 含义 TEE tee-*模型在硬件安全 enclave 中运行。Venice 无法访问运算过程。您可以通过证明(attestation)验证。 E2EE e2ee-*完整的端到端加密。您的 prompt 在发送前会在客户端加密。只有 TEE 能够解密。
E2EE 模型在 TEE 保护之上加入了客户端加密。TEE 模型提供 enclave 安全性,无需客户端加密。
可用模型
Loading…
查看模型页面 获取包含定价和上下文限制的完整列表。
TEE 模型
TEE 模型在硬件安全 enclave(Intel TDX、NVIDIA Confidential Computing)中运行。模型权重和您的数据受到保护,不会被主机系统访问——包括 Venice 的基础设施。
基础用法
TEE 模型的使用方式与常规模型完全相同:
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)
验证 TEE 证明
您可以通过获取模型的证明报告,以密码学方式验证模型正在真实的 TEE 中运行:
# 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 "
证明响应包含:
字段 说明 verified证明是否通过了服务端验证 nonce您的 nonce,用于确认新鲜性 model被证明的模型 ID tee_providerTEE 提供商标识符 intel_quote用于客户端验证的原始 Intel TDX quote(base64) nvidia_payloadNVIDIA GPU 证明数据(如适用) signing_key用于验证响应签名的公钥(通常 E2EE 流程必需;某些纯 TEE 模型可省略) signing_address从签名密钥派生的以太坊地址
在生产用途中,请在客户端通过解析 Intel TDX quote 并检查 NVIDIA 证明来验证证明。
对于纯 TEE 模型验证,signing_address 和服务端验证字段足以进行基础证明检查。当您需要客户端 E2EE 密钥协商和严格的密钥绑定检查时,需要 signing_key。
响应签名
TEE 模型可以对其响应进行签名,证明输出来自被证明的 enclave:
# 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 "
E2EE 模型
E2EE 模型在 TEE 保护之上增加了客户端加密。您的 prompt 在离开设备之前被加密,只有 TEE 能够解密。
Venice E2EE 使用:
ECDH(椭圆曲线 Diffie-Hellman) 基于 secp256k1 进行密钥交换
HKDF-SHA256 用于密钥派生
AES-256-GCM 用于对称加密
TEE 证明 用于验证模型运行在安全 enclave 中
E2EE 需要客户端实现。下面的示例展示了完整协议。
E2EE 的工作方式
生成临时密钥对
客户端为此会话生成 secp256k1 密钥对。
获取 TEE 证明
客户端请求 /api/v1/tee/attestation 并接收模型的公钥、证明证据和 nonce。
验证证明
客户端检查 nonce 匹配、debug 模式被禁用以及证明有效性。
加密消息
客户端使用 ECDH 共享秘密 → HKDF → AES-GCM 加密 prompt。
发送请求
客户端发送带 E2EE 头部(X-Venice-TEE-Client-Pub-Key、X-Venice-TEE-Model-Pub-Key、X-Venice-TEE-Signing-Algo)的请求。
解密响应
客户端接收加密的 chunk 并使用私钥解密。
前置条件
JavaScript(Node.js ESM):
npm install elliptic @noble/ciphers @noble/hashes
Python:
pip install cryptography ecdsa requests
步骤 1:检查模型 E2EE 支持
首先,通过检查 /models 端点验证模型是否支持 E2EE。
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', ...]
步骤 2:生成临时密钥对
为每个会话生成新的密钥对。私钥应仅保留在内存中,并在使用后安全清零。
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 )
}
验证辅助函数
在发送请求之前使用这些辅助函数验证密钥和加密内容。
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 )
}
步骤 3:获取并验证 TEE 证明
证明证明模型正在真实的 TEE 中运行。在信任模型的公钥之前,请始终验证证明。
重要:Nonce 长度 - 客户端 nonce 必须是 32 字节(64 个十六进制字符) 。某些 TEE 提供商要求恰好 32 字节,并会拒绝更短的 nonce。
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 ,
}
}
步骤 4:加密消息
在发送之前加密用户和系统消息。只有 user 和 system 角色的消息需要加密。
当存在 E2EE 头部时,所有 user 和 system 角色的消息都必须加密。在这些角色中发送任何明文内容将导致 “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' )
// 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
})
}
步骤 5:使用 E2EE 头部发送请求
包含所需的头部以启用 E2EE 处理。
Header 说明 X-Venice-TEE-Client-Pub-Key您的临时公钥(未压缩十六进制,130 个字符) X-Venice-TEE-Model-Pub-Key来自证明的模型公钥 X-Venice-TEE-Signing-Algo始终为 ecdsa
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
}
步骤 6:解密响应 chunk
来自 E2EE 模型的响应是十六进制编码的加密 chunk。使用您的私钥解密每个 chunk。
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
}
完整工作示例
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 );
#!/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()
E2EE 限制
功能 状态 Streaming 必需 (不支持非流式)Web search 禁用 (会泄露内容)文件上传 不支持 Function calling 不支持 Venice 系统 prompt 禁用 (必须在客户端加密)
安全最佳实践
每个会话生成新的密钥对 - 不要复用临时密钥
清零私钥 - 使用完成后从内存中清除私钥字节
验证证明 - 始终检查 verified: true 和 nonce 匹配
检查 debug 模式 - 拒绝来自 debug enclave 的证明
使用流式传输 - E2EE 需要流式传输以正确分块加密
优雅处理错误 - 不要向用户暴露解密错误
使用 32 字节 nonce - TEE 提供商要求恰好 32 字节
最佳实践
不要仅信任 verified: true 响应。在客户端解析 Intel TDX quote 并验证测量值是否与预期值匹配。对于 NVIDIA GPU,通过 NVIDIA 的验证服务检查证明。
始终为每个证明请求生成新的随机 nonce。这可以防止攻击者提供过时证明的重放攻击。
签名密钥应该绑定到 TDX REPORTDATA 字段。这证明密钥是在 enclave 内部生成的。
验证 TDX 证明没有设置 debug 标志。debug enclave 可以被检查,不应被信任用于生产环境。
E2EE 需要谨慎的密码学实现。请使用我们的官方 SDK 而不是自己实现协议。
检查模型能力
您可以通过 models 端点检查模型是否支持 TEE 或 E2EE:
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}'
错误处理
错误 原因 解决方案 TEE attestation verification failed证明未通过验证 重试或联系支持 Attestation nonce mismatch可能的重放攻击 生成新的 nonce TDX debug mode detectedenclave 处于 debug 模式 不要用于生产环境 Failed to decrypt fieldE2EE 解密在服务端失败 检查您的加密实现 E2EE requires streaming对 E2EE 模型发送非流式请求 设置 stream: true Encrypted field is not valid hex与 E2EE 头部一起发送了明文 加密所有 user/system 消息 Invalid public key错误的密钥格式 使用 130 个十六进制字符并以 04 开头
故障排查
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 字节
检查模型是否支持 E2EE(supportsE2EE: true)
验证您的 API 密钥有效且可访问请求的模型
验证到 Venice API 的网络连接
确保您使用的是生成头部中发送的公钥的相同私钥
检查响应内容是否确实是十六进制编码(E2EE 处于激活状态)
验证模型公钥与用于加密的密钥匹配
Encrypted field is not valid hex
当存在 E2EE 头部时,所有 user 和 system 角色的消息都必须加密
验证您的加密内容通过 isValidEncrypted() 验证(最少 186 个十六进制字符)
检查加密输出是小写十六进制且没有任何前缀
客户端公钥必须恰好是以 04 开头的 130 个十六进制字符
使用 validateClientPubkey() 辅助函数在发送前验证格式
确保您使用未压缩的公钥格式(65 字节 = 130 个十六进制字符)
验证模型 ID 正确且模型支持 E2EE
使用 /models 端点验证可用的 E2EE 模型