Warning
unrecommended
: deprecated in favor of NIP-17
final
unrecommended
optional
暗号化されたダイレクトメッセージを指す固有のkind4
は、次のような属性を持っている。
content
は、ユーザーが書きたい文字列のbase64エンコードを送信者の秘密鍵と受診者の公開鍵を組みあわせて作られる共有暗号で暗号化したものと等しくなければならない (MUST)。base64エンコードされた初期化ベクトルは、"iv"という名前のクエリ文字列パラメータのようにして添付される。ここに例を示す。"content": "<encrypted_text>?iv=<initialization_vector>"
tags
にはリレーがうまく彼らにそのイベントを転送するため、メッセージの受信者を識別するエントリを次のように格納しなけばならない (MUST)。 ["p", "<pubkey, as a hex string>"]
tags
には、文脈に沿った、より整理された会話ができるよう会話の中の前のメッセージや、明示的に返信しているメッセージを示すエントリを次のように含めても構わない (MAY)。["e", "<event_id>"]
メモ: ECDH実装libsecp256k1のデフォルトでは、秘密は共有点 (X座標とY座標の両方) のSHA256ハッシュである。Nostrでは、共有点のX座標のみが秘密として使用されハッシュ化されない。libsecp256k1を使用する場合は、X座標をコピーする関数をsecp256k1_ecdh
中でhashfp
引数として渡す必要が有る。
JavaScriptでそのようなイベントを生成するためのサンプルコードはこちら。
import crypto from 'crypto'
import * as secp from '@noble/secp256k1'
let sharedPoint = secp.getSharedSecret(ourPrivateKey, '02' + theirPublicKey)
let sharedX = sharedPoint.slice(1, 33)
let iv = crypto.randomFillSync(new Uint8Array(16))
var cipher = crypto.createCipheriv(
'aes-256-cbc',
Buffer.from(sharedX),
iv
)
let encryptedMessage = cipher.update(text, 'utf8', 'base64')
encryptedMessage += cipher.final('base64')
let ivBase64 = Buffer.from(iv.buffer).toString('base64')
let event = {
pubkey: ourPubKey,
created_at: Math.floor(Date.now() / 1000),
kind: 4,
tags: [['p', theirPublicKey]],
content: encryptedMessage + '?iv=' + ivBase64
}
この標準はピア間の暗号化通信の最先端と考えられている物とは程遠く、加えてイベントのメタデータも流出させる。そのため本当に秘密を保ちたい用途には絶対に使用してはならない。使用する際は、AUTH
を使用してあなたのkind:4
イベントを取得可能な人を制限できるリレーでのみ使用するべきである。
クライアントは.content
に含まれる公開鍵とノートの参照を検索して置換するべきではない。もし通常のテキストノートのように処理 (文中の@npub...
を["p", "..."]
タグがある#[0]
で置き換える) した場合、タグは流出し、メンションされたユーザーは受信トレイにメッセージを受け取る。