nips/76.md
2024-09-13 13:09:07 -04:00

2.3 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

Probabilistic permissions use bloom filters that include a set of pubkeys. They are represented by a colon-separated value with:

  1. the size of the bit array
  2. the number of hashing rounds used by the filter
  3. the bit array in Base64.
["prp", "<BitArray 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