refactor: replace NIP-04 + custom crypto with nostr-sdk + NIP-44 #1

Merged
k9ert merged 5 commits from nazim/nostr-cli:refactor/nostr-sdk-nip44 into main 2026-02-23 07:38:39 +00:00
Contributor

What

Replaces all custom cryptography and NIP-04 encryption with nostr-sdk (rust-nostr Python bindings) and NIP-44.

Why

  • NIP-04 is deprecated — known vulnerabilities (no padding, IV reuse risks, metadata leaks)
  • NIP-44 is the replacement (XChaCha20-Poly1305, HMAC-SHA256 key derivation, proper padding)
  • 4 dependencies → 1websockets + cryptography + secp256k1 + bech32 all replaced by nostr-sdk
  • nostr-sdk handles key management, event signing, relay connections, and encryption — no reason to reimplement any of it

Changes

Encryption

  • Outgoing DMs: NIP-44 V2 (was NIP-04)
  • Incoming DMs: NIP-44 first, NIP-04 fallback (backwards compatible)

Dependencies

  • Before: websockets, cryptography, secp256k1, bech32
  • After: nostr-sdk (single dependency, Rust-backed)

Key management

  • generate_keypair()Keys.generate()
  • load_identity()Keys.parse() (handles nsec, hex automatically)
  • No more manual bech32 ↔ hex conversion

Relay communication

  • Custom websocket code → nostr-sdk.Client (connection pooling, auto-reconnect)
  • Event signing via EventBuilder.sign_with_keys()

Unchanged

  • Injection shield (regex + local DeBERTa)
  • Wake mechanism
  • CLI interface and all commands

Tests

28/28 passing — updated for nostr-sdk API, added NIP-44 roundtrip, NIP-04 backwards compat, and wrong-key-fails tests.

