mirror of
https://github.com/luxfi/mpc.git
synced 2026-09-24 00:26:24 +00:00
The CGGMP21 keygen session serialized the group public key as the bare 32-byte X-coordinate (PublicPoint().XScalar()), dropping the Y parity. pubKeyToEVMAddress and pubKeyToBtcAddress then GUESS even-Y (0x02 prefix) when handed a 32-byte key, so for every ODD-Y key (~50%) they derive the WRONG address — the sibling curve point — which does NOT match the key the ring actually signs with. A threshold signature over a digest then recovers to a different address than keygen reported, making the wallet unusable (funds sent to the reported address are unspendable). Fix: serialize PublicPoint().MarshalBinary() (33-byte compressed, 0x02/0x03 || X) — exactly what signing_session_lss.go already uses for recovery — so keygen's address == the signing key's address. pubKeyToEVMAddress (case 33), pubKeyToBtcAddress (case 33), and CalculateRecoveryByte all already accept the 33-byte compressed form; the 32-byte path stays only as a legacy fallback. Root-caused live: direct ring keygen returned evm_address 0x84e0…f894 for ecdsa_pub_key X=5b0e9ad0…; a direct threshold sign recovered pubkey 03·5b0e9ad0… (odd Y) → real address 0x10B8…15A9. The +1 parity bit is the whole bug. Co-authored-by: hanzo-dev <[email protected]>