Saltar al contenido principal
Venice ofrece modelos con privacidad mejorada que se ejecutan en entornos de ejecución confiables (TEE) y admiten cifrado de extremo a extremo (E2EE). Estos modelos proporcionan garantías criptográficas de que tus datos permanecen privados, incluso frente a Venice.

Comprendiendo los niveles de privacidad

TipoPrefijoQué significa
TEEtee-*El modelo se ejecuta en un enclave protegido por hardware. Venice no puede acceder al cómputo. Puedes verificarlo mediante atestación.
E2EEe2ee-*Cifrado completo de extremo a extremo. Tus prompts se cifran del lado del cliente antes de enviarse. Solo el TEE puede descifrarlos.
Los modelos E2EE incluyen protección TEE más cifrado del lado del cliente. Los modelos TEE proporcionan seguridad de enclave sin requerir cifrado del lado del cliente.

Modelos disponibles

Cargando…
Consulta la página de Modelos para ver la lista completa con precios y límites de contexto.

Modelos TEE

Los modelos TEE se ejecutan dentro de enclaves protegidos por hardware (Intel TDX, NVIDIA Confidential Computing). Los pesos del modelo y tus datos están protegidos frente al sistema anfitrión, incluida la infraestructura de Venice.

Uso básico

Los modelos TEE funcionan exactamente igual que los modelos normales:
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)

Verificación de la atestación TEE

Puedes verificar criptográficamente que un modelo se está ejecutando en un TEE genuino obteniendo su informe de atestación:
# Genera un nonce aleatorio (evita ataques de repetición)
NONCE=$(openssl rand -hex 16)

# Obtén la atestación
curl "https://api.venice.ai/api/v1/tee/attestation?model=tee-qwen3-5-122b-a10b&nonce=$NONCE" \
  -H "Authorization: Bearer $API_KEY_VENICE"
La respuesta de atestación incluye:
CampoDescripción
verifiedSi la atestación pasó la verificación del lado del servidor
nonceTu nonce, que confirma la frescura
modelEl ID del modelo atestado
tee_providerIdentificador del proveedor del TEE
intel_quoteCita Intel TDX en bruto (base64) para verificación del lado del cliente
nvidia_payloadDatos de atestación de GPU NVIDIA (si aplica)
signing_keyClave pública para verificar las firmas de respuesta (normalmente requerida en flujos E2EE; puede omitirse en algunos modelos TEE simples)
signing_addressDirección de Ethereum derivada de la clave de firma
En entornos de producción, verifica la atestación del lado del cliente parseando la cita Intel TDX y comprobando la atestación de NVIDIA.
Para la verificación de un modelo TEE simple, signing_address y los campos de verificación del lado del servidor son suficientes para las comprobaciones básicas de atestación. Se requiere un signing_key cuando necesitas el acuerdo de claves E2EE del lado del cliente y comprobaciones estrictas de vinculación de claves.

Firmas de respuesta

Los modelos TEE pueden firmar sus respuestas, demostrando que la salida provino del enclave atestado:
# Tras obtener una completación, 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"

Modelos E2EE

Los modelos E2EE añaden cifrado del lado del cliente sobre la protección TEE. Tus prompts se cifran antes de salir de tu dispositivo, y solo el TEE puede descifrarlos. E2EE de Venice utiliza:
  • ECDH (Elliptic Curve Diffie-Hellman) sobre secp256k1 para el intercambio de claves
  • HKDF-SHA256 para la derivación de claves
  • AES-256-GCM para el cifrado simétrico
  • Atestación TEE para verificar que el modelo se ejecuta en un enclave seguro
E2EE requiere implementación del lado del cliente. Los ejemplos a continuación muestran el protocolo completo.

Cómo funciona E2EE

1

Generar par de claves efímeras

El cliente genera un par de claves secp256k1 para esta sesión.
2

Obtener atestación TEE

El cliente solicita /api/v1/tee/attestation y recibe la clave pública del modelo, la evidencia de atestación y el nonce.
3

Verificar la atestación

El cliente comprueba la coincidencia del nonce, que el modo de depuración esté deshabilitado y la validez de la atestación.
4

Cifrar mensajes

El cliente cifra los prompts utilizando un secreto compartido ECDH → HKDF → AES-GCM.
5

Enviar solicitud

El cliente envía la solicitud con cabeceras E2EE (X-Venice-TEE-Client-Pub-Key, X-Venice-TEE-Model-Pub-Key, X-Venice-TEE-Signing-Algo).
6

Procesamiento en el TEE

El TEE descifra la solicitud, la procesa y cifra la respuesta.
7

Descifrar la respuesta

El cliente recibe fragmentos cifrados y los descifra con la clave privada.

Requisitos previos

JavaScript (Node.js ESM):
npm install elliptic @noble/ciphers @noble/hashes
Python:
pip install cryptography ecdsa requests

Paso 1: Verificar el soporte de E2EE del modelo

Primero, verifica que el modelo admite E2EE consultando el 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)
}

