Vai al contenuto principale
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

TipoPrefissoCosa significa
TEEtee-*Il modello viene eseguito in un’enclave protetta hardware. Venice non può accedere al calcolo. Puoi verificarlo con l’attestation.
E2EEe2ee-*End-to-end encryption completa. I tuoi prompt vengono cifrati lato client prima di essere inviati. Solo il TEE può decifrarli.
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.

Modelli disponibili

Caricamento…
Consulta la pagina 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:
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)

Verifica dell’attestation TEE

Puoi verificare crittograficamente che un modello sia in esecuzione in un TEE genuino recuperando il suo report di attestation:
# 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"
La risposta di attestation include:
CampoDescrizione
verifiedSe l’attestation ha superato la verifica lato server
nonceIl tuo nonce, a conferma della freschezza
modelL’ID del modello attestato
tee_providerIdentificatore del provider TEE
intel_quoteQuote Intel TDX raw (base64) per la verifica lato client
nvidia_payloadDati di attestation NVIDIA GPU (se applicabile)
signing_keyChiave pubblica per verificare le firme delle risposte (tipicamente richiesta per i flussi E2EE; può essere omessa per alcuni modelli TEE semplici)
signing_addressIndirizzo Ethereum derivato dalla chiave di firma
Per l’uso in produzione, verifica l’attestation lato client effettuando il parsing del quote Intel TDX e controllando l’attestation NVIDIA.
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.

Firme delle risposte

I modelli TEE possono firmare le loro risposte, dimostrando che l’output proviene dall’enclave attestata:
# 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"

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
E2EE richiede un’implementazione lato client. Gli esempi seguenti mostrano il protocollo completo.

Come funziona E2EE

1

Genera coppia di chiavi effimere

Il client genera una coppia di chiavi secp256k1 per questa sessione.
2

Recupera attestation TEE

Il client richiede /api/v1/tee/attestation e riceve la chiave pubblica del modello, le evidenze di attestation e il nonce.
3

Verifica attestation

Il client controlla la corrispondenza del nonce, che la modalità debug sia disabilitata e la validità dell’attestation.
4

Cifra messaggi

Il client cifra i prompt usando lo shared secret ECDH → HKDF → AES-GCM.
5

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).
6

Elaborazione TEE

Il TEE decifra la richiesta, la elabora e cifra la risposta.
7

Decifra risposta

Il client riceve chunk cifrati e li decifra con la chiave privata.

Prerequisiti

JavaScript (Node.js ESM):
npm install elliptic @noble/ciphers @noble/hashes
Python:
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.
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', ...]

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

Helper di validazione

Usa queste funzioni helper per validare le chiavi e i contenuti cifrati prima di inviare le richieste.
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)
}

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.
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.
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,
  }
}

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

Passo 5: Invia la richiesta con gli header E2EE

Includi gli header richiesti per abilitare l’elaborazione E2EE.
HeaderDescrizione
X-Venice-TEE-Client-Pub-KeyLa tua chiave pubblica effimera (hex non compresso, 130 caratteri)
X-Venice-TEE-Model-Pub-KeyChiave pubblica del modello dall’attestation
X-Venice-TEE-Signing-AlgoSempre ecdsa
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
}

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

Esempio completo funzionante

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

Limitazioni di E2EE

E2EE ha alcuni vincoli dovuti ai requisiti di cifratura:
FunzionalitàStato
StreamingObbligatorio (non-streaming non supportato)
Ricerca webDisabilitata (esporrebbe il contenuto)
Upload di fileNon supportato
Function callingNon supportato
Prompt di sistema VeniceDisabilitato (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

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.
Genera sempre un nuovo nonce casuale per ogni richiesta di attestation. Questo previene attacchi replay in cui un attaccante potrebbe servire un’attestation obsoleta.
La chiave di firma dovrebbe essere legata al campo TDX REPORTDATA. Questo dimostra che la chiave è stata generata all’interno dell’enclave.
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.
E2EE richiede un’implementazione crittografica attenta. Usa i nostri SDK ufficiali invece di implementare il protocollo da solo.

Verifica delle capacità del modello

Puoi controllare se un modello supporta TEE o E2EE tramite l’endpoint models:
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}'

Gestione degli errori

ErroreCausaSoluzione
TEE attestation verification failedL’attestation non ha superato la validazioneRiprova o contatta il supporto
Attestation nonce mismatchPossibile attacco replayGenera un nonce fresco
TDX debug mode detectedL’enclave è in modalità debugNon usare per produzione
Failed to decrypt fieldDecifratura E2EE fallita lato serverControlla la tua implementazione di cifratura
E2EE requires streamingRichiesta non-streaming a un modello E2EEImposta stream: true
Encrypted field is not valid hexTesto in chiaro inviato con header E2EECifra tutti i messaggi user/system
Invalid public keyFormato di chiave erratoUsa 130 caratteri hex che iniziano con 04

Troubleshooting

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
  • 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
  • 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
  • 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
  • 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)
  • Verifica che l’ID del modello sia corretto e che il modello supporti E2EE
  • Usa l’endpoint /models per verificare i modelli E2EE disponibili

Risorse