nip04_encrypt/decrypt previously double-hashed the ECDH shared secret
(SHA256 over the libsecp default hash) and packed base64(IV || ciphertext),
making signer-produced DMs readable only by itself.
- core/keys.rs: add ecdh_shared_secret_raw_x() using
secp256k1::ecdh::shared_secret_point — raw X coordinate, unhashed.
Existing hashed helpers unchanged (NIP-44 still uses them).
- nips/nip004.rs: use the raw-X key; emit base64(ct)?iv=base64(iv);
decrypt parses only the ?iv= format (standard-only, no legacy fallback;
missing separator -> Nip04InvalidFormat). Key derivation is
parity-independent, so the both-parity dance is removed.
- Tests: known-answer vector generated with nak (fixed key 1111..11,
peer 4f355bdcb7cc..., plaintext 'nak vector' ->
H3hKxnfd4MX/a9Rl0cvmFg==?iv=y8Ngg9dcK8XinwERJpzNsA==); format and
legacy-rejection tests; raw-X symmetry/regression test vs hashed ECDH.
- End-to-end verified both directions against a live signer daemon and
nak decrypt --nip04 / nak encrypt --nip04.
- Also includes pre-existing local changes: nip060/nip061, relay pool,
cashu service, Cargo.lock.