-
Notifications
You must be signed in to change notification settings - Fork 602
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
NIP-59 Gift Wrap #468
NIP-59 Gift Wrap #468
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
NIP-59 | ||
====== | ||
|
||
Gift Wrap | ||
------------------------------- | ||
|
||
`draft` `optional` `author:kieran` | ||
|
||
This NIP defines a simple method to protect event metadata leakage by using randomly generated keys. | ||
|
||
A gift wrap event is a `kind 1059` event which wraps another event with a single use key. | ||
|
||
This event kind can be used to wrap DM's or other events which are considered private. | ||
|
||
This is similar in concept to Onion Routing. | ||
|
||
To construct a wrapped `kind 4` you first start by producing the `kind 4` event as normal, then create a random key and produce the `kind 1059` by encrypting the `kind 4` as a JSON string and storing it in `content` of the `kind 1059` using the same `p` tag to notify the recipient. | ||
v0l marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
Example wrapped event: | ||
```json | ||
{ | ||
"id": "3731dc639ada388aa5ee8c3404351868d4dd0fdcac00183e540669ddc25e8ad4", | ||
"pubkey": "4d02c0b4e16db38b80fa3b46548417a4ccc975337e29bc22da72132cf69f3b4a", | ||
"content": "7sW2yHvC5o/x6b0xCKPpH8KZJQeQYxt3Y53mxMV53yGQ5kn/jgMM74k+vfwegYBY9zjlQeTvyF5gYuJIHM4KN2SZq7zaCIKqTqMjYhLPI4VjIvowhmMuuZgRlB7cestrYh6OSSteICye6sxkS1NdpON31u+JNK/GHFVRJqfYF4Fnzaka2u9WHQKmm9/nN040OHZ41eT3YUWpaZHupVx1fuN6UoeyPjb2PW4yiwxD72LhlAoNGjR+otpWZ3kD6LU3Btrz8btjSD272wJXT/FBX5Gs59BMCDeJ4eReNfbbVBB5mlXvVqVC/tnHntVgNvAP5GsZE56/4t+kLqql0dqZU/haC8wpOxqtzqzhzxTHxS/IQ3HYpDnU8XuXUqNw1zOQhp0F65rXZUf9nN0gIa/zGa35fK2ek2p8K/3exKssO7fVxaMeTVxP7jEoCmn47gsy5mv4fH7MtxoWvWMapvGFLZf58NPy54ktvldOdGp9BJLO+6/2P7KJqb7bvu0EIPdYCcUt+muYwiJCUoHNFfFQwKrrpr23XuPQlPYNPUs6orbNBs/Oj8vMfZC5hb/AUaNanGtsqsBgqfEufyonBtihMzLZqn9OZNWHE7lYfnhSOZnUjStl03Bd94Qx1rp7IHZN?iv=cIiZuLb2FMsLzc+yYf+3IQ==", | ||
"kind": 1059, | ||
"created_at": 1682286690, | ||
"tags": [ | ||
[ | ||
"p", | ||
"63fe6318dc58583cfe16810f86dd09e18bfd76aabc24a0081ce2856f330504ed" | ||
] | ||
], | ||
"sig": "48e50d7c2d301a494e0cf250685fe4a1d7d03bdb0efae38a0e9575d2dea04b8c227f8bc35fd0451f7e1d7828a8c5f7b2f81fdab135d7a3ef92c4364aaaa8514f" | ||
} | ||
``` | ||
|
||
The `content` is NIP-04 encrypted JSON string with the temporary key, this is the inner event: | ||
v0l marked this conversation as resolved.
Show resolved
Hide resolved
|
||
```json | ||
{ | ||
"id": "08eb6f89e916b0bd747c039d33c11be0575c4c6d2c08363ada1243ea771a92d2", | ||
"pubkey": "63fe6318dc58583cfe16810f86dd09e18bfd76aabc24a0081ce2856f330504ed", | ||
"content": "73ZaB2WzPlIwwC55YnhsFA==?iv=1R2WlyrAk9VQ1NdhNuWmsw==", | ||
"kind": 4, | ||
"created_at": 1682286690, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. created_at can be made optional to save space, verifier assumes created_at is the same, and verifies the sig as if it is present (not as if it is excluded!). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think the additional complexity is worth the space saving. |
||
"tags": [ | ||
[ | ||
"p", | ||
"63fe6318dc58583cfe16810f86dd09e18bfd76aabc24a0081ce2856f330504ed" | ||
] | ||
], | ||
"sig": "703bbc5e15208b106ae0885c6c3f20ee97c1f9e6e45e617d49ea6200f3437d74cd5cb186df3656a18fa9b23c362c39676229ab98a323b29112b33cbbd8a910ca" | ||
} | ||
``` | ||
|
||
Clients can decrypt the gift wrapped event and can continue to work as normal. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if the sender of the event would like to decrypt it at a later date, they can use their "tweaked" private key, rather than a random key when producing the event. the "tweak value" can use any outer-envelope data, depending on the needs of the user. tweaking secp256k1 private keys is a well-known mechanism, and should be considered if a client wants to be able to read these events later from a message store, for example.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any change in how key material is handled needs to be added to NIP-07 or else it's not possible for me to use, this is why ephemeral keys work for me because i create the secret material.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this would not be a change to how key material is handled. these keys are still ephemeral. its just that if you really wanted to decrypt it later, however annoying that may be. you, optionally, could.
doesn't have to be part of this NIP, but it might want to be mentioned that since the creator of the event controls the ephemeral key, there's no hard requirement that it not be a derived key or a weak key, and no guarantee that the recipient can be assured that the creator cannot decrypt it later, or that the key was made poorly
if you wanted to be able to guarantee the key is hard, you can derive the ephemeral key in such a way that the recipient can verify it
for example, you can use the inner event id as the private key
then you'd have to crack the dlp or reverse a hash to create a weak key - the recipient can be assured the ephemeral key is free of artifacts or structure
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you think of adding a nonce key with a random string to the wrapped event JSON (not as a tag, but as an extra field)?
So for the DM example, you could send the gift wrapped DM with 2 1059 events from different random keys and 2 nonces, one to the recipient and another one to yourself (so you can keep chat history). With 2 nonces, the 2 gift wrap
content
s won't match, so no one can tell it is the same message.This way you don't need to keep track of the wrapping key for decrypting chat history.
The down side is the created_ats will be close to each other and your copy won't have a
p
tag with the recipient so you cant fetch just the messages sent to a specific user. =(There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here is another way to solve this problem (not the decryption part, but the querying part).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@staab nice so the sender should encrypt the receiver pubkey using the shared secret
But from NIP-04, is
secp256k1.getSharedSecret(SENDER_privkey, '02' + RECEIVER_pubkey).slice(1, 33)
the same value assecp256k1.getSharedSecret(RECEIVER_privkey, '02' + SENDER_pubkey).slice(1, 33)
? So the receiver can use it to also encrypt his own pubkey and query with{ #p: [encrypted_receiver_pubkey] }
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No idea, encrypted tags would rely on signing with a shared secret. This PR uses ephemeral keys, but it would be easy to convert it to using a shared secret (since one is necessary for decryption anyway). Encrypted tags could then be encrypted symmetrically.