Skip to content

Conversation

alltheseas
Copy link
Collaborator

@alltheseas alltheseas commented Oct 16, 2025

Summary

adds support for sending and receiving nip-17 DMs

image

Checklist

  • I have read (or I am familiar with) the Contribution Guidelines
  • I have tested the changes in this PR
  • I have profiled the changes to ensure there are no performance regressions, or I do not need to profile the changes.
  • I have opened or referred to an existing github issue related to this change. Explore DM gift wrap (nip17)
  • My PR is either small, or I have split it into smaller logical commits that are easier to review
  • I have added the signoff line to all my commits. See Signing off your work
  • I have added appropriate changelog entries for the changes in this PR. See Adding changelog entries
    • I do not need to add a changelog entry. Reason: [Please provide a reason]
  • I have added appropriate Closes: or Fixes: tags in the commit messages wherever applicable, or made sure those are not needed. See Submitting patches

Test report

Please provide a test report for the changes in this PR. You can use the template below, but feel free to modify it as needed.

Device: iOS simulator 17 pro

iOS: iOS 26

Damus: 17 pro simulator

Setup: [Please provide a brief description of the setup you used for testing, if applicable]

Steps: [Please provide a list of steps you took to test the changes in this PR]

Results:

  • PASS
  • Partial PASS
    • Details: [Please provide details of the partial pass]

Other notes

[Please provide any other information that you think is relevant to this PR.]

@alltheseas
Copy link
Collaborator Author

@kernelkind feedback - ensure that nip-59 and nip-44 are implemented. Giftwraps related to NIP-17 should be implemented in nostrdb for performance reasons

@alltheseas
Copy link
Collaborator Author

alltheseas commented Oct 17, 2025

on implementation of nip-59, and nip-44

• Confirmation

  - damus/Core/NIPs/NIP44/NIP44.swift:229 derives the shared conversation key with secp256k1 ECDH + HKDF, then expands to the ChaCha20 key/nonce and HMAC key before performing v2 padding, encryption,
    and MAC tagging exactly as laid out in NIP-44; the payload serializer prefixes version 0x02 and base64-encodes the bundle at damus/Core/NIPs/NIP44/NIP44.swift:259.
  - damusTests/NIP44v2EncryptionTests.swift:36 exercises the implementation against the official nip44.vectors.json, covering conversation keys, message keys, deterministic vectors, random nonces, and
    failure cases, which confirms conformance instead of a best-effort port.
  - damus/Core/NIPs/NIP17/NIP17.swift:64 produces unsigned rumor events (no signature field), damus/Core/NIPs/NIP17/NIP17.swift:154 seals each rumor with a kind:13 event (empty tags, sender signature)
    and gift-wraps that seal with a fresh ephemeral key into kind:1059 that only carries the recipient p tag, matching the layering and metadata-hiding requirements from NIP-59.
  - Sending flows call NIP17.wrapMessage so every outgoing DM17 message is sealed and wrapped per spec before publish (damus/Features/DMs/Views/DMChatView.swift:153), while the UI keeps the original
    unsigned rumor for immediate display.
  - Incoming kind:1059 events run through NIP17.unwrapGiftWrap, which verifies the seal signature, checks the rumored author, and reconstructs a display event (damus/Features/Timeline/Models/
    HomeModel.swift:860), ensuring we only accept well-formed NIP-59 payloads.

  You can optionally run the existing NIP-44 unit suite (xcodebuild test focusing on NIP44v2EncryptingTests) if you want a fresh proof that nothing regressed.

On implementaion of giftwrap inside nostrdb:


Not yet. All gift-wrap logic lives in the Swift layer (damus/Core/NIPs/NIP17/NIP17.swift handles sealing/wrapping and damus/Features/Timeline/Models/HomeModel.swift:860 unwraps them), but the nostrdb
  core still knows nothing about NIP-17 kinds. The kind mapper in nostrdb/src/nostrdb.c:6999 only enumerates legacy kinds (no entries for 13, 14, 15, or 1059), there are no DM17 buckets or helpers
  declared in nostrdb/src/nostrdb.h, and nostrdb’s Swift bindings contain zero references to .dmSeal or .dmGiftWrap. So nostrdb currently just treats those events as opaque notes; the NIP-17-specific
  caching/indexing described in the integration plan hasn’t been implemented.

@alltheseas
Copy link
Collaborator Author

alltheseas commented Oct 17, 2025

@jb55 @danieldaquino can y'all provide guidance - let's see if we can bring giftwrapping to NDB

Bringing full NIP-17 gift wrapping into the nostrdb core would mean teaching the C/LMDB layer how to:

 - Perform the NIP-44 v2 crypto (ECDH → HKDF → ChaCha20 + HMAC).
 - Persist the new DM17 buckets and indexes the integration plan describes.
 - Expose new APIs/bindings so Swift calls into nostrdb for wrapping, sealing, caching, etc.

 nostrdb currently has none of that plumbing, and it doesn’t ship any ChaCha20/HKDF/HMAC implementations we could reuse—the Swift version relies on CryptoKit/CryptoSwift. Re‑implementing the
 cryptography correctly in C (or wiring in a vetted library) plus adding the database schema/migration work is a substantial project: it touches every layer of nostrdb and requires a careful design/
 audit to avoid security or migration regressions.

 I’m happy to start on it, but I’ll need more guidance before diving into something of that scope (e.g. acceptable crypto dependencies, target schema, migration strategy). Let me know how you’d like to
 proceed, or if you want a more incremental step (for example, moving the wrapper through a nostrdb C shim that still calls into Swift for crypto).

Here’s what I need nailed down before implementing NIP‑17 wrapping inside the nostrdb core:

 - Crypto stack: Should we implement the NIP-44 v2 primitives ourselves in C, or can we depend on an external library? If external is OK, which one(s) are acceptable for HKDF, ChaCha20, and HMAC-
   SHA256?
 - Randomness source: Is there a preferred CSPRNG we must use inside nostrdb, or can we rely on the existing random facilities?
 - Key management: How should nostrdb receive and store DM key material (self privkeys, aliases)? Is it acceptable to keep it only in memory via a keyring API, and how are key rotations/alias updates
   expected to be triggered?
 - Storage layout: Do we follow the integration-plan sketch (new LMDB buckets for envelopes/cache)? If so, need confirmation on key/value formats, room hashes, and migration/versioning requirements.
 - API surface: What Swift bindings are expected? e.g. ndb_dm17_wrap_message, ndb_dm17_unwrap, ndb_dm17_list_rooms, etc. Any constraints on return types or async behavior?
 - Performance: Any throughput or latency targets for wrapping/unwrapping? Should we cache seals or re-encrypt on demand? Acceptable limits on cache size?
 - Testing/Auditing: Are there required test vectors or external audits we must match? Should we reuse the existing Swift test vectors or add new C-level ones?
 - Rollout path: Do we need backward compatibility for existing stored wraps? If the DB schema changes, how should older clients handle it?

 Answering these will let me design the nostrdb-side implementation confidently.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant