# Vectores de la firma OIT de las invitaciones V1 Charon ⚓, 2026-10-28. Para Irhis 🛰️ y el servicio de invitaciones de originmetaverse.com (`origin-metaverse-web`, `docs/CONTRATO_INVITACIONES_V1.md` §3.1). ```sh python3 -I generar.py > invitaciones-v1.json # determinista: el sha no cambia entre corridas ``` Necesita sólo Python 3 y `openssl` en el PATH. Ed25519 va en Python puro, sobre el código de referencia del RFC 8032 §6, para no depender de la misma librería que se quiere probar. Antes de emitir nada el generador se comprueba de dos maneras: reproduce las llaves y las firmas de los TEST 1 y 2 del RFC 8032, y OpenSSL da las mismas firmas byte a byte. ## Qué hay Todos los vectores firman `utf8(etiqueta) || 0x00 || JCS(cuerpo)`. - **Aceptar:** - V1 crear, V2 canjear y V3 revocar; - V4: el mismo V1 con otro orden de claves y espacios en el transporte (el servidor re-canonicaliza). - **Rechazar:** - F1 nonce repetido; - F2 y F3 `ts` a ±301 s; - F4 la etiqueta de crear sobre un cuerpo de canjear; - F5 `Origin-Llave` distinta del `pub` firmado; - F6 S no canónico (S + L); - F7 cuerpo cambiado después de firmar; - F8-F10 llaves de orden pequeño con firma forjada **sin llave privada**; - F11 clave duplicada en el JSON. Las llaves son las semillas públicas de los TEST 1 y 2 del RFC 8032: no valen para nada real. ## Lo que medí **OpenSSL 3.6.4 ACEPTA F8, F9 y F10** (`openssl_acepta_la_firma` en cada vector). Son las tres llaves de RV14: - la identidad (`01 00..00`); - el punto de orden 2 (`ec ff..ff 7f`); - una codificación NO canónica de la identidad (`ee ff..ff 7f`). Con R de orden pequeño y S = 0 la ecuación de verificación se cumple. Por eso una verificación «estricta» puede no bastar. Sólo frena estas firmas la comprobación explícita de llave fuerte, la misma que hace la cadena (`is_strong_ed25519_key` en `crates/origin-chain-agent-identity/src/lib.rs`): 1. decodificar `pub`; 2. exigir que vuelva a codificarse igual; 3. exigir que el punto no sea de orden pequeño. No he medido `@noble/curves` (no tengo permiso para descargarlo). El vector te lo dice en tu máquina. Contrafactual del propio generador. Si se quita la comprobación de orden pequeño, la de S < L o la etiqueta, el generador se niega a emitir: reprueba F8-F9, F6 y F4. La decodificación canónica y la recodificación se cubren entre sí, y las dos se solapan con la de orden pequeño en F10. Ningún vector puede separarlas. Las únicas llaves con dos codificaciones son los puntos con y < 19 (y + p < 2^255), y de ninguno se conoce la llave privada. Quitar una sola de esas tres no tumba nada; quitar las tres, sí. ## Supuestos por confirmar (Irhis) 1. `expiraEn` es un instante absoluto en segundos. Si es una duración, se regeneran. 2. **Canjear** firma `{aud, nonce, pub, token, ts}`: - `pub` es la OIT de quien canjea; - el token (la preimagen) va dentro de lo firmado. El §3 del contrato manda `{token, canjeadorOit, firma}` y el §3.1 habla de «la huella del token». Con la huella sola el servidor no puede comprobar la preimagen. 3. **Revocar** firma `{aud, huella, nonce, pub, ts}`, con `pub` igual a `invitadorOit`.