Assigned: @kwsantiago
Decision: build it, matching the reference signer (Amber)
NIP-44 v3 is not yet in the NIP-44 spec (v2 is current), but the reference signer ships a full implementation per the nostr-land/nip44v3 draft, so keep follows it for interop. Amber: Nip44v3 cipher + NIP44_V3_ENCRYPT / NIP44_V3_DECRYPT signer types + nip44v3Encrypt/Decrypt(plaintext, priv, pub, kind, scope).
Algorithm (from Amber Nip44v3.kt, version byte 0x03)
- ECDH(secp256k1) → HKDF-SHA256, salt
"nip44-v3\x00" || nonce (32-byte nonce), info encryption_key / mac_key.
- ChaCha20 with an all-zeroes 96-bit nonce over padded plaintext (v2-style min-32 padding).
- HMAC-SHA256 over
nonce || kind || scope_len || scope || ciphertext.
- kind + scope are authenticated alongside the ciphertext (cross-context replay protection) — the v3 distinction vs v2.
- Wire (base64):
version(0x03) || nonce(32) || mac(32) || kind(u32be) || scope_len(u32be) || scope || ciphertext.
- Production must not allow caller-supplied nonce (Amber exposes a nonce overload for tests only).
Proposed work (RMP: crypto in Rust)
- keep (Rust): add
nip44_v3 to keep-core crypto alongside v2 (nip44_v3_encrypt/decrypt(plaintext, priv, pub, kind, scope)), fail-closed on malformed/short payloads + MAC mismatch + missing kind. Expose over FFI (keep-mobile). Port Amber's Nip44v3Test.kt vectors for parity.
- keep-android: wire
NIP44_V3_ENCRYPT / NIP44_V3_DECRYPT NIP-55 request types (kind + scope params) on both transports + the NIP-46 methods; distinct permission scope from v2; reject malformed v3 (missing kind) fail-closed.
Cadence
keep PR (cipher + FFI + tests) → merge → pin → keep-android PR (NIP-55/46 wiring + permission scope).
Priority
Emerging — v3 is a draft, but the reference signer implements it; build for interop parity.
Assigned: @kwsantiago
Decision: build it, matching the reference signer (Amber)
NIP-44 v3 is not yet in the NIP-44 spec (v2 is current), but the reference signer ships a full implementation per the
nostr-land/nip44v3draft, so keep follows it for interop. Amber:Nip44v3cipher +NIP44_V3_ENCRYPT/NIP44_V3_DECRYPTsigner types +nip44v3Encrypt/Decrypt(plaintext, priv, pub, kind, scope).Algorithm (from Amber
Nip44v3.kt, version byte 0x03)"nip44-v3\x00" || nonce(32-byte nonce), infoencryption_key/mac_key.nonce || kind || scope_len || scope || ciphertext.version(0x03) || nonce(32) || mac(32) || kind(u32be) || scope_len(u32be) || scope || ciphertext.Proposed work (RMP: crypto in Rust)
nip44_v3tokeep-corecrypto alongside v2 (nip44_v3_encrypt/decrypt(plaintext, priv, pub, kind, scope)), fail-closed on malformed/short payloads + MAC mismatch + missing kind. Expose over FFI (keep-mobile). Port Amber'sNip44v3Test.ktvectors for parity.NIP44_V3_ENCRYPT/NIP44_V3_DECRYPTNIP-55 request types (kind + scope params) on both transports + the NIP-46 methods; distinct permission scope from v2; reject malformed v3 (missing kind) fail-closed.Cadence
keep PR (cipher + FFI + tests) → merge → pin → keep-android PR (NIP-55/46 wiring + permission scope).
Priority
Emerging — v3 is a draft, but the reference signer implements it; build for interop parity.