fix: endurecer la validación del xpub tras revisar la criptografía

La matemática pasa todos los vectores oficiales (RIPEMD-160, secp256k1, BIP32
vectores 1 y 2, bech32/BIP173) y no se ha tocado. Los fallos estaban en la
validación de la entrada:

- No se comprobaba la checksum del xpub: un carácter mal copiado generaba 200
  direcciones ajenas y el usuario veía su cartera 'sin actividad'. Mismo
  patrón de falso negativo silencioso que el resto de fallos de hoy.
- No se validaba la longitud (78 bytes) ni el formato de la clave pública.
- tpub se trataba como mainnet: la red se detectaba por prefijo de texto
  ('tb'/'u'/'v') y un tpub empieza por 't' pero no por 'tb'. Ahora se detecta
  por bytes de versión, con las diez variantes.
- deriveChildPubkey aceptaba índices endurecidos, imposibles desde una clave
  pública. No alcanzable desde la UI, pero debe defenderse sola.

Se añade tests/ con las cuatro baterías, documentando también qué NO cubren:
no sustituyen una auditoría externa.
This commit is contained in:
Aitor
2026-07-27 14:59:48 +02:00
parent 728ba655ee
commit 8d58ef7ae0
7 changed files with 316 additions and 6 deletions
+24
View File
@@ -40,6 +40,30 @@ y el versionado sigue [Versionado Semántico](https://semver.org/lang/es/):
**Qué puedes hacer** —, que aquí cobra sentido literal: todavía estás a
tiempo de cambiar la transacción.
### Corregido
- **Revisión de la criptografía watch-only.** Se verificó la derivación completa
contra los vectores oficiales de los estándares: RIPEMD-160 (los seis del
estándar, incluido el de un millón de caracteres), secp256k1, BIP32 (vectores
1 y 2) y bech32/BIP173. **La matemática es correcta y no se tocó.** Los fallos
estaban en la validación de la entrada:
- **No se comprobaba la suma de verificación del xpub.** Un carácter mal
copiado se aceptaba sin protestar y generaba 200 direcciones ajenas: el
usuario habría visto su cartera "sin actividad" y se habría quedado
tranquilo. Falso negativo silencioso, el mismo patrón que el resto de fallos
de esta jornada. Nuevo `decodeBase58Check`.
- **No se validaba la longitud** del material decodificado (deben ser 78
bytes) ni que la clave pública fuese comprimida (0x02/0x03).
- **`tpub` se trataba como mainnet.** La red se detectaba mirando si el texto
empezaba por "tb", "u" o "v" — y un `tpub`, el formato más común de testnet,
empieza por "t" pero no por "tb". Generaba direcciones `bc1…` a partir de
claves de testnet. Ahora se detecta por bytes de versión, que son
inequívocos, con las diez variantes (x/y/z/Y/Z y t/u/v/U/V).
- **`deriveChildPubkey` aceptaba índices endurecidos**, matemáticamente
imposibles desde una clave pública. No era alcanzable desde la interfaz,
pero una función criptográfica debe defenderse sola.
- Añadida la carpeta `tests/` con las cuatro baterías y su documentación,
incluido qué **no** cubren: no sustituyen una auditoría externa.
---
## [1.11.0] — 2026-07-27
### Añadido