3.8 KiB
NIP-4e
Decoupling encryption from identity
optional
draft
This NIP describes a system for users to share private data between their own devices that doesn't rely on all devices holding the user account private key.
The problem
Currently many NIPs rely on encrypting data from the user to themselves -- such that the data can be accessed later on a different device -- using NIP-04 or NIP-44 and the users as both the sender and the receiver, e.g. NIP-51 and NIP-60. This works fine, but it assumes all devices have direct or indirect access to the same secret key. This assumption cannot be fulfilled in the case of approaches where the key isn't known, such as when using FROST or MuSig2 signers.
Also, in some use cases having the encryption key be on device can drastically increase performance of encrypting and decrypting stuff, and such a thing is not possible to do while also using NIP-46 for keeping the user's main Nostr key safer. It's also not possible to perform any encryption while offline if the encryption keys live in a remote bunker.
There are probably other advantages to not tying the user's identity to the keys used for more mundane things such as encryption, which we can write here later.
The solution
- Every client on every device can generate a new device key and store it locally, while making its public key public in a Nostr event.
- The first device to come into the world will generate a random encryption key.
- When another device's device key is spotted, the device that knows the original encryption key encrypts that key to the target device's device key using NIP-44 and sends it out.
- Encryption and decryption are performed using the encryption key using the NIP-44 algorithm, skipping the first step and proceeding with conversation key set to the shared encryption key.
Specifics
All events should be signed by the user's pubkey.
- encryption key announcement (
kind:4330
)
The purpose of this event is for a client to tell other clients that a global encryption key exists (and what is the latest). Each encryption key has an ID given by the first 16 chars of its hex-encoded sha256 hash output.
{
"kind": 4330,
"pubkey": "<author pubkey>",
"tags": [
["p", "<device pubkey>"],
["latest", "<sha256(encryption-key).take(8).hex()>"]
]
// other fields...
}
- device key announcement event (
kind:4331
)
{
"kind": 4331,
"pubkey": "<author pubkey>",
"tags": [
["p", "<device pubkey>"]
],
"content": "device key for client X on platform Y"
// other fields...
}
- encryption key sharing event (
kind:4332
)
These should be deleted after they're read and used.
{
"kind": 4332,
"pubkey": "<author pubkey>",
"tags": [
["p", "<device pubkey>"]
],
"content": "<nip44_encrypt(encryption-key)>"
// other fields...
}
-
Usage
- clients can rotate the latest encryption key for a user anytime -- any time they do it they should publish a new
kind:4330
event then a newkind:4332
event for every other client they know of. - clients can rotate their device key, which is equivalent to them being a totally new client from the point of view of the other clients.
- clients may exclude device keys from other clients known to be compromised by just blacklisting them and then rotating the encryption key.
- since every new iteration of the encryption key has a natural ID, whenever it is used to encrypt something (for example, a NIP-51 list), the ID should be added to the event as a tag
["ekey", "<id>"]
. - clients should keep track of past encryption keys until they're confident that all the possible events that may have used the previous encryption key were properly decrypted and updated to the latest key.
- clients can rotate the latest encryption key for a user anytime -- any time they do it they should publish a new