2.2 KiB
NIP-76
Relay Read Permissions
draft
optional
Tag names rp
(read permission) and prp
(probabilistic read permission) define which keys are authorized to download an event from the relay.
Events that include an rp
or prp
require AUTH to be downloaded.
Read Permission
The rp
tag accepts a list of pubkeys
["rp", "<pubkey1>", "<pubkey2>", "<pubkey3>"]
Relays MUST check if the authed user is one of the keys in the rp
before sending the event to the client.
Probabilistic Read Permissions
Bloom filters are bit arrays that encode keys n
times. They are represented by a base64 encoded tag value with the n
as the third element.
["prp", "<bit size>:<rounds>:<base64>"]
Bloom filters MUST use SHA-256
functions of the key + iterating index as the psedocode below:
class BloomFilter(size: Int, n: Int, buffer: ByteArray) {
val bits = BitArray(buffer)
fun bitIndex(value: ByteArray, index: Byte) {
return BigInt(sha256(value || index)) % size
}
fun add(pubkey: HexKey) {
val value = pubkey.hexToByteArray()
for (index in 0..n) {
bits[bitIndex(value, index)] = true
}
}
fun mightContains(pubkey: HexKey): Boolean {
val value = pubkey.hexToByteArray()
for (index in 0..n) {
if (!bits[bitIndex(value, index)]) {
return false
}
}
return true
}
fun encode() = size + ":" + rounds + ":" + base64Enc(bits.toByteArray()) // base64 might include extra 0 bits to fill the last byte
fun decode(str: String): BloomFilter {
val parts = str.split(":")
return BloomFilter(parts[0].toInt(), parts[1].toInt(), base64Decode(bits.toByteArray()))
}
}
Relays MUST check if the authed user is in the filter before returning the event.
Test cases
The filter below has 100 bits, with 10 rounds or hashes that should be able to match 10,000,000 keys without a single false positive.
["prp", "100:10:QGKCgBEBAAhIAApO"]
It includes keys ca29c211f1c72d5b6622268ff43d2288ea2b2cb5b9aa196ff9f1704fc914b71b
and 460c25e682fda7832b52d1f22d3d22b3176d972f60dcdc3212ed8c92ef85065c