// Ejemplo de uso
const models = await getE2EEModels('your-api-key')
console.log('E2EE Models:', models.map(m => m.id))
// Salida: ['e2ee-qwen3-5-122b-a10b', 'e2ee-glm-5', ...]

Paso 2: Generar par de claves efímeras

Genera un nuevo par de claves para cada sesión. La clave privada debe mantenerse solo en memoria y borrarse de forma segura tras su 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 no comprimido (65 bytes en hex)
  }
}

// Seguridad: rellena con ceros la clave privada cuando termines
function zeroFill(arr) {
  arr.fill(0)
}

Ayudantes de validación

Usa estas funciones auxiliares para validar las claves y el contenido cifrado antes de enviar las solicitudes.
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) {
  // Mínimo: ephemeral_pub (65) + nonce (12) + tag (16) = 93 bytes = 186 caracteres hex
  return s.length >= 186 && /^[0-9a-fA-F]+$/.test(s)
}

Paso 3: Obtener y verificar la atestación TEE

La atestación demuestra que el modelo se está ejecutando en un TEE genuino. Verifica siempre la atestación antes de confiar en la clave pública del modelo.
Importante: longitud del nonce — El nonce del cliente debe ser de 32 bytes (64 caracteres hexadecimales). Algunos proveedores de TEE requieren exactamente 32 bytes y rechazarán nonces más cortos.
import crypto from 'crypto'

async function fetchAndVerifyAttestation(modelId, apiKey) {
  // Genera un nonce de cliente para protección contra repetición (32 bytes = 64 caracteres 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 la atestación
  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')
  }

  // Obtén la clave pública del modelo para cifrar
  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,
  }
}

Paso 4: Cifrar los mensajes

Cifra los mensajes de usuario y de sistema antes de enviarlos. Solo los mensajes con rol user y system necesitan cifrarse.
Cuando hay cabeceras E2EE presentes, todos los mensajes con rol user y system deben estar cifrados. Enviar contenido en texto plano en estos roles dará lugar a un error “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')

  // Normaliza la clave pública (añade el prefijo 04 si es necesario)
  let normalizedKey = modelPublicKeyHex
  if (!normalizedKey.startsWith('04') && normalizedKey.length === 128) {
    normalizedKey = '04' + normalizedKey
  }

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

  // Genera un par de claves efímeras para este mensaje
  const ephemeralKeyPair = ec.genKeyPair()

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

  // Deriva la clave AES usando HKDF
  const aesKey = hkdf(sha256, sharedSecretBytes, undefined, HKDF_INFO, 32)

  // Genera un nonce aleatorio
  const nonce = crypto.randomBytes(12)

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

  // Obtén la clave pública efímera (no comprimida)
  const ephemeralPublic = new Uint8Array(ephemeralKeyPair.getPublic(false, 'array'))

  // Combina: 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
  })
}

Paso 5: Enviar la solicitud con cabeceras E2EE

Incluye las cabeceras requeridas para habilitar el procesamiento E2EE.
CabeceraDescripción
X-Venice-TEE-Client-Pub-KeyTu clave pública efímera (hex no comprimido, 130 caracteres)
X-Venice-TEE-Model-Pub-KeyClave pública del modelo obtenida de la atestación
X-Venice-TEE-Signing-AlgoSiempre ecdsa
async function sendE2EERequest(messages, model, e2eeContext, apiKey) {
  // Cifra los mensajes
  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',
      // Cabeceras 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 requiere streaming
    }),
  })

  return response
}

Paso 6: Descifrar los fragmentos de respuesta

Las respuestas de los modelos E2EE son fragmentos cifrados codificados en hexadecimal. Descifra cada fragmento con tu clave privada.
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) {
  // Mínimo: ephemeral_pub (65) + nonce (12) + tag (16) = 93 bytes = 186 caracteres hex
  if (s.length < 186) return false
  return /^[0-9a-fA-F]+$/.test(s)
}

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

  // Parsea los componentes
  const serverEphemeralPubKey = raw.slice(0, 65)
  const nonce = raw.slice(65, 65 + 12)
  const ciphertext = raw.slice(65 + 12)

  // ECDH con la clave efímera del servidor
  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 clave AES
  const aesKey = hkdf(sha256, sharedSecretBytes, undefined, HKDF_INFO, 32)

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

  return new TextDecoder().decode(plaintext)
}

// Procesa la respuesta en 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) // Salida en tiempo real
        } else if (content) {
          fullContent += content
          process.stdout.write(content)
        }
      } catch (e) {
        // Omite fragmentos mal formados
      }
    }
  }

  return fullContent
}

