{"_id":"2fa-wasm","_rev":"3-4299ba4b625c72ae04d84872b8b303a9","name":"2fa-wasm","dist-tags":{"latest":"1.1.1"},"versions":{"1.0.0":{"name":"2fa-wasm","version":"1.0.0","keywords":["wasm","webassembly","2fa","totp","hotp","base32","hmac","sha1","sha256","sha512","otp","google-authenticator","assemblyscript"],"author":{"name":"Edison Manrique"},"license":"Apache-2.0","_id":"2fa-wasm@1.0.0","maintainers":[{"name":"edison-manrique","email":"edison.manrique.chocce@gmail.com"}],"homepage":"https://github.com/edison-manrique/2fa-wasm#readme","bugs":{"url":"https://github.com/edison-manrique/2fa-wasm/issues"},"dist":{"shasum":"563ebf2e4a1761b72bb622b4b45724ad0ecedf94","tarball":"https://registry.npmjs.org/2fa-wasm/-/2fa-wasm-1.0.0.tgz","fileCount":6,"integrity":"sha512-sKzjRtA7NdRcwCs58efmGjnoCndGfiGrgAf0GDumPgnKrJ3l4QY+/oBwFUZ1gAPZzFheo4dD6DQqtorHJbhaOw==","signatures":[{"sig":"MEUCIA6DKjced/vTlC9Ul3/WoF9+EMia2QF4tYMBrZEPHlzuAiEA8dRAwSYLrzCwwNCqHrXP/mN6s0gvVxJ6GX3BiRig46c=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":44657},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=18.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"2d2f9e9f418c8a914cd9bf1ddcd2f8755fb8ea30","scripts":{"test":"node test/index.test.js","build":"npm run asbuild && npm run build:ts","asbuild":"asc assembly/index.ts --target release","build:ts":"esbuild src/index.ts --bundle --format=esm --minify --platform=browser --outfile=dist/index.js && tsc --emitDeclarationOnly","examples":"node examples/server.cjs","test:stress":"node --expose-gc test/stress.test.js","asbuild:debug":"asc assembly/index.ts --target debug","prepublishOnly":"npm run build"},"_npmUser":{"name":"edison-manrique","email":"edison.manrique.chocce@gmail.com"},"repository":{"url":"git+ssh://git@github.com/edison-manrique/2fa-wasm.git","type":"git"},"_npmVersion":"11.13.0","description":"Biblioteca de autenticación de dos factores (2FA / HOTP / TOTP / Base32 / HMAC) de alto rendimiento en AssemblyScript / WebAssembly con TypeScript wrapper.","directories":{},"_nodeVersion":"22.15.0","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/2fa-wasm_1.0.0_1785028908018_0.3261658675274306","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"name":"2fa-wasm","version":"1.1.0","keywords":["wasm","webassembly","assemblyscript","typescript","2fa","two-factor","otp","totp","hotp","base32","hmac","sha1","sha256","sha512","otpauth","google-authenticator","authenticator","zero-allocation","zero-alloc","constant-time","rfc4226","rfc6238","rfc4648","rfc2104"],"author":{"name":"Edison Manrique"},"license":"Apache-2.0","_id":"2fa-wasm@1.1.0","maintainers":[{"name":"edison-manrique","email":"edison.manrique.chocce@gmail.com"}],"homepage":"https://github.com/edison-manrique/2fa-wasm#readme","bugs":{"url":"https://github.com/edison-manrique/2fa-wasm/issues"},"dist":{"shasum":"02f3292489dcc06f3c4fb4f5489cb72d19cc7ded","tarball":"https://registry.npmjs.org/2fa-wasm/-/2fa-wasm-1.1.0.tgz","fileCount":15,"integrity":"sha512-2A4SREvdyeBf2LxarLlt6hPvTQV2rTinPXxa4zLl2uuPICJBMAZpdIpnBf8f7rUQMTl+We9jgAtZOypHvidYYw==","signatures":[{"sig":"MEYCIQCW2VFj9v6ztw8iiZ0du2ThpxI9GC12yF5tSll58r4JVQIhANEmYD0i+T5MFIZIl4r3ohdWMpmLiR2SnFj/XYHbjGm7","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":83140},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=18.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"650ef4482cabbc80fb1da99884a73760d2f3f559","scripts":{"test":"bun test","build":"bun run asbuild && bun run build:ts","asbuild":"asc assembly/index.ts --target release","build:ts":"esbuild src/index.ts --bundle --format=esm --minify --platform=browser --outfile=dist/index.js && tsc --emitDeclarationOnly","examples":"bun examples/server.ts","typecheck":"tsc --noEmit","test:stress":"bun test test/stress.test.ts","asbuild:debug":"asc assembly/index.ts --target debug","prepublishOnly":"bun run build","test:correctness":"bun test test/index.test.ts"},"_npmUser":{"name":"edison-manrique","email":"edison.manrique.chocce@gmail.com"},"repository":{"url":"git+ssh://git@github.com/edison-manrique/2fa-wasm.git","type":"git"},"_npmVersion":"11.13.0","description":"Biblioteca 2FA zero-allocation (HOTP/TOTP/Base32, RFC 4226/6238/4648) en AssemblyScript/WebAssembly con wrapper TypeScript. Compatible con otpauth:// (Google Authenticator), validación constant-time, ~478K TOTP/s.","directories":{},"sideEffects":false,"_nodeVersion":"22.15.0","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/2fa-wasm_1.1.0_1785294476418_0.9915379456605318","host":"s3://npm-registry-packages-npm-production"}},"1.1.1":{"name":"2fa-wasm","version":"1.1.1","description":"Biblioteca 2FA zero-allocation (HOTP/TOTP/Base32, RFC 4226/6238/4648) en AssemblyScript/WebAssembly con wrapper TypeScript. Compatible con otpauth:// (Google Authenticator), validación constant-time, ~478K TOTP/s.","author":{"name":"Edison Manrique"},"license":"Apache-2.0","type":"module","sideEffects":false,"main":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"scripts":{"asbuild":"asc assembly/index.ts --target release","asbuild:debug":"asc assembly/index.ts --target debug","build:ts":"esbuild src/index.ts --bundle --format=esm --minify --platform=browser --outfile=dist/index.js && tsc --emitDeclarationOnly","build":"bun run asbuild && bun run build:ts","prepublishOnly":"bun run build","typecheck":"tsc --noEmit","test":"bun test","test:correctness":"bun test test/index.test.ts","test:stress":"bun test test/stress.test.ts","examples":"bun examples/server.ts"},"keywords":["wasm","webassembly","assemblyscript","typescript","2fa","two-factor","otp","totp","hotp","base32","hmac","sha1","sha256","sha512","otpauth","google-authenticator","authenticator","zero-allocation","zero-alloc","constant-time","rfc4226","rfc6238","rfc4648","rfc2104"],"repository":{"type":"git","url":"git+ssh://git@github.com/edison-manrique/2fa-wasm.git"},"bugs":{"url":"https://github.com/edison-manrique/2fa-wasm/issues"},"homepage":"https://github.com/edison-manrique/2fa-wasm#readme","engines":{"node":">=18.0.0"},"gitHead":"0c67db9325d479758e1aca1b1c484dc2bc9ce9f9","_id":"2fa-wasm@1.1.1","_nodeVersion":"22.15.0","_npmVersion":"11.13.0","dist":{"integrity":"sha512-Kp2DOeXMoswrpL7sYZwetXwcMBSBVLIWhaN/xjQCS0DDxitU+zEpEJPDifyG9NVXHwFt7LXvW0lrwUNgHokHPA==","shasum":"57e9a82389679ab5096e30d3d94b1581e71fabaa","tarball":"https://registry.npmjs.org/2fa-wasm/-/2fa-wasm-1.1.1.tgz","fileCount":15,"unpackedSize":82741,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQD6GVLMiNFpgercYUsjv5AwLWm8mF0kY5BaHMQG7qOVkQIhAKKWB8e29bMRn1yaEU+rwOmjc64ORB+m8686QSlrjZXM"}]},"_npmUser":{"name":"edison-manrique","email":"edison.manrique.chocce@gmail.com"},"directories":{},"maintainers":[{"name":"edison-manrique","email":"edison.manrique.chocce@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/2fa-wasm_1.1.1_1785296572086_0.6417835480218361"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-26T01:21:47.890Z","modified":"2026-07-29T03:42:52.410Z","1.0.0":"2026-07-26T01:21:48.160Z","1.1.0":"2026-07-29T03:07:56.574Z","1.1.1":"2026-07-29T03:42:52.247Z"},"bugs":{"url":"https://github.com/edison-manrique/2fa-wasm/issues"},"author":{"name":"Edison Manrique"},"license":"Apache-2.0","homepage":"https://github.com/edison-manrique/2fa-wasm#readme","keywords":["wasm","webassembly","assemblyscript","typescript","2fa","two-factor","otp","totp","hotp","base32","hmac","sha1","sha256","sha512","otpauth","google-authenticator","authenticator","zero-allocation","zero-alloc","constant-time","rfc4226","rfc6238","rfc4648","rfc2104"],"repository":{"type":"git","url":"git+ssh://git@github.com/edison-manrique/2fa-wasm.git"},"description":"Biblioteca 2FA zero-allocation (HOTP/TOTP/Base32, RFC 4226/6238/4648) en AssemblyScript/WebAssembly con wrapper TypeScript. Compatible con otpauth:// (Google Authenticator), validación constant-time, ~478K TOTP/s.","maintainers":[{"name":"edison-manrique","email":"edison.manrique.chocce@gmail.com"}],"readme":"# 🔐 2FA WASM\n\nBiblioteca de autenticación de dos factores (2FA) ultra-rápida y de alto rendimiento compilada en WebAssembly (WASM) utilizando AssemblyScript y empaquetada con un wrapper TypeScript Zero-Allocation.\n\nSoporta **HOTP** (RFC 4226), **TOTP** (RFC 6238) y **Base32** (RFC 4648) sobre **HMAC-SHA1 / SHA256 / SHA512** —con **validación de tokens en tiempo constante** (a prueba de _timing attacks_) y compatibilidad total con **`otpauth://`** (Google Authenticator, Authy, etc.)— con rendimiento extremo (**~478 K TOTP/s** rotando los 3 algoritmos) y **0 % de presión sobre el Garbage Collector (GC)**.\n\n---\n\n## 🚀 Características Principales\n\n- ⚡ **Máximo Rendimiento**: Núcleo HMAC desplegado en WebAssembly con **~478 000 TOTP/s** (rotando SHA-1/256/512) y memoria completamente plana bajo carga.\n- 🧹 **Zero-Alloc (Cero Alocaciones GC)**: Alocador _arena_ estático (`memory.data` + `save/restore`) y contextos hash como _struct sobre puntero_ (`changetype`, sin `new` en el heap) — **`WASM Δ 0 B` verificado bajo 500 000 operaciones**.\n- 🌐 **Multiplataforma**: Funciona sin modificaciones en Node.js, Bun, Deno y Navegadores Web (Vite, Webpack, etc.).\n- 🛡️ **Seguridad Crypto**:\n  - **HMAC-SHA1 / SHA256 / SHA512** (RFC 2104) como primitiva de HOTP/TOTP.\n  - **Validación constant-time** de tokens: comparación por XOR acumulativo sin _early-exit_, inmune a ataques de timing.\n  - Correctitud **validada contra vectores oficiales** (RFC 4226 Ap. D, RFC 6238 Ap. B, RFC 4648) y **`node:crypto`** (36/36 tests).\n- 🔑 **HOTP / TOTP**: generadores y validadores con ventana de tolerancia, 4–8 dígitos, y los 3 algoritmos (SHA-1 por compatibilidad, SHA-256/512 para mayor seguridad).\n- 📱 **Compatibilidad `otpauth://`**: `toString()` genera URIs escaneables y `URI.parse()` las reconstruye — integración directa con Google Authenticator, Authy, 1Password, etc.\n- 🔐 **Secrets seguros**: generación aleatoria con `crypto.getRandomValues` y conversiones Base32/hex.\n- 📦 **Binario Compacto**: ~14 KB de WebAssembly optimizado.\n\n---\n\n## 📦 Instalación\n\n```bash\nnpm install 2fa-wasm\n```\n\nO con Bun / Yarn / pnpm:\n\n```bash\nbun add 2fa-wasm\n```\n\n---\n\n## 💻 Guía de Uso\n\n### 1. Inicializar la biblioteca\n\n```ts\nimport { TwoFaWasm } from \"2fa-wasm\"\n\n// Carga automática desde la URL por defecto (navegador / bundler)\nawait TwoFaWasm.load()\n\n// O cargando desde un buffer binario explícito (útil para Node.js / Bun):\n// import { readFileSync } from \"node:fs\"\n// const wasmBuffer = readFileSync(\"node_modules/2fa-wasm/dist/2fa.wasm\")\n// await TwoFaWasm.fromBuffer(wasmBuffer)\n```\n\n> La carga se realiza **una sola vez**. Después puedes usar `TOTP` / `HOTP` / `Secret` / `Base32` / `URI` directamente (usan el singleton global).\n\n### 2. TOTP (Time-based OTP — RFC 6238)\n\nEl caso de uso más común (Google Authenticator y compatibles).\n\n```ts\nimport { TwoFaWasm, TOTP, Secret } from \"2fa-wasm\"\n\nawait TwoFaWasm.load()\n\n// 🔐 Genera un secret nuevo (20 bytes, típico para SHA-1)\nconst secret = new Secret()\nconsole.log(secret.base32) // → \"JBSWY3DPEHPK3PXP…\" (para mostrar al usuario / QR)\n\n// 🔑 Genera el código TOTP actual (6 dígitos)\nconst code = TOTP.generate({ secret })\nconsole.log(code) // → \"123456\"\n\n// ✅ Valida un código ingresado por el usuario (ventana ±1 por defecto)\nconst delta = TOTP.validate({ token: code, secret })\nconsole.log(delta) // → 0 (período exacto) | ±1 (ventana) | null (inválido)\n\n// ⏱️ Segundos restantes del período actual\nconst totp = new TOTP({ secret, period: 30 })\nconsole.log(totp.remaining()) // → 18\n```\n\n> 🛡️ Para mayor seguridad usa SHA-256/512 y un secret de 32/64 bytes: `new TOTP({ secret: new Secret({ size: 32 }), algorithm: \"SHA256\" })`.\n\n### 3. HOTP (Counter-based OTP — RFC 4226)\n\n```ts\nimport { TwoFaWasm, HOTP, Secret } from \"2fa-wasm\"\n\nawait TwoFaWasm.load()\n\nconst secret = Secret.fromBase32(\"JBSWY3DPEHPK3PXP\")\n\n// 🔑 Genera el código HOTP para un counter (vector RFC 4226)\nconst code = HOTP.generate({ secret, counter: 0 })\nconsole.log(code) // → \"755224\"\n\n// ✅ Valida con ventana de tolerancia (±window)\nconst delta = HOTP.validate({ token: \"287082\", secret, counter: 0, window: 1 })\nconsole.log(delta) // → 1 (el token corresponde al counter 1, dentro de la ventana)\n\n// 🔄 API con estado: el counter se auto-incrementa en cada generate()\nconst hotp = new HOTP({ secret, counter: 0 })\nhotp.generate() // counter 0 → luego incrementa a 1\nhotp.generate() // counter 1 → luego incrementa a 2\n```\n\n### 4. Secret (gestión de la clave compartida)\n\n```ts\nimport { TwoFaWasm, Secret } from \"2fa-wasm\"\n\nawait TwoFaWasm.load()\n\n// 🎲 Aleatorio (20 bytes por defecto; 32/64 para SHA-256/512)\nconst s1 = new Secret()\nconst s2 = new Secret({ size: 32 })\n\n// 📥 Desde un Base32 existente (pegado por el usuario)\nconst s3 = Secret.fromBase32(\"JBSWY3DPEHPK3PXP\")\n\nconsole.log(s3.base32) // → \"JBSWY3DPEHPK3PXP\"\nconsole.log(s3.hex) // → \"48656c6c6f21deadbeef\"\nconsole.log(s3.bytes) // → Uint8Array (bytes crudos)\n```\n\n### 5. Base32 (RFC 4648)\n\n```ts\nimport { TwoFaWasm, Base32 } from \"2fa-wasm\"\n\nawait TwoFaWasm.load()\n\nconst encoded = Base32.encode(new TextEncoder().encode(\"foobar\"))\nconsole.log(encoded) // → \"MZXW6YTBOI\"\n\nconst decoded = Base32.decode(\"MZXW6YTBOI\") // → Uint8Array (bytes de \"foobar\")\n\n// 🧹 Decode tolerante: acepta lowercase, espacios y padding (típico de secrets pegados a mano)\nBase32.decode(\"mzxw 6ytb oi======\") // → mismos bytes\n```\n\n### 6. URI `otpauth://` (compatible con Google Authenticator)\n\nGenera y parsea URIs estándar para códigos QR y migración entre apps.\n\n```ts\nimport { TwoFaWasm, TOTP, URI } from \"2fa-wasm\"\n\nawait TwoFaWasm.load()\n\nconst totp = new TOTP({\n  issuer: \"MiApp\",\n  label: \"usuario@ejemplo.com\",\n  secret: \"JBSWY3DPEHPK3PXP\",\n  algorithm: \"SHA1\",\n  digits: 6,\n  period: 30\n})\n\n// 📱 Genera la URI otpauth:// (para el código QR)\nconst uri = totp.toString()\n// → \"otpauth://totp/MiApp:usuario%40ejemplo.com?secret=JBSWY3DPEHPK3PXP&algorithm=SHA1&digits=6&period=30&issuer=MiApp\"\n\n// 📥 Reconstruye desde una URI (ej. escaneada o importada)\nconst parsed = URI.parse(uri)\nconsole.log(parsed.issuer) // → \"MiApp\"\nconsole.log(parsed.generate()) // → código TOTP actual\n```\n\n> `URI.parse()` devuelve una instancia `HOTP` o `TOTP` según el tipo de URI, lista para `generate()`/`validate()`.\n\n### 7. API de bajo nivel (`TwoFaWasm`)\n\nAcceso directo a las primitivas del WASM (uso avanzado).\n\n```ts\nimport { TwoFaWasm } from \"2fa-wasm\"\n\nconst wasm = await TwoFaWasm.load()\n\n// 🔏 HMAC directo (SHA1 / SHA256 / SHA512)\nconst mac = wasm.hmac(\"SHA256\", clave, mensaje) // → Uint8Array\n\n// ⏱️ Counter y segundos restantes de TOTP\nconst counter = wasm.totpCounter(30) // counter del período actual\nconst remaining = wasm.totpRemaining(30) // segundos restantes\n\n// 🔑 Generación/validación raw (bytes, sin formatear)\nconst code = wasm.hotpGenerate(secretBytes, 0, 6, \"SHA1\") // → \"755224\"\nconst delta = wasm.totpValidate(\"123456\", secretBytes, Date.now(), 30, 6, 1, \"SHA1\")\n```\n\n### 8. Utilidades\n\n```ts\nimport { bytesToHex, hexToBytes, toUint8Array, getRandomBytes } from \"2fa-wasm\"\n\nconst hex = bytesToHex(new Uint8Array([0xde, 0xad, 0xbe, 0xef])) // \"deadbeef\"\nconst bytes = hexToBytes(\"deadbeef\") // Uint8Array(4)\nconst utf8 = toUint8Array(\"texto\") // string → Uint8Array (UTF-8)\nconst random = getRandomBytes(32) // 32 bytes aleatorios (crypto-safe)\n```\n\n---\n\n## 📊 Benchmarks de Rendimiento\n\nPruebas ejecutadas en Bun (JavaScriptCore) sobre un procesador x86-64 moderno, en single-thread:\n\n| Operación                            | Rendimiento            | Memoria        |\n| ------------------------------------ | ---------------------- | -------------- |\n| TOTP generate (3 algoritmos rotados) | **~478 K ops/s**       | —              |\n| Estrés 500 000 ops                   | estable (~478 K ops/s) | **WASM Δ 0 B** |\n| Heap JS tras 500 000 ops             | —                      | **Δ ~0.02 MB** |\n\n**Rondas de estrés (zero-alloc verificado):**\n\n| Iteraciones | Ops/seg | Heap Δ  | WASM Δ  |\n| ----------- | ------- | ------- | ------- |\n| 10 000      | 328 185 | 0.00 MB | **0 B** |\n| 50 000      | 477 666 | 0.00 MB | **0 B** |\n| 100 000     | 486 251 | 0.00 MB | **0 B** |\n| 500 000     | 478 387 | 0.02 MB | **0 B** |\n\n> El throughput se **estabiliza** (~478 K ops/s) en lugar de degradarse, y la memoria lineal del WASM **nunca crece** (`Δ 0 B`) — la garantía zero-alloc se cumple bajo carga real, no solo en el caso feliz.\n\n**Validación de correctitud (36/36 tests):**\n\n| Estándar                | Cobertura                                          |\n| ----------------------- | -------------------------------------------------- |\n| HOTP — RFC 4226, Ap. D  | 10 contadores (SHA-1, 6 dígitos) + ventana/delta   |\n| TOTP — RFC 6238, Ap. B  | 6 timestamps × SHA-1/256/512 (8 dígitos)           |\n| Base32 — RFC 4648       | vectores + tolerancia (padding/lowercase/espacios) |\n| HMAC — vs `node:crypto` | SHA-1/256/512 + clave larga (> bloque)             |\n\n---\n\n## 🏗️ Arquitectura Zero-Allocation\n\n- **Alocador _arena_ estático**: 32 KB reservados en el _data segment_ del WASM en **tiempo de compilación** (`memory.data`), con `save()`/`restore()` por operación — ninguna reserva toca el heap del runtime.\n- **Contextos como _struct sobre puntero_**: los contextos hash (SHA-1/256/512) se superponen sobre el scratchpad vía `changetype` (sin `new`), eliminando por completo las alocaciones en el heap.\n- **Validación constant-time**: `hotp_validate_raw` compara el token generado con el recibido mediante XOR + OR acumulativo de longitud fija (sin _early-exit_), evitando fugas por timing.\n- **Única asignación**: el string del código OTP que se entrega al usuario (inevitable); todo lo demás vive en el scratchpad.\n- **Resultado verificado**: `WASM Δ 0 B` y heap estable bajo 500 000 operaciones.\n\n---\n\n## 🛠️ Comandos de Desarrollo\n\n```bash\n# Compilar binario WASM (AssemblyScript) + bundle TypeScript (esbuild minificado)\nbun run build\n\n# Compilar solo el binario WASM\nbun run asbuild          # release → dist/2fa.wasm\nbun run asbuild:debug    # debug → build/debug.wasm + .wat + sourcemap\n\n# Verificación de tipos\nbun run typecheck\n\n# Tests (suite de correctitud + estrés zero-alloc)\nbun test\n```\n\n---\n\n## 📁 Estructura del Proyecto\n\n```\n2fa-wasm/\n├── assembly/            # Núcleo en AssemblyScript (→ WebAssembly)\n│   ├── index.ts         # Exportaciones WASM (hmac, base32, hotp, totp)\n│   ├── memory.ts        # Alocador arena estático (Memory: alloc/save/restore)\n│   ├── sha1.ts          # SHA-1 (struct sobre puntero, compress desplegado)\n│   ├── sha2/\n│   │   ├── sha256.ts    # SHA-256 (sliding-window)\n│   │   ├── sha512.ts    # SHA-512 (sliding-window)\n│   │   ├── constants.ts # Constantes K e IV\n│   │   └── common.ts    # Helpers (bswap, Ch, Maj, Sigma, sigma)\n│   ├── hmac.ts          # Dispatch HMAC interno (SHA1/256/512)\n│   ├── hotp.ts          # HOTP (RFC 4226, validación constant-time)\n│   ├── totp.ts          # TOTP (RFC 6238)\n│   └── base32.ts        # Base32 (RFC 4648, decode tolerante)\n├── src/                 # Wrapper en TypeScript\n│   ├── index.ts         # Punto de entrada (re-exports)\n│   ├── twofa-wasm.ts    # Cargador (load/fromUrl/fromBuffer) + API bajo nivel\n│   ├── allocator.ts     # WasmAllocator (caché de heap, zero-alloc)\n│   ├── base32.ts        # Base32\n│   ├── secret.ts        # Secret (bytes/base32/hex)\n│   ├── hotp.ts          # HOTP + interfaces\n│   ├── totp.ts          # TOTP + interfaces\n│   ├── uri.ts           # Parser otpauth://\n│   └── types.ts         # Tipos (HashAlgorithm, configs) + utilidades\n├── test/\n│   ├── index.test.ts    # Suite de correctitud (RFC 4226/6238/4648, node:crypto)\n│   └── stress.test.ts   # Estrés zero-alloc (WASM Δ 0 B)\n├── dist/                # Build (generado)\n├── asconfig.json        # Configuración de AssemblyScript\n├── package.json\n├── tsconfig.json\n├── LICENSE              # Apache-2.0\n└── README.md\n```\n\n---\n\n## 📜 Licencia\n\n[Apache License 2.0](./LICENSE) © **Edison Manrique**\n\n> **Exención de responsabilidad:** este software se proporciona \"tal cual\" (AS IS), sin garantía de ningún tipo. Aunque HOTP, TOTP, HMAC y Base32 son estándares (RFC 4226 / RFC 6238 / RFC 2104 / RFC 4648), esta implementación no ha sido auditada formalmente y no debe emplearse en aplicaciones de seguridad crítica sin verificación independiente.\n","readmeFilename":"README.md"}