
Legion es un tejido de autenticación de conocimiento cero construido para la privacidad.
Autenticación de Conocimiento Cero Real con Firmas de Anillo de Dispositivos Vinculados al Hardware
Legion es un sistema de autenticación de conocimiento cero sin contraseña que demuestra que estás autorizado sin revelar quién eres.
Autentícate usando solo tu huella dactilar + frase de recuperación de 24 palabras (como MetaMask). Sin nombres de usuario, sin contraseñas, sin secretos del lado del servidor.
| Propiedad | Garantía |
|---|---|
| Autenticación | Sin contraseña (BIP-39 + Huella dactilar) |
| Anonimato del usuario | 1 de 2^20 (1,048,576) |
| Anonimato del dispositivo | 1 de 2^10 (1,024) por usuario |
| Error de solidez | 2^-128 |
| Sistema de prueba | Halo2 PLONK (configuración transparente) |
| Derivación de credenciales | Blake3 (semilla BIP-39) |
| Vinculación de hardware | WebAuthn Nivel 2 (TPM/Secure Enclave) |
| Multidispositivo | Máx. 2 dispositivos por cuenta |
| Limitación de velocidad | 5 intentos/hora |
| Revocación de dispositivos | Lista negra instantánea |
git clone https://github.com/deadends/legion.git cd legion
chmod +x scripts/install.sh && ./scripts/install.sh
scripts\install.bat
**¡Eso es todo!** Abre http://localhost en tu navegador.
### Lo que se instala
- ✅ Redis (almacenamiento de sesiones)
- ✅ Legion Server (verificador de pruebas ZK)
- ✅ Frontend (cliente WASM)
- ✅ Nginx (proxy inverso)
**Rendimiento**: Registro ~5s, Autenticación ~2min (generación de pruebas k=14)
---
### Configuración manual (sin Docker)
<details>
<summary>Haz clic para expandir la instalación manual</summary>```bash
# 1. Install Redis
# macOS: brew install redis && redis-server
# Ubuntu: sudo apt install redis && redis-server
# Windows: https://redis.io/docs/install/install-redis/install-redis-on-windows/
# 2. Run server (terminal 1)
cd legion-server
cargo run --release --features redis
# 3. Build frontend (terminal 2)
cd wasm-client
wasm-pack build --target web --release
python3 -m http.server 8000
# 4. Open http://localhost:8000
Para despliegue en producción, consulta DEPLOYMENT.md
| Nivel de Seguridad | k | Tiempo de Prueba | Tamaño de Prueba | Caso de Uso |
|---|---|---|---|---|
| Desarrollo | 12 | ~30s | 3.2 KB | Pruebas |
| Producción | 14 | ~2min | 3.4 KB | Recomendado |
Hardware de Prueba: Lenovo IdeaPad 3 - Intel Core i3 11.ª Generación
Nota: El rendimiento puede variar según las especificaciones del hardware.
| Métrica | Valor | Notas |
|---|---|---|
| Tamaño de Prueba | 3,264 bytes | 3.19 KB comprimido |
| Entradas Públicas | 10 | Raíz del árbol de usuario, raíz del árbol de dispositivo, nullifier, etc. |
| Generación de Parámetros | 7.03s | Configuración única por valor k |
| Creación de Circuito | 2.3µs | Sobrecarga insignificante |
| Generación de Clave Verificadora | 1.29s | Generación de clave única |
| Verificación de Prueba | 107.7ms | Verificación real de ZK proof |
| Verificación Total | 8.43s | Extremo a extremo (sin caché) |
Desglose:
| Métrica | Valor | Notas |
|---|---|---|
| Tamaño de Prueba | 3,392 bytes | 3.31 KB comprimido |
| Entradas Públicas | 10 | Raíz del árbol de usuario, raíz del árbol de dispositivo, nullifier, etc. |
| Generación de Parámetros | 100.78s | Configuración única por valor k |
| Creación de Circuito | 5µs | Sobrecarga insignificante |
| Generación de Clave Verificadora | 12.89s | Generación de clave única |
| Verificación de Prueba | 967.2ms | Verificación real de ZK proof |
| Verificación Total | 114.65s | Extremo a extremo (sin caché) |
Desglose:
Importante: La generación de parámetros y la generación de clave son costos únicos que se pueden almacenar en caché. Una vez en caché, la verificación toma solo entre ~108-967ms según el valor de k. La implementación actual aún no almacena parámetros en caché.
¿Por qué es más lento que los benchmarks anteriores? El circuito sin contraseña ahora verifica DOS árboles Merkle (usuario + dispositivo) en lugar de uno, proporcionando anonimato real a nivel de dispositivo (1 de 1024 dispositivos por usuario).
📖 Para un flujo de autenticación detallado paso a paso con detalles criptográficos, consulta ARCHITECTURE_FLOW.md
┌─────────────────────────────────────────────────────────────────────────┐ │ CLIENT (Browser + WASM) │ ├─────────────────────────────────────────────────────────────────────────┤ │ ┌────────────────┐ ┌─────────────────┐ ┌──────────────────────────┐ │ │ │ UI Layer │ │ WASM Prover │ │ Local Storage │ │ │ │ (Vanilla JS) │ │ (Rust→WASM) │ │ (IndexedDB) │ │ │ ├────────────────┤ ├─────────────────┤ ├──────────────────────────┤ │ │ │ • Registration │ │ • Blake3 Hash │ │ • Full Merkle Tree │ │ │ │ • Login Form │ │ • BIP-39 Derive │ │ • Device Trees │ │ │ │ • Session UI │ │ • Halo2 Prover │ │ • WebAuthn Credentials │ │ │ │ • Tree Sync │ │ • Merkle Proof │ │ • Tree Version Cache │ │ │ └────────────────┘ │ • Ring Sigs │ └──────────────────────────┘ │ │ └─────────────────┘ │ │ ┌──────────────────────────────────────────────────────────────────┐ │ │ │ Hardware Security (WebAuthn Level 2) │ │ │ ├──────────────────────────────────────────────────────────────────┤ │ │ │ • TPM 2.0 / Secure Enclave • FIDO2 Authenticator │ │ │ │ • Device Private Key (ECDSA) • Biometric/Touch Required │ │ │ └──────────────────────────────────────────────────────────────────┘ │ └────────────────────────────────┬────────────────────────────────────────┘ │ HTTPS/TLS 1.3 │ (Encrypted Channel) ▼ ┌──────────────────────────────────────────────────────────────────────────┐ │ LEGION SERVER (Rust/Axum) │ ├──────────────────────────────────────────────────────────────────────────┤ │ ┌─────────────────────────────────────────────────────────────────┐ │ │ │ API Layer (Axum) │ │ │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ POST /api/register-blind │ Blind registration │ │ │ │ GET /api/download-tree │ Download full Merkle tree │ │ │ │ POST /api/verify-anonymous-proof │ Verify ZK proof │ │ │ │ POST /api/verify-session │ Session validation │ │ │ │ POST /api/webauthn/* │ WebAuthn endpoints │ │ │ │ GET /health │ Health check │ │ │ └─────────────────────────────────────────────────────────────────┘ │ │ │ │ │ ┌─────────────────────────────────────────────────────────────────┐ │ │ │ Business Logic Layer │ │ │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ • Blind Registration │ • Tree Synchronization │ │ │ │ • ZK Proof Verifier │ • Nullifier Tracker (replay) │ │ │ │ • Session Manager │ • Linkability Tag Validator │ │ │ │ • WebAuthn Service │ • Timestamp Validator (±10min) │ │ │ │ • Device Revocation │ • Rate Limiter (5/hour) │ │ │ └─────────────────────────────────────────────────────────────────┘ │ │ │ │ │ ┌─────────────────────────────────────────────────────────────────┐ │ │ │ Cryptographic Layer │ │ │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ • Halo2 Verifier (PLONK) │ • Poseidon Hash (ZK-friendly) │ │ │ │ • Blake3 (credential) │ • BIP-39 (recovery phrase) │ │ │ │ • Merkle Tree (2^20) │ • Device Trees (2^10 per user) │ │ │ │ • Ring Signature Verify │ • WebAuthn Signature Verify │ │ │ └─────────────────────────────────────────────────────────────────┘ │ └────────────────────────┬──────────────────────┬──────────────────────────┘ │ │ ▼ ▼ ┌────────────────────────┐ ┌───────────────────────────┐ │ Redis (In-Memory) │ │ RocksDB (Persistent) │ ├────────────────────────┤ ├───────────────────────────┤ │ • Session Tokens │ │ • Merkle Tree Leaves │ │ • Linkability Tags │ │ • Device Trees │ │ • Spent Nullifiers │ │ • Nullifier History │ │ • Rate Limit Counters │ │ • WebAuthn Credentials │ │ TTL: 1 hour │ │ • Revoked Devices │ └────────────────────────┘ └───────────────────────────┘
### Flujo de autenticación (simplificado)```
┌─────────────┐ ┌──────────────┐
│ Client │ │ Server │
│ (Browser) │ │ (Verifier) │
└──────┬──────┘ └──────┬───────┘
│ │
│ 1. Generate 24-word recovery phrase (BIP-39) │
│ → 256-bit entropy (like MetaMask) │
│ → User writes down on paper │
│ │
│ 2. Derive account_id from phrase (Blake3) │
│ account_id = Blake3("LEGION_ACCOUNT_V2" || bip39_seed) │
│ → Deterministic, no server interaction │
│ │
│ 3. Hash account_id for tree leaf (Poseidon) │
│ credential_hash = Poseidon(account_id) │
│ │
│ 4. Blind registration (TRUE zero-knowledge) ────►│
│ → Sends ONLY credential_hash (no phrase/identity) │
│ → Server adds to tree, returns tree_index │
│ ◄────│ {tree_index: 114}
│ │
│ 5. Download full Merkle tree (one-time sync) ────►│
│ → Client stores entire tree in IndexedDB │
│ → Enables TRUE zero-knowledge (no server queries) │
│ ◄────│ {tree_data: [all leaves],
│ │ merkle_root, version}
│ │
│ 6. Generate WebAuthn key (TPM/Secure Enclave) │
│ → Fingerprint prompt creates hardware-bound key │
│ → device_pubkey (ECDSA P-256, non-exportable) │
│ → Stored in TPM 2.0 / Secure Enclave │
│ │
│ 7. Register device in device tree ────►│
│ → device_commitment = Blake3(credential_id) │
│ → Server converts to valid field element if needed │
│ → Server adds to user's device tree (1 of 1024 slots) │
│ ◄────│ {device_position: 0,
│ │ device_tree_root}
│ │
│ 8. LOGIN: Touch fingerprint to authenticate │
│ → WebAuthn verifies hardware-bound key │
│ → Decrypts recovery phrase from local storage │
│ → Re-derives account_id from phrase │
│ │
│ 9. Fetch device Merkle proof ────►│
│ → Sends account_id (derived from phrase) │
│ → Server returns device tree path │
│ ◄────│ {device_path: [siblings],
│ │ device_root}
│ │
│ 10. Compute user Merkle proof CLIENT-SIDE │
│ → Uses local tree from IndexedDB │
│ → Computes path for tree_index │
│ → Server NEVER learns which user! │
│ │
│ 11. Compute nullifier (replay protection) │
│ nullifier = Poseidon(account_id || challenge) │
│ → ONE-TIME USE: Different every login │
│ → Prevents proof replay attacks │
│ │
│ 12. Compute linkability tag (session binding) │
│ linkability_tag = Blake3(device_pubkey || nullifier) │
│ ⚠️ Binds session to specific device+user │
│ │
│ 13. Generate ZK proof (Halo2 PLONK, ~2min for k=14) │
│ Proves in zero-knowledge: │
│ ✓ User exists in Merkle tree (1 of 2^20) │
│ ✓ Device exists in device tree (1 of 2^10) │
│ ✓ account_id hashes to credential_hash │
│ ✓ Nullifier computed correctly │
│ ✓ Timestamp is fresh │
│ WITHOUT revealing which user or device │
│ │
│ 14. Submit proof ────►│
│ {proof, public_inputs, linkability_tag, k=14} │
│ │ • Check device not revoked
│ │ • Verify timestamp (±10min)
│ │ • Rate limit check (5/hour)
│ │ • Check nullifier (replay?)
│ │ • Verify ZK proof (~115s)
│ │ • Mark nullifier as used
│ │
│ ◄────│ {session_token, expires_at}
│ │
│ 15. Verify session (every request) ────►│
│ {session_token, linkability_tag} │
│ │ • Lookup in Redis
│ │ • Verify linkability_tag
│ │ (prevents session theft)
│ │ • Check not spent
│ ◄────│ {valid: true}
│ │
🔍 ¿Quieres más detalles? Consulta ARCHITECTURE_FLOW.md para:
┌─────────────────────────────────────────────────────────────────────────┐ │ SESSION SECURITY MECHANISMS │ ├─────────────────────────────────────────────────────────────────────────┤ │ │ │ 1. LINKABILITY TAG (Zero-Knowledge Device Binding) │ │ ═══════════════════════════════════════════════════════ │ │ │ │ linkability_tag = Blake3(device_pubkey || nullifier) │ │ │ │ • Computed client-side using hardware-bound device key │ │ • Sent with every session validation request │ │ • Server verifies: stored_tag == provided_tag │ │ │ │ ✅ PREVENTS: Session token theft/replay on different device │ │ ✅ ENSURES: Same user + same device for entire session │ │ ✅ MAINTAINS: Zero-knowledge (server doesn't learn identity) │ │ │ │ ───────────────────────────────────────────────────────────────── │ │ │ │ 2. SESSION TOKEN (Cryptographic Binding) │ │ ═══════════════════════════════════════════════════════ │ │ │ │ session_token = Poseidon(nullifier || timestamp || linkability_tag) │ │ │ │ • Generated server-side after proof verification │ │ • Stored in Redis with linkability_tag as value │ │ • Cannot be forged without knowing nullifier │ │ │ │ ✅ PREVENTS: Token forgery │ │ ✅ ENSURES: Cryptographic binding to proof │ │ │ │ ───────────────────────────────────────────────────────────────── │ │ │ │ 3. NULLIFIER (Replay Protection) │ │ ═══════════════════════════════════════════════════════ │ │ │ │ nullifier = Poseidon(credential_hash || challenge) │ │ │ │ • Unique per authentication attempt │ │ • Tracked in RocksDB (permanent) and Redis (cache) │ │ • Server rejects if nullifier seen before │ │ │ │ ✅ PREVENTS: Proof replay attacks │ │ ✅ ENSURES: One-time use per challenge │ │ │ │ ───────────────────────────────────────────────────────────────── │ │ │ │ 4. TIMESTAMP VALIDATION (Time-Bound Security) │ │ ═══════════════════════════════════════════════════════ │ │ │ │ • Proof includes timestamp (Unix epoch) │ │ • Server validates: |proof_time - server_time| < 5 minutes │ │ • Session TTL: 1 hour (sliding window) │ │ │ │ ✅ PREVENTS: Old proof replay │ │ ✅ ENSURES: Fresh authentication │ │ │ │ ───────────────────────────────────────────────────────────────── │ │ │ │ 5. CHALLENGE-RESPONSE (Freshness Guarantee) │ │ ═══════════════════════════════════════════════════════ │ │ │ │ • Server generates random 32-byte challenge │ │ • Stored in Redis with 5-minute TTL │ │ • Client must include in proof │ │ • Server verifies challenge matches and deletes │ │ │ │ ✅ PREVENTS: Pre-computed proof attacks │ │ ✅ ENSURES: Proof generated for this specific session │ │ │ └─────────────────────────────────────────────────────────────────────────┘
## 🔐 Propiedades de Conocimiento Cero
### Lo que sabe el servidor
- ✅ Alguien en el conjunto de anonimato autenticado
- ✅ La prueba es criptográficamente válida
- ✅ Mismo usuario+dispositivo mediante etiqueta de vinculabilidad
- ✅ Estado del límite de velocidad (intentos restantes)
- ✅ Estado de revocación del dispositivo
- ✅ Número total de usuarios registrados
- ✅ Raíz del árbol de Merkle (pública)
### Lo que el servidor NO puede saber
- ❌ Qué usuario específico (1 de 1M)
- ❌ Qué dispositivo específico (1 de 1K por usuario)
- ❌ Frase de recuperación (semilla BIP-39)
- ❌ account_id (derivado de la frase)
- ❌ Clave privada del dispositivo (en TPM/Enclave Seguro)
- ❌ Qué hoja del árbol pertenece a qué usuario
- ❌ Ruta Merkle del usuario (calculada del lado del cliente)
- ❌ Posición tree_index del usuario
## 📦 Despliegue
Consulte [DEPLOYMENT.md](https://github.com/deadends/legion/blob/passwordless-v1.3/docs/DEPLOYMENT.md) para una guía detallada de despliegue en producción.
### Despliegue rápido con Docker```bash
# Production build
docker-compose -f deployment/docker-compose.yml up -d
# Check logs
docker-compose -f deployment/docker-compose.yml logs -f legion-server
# Check health
curl http://localhost/health
RUST_LOG=info LEGION_DATA_PATH=/var/lib/legion/data REDIS_URL=redis://127.0.0.1:6379
## 🧪 Pruebas```bash
# Run all tests
cargo test --workspace
# Run with Redis features
cargo test --workspace --features redis
# Benchmark
cargo bench
¡Las contribuciones son bienvenidas! Lea primero CONTRIBUTING.md.
git checkout -b feature/amazing)git commit -m 'Add amazing feature')git push origin feature/amazing)¿Encontró un problema de seguridad? Consulte SECURITY.md para divulgación responsable.
NO abra issues públicos para vulnerabilidades.
Licencia MIT - consulte el archivo LICENSE para más detalles.
Cambios Principales:
Arquitectura:
Cambios Principales:
Añadido:
Correcciones de Seguridad:
Construido con ❤️ por la privacidad y la seguridad