## What Replaces all custom cryptography and NIP-04 encryption with `nostr-sdk` (rust-nostr Python bindings) and NIP-44. ## Why - **NIP-04 is deprecated** — known vulnerabilities (no padding, IV reuse risks, metadata leaks) - **NIP-44** is the replacement (XChaCha20-Poly1305, HMAC-SHA256 key derivation, proper padding) - **4 dependencies → 1** — `websockets` + `cryptography` + `secp256k1` + `bech32` all replaced by `nostr-sdk` - `nostr-sdk` handles key management, event signing, relay connections, and encryption — no reason to reimplement any of it ## Changes ### Encryption - **Outgoing DMs:** NIP-44 V2 (was NIP-04) - **Incoming DMs:** NIP-44 first, NIP-04 fallback (backwards compatible) ### Dependencies - **Before:** `websockets`, `cryptography`, `secp256k1`, `bech32` - **After:** `nostr-sdk` (single dependency, Rust-backed) ### Key management - `generate_keypair()` → `Keys.generate()` - `load_identity()` → `Keys.parse()` (handles nsec, hex automatically) - No more manual bech32 ↔ hex conversion ### Relay communication - Custom websocket code → `nostr-sdk.Client` (connection pooling, auto-reconnect) - Event signing via `EventBuilder.sign_with_keys()` ### Unchanged - Injection shield (regex + local DeBERTa) - Wake mechanism - CLI interface and all commands ## Tests 28/28 passing — updated for nostr-sdk API, added NIP-44 roundtrip, NIP-04 backwards compat, and wrong-key-fails tests.
- Replace websockets, cryptography, secp256k1, bech32 deps with single nostr-sdk
- Encrypt outgoing DMs with NIP-44 (V2) instead of NIP-04
- Listen decrypts NIP-44 first, falls back to NIP-04 for old messages
- All key management (keygen, parse, bech32) via nostr-sdk Keys
- Event signing via nostr-sdk EventBuilder.sign_with_keys()
- Relay comms via nostr-sdk Client (connection pooling, auto-reconnect)
- Injection shield and wake mechanism unchanged
- 28 tests passing (updated for nostr-sdk API)
- Fix subscribe() to pass single Filter (not list) per nostr-sdk 0.44 API
- Fix listen_for_dms to use fetch_events() with timedelta timeout
- Add test_e2e.py: two-agent DM test over real relay (wss://relay.damus.io)
  - TestE2EDM: NIP-44 send → NIP-44 receive
  - TestE2ENip04Compat: NIP-04 send → NIP-04 fallback receive
- 30/30 tests passing (28 unit + 2 e2e)
Owner

🔍 Recherche: Python Nostr Libraries — Stand der Dinge

k9ert hat angemerkt, dass die Python-Nostr-Landschaft bescheiden ist. Hier der Überblick:

Pure Python Libraries (alle problematisch)

Library Status Problem
python-nostr ⚠️ Veraltet Kaum maintained, alte NIP-Implementierungen
pynostr ⚠️ Nische Fork, nutzt coincurve, kleine Community
nostr-protocol Archived War die low-level lib von rust-nostr, deprecated

Rust + Python Bindings

Library Version Status
nostr-sdk v0.44.2 (Jan 2026) Aktiv maintained

nostr-sdk ist der klare Gewinner — und genau das was dieser PR nutzt:

  • Backed by rust-nostr (aktives Projekt)
  • NIP-04 + NIP-44 (wichtig: NIP-04 hat known vulnerabilities)
  • NWC, Relay Pool, auto-reconnect built-in
  • Multi-Platform (Linux x86/ARM, macOS, Windows)
  • ALPHA state, aber API stabilisiert sich
  • 1 dep statt 4 → weniger Angriffsfläche

Zum PR

Dieser PR geht in die richtige Richtung: nostr-sdk als single dependency, NIP-44 als Default mit NIP-04 Fallback, sauberes Aufräumen der custom Crypto.

Frage an @noopsec: Du hattest im Chat auch Verbesserungen vorgeschlagen (Class-Based Architecture, NostrMessage Dataclass, Multi-Relay parallel, receive One-Shot Command). Sollen wir die in diesen PR reinmergen oder als Follow-Up PR?

Aus meiner Sicht wäre der einfachste Weg:

  1. Diesen PR als Basis mergen (Nazim hat die schwere Arbeit gemacht: nostr-sdk Migration + NIP-44 + Tests)
  2. Follow-Up PR von noopsec für die Architektur-Verbesserungen (Class refactor, Dataclass, receive command) on top

So haben wir eine saubere Git-History und keine Merge-Konflikte.

Was meint ihr @k9ert @noopsec?

## 🔍 Recherche: Python Nostr Libraries — Stand der Dinge k9ert hat angemerkt, dass die Python-Nostr-Landschaft bescheiden ist. Hier der Überblick: ### Pure Python Libraries (alle problematisch) | Library | Status | Problem | |---------|--------|---------| | `python-nostr` | ⚠️ Veraltet | Kaum maintained, alte NIP-Implementierungen | | `pynostr` | ⚠️ Nische | Fork, nutzt coincurve, kleine Community | | `nostr-protocol` | ❌ **Archived** | War die low-level lib von rust-nostr, deprecated | ### Rust + Python Bindings | Library | Version | Status | |---------|---------|--------| | **`nostr-sdk`** | v0.44.2 (Jan 2026) | ✅ Aktiv maintained | **`nostr-sdk` ist der klare Gewinner** — und genau das was dieser PR nutzt: - Backed by [rust-nostr](https://github.com/rust-nostr/nostr) (aktives Projekt) - NIP-04 + **NIP-44** (wichtig: NIP-04 hat known vulnerabilities) - NWC, Relay Pool, auto-reconnect built-in - Multi-Platform (Linux x86/ARM, macOS, Windows) - ALPHA state, aber API stabilisiert sich - 1 dep statt 4 → weniger Angriffsfläche ### Zum PR Dieser PR geht in die richtige Richtung: `nostr-sdk` als single dependency, NIP-44 als Default mit NIP-04 Fallback, sauberes Aufräumen der custom Crypto. **Frage an @noopsec:** Du hattest im Chat auch Verbesserungen vorgeschlagen (Class-Based Architecture, NostrMessage Dataclass, Multi-Relay parallel, `receive` One-Shot Command). Sollen wir die in diesen PR reinmergen oder als Follow-Up PR? Aus meiner Sicht wäre der einfachste Weg: 1. **Diesen PR als Basis mergen** (Nazim hat die schwere Arbeit gemacht: nostr-sdk Migration + NIP-44 + Tests) 2. **Follow-Up PR von noopsec** für die Architektur-Verbesserungen (Class refactor, Dataclass, receive command) on top So haben wir eine saubere Git-History und keine Merge-Konflikte. Was meint ihr @k9ert @noopsec?
ci: add Forgejo Actions workflow (test matrix + lint)
Some checks failed
CI / test (3.11) (pull_request) Failing after 5s
CI / test (3.12) (pull_request) Failing after 5s
CI / test (3.13) (pull_request) Failing after 6s
CI / lint (pull_request) Failing after 5s
ad0c15ca42
ci: add pytest to test dependencies
Some checks failed
CI / test (3.11) (pull_request) Successful in 7s
CI / test (3.12) (pull_request) Successful in 8s
CI / lint (pull_request) Failing after 6s
CI / test (3.13) (pull_request) Successful in 8s
feee1e5d57
style: fix ruff lint + format issues
All checks were successful
CI / test (3.11) (pull_request) Successful in 8s
CI / test (3.12) (pull_request) Successful in 8s
CI / lint (pull_request) Successful in 6s
CI / test (3.13) (pull_request) Successful in 8s
7fba962760
k9ert merged commit 9f61a9e8c0 into main 2026-02-23 07:38:39 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Hermes/nostr-cli!1
No description provided.