Ejemplo completo en funcionamiento

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() {
  // Paso 1: Genera el par de claves efímeras
  console.log('🔑 Generating ephemeral key pair...');
  const ec = new EC('secp256k1');
  const keyPair = ec.genKeyPair();
  const clientPublicKeyHex = keyPair.getPublic('hex');

  // Paso 2: Obtén y verifica la atestación
  console.log('🔍 Fetching TEE attestation...');
  const clientNonce = crypto.randomBytes(32).toString('hex'); // se requieren 32 bytes
  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');

  // Paso 3: Cifra el mensaje
  console.log('🔐 Encrypting message...');
  const plaintext = 'What is 2+2? Answer briefly.';

  // Normaliza y parsea la clave pública del modelo
  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 }];

  // Paso 4: Envía la solicitud 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 }),
  });

  // Paso 5: Descifra la respuesta
  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) {
          // Descifra
          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);

Limitaciones de E2EE

E2EE tiene algunas restricciones debido a los requisitos de cifrado:
FuncionalidadEstado
StreamingObligatorio (no se admite el modo sin streaming)
Búsqueda webDeshabilitada (filtraría contenido)
Subida de archivosNo admitida
Llamadas a funcionesNo admitido
System prompt de VeniceDeshabilitado (debe cifrarse del lado del cliente)

Buenas prácticas de seguridad

  1. Genera nuevos pares de claves por sesión — No reutilices claves efímeras.
  2. Rellena con ceros las claves privadas — Borra los bytes de la clave privada de la memoria cuando termines.
  3. Verifica la atestación — Comprueba siempre que verified: true y que el nonce coincide.
  4. Comprueba el modo de depuración — Rechaza las atestaciones de enclaves en depuración.
  5. Usa streaming — E2EE requiere streaming para una correcta fragmentación del cifrado.
  6. Gestiona los errores con cuidado — No expongas los errores de descifrado a los usuarios.
  7. Usa nonces de 32 bytes — Los proveedores de TEE requieren exactamente 32 bytes.

Buenas prácticas

No te limites a confiar en la respuesta verified: true. Parsea la cita Intel TDX en el cliente y verifica que las mediciones coinciden con los valores esperados. Para GPU de NVIDIA, verifica la atestación mediante el servicio de verificación de NVIDIA.
Genera siempre un nuevo nonce aleatorio para cada solicitud de atestación. Esto evita ataques de repetición en los que un atacante podría servir una atestación obsoleta.
La clave de firma debe estar vinculada al campo TDX REPORTDATA. Esto demuestra que la clave se generó dentro del enclave.
Verifica que la atestación TDX no tenga marcas de depuración activadas. Un enclave de depuración puede inspeccionarse y no debe considerarse confiable para producción.
E2EE requiere una implementación criptográfica cuidadosa. Usa nuestros SDK oficiales en lugar de implementar el protocolo por tu cuenta.

Comprobación de las capacidades del modelo

Puedes comprobar si un modelo admite TEE o E2EE a través del endpoint de modelos:
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}'

Manejo de errores

ErrorCausaSolución
TEE attestation verification failedLa atestación no superó la validaciónReintenta o contacta con soporte
Attestation nonce mismatchPosible ataque de repeticiónGenera un nonce nuevo
TDX debug mode detectedEl enclave está en modo de depuraciónNo usar para producción
Failed to decrypt fieldFalló el descifrado E2EE del lado del servidorRevisa tu implementación de cifrado
E2EE requires streamingSolicitud sin streaming a un modelo E2EEEstablece stream: true
Encrypted field is not valid hexSe envió texto plano con cabeceras E2EECifra todos los mensajes user/system
Invalid public keyFormato de clave incorrectoUsa 130 caracteres hex que comiencen con 04

Solución de problemas

La longitud del nonce es incorrecta. Los proveedores de TEE requieren exactamente 32 bytes (64 caracteres hexadecimales).
  • Usa crypto.randomBytes(32).toString('hex') (JS) o secrets.token_hex(32) (Python).
  • Error común: secrets.token_hex(16) produce 32 caracteres hex (16 bytes), no 32 bytes.
  • Comprueba que el modelo admite E2EE (supportsE2EE: true).
  • Verifica que tu clave API es válida y tiene acceso al modelo solicitado.
  • Verifica la conectividad de red con la API de Venice.
  • Asegúrate de utilizar la misma clave privada que generó la clave pública enviada en las cabeceras.
  • Comprueba que el contenido de la respuesta está realmente codificado en hexadecimal (E2EE activo).
  • Verifica que la clave pública del modelo coincide con la utilizada para cifrar.
  • Todos los mensajes con rol user y system deben estar cifrados cuando hay cabeceras E2EE presentes.
  • Verifica que tu contenido cifrado pasa la validación isValidEncrypted() (mínimo 186 caracteres hex).
  • Comprueba que la salida del cifrado es hex en minúsculas sin ningún prefijo.
  • La clave pública del cliente debe tener exactamente 130 caracteres hexadecimales comenzando con 04.
  • Usa el ayudante validateClientPubkey() para verificar el formato antes de enviar.
  • Asegúrate de utilizar el formato de clave pública no comprimido (65 bytes = 130 caracteres hex).
  • Verifica que el ID del modelo es correcto y que el modelo admite E2EE.
  • Usa el endpoint /models para comprobar los modelos E2EE disponibles.

Recursos