diff --git a/76.md b/76.md index 3a49700c..adf4c865 100644 --- a/76.md +++ b/76.md @@ -6,13 +6,13 @@ 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. +Tags `rp` (read permission) and `prp` (probabilistic read permission) specify which keys are authorized to download an event from the relay. -Events with an `rp` or `prp` require AUTH to be downloaded. +Events tagged with `rp` or `prp` require AUTH for download. ## Read Permission -The `rp` tag takes a pubkey. Multiple `rp` tags represent a logical OR. +The `rp` tag takes a pubkey in lowercase hex as value. ```json ["rp", ""] @@ -20,27 +20,28 @@ The `rp` tag takes a pubkey. Multiple `rp` tags represent a logical OR. ["rp", ""] ``` -Relays MUST check if the authed user is one of the keys in the `rp` before sending the event to the client. +When responding to `REQ`s, if an event contains `rp` tags, relays MUST verify that the authenticated user is either the event's author or one of the keys in the `rp` set before delivering it to the client. ## Probabilistic Read Permissions -Probabilistic permissions use bloom filters of a set of authorized pubkeys. They are represented by a colon-separated value with: -1. the number of bits in the bit array -2. the number of hashing rounds used by the filter -3. the bit array in Base64. +Probabilistic permissions are implemented using Bloom filters that represent a set of authorized pubkeys. These permissions are expressed as a colon-separated value comprising: +1. the number of bits in the bit array, +2. the number of hash rounds applied, and +3. the bit array encoded in Base64. +4. the salt encoded in Base64. ```json -["prp", "::"] +["prp", ":::"] ``` -Bloom filters MUST use `SHA256` functions of the key + iterating index as the pseudocode below demonstrates: +Bloom filters MUST use `SHA256` functions applied to the concatenation of the key, salt, and index, as demonstrated in the pseudocode below: ```js -class BloomFilter(size: Int, rounds: Int, buffer: ByteArray) { +class BloomFilter(size: Int, rounds: Int, buffer: ByteArray, salt: ByteArray) { val bits = BitArray(buffer) fun bitIndex(value: ByteArray, index: Byte) { - return BigInt(sha256(value || index)) % size + return BigInt(sha256(value || salt || index)) % size } fun add(pubkey: HexKey) { @@ -64,26 +65,26 @@ class BloomFilter(size: Int, rounds: Int, buffer: ByteArray) { } fun encode() { - return size + ":" + rounds + ":" + base64Encode(bits.toByteArray()) + return size + ":" + rounds + ":" + base64Encode(bits.toByteArray()) + ":" + base64Encode(salt) } fun decode(str: String): BloomFilter { - val parts = str.split(":") - return BloomFilter(parts[0].toInt(), parts[1].toInt(), base64Decode(parts[2])) + val [sizeStr, roundsStr, bufferB64, saltB64] = str.split(":") + return BloomFilter(sizeStr.toInt(), roundsStr.toInt(), base64Decode(bufferB64), base64Decode(saltB64)) } } ``` -Relays MUST check if the authed user is in the filter before returning the event. +When responding to `REQ`s, if an event contains `prp` tags, relays MUST verify that the authenticated user is either the event's author or matches any of the filters before delivering it to the client. -Multiple `prp` tags represent a logical OR. +If both `rp` and `prp` tags are present, the authenticated user MUST either be in the `rp` set or match any `prp` filter. ### Test cases -The filter below has 100 bits, with 10 rounds of hashes that should be able to match 10,000,000 keys without a single false positive. +The filter below has 100 bits and uses 10 rounds of hashing, which should be capable of handling up to 10,000,000 keys without producing any false positives. ```json -["prp", "100:10:QGKCgBEBAAhIAApO"] +["prp", "100:10:AAAkAQANcYQFCQoB:hZkZYqqdxcE="] ``` It includes keys `ca29c211f1c72d5b6622268ff43d2288ea2b2cb5b9aa196ff9f1704fc914b71b` and `460c25e682fda7832b52d1f22d3d22b3176d972f60dcdc3212ed8c92ef85065c`