Uno: la señal A y la señal E eran la misma condición escrita dos veces, así que
un solo hecho llegaba al umbral de dos señales. Un pago corriente de bech32 a
taproot salía como cambio identificable con certeza PROBABLE, y el informe
mostraba las dos señales contradiciéndose entre sí.
Dos: sin señal fuerte, el índice caía en la salida menor. Pagando poco desde
una moneda grande el cambio es la mayor, así que la app señalaba el pago. El
detalle llegaba a decir 'el output redondo es el pago' y a continuación lo
marcaba como cambio. El peritaje usa ese índice, de modo que podía presentar
la dirección del destinatario como rastro del actor.
Ahora cada señal apunta a un output o admite que no puede, y si ninguna apunta
el índice queda vacío. tests/test5.js deja los dos casos como regresión.
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.