ZKshare
Servidor MCP Stdio que expone herramientas de zkShare a clientes de IA: almacenar contexto cifrado, pruebas, búsqueda semántica, uso compartido y llamadas sandbox mediante POST /api/v1/context con ZKSHARE_API_KEY.
Documentación
zkShare
API de contexto orientada a la privacidad para usuarios, agentes de IA y sistemas de back-office. Un único punto de entrada HTTP
(POST /api/v1/context) gestiona el almacenamiento de hechos cifrados, envoltorios de prueba basados en compromisos,
búsqueda semántica sobre datos cifrados, hechos cifrados de extremo a extremo (sellados por el cliente) y una
ejecución aislada en sandbox para cálculos sensibles. La implementación es una aplicación Next.js
(App Router) respaldada por PostgreSQL con pgvector.
Este documento está dirigido a desarrolladores que se integran con la API y a operadores que autoalojan el servicio. No es un folleto de marketing: los niveles de precios, los paneles de control y la facturación son capas opcionales definidas por separado en el código de la aplicación.
Modelo de privacidad y seguridad
La plataforma está diseñada en torno a tres límites de confianza:
| Límite | Lo que el operador puede ver | Lo que permanece privado |
|---|---|---|
| Almacén sellado por el servidor | Texto cifrado, IV, etiqueta de autenticación, compromiso, vector de incrustación. El servidor posee la clave AES-256-GCM (ZKSHARE_ENCRYPTION_SECRET) y descifra en memoria solo cuando el llamador invoca los resúmenes prove, share o search. | Los operadores de base de datos (sin el secreto de cifrado) y los lectores directos de tablas (RLS deniega anon y authenticated) no pueden leer el texto plano. |
| Almacén sellado por el cliente (E2EE) | Blobs de texto cifrado opacos, IV, etiqueta de autenticación, compromiso y un vector de incrustación proporcionado por el llamador. El servidor nunca recibe ni deriva texto plano, y nunca invoca un modelo de incrustación sobre el hecho. | El operador de la plataforma. El descifrado requiere la propia clave del llamador, que nunca sale del llamador. |
| Envoltorios de prueba | Un envoltorio JSON versionado y firmado con HMAC (compromiso + consulta + respuesta sí/no + nonce). Verificable por cualquiera que posea ZKSHARE_PROOF_SECRET. | El texto plano del hecho utilizado para derivar la respuesta nunca se incluye en el envoltorio. |
Qué significa esto en la práctica
- Los usuarios pueden probar una propiedad de un hecho personal (por ejemplo, "el usuario prefiere viajes a la playa") ante
un tercero sin exponer el valor subyacente. El tercero verifica el envoltorio
mediante
verify_proof. - Los agentes pueden mantener e intercambiar contexto entre sesiones o límites de herramientas sin exponer los
valores brutos a los sistemas posteriores. El intercambio produce un
share_tokende un solo uso y con límite de tiempo vinculado a un identificador de agente destinatario. - Las empresas que integran la API pueden ofrecer garantías de privacidad que son técnicas, no contractuales: RLS deniega el acceso directo a las tablas, la clave de cifrado es exclusiva del servidor, el secreto HMAC de prueba es exclusivo del servidor, y la ruta sellada por el cliente permite que los datos sensibles permanezcan completamente fuera del alcance del operador.
SECURITY.md es la referencia canónica para el modelo de amenazas, el resumen del
modelo de confianza, la divulgación de vulnerabilidades, la lista de verificación del operador y los controles de exposición
a LLM de terceros.
Contrato de API
| Operación | Comportamiento |
|---|---|
store | Sellado por el servidor: el llamador envía value. El servidor cifra con AES-256-GCM, calcula un compromiso con sal, genera una incrustación (o acepta un embedding de 1536 dimensiones) y persiste con client_encrypted = false. Sellado por el cliente: el llamador envía ciphertext, iv, auth_tag, commitment y el obligatorio embedding. El servidor almacena los blobs y el vector, establece client_encrypted = true y nunca deriva nada del texto plano o la etiqueta. |
prove | Carga un hecho sellado por el servidor, lo descifra en memoria, deriva una respuesta sí/no para la consulta proporcionada (LLM con temperature: 0, o una heurística cuando los LLM externos están deshabilitados) y devuelve un envoltorio de prueba firmado con HMAC. Devuelve 422 / CLIENT_ENCRYPTED si el hecho está sellado por el cliente. |
share | Igual que prove, más la inserción de una fila en share_tokens (recipient_agent_id, expiry, proof) y devuelve un share_token. El token es una cadena base64url de 24 bytes, válida durante siete días. |
search | Incrusta la consulta, llama a match_facts (una función SQL de security definer con distancia coseno sobre pgvector) y devuelve resúmenes clasificados solo para filas selladas por el servidor. Las filas selladas por el cliente se excluyen a nivel de SQL y a nivel de aplicación. |
verify_proof | Valida un envoltorio sin cargar ningún hecho. Un envoltorio malformado devuelve 400 / VALIDATION_ERROR; un envoltorio bien formado con un HMAC incorrecto devuelve 200 con data.valid: false. |
sandbox | Ejecuta una pequeña función de lista permitida dentro de un sandbox aislado node:vm (sin E/S de host, tiempo de espera de 50 ms) y devuelve el resultado con metadatos de atestación y un JWT HS256 de corta duración (proof_of_execution). Cada respuesta anuncia provider: "vm-sandbox": esto es aislamiento de software, no atestación de hardware. |
Las formas autoritativas de solicitud y respuesta se encuentran en types/index.ts y
openapi.json.
Protocolo de Contexto de Modelo (MCP)
El paquete npm zkshare-mcp (npm, fuente packages/zkshare-mcp/) es un servidor MCP stdio que expone herramientas (zkshare_store, zkshare_prove, …) que llaman a POST https://zkshare.io/api/v1/context (o a tu ZKSHARE_API_URL) con ZKSHARE_API_KEY.
Nombre canónico del Registro MCP oficial: io.github.sp0oby/zkshare — consulta de registro · Acerca del Registro MCP (metadatos de descubrimiento; el paquete ejecutable permanece en npm).
Usuarios finales: Node.js ≥ 18, luego npx -y zkshare-mcp — sin clonación. Configura tu host (ejemplo a continuación).
Colaboradores: desde la raíz del repositorio pnpm install, luego pnpm mcp para ejecutar el paquete local; la fuente está en packages/zkshare-mcp/.
Los cuerpos avanzados de store sellados por el cliente permanecen en HTTPS/OpenAPI — no a través de herramientas MCP.
// ~/.cursor/mcp.json
{
"mcpServers": {
"zkshare": {
"command": "npx",
"args": ["-y", "zkshare-mcp"],
"env": {
"ZKSHARE_API_KEY": "zk_live_…",
"ZKSHARE_API_URL": "https://zkshare.io"
}
}
}
}
Códigos de error
| Código | HTTP | Significado |
|---|---|---|
INVALID_API_KEY | 401 | Clave faltante, malformada o revocada. |
RATE_LIMITED | 429 | Límite de ventana deslizante por clave superado. Se incluye el encabezado Retry-After. |
VALIDATION_ERROR | 400 | El cuerpo falla el esquema Zod o se pasó una prueba malformada a verify_proof. |
FACT_NOT_FOUND | 404 | Ninguna fila coincide con (api_key_id, logical_user_id, fact_key). |
PROOF_FAILED | 400 | El descifrado falló o no se pudo derivar una respuesta sí/no definitiva. |
CLIENT_ENCRYPTED | 422 | Se llamó a prove o share contra un hecho sellado por el cliente. |
INTERNAL_ERROR | 500 | Excepción capturada. El mensaje original se registra mediante lib/logger.ts; los clientes ven un mensaje genérico. |
Arquitectura
- Tiempo de ejecución:
/api/v1/contextes un manejador de rutas de Node.js (no Edge) para que AES-256-GCM, la derivación de claves scrypt y el cliente de rol de servicio de Supabase se comporten de manera determinista. - Persistencia: PostgreSQL con extensiones y tablas gestionadas por migraciones versionadas en
supabase/migrations/. Tablas:api_keys,facts,audit_logs,share_tokens. La tablafactsalmacena texto cifrado, IV, etiqueta de autenticación, compromiso, una incrustación devector(1536)y un indicador declient_encrypted. - Búsqueda:
match_facts(api_key_id, logical_user_id, query_embedding, match_count)es una función desecurity definercon un índice IVFFlat. Devuelve solo filas selladas por el servidor. Actualizar el tipo de fila de la función requiere un reemplazo de estiloDROP FUNCTION ... CASCADE(una restricción de PostgreSQL): las migraciones lo manejan explícitamente. - Autenticación y autorización:
- Panel de usuario final: inicio de sesión con enlace mágico de Supabase Auth.
middleware.tsredirige a los visitantes no autenticados fuera de/dashboard. - API HTTP: encabezado
x-api-key. Las claves se almacenan como hashes SHA-256; solo se muestra el prefijo en el panel. Rotar una clave requiere generar una nueva: el texto plano nunca se persiste. - Acceso a la base de datos: RLS deniega todo acceso directo desde los roles
anonyauthenticated. La aplicación usa el rol de servicio de Supabase solo en el lado del servidor.
- Panel de usuario final: inicio de sesión con enlace mágico de Supabase Auth.
- Limitación de velocidad: Upstash Redis (ventana deslizante) cuando está configurado; se usa un respaldo en proceso en el desarrollo local.
- Claves de cifrado:
ZKSHARE_ENCRYPTION_SECRET— secreto maestro AES-256-GCM del lado del servidor (derivado de scrypt; mínimo 32 caracteres).ZKSHARE_PROOF_SECRET— secreto HMAC para compromisos y envoltorios de prueba (mínimo 16 caracteres).ZKSHARE_ENCLAVE_JWT_SECRET— secreto HS256 para atestaciones de sandbox (mínimo 32 caracteres).- Los tres son obligatorios para las rutas de código relevantes. La aplicación lanza una excepción al inicio si alguno falta o es demasiado corto.
Estructura del repositorio
| Ruta | Propósito |
|---|---|
app/ | Rutas de Next.js App Router: sitio público, panel, endpoints de API (api/v1/context, api/keys, api/billing, api/webhooks/stripe, api/health, api/health/ready, api/audit/export, auth/callback). |
lib/ | Módulos solo de servidor: encryption.ts, zk.ts, embeddings.ts, search.ts, sandbox.ts, api-key.ts, rate-limit.ts, audit.ts, llm-client.ts, supabase-server.ts, supabase-browser.ts. |
components/ | Componentes de interfaz construidos sobre primitivas shadcn/ui. |
types/index.ts | Esquema de solicitud Zod, enumeración de operaciones, códigos de error y tipos de fila compartidos. |
supabase/migrations/ | Migraciones SQL ordenadas. |
circuits/ | Notas y marcadores de posición para el futuro cableado de Groth16. snarkjs es una dependencia de tiempo de ejecución pero no está en la ruta de confianza predeterminada. |
packages/zkshare-mcp/ | Paquete npm publicable zkshare-mcp — servidor MCP stdio que hace proxy a /api/v1/context. |
openapi.json | Descripción OpenAPI 3.1 de la superficie pública. |
SECURITY.md | Modelo de amenazas, lista de verificación operativa y la matriz de cifrado / LLM. |
Desarrollo local
pnpm install
cp .env.local.example .env.local
# Fill the Supabase, ZKSHARE_*, and (optionally) LLM, Upstash, and Stripe values.
# Defaults for LLM model slugs live in lib/llm-client.ts.
pnpm dev
Aplica las migraciones contra tu base de datos de Supabase antes de ejercitar la API. Consulta
supabase/README.md.
Pruebas de humo
Almacén sellado por el servidor seguido de una prueba:
curl -sS -X POST http://localhost:3000/api/v1/context \
-H "x-api-key: zk_live_..." \
-H "Content-Type: application/json" \
-d '{"operation":"store","user_id":"user_123","fact_key":"example","value":"hello"}'
curl -sS -X POST http://localhost:3000/api/v1/context \
-H "x-api-key: zk_live_..." \
-H "Content-Type: application/json" \
-d '{"operation":"prove","user_id":"user_123","fact_key":"example","query":"does the fact say hello?"}'
Verificación de una cadena de prueba:
curl -sS -X POST http://localhost:3000/api/v1/context \
-H "x-api-key: zk_live_..." \
-H "Content-Type: application/json" \
-d '{"operation":"verify_proof","proof":"<base64url envelope from the prove response>"}'
Sondas de salud:
- Liveness:
GET /api/health - Readiness (base de datos):
GET /api/health/ready
Autoauditoría (rutas críticas de privacidad)
pnpm run verify:crypto
Esto ejecuta scripts/verify-crypto.ts directamente con el soporte integrado de TypeScript de Node y
verifica el viaje de ida y vuelta del cifrado, la detección de manipulación, los compromisos deterministas y los tres
resultados de verify_proof (valid, invalid, malformed).
Preparación para producción
La lista de verificación completa del operador se encuentra en SECURITY.md → Operator checklist.
Como mínimo, antes de exponer la API a la internet pública:
- Los tres secretos de
ZKSHARE_*están configurados con valores de alta entropía; la aplicación lanza una excepción al inicio de lo contrario. ZKSHARE_CORS_ORIGINes una lista de permitidos explícita de orígenes separados por comas.*es solo para demostraciones no autenticadas.- Las migraciones en
supabase/migrations/se han aplicado en orden de marca de tiempo en el entorno de destino. - Upstash Redis está configurado (
UPSTASH_REDIS_REST_URL+UPSTASH_REDIS_REST_TOKEN); el respaldo de limitación de velocidad en proceso es solo para desarrollo local. GET /api/health/readydevuelve200sin entradas demissingy conwarningsreconocido.
Estado de la afirmación de "conocimiento cero"
El campo proof devuelto hoy es un envoltorio JSON versionado firmado con HMAC-SHA256 que vincula
el compromiso, la consulta y la respuesta sí/no. snarkjs se incluye como dependencia, y
circuits/ documenta la ruta Groth16 prevista para trabajo futuro. La verificación Groth16 no está en
la ruta de respuesta predeterminada. Trata cualquier afirmación externa de SNARK completo en cada llamada como aspiracional
a menos que el verificador y los artefactos de circuito se hayan publicado y auditado.
Contribuciones
Consulta CONTRIBUTING.md para la lista de verificación de desarrollo local, los
comandos de verificación requeridos antes de abrir una solicitud de extracción y cómo marcar cambios que
afecten al plano de datos o a las rutas criptográficas.
Informar de una vulnerabilidad
Por favor, no abras un issue público para vulnerabilidades de seguridad. El proceso de divulgación
y los canales de contacto están documentados en SECURITY.md.
Licencia
Publicado bajo la Licencia MIT.