From d4283ff4c5c46d5d179d1542d2055caae7c2ac11 Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Mon, 29 Jan 2024 22:56:56 -0500 Subject: [PATCH 01/81] Create README.md --- README.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..1fc0a66 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# Waku RFCs + +## Contributing From bbf470edda87a60f46ebf8ce608db191beaf06e2 Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Mon, 29 Jan 2024 23:18:10 -0500 Subject: [PATCH 02/81] Create toy-chat.md --- informational/22/toy-chat.md | 53 ++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 informational/22/toy-chat.md diff --git a/informational/22/toy-chat.md b/informational/22/toy-chat.md new file mode 100644 index 0000000..168809c --- /dev/null +++ b/informational/22/toy-chat.md @@ -0,0 +1,53 @@ +--- +slug: 22 +title: 22/TOY-CHAT +name: Waku v2 Toy Chat +status: draft +tags: waku/application +editor: Franck Royer +contributors: + - Hanno Cornelius +--- + +**Content Topic**: `/toy-chat/2/huilong/proto`. + +This specification explains a toy chat example using Waku v2. +This protocol is mainly used to: + +1. Dogfood Waku v2, +2. Show an example of how to use Waku v2. + +Currently, all main Waku v2 implementations support the toy chat protocol: +[nim-waku](https://github.com/status-im/nim-waku/blob/master/examples/v2/chat2.nim), +js-waku ([NodeJS](https://github.com/status-im/js-waku/tree/main/examples/cli-chat) and [web](https://github.com/status-im/js-waku/tree/main/examples/web-chat)) +and [go-waku](https://github.com/status-im/go-waku/tree/master/examples/chat2). + +Note that this is completely separate from the protocol the Status app is using for its chat functionality. + +# Design + +The chat protocol enables sending and receiving messages in a chat room. +There is currently only one chat room, which is tied to the content topic. +The messages SHOULD NOT be encrypted. + +The `contentTopic` MUST be set to `/toy-chat/2/huilong/proto`. + +# Payloads + +```protobuf +syntax = "proto3"; + +message Chat2Message { + uint64 timestamp = 1; + string nick = 2; + bytes payload = 3; +} +``` + +- `timestamp`: The time at which the message was sent, in Unix Epoch seconds, +- `nick`: The nickname of the user sending the message, +- `payload`: The text of the messages, UTF-8 encoded. + +# Copyright + +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). From b1e2a79ce6fe4dcae62a3cd3db631751382b7018 Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Tue, 30 Jan 2024 01:07:32 -0500 Subject: [PATCH 03/81] Create toy-eth-pm.md --- informational/20/toy-eth-pm.md | 219 +++++++++++++++++++++++++++++++++ 1 file changed, 219 insertions(+) create mode 100644 informational/20/toy-eth-pm.md diff --git a/informational/20/toy-eth-pm.md b/informational/20/toy-eth-pm.md new file mode 100644 index 0000000..80a59b3 --- /dev/null +++ b/informational/20/toy-eth-pm.md @@ -0,0 +1,219 @@ +--- +slug: 20 +title: 20/TOY-ETH-PM +name: Toy Ethereum Private Message +status: draft +tags: waku/application +editor: Franck Royer +contributors: +--- + +**Content Topics**: + +- Public Key Broadcast: `/eth-pm/1/public-key/proto`, +- Private Message: `/eth-pm/1/private-message/proto`. + +This specification explains the Toy Ethereum Private Message protocol +which enables a peer to send an encrypted message to another peer +using the Waku v2 network, and the peer's Ethereum address. + +The main purpose of this specification is to demonstrate how Waku v2 can be used for encrypted messaging purposes, +using Ethereum accounts for identity. +This protocol caters for Web3 wallets restrictions, allowing it to be implemented only using standard Web3 API. +In the current state, the protocol has privacy and features [limitations](#limitations), has not been audited +and hence is not fit for production usage. +We hope this can be an inspiration for developers wishing to build on top of Waku v2. + +## Goal + +Alice wants to send an encrypted message to Bob, where only Bob can decrypt the message. +Alice only knows Bob's Ethereum Address. + +## Variables + +Here are the variables used in the protocol and their definition: + +- `B` is Bob's Ethereum address (or account), +- `b` is the private key of `B`, and is only known by Bob. +- `B'` is Bob's Encryption Public Key, for which `b'` is the private key. +- `M` is the private message that Alice sends to Bob. + +## Design Requirements + +The proposed protocol MUST adhere to the following design requirements: + +1. Alice knows Bob's Ethereum address, +2. Bob is willing to participate to Eth-PM, and publishes `B'`, +3. Bob's ownership of `B'` MUST be verifiable, +4. Alice wants to send message `M` to Bob, +5. Bob SHOULD be able to get `M` using [10/WAKU2 spec](../../standards/core/10/WAKU2.md), +6. Participants only have access to their Ethereum Wallet via the Web3 API, +7. Carole MUST NOT be able to read `M`'s content even if she is storing it or relaying it, +8. [Waku Message Version 1](../../standards/application/26) Asymmetric Encryption is used for encryption purposes. + +## Limitations + +Alice's details are not included in the message's structure, +meaning that there is no programmatic way for Bob to reply to Alice +or verify her identity. + +Private messages are sent on the same content topic for all users. +As the recipient data is encrypted, all participants must decrypt all messages which can lead to scalability issues. + +This protocol does not guarantee Perfect Forward Secrecy nor Future Secrecy: +If Bob's private key is compromised, past and future messages could be decrypted. +A solution combining regular [X3DH](https://www.signal.org/docs/specifications/x3dh/) +bundle broadcast with [Double Ratchet](https://signal.org/docs/specifications/doubleratchet/) encryption would remove these limitations; +See the [Status secure transport spec](https://specs.status.im/spec/5) for an example of a protocol that achieves this in a peer-to-peer setting. + +Bob MUST decide to participate in the protocol before Alice can send him a message. +This is discussed in more in details in [Consideration for a non-interactive/uncoordinated protocol](#consideration-for-a-non-interactiveuncoordinated-protocol) + +## The protocol + +### Generate Encryption KeyPair + +First, Bob needs to generate a keypair for Encryption purposes. + +Bob SHOULD get 32 bytes from a secure random source as Encryption Private Key, `b'`. +Then Bob can compute the corresponding SECP-256k1 Public Key, `B'`. + +### Broadcast Encryption Public Key + +For Alice to encrypt messages for Bob, +Bob SHOULD broadcast his Encryption Public Key `B'`. +To prove that the Encryption Public Key `B'` is indeed owned by the owner of Bob's Ethereum Account `B`, +Bob MUST sign `B'` using `B`. + +### Sign Encryption Public Key + +To prove ownership of the Encryption Public Key, +Bob must sign it using [EIP-712](https://eips.ethereum.org/EIPS/eip-712) v3, +meaning calling `eth_signTypedData_v3` on his Wallet's API. + +Note: While v4 also exists, +it is not available on all wallets and the features brought by v4 is not needed for the current use case. + +The `TypedData` to be passed to `eth_signTypedData_v3` MUST be as follows, where: + +- `encryptionPublicKey` is Bob's Encryption Public Key, `B'`, in hex format, **without** `0x` prefix. +- `bobAddress` is Bob's Ethereum address, corresponding to `B`, in hex format, **with** `0x` prefix. + +```js +const typedData = { + domain: { + chainId: 1, + name: 'Ethereum Private Message over Waku', + version: '1', + }, + message: { + encryptionPublicKey: encryptionPublicKey, + ownerAddress: bobAddress, + }, + primaryType: 'PublishEncryptionPublicKey', + types: { + EIP712Domain: [ + { name: 'name', type: 'string' }, + { name: 'version', type: 'string' }, + { name: 'chainId', type: 'uint256' }, + ], + PublishEncryptionPublicKey: [ + { name: 'encryptionPublicKey', type: 'string' }, + { name: 'ownerAddress', type: 'string' }, + ], + }, + } +``` + +### Public Key Message + +The resulting signature is then included in a `PublicKeyMessage`, where + +- `encryption_public_key` is Bob's Encryption Public Key `B'`, not compressed, +- `eth_address` is Bob's Ethereum Address `B`, +- `signature` is the EIP-712 as described above. + +```protobuf +syntax = "proto3"; + +message PublicKeyMessage { + bytes encryption_public_key = 1; + bytes eth_address = 2; + bytes signature = 3; +} +``` + +This MUST be wrapped in a Waku Message version 0, with the Public Key Broadcast content topic. +Finally, Bob SHOULD publish the message on Waku v2. + +## Consideration for a non-interactive/uncoordinated protocol + +Alice has to get Bob's public Key to send a message to Bob. +Because an Ethereum Address is part of the hash of the public key's account, +it is not enough in itself to deduce Bob's Public Key. + +This is why the protocol dictates that Bob MUST send his Public Key first, +and Alice MUST receive it before she can send him a message. + +Moreover, nim-waku, the reference implementation of [13/WAKU2-STORE](../../standards/core/13/store.md)), +stores messages for a maximum period of 30 days. +This means that Bob would need to broadcast his public key at least every 30 days to be reachable. + +Below we are reviewing possible solutions to mitigate this "sign up" step. + +### Retrieve the public key from the blockchain + +If Bob has signed at least one transaction with his account then his Public Key can be extracted from the transaction's ECDSA signature. +The challenge with this method is that standard Web3 Wallet API does not allow Alice to specifically retrieve all/any transaction sent by Bob. + +Alice would instead need to use the `eth.getBlock` API to retrieve Ethereum blocks one by one. +For each block, she would need to check the `from` value of each transaction until she finds a transaction sent by Bob. + +This process is resource intensive and can be slow when using services such as Infura due to rate limits in place, +which makes it inappropriate for a browser or mobile phone environment. + +An alternative would be to either run a backend that can connect directly to an Ethereum node, +use a centralized blockchain explorer +or use a decentralized indexing service such as [The Graph](https://thegraph.com/). + +Note that these would resolve a UX issue only if a sender wants to proceed with _air drops_. + +Indeed, if Bob does not publish his Public Key in the first place +then it can be an indication that he simply does not participate in this protocol and hence will not receive messages. + +However, these solutions would be helpful if the sender wants to proceed with an _air drop_ of messages: +Send messages over Waku for users to retrieve later, once they decide to participate in this protocol. +Bob may not want to participate first but may decide to participate at a later stage +and would like to access previous messages. +This could make sense in an NFT offer scenario: +Users send offers to any NFT owner, +NFT owner may decide at some point to participate in the protocol and retrieve previous offers. + +### Publishing the public in long term storage + +Another improvement would be for Bob not having to re-publish his public key every 30 days or less. +Similarly to above, if Bob stops publishing his public key then it may be an indication that he does not participate in the protocol anymore. + +In any case, the protocol could be modified to store the Public Key in a more permanent storage, such as a dedicated smart contract on the blockchain. + +## Send Private Message + +Alice MAY monitor the Waku v2 to collect Ethereum Address and Encryption Public Key tuples. +Alice SHOULD verify that the `signature`s of `PublicKeyMessage`s she receives are valid as per EIP-712. +She SHOULD drop any message without a signature or with an invalid signature. + +Using Bob's Encryption Public Key, retrieved via [10/WAKU2](../../standards/core/10/WAKU2.md), Alice MAY now send an encrypted message to Bob. + +If she wishes to do so, Alice MUST encrypt her message `M` using Bob's Encryption Public Key `B'`, +as per [26/WAKU-PAYLOAD Asymmetric Encryption specs](../../standards/application/26/payload.md/#asymmetric). + +Alice SHOULD now publish this message on the Private Message content topic. + +# Copyright + +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). + +## References +- [10/WAKU2 spec](../../standards/core/10/WAKU2.md) +- [Waku Message Version 1](../../standards/application/26) +- From eed6ef582ed9b20e1ca9f5c02de4b89ea153a208 Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Tue, 30 Jan 2024 01:26:27 -0500 Subject: [PATCH 04/81] Delete informational/20 directory --- informational/20/toy-eth-pm.md | 219 --------------------------------- 1 file changed, 219 deletions(-) delete mode 100644 informational/20/toy-eth-pm.md diff --git a/informational/20/toy-eth-pm.md b/informational/20/toy-eth-pm.md deleted file mode 100644 index 80a59b3..0000000 --- a/informational/20/toy-eth-pm.md +++ /dev/null @@ -1,219 +0,0 @@ ---- -slug: 20 -title: 20/TOY-ETH-PM -name: Toy Ethereum Private Message -status: draft -tags: waku/application -editor: Franck Royer -contributors: ---- - -**Content Topics**: - -- Public Key Broadcast: `/eth-pm/1/public-key/proto`, -- Private Message: `/eth-pm/1/private-message/proto`. - -This specification explains the Toy Ethereum Private Message protocol -which enables a peer to send an encrypted message to another peer -using the Waku v2 network, and the peer's Ethereum address. - -The main purpose of this specification is to demonstrate how Waku v2 can be used for encrypted messaging purposes, -using Ethereum accounts for identity. -This protocol caters for Web3 wallets restrictions, allowing it to be implemented only using standard Web3 API. -In the current state, the protocol has privacy and features [limitations](#limitations), has not been audited -and hence is not fit for production usage. -We hope this can be an inspiration for developers wishing to build on top of Waku v2. - -## Goal - -Alice wants to send an encrypted message to Bob, where only Bob can decrypt the message. -Alice only knows Bob's Ethereum Address. - -## Variables - -Here are the variables used in the protocol and their definition: - -- `B` is Bob's Ethereum address (or account), -- `b` is the private key of `B`, and is only known by Bob. -- `B'` is Bob's Encryption Public Key, for which `b'` is the private key. -- `M` is the private message that Alice sends to Bob. - -## Design Requirements - -The proposed protocol MUST adhere to the following design requirements: - -1. Alice knows Bob's Ethereum address, -2. Bob is willing to participate to Eth-PM, and publishes `B'`, -3. Bob's ownership of `B'` MUST be verifiable, -4. Alice wants to send message `M` to Bob, -5. Bob SHOULD be able to get `M` using [10/WAKU2 spec](../../standards/core/10/WAKU2.md), -6. Participants only have access to their Ethereum Wallet via the Web3 API, -7. Carole MUST NOT be able to read `M`'s content even if she is storing it or relaying it, -8. [Waku Message Version 1](../../standards/application/26) Asymmetric Encryption is used for encryption purposes. - -## Limitations - -Alice's details are not included in the message's structure, -meaning that there is no programmatic way for Bob to reply to Alice -or verify her identity. - -Private messages are sent on the same content topic for all users. -As the recipient data is encrypted, all participants must decrypt all messages which can lead to scalability issues. - -This protocol does not guarantee Perfect Forward Secrecy nor Future Secrecy: -If Bob's private key is compromised, past and future messages could be decrypted. -A solution combining regular [X3DH](https://www.signal.org/docs/specifications/x3dh/) -bundle broadcast with [Double Ratchet](https://signal.org/docs/specifications/doubleratchet/) encryption would remove these limitations; -See the [Status secure transport spec](https://specs.status.im/spec/5) for an example of a protocol that achieves this in a peer-to-peer setting. - -Bob MUST decide to participate in the protocol before Alice can send him a message. -This is discussed in more in details in [Consideration for a non-interactive/uncoordinated protocol](#consideration-for-a-non-interactiveuncoordinated-protocol) - -## The protocol - -### Generate Encryption KeyPair - -First, Bob needs to generate a keypair for Encryption purposes. - -Bob SHOULD get 32 bytes from a secure random source as Encryption Private Key, `b'`. -Then Bob can compute the corresponding SECP-256k1 Public Key, `B'`. - -### Broadcast Encryption Public Key - -For Alice to encrypt messages for Bob, -Bob SHOULD broadcast his Encryption Public Key `B'`. -To prove that the Encryption Public Key `B'` is indeed owned by the owner of Bob's Ethereum Account `B`, -Bob MUST sign `B'` using `B`. - -### Sign Encryption Public Key - -To prove ownership of the Encryption Public Key, -Bob must sign it using [EIP-712](https://eips.ethereum.org/EIPS/eip-712) v3, -meaning calling `eth_signTypedData_v3` on his Wallet's API. - -Note: While v4 also exists, -it is not available on all wallets and the features brought by v4 is not needed for the current use case. - -The `TypedData` to be passed to `eth_signTypedData_v3` MUST be as follows, where: - -- `encryptionPublicKey` is Bob's Encryption Public Key, `B'`, in hex format, **without** `0x` prefix. -- `bobAddress` is Bob's Ethereum address, corresponding to `B`, in hex format, **with** `0x` prefix. - -```js -const typedData = { - domain: { - chainId: 1, - name: 'Ethereum Private Message over Waku', - version: '1', - }, - message: { - encryptionPublicKey: encryptionPublicKey, - ownerAddress: bobAddress, - }, - primaryType: 'PublishEncryptionPublicKey', - types: { - EIP712Domain: [ - { name: 'name', type: 'string' }, - { name: 'version', type: 'string' }, - { name: 'chainId', type: 'uint256' }, - ], - PublishEncryptionPublicKey: [ - { name: 'encryptionPublicKey', type: 'string' }, - { name: 'ownerAddress', type: 'string' }, - ], - }, - } -``` - -### Public Key Message - -The resulting signature is then included in a `PublicKeyMessage`, where - -- `encryption_public_key` is Bob's Encryption Public Key `B'`, not compressed, -- `eth_address` is Bob's Ethereum Address `B`, -- `signature` is the EIP-712 as described above. - -```protobuf -syntax = "proto3"; - -message PublicKeyMessage { - bytes encryption_public_key = 1; - bytes eth_address = 2; - bytes signature = 3; -} -``` - -This MUST be wrapped in a Waku Message version 0, with the Public Key Broadcast content topic. -Finally, Bob SHOULD publish the message on Waku v2. - -## Consideration for a non-interactive/uncoordinated protocol - -Alice has to get Bob's public Key to send a message to Bob. -Because an Ethereum Address is part of the hash of the public key's account, -it is not enough in itself to deduce Bob's Public Key. - -This is why the protocol dictates that Bob MUST send his Public Key first, -and Alice MUST receive it before she can send him a message. - -Moreover, nim-waku, the reference implementation of [13/WAKU2-STORE](../../standards/core/13/store.md)), -stores messages for a maximum period of 30 days. -This means that Bob would need to broadcast his public key at least every 30 days to be reachable. - -Below we are reviewing possible solutions to mitigate this "sign up" step. - -### Retrieve the public key from the blockchain - -If Bob has signed at least one transaction with his account then his Public Key can be extracted from the transaction's ECDSA signature. -The challenge with this method is that standard Web3 Wallet API does not allow Alice to specifically retrieve all/any transaction sent by Bob. - -Alice would instead need to use the `eth.getBlock` API to retrieve Ethereum blocks one by one. -For each block, she would need to check the `from` value of each transaction until she finds a transaction sent by Bob. - -This process is resource intensive and can be slow when using services such as Infura due to rate limits in place, -which makes it inappropriate for a browser or mobile phone environment. - -An alternative would be to either run a backend that can connect directly to an Ethereum node, -use a centralized blockchain explorer -or use a decentralized indexing service such as [The Graph](https://thegraph.com/). - -Note that these would resolve a UX issue only if a sender wants to proceed with _air drops_. - -Indeed, if Bob does not publish his Public Key in the first place -then it can be an indication that he simply does not participate in this protocol and hence will not receive messages. - -However, these solutions would be helpful if the sender wants to proceed with an _air drop_ of messages: -Send messages over Waku for users to retrieve later, once they decide to participate in this protocol. -Bob may not want to participate first but may decide to participate at a later stage -and would like to access previous messages. -This could make sense in an NFT offer scenario: -Users send offers to any NFT owner, -NFT owner may decide at some point to participate in the protocol and retrieve previous offers. - -### Publishing the public in long term storage - -Another improvement would be for Bob not having to re-publish his public key every 30 days or less. -Similarly to above, if Bob stops publishing his public key then it may be an indication that he does not participate in the protocol anymore. - -In any case, the protocol could be modified to store the Public Key in a more permanent storage, such as a dedicated smart contract on the blockchain. - -## Send Private Message - -Alice MAY monitor the Waku v2 to collect Ethereum Address and Encryption Public Key tuples. -Alice SHOULD verify that the `signature`s of `PublicKeyMessage`s she receives are valid as per EIP-712. -She SHOULD drop any message without a signature or with an invalid signature. - -Using Bob's Encryption Public Key, retrieved via [10/WAKU2](../../standards/core/10/WAKU2.md), Alice MAY now send an encrypted message to Bob. - -If she wishes to do so, Alice MUST encrypt her message `M` using Bob's Encryption Public Key `B'`, -as per [26/WAKU-PAYLOAD Asymmetric Encryption specs](../../standards/application/26/payload.md/#asymmetric). - -Alice SHOULD now publish this message on the Private Message content topic. - -# Copyright - -Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). - -## References -- [10/WAKU2 spec](../../standards/core/10/WAKU2.md) -- [Waku Message Version 1](../../standards/application/26) -- From 76be4297da78d936ef03c9bb0bb684186c3d3cfb Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Tue, 30 Jan 2024 01:26:35 -0500 Subject: [PATCH 05/81] Delete informational/22 directory --- informational/22/toy-chat.md | 53 ------------------------------------ 1 file changed, 53 deletions(-) delete mode 100644 informational/22/toy-chat.md diff --git a/informational/22/toy-chat.md b/informational/22/toy-chat.md deleted file mode 100644 index 168809c..0000000 --- a/informational/22/toy-chat.md +++ /dev/null @@ -1,53 +0,0 @@ ---- -slug: 22 -title: 22/TOY-CHAT -name: Waku v2 Toy Chat -status: draft -tags: waku/application -editor: Franck Royer -contributors: - - Hanno Cornelius ---- - -**Content Topic**: `/toy-chat/2/huilong/proto`. - -This specification explains a toy chat example using Waku v2. -This protocol is mainly used to: - -1. Dogfood Waku v2, -2. Show an example of how to use Waku v2. - -Currently, all main Waku v2 implementations support the toy chat protocol: -[nim-waku](https://github.com/status-im/nim-waku/blob/master/examples/v2/chat2.nim), -js-waku ([NodeJS](https://github.com/status-im/js-waku/tree/main/examples/cli-chat) and [web](https://github.com/status-im/js-waku/tree/main/examples/web-chat)) -and [go-waku](https://github.com/status-im/go-waku/tree/master/examples/chat2). - -Note that this is completely separate from the protocol the Status app is using for its chat functionality. - -# Design - -The chat protocol enables sending and receiving messages in a chat room. -There is currently only one chat room, which is tied to the content topic. -The messages SHOULD NOT be encrypted. - -The `contentTopic` MUST be set to `/toy-chat/2/huilong/proto`. - -# Payloads - -```protobuf -syntax = "proto3"; - -message Chat2Message { - uint64 timestamp = 1; - string nick = 2; - bytes payload = 3; -} -``` - -- `timestamp`: The time at which the message was sent, in Unix Epoch seconds, -- `nick`: The nickname of the user sending the message, -- `payload`: The text of the messages, UTF-8 encoded. - -# Copyright - -Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). From c13a64214c4fb8c3208d8d0b99264856034084da Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Tue, 30 Jan 2024 01:29:10 -0500 Subject: [PATCH 06/81] Create enr.md --- standards/core/enr.md | 165 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 165 insertions(+) create mode 100644 standards/core/enr.md diff --git a/standards/core/enr.md b/standards/core/enr.md new file mode 100644 index 0000000..129e4ca --- /dev/null +++ b/standards/core/enr.md @@ -0,0 +1,165 @@ +--- +slug: 31 +title: 31/WAKU2-ENR +name: Waku v2 usage of ENR +status: +tags: waku/core +editor: Franck Royer +contributors: +--- + +# Abstract + +This RFC describes the usage of the ENR (Ethereum Node Records) format for [10/WAKU2](/specs/10) purposes. +The ENR format is defined in [EIP-778](https://eips.ethereum.org/EIPS/eip-778) [[3]](#references). + +This RFC is an extension of EIP-778, ENR used in Waku v2 MUST adhere to both EIP-778 and 31/WAKU2-ENR. + +# Motivation + +EIP-1459 with the usage of ENR has been implemented [[1]](#references) [[2]](#references) as a discovery protocol for Waku v2. + +EIP-778 specifies a number of pre-defined keys. +However, the usage of these keys alone does not allow for certain transport capabilities to be encoded, +such as Websocket. +Currently, Waku v2 nodes running in a Browser only support websocket transport protocol. +Hence, new ENR keys need to be defined to allow for the encoding of transport protocol other than raw TCP. + +## Usage of Multiaddr Format Rationale + +One solution would be to define new keys such as `ws` to encode the websocket port of a node. +However, we expect new transport protocols to be added overtime such as quic. +Hence, this would only provide a short term solution until another RFC would need to be added. + +Moreover, secure websocket involves SSL certificates. +SSL certificates are only valid for a given domain and ip, so an ENR containing the following information: +- secure websocket port +- ipv4 fqdn +- ipv4 address +- ipv6 address + +Would carry some ambiguity: Is the certificate securing the websocket port valid for the ipv4 fqdn? +the ipv4 address? +the ipv6 address? + +The [10/WAKU2](/specs/10) protocol family is built on the [libp2p](https://github.com/libp2p/specs) protocol stack. +Hence, it uses [multiaddr](https://github.com/multiformats/multiaddr) to format network addresses. + +Directly storing one or several multiaddresses in the ENR would fix the issues listed above: +- multiaddr is self-describing and support addresses for any network protocol: + No new RFC would be needed to support encoding other transport protocols in an ENR. +- multiaddr contains both the host and port information, allowing the ambiguity previously described to be resolved. + +# `multiaddrs` ENR key + +We define a `multiaddrs` key. + +- The value MUST be a list of binary encoded multiaddr prefixed by their size. +- The size of the multiaddr MUST be encoded in a Big Endian unsigned 16-bit integer. +- The size of the multiaddr MUST be encoded in 2 bytes. +- The `secp256k1` value MUST be present on the record; + `secp256k1` is defined in [EIP-778](https://eips.ethereum.org/EIPS/eip-778) and contains the compressed secp256k1 public key. +- The node's peer id SHOULD be deduced from the `secp256k1` value. +- The multiaddresses SHOULD NOT contain a peer id except for circuit relay addresses +- For raw TCP & UDP connections details, [EIP-778](https://eips.ethereum.org/EIPS/eip-778) pre-defined keys SHOULD be used; + The keys `tcp`, `udp`, `ip` (and `tcp6`, `udp6`, `ip6` for IPv6) are enough to convey all necessary information; +- To save space, `multiaddrs` key SHOULD only be used for connection details that cannot be represented using the [EIP-778](https://eips.ethereum.org/EIPS/eip-778) pre-defined keys. +- The 300 bytes size limit as defined by [EIP-778](https://eips.ethereum.org/EIPS/eip-778) still applies; + In practice, it is possible to encode 3 multiaddresses in ENR, more or less could be encoded depending on the size of each multiaddress. + +## Usage + +### Many connection types + +Alice is a node operator, she runs a node that supports inbound connection for the following protocols: +- TCP 10101 on `1.2.3.4` +- UDP 20202 on `1.2.3.4` +- TCP 30303 on `1234:5600:101:1::142` +- UDP 40404 on `1234:5600:101:1::142` +- Secure Websocket on `wss://example.com:443/` +- QUIC on `quic://quic.example.com:443/` +- A circuit relay address `/ip4/1.2.3.4/tcp/55555/p2p/QmRelay/p2p-circuit/p2p/QmAlice` + +Alice SHOULD structure the ENR for her node as follows: + +| key | value | +|--- |--- | +| `tcp` | `10101` | +| `udp` | `20202` | +| `tcp6` | `30303` | +| `udp6` | `40404` | +| `ip` | `1.2.3.4` | +| `ip6` | `1234:5600:101:1::142` | +| `secp256k1` | Alice's compressed secp256k1 public key, 33 bytes | +| `multiaddrs` | len1 | /dns4/example.com/tcp/443/wss | len2 | /dns4/quic.examle.com/tcp/443/quic | len3 | /ip4/1.2.3.4/tcp/55555/p2p/QmRelay | + +Where: +- `|` is the concatenation operator, +- `len1` is the length of `/dns4/example.com/tcp/443/wss` byte representation, +- `len2` is the length of `/dns4/quic.examle.com/tcp/443/quic` byte representation. +- `len3` is the length of `/ip4/1.2.3.4/tcp/55555/p2p/QmRelay` byte representation. Notice that the `/p2p-circuit` component is not stored, but, since circuit relay addresses are the only one containing a `p2p` component, it's safe to assume that any address containing this component is a circuit relay address. Decoding this type of multiaddresses would require appending the `/p2p-circuit` component. + +### Raw TCP only + +Bob is a node operator, he runs a node that supports inbound connection for the following protocols: +- TCP 10101 on `1.2.3.4` + +Bob SHOULD structure the ENR for her node as follows: + +| key | value | +|--- |--- | +| `tcp` | `10101` | +| `ip` | `1.2.3.4` | +| `secp256k1` | Bob's compressed secp256k1 public key, 33 bytes | + +Indeed, as Bob's node's connection details can be represented with EIP-778's pre-defined keys only +then it is not needed to use the `multiaddrs` key. + +## Limitations + +Supported key type is `secp256k1` only. + +In the future, an extension of this RFC could be made to support other elliptic curve cryptography such as `ed25519`. + +# `waku2` ENR key + +We define a `waku2` field key: + +- The value MUST be an 8-bit flag field, +where bits set to `1` indicate `true` and bits set to `0` indicate `false` for the relevant flags. +- The flag values already defined are set out below, +with `bit 7` the most significant bit and `bit 0` the least significant bit. + +| bit 7 | bit 6 | bit 5 | bit 4 | bit 3 | bit 2 | bit 1 | bit 0 | +| --- | --- | --- | --- | --- | --- | --- | --- | +| `undef` | `undef` | `undef` | `undef` | `lightpush` | `filter` | `store` | `relay` | + +- In the scheme above, the flags `lightpush`, `filter`, `store` and `relay` correlates with support for protocols with the same name. +If a protocol is not supported, the corresponding field MUST be set to `false`. +Indicating positive support for any specific protocol is OPTIONAL, +though it MAY be required by the relevant application or discovery process. +- Flags marked as `undef` is not yet defined. +These SHOULD be set to `false` by default. + +## Usage + +- A Waku v2 node MAY choose to populate the `waku2` field for enhanced discovery capabilities, +such as indicating supported protocols. +Such a node MAY indicate support for any specific protocol by setting the corresponding flag to `true`. +- Waku v2 nodes that want to participate in [Node Discovery Protocol v5](https://github.com/ethereum/devp2p/blob/master/discv5/discv5.md) [[4]](#references), however, +MUST implement the `waku2` key with at least one flag set to `true`. +- Waku v2 nodes that discovered other participants using Discovery v5, +MUST filter out participant records that do not implement this field or do not have at least one flag set to `true`. +- In addition, such nodes MAY choose to filter participants on specific flags (such as supported protocols), +or further interpret the `waku2` field as required by the application. + +# Copyright + +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). + +# References + +- [1] https://github.com/status-im/nim-waku/pull/690 +- [2] https://github.com/vacp2p/rfc/issues/462#issuecomment-943869940 +- [3] https://eips.ethereum.org/EIPS/eip-778 +- [4] https://github.com/ethereum/devp2p/blob/master/discv5/discv5.md From efa2ba5d79e6035bdc4651f087a7adcb3882a8ce Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Tue, 30 Jan 2024 01:31:25 -0500 Subject: [PATCH 07/81] Create peer-exchange.md --- standards/core/peer-exchange.md | 170 ++++++++++++++++++++++++++++++++ 1 file changed, 170 insertions(+) create mode 100644 standards/core/peer-exchange.md diff --git a/standards/core/peer-exchange.md b/standards/core/peer-exchange.md new file mode 100644 index 0000000..189a872 --- /dev/null +++ b/standards/core/peer-exchange.md @@ -0,0 +1,170 @@ +--- +slug: 34 +title: 34/WAKU2-PEER-EXCHANGE +name: Waku v2 Peer Exchange +status: +category: Standards Track +tags: waku/core-protocol +editor: Daniel Kaiser +contributors: +--- + +## Abstract + +This document specifies a simple request-response peer exchange protocol. +Responders send information about a requested number of peers. +The main purpose of this protocol is providing resource restricted devices with peers. + +**Protocol identifier**: /vac/waku/peer-exchange/2.0.0-alpha1 + +## Background and Motivation + +It may not be feasible on resource restricted devices to take part in distributed random sampling ambient peer discovery protocols such as [33/WAKU2-DISCV5](/spec/33/). +The Waku peer discovery protocol specified in this document allows resource restricted devices to request a list of peers from a service node. +Network parameters necessary to connect to this service node COULD be learned from a static bootstrapping method or using [EIP-1459: Node Discovery via DNS](https://eips.ethereum.org/EIPS/eip-1459). +The advantage of using Waku peer exchange to discover new peers over using a static peer list or DNS discovery is a more even load distribution. +If a lot of (resource restricted) nodes would use the same service nodes as relay or store nodes, the load on these would be very high. +Heavily used static nodes also add a centralized element. Downtime of such a node might significantly impact the network. + +However, the resource efficiency of this protocol comes at an anonymity cost, which is explained in the [Security/Privacy Considerations](#securityprivacy-considerations) section. +This protocol SHOULD only be used if [33/WAKU2-DISCV5](/spec/33/) is infeasible. + +## Theory and Protocol Semantics + +The peer exchange protocol specified in this document is a simple request-response protocol. +As Figure 1 illustrates, the requesting node sends a request to a peer, which acts as the responder. +The responder replies with a list of ENRs as specified in [31/WAKU2-ENR](/spec/31/). +The [multiaddresses](https://docs.libp2p.io/concepts/addressing/) used to connect to the respective peers can be extracted from the ENRs. + +![Figure 1: The responder provides a list of ENRs to the requester. These ENRs contain the information necessary for connecting to the respective peers.](/rfcs/34/protocol.svg) + +In order to protect its anonymity, the responder MUST NOT provide peers from its actively used peer list as this opens pathways to *Neighbourhood Surveillance* attacks, as described in the +[Security/Privacy Considerations Section](#securityprivacy-considerations). +The responder SHOULD provide a set of peers that has been retrieved using ambient peer discovery methods supporting random sampling, e.g. [33/WAKU2-DISCV5](/spec/33/). +This both protects the responder's anonymity as well as helps distributing load. + +To allow for fast responses, responders SHOULD retrieve peers unsolicited (before receiving a query) +and maintain a queue of peers for the purpose of providing them in peer exchange responses. +To get the best anonymity properties with respect to response peer sets, responders SHOULD use each of these peers only once. + +To save bandwidth, and as a trade off to anonymity, +responders MAY maintain a larger cache of exchange peers and randomly sample response sets from this local cache. +The size of the cache SHOULD be large enough to allow randomly sampling peer sets that (on average) do not overlap too much. +The responder SHOULD periodically replace the oldest peers in the cache. +This document provides recommended choices for the cache size in the [Implementation Suggestions Section](#implementation-suggestions). + +Requesters, in the context of the specified peer exchange protocol, SHOULD be resource restricted devices. +While any node could technically act as a requester, using the peer exchange protocol comes with two drawbacks: + +* reducing [anonymity](#securityprivacy-considerations) +* causing load on responder nodes + +## Wire Format Specification + +```protobuf +syntax = "proto3"; + +message PeerInfo { + bytes enr = 1; +} + +message PeerExchangeQuery { + uint64 num_peers = 1; +} + +message PeerExchangeResponse { + repeated PeerInfo peer_infos = 1; +} + +message PeerExchangeRPC { + PeerExchangeQuery query = 1; + PeerExchangeResponse response = 2; +} + +``` + +The `enr` field contains a Waku ENR as specified in [31/WAKU2-ENR](/spec/31/). + +Requesters send a `PeerExchangeQuery` to a peer. +Responders SHOULD include a maximum of `num_peers` `PeerInfo` instances into a response. +Responders send a `PeerExchangeResponse` to requesters containing a list of `PeerInfo` instances, which in turn hold an ENR. + +## Implementation Suggestions + +### Discovery Interface + +Implementations can implement the libp2p discovery interface (e.g. [nim](https://github.com/status-im/nim-libp2p/issues/140), [javascript](https://github.com/libp2p/js-libp2p-interfaces/tree/master/packages/interface-peer-discovery)). + +### Exchange Peer Cache Size + +The size of the (optional) exchange peer cache discussed in [Theory and Protocol Semantics](#theory-and-protocol-semantics) +depends on the average number of requested peers, which is expected to be the outbound degree of the underlying +[libp2p gossipsub](https://github.com/libp2p/specs/blob/master/pubsub/gossipsub/gossipsub-v1.1.md) mesh network. +The recommended value for this outbound degree is 6 (see parameter `D` in [29/WAKU2-CONFIG](/spec/29/)). +It is recommended for the cache to hold at least 10 times as many peers (60). + +The recommended cache size also depends on the number of requesters a responder is expected to serve within a *refresh cycle*. +A refresh cycle is the time interval in which all peers in the cache are expected to be replaced. +If the number of requests expected per refresh cycle exceeds 600 (10 times the above recommended 60), +it is recommended to increase the cache size to at least a tenth of that number. + +We will investigate peer exchange cache sizes and refresh strategies, +and provide suggestions based on that in future versions (draft, stable) of this document. + +## Security/Privacy/Anonymity Considerations + +The peer exchange protocol specified in this document comes with anonymity and security implications. +We differentiate these implications into the requester and responder side, respectively. + +### Requester + +With a simple peer exchange protocol, the requester is inherently susceptible to both *neighbourhood surveillance* and *controlled neighbourhood* attacks. + +To mount a *neighbourhood surveillance* attack, an attacker has to connect to the peers of the victim node. +The peer exchange protocol allows a malicious responder to easily get into this position. +The responder connects to a set of peers and simply returns this set of peers to the requester. + +The peer exchange protocol also makes it much easier to get into the position required for the *controlled neighbourhood* attack: +A malicious responder provides controlled peers in the response peer list. + +More on these attacks may be found in our [research log article](https://vac.dev/wakuv2-relay-anon). + +As a weak mitigation the requester MAY ask several peers and select a subset of the returned peers. + +### Responder + +Responders that answer with active mesh peers are more vulnerable to a *neighbourhood surveillance* attack. +Responding with the set of active mesh peers allows a malicious requester to get into the required position more easily. +It takes away the first hurdle of the *neighbourhood surveillance* attack: The attacker knows which peers to try to connect to. +This increased vulnerability can be avoided by only responding with randomly sampled sets of peers, e.g. by requesting a random peer set via [33/WAKU2-DISCV5](/spec/33/). +(As stated in the [Theory and Protocol Semantics Section](#theory-and-protocol-semantics), +these peer sets SHOULD be retrieved unsolicitedly before receiving requests to achieve faster response times.) + +Responders are also susceptible to amplification DoS attacks. +Requesters send a simple message request which causes responders to engage in ambient peer discovery to retrieve a new random peer set. +As a mitigation, responders MAY feature a `seen cache` for requests and only answer once per time interval. +The exchange-peer cache discussed in [Theory and Protocol Semantics Section](#theory-and-protocol-semantics) also provides mitigation. +Still, frequent queries can tigger the refresh cycle more often. The `seen cache` MAY be used in conjunction to provide additional mitigation. + +### Further Considerations + +The response field contains ENRs as specified in [31/WAKU2-ENR](/spec/31/). +While ENRs contain signatures, they do not violate the [Waku relay no-sign policy](/spec/11/#signature-policy)), +because they are part of the discovery domain and are not propagated in the relay domain. +However, there might still be some form of leakage: +ENRs could be used to track peers and facilitate linking attacks. +We will investigate this further in our Waku anonymity analysis. + +## Copyright + +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). + +## References + +* [33/WAKU2-DISCV5](/spec/33/) +* [31/WAKU2-ENR](/spec/31/) +* [multiaddress](https://docs.libp2p.io/concepts/addressing/) +* [libp2p discovery interface](https://github.com/status-im/nim-libp2p/issues/140) +* [libp2p gossipsub](https://github.com/libp2p/specs/blob/master/pubsub/gossipsub/gossipsub-v1.1.md) +* [29/WAKU2-CONFIG](/spec/29/) +* [Waku relay anonymity](https://vac.dev/wakuv2-relay-anon) From 7b38e255c22849238ae0c61fb61a59507ae348c8 Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Tue, 30 Jan 2024 01:33:23 -0500 Subject: [PATCH 08/81] Create noise.md --- standards/core/noise.md | 347 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 347 insertions(+) create mode 100644 standards/core/noise.md diff --git a/standards/core/noise.md b/standards/core/noise.md new file mode 100644 index 0000000..fe92672 --- /dev/null +++ b/standards/core/noise.md @@ -0,0 +1,347 @@ +--- +slug: 35 +title: 35/WAKU2-NOISE +name: Noise Protocols for Waku Payload Encryption +status: +tags: waku-core-protocol +editor: Giuseppe +contributors: +--- + +This specification describes how payloads of [Waku messages](spec/14/) with [version 2](/spec/14/#version2) can be encrypted +in order to achieve confidentiality, authenticity, and integrity +as well as some form of identity-hiding on communicating parties. + + +This specification extends the functionalities provided by [26/WAKU-PAYLOAD](/spec/26), +adding support to modern symmetric encryption primitives +and asymmetric key-exchange protocols. + + +Specifically, it adds support to the [`ChaChaPoly`](https://www.ietf.org/rfc/rfc7539.txt) cipher for symmetric authenticated encryption. +It further describes how the [Noise Protocol Framework](http://www.noiseprotocol.org/noise.html) can be used to exchange cryptographic keys and encrypt/decrypt messages +in a way that the latter are authenticated and protected by *strong forward secrecy*. + + +This ultimately allows Waku applications to instantiate end-to-end encrypted communication channels with strong conversational security guarantees, +as similarly done by [5/SECURE-TRANSPORT](https://specs.status.im/spec/5) but in a more modular way, +adapting key-exchange protocols to the knowledge communicating parties have of each other. + + +## Design requirements + +- *Confidentiality*: the adversary should not be able to learn what data is being sent from one Waku endpoint to one or several other Waku endpoints. + - *Strong forward secrecy*: an active adversary cannot decrypt messages nor infer any information on the employed encryption key, +even in the case he has access to communicating parties' long-term private keys (during or after their communication). +- *Authenticity*: the adversary should not be able to cause a Waku endpoint to accept messages coming from an endpoint different than their original senders. +- *Integrity*: the adversary should not be able to cause a Waku endpoint to accept data that has been tampered with. +- *Identity-hiding*: once a secure communication channel is established, +a passive adversary should not be able to link exchanged encrypted messages to their corresponding sender and recipient. + + +## Supported Cryptographic Protocols + +### Noise Protocols + +Two parties executing a Noise protocol exchange one or more [*handshake messages*](http://www.noiseprotocol.org/noise.html#message-format) and/or [*transport messages*](http://www.noiseprotocol.org/noise.html#message-format). +A Noise protocol consists of one or more Noise handshakes. +During a Noise handshake, two parties exchange multiple handshake messages. +A handshake message contains *ephemeral keys* and/or *static keys* from one of the parties +and an encrypted or unencrypted payload that can be used to transmit optional data. +These public keys are used to perform a protocol-dependent sequence of Diffie-Hellman operations, +whose results are all hashed into a shared secret key. +After a handshake is complete, each party will then use the derived shared secret key to send and receive authenticated encrypted transport messages. +We refer to [Noise protocol framework specifications](http://www.noiseprotocol.org/noise.html#processing-rules) for the full details on how parties shared secret key is derived from each exchanged message. + +Four Noise handshakes are currently supported: `K1K1`, `XK1`, `XX`, `XXpsk0`. Their description can be found in [Appendix: Supported Handshakes Description](#Appendix-Supported-Handshake-Description). +These are instantiated combining the following cryptographic primitives: +- [`Curve25519`](http://www.noiseprotocol.org/noise.html#the-25519-dh-functions) for Diffie-Hellman key-exchanges (32 bytes curve coordinates); +- [`ChaChaPoly`](http://www.noiseprotocol.org/noise.html#the-chachapoly-cipher-functions) for symmetric authenticated encryption (16 bytes authentication tag); +- [`SHA256`](http://www.noiseprotocol.org/noise.html#the-sha256-hash-function) hash function used in [`HMAC`](http://www.noiseprotocol.org/noise.html#hash-functions) and [`HKDF`](http://www.noiseprotocol.org/noise.html#hash-functions) keys derivation chains (32 bytes output size); + +#### Content Topics and Message Nametags of Noise Handshake Messages + +We note that all [design requirements](#Design-requirements) on exchanged messages would be satisfied only *after* a supported Noise handshake is completed, +corresponding to a total of 1 Round Trip Time communication *(1-RTT)*. +In particular, identity-hiding properties can be guaranteed only if the recommendation described in [After-handshake](#After-handshake) are implemented. + +In the following, we assume that communicating parties reciprocally know an initial [`contentTopic`](/spec/14/#wakumessage) +where they can send/receive the first handshake message(s). +We further assume that messages sent over a certain `contentTopic` can be efficiently identified by their intended recipients +thanks to an arbitrary 16 bytes long `message-nametag` field embedded in the message payload +which is known in advance before messages reception. + +The second handshake message MAY be sent/received with a `message-nametag` deterministically derived from the handshake state obtained after processing the first handshake message +(using, for example, `HKDF` over the handshake hash value `h`). +This allows +- the recipient to efficiently continue the handshakes started by each initiator; +- the initiators to efficiently associate the recipient's second handshake message to their first handshake message, +However, this does not provide any identity-hiding guarantee to the recipient. + +After the second handshake message is correctly received by initiators, the recommendation described in [After-handshake](#After-handshake) SHOULD be implemented to provide full identity-hiding guarantees for both initiator and recipient against passive attackers. + +### Encryption Primitives + +The symmetric primitives supported are: +- [`ChaChaPoly`](https://www.ietf.org/rfc/rfc7539.txt) for authenticated encryption (16 bytes authentication tag). + +## Specification + +When [14/WAKU-MESSAGE version](/spec/14/#payload-encryption) is set to 2, +the corresponding `WakuMessage`'s `payload` will encapsulate the two fields `handshake-message` and `transport-message`. + +The `handshake-message` field MAY contain +- a Noise handhshake message (only encrypted/unencrypted public keys). + +The `transport-message` field MAY contain +- a Noise handshake message payload (encrypted/unencrypted); +- a Noise transport message; +- a `ChaChaPoly` ciphertext. + +When a `transport-message` encodes a `ChaChaPoly` ciphertext, the corresponding `handshake-message` field MUST be empty. + +The following fields are concatenated to form the `payload` field: + + - `message-nametag`: an arbitrary identifier for the Waku message (16 byte). + If the underlying encryption primitive supports it, the contents of this field SHOULD be passed as additional data to the encryption and decryption routines. + - `protocol-id`: identifies the protocol or primitive in use (1 byte). + Supported values are: + - `0`: protocol specification omitted (set for [after-handshake](#After-handshake) messages); + - `10`: Noise protocol `Noise_K1K1_25519_ChaChaPoly_SHA256`; + - `11`: Noise protocol `Noise_XK1_25519_ChaChaPoly_SHA256`; + - `12`: Noise protocol `Noise_XX_25519_ChaChaPoly_SHA256`; + - `13`: Noise protocol `Noise_XXpsk0_25519_ChaChaPoly_SHA256`; + - `30`: `ChaChaPoly` symmetric encryption. + - `handshake-message-len`: the length in bytes of the Noise handshake message (1 byte). + If `protocol-id` is not equal to `0`, `10`, `11`, `12`, `13`, this field MUST be set to `0`; + - `handshake-message`: the Noise handshake message (`handshake-message-len` bytes). +If `handshake-message-len` is not `0`, +it contains the concatenation of one or more Noise Diffie-Hellman ephemeral or static keys +encoded as in [Public Keys Encoding](#Public-Keys-Encoding); + - `transport-message-len`: the length in bytes of `transport-message` (8 bytes, stored in Little-Endian); + - `transport-message`: the transport message (`transport-message-len` bytes); + Only during a Noise handshake, this field would contain the Noise handshake message payload. + The symmetric encryption authentication data for `transport-message`, when present, is appended at the end of `transport-message` (16 bytes). + + +### ABNF + +Using [Augmented Backus-Naur form (ABNF)](https://tools.ietf.org/html/rfc5234) we have the following format: + +```abnf +; message nametag +message-nametag = 16OCTET + +; protocol ID +protocol-id = 1OCTET + +; contains the size of handshake-message +handshake-message-len = 1OCTET + +; contains one or more Diffie-Hellman public keys +handshake-message = *OCTET + +; contains the size of transport-message +transport-message-len = *OCTET + +; contains the transport message, eventually encrypted. +; If encrypted, authentication data is appended +transport-message = *OCTET + +; the Waku WakuMessage payload field +payload = message-nametag protocol-id handshake-message-len handshake-message transport-message-len transport-message +``` + +### Protocol Payload Format + +Based on the specified `protocol-id`, +the Waku message `payload` field will encode different types of protocol-dependent messages. + +In particular, if `protocol-id` is +- `0`: payload encodes an [after-handshake](#After-handshake) message. + - `handshake-message-len` MAY be 0; + - `transport-message` contains the Noise transport message; +- `10`,`11`,`12`,`13`: payload encodes a supported Noise handshake message. + - `transport-message` contains the Noise transport message; +- `30`: payload encapsulate a `ChaChaPoly` ciphertext `ct`. + - `handshake-message-len` is set to `0`; + - `transport-message` contains the concatenation of the encryption nonce (12 bytes) followed by the ciphertext `ct` and the authentication data for `ct` (16 bytes); + - `transport-message-len` is set accordingly to `transport-message` length; + + +### Public Keys Serialization + +Diffie-Hellman public keys can be trasmitted in clear +or in encrypted form (cf. [`WriteMessage`](http://www.noiseprotocol.org/noise.html#the-handshakestate-object)) with authentication data attached. +To distinguish between these two cases, public keys are serialized as the concatenation of the following three fields: + +- `flag`: +is equal to `1` if the public key is encrypted; +`0` otherwise (1 byte); +- `pk`: +if `flag = 0`, it contains an encoding of the X coordinate of the public key. +If `flag = 1`, it contains a symmetric encryption of an encoding of the X coordinate of the public key, followed by encryption's authentication data; + +The corresponding serialization is obtained as `flag pk`. + +As regards the underlying supported [cryptographic primitives](#Cryptographic-primitives): +- `Curve25519` public keys X coordinates are encoded in little-endian as 32 bytes arrays; +- `ChaChaPoly` authentication data consists of 16 bytes +(nonces are implicitely defined by Noise [processing rules](http://www.noiseprotocol.org/noise.html#processing-rules)). + +In all supported Noise protocols, +parties' static public keys are transmitted encrypted (cf. [`EncryptAndHash`](http://www.noiseprotocol.org/noise.html#the-symmetricstate-object)), +while ephemeral keys MAY be encrypted after a handshake is complete. + + +### Padding + +To prevent some metadata leakage, +encrypted transport messages SHOULD be padded before encryption. + +It is therefore recommended to right pad transport messages using [RFC2630](https://datatracker.ietf.org/doc/html/rfc2630#section-6.3) so that their final length is a multiple of 248 bytes. + + +## After-handshake + +During the initial 1-RTT communication, +handshake messages [might be linked](#Content-Topics-and-Message-Nametags-of-Noise-Handshake-Messages), +depending on the `message-nametag` derivation rule implemented, +to the respective parties through the `contentTopic` and `message-nametag` fields employed for such communication. + +After a handshake is completed, +parties MAY derive from their shared secret key (preferably using `HKDF`) +two random `nametag-secret-outbound` and `nametag-secret-inbound` values used to deterministically derive +two arbitrary-long ordered lists of `message-nametag` +used to indentify outbound and inbound messages, respectively +(e.g. the `n`-th inbound `message-nametag` MAY be computed as `HKDF(nametag-secret-inbound || n)`). +This allows communicating parties to efficiently identify messages addressed to them sent over a certain `contentTopic` +and thus minimize the number of trial decryptions. + +When communicating, +parties SHOULD set `protocol-id` to `0` +to reduce metadata leakages and indicate that the message is an *after-handshake* message. + +Each party SHOULD attach an (unencrypted) ephemeral key in `handshake-message` to every message sent. +According to [Noise processing rules](http://www.noiseprotocol.org/noise.html#processing-rules), +this allows updates to the shared secret key +by hashing the result of an ephemeral-ephemeral Diffie-Hellman exchange every 1-RTT communication. + + +## Backward Support for Symmetric/Asymmetric Encryption + +It is possible to have backward compatibility to symmetric/asymmetric encryption primitives from [26/WAKU-PAYLOAD](/spec/26), +effectively encapsulating payload encryption [14/WAKU-MESSAGE version 1](/spec/14/#version1) in [version 2](/spec/14/#version2). + +It suffices to extend the list of supported `protocol-id` to: +- `254`: AES-256-GCM symmetric encryption; +- `255`: ECIES asymmetric encryption. + +and set the `transport-message` field to the [26/WAKU-PAYLOAD](/spec/26) `data` field, whenever these `protocol-id` values are set. + +Namely, if `protocol-id = 254, 255` then: +- `message-nametag`: is empty; +- `handshake-message-len`: is set to `0`; +- `handshake-message`: is empty; +- `transport-message`: contains the [26/WAKU-PAYLOAD](/spec/26) `data` field (AES-256-GCM or ECIES, depending on `protocol-id`); +- `transport-message-len` is set accordingly to `transport-message` length; + +When a `transport-message` corresponding to `protocol-id = 254, 255` is retrieved, +it SHOULD be decoded as the `data` field in [26/WAKU-PAYLOAD](/spec/26) specification. + +## Appendix: Supported Handshakes Description + + +Supported Noise handshakes address four typical scenarios occurring when an encrypted communication channel between Alice and Bob is going to be created: + +- Alice and Bob know each others' static key. +- Alice knows Bob's static key; +- Alice and Bob share no key material and they don't know each others' static key. +- Alice and Bob share some key material, but they don't know each others' static key. + + +**Adversarial Model**: an active attacker who compromised one party's static key may lower the identity-hiding security guarantees provided by some handshakes. In our security model we exclude such adversary, but for completeness we report a summary of possible de-anonymization attacks that can be performed by an active attacker. + +### The `K1K1` Handshake + +If Alice and Bob know each others' static key (e.g., these are public or were already exchanged in a previous handshake) , they MAY execute a `K1K1` handshake. Using [Noise notation](https://noiseprotocol.org/noise.html#overview-of-handshake-state-machine) *(Alice is on the left)* this can be sketched as: + +``` + K1K1: + -> s + <- s + ... + -> e + <- e, ee, es + -> se +``` + +We note that here only ephemeral keys are exchanged. This handshake is useful in case Alice needs to instantiate a new separate encrypted communication channel with Bob, e.g. opening multiple parallel connections, file transfers, etc. + +**Security considerations on identity-hiding (active attacker)**: no static key is transmitted, but an active attacker impersonating Alice can check candidates for Bob's static key. + +### The `XK1` Handshake + +Here, Alice knows how to initiate a communication with Bob and she knows his public static key: such discovery can be achieved, for example, through a publicly accessible register of users' static keys, smart contracts, or through a previous public/private advertisement of Bob's static key. + +A Noise handshake pattern that suits this scenario is `XK1`: + +``` + XK1: + <- s + ... + -> e + <- e, ee, es + -> s, se +``` + +Within this handshake, Alice and Bob reciprocally authenticate their static keys `s` using ephemeral keys `e`. We note that while Bob's static key is assumed to be known to Alice (and hence is not transmitted), Alice's static key is sent to Bob encrypted with a key derived from both parties ephemeral keys and Bob's static key. + +**Security considerations on identity-hiding (active attacker)**: Alice's static key is encrypted with forward secrecy to an authenticated party. An active attacker initiating the handshake can check candidates for Bob's static key against recorded/accepted exchanged handshake messages. + + +### The `XX` and `XXpsk0` Handshakes + +If Alice is not aware of any static key belonging to Bob (and neither Bob knows anything about Alice), she can execute an `XX` handshake, where each party tran**X**mits to the other its own static key. + +The handshake goes as follows: + +``` + XX: + -> e + <- e, ee, s, es + -> s, se +``` + +We note that the main difference with `XK1` is that in second step Bob sends to Alice his own static key encrypted with a key obtained from an ephemeral-ephemeral Diffie-Hellman exchange. + + +This handshake can be slightly changed in case both Alice and Bob pre-shares some secret `psk` which can be used to strengthen their mutual authentication during the handshake execution. One of the resulting protocol, called `XXpsk0`, goes as follow: + +``` + XXpsk0: + -> psk, e + <- e, ee, s, es + -> s, se +``` +The main difference with `XX` is that Alice's and Bob's static keys, when transmitted, would be encrypted with a key derived from `psk` as well. + + +**Security considerations on identity-hiding (active attacker)**: Alice's static key is encrypted with forward secrecy to an authenticated party for both `XX` and `XXpsk0` handshakes. In `XX`, Bob's static key is encrypted with forward secrecy but is transmitted to a non-authenticated user which can then be an active attacker. In `XXpsk0`, instead, Bob's secret key is protected by forward secrecy to a partially authenticated party (through the pre-shared secret `psk` but not through any static key), provided that `psk` was not previously compromised (in such case identity-hiding properties provided by the `XX` handshake applies). + + +## References + +1. [5/SECURE-TRANSPORT](https://specs.status.im/spec/5) +2. [10/WAKU2](/spec/10) +3. [26/WAKU-PAYLOAD](/spec/26) +4. [14/WAKU-MESSAGE](/spec/14/#version1) +5. [Noise protocol](http://www.noiseprotocol.org/noise.html) +6. [Noise handshakes as key-exchange mechanism for Waku2](https://forum.vac.dev/t/noise-handshakes-as-key-exchange-mechanism-for-waku2/130) +7. [Augmented Backus-Naur form (ABNF)](https://tools.ietf.org/html/rfc5234) +8. [RFC2630 - Content-encryption Process and padding](https://datatracker.ietf.org/doc/html/rfc2630#section-6.3) + + +## Copyright + +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). From 71278a84442a7c4c6fa02ab2713ef6a59834e999 Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Tue, 30 Jan 2024 01:38:08 -0500 Subject: [PATCH 09/81] Create noise-sessions.md --- .../core/noise-sessions/noise-sessions.md | 155 ++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 standards/core/noise-sessions/noise-sessions.md diff --git a/standards/core/noise-sessions/noise-sessions.md b/standards/core/noise-sessions/noise-sessions.md new file mode 100644 index 0000000..8aefa13 --- /dev/null +++ b/standards/core/noise-sessions/noise-sessions.md @@ -0,0 +1,155 @@ +--- +title: WAKU2-NOISE-SESSIONS +name: Session Management for Waku Noise +tags: waku-core-protocol +editor: Giuseppe +contributors: +--- + +## Introduction + +In [35/WAKU2-NOISE](https://rfc.vac.dev/35/) we defined how Waku messages' payloads can be encrypted using key material derived from key agreements based on the [Noise Protocol Framework](http://www.noiseprotocol.org/noise.html). + +Once two users complete a Noise handshake, +an encryption/decryption session - _or a Noise session_ - would be instantiated. + +This post provides an overview on how we can possibly implement and manage one or multiple Noise sessions in Waku. + +## Preliminaries + +We assume that two users, e.g. Alice and Bob, successfully completed a Noise handshake. + +Using [Noise terminology]((http://www.noiseprotocol.org/noise.html)), at the end of the handshake they will share: +- two _Cipher States_ `CSOutbound` and `CSInbound`, to encrypt and decrypt outbound and inbound messages, respectively; +- a handshake hash value `h`. + +As suggested in Noise specifications in regards to [Channel Binding](http://www.noiseprotocol.org/noise.html#channel-binding), +we can identify a Noise session with a `session-id` derived from the handshake hash value `h` shared on completion of a Noise handshake. + +More specifically, when Alice and Bob call [Split()](http://www.noiseprotocol.org/noise.html#the-symmetricstate-object) in order to derive the two final encryption and decryption Cipher States, +they further compute `session-id = HKDF(h)` using the supported key derivation function `HKDF`. + +Such `session-id` will uniquely identify the Noise cryptographic session instantiated on completion of a Noise handshake, +which would then consist of the tuple `(session-id, CSOutbound, CSInbound)`. +For each instantiated Noise session we assume this tuple to be properly persisted, +since it is required to either retrieve and encrypt/decrypt any further exchanged message. + +Once a Noise session is instantiated, +any further encrypted message between Alice and Bob within this session is exchanged on a `contentTopic` with name `/{application-name}/{application-version}/wakunoise/1/sessions/{ct-id}/proto`, +where `ct-id = Hash(Hash(session-id))` +and `/{application-name}/{application-version}/` identifies the application currently employing [35/WAKU2-NOISE](https://rfc.vac.dev/35/). + +## Session states + +A Noise session corresponding to a certain `session-id`: +- is always **active** as long as it is not marked as **stale**. +For an active `session-id`, new messages are published on the content topic `/{application-name}/{application-version}/wakunoise/1/sessions/{ct-id}/proto`; +- is marked as **stale** if a [session termination message](https://rfc.vac.dev/spec/35/#session-termination-message) containing `Hash(session-id)` is published on the content topic `/{application-name}/{application-version}/wakunoise/1/sessions/{ct-id}/proto`. +Session information relative to stale sessions MAY be deleted from users' device, unless required for later channel binding purposes. + +When a Noise session is marked as stale, it means that one party requested its termination while being online, +since publication of a hash pre-image for `ct-id` is required (i.e. `Hash(session-id)`). + +Currently, it is not possible to mark a Noise session as stale when `session-id` is lost or gets corrupted in users' devices. +However, since `session-id` is shared between Alice and Bob, +one party MAY decide to mark a Noise session as stale if no message from the other end was received within a certain fixed time window. + +The above mechanism allows a Noise session to be marked as stale either privately or publicly, +depending if `Hash(session-id)` is sent on `/{application-name}/{application-version}/wakunoise/1/sessions/{ct-id}/proto` to the other party in encrypted form or not, respectively. + +When a Noise session is publicly marked as stale, +network peers MAY discard all [stored](https://rfc.vac.dev/spec/13/) messages addressed to the content topic `/{application-name}/{application-version}/wakunoise/1/sessions/{ct-id}/proto`. +In this the case and in order for parties to retrieve any eventually delayed message, +peers SHOULD wait a fixed amount of time before discarding stored messages corresponding to a stale Noise session. + +A stale Noise session cannot be directly marked as active +and parties are required to instantiate a new Noise session if they wish to communicate again. + +However, parties can optionally persist and include the `session-id` corresponding to a stale Noise session in the [prologue information](https://noiseprotocol.org/noise.html#prologue) employed in the Noise handshake they execute to instantiate their new Noise session. +This effectively emulates a mechanism to _"re-activate"_ a stale Noise session by binding it to a newly created active Noise session. + +In order to reduce users' metadata leakage, it is desirable (as suggested in [35/WAKU2-NOISE](https://rfc.vac.dev/spec/35/#after-handshake)) that content topics used for communications change every time a new message is exchanged. +This can be easily realized by employing a key derivation function to compute a new `session-id` from the previously employed one (e.g. `session-id = HKDF(prev-session-id)`), +while keeping the Inbound/outbound Cipher States, the content topic derivation mechanism and the stale mechanism the same as above. +In this case, when one party sends **and** receives at least one message, +he SHALL publicly mark as stale all Noise sessions relative to messages exchanged before the earlier of these two send/receive events. + +## Multi-Device support + +Alice and Bob might possess one or more devices (e.g. laptops, smartphones, etc.) they wish to use to communicate. +In the following, we assume Alice and Bob to possess $N$ and $M$ devices, respectively. + +Since a Noise session contains cryptographic material required to encrypt and decrypt messages exchanged on a pre-defined content topic derived from a `session-id`, +messages should be encrypted and decrypted within the Noise session instantiated between the currently-in-use sender's and receiver's device. + +This is achieved through two main supported session management mechanisms that we called `N11M` and `NM`, respectively. + +### The $N11M$ session management mechanism + +In a $N11M$ setting, each party's device shares the same Noise session information used to encrypt and decrypt messages exchanged with the other party. + +![](./images/N11M.png) + +More precisely, once the first Noise session between any of Alice's and Bob's device is instantiated, +its session information is securely propagated to all other devices, +which then become able to send and receive new messages on the content topic associated to such session. +We note, however, that two devices belonging to one party cannot simultaneously send different messages to the other, since only the first message received will be correctly decrypted using the next nonce. + + +The most updated session information between Alice and Bob is propagated in encrypted form to other devices, +using previously instantiated Noise sessions. +In particular, all Alice's (resp., Bob's) devices that want to receive such updated session information, are required to have an already instantiated Noise session between them in order to receive it in encrypted form. +The propagated session information corresponds to the latest session information stored on the device currently communicating with (any of the devices of) the other party. + +We note that sessions information is propagated only among devices belonging to the same party and not with other party's devices. +Hence, Alice has no knowledge on the number of devices Bob is using and vice versa. + +When any device marks a Noise session between Alice and Bob as stale, +all other (updated) devices will consider such session as stale +without publishing the `Hash(session-id)` on the corresponding session content topic. + +In case a Noise session between two devices belonging to the same party is marked as stale, +such two devices stop to reciprocally propagate any information regarding Noise sessions instantiated with other parties. + +As regards security, an attacker that compromises an encrypted message propagating session information, +might be able to compromise one or multiple messages exchanged within the session such information refers to. +This can be mitigated by adopting techniques similar to the the ones proposed in [35/WAKU2-NOISE](https://rfc.vac.dev/spec/35/#after-handshake), +where encryption keys are changed every time a new message is exchanged. + +This session management mechanism is loosely based on the paper ["Multi-Device for Signal"](https://eprint.iacr.org/2019/1363.pdf). + +## The $NM$ session management mechanism + +In a $NM$ setting, we require all of $N$ Alice's devices to have an active Noise session with each of Bob's $M$ devices, +for a total of $NM$ concurrently active Noise sessions between Alice and Bob. + +![](./images/NM.png) + +A message is sent from the currently-in-use sender's device to all recipent's devices, +by properly encrypting and sending it to the content topics of each corresponding active Noise session. + +We note that this allows the recipient to receive a message on all his devices simultaneously. +However, on the sender side, only the device which effectively sent the message will know its full content. + +If it is required for sent messages to be available on all sender's devices, +each pair of sender's devices SHOULD have an active Noise session used for syncing purposes: +this sums up to a total of $N-1$ and $M-1$ extra Noise sessions instantiated on each Alice's and Bob's device, respectively. + +Thus, if Alice wants to send a message to Bob from one of her $N$ devices, +she encrypts and sends her message to each of Bob's $M$ devices +(and, eventually, to each of her other $N-1$ devices), +using the appropriate Noise session information. + +If one device marks a Noise session as stale, +all active sessions instantiated with such device SHOULD be marked as stale as soon as possible. +If the device declaring a stale session does not send a session termination message to all the other party's devices with which has an active session, +the other party SHOULD send a termination message to mark all such Noise sessions as stale. + +This session management mechanism is loosely based on [Signal's Sesame Algorithm](https://signal.org/docs/specifications/sesame/). + +# References +- [13/WAKU2-STORE](https://rfc.vac.dev/spec/13/) +- [35/WAKU2-NOISE](https://rfc.vac.dev/35/) +- [The Noise Protocol Framework](http://www.noiseprotocol.org/noise.html) +- [The Sesame Algorithm: Session Management for Asynchronous Message Encryption](https://signal.org/docs/specifications/sesame/) +- ["Multi-Device for Signal"](https://eprint.iacr.org/2019/1363.pdf) From 12436232ba53d21a6b19031804d3582b0d6f6848 Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Tue, 30 Jan 2024 01:39:26 -0500 Subject: [PATCH 10/81] Update enr.md --- standards/core/enr.md | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/standards/core/enr.md b/standards/core/enr.md index 129e4ca..670c88d 100644 --- a/standards/core/enr.md +++ b/standards/core/enr.md @@ -1,21 +1,19 @@ --- -slug: 31 -title: 31/WAKU2-ENR +title: WAKU2-ENR name: Waku v2 usage of ENR -status: -tags: waku/core +tags: waku/core-protocol editor: Franck Royer contributors: --- -# Abstract +## Abstract This RFC describes the usage of the ENR (Ethereum Node Records) format for [10/WAKU2](/specs/10) purposes. The ENR format is defined in [EIP-778](https://eips.ethereum.org/EIPS/eip-778) [[3]](#references). This RFC is an extension of EIP-778, ENR used in Waku v2 MUST adhere to both EIP-778 and 31/WAKU2-ENR. -# Motivation +## Motivation EIP-1459 with the usage of ENR has been implemented [[1]](#references) [[2]](#references) as a discovery protocol for Waku v2. @@ -25,7 +23,7 @@ such as Websocket. Currently, Waku v2 nodes running in a Browser only support websocket transport protocol. Hence, new ENR keys need to be defined to allow for the encoding of transport protocol other than raw TCP. -## Usage of Multiaddr Format Rationale +### Usage of Multiaddr Format Rationale One solution would be to define new keys such as `ws` to encode the websocket port of a node. However, we expect new transport protocols to be added overtime such as quic. @@ -50,7 +48,7 @@ Directly storing one or several multiaddresses in the ENR would fix the issues l No new RFC would be needed to support encoding other transport protocols in an ENR. - multiaddr contains both the host and port information, allowing the ambiguity previously described to be resolved. -# `multiaddrs` ENR key +## `multiaddrs` ENR key We define a `multiaddrs` key. @@ -67,9 +65,9 @@ We define a `multiaddrs` key. - The 300 bytes size limit as defined by [EIP-778](https://eips.ethereum.org/EIPS/eip-778) still applies; In practice, it is possible to encode 3 multiaddresses in ENR, more or less could be encoded depending on the size of each multiaddress. -## Usage +### Usage -### Many connection types +#### Many connection types Alice is a node operator, she runs a node that supports inbound connection for the following protocols: - TCP 10101 on `1.2.3.4` @@ -99,7 +97,7 @@ Where: - `len2` is the length of `/dns4/quic.examle.com/tcp/443/quic` byte representation. - `len3` is the length of `/ip4/1.2.3.4/tcp/55555/p2p/QmRelay` byte representation. Notice that the `/p2p-circuit` component is not stored, but, since circuit relay addresses are the only one containing a `p2p` component, it's safe to assume that any address containing this component is a circuit relay address. Decoding this type of multiaddresses would require appending the `/p2p-circuit` component. -### Raw TCP only +#### Raw TCP only Bob is a node operator, he runs a node that supports inbound connection for the following protocols: - TCP 10101 on `1.2.3.4` @@ -115,13 +113,13 @@ Bob SHOULD structure the ENR for her node as follows: Indeed, as Bob's node's connection details can be represented with EIP-778's pre-defined keys only then it is not needed to use the `multiaddrs` key. -## Limitations +### Limitations Supported key type is `secp256k1` only. In the future, an extension of this RFC could be made to support other elliptic curve cryptography such as `ed25519`. -# `waku2` ENR key +## `waku2` ENR key We define a `waku2` field key: @@ -141,7 +139,7 @@ though it MAY be required by the relevant application or discovery process. - Flags marked as `undef` is not yet defined. These SHOULD be set to `false` by default. -## Usage +### Usage - A Waku v2 node MAY choose to populate the `waku2` field for enhanced discovery capabilities, such as indicating supported protocols. @@ -153,11 +151,11 @@ MUST filter out participant records that do not implement this field or do not h - In addition, such nodes MAY choose to filter participants on specific flags (such as supported protocols), or further interpret the `waku2` field as required by the application. -# Copyright +## Copyright Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). -# References +## References - [1] https://github.com/status-im/nim-waku/pull/690 - [2] https://github.com/vacp2p/rfc/issues/462#issuecomment-943869940 From 2063dd3d18f849428dd91e2c12d61ddd296ac802 Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Tue, 30 Jan 2024 01:40:21 -0500 Subject: [PATCH 11/81] Update noise.md --- standards/core/noise.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/standards/core/noise.md b/standards/core/noise.md index fe92672..e4a4204 100644 --- a/standards/core/noise.md +++ b/standards/core/noise.md @@ -1,8 +1,6 @@ --- -slug: 35 -title: 35/WAKU2-NOISE +title: WAKU2-NOISE name: Noise Protocols for Waku Payload Encryption -status: tags: waku-core-protocol editor: Giuseppe contributors: From 6f42b1e1229c75795db5c57f2c651190415ad7e9 Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Tue, 30 Jan 2024 01:44:14 -0500 Subject: [PATCH 12/81] Update peer-exchange.md --- standards/core/peer-exchange.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/standards/core/peer-exchange.md b/standards/core/peer-exchange.md index 189a872..0441e17 100644 --- a/standards/core/peer-exchange.md +++ b/standards/core/peer-exchange.md @@ -1,8 +1,6 @@ --- -slug: 34 -title: 34/WAKU2-PEER-EXCHANGE +title: WAKU2-PEER-EXCHANGE name: Waku v2 Peer Exchange -status: category: Standards Track tags: waku/core-protocol editor: Daniel Kaiser From 012a3ece1a775a7f77377d8f5b3bd9452e15d419 Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Tue, 30 Jan 2024 01:46:00 -0500 Subject: [PATCH 13/81] Add files via upload --- standards/core/noise-sessions/N11M.png | Bin 0 -> 99382 bytes standards/core/noise-sessions/NM.png | Bin 0 -> 93899 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 standards/core/noise-sessions/N11M.png create mode 100644 standards/core/noise-sessions/NM.png diff --git a/standards/core/noise-sessions/N11M.png b/standards/core/noise-sessions/N11M.png new file mode 100644 index 0000000000000000000000000000000000000000..bc28d58eeb4ba0fa415d1a7b9318ab80680c96d5 GIT binary patch literal 99382 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 R<(I)f6kU_O549b_{~x+-;`aam literal 0 HcmV?d00001 diff --git a/standards/core/noise-sessions/NM.png b/standards/core/noise-sessions/NM.png new file mode 100644 index 0000000000000000000000000000000000000000..b445d3d7c410dafbb0faf7ff2d1c28ee7c09bce6 GIT binary patch literal 93899 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�ZjL3IPi6aeuE-oQ&mL3F4X>l3^y4ijn(^h z;7nsC75qmxSq6213Tj9rTj6(9l;Or|4{G`hw@I?-DoXKielv}a8QvJjNZ=pVNfq&M zX=_r#Dz^ci?~8i?0)2_XZKAaPF?(F({?NdEb%)GesBvnvArbmY80 z<5z8von0-*gP>cD88j(2-~Gfy!oYM5 zjTjMc4t#?g(VGds%8}>AacrVmV{iPw)_}2Un&36GLB)Z~WE@6KnaseOnwGLqBI%76dw0QvC6mAVbbNt@+MIOb z8yuBqWIuWb7X;rqEfmeHFMR2Jl8j+e>;E);4B{r!|IRBB2L#njB`IzJ^GoVbLkMI!5J`wqeV4I2i4++7Y}-CkAkR;(Vgqd%@pHRcQQ3%LT+YzN_wZ$U()_qA-wG=iQC z2={D<{+=0vcjz@9?TSY>79x_ck>DOe^dD5T}nKKT=!? z=|t3H(xeo>A7p`ScqgDvtix&I$T)X?@gxY&WFy_=r#%)Ji;2 zdOdZvdh`7EWX6@Po1Dv+Sqe50Ql{r)t!o`+>-Q>dl zH(xT|aPfB)uyOW^QeE922lndJ7QeHX2m08})F);OZeu&kRX4*D4mf{ZlzA zt^yQ)5plu~(mo9G$6zTz-ywH*H}Pe_Tk+Kz=#F0yBH?pkL6waGqb@P%5r>@|c56LM z(1jDi{=D%r-hNeym~KuplIK@p3kmJy4GfE9{ue1cj&#Qm+T|LUICcTau7OdIS&#%H zAN@>c$RH2!_AdkMQv%ciMvpH<*e+#+gOvDr&s>c`)EA4>x)E1)9UY(I2LX^egJ_1b@3;C8}RSuL!9u zrW>5CAL}4W85syn$j^r9g;D+eoyq#3(^a6}`fa`yAt-~~PWGDY2gx^c_<&Kju?~ko z%2tKcGq5f*1xO(cJ+!n9p&)qbKbjf&*d53K*h)|!?o7p+q5%ekTPPGv)qo_@{Q3XN z22*S+)$k9LAmofC0jz1-IY1xG(u#B$2ybOPMDr#JCya_`UpFv_7$JejtZZ>d?Hhoi z!i5|ec=PN3dxl#M{0$WFj*Wm4LIdR2&{a_E&Nn(OfRwb*Yw*J^{p!tou#n4iTDm;rCR`$HOE zJ@(lt;F5aKM7lGW7%INvuQd7X_KUp8PH*`8JMU$F8$l@RIUxwvQM%8A>TwMMrVGpR zXV6jsTYSvs0hobTU7d+%*3t{(}PhaNUJ& zNR#<`1SmspW;=o73}iA}1MkW4zy-<~LXt}cbe)t#ZBV04&Ua_*C7|Jj!v2tM;H|u5 z4yWgX;7|J)G=(O=r`C*1;tXVY5#Z6C$1-Txy(B5quCMHSaQ3hH$GgJ`-|oR3HiODZ zs0(R07jr9)q=H^ZzOc3a1nYa~Diuh?JU;@itfd~e`;Yz_9{!X58aUbk5Ap~{=6{X4 zYFy3&F(FU!o{xZZ9uT04-~VMrlxfxOeE~@qtkk#Gx}F@-0AxxL128{jrY@3o3(fMG zQGs&oN(}(mHGrs-M1pfrN_Kkb`#azIm1xCWb6l!aCUT@QP7yd{^P5uX0-lIr8=`B^ z%v^Mv+_3SZNMyIh1t|#@fxb5+Och}Ecd|q)D6Z^Xc951xE;Lh0+xIzLh2$j|3I0J4 zm20;InYo1#ywHV3K)7`)5CIN3z(vrsMGs6BO#N{J4wYZWu^C?HF+3vHG`(&f6EA_> z`YIGq!aDDC_q;eDFD^Plgq&T!IS@eM!}7*#S)_+9(-SAC1!cwWZb`ObV0iE~xo!ZA z_B^Yi>l272>gj;171+=cFbkphZrb8|zvV?cn8&@Vu`7li#C>6U;8}8HmPK18t5VSmd zzvt*HMU_Y^&4FGvQdhv-k}vhbO%Yr95@Sbt#c8VrSz%nBYWGM4YDBA$RS%_XgowNW zbyz>(Ban2Qx#ba9geybFq8YXpsUFnz4g5W`5h@@b+gWyQcj~NoPvRAK2;#hl55b+X zbMk%2TVldynR$C z8j5#_Y&BA6h*=f}r5?5CTm8_r2W-zsAg7~rK4MIFUMvLXUwvMB_0N2$FV)Q{hckf-47BTE>)l;;%Atx3Dy{b&esfS3K28S*Oi%p37rQ`P19AS!ejyQX z!|ATFrU19m(0A16;AY} zN&qLxjwf?;^f{^CUs-vo9TNL@gH18KuELFv87Dq$ z5)8545ABKa!Fqp1<9%U|2=iBaER)0%H|Bu&{1v&Ww38mdI#V{Za)9p}Y0)hSR z{|HW694XAtvzq^pcfNHCOym2YAr4i15&+tftQ$PWn>Ns5(8u`whUdG95`4izTJda# zmC7&%2)!#`F5aXHeh$tnMN1U7KqLG2)}Mf9+bgdN2gp5T*>NZVO?mbpGPCHb@rAPW zl8!33z5%|q&#yis$R4{S=cCEDh-@SryMu>DBr!p&F?gMcX?1}uc| z^uak}Xo0fbE(5>DVXZ{Yp;pUUulIj}n3wY}o%^Z5KqC6_Kv6;u_FxR< zo<^a>)1WKb<)4H)yoYC>e&4Oo2zs)QYn#6mdQH7-j~w?G?|pCk(w}jE5^%=1$Txn~ zVJ=!(SUZz)BYfa0c*ptZcHl*Cz!oY@i zrvEY=%SSax1{YfxDGP{GLtCGiqjb|mjf*=@4L`g1;j%(6j~BNpxSrNm>i+#Hxy9am zeb1`RtjRVf2mSKoKG#fjQoFHj2VxV}s&mgTH^cef`==#j>Di$IQQL;U$A^!f2m%`V zJbkVgsyn26wKcPUfIZI>RegVtb8+nQBBkB6_SO1`(ek}2VXst%)`z~buiTN5u`@FN zHHkLa#E^jtpI?af8#8Im3=BU!AupkE`H;1*UAyg|a5pEwlz0S!&_t&Rxw-|tH%H?Pj z%h>2|CRVoq{eAMaBgK8FW!;kbjR>PJJCnU)7n0CvK^^BHEAad6=L`QHqLQd{>dW8E zs-D6^UJvsS-&^Il!+N=7#G-Z(xCe_driK&kui4A~ z1O&IS_1&m;ZcNnC;6G5N#LMsk#Z(Hwi!6xweoErf9X=!}@+fHRZD#r|_+nNf>V0>; zZNZ!PCvL-i`zKMgM8{sAs_oQR>b2vA6uHFPukSE6m3TIeP`TzIx&2U~u0@WS(P*rI z+BLFk$}2kMu6e zD(b+D_BIQ4t1`yz>F^J6A9%hl|G3&ZAGs*}h2AkBRnQ=Cr(#1{qA&E)YeQAeC(45R zQ2pQ#rKaH$wU9E{;`rn#34W4gNP4q!$JKD?Tagg6`CZR|bF-r7p3O!hm0bsU3knKa z{nKLFOHVdW_PN05U@M%I^emX9ohta*s3?8^hzNykSs-sl--a)D|BvY}LE@;UuA5w( z@ZPZ%0pDlF<6tvb6D7t^1nuS6vmEN2^ypsuYYYBfettr=&+|N8h*YuOw)x=}G&M76 zM?1vS{4Doi+Rw&KssH8jnbZn7hchsq-Ttw>Wl=kdK|afYVNi4zl_)bN7$;@S1DiOi zA&Kb0UYtnllTJcm{s?vZx&6U2d`Zty9t8J?wcUg?lx|@=Hq+F0wHUfh5#4lQ$>qRp zkmFq=wcPb11yI^wCaDSplmZr$1BOEzgYs2qn**zX{xJOa$0oc$$HxD2E0E%({mvBK zr3e`iU>MfWAZsm5?XW}jT?*fG8Bn((l#CGihQ$!7+ zx{5`%V;LJjr)&bp(OY?_+FsPv)zFxL@2Yp6* zZI~yET0_O0Nr4X3D%}~P&qrdtnHd?^ufrSiLjvdK0wCFqz4?kcO{1l@<=v?Q-8$}| zt-L(>Wh3P8nlvqW9}3NmgSAC)(g(1g`iOi(cZ8GYN^B!yW2d*93sbdaw#ju3p(uZI zgzqfq=(GG03zWwE)L3iW#i9?UvuOYAgNIo{b>0<+KmR*c@D&cQnSShVTL7XLim`jlaY_&L9wvgYN@M7q#zOfJw06qxjZHvdaZ zUkSoIo+37l15Au5&!z7_VJt50%sDn60f1mwnl;O!Z4~9+Zw&#z1qpMGEUOsb7dIu< ze84RRVLuV5k?o1#u~oOxsi${K1seVBft;}NW{WXy*0zw8vE^I~V8+<)d( zlKvlOa&0G=a`I1Hm8fUiSclQ2qH9VwQ=*=x$rZzkewd#n5TF1sXGukL69EVs0l)6c zjSe>vF7D%3gs-9sZ7dYh=&0 z=C8z&KJ2>AP%clawrYq{6t>>j|EbJ_NQ^Cwf;+v{-sPz5LJbz9R{vH!L%XsMPca6R zR7+6I4_f6_*v~$ySxW3Q>zW$4YY;@HSU~*;o0d~wn3x$mTMGwXd)Cq&c6;LkkFpaN z2&iYH3>4b3THx1t|0>@5Z6>OalP#6%i2FnaegN%|^!nTPr%=bmBX(SYk8&nsL%Nnu zh>}_2Ui;56q^FUcOIT5|m}MhMKxB(IA@l$4>!Fa+ZSh)rhe;bW6!qS|5gs z?ab^nmnhqWek_czeT>R|e!IG*Cm?tx3=YVoqRd^cY4E#|`GCaHeQXOVYb4*XZ^(P` znt#J?sY~p@=7GR8X|nEj{H0jO0Pi{DycBwy)pXseC6@6E&rc@Vzn9>NTfYGvDAm8B zg;!iq_rXbdz*k`)TD4@?s7#K!>(Hbpm2rJBAoL1zj%_l6%D~cXLZMd*ToQifAMeaA z{fV|^AIQ@l*s~=Z7tcIaGolUWC!cbmjrlI z*L1~QHE$2S7Y7BXZZ~p88Ro|acDA|Q=>Aq_6IV#yBxGz^boJcqN%{+L(|oX-b%j_& z*&pW|2r_$M&hdg?Z-VZF)2?)K3F4ynwfTouwTp))zk~rn{rSb!c_rFatO4ndj<2(b z@!hzDkm28;&j=V1zy8L^(eyt1Y=dHJHHNrO#}_PFu~*>MCNLOvN$gC4NM1-u1b>X% zzVQ_)A7;lj7)|`FUDi7|p=Vr$(P?EIevhB10N~r9*+xD|Lu>3{pKZJp`VFwT#GaQmioh zR#SN7G3~IW<}0K&@H=}u?!J#|))|!KyKmLg)#rf*M>OfHN!~v^`dL!kZ+;V7emkgf zFz(`v(jD0E5<60NRZ?lr@$)1oysxEO3#RgEC-W#*-cIuWi<3^4!QYvG@Ab=#zH&Cq zp5zO9?bNh;|Dn=Wc)aD_s2ZLqqpc5Km$|Vhzx0A{N2`Fp;i+iP>omR!J2Zu=I4Ls( zqse~KxjJX^@g(1*oN<$q;;vSyq(7`V-a`D%Q2h#?voJ$Hb{&b*>zgRYACnHOmUi2z zsArHPn>Tu4kt*dm$?YImVE=pGciOi-%Wx_5P|!Fp#-+6c&igk4kP)M17iU$7*^y=Q z9xD8-QM%047gT7bGg{&e7uX)v*xeMCxZW+sn$0S>YWE31%~OmTtLaH(zO<>Q%})h$3`xQnU-G1Tf|I{1!3N&ZDQjE<-$+O;|OB15b@sDr$E62VET)I;TH?(Bg z!0+&71&wC+qqIZzp@F2TTiuBQuJ#qA(dq6vWj5!q8KsWMx(^ze4Yv>WkP7vc8RHAZ z`KpxU{Czhql@`S@XCefp7hP!w#4Jz1`1?(!TeBDt1wp6h;Y?C{m}ZUxKODT%xWTSI zV1cc=M_P0h30h#*118Y*?{qV%bPqGbF^>_e3)uWuVnFr7KS%FhwD`^WfCvgYs(dMX zwR4VodQM{SvVeEoOrx`ekM{{ap1!tsLU+oTwArdomegn-j2^qn5E1~^^+PH=BwXI# zK)m*pf?S<~h?DH&Py-YM66C<;GQl!@dzJB#+PnLw9Yti#+h1KUMyB`j@-DI1VR)#W zX7?F6kndVFe*eJ4mDfcD2)h?dk$Sz+{6ok$?Wm<}b(}c$4=EpW{?qgMaDYTs)69=A zwqP^qaPuiO-8(&5@~ZPZQW`f7QN*w@MNA$@Q8%A>^G+RNNLC!M74C^v6_}xH8gJxm zVLig(%U^TTT7vKt*fMV8{8^q%o>cR30AqjusO>tb{n4INtj*@mDnrvK3XLAxGGknd zHX-p9!vU7luPiJV{878!t}+J83RB) z>cd0Os}O#vBbiq*LA)~9;xARLzi*mG|=E3H$?Yl{VJNxlZk>s$b}&@1CoET+AYsT={+IHwOmu3ZJxircU(U~ z^660?e+>qroeXB8K*N(agTkKla#f}!Xp*m_n`#i6rS2c0p-k6!UozXO?#T!fXmG_sO(0N`{8ee&PFcWy$>Om|rJ?ESk&SdSo=9O0ie8jTz zbY+{q_jYJBnZWvPxW~gOXW&XQO7WfU8@IFKllU+bKwCX3ASA;PD3USbMoNBB{f2Xn z{ksB?k7YK~I#WbXD?&XDlK$)Q@Cy~0$a`f;?1-!!+OpJ_V(ouGKsB3VnCO?I$UDHR zbH{9CU5T|h=SR*U-(EOCk^GT7XQX|h)%QF`%EZ83xvS}p_O*Hh^|F>9g&H6!CF?N~ z%u&T{$Fy6ptndRv-)I<M~|7 zdSQP|g1lX8wIwJslzPfsKVez1MHdisPwyjIrm5#z;+;!x-45L=IL;&063wNtq~%1|?Da zg~`n$+Q4t9rz=f`sp8hH;~BX^^ATKuhKVP=rSGTHj(ef8iq6)ws$0#;*CLUzsVFOb z%$=qljdd*o&XvZy%|10zkn}d~E>{rWda29qLNLZ)mdW_y1uusd2+Hft)ZEEPY%05NjoQ>oDYIL(PIYffC0 zYGZJ7_tXi%u&O-qqL|4=2F@EgA|&VEjyInLmUgznk{PnwreL-ac9;SD85w$Y!b= zO*w}ntrtoN;T z*E`rU4&I}=rdtCRmAe!#!?3r>QyuIQsbfSEr*2pnIjlVAr0mi-DSmtzg?W+QvDbKxEX&Fp{5P7_gJg@-`pWu z-IVE`y2SSTP?db))B#7s?4Yy`1-M}E(beH#V8191`xgvH&>%!LF_ki)Ze^x~SqZM? zO+99eoDNUvXS=Z&xbLK-oqkmE*GY-Z^~UHCcnh6a=`6M!5#vbok1z#q)D}K)OhocDp`wLVK+tjRDD!^3=^{Ao?a|a>S74!54*JBX_(R7m z_q1IQm82Tyr;p;mdk9m2R{Lz zNa^Qsj`BK(DFJZLx2Y{&^qL7k7tFzLo!YMI4ZG^!ckwU>NW%@MNVA$ESq*3Rql81< zIK-eQlQ!^sr2~T?x4a&i=KGjN>F5hzl>+k+=(Y08*5;-?B;X)5QwO&|+Ueo;OgHGK zgm{j|^vI;lyP>AR9SZeY)3rlO#Q+B#PqSEWKY&F1-iyxTp_ue>DqE(cH{Dj>Vxw=HjaN`uECrHNqW^mQmT6t*Bc}fKHM30vY94hT}|O76gqZva=;JJ zVwd_Io46locZ!^E+sYhpqGni?_M#-VNZSiy)ns(Kp?51>RMJB9z-mh9Lm;U)D>{Xb zWi#*8-2kr3Ny?W?l``FF*Zn&dm+4neyQUcI5dHgAx=m}$yLOm~Da9SG&{>k!zL$+O z2XpGD`)~aXc!Ki8X2)PlKJ&@jnsFB#cQGu}diGociNc#%batvnUX(8pw2l6ABYUVL zisWpXe%x|5c<;@Dcvi`gkfrl*kN9*VRMdG$lCiU?(3l{mDpW_ye-coze7>4oSUz$G z4j;{v;lx75oJR$UkUnJgm(wL7?x;VRV&Q!gYL!aAvW7;oA@=VUAWTRqN_5C5hE^?; z$??@@WE%J6qyhg>AD}E`!z54oH%);mWy*|Hduykd$8dmq^Xyn!a!tO+l=J9lr7~nW z`C(QgL-<4U-ljwHam(_s+H`iP<_k{nBv~5QN%46i#YWeXW|!kvC6n{( zT)AuB>;^%OMk4GxbqDkYE9{jaN5O>v6MAdQZmU4s7gyZ&I(wL)@Z;^nGZ&=;jZ*ZC zzA&Yo282qM6K5OaF_J}` z`|`u{0heOIVEV;V>VNiYJ;P7hgpS&924Y4zbr};SaFpxK7i>IB}j++>_n0 zKYkPK+D15H*>aL(v|pK@cTE8g_nT4CZ2F+Onp240Y!DP|#v|Y$H-}C(gRS7`<&=xY zezjKMLenvTC#vm=L&yehr2u!TTRaH?vsBv6#$UrN>u#~SIN4p!yiuW4KV2diWN##r z{hVC)s`(Vm#9g``oPF$8#t2t-hW{hhrcl|b&U-)$mpENW+naLBH70>#m9NhR~?T3=OOAH0JDr+z77+uW!rQU zB-55qF@~QNDER>Q+bze(?!)u{6RozmyuFM`k7}3A7uf2n9r6~@hRKfh4!7%ki}tjK z40i0j-7F6$ZPlLAUowy(^?vYg(80xE!cQib2EJo=7UlWZwSEyhPg>lBdv*IHo{o0# z7AMIU5EyTEdAsnK`sY2Fey#b(7N!o!mw}sHUejhKHW(@>vz>|#|4Hb78w**DmMH#E zi5?ssIN{PUZv1jEsWQK2EPTfk?9CO$cZO1m?1k!uI)$*tzZl9S!5jAh28fAd5lw4cTpzlQ(9Ob%z87- z>=oVTJ2T+S{|rn9Lb`d!mj!xk+Oiq}CwDpB>(IU!L#^^IZCFZr*P}k3Wn;A3b8Md* z{G<$x$1%ViAr>Jh`It09%F?_Yy#ZzbUfUYZYpl9Nitb?h7WwyHRrlB)Hq%?ztao-H z(iO`lJ$7KYefG*y55IQu*Rlx*#u@TVv(`hF+EH*O-u~FNJoF9?jqI@OrXGdB`U-0E z_W~)!2U14|f=IsDUHm^Aufr|iYN+bPt$rXmWyiYW8?&N+QY~dYewTzZRSXLYPK}0{ z_*n*%;n((mY*Fc;2%O=9_>l7g%TmwRRn_r$9eNaUC1q!?O}Uf{3^n0wUwCR<$t;Eh zu_(H@0L8UE5>B@B58m_^4$SrW)JpIjZ1mTyAlT3*?ulN<^7K!ckGra9g?|SVf_502 zjZW-Py!HKxnVBp}g9$!3fjZ8>o%FFNH!fuXkL7fUFt%N=2gdCtBTsx#b@|>EVa@5B5F5D93jc_X!XX7~qDd ztclhQu1gVBu>APqRm^$mme|9{^O^pAP`hzhmVJUv4OY=iYYEY28fjVc%xhk?2gj8d zgY!XJo3|(*zpC*%fTGYLwIJgOWLe07@l;aMWpP|7^#`Bw-M~`OlsuRmvq?kS1WPe* ziZzSJYiEriXPz%4o1KH37KJ$5fd{h&eB(SPg#_h@I;XZs5#|(y7OU1ne6jnavlbHd z<^vWdq6uu$w;w$Zr6N=V$6{!ulce_3NE#Z869D~{ zPnr4*`_Im$83`LCOL1^e$FW0oRvNvWih)O{$kp9@1F7El?SsTBL)?K!P|+CCo>l*T z$Q?(~xyMysL)eW{5vi3X8ThX3$K`AM0I?fdY&xRO*o(U}xAFotI7$d#yit!;Qyl*j zq&c;D^@5-_jp@G_`&A10jS5N7(wwZ!wkNO!9&^rYQeLxd7p&uSg5gU1E`~-pWk$^I zvh7$KYYVaZ=;ykNk#H4-SVzCJ2GV&Ehb$$pVjB64uMA|oE6_F09C-#h)xEL}Z{LGO zEiH@0OMmwb49f?O^!vf&f@WgW`Ix1C=&)4FY?%A2{tW}U!6Gl)cm_6FFmW0%V19#k zZ@gp>eEQ#YC_0hmbq4*urnHXcCP!&|;#Y=qsLL5&l$4NkZ0@IFpIq6GoO`4@+Z=^q zAcum#r(||JeXLQDT1cCQ`p{&>PT*q9{#%jYoEg>g10Mbb6l;v5^y*h@C@S3Gy66bk zS@F|D&TI1l>p}#5H}i#SG&GNrBEp5rC=k!VR=)JC81@Rk>z5!NYD( zE39(~D(@~S8nV?&wSRCp0$g6a2IpeZ8bp_oxE%|?QQE&N*CCOo(OKz{>|IcCwpoya zCF!@}MTs2^@E~ypav+o`kFH>+%M26(ZH8MRo-!zbkJl zF-Ym6BqKyiXe4kfYa$`-kY?mgxV;TT^4JXsz1{m9=hN<216#@S%s8_ES#)7c+9&+h zPBTBI2;M+?X)m?STiDu*Ba{a(oP>mG8K#j{!q^Gix77V7fI_~H;?gu36WI+f}Q>qXvl+?XCIJd`G`33kmur9+#Kn6S}hpu+L_n6eKJPz{}CrOF8_slu1Gx z4JoN&NxLC*^Egu^H^nXLc&AJQ4+}LziWt<5jLja+s+S0)OQEFMSe)u>q|e#!^A)rk zPF>pHcjH1F=KF2E`HEq)ZEr*OO*mrHTFa^Tr zJ7^dDfEcT72p@zpfCd>C%Vu<<+TWFt)u;Ae;Sei|$!`W|7na11Y3gRc^tIe0=O%$ak+>)dhZq_e_$I$v~qYRBO&0(?Val|&J+mx*!`f7 zrMV@0>G(J%Qy*9*$tz~VaNfg4f|=}g^*c}aaMTQy*KANL??s~sYKsIE#B6PC%!ff} z{*VS(2R$a_H4f#lNjoTLz9Jg9u!9mufh4J!F4|Y04%Iv^G5aexU5RX%MqkyfrJ=FU z2&MymHTp@!y}BV>kuk;W|5?798wdeq6wuXx!sv&ck4*Q}BK(IJ8(^QX ztvRS18e9hk+@v%sPE-Ix7d`OV7BsLY0V)KAFpMTMjc8YBM>@SzBBt(z-_PS}q(6*R z6?kw3FYK%g1AMCG|8<)fzizwv+6kTWcn`|M$E|olj2}^ zX;va)fJGmqVGYKAnp;r2 zd|q)evP3MN#Px1~Ty0%%eHfn16TV=ENFUq=gU@EuPvnx#F|2g)DJfwJQ$Kr0PKuy8 z7$Q#(o(EL5L>Fyy<&PmbWen9F(~yPo3cVW3@8`d<@--CKFIc__`}!L^+h?5qO3DR| zGzN-=ay^F>>$CM3?|!!XH`D`9w6K)9TJOevQIzQuq97Ry(7_!Yu^Veu#`7k-5#|q8 zB{>#RUv}_Cwk$(vgmZ75t#JpwOmY?wX zrmq!q_`3>?>HwVmzvVcW=H;k`Ps>6F8SeuE=DEP7^q_1 zF$2m{p#V!I=Fr_jYs>UexJl1?|LuW>b{yj8WYtI-kMMs$FOz~xnc7@`p;HF72ZTg8 zj{SZ;6}@_cf%o+%+%AAQ0GOqE4a&)7@|VgZCh3fg1?oz{bD*R}UsnHKQRgE>PQ$Slm_o>o&nrb+JbW)Pis8DA8YCh&q z)aDv3+(=n%d3^^9G;z*3F#%lKzi#QOe>o$SI5&VnJ?%w)jm!S(mwy}kj=?Qv`0M!J zkY5|5J<7HP^7-vSa>dNp&^_n!RSiBh_r4M^ETQJ9gbk9!?GFo*Vr%RRT>e|2=Arqw zSjUGk%)@Ytt1Q%mlRivnA#nTq%lq886l@JuQT~eGmk@S2p|7r}v7X*8B*TpIJamr` z7xl<&^+^dHk}yjaW-{9n#sVlj{SzKZrot_Gc@5L3V#?v-{(J*63Hx4~7|Ak_$M+dG z2+fgV2*aB0hZm@-?8hw(gm6k{h8Uh5w!`0L#^u&tpR`<<rqX0TkIa^Sx7v?Pz~2+Y$qi)RH1hT|tXS8RvNFL!Uzo zx0P%uQv8EK7@Z!vY`U9z`q$Z9{?S3SR7Q+{t=IG@scRG^Z-ZL>q4`U9`8af}5{g@{ zp0*TzbKo%99Qp3JZa$^CsS++aH(srFt}rw#IFY)4bAyu@56%p2AX=D)m*)d~E2;pk zyFJ%%6@}MC$uFSNICk;Vv!4{M<+!9H4Zgv#E_C)T^+S|kFypTmKAcPayvZhW7#eTL z7+m!H?NFacBWK1c^ao$cpg4}Vgi^E+gta_Oa8S&b^CE~wKEw#LGY$7_+auu~)?!>G zg=Xe`G5F_m-|ogbnTnM-YGE?6=zH@K%=C@kH|DNCHW^T7oMsDxHl zF^TO_Uw{dMlBT?L7&Ga;9_(*d^Vrv*@Mcd`{t$=|6WRqXOUv$$ScQ9TOc_*I&}PHW zWKGkQUeogETD~&po+he5PfyF!!R)Ir9f#L7W`+%KmTE{v^Jr5P%84-4pPl@eQ`V=q~0^PkI{pAMLk?>&M`RmPrzi0U_8-ODaOksblLkM_jufa zh>|epg^LAYeRY3I(^sWkPHhHSb(zjL*PJ#S8Ank^MiLq+X(KYKp7%8NeIEMVyE3|1 z8rDZOp{V${eR^-(x6Yu4-A{qfALwfD;yUT^7w^{T&HYK%?*d#W1OBdgiEWP*bm+sU zXSAdZTvx)q^9pTJWbs8Ame4(+UxNh7f1K=R!KV%X7_dQp zE;KHJv=EjHy$&Si!g*{l3#rjjcB|Nr;@|I+>6ZyQ-D zq`|R}TA*GYEvgV;IblZPh3l*?VBj7~{A5QC9SEIAy-oS)J8i}uFS!|0%GUttxsQ{S z>|&kTy7gqjs>6nd1g)?*0bx5N@>T%7(qR%h6|A>zg$hSkWP-PJz*Nk+C#n98b}o?3 zdI&i|Q!^#`czzcS5&(*jjqI6p1fNC2ZSc)pMD4jveItlLOwhzJ@Ojnip5oSz^2RL` zz4J8$k)O2@;FLrYcRiy~)#fp7%5;{9uxSAPLvV9Y18!Pa_~DDq#pvT5QrL06Tu=&J zct5YB;dC@d_R^t*Paq@HXvru5=HuBQ>`L3x%akZtc`r?JDj+gczZ^Q!vhpRE&FHKO z{2zj2erR>I%1Z$6!qFD=av#A3o`b8<%DjRQO*VjP{$)c%(HLd1T?O)iOXq=DaybIQ z1=C5G60V=h-)S&=vi#nkO;7;kUxEfTV<8_B-E5-|YixJ@3rAuo2C>6B*7|j9(7t`R z*iQ|8+iz{s1{`jVIFL5ID@R5ympAUiSn3v9t>0tVMm}WQeoI58ATufFw*@-(AN;U> zA`tc9H9lejR^-rentp@6$z~cQKHH(k2n0){H7tkAf#AB0oYf0lOFnrK`}6yVexl!t zfY~-AEz%I?7(80Qg-%nQX;XH{OT})YQTqrEAY+yHekykzc8AbpQUZ?N+g_XIl`l$g z33nXAr9#I>x!K4Bwxl;-=r3R*2m0sv$aN`v2+8X6lb{#*4#fOM%JgJBI@5>Sl^NRJ z@>HN+yAA$o`k5`UuLVnJWyC0j8K8Ak0igIyqm1mje{WZ0w?K_J%3m>Qm9$`K^0%Bs zD3|Li)D=a9*}0$B|5d%FXhe6!Zp;-Xod5h>zcxk#j-0=(su~50E`DhH8&bSGug$F( zxbFn4&rRAq!4e8%=W|AaR{R=eebssQehW~#xGlj{dPfrgo9ofa@NmraXBP$s19foZ z{D+;pb}!Wdz4PhKgYdoPb?K@c9}S*_t=XtlM4!5ju?_7$=$?Sc+@}*Y^KKhS-SfDq zEq?Uubg_}`0z6d8w892-t~YC1vk8|;El`?QEH(8V*fF?>-FE9niGKEC7fOwJ*IJZ0 zIB1Ws_;WQqnr3WO@(NaQj12Rn$n}p8dyi31SNw*d9X4wc=cq->w|Ns41ds>6{dIc( z=GJDAR3-ghn%-iso3U+be@DnUn5|aKx#v;8+@D1PsyL(;Y}h<*bgGmk3iJ-YF}g8@ z*b-gS1}VV&wwPl?sIA+#Y69s0ncR#~_x;ZaS=RvAHB?g}MmO6>{i(;G;N1zd6843aHQtlD zx~}al{#?U1?3mE`_maeKmgk^YbkgyN5uK(d_s%{qKVsqAQBjUPm9`-YUIFUs+4tKA z*RGag3*7n>rlG(Sw68324C)z2=};din{!yl5^0FM>;i{ z^m)~Kujig^zs68xk?wn;`9B-$r3#P8=Y}{~b>k2qyn06(&RPw#t0OxzUtmn^rIr#m z0V|2qROtw4#@d-J9U*M)T#-NU1p4Kl8s9^JDz3dh5|d3F%*~)5cl7)O?%8ZM)+jGE z|M9d)~zM@u4oz8AiT9)%) zI{R>^?&PFL(~z^f;m0u5`1aL3;4!pUadQBkh$H?JD*K!62Gfaz42N(x_CE2{8OO|m z&w1i8ZMrX6TpLL8z;5c^P$i^W-)%^7Y1Y$c9w99)g9Tl+m~*NX6=|7(!IERMzP%jm zhDq1iQ)^lWPshJg<%{Y*{{8SdxTLD(1i{N=Opm84o1N_@FG}$Z=dF6b&zaWQko@Xh z9oBBY;UNhR1?{+lryJS&>-3EU`uK?VKtz^Jo>G#eO*HGh*8Iw`XZjKPS6%CKsa5he zqsE>(nAt-3JcKaK3%ZQ()?ZtET4P$C?-hIP$M;pvW0$RhCY9wE-4FF$c$38=w_mlg zdUeNyi%B9klk=;1r8oEgToto2Q+*YuQOiaiJ``Uw9C?M)-6*zWR^!)Q_c-Y#YG!XR z3+H|>XqGw@pJO^_qD%?bkt{8E_del@59Kn|o6lL{9u}Zfk82vxT@z|EL#J&Sxo+{z zR|0fbrueKG1ZQ|MDB6BJF3SiMB#N}{0}~gG;Qg;GmwrRyTvc2rUshiH zIa_Na5++4(Jef@v%2j~ok-jFxbdq0 z9^C6*X*IsGa}1t$Vfxyh-m0gUV74>Mm2qW%vD6x}6zZTKuRRl9$h4jOeYNSg+$W9l zyXTX?qR>0{AZr56R;P4_~_`Gp|0FHL{PL7M42ja%H6^vu#Z zm{_se`u!MnS-N_9a;8Oy7?@IDP5N3fovgcoX@RyemCIu_;7pAnE72Ks?`)isZrgca zPBe%)?{PX`TeMu%VdbmsMug5%p-0Sigp@#;ls{AGVEpIZ#@C*YL(WvoL8FV;!zO)v z#b~9jo?#&nvNigOPdo#zzNdVOB*cG`Irrp8{%Pc%iY6Me!MmAs_i`3qZw2DXoWj3fl_e9`E4bTe?AKUe~rc;=Yl`m#ko`0 z`x9bo{)H`jqqNqL)Bu!#YYhTUj8^@a)Ob5G8(@`nGA-L3zt+wXJ) ze6R7|)CT0gNH*lp8^T{7X$?BSWtA8XnkC`t=#Z5rMFBj-tq<#mK`bUu@ZZ1l?N}Q-+)7Rd}lQZIGJ^grcM~=IY!QZQB`us6!9RPHsU*GIi^)>#1g7J*MWN zcYe;aL2AR$d>sHQVPuW`2gQiZCh6WT6 z^{0W8^dA8XXP8U?)*!_L?hz+P94VwRv3{_n0i{DKhJukj0P#w^63o{FrBVqZi5L0{ zn}%VXc|(fH1p=XpgEC!q8U039A+5(zqPK(~Cn=3%-cb`0qAvZn-*N*jp-#{yA7wZX z3lY3%Wf!bak{QSIZ|ow8wkUj(jbjTqt40sTcQ;S$MTae%vw);OO8SY!Xa#+kWOmb8 zOimzqQQ*>G64FV-Z_uo~5Dk)tioUhCyj8%*%H>!?3t$X@DO?)ERB2`b-76dTAOd6g z_ZhNl&}x3UJ4_mIvgG(+N35!4CDifK7lT)kbcO44AwHb#dDjQN(P@_0uo~N((wHub4s>}bq!8hwcA3(i<&uo$b~w%9G!!F zsX!ALXekN(AV>RPH{`rWnBUBNs)e+@XUSnKH2^;GT}S3V-tD{EU5VG`ymbxWOn4nW z;6gGWGK)zGN?V1OA%tu3 z5XD)Dn>v5PMnSARmi+_HfP!_oBhkgPYay^_0IZ$L+%8#syc^hB5;r@Nh<#+4J*Zar zcMVLkDJS4{JKjE+rmZ?T58FTHk07zr6@o^#h`om&!lSb{%^w%%sGG?rq$2e)$Y6RS z1c+Q6u+-$#!eoE8>%;hARYMn$c;7sCiS`g<%0almDQF5zwx;y9MK|&BPq0dI)qW63 zPb>W~>{dy8NRK?b=1m$w;4XjRz`TJz6HR{S_6jm-mil#^_)Y_hog|g zP*3^(#NQyjG>evG*Uf?1=e#@X1cl9()x|YUgfPrJ9U30rz^;Gj zkZqDzS(d#GHi^?TNAdZ55650dWd9vM;D2d5jF6Cy#ux&l1eE#0nW>Fe1W^Ex&>Cz9cIiKj5+!N?ib5l_1RewNd^k6nB7J#^(KcDvW3qMKRvvr zqm)iKQ4nC4q!oBcYN%-;;aoi!e=>q0B}2~Dds3XN^E~0y{(QYZjrj65D!Ij0#+l>? zICwi+YRsGWfd8BaikfVsbViL8-trbT>2a@^x{sGxRNj6#TQ#(w{HiF?uJPo3 z%$6w+tYcu;hfGYhi|hfLPnlH16Ag_&b}DYCYyOfX8EE1|>#9=LE;t!i?NEM@NHIz+ zR=GRL+vV_#5Lggd|1$y%#w^)bEK{l84P>$=(PXLe#@zOMuZ-*IPq5QI6~S;1%(z?p zw&7qUbMx*bP3E#x;S*u2Q26#`cI2J#yzT^oTHzeB^!D|hrLPZTk*Mnab}?D>89I3? zh#_oMkzD%vJAk%Ce}g=&HA&h?ku4XHZgS!F_8D;ET({6yNm^~YU?Dep0}s&Q594gb z^l)jEcF?>`xo{o;msZlkz8}{e_veE-I5F8;);3zl*Mf!yez3-Wp=0VU5~?N%*N7y2 z_-THxljV1FjngE9U_U%(eWXqaN}k&~B|jdjPtqJ|3Ll8<&q+Zx(yA^;;S44ZQCom8 z$haESBhn@Ta77H#-Mq9VXbpui9LK$D6GME6UfI*m`QS;tSjp{nyW$3uME1B-(;8En zp^DLVUC7hPFw{~nr9tJ2^iPA z9}ZS98Dh>sx5NSYOxUr?H&{V?Z}2Mg3oUZIDjs(O$Ibu-x60cAE2&lpv?01QnVWGcDa-nkj&>&TxRluD@Zyp+KuUIfvb7Sp1E(d zD;jD*{0`&Y1{%*=!Ur5~9rIAy+udeal*yn+?%*Oi$A^v~#xG!;m;V5zo^0^ra}VV* z>(YGQED*7p>%mjs~?P}7V9l;fQ%@SzE&a?~shK0!qZG!o697n(Jp$$+u#8>)) z|K3{-CtpBI+YUAH$J#OVABZGUb#?nXDdF;%q{pDW`c0}eq6<9B3^#q#tz~!1{XOV4 zb0Eii8{Xgsp~E!k3_JycS6{LyW?S?P!?hl|1meo#{Q0Ed$AJyX0pL}LOJUa^8_eow z>@RSgkMZTn*!v9G=N9KPr7b?#`cC`aw3c1W2lL3>t7x6G4%~rv!L0JMC!_r2i0YCP zU|wDcaEKiqrI0dqRB_|g*8M4E{eFRpo@-byTfHv>TA~#%Hes%y)Z2FvtyL7`nz2LO zkY^4!hSfXn#O8m4zucnvhXd?NA$HNpOXCN?dT8r^D26SS{2fCHiD2QYzll&rX!LXDKXsXFyH=7fWD(cPXk8X)Q!_=(U$48iT;? z*&74-XgkfuRFeeWKZ5TxV2jey2R;s=xYd?i-(Bv_nfzJkzJJllQ1SG~GxD{WVC~?8 zGRJV(N~SF}3Aond@wxtUFSii5R-h4-Hlu%FL~f%tuxIh0%}amjf6$;SsFOM&7XZ8mF3 zV8yYD;k~;Ss3!@UejGM-ghl8mS-cPta-k6>?id$_$NeCUUa|dWwTd2t)GQf6q|V!zVV{JRKWn5u{}HZ~!If|_@$YxQG>hh7 z4+p(E3&Rc`1`8Cl!jJg-wI>koI{Iq+b*GsGfp~yJdM09`A zE==&cNpj)Z2$jCRV|DdbhcY_96WkfP;u+Ygfd)YjY;_n@&B~d>tC!-C}$v%WLkRs$i_h?SUZoRB`hLrlDaX`K+Hj zIm`#D^`tyC)m?!Pq1&8b%oGQf{}Y+*S2zRdnZCdYIAo5c`GI5{-{gLm%sWEWP+6-h zh*KziROfe2!f@ztF4m?ATyB26r~l6h21~M?x@pZ6R71|x_i;F3(32#1%3Yna3KTqY z7bNiUt zVC9Q_?cNYq4qwBpw}}Pz&mZe*$9%y!y@IMP^>2j01Sw|DOs z>kHUSzM%=%i@b?X!VO}0UNB1>u-B0--Id7mFYj&eNd?%k$jJuF-&v)q4y^num|6nY z?KH|P?9QRXyOO>+S;N?GGE~Joj3S#_A7kLSHj+oCQ8{Y#JV8P^k1;nXUqtRd`X@oKmI7J@76ni_uZ-a7=wH0EjtDVp!nT9pp1fu+GccBy}> zaiLZXuqi)i;;oxk&>w|ZIib#7BUDv(&y%4pzjN|VG?{NfVwc@AdN-GeX(o67woM{b&9ZX|!mVQIAR<)$5v08of70PMi?SFw4e$LHvy!651v)<+_*HP7Rm+7%nm0+McDW@2z4-JmW9b zYzD8I{G91Q6mCk?hMS_}a?=EV#w&I$l#a#hNU%IzV@+x#hiT!&Z|FWSX| zE{Ox{5)^42mm@}g!;y3})0&IGhaYVH=?#jM=dow9Djw>9j?K^U40Gx0e^J&9pQ~X8 z&NZxvlSUT>zp#^rReWqIB#Wq?ifuK3VcKw zJFC55US<=*a7^dSgsm^zq{ZG|0f8v04+AjCbdw{uhVVc!Qfs0i<6uvxk`j11jBdqR zN9vG?ZV4YaW3@Zel8dliSeB33%WW@z8B%v53@#1yCelaVCR{5~NGDzA= z!mLpc6QW7RZdE>}!JK7pZ?s$!a#WB?0RSqP<9q6?4C71!97wxunWh6;StWZ;IN|3W z13$hX;|804Y95@7G$(B7+VCl0*kuaYPG5M1)lx6y^6*x)%>F{=G{suh5(B(R>kJv? z2JMAJpV8)e!EeK_+o)m`aAs!KZUk{ zu?CsvB^|;lPUa~7Q3(J0u){Uhd6k4+u8YA}S8|80Nzp0u9}~D!sN?drq{|kNBz{*; z<+wScSEUzo`QYrE*v!-XnzQxSwm{1dJvE`VwmNccw43umSCez2j~&(%0zzE7NsB zlWic1My{sue>PJ-4CY!Fz6Z>!)v1}-_~!5d3N~#fOIC?xLWPFZX%wPZNCxAW$#Lwm zLic?cSlV;++O)IA*EQ7p!-dfnvwpE8NRcqepuurQ>4aKcf>&xy(zWl%AxzHt!jXE; z!@VriCP&6+JaD~`a#vc#TLc~g{t_VM1%urr=xT= ztLQ?_;Y7M_N`hU>GkB(CEO@mxIf@UfRmAQ)Ld_{{sU2e*weQzeRfz$TYjU89`kQo| zwO?&)51a%v>5yF*#n|3dl8FL`qhl5>5uMEX_fN_2d~JSTq#jc_{Z37><<^RYIY&3u zjY7r;&JfKiz|AN&wkRLjPRhYsII(s-Ub(fHgWsv0Ap&DxZ=jzQ3^+1;@VS#Q1xbsu z{R2dA^uFYm+1+M32i#7@^rd|pSTD6+Qi?9x${uqxT9kpu7A1&86={YnIiY=-i+l zyj%W)SsvK>xKH;)d-`6sCxO$?x8vN6hMbM4%v3~z)(v5{)54zTK>s`H8*b7;Bu#BbKl{Qev1Kgk6wzN23XY4?1?R5jATQ?VH!WWtvDT!M4g)2}8-0v0 z8sSA8{LerP<*}RVvssP3$@k=`#eyqk<|lAQ#+3GuN?|#WxhOur%lSL0pi?mMbT6QR z4;m3IJ+EHVVR~{DN3=3kjg}C~7SwXj915L;*J8FWeKfzmW|RP_7ig9Kh_Oz6_nb;& zSUd4HB4voWBm;)|Mh*|#;0e@^+2L{@Ue0TQfwijk8;K^07q#C9LQUC+irp`1j(ICe z%TkV^@d7_u_}?H4?DI8>?kN=PMu;~Q_E16lu^iAk0$VRJ0ZO07@2k%Da>EQTk`s}87Ighle21Lupm7#Yv@TPh-irR0G%ijA3 zf0h?|&Sc%Z>xp=gSou4}e2EbhQ8i4TP@-~n@|E&yE0{~*c-5i+B5apb>PF+V)%1na z(Y*1rS(b=8Nh(m?(;i}Ww&xXRjjcOB7@jHP)onOoC)k25s>5c*G060H`@#aobDZxh z`F78F9&sNJ)^;h$HaTd+MZ9jj@Wz5SM2$F@VdABe!~75o5}4vxt4Yr2$-I1Y-1qZu zq!xL31#xO3T76!+ z-uic|xl+KR{`1@fqmZ?r7jm0%@`1#czAcKUUfDf*5o4nCCWNvo81VSFy|F97f!6oz zf)r@=plJX4_j%w0SFoxuEd_Q{x@7muK$_O!+1w18s8px>v{4y++`4x}%x*bQHz(@X zJrU6YG7%3N0;3Hn$R#Bhf&tSaqfaaIcl!rRGBuI%K9PhEBz-KZ#)C9$0D+mJ#v3GY zGMLiVmuqn@?Z1JzatZ$b2)W&T4=L;(7|BSyw|&;&jErKO)PoGq zZZ8bvTsLqZe(gsdELXIFv<&a>zHTAo0A**Z4y;nV&&+CCLt~36DPC2SsP@{%^`xNj z4^4pVEewC~Xa^Y4+E;}s(46t){DOVm-rV6hY}R*djp5gC63%yc1u$KdV<5=8Up_fY zBp-r99u) zF8gpbUV;k<)8oBMUVlpcj?>30ZyuwDWhUfk3QX3X>tc|$o-slWxt}YWkpe@fo*k(j z!W53Te>;aEXTJIGy2HDtzZ>4m+u{jbtM3@x9bx;sGMI4G*b?Af-rwgw$IZJX1%hFa zs=O=eqrnXJe=%@)awDT1X=k$wv&UPzywUKEwY3e%EYD{d&>^J(_}kpaUkj=flWY4; zNm{1@C@)<`q@b4%%`eX|fWd|rV9xodFPx3KOg~x}3u#-xeAY(m7J>z209=dpFC{ATcK(ZLFM{U@4HI~;BCc^)lXxK+k!RNbCi~Mi4 zpFmC-(FCTZU`>>GfxjD8wgHm+lHmr$A&cAC(t1&YXxMqhQd4prCkA56nK z$Px>wvNaKu0G>Q$KTnEm{C@ZP$!(;VGon9DktNB*ri9pZY^llfGw=DinmwaM^R+CHE&-jg}>_a`j|r;DV#i+&T>EwIRwdy9uB z-ocF$00HaC2SGA}nBN@1XK!qsCw|9J@QSZ?T(lXrCeAtDMA0)f6YrX=NV_(O3xAyC z!H+CDo!Fi_Ma%{tN0fkvkwq+|5wysBBUSno-0rF{@uLQ_ACi>#Z-dM6G=NHe=f5kU z7*G7J^%gJc))HV<9%#2@UxRoR8W1Q6gwddmuP^JSkQH0YeTNIhv8)E!@1Nb?YJfXz zpz9H}*JAj#gALW}-6=1N>?>~u3Vj0ok1#1++Yc-iaR@^~;02sq=!I5>If}=*@F7j_}y?X48Zy?>Q{s?p%8c_r44i}3l z$1Lgv*L(j#zI=tMM4s$LifmU?OnO7#OtZWEQg7O7L3a|_nJNLLLhH$WldY7+HEI$6 z*TiI(VJNBA=~@NofigeSdW82_`AFJy4G6x@v|_P}l+wRr;n6<3A7beX=lbjCtEQDq z{{Yrad;}m*E~cFo9Js7zl*dr_#DUNUvh~BgkC>XcOWCY# z3@Y0no{HC+ zUFC!pHK53}_-RFd1@JRGlx_y>J)Qmf`9*@zFAr9)TSs$1h_BtS53RzPcH~_JgNkzt z{fB?zsm!bI@WF|WBQ8kcr0*`QzEmFADG)Gu>YK!2r#!~{c?(!L{aOA7x!5o=tAH-{ z-p#r_8dKxf>HJ2#wCUF&E?@QQpg7I{Vc@3@>zS{}7W?%oG9m0j{l#0#Uw!LNd8Vpf zFZ#_ke~vv7xcL{%k$2Ujk`5WuRrMeoW5_>Ig z2iZWp+@Gbt{nqFK{|w`=XW@*Oiye{c>a5ad)mI2`Uv2hEv1gOL81j@a^8KS1LLY&U z9M^irEg{zgL4AL(Tll%)jNx(hafHS5YA}r=f2>zneD{=<4)+d5#Y*q&0yeR7OND)n zoJ}?x$QkD$ZgL8)C4r_?@D3yl3AH|l;vXI=_$IfkBf_W??OEtpAIUUeIPwH_Iy{*| zJ2KEHGqb3t8$ilx4M>cV>u96LA=h9D9WP%kd<5xH;2 zQMyY|gkEQfb(VOiA{{1z8pCWn=U8tmBI6*|?hYiIgHE%z2+GhYunpjp|KH@I!)CPI z3W2MUtzUzFnN$hM9w|2GjkTZNsLjCL(jIg6 zot=zfU|Azn$90rucydUQx$u1|b`#D3ZB}~vfXBn&nHTss^o42t9g+xR%7+GiA3clP zCtnq&{;od={T?8*Jo`l^EYMe$Sj@LQj*Op=fb45w+KG{0-LXSxx^5+2FNw;Ti#3V_ z&t0|QMg}ILq>h>)WvCdPn*god4A9gxE+YATJyM^!_XvDq*x#WuD|e>NF|doNFYaJZ!dhGPUs2H6$1Pb-@(1Q48y8p*4dG8!AOf zOJt7s8%TOe33AI#rillT6GyNnTX9IiBIkLNb1dhs`egAuT^g&Yzdel~-2vQ*;N z71CjW9pu`%VCk-w{CN=3&01Ch?_SPqDsDH8086Li4KIG)xOavzp%D^C0jK+FY&)cI6NM-Ypi>>~H}c z$B)kfh01e)-`r^=W>);(0F0T#12G0qUK&dX5%+ zBTML!yZ0>eQQ^^0(Zh2zbLd?wPqeh>%j`JdUrJRM zgr1#uB58JRyvd+yr!_Xe;m5}A>pp>)nyfC8(97uhDMP@$dK3BoJCjSYp(XycdlHPA z-V}U_8T_8Ek}$5gSOZfvKH*1bBnC#@X&ZvECfgXl4wQjxm?uKISGB=#K5#RX?=-o< z``XR%I?_u-U;-@nDv1hcr!^tkYN|iQmZylmVnc3tb7*OVHZ!1ps5y@By>mEgFWSP=Ry327gnd zBI4xlETHsanSK5Mb;EBiL)q&y-5Zh017sJZC4Zguxi^vQ@@fU04;5Q47&FtnIrWqF zS~-$FoWy0r_ymgD=(fo;BvL9gIxV$ft_^l7ksoMrCl&oq&B)eNz+mZ50HbfoTX|Q{opjfnHs98{GypVV#h9Hd(c;WdGId2R%j|RM? zeI=cm1G{@=wBE-@{7p4!)djJg9qMzpo&X9qM*-`_FAim7l3~MWOe+xDLYu)=xAX9*$+hS-G!qUe!~QS7o|h{QQL18zvgX@464ehS-1j@M z%g$|t!66Rq+j6fQraHnVio!tXquc$cETU+xhN88?Xs~9Hf0p3uQW0^+qVqo>Xs|yO zFuFk!QRzAa>3?A56CI$vrO90dO2!{`Wcl<=;Vv}gyf4C#U|k547fr#C-NEScg*6p6 zAV?>^=g`XQhO)KWIN^mbVoqzlwZ+ z7Nw~ZkPQvo_bZt-;OrKFCf_xL(L$$52$ndZ1^m~f5}L#s%=2KCfm4&|PD&Ilw>DJO zIiH+g-hF$aDsZ!mMm0HpO1*5+nLzv5X|M+MfQRuS8d!?PTmOyf4DJ>r!2d7}`O4@l zZ)abb?3V|7DV)0DJOkjFPpYA@WAGLhvH%c6svG#7+gd6wa4egM2u>-;q*8hwQu`WB zqn_Z0&!Ussvvat^B9Bv(c4zf!S{#}>Iy$RyQ~Go5P(LK)>(L-n z-8aGu;#ZCUudy$h(bRgIQX=1A?l|%Q+Z--TT)srz&!Fl_HoEJI>Ch`N zSDJ>dQSP7{WqQPnZKZ;J#zpc0+jSn~q+KA?+JAW+K`s^LHpO9WiyUw718qsj+|%~k zyDNI~bNp~DABnu0m>$T=XgIPAS#gcy(UXs)1#hK_O?TNOB& zRi{NCcy{&e%SU!UQ<&C|S>~Qprr;2JscqT4TbGXed7Og%=UnMBQdh{%RIMpSFiFKbCC*w^Q*2eC09QLR)Ni)N_^V=pzCy`sox2t?a&2koW-Mg}d$cEHXm2VGX^R?>W(SKqzg%*8X z6O>Y-dZR-3<>=^yx-SE*JtT3Z$R@L)woQImyYxFEJceTle?W`W4==@yT_$4HU6r}L z<+dLxanOoXjr-}i6TOy!@2F{3%z;wy+ntSHNE zk32xWVJ1okSwLAb7FrNja#f4CPt=M0m3jMYCOCbd(ujyEBlVK|KoA-Rq^SV%5dXUk z5y(QYGwfVbGy=GK6Q#}cbAMcWREIoTXTj#yQOG8??QchdM12xzG#YSKU_O>1)GxFn z`#2g{!j;CUeF-p})W9Hmci5Mcf`jJ5#<_e`x4wPJR%B3^4)WZwQzk$2yd)-iyykho8)jGqdGix~zZm<6>@s=99L@bfLkTLwJ8c}7mBGUbQB98Kb zz00`uAR++Y*0`YYI66o-`~EgkL*%aUmt6tKor-9!L~wNhkPtrX)fO^hS=drxby5l7 z(-Jq>FEkd_&}*nZEmjQE(lrGHv?d<`r=m;{IHoR>xj=;&$_3{netmG*obCsdu#|u7 z(xU=!tQA`qX_W0*20y3%Zb^+VD+9SW{uXu&Ws=(V3%7~MeB6r5uscCr=HzYlY z*8Vi6PJ_+jSMeHm*tv^?*RI?)FIM?$FY0EM_Zie`35}@qu&Gudi`RUZ4fIxpep|Tn zb+whsQ8roM(2UlKa&DapXq3NlZF`XO%Q99gMn0pfY}})pnSihZUGe?W3k83c0 z`-T=nw_9A2n&x`Rz4TqmN;t7ABiZCV!?l)#ZQN)Z)R0zSqfbQwTd)9>g=`DG?~H#> z=)QVj;0oa&`)PKG(xBb6Iv2g%&a}BFc_lbKQ9}8)2QZrAZ|A%l zyk-Tbkjj5y7XS=}cQE!Vc21mtASp97@{9>1i=r8%QVU0EL74tL2U zA(K79t!>)^3ZGZ=4tMA(1+&^+6MP%GU;hOVprHRVb03z#kB~?nbBFV7id%GKK)S}W zn2xkPy}o@yLK~nTh@mp$i>rihBJ6bkJQ&zs?M(IcjI?9wfUV#$WUvs3PPgAB3_U5b zKGxL+z9qIp%tvk=g(FfiLqTzyz)?s^Sq>O6S~j(IgTthll@?!G$*{^ttH$#v;;Nde zPp2S5+;;l*QG)nCu#DbFcv)4mNU9o3&i#a$6(82Y%HXt+Lbs~{eDjIIYxcAFcllBxGtB1&#GICD50hcu%KPWu7i5S&q zfU0q+4@>B$3yJOEyfaXAY6pN}uTd!Zl+a6Q`ihq%##W1$T(5Q_d&W|(( zr61Gr@kH@}-JB}wY;n4-5-*mw_Yq(_ifdz`VeDZ4;j;+ZqXKJLU`t)YB9?XZGTme* z@JyO3*n+L=t^~gaQvq(|Uyvtd0wqfMvty^0;{+s1pqS^5xIWk6f*FTFf~Ux{8&fmd z0o$VK!;*2L9<}#Cf|gxDMAsQ;R@K19|96LuA&(=4G+6gr-;DUKasJ+&xOi~O z*eIZ3lX)~1Qnv@TgcFDydc))9^~pd6RlbdpY6nhXo57+=yaU#BwT(}&l%rK2_Y{$kV)w; zNDSk3jz_aI&X$*C?ECum&dnk|Mg?gwYHKXGBp@dg4eHMf7zZb2Y7P9>4GpUxLQ!Kwbc0nfuOW4R_JZzDb41{Nzf5;C z!5o*9S&J8s+ba1ZNA)yCgt4T(1>T1lZ+yAxlki zW;*Qil?amwh(}Voe|lUEK1w0S?xpWVDeudQX+A)Gt1wsE3yJYDA=~ecb#rwME^aW0 zd=IdRk%j6(O$QKc682&JL>L_xp$(rI*_ZkCp7?gpQC>zt_+0n5&S!w<{dic$fJPXF z!5s5y7P7~1U$dZ9QD?zRUf&O(z)v_f=I5%}l({BtAx?@S48b-o9+v(i?SyTcvh!D1 zGSi5;H8TqzwjYg|z4V`T$RI2*K#Fm0qJU1A#pmis#b9fgahlu7M; zG{{&5tfzdcW~DARMJ{DN2)#uZoLNyfKwz@2up%sqi8b?vBETM5I zSaz*4)Zg6g+xMF|K($O>Umq9y%BZ+5?lH7d_XRC4Xc72U7)hR{$SmX~3YuJj zwaofMi>p(_)ybDkZu^(^}?IYug&z>K#W?m7(|623P5nLR(c7>-{@ZOo8*!9VfGeP>KRkP!gaxK3643ELt^iiIvQ8mlo1X4~U+50t$ z&1T6GeOo;a|pzXmTTPJf#{=DSo5kH-VK`3UQ?06+H-B-E6Gy;X*{L^1~FtOow{ z|Gt=jLvzIo`{ggO_L5_u?>=(Q|L#iS)89y+t6NdlTrU4@Dq`^oS{7r@(<0wWNAxW(OeN*~{T>$Wt zk-lU|#{j#j13f1l#>ICn)!6zMi)?muD9vuu> z7K19O0Lo}~@4Mp_P}?=C3R^`oa=$5VPey5IW1(Jxa7h@ z`FV3YS1#q<`wIpPn43q4+6SdqS&3C3czWAOn$k;fR^f?#iAoU)w#Aq)E=$ zhjpnyVuM1qU`AnGpPX`9cEv|ED0|J7GC`9RqG!1=tcLKd=z?aSY~2zFK)SmnSn6|F zZV*YX{pqYZj56@fG9S}c+ePL1P_JkG{+1q%L&DwM0k6_$iDg``*+Rv)1HsD(8#g{Q zXGO_$T9D9p+eGrTq9t!uATzv5qFu7r%kueoB?dKtu~V{WphmH_e-T?SYHrQAu*9|L zRGp<{5OVC-onqfTiXmg9;P8Kg4_DYGiGzRV69!4Hjj=r9i3=KeZ@ zJh>D%Pf^6d@~ck3V7ef8;t_y@bct*vYay9i=0?_6*%Ni z`l1uaF}_zwBYX)U(Wf{IX2Kr2SNnQeINB_y1+7okcj3wi6`?VC-E!y7Z6+j|?<}h& z#Wa9GXs#x*l&7zY%u6f zwW+o^rXiLuk=QTHT$S5Lo#-pD%5uA}X_)zAFpl)-0(3o9iM~R9uA%}PA`*CG?AOOG zVK9WC+b|3pTph&Iq9(krb-DUrFk}?)5+l*EPD5JEWGCD)45k4pWdaOl@&suF2Hx{1 z6bTrNFnn3~$ly&R#$bHm-2ShZ{d8jni?u#i7I+sQzQkt*rA&!) z;_#a*4gdXh6*=G=HV#2ZG#)K#7A&9_p6mssUj6_KG7YTpCY^-rk?<-n^sHH6lA74(adCu6oHRxjT(@2>$ui8hA0 z>z6BF;&SUg!2pN}-k|Qt?{5TY2g)vBe8#Q8OScXjLKAh zQNJxDj!A8e^T8>B+#u4y{{m&$p4TFjjxIL5_u;%pGgWl)gedR`2)hJaRor=*mw%hJ zShlui%Z>*nod5Pw`(FWK*7Y3H$$C40n?X+6p>+8uDoDGrwJr&XyEjM_O(e-HB~j$b z8McRr(US*^LdUu<{jUvLp+nXYj(P?PztGY0;s-%r}h@4;dGUq zJ28%k9AN!EAMS&jsB*c~XyK7NiukjW6DFy^cQ$c_$sym82g`3hUSoQ+_WSN@l=TT? zb$Pz{7`#G$0ElR9e%1oogw4B8>QG-v%=x!m2#`6LE8<6!8*`F<(18mr=B2ctjeA&q zm=PAYQirn-DO&-w=ho)RgiiysP52RwR}SrQz3p0X&i{ol5t~DVJ@vcnZdKR(Dnld6 z2M~EE7}(I^peNk>fJ($cEcgcQDAVv!)@_~Rh>*=xC-r+yDt!h;oWuCFfwy?4}o5CQrFV<}F zJ6Pd0kF+Tzuu)lp%Q>{RTVHS(-^C%bExyf5pvCIi^wF&kKwYDOQ^L1DW9zQ@UIN&U zAq*j1qF^EtR_4Fl{S&Z^_!VE8zL{GF@}5(;X#A9CNeMC{gwLnM-O)PVPT(0tp&*p%R4|Xf^A@>4bhm%E-P}%R7IMjjjk%RSxwAhlZtRcfNNA|Bj@mI6LJGX1 zm&4=TGieA3y3z?Tt>3pZyulY#v~R|Hm%3j(X!qWzAcOjbYR_qIzs$yDw|dgF-NgQY za?gLiG+u1L@`>uxs?jz8OaxB@b%iGj3-;a#Hh z)yd1{+ajL1LFU%HSyL|&#IbOI(sWH%wTiB|8&Th8R-|d}P|ok+u*4fHZT0n!#|FE~ zc2l0_B_HnI7(B&k*Egwy<4=5+0SO92VxPsJ+o*<7(D-aGqhgSholj^4FfLM!M-Y=R14&>u}SH;jVI;U z58&14HQHh=`R_h?PC>P1sVqx(bv~8%C~_aIQ&&qu08QVKYUK>vKmjU>3TyMG)O~C# z?7kN!eRQh@sz&VM*^DneL-PJ-6AG%7Rk%hhYC2~ys=2NCK3#m^==rX?lr%hf=wAtW zd1%pgwVvzIf$IFsXgf_kH8FkbwQ$m#A>tN>4-F<}j|F)rz|L;T7#gj>E^W4p*4k0B zf0jSP&uk#< zq#*%=6w%euS!<*=$l2L?blXO-a4<_p$gVF-x-)3NjeErUc3QuLU5Qwyefx}+`t2)l zNZK7S4%!g*%nhm24$|B?^|X&~xMpJ91&rM;KJT&<9awOQtsNRO#)*y`i0yuPGefbs zu+RrcaI6h=np_rX%}9D{0^0|Ixu{wm){_Z4S>hsVH{3QV_i?eO_Vae0d{}xWF`7W~ zh!(EzNFY7;U!V=Q|ZyQ-eUF;1E0HP^@V_H?_MI+gSZjx{<|z2gA0k4ks-4F4)qVu#Eq2JE*UUe zNeZv&TJgUmWsYeuq4X27R26LNNtl{&`KRqHn_-5vhZ%WP6dpG-3^qJc(|I`C1O~6w zv&RfCMA7S0Ue?)D#ujg1Ur{t5=z}bWSw^i8nU$tv(1g zoA;}ch?G+{UXNu1)xXQ@t{Gph{mOotw-m6Ciuij1gF+g*;WU~X_i2=-UvV;~J`urI z&bt+|-bFkv1EH;zHf7<_<;RHRhhYp-k#SOk;`KKBjx=o^ATkSAwo|(uIY4N zkNIv)Il0fZ^4p+3A|vxdJK^l_Sj=WJrxh0AP*owHL~ zrdbXjax1;>nQZ2gO)*g`?GVK-w4NfAjc<~-P`z-^ia^xOI`+uy!~!z|Tv)ApP}|(f z{T@5Y!9B0n=1vQ*o(k-%mtm$^bss0k2&NEZp2u#jY$q|P$i}z)nwYqWFAD7^hbE;& z-iojESy_$R#q=u$8zcx#uNDv$tm^ymePUkMGBrP7PsogIfyf z{*|kTu#1Tgs3lm*Zk_~?Oc$YwgubOGU@>d+dx zKUBZB)?Sa=Xa$PfUw>uQYruW3{06`50-&-`mBDrZ%r20I0gnk8a&LYG=_2EnsuGE< zIv3%f6~N^Gu{csl$u~R)L19lWw9WhMDmMRHmz;P@1OOT@A1DIj+{C2(h&?_mrR01N z$BLSO&_{dL6BTvf_i{6PPWnZKxaGgE4`uTnm~Dy*Cg5Lge+156!X%`mf+%S*_bcgtVgB zHG>wrGjHY&9?|{RM~NYbry5~Bd(}QLgT2=K-_HPqJ-tROpu@+|6@0+xaKwz|Y@>&7 zgV7$9@C(+9lZ2=ra1UWGuKIn~Ko_hgtx@atZV{OmfTQ15JJ2NGlKjbyKCeLp0r_1X zXp7d}=0;sOCTOcY6Q_Mt{#Mq=DHB zVL1tin3m6@TblV0X*O`10^l(C0MB*FZ9$H>;g=4Tzl_!2fM>p^f~?cafi59B_`QpZ zWx5Z|zBWSu+d^-_3>WHb19oF~0`gDF%bm6Ck%|^`}#t5u6hzG{x1>o)QO-DrOxgnuQtCU2Du)LIwR2sZo|^! zu_(||rwr~_=TYT!ZK$k+sN)HU)>5hl_hW*7=_RBC^SoD7;{&v1{Ev>nt=_11s~1n* zBzOWXy_?VtuM>uCW)CpL+3D6*uGyTazWe55SHU@u^lZtdkr&tk5TmX^EMnYj#kWM8 z46SH|_G|)d-`U-zp*k|t)xB|wlGJto6;ItiJiX$q$er+d4UdCmxW9kv_W_15a786B z{RegG98}spS|CTE1wTRTfi3vHJ zXAo-IkJ|jA>r3k*fZr5OA`?VceG4&IKHdZMQv&-p+-6peV=%0#)-dYYRLBd*L7k?q z#%QzqQAMLM50lpX9^fU1Sr-;CTA8{@avG6GwWjJ2ZF_xbhV$>Ak_(aPF5Is)rnEbW zHNupn!YprIZ~SfqQw#^VGWh?*Th;|n%TYPP@z zo%qupwL;~!X-Q}d^8Co$g~8He6SIr&yX>-~tn`PnJw%CShNkdnY<2#xiQT`YLp-&| z0mW!9c&Y@esU_1YNDBD{TmDUz3i;McVouV8LoC=j$}&>h zBF@^u@r|eXR6aHa`}uhjp@c)CQ}eB>(FbwW>mEli7;1GGJoU#S;VH6seo>DI93&r3 zUcT3Dh}d`i5d)d4(dNeYaa=aN)%kPd-uq0!J%aR)KRqK~a`Qq3`jcbo$ab*2HfAS= zR2*!}L#iR?t@oKS2NaeN4*V)^V3hECK|!x z+;5-m4{bh8(~a?7%AvZrQ2p)4&h`&o!C4@cef?IfOIod=3+xSoBJv-Zsrcq_WVggR|_Wb#UK>X0!Mf}8si#XkSTl2E_p zpU#1Et0%N!)X26^^1B`LCXKWH=*fBSQNCm!6P~H8azRtyPDfGox7@+4T+% z22QYThF37J4^JO9-Jnh-CWH`3Wu)13d(*^K&y52geaB5UUO2=()$Du&w11FrNnVg|)Y)g8*y;!aAn&c&kZjcZ$++dyYjs z&7Nb(woCTw#rM`**O4W0@#eW~wtnxkB@Z3yEFy`UJChOxL9j z2Jn8^>Jen5e87ZNR@sfK-bD`{Q=e6r-0Xc+eZIVSG?z8ang)!GMbh$ZDEsoSZ`L7E<3$Z*M@@~Q;JeDIQJrsGoKojin zQ zvLA6J=TgN10ps=Id``iE`s4tdkO2kaFExqoY};f98u*{?ITE$iXDr3Vk(Wg*zOB}r zHSaNB);$cnV5NEJC^kg#T=!}D9P?N6PpyNVYt4>2!}Av0vOcI>`z{pOlr1D`GnmV+ zEBKWwEN`kW;G<8AY5VV${{IBDf64?LO7&V>sb!t+x)sfj2fr(td$E1jW*S~vX<~HcPb0+N4b)) zigKv*M`s*2i@M(Pr9_jm$1L+fcPf759b#@D?smK}DK=a4m|vbai@`|BO}Bm$IoVmK zZYMv=ImCFLt4V$HBBVF*ny<1fbJHml%>Ht=_v#kj)~rw?P#JaBJnDFVNWiSkRsMcJ zwZZUX##6AXijvcx<$O!>DXIVOA-|60)RfO7M!yJ2%mO{3D)9fPwYzCID{w^ z+3kiUn-u}QxzCWNa)Jf%W~0rR1(sp7H^>RTrD87C42pQFe>GU_cPG1tHR6=|j-)$a z5hGzAprG_2w}J2d_cgGR;$B;qW0sMyzZ0R<$jSbTFH_35w(Pm@8|TvJ*Z{@6n@A-h zRv^waPymCtcDsCU7TmUA7|=9*0Q0PJsg!HA!D#4*b=+f^!s&9FQaP8($>VGdDHSs0 zAF>|2HhOCY=7Ij#qVf$(2LBA{(xaudSizHuh(HqDvv+Kd!_icUL`UoiHlzE!T8U%akbTNzV-GSl=|7O9r3LT?aw$aDw5mi4IOa_-*+4e^uRW?*SsUN+MEFIvf?T6U5QhPN$nqg0b&Q2pusM%vV#D|;o`*7gK*I&1ne=fIlRpP-ks=$(^{7H`?`Sv5|;a*YPMu#%Sck&tQ zMNAar$@-Ou%;7$?4#Gr_Lqx`UcKqyaio-T{qA(Or-yq9gn4M1$gH-+x^1_csIcC1M zJ^nLqalvOkSVkoqau6KU?}CAA2Op7O;aC35b{Di%d;beAX>fzf!oLW^8w8*IpPv+T ztu-h!Hz>Egf2D7qEEm$4j=nFKF*E0p0qvU9|!FMQU1f(a*@x zi2>eL-7KgAU4+o_Gj|DzI+5d1 z;NeC2=si``?*gnoi`VGW6UQMZ^mdYtcfx2f)NG|7^eyJU1nt_JULaZwE?q*5!#o@W zO7UBr1uYU_V6ck{wzLs6A0~1HkpB_z;%V&a>g`UF_E7|5$0~IGsf;G36DH@2iK2J^ zYfsEcfH~KE%HYXr7w`(}Vxjn~K`e6c4IZz6-LafJ5^*4=Jsb|5g7GwShk8i8UWkJ! zizs(kRylfp$T7@e#R-jOoOH>4j3^8@davW(-5vk#$_P6ENtmS|L`vX|JtKc&Ad~JbG_qS}9otecvKTv;U-4ydh@kk+= zHU5p?r5o4qOP*G3i|zDsM=;|`i`2lJr6R%Jd9+bGltdy>!$^A@`!B!&jQeYti+BWm|? zz63&!@vFQ+0ay?hnh}{d6lTXy!Lbvr;d9*a8{Bte;5%K8C3Hp7@BH-J4&Vqmm;>3x z8Kv#6u?VqfP)ka~CF8)2wGIu6J36Y>37V<*UO-aOS`t%UQ9Eipl5dSq``~)8Drsvz>n(U z(BRG7{c~j_CNm^W7d}M?o*95nYV?a`CkfQu|3q+V=py%wT!YY_ThgeSGbG{9TT~oa zaNX}gm;6@~o*Gs1>ojCKIuNyvR(W?@19D?70T93wk5XOcS(1gqs{@VbTNl3`x_74QCg_Ysu2bLvD`%n!q{R)b2ntmVN1=6 z@uL}U54ML}^} zUWcMh^$yb1cq5Dk?o5O;2@id1sb7pW;*8Gkrl6-Xc@*8544&B-<6)TmK?0PT=rk=) z*pcBzfZNdTx)aUQ^)?5=fo_iUlh`G zZYpTuFwA@Ile?%0tF8F#`4mV^F^-hzAf=X)%0*jR^WBH^)3}cY1afAVbLPt1xD`Rp z@?0ASm%M5#WT#_@yvecLU}1VKGn62o27y#)x>PD0S*RG+afH*=rmf1F*oKe2p4lXF zsZf95!4+7hL;5~wVMzX!3Zwli8S_FHiBu7KU`e8g5mp&?j9C+d!_7Tp5#$6oa_j1S zKt^VfkKs)S2FkmKR!cg_L++?9RN9WAH*g_|86=T_Bss}+j(ZO#TWEJG=H%TkNiVK# z;f&Rhav1&M3lYT`KYR8+i_#atG>=%#EQe#=$yom)SJGm*Mdt~3g|Ad6XH8mHqcMul z+KN9wYpxwRL=9du>*4ej0lR(g8282bx+a19!{OHD1hx|}27@i=q*HO6eSSv=@_Ji` zQ?&NM=>~MW`H?B@10O-SUf_k2zFJUCQe+A3^DburC0(=WI{?!A$OJwm2dURNg2$HIfpi5vefS zN-y_b5i>NC?M#7U#%|46T{ZqGma`C#_x3L?Z9^);3va9BP?Nm_nISjO-4mbIwtNXb zvt3t~T@@LZmH08es%AqHK8-pVr5vne0COA1#^l>@tpH|ey#W+8%avJv`Yi?Lk0ES<8_EpZE>bU^W7gLn;y=I$|dpH_)$)vWM*j{ zRI?C@LSiE&oN9?k{hEhZT*$Z!udwXfC!iJ-jMO=t$vfQE6}+wS35~m-O_p0gxEh35Vy@v8sv$WZW1Vl9 zt{ZfMGrw|!6+V4Z3ldDy=P=b`A1JwX!PMtIodKGzVF-UWaO{L`D^T{^QwS;`*MMPGRVUL#}8=gwfhdiu(C_75T}vEtw%u^`0jw7d@1a2hG0Q}lE?O|unvvN1+oUQq2J`#8f51Zm2bP(H(Gy?{ zUQ^ClQjE}6@Wk%d8MZX{qWFg=C=H--pWpr~ZiBs(ZMjBgq}3i!p~)a@4}Wd@TuPX( z{m$Hvn0&eNKn`8$ao9CPnnMa2V}g-=t_GM#;#VFZ*U_u6M}Zo80$?+guR@-7Il~TO z*TFsT3;J@ndl{Xtom&iKACac$8 zp0Dc?t?6ALRnl)pvM;o@{CKd3JsqLQEp6*}L#i0yNH;&CaJ~BgXt}JyaB>mz#l7K1 z?SXV00qZ|RMl3=zPs;6AP;0~Q9Sj1tEJ(L&V_pF9@q093X28|irIy4m{@?)52!REM zIGtFOun*pnJZcHFxPmk&$sP=iPr<5LZ#ZhqrJ#ZQ8ztKPbTGH7A+l^1w+%fi0gP@2 z<+dVm9D{65D4K&XOwv&%jFyb8?H3y6rjQ;^;8=ltzeZ}kJkIIs{3$1VkB+nNP(=|~ zkHn+szuTK=t8m5JxV**JLUs5VGCEV!*dg}9i9h7}j#j0RvNsg_~ z0wwv03u^8`bKb=7YI#2RW@xbMKx080;#ztIBJ7Q#Q8l1q8IutLc*ka=hfW=X29(_uC`@P#*Z+%yirlf&SOpr<9jBUNu)To zCSGrIUua)<+HP;e0;PwMU+3l%_Tif{KxB0o2cg(qC^cDA(W86=$&-HHk*qoI_l2Om zW;6{WjF&n*6$^IY3Q83QP|)1Xd2#q}DpU-ePO3_yT3&aDsqlJ5xOW~JTd97pt&xeJ zjl%?p8ZMQl$JmG_UA=DmU3DDLQxY-Q%q=b`I7&$OeRInqd5J>cWF?BxKI?y!h&{v( zA@zC-0#eJ0n)nHcqyGncZypb2|Naf1M2YsIq@vZ979lBXSK3Tj1{tJnEW<>Fl&tMZ zS}3M0g<-~$Fhh3jO$%a(v9)Jc*&^J>adv(0-}C$Z`#jI<{^#zm>(#4^nREFZ$MN0{ zDr>l&oPvVu-pz$Yc&s-ncGex|EVuGnWYX@IITqQ?+_@@-AGqz=4a^;gJWo zkrBq|gtWr-CG1Q%3N~>$V`9x}FzH0Vvc%!jtivsM!fC1jOi{0eWF?PMU2e@cseWu- zSm6;7a&@cnS7^t5w!urGmUk40g+qcDx!LQmxwp4cg4SMJlc#hG%FKhy+1fF(&_6a_ zgqmhL|FwE`xwl~`tFZJ*YGz6Wk(_}_N$cRJT;4YZtKi#}Z<3p?Wv8=YGyM)q9@N-a zi?E)RuokhFlt$l{Yp&}1fqKmq>N33xV5kzG&KT~@&Fevf)E=wXQ864HaOKr+7BiryY*Wn14Ig-GjO?32v~muBgBHak4?JvW&cRN6MV>y>X4i;R)BR5x;K0;D5oFMW+@qGr@tAvRtt zlSPOUJkygY+mHM9u0dW)0E|G@CVrR;L#Ml_MRTm*WZaMoya-96n?;>wlG;%h-uxjmy<7lHAHDk3EE_&k{UFe#-KynSd zhQ&1t4Q&m-Vf;l3aXBqsq1T2bo=Kd|bZ4|dr4<0af4uVQ;>{=1+zM@syCG+ym$YX4 zE6;`cK;O+xy2LW@?CKhUbA6BCZ7#!wVUd6-vB0reVY5;{Pfz|{x|uo*hZocBH@^}x`REk|9W-`sB6Ip(ODmki%Nyf-Ve&mS8PS4Jon+x6Ql2--24DDQCAY@ znDLKaglE#YBCYo^t#9-AZahnEdFsr$-?pR22kmx$21K6UR9pA+>xjnX7;cSQ7p>r_ z<9-MLcxy_n;H%)R1ElOdg(+`+?x1ee@dwb-)yLpy*V>Q>)zJ7XjL>-uvITdnyA^@Z zZvLs?M|b$EUuCgXo49GVm_-3w8GeUzT#Z^)2y(oE@}xNxRP@XZpq<^z-OpinvBdST zmlYVT7ab&4sQ7Ebb`a$nT*2GYTtZv0+ZZp7F=c#5(V6LrV;ONG!RuTay4@ZQKv@o6 z2mQyYq|1vbJ$qrDK{zHBXf-MBPV|_h4fxi+bL^Aq>UPkD==;l2tPF*qp2%)!xQ~Q0 z%EeRAl^^aS7rfPS0N0oXS?A>8;q^Ekw$+3|Pq!#?~hk@p#yLpChQ3K)D<~=Ro4W9t*H?;nV$QY zC_0y|EW3}IlNT@e1^F&ZFNQ`7-qzd;DsX^U9lC!+7}hS)*^sn#Hy4jcWh^<&e@=w1`+v>_M};jmYpSJPF|@xI zt>F#+cjOl4vZG<>I|?Zbr>-}=CxWkrqM(BI$5k?$6NvU)q@UhZY6c`)PE?0OP8UG{y@eHW`QCRx{EBWZ3UXQ za$RHC=f`^=Pv0!ebySXkXoGe6fOW0og=W<+nou^L)VW0A>UvSxYG;s!iD%^Oe`>qnJ8_EuizHoExdQ0_GODq6rw<-CRZP3&J>;$*{=UwzA!kia=Tn{5Qn6Rivu7{ zb;fg=)C+Db=k+m-S)c0;;u;o6*D_1-NMWV9;iRylx33wnyGB#s)8h{p0HR%o`hdGQ z4)B(IMm!^?d*`-3q`ricR2E($vB@uvgsQ9dq9}SP)iX zlnk%T&esqE;BchPc*wY?>ttzdAb2*k<%1b*24|>(n?KVC zoQRcSf6l{x==G0T-k26l(#Bm{UiA4>(Ic`O%wombbcdKI!~q})FQH`k9TOhY*1gh0 zZfg0gpb>8Rm3DfAvkRFrQT*JMe@*rYl-mBBzGJa%$5CUYs<1chfx1#5T3z5|*!b=B zF>zwk1OSNlet`o)9_F+YLx9^|OJ`zDy31+Cc>K(=)9he(Ly84%;$gZED-(PAp85g| z>L~OcK^R|as)KTT`qL98ke>JeQZT|0E-_LMzug5-cVg#u9=tD}S$Xk07L(2s<{GP* z7(qi{$6B?zYdD0%*~5Eu0>_e}{%GiB7QUOe`%?)jHmsGX>Z$H#-(MdQCtd@3FA-|< zv$hqrUk_sS6{bAzhjn53tL{4%-du@L_NZtawH1h*gVC5#>N-3t%$ev7W24cdl#FI5B}u_mvJo z$8)Rw9d~_7unElN%AB?z#&z~Y^De77z^XYuEdZN)w+U^zgSMwI7Xp!8D+<7!1^M7_ z558y?Bc8(t!cj};ty$k(f_6XlKDPKZn(nrB&bfY9JV)MQ_!Dc#3E&>Sx(xO$B3f6$ zf#4@O)w!z)MtaYEi>4C;WcMi^Rgfur6y1P!F*jM#nd~k>CeRCmGwAl$>C=hKyR%Is zW#k$Y*&@{Y_hLWIA91~tazl91u(r>0=|V|DHymhV0lo0SFXg#t7ja8u=;j7HS7VzE6CGfu#L`9!h~1Ma5#6~WtZ?7p#>@&?o`?mgiH zypK>#g%}KeLLoeh}+$BiL!oZG^UvwA9lC4^YFGTwprbt@e>jXo@Qv^y7MIx@W%;%ce87)Cl%{))IK0ND>TSe55Ta}OYHE+AQoRF9fkE4W)z-##{ zStGBj*yNJ%REJ;@VBl8u&a48I+Fsr_`7kw=w(W#-9f>RY^!iovet-$7 z5<33Ow1y}o+cMZ)NHpH-eC1g>>KoT?&+5`9^3OL#}XC!X+f$4b26NtAjTCTB3F~Oxjtl6YUc%8>5&jVvjU~Yr? z?+lb#-aN=|ypId%ZK{0(Eb2aP!Y617SjcD>|>0|2aw#cgiL2KZOZ_?0Kna)2QhTir(5%syHOfPxP@Y{A4iAPVE zG_7-Mmk#k0n%8Y5lJkYY^4%zNF|S;W%NLVc4}fo&zbC|0{rxbdJ&k<|_@XAGnqy1xdT!eQGVDHZn4hm;X{TL;N(4Sh zI+z#(YklckV!GDO(1cfY)t%6A8`DIl^C$G8s@<-<_6-_3fsEu_NWCg-(aEu(D6ee{ zSdhtwneGv7&Q_mKltD?N^(4G-PGpjgobtYMv5M;`mBKQ<7v?}&Xrwo^wu~Y4loq9^ zZ8ZJT7$m>^27qe35dnaX0Sx$o6U8MzOI~#Wzq}JK>94#stdp{MNDpo54OH~&JJzIahNMp$qc=| zUd6zn{i!TI1i}un+2__X8@yLoY0R|zKK>Y0%D;8OY4Q=UYGZoGi(e`e%;n$c{ouwd z=2xfQfb;Tn!=>>XdqvP8+}aLiVISdz!DpSjiQrFg3YJs~LfIn(sXDgxxkV0-Vmsaa zu_;-ge^RT^=Au@;A<^qAeN*KiKu2iO4aC`%H)A(sz_L@_{4os1b!Hsu5@75r3*x>^ zZMe*j376JsFAzU4-(L6UCcV3{KzY5AUIoy%?+x(?HA6cAKZZ*<6QAKH$Ofe~T>Y z7cj(MxL6`a+}RB0zXclT$qF2thj__ji$qf&>uRQkwC29D;4xHs=ORnfz)t5u?3)Jk z3N1#GH(n3S%Nzh)DHP$+?9>50j|(p=f$5x>2~7SdXJdp|dA#^FL}|1TOXF9M^si^1EkLBh$#`3Q zgjKP*M&vP!yBfZ2Gx2cczyhKb)D9uz+c1*>c{Q5>0uEH7G0pt0Nug|NjgL@vF9z{K z7dd^XF37deAOb$B{y#BRC6cNpm$3TghK3oWSg4nMa&>eLKQ?CwxbM$4^gF8WUFqxF z4UQ{LQc|0oz!9O6c7e1(hgJtepfora#l4%#ra2G+U zGDmRj8;Cta!$?&LktiNv69&!91o$X3WYo1k zSNr&D%ny8aVdkfcJ2y@t)_@@ckf=?UvR9xs#vU+g(0FgkkRX!+WP%AC!G9(Y??z@^;{tRJb%Pb4y`R?<1)`b@RgGFm+gn=IX1(NIY5xN1w z>@|~FH{M2uOtf!n?-9uwhP5>jGycHQY+zq<>ckruoiva!jcv^>$g|PS)zH1tYV1VA zGju6V;AT)~LPO>3+WrNoG57+{8pZX89iEetRI*9dp*!iZV*0TI!>oojdsw3Yi`!M^ zwY~V|DyAeUUpm~LR+_u*vNhDQFNdUbmgHOd_9Epbyd)Y9I>d|s2Yk*V{gZ#*gTCuQ zq=h)43o5YQ81{*cw2GGsujBL!k08+)(>i+Ba+dElqi!S=)LtxS~|agL6F0uqcFvOSMr8M?r{k zIB~WFNmep}Oa9P>2MVrjpvo18dU}6M!PggIVVJh#YP=PLuL2c2W6Ht}N0*&%Gf;B< zew=c3mXX)J)uAPn#M*uoVt9StfD^I>kIl5rs@+kBxlrq2GI&c$-}n=V(3!#jYVQ$v zE8kfAmN&!!s9Fum(N6Yo)^I63JEC`*G^3;Eg|{K$rxO|}^#ij~ex}3+4)0aJ#9-aT zws*#Y)W!?iJ`KL}d6}Y#8#^b18cbPoPSndi5LX{-(`4ENN5~iY*3(O2Mz0W|;|9tX zm&;~yCviBb*zMlsaNaIZpWy)PyxI-TNI;`$B7UPWE(m8_yG^#b^@e52LKVn5I&~gM zPyK8@MzA|TfAN(hm|m8MN$KJTq2~79|A`>Usod6OKoQpA2D4 zarzngCY4BRUk`*VtaND`f`&Nt%BJ(|?aDiEcCtdlT2B3X(<80Jn9pO|xbN^m#Z1Ak zdDO&rtcjUFSJCMCu>EBM?_(B=ul@@+e?Qh@Ha3llZ94nxtn?0&ddpzyZAh@2FTDe% z)?ZmK$HW4wzFjgn-zWd^7yA5}MZmE-Xw+&Umb7Acl9Csk-s9g|tjeOfkfZgMdfP(G zG`>1j)~hDqia~^2x24wu(h9Opp?`}-{l&wZByLsCwGRk^dK3FsJ%Wr^j^kh4Qu~!j zy{>dabeDGPrVPDt6q;L^|3vYcpdmA%h#|?itI#5DV6^Xhj~Xs2S)frp(;QWA@nfUK zj3%+;lB(7U^$ROx&Uj0x&b;TA^=$5RB6$4?OpkJJ@54sc&h82WZC+j9f4N%7)7ROg z*>uen?MoEDN~4HkpSNzOmReRzLTe1IK)GtewCV5TWe}+< zUGT|;yXz;K?yTe_yr#p$T7_g!C4VAlhQz?}SLg+`IKDodw#n3Pc6im{6P*dZ#*uO^T9mXvUk!of}^=? zi|44~fDhR%ivps*#I=aq!)b^b{#k(Ow+(VS9`6Sc!n$8SUr?~N-bq4H&=74~9V6AavNn)| zM+E=s`{Ed~RB}O7Q|i7?Fm0@BA4WakMpk{QDnk(c0-%!+?8CC*rW-|Ne`^d_*?Wq0 zpcE%3&>oX!l&PK=*2s`LH-)J>nW&)cXc4l72V;o`-*K5~jERKX42L#Pr?42{M#d_z#y$WvNt(xK$TV}((7fwb z48W4@iQZP@1;Vu?`T+pklPrFR{_e0wEf~ny*(;{{&LjvJtCl=@CukNpT)<`s6g0sJ zzNl-L))~HIn&DiyBVAwMK-EbM4Ws3kL&1`hsnT+Xo~iW>HR6qqE@#{y8_T{=5rzX< z8Bwtq+Le2h2}6KybccpGCSY;E7F!j7Z~+KyW|uc)X3s|1OeHdA)XIiKief}Bc{$oV zc$b<0>m!a)tIf;BD0#nX-FzYz>0e4F5}{faWWIg|n~1mi^qug2XKIyF3ND})CiIxE zu00wssx%MSA(>UH9&oo>=K+H5@^-=O;H#ASlc3AJzptqobbR|Im3c;CfV05z%(J1cj61Df zuVK&MQc#@mz5t6|Naoz}^ignXt&j`v{f&EDBgSg*`H{MUqg<$Vz}=c#zAfE_7|_{K zAh&i1mty?x-vn)8KqhezxwiUMGZMc}u6`<(fK)8?kx5i&*c{hl^;}3jU5a_-c#*D+s&ybZ&P& z=vbiZr4(`H7|MqGOFWr%Bc%qjwN@Y$6Oyv>NUZCRhs7|78mi5vDW_>GJo~4GkXT^6 zm;@$G)>)&q`yGUcumu8LQ0yu+fB%==|T;e z?bmB;eRV&Vu9R7G)o$;r6JQHSN!iAnt$_ z7_<;^xf)HMs^NIBN*fy_=a}*FgigiaG7wD>QrAv7+r7p7^Z>W}2$ulq5uCuTUoOz0 z0!}e+9V!Me3Y^`!gDHb14oo&Ruf5*>lhyU3)NOvDz-J0Dfhlr&IedHL_Xv_z)$G0z zAkj*rz2}0@dp11rrRFks!4!YWA2htpzZ=OQXYE=m=3b2z1IUAJ*4SH?GZXGrE+U!; zuXA?_lR;fTIIF(OMpBqEIDy!-1z|ffq7fvtkU(E7x48QKcF?azo1udq#v=c1sP&ZC zQkt6;&gMkOuVd#}7i^~5?}tU0eS;F%Iv#^mKX6q&$Hx zi51J~<-VC$imL*m2DhW@EulxB*!uTTI*e#eS?}TX4TTnc8XL# zk>Is3TU(>L%IG5;dYURj`S4N~umntI1%kmRGqIK3_k{`4d}Zh=uMKoJ+3$ODVP=z| zf(6ot@VY9wx<0sr;8!eSK@|CSI4 zJx+nV-p6p#Jo?R#U?|K4RYG0WOGV0Ko9ZqEQ)))CnF7ErW}bI`7U7+`%f?%CR0+mA2922l3;md5S0nhj!{01IO? z9t2VT>>*u3a`j@tLBQPF<-!cW2VlVAIRGI~9`N0lH(^|(Th+a%TB4{tvaYV`0b$ba z^6eQ78L}sMl%5s@&=OTYf%tBt+-KBXhmvOu88aO#tm8()M{jX~^SMzSlTA?DHUe@5 zx4xjgP8WEN@|$W6pfeo2WuQ0+t+2UZtSW%CV;0nmobQs(E4hduyU2*W3SNIdnw64c zpck?41?mPb&)4Rr?V4C$67LM@;Wd~ufRV7$}4K^WQ2HW5F zkD}eLN{2Gp6O;VHn=lroo;gXf%pI4QoCFV=-1p+m^$qwSwqlnIiy&TjlGoXlQ;S~Z zPwpY-00_%)#4rlswqNc+^xYr~8z}m#QTOl0hHt3jerbs%cvKj}kC+;jpA-U4Krb_D z2WneM9q3MfzmNF@N${|$=pVU^qKw(v09Or-w=C7tw-0LsbB%M3df=7p+PProH=^YE zT;Epy5*Hp?RO>{2hMbbeexnYt^NxaCqP2%e25@eiOxlSsiS^bIgPxu(v6y#Lty{ZVzaMC&Gevb+h>&Gw_AM4)Y`yds)56w)!1> zKJBJcm`;Gq_Ub<;%@ELFaFa`F?8PX;V>uZUCJ_dlqOFk`JK zRZI~4U#hTpo65hsc+HH2ucT^{=K%gPguz4wG19IOC-aBv9w8pA{O;C?;;ooUJc3i4 zy(sEh>TF%s4j@Wl0mjI8si-gJ8>Xc#JAcI;IT2Y8CVDZUxp13GuNbi{m=HYpZs;2# zRVCP5k&`w!SFuz>Z+wT5V`q0`tSjy8s&vj*8zZvXcj>Pn7nFp%70xrixzcXen&er% zi!dpHqxTTLQcprht#2$Of72JVk3;uZ5SpFhary>&)<_E~ZOsD=oJk+Wgm@?QOCT9M zRR~0=S28G07MP>1Ed(q;SP!1D$n$nve zX?;hTJb(&=Gk_Nc@M0z14zk@J!~#430-8LFn42dnG(i_am>{tC073y{dr`=n+k2+1 zga}TtFpXL&KbaeG0e`asvg~Lv_Qfhq~5S7eU1&5iGcwi5ZwCErJUzDWg9QCFS#7dQq`cg_x|Q# zt8L4^AwCr}du0&C?@pJ1xh^M_N9mV`6%Y?hj9(%Vrd@C7c@09A-9b9dxW^Xhg=Ab7 z{P$@i^k%bp%515(S}XRTkqhn4NZRN#t3L)eWYU_|ekb&7BsI2Ce3IS_-d%j!<}0tNwW__@5SRwfQfx4_pKJ^pkOn26pf^a8sD7 z*{kc;{E#TBf|AkU9&%q?Qo1t$>6h4{KBl2i6l)N0@>fDP*+yQR;f`rZ)<%x%tqpRP zlZfc#&X*AB8)uV-tL6Mh)T-a>M05CX7e2-t1V}?_AkyD^t)9T;txHbH{CVZ-R_$de zl-so?R@Zs&qj>r#P0`l2b9x;me<&+#@wr`G6?0C9n&$)PnFTBc1K#3+o8mD5^2M3G zl!k6v(o-lP7Xt}aKh_mS?qegV zg!);awA3I?u(UbmEj_TwDJu}i2?|av!2fJI^L7kYU>;3t3-lAGwDqm_7YM;qlB=_9 zx^v|3yB@L7akOYR%`IDq3dCLYa~Pzx)PIDrUz?(k6B<)cb4$@b!s1N_?CgJC2(r1?*&rc`O7{D&C6E7EK$%nww%SX`(u@P3^7G**7r)c6%_;s5B(j%Y#He8? zUYm^3I@j^)3e?j%4weB%l3E%2zTzYUhy-INXuAj31vKx`UYBtb-h$g;{`I?rmX(?% z>se|Z_LmaSmX!O>1JL2)F`bGIn~ir0IWXPOpCS>d4=7i)U8%dfVfgPkxv&3KPlYOK zur>$JLhts>d(eHXhKarIx@yN$Z>N9i^%<~&#Dg2!S$oNQaTPr1EKW@KR&B5h z0X#PlV<4336-O0E^6EQgPGCEu)Zf6?HO1M}Q1ThIuJRlAE7%`1m_0{u&^c6i@1cRM zCZu?s8$N%f`r>BE7}JPFOH~$QZjdefGQ=)61>8-8+4njcD{H(JP-0eQD2Ss5Z>IG7|7$6*v0<-@O5T8O zR6cKJfaOGf=q(UE*XI60Bbm==l^>rJqGJ z-n}ukwhMc@4pCl@l4L1JEb+KQLOBTsW}Z?sv;?GPX6DDXSFu4(y^&A1{qcqKk4StnZ7|iWmch9Apt(wnOeu&65;8HR!Oi1b;G|nh; z1Q3wdeA1(L6#&knRCWgvwmInL=DN8R>h6a7d*7Xr&tUyJJ{g21Alrf8J)W%$mF=Vh zr9Na}03fi#r|8aV(I*fBDj*YGNG)_EGa6D}X4^EGrE!ujc0@cog2+VLN*?e#wpm?4 zC^d#TZk*jb!FaJ*^cqEs9fLL-@ZyCQF-6ie9k+LfZnF5_P(va2)M`x=C=Utb?8;n* zHGNUtN)9(Ta+g)B`e&QPXx;`<>>$F|puKr8kg>}d zwV7dAzD?2>R~S||WDZEe4V_3&FRV()t1CBbBRe!nZZa?As!L2Mk|S`Bg1=OEt2}%b*3Y z9%WVxkxC6zw09iAHP3F880#{j_Ewqb#L~8)(esBPs?V?+OzOjoYbj**qE0MfPFNYA z95r0qu%94Kf$$9oc~e!tdkrTUe7k)m7SCV`gB4gl>x7XpZuW-n)(bX)QM=|Q9us-u zED4pF4(Og8!yp8BA(5ZMEe^qq44V3-v?r&XXS;3rfi+DBf5F&v;~lNz8@*bM;t+w> z0CA~Kb%1f}CfLk6;4&T2m{tS9ylS-<3}_a1Xdz#W;Qb+mq#D6zlCKSb?1MOK=ta4P zZBD*yo850QRgfOUus%k2gMa@c*M@q0yh^P58hRxKYJBJEsxR)heugC!tW>w#p*Nw8 zUyvev41L*HjYq@>X|;!U=Rd;sfnKoMOJh_~_$>+wc_z>qL(`|$_DP;sN*??@^y8rG zXfxG{>STs4=f`~}Q(z*pT4Sm13D%4JO!iTG5s9Poe)4Th1|B|oU@(_aoBpt|`4bw-|vrg2SGsCuO1ZzsTOr~7&PK^0}_I7w|V-Y$}(L9$j<7_gk(?= ziy+Qpz|4oX5yCKakS+zst(Xr;xIY7UrSCanaItm!7qi?KxA7B$PiiOvqiS@TCP_dL z$H>pQxSkKF(m$nxIk-E_{N@`ReCklG26g~K+!NkmNwg{0tDm`}FE?zq#yA#la*`j3@@ z=XLSQ=K4{an_uBd>}=NsU##4pm$<5ePN!AB@o|)qKr2a$D#7VIs6N5Y>KuuJh)3#i zJY(P6u6U5W3io=v#Ur9z5)_$Wrd4OS8nN9Dfi&IjK!IUz6Eb{AuJ^(kfF*V!syZB? zdm?~nm7|1W~pNedU~4(wIOcI2&7T53X`r{?6KF> zZ*@`e2O#OXJ?io6K0t+wk*x$rgOB*G`{BjUm!k+!6GJ)Z3^skZZJO>H18l7YU-^vh;`DV17i%iX!`(Vo3GwU z*DWgoD?>PS#!rND7W~daALeUB>+h^RXu58k{Yi{y+^T$S1?;9j3~uY#+{zf9W4Vq- zU}9(b)jiND-jH6y)jr(l$1e^5R6FK9i*cCl@~;it)%w`KW+=%xXh@_~`^KqZ9YDD~ zqp7`0h2gBhJAA?twCt@=%oJ$xkLsJGSvid zOC`0O)~+sF&-!>9{TSdz3uQA7^^_UTcL(z;H;r|eWE$J;)D-+MV}M5)uj>!mYxT@J zLWqw=9LRE7PnT?4xXEu#9@~t}|7#m-E!9dEHID+E>iJ+n$&?AfBMWfx2s^0#pKHA6 z7!m>2%tXci(?jDXv%qcj^2WDdc)_&%KclTA@|v5ZmbKcJF!p=@J2n9}I#_o1u|q3P zy*0VMf^yQ)_=t8Bph{l5C=;Au$IJw1I?Ri(DH%rp$(NJjBRPHR(>nLf^;t;ln+H$s zB;m#yBYoU|iV`MbHxG1y_h8w;=zbFDWzsSVNZW|^KHH3shGjreL^ep9I>kW zSE?!;qbLyk&9UB@jeG}#3!;HX#gY1U=tuO5D)CIZQg;k$eQa`C>Pfb%~1j}>>i#g!sRSH5DcbI&-uQb z@B{w=5gLx2PR*?^fA>buC3>B?j;WH*k$ZLIEzjrz05ynPW=uLar^UkOTBn+j)OwEw zQ`TIO$W}(BP2v+2-=iwgoXh#7wm$E|ehij$!P->OX_g@kcH59bRVhadEBV(#!kU#S zd7Sh-P()xY@o~dVm1yy(9QYv}++i8yPOD5oz250RN(8YAM4-KA-wxD)(cxOQ>7UzU z5*2q>s|;Hn0xMiAGY&m0bd z-u4w)Ts@rH0AJY>G^dOTMOD|<+^T#Pge^I2H+H2o@!6iJ&=6qP?cU!DQ4A~1tNnKK zs8J!DlecOQ!jC9mfKZ#hwKCSI{VK z0Dxq^4fK9r#x!guO2|rP_T_PEG4B`pKyr6&eGK5%D_wfl3d&xwv^$PSuFW_b?9EYq zlBqvSf{NXbHB( z0S;GYrDC3V^18sl>Wz`RKN9S&Uzm=pPQ_L==*`vb`JF4^z&P=1#UoVEyq~xZV&4Wc zn3c`S6w0ofE9C*hXrN zeR(DvJHGGwJgY}T0$@oyjSavNv9AHElbXtJk!Pvw13tNQ%b+^NZp{rGU_^kru%#W!FO+e7TO`63KV z`R9JxUZ-M+Zp=QkVI~|Jd2C$cxCsQz3t4JMp$HG5eJ9unej`J5x`Ix69oT!;*^6Y) zxIuEk6Tt2wfbn`c75KKIsBC5H+tzPNx7bk)s|13Y$YYM&xO)r+jBQcY=CNiJ?L78v z^(>C?tz+Ptz1w)((9O8@epvIjKlaPPqSXYHvXoBbh9nvTrsp0zloerITz7&S7mdUm z)^$Le%siNN3=wUV4+qqzMCf{6A5sjty6wM4wkU^u?>0*{uo8z*G8iQgG1u^)oT&O3 zmTzX%+oW2m=c^+cXp8bZb5Vfe53Bad;lwm&L9^a`Yu*-tQ!f@OoiTp9SI!jSUMcl zoJwg|7#K%6WT;CWP;En-C+KC&A%!pO5s=o6t=d}@J^WlTsB0{po6?!ItNC3?BH6h{Dl1U+OAWRBd9<+O6#BOdv9 zzx#@M1^tH+;Mze)sFBNESou9Z_HnHKX_>)ZtF*`yp9KbD!8y57=j9&S75Xxli#k)G z4;<$vB(*QS-Kj`aq;$SSc!cVXED8j<05B2PMLp(-TYz_p{4dMht2(A0%{j|RpYjH^ z3`e`Jy-!i?k$$8$!3SOVs!ZsXWU!apEG8iR4G?bqOiqJl2K(@Yk!Zf@bst9)h55t~ z8<)DsQPL?Q7!wcn#PI7~#xDWH`;y0Z8+L)CK~7a=`&1pGo3u6SO}_VU4iwUcY!ZRt zewCiK3X;*A!MlORZVj!Zvjua?Y6NZ4uI=xl!j5yg^X25;c_!v|f zG)AR#3nq05yg7RweAI&!2oA=t+xEwhPAhDo{)n8kV^Hg=g%sE6dqKp$oic~M%jDWL z*HX>g{ej|iI^JI6mTuF$>#9=uLU>My78QTX>QbB=D-6d^LF*L0jL%!=!)f~p2kV0v z?Dnekbvk#;!)jR*X@j?^uW#ZO*_#itl`U=9Q6TrQ}5$6}8psT$z%Oao-c z=}*J%vtMK-qy(Tht;cl2Hk9qI1BNjZHS3|~@PeG*WYV`}8l>#KMh5i{`1~?|wLDTwy#ou*t z3TgNh^UJ^#^LI+xP%b9zzN35X>E8sF`F#w%8z8v>5*Dz0FC23)h}_1hB%=$Rx9bnR zxY{fzv(>o{!k6F_^MOM^EexhX5K8|E5IWtl{Imh0*5K5UX)CrK1S;=tQN?rDyAPlj z?Xk@28wBmbvnZ?AVuUf2l^I6!mvQ6{04bmhrP}3U+t?XzmL_N2PsHh)fVzv<_OVR+ z$m*UO+`8S0-@hnvmeOCSqVDB&(6djskekV?BFZ+vX|HjVhw7=^;@t-g!beXTn1)Rv zQ_f&`Ul&b4O8~645y5$O_w8F)bUl`W(-oN#Q2q)S$X`g{M#vRfG-Cn-{ zW%kkVN}X8-@*t0tf5aSZl`!}ObvW}H2m#mT%G?lE^zfdr3l7u!Lev|#Wy zQreKMxtJ)sgDP}f{pq5SonY;h(S;deNP=g=%xXUe<(Df)qyS=QZGoz=>LoDl!dwrZM4`TsV%LgEir8d#CKrwiI`Ef{-NsTD}T&Tzhce2ddTYbZu9CGweo&eMqYQ$4BaQ4J;hB4(t(u7vW?8+EU4ERUAZ7 z2-)h4z+YlpBV4}S{uu38kedlF#fIc|8TG^x$iM3_Ol$r1Lr;v{hA7>L1x!#D}YA>im4tWB#9IKo41g}E2R5fxoyD1#d0a3X*O-3hBpfyYlv9z2go zQWoFcI1Q($M!?Y&$qm_{A5_ZEM{8Sr|NM-d!a<+U8?^QcBi-nlWZDji7z6HoYa6&_=Dd>Df?&k8JWYj+eV^cXIH>n?!F;D>J0ic|3=QLcxeZ)z zn1GS1xd6_up@ydCGs*oWSnx8;1|Q#6eUVnWwt6)96IRrh;A~028oX|*t`FPxG)f$T z%PJWnl;$SQlH=Ryu^Ljg90u?3S`8KUkQitMM(%;6*2VV|m<~Vc4sV(~Ygv9`*#XR0 zwKF!ARP>PtN9|lNw4GT%qSj>J2|3ik3J@5O){7&C7A~Gd;yV#D7>=TR3ht@sg|EdK zQqzMtk(J|icDl-*4 z4<}i>!y7e$==_a>-9@N#$7~Lk+-NqRR0!BKuR`em#^{9L;L4Y>>My<@o8OPAA)G6j zODkrh;FP78F=(Rx!c}9|Y_u+eFHk9qG`yimMJWM(jqzu|!>X)zFVkI>I-#r(NU`Kd zn`Rq+9*+{Hk{TBidL5^b{qVRdaf8y75-Wt@Eurc=h;FD2sQ6oyKSc_-Kc;>jX;d?q zRyLD1M+M-gvm5Dst@Qjcf7_k;)`g>T2vShpl9pKrrj7x z1VVLOF#~!TNAQfQgQ;wRUDC8>voLW$S~8xvh~N~?CEb=8wi-`TB)9u45iT^`YA56> zY($khd8S;6|1gzmdkO@t%VWf(b_3iYwM1{DOTly^v=psTki~h_T^LyeQFG#eXs(zx zUn|uUUqIM&(*F=zq~2Z9EB4}sOl==p`LlmR^RunjyaQJ><}*sl!QTZ^wGU_DwKT(s zWN>nEA}bTh>JjHwF>)!~(_wec-2w$XM z@Cw0u_o_+m{+P@IrI_~x7i#Yo6T|t(E^>dy6w?;DixycH)#>13p|^Z5UV*R@vdhiB z^L*>o*qp6(f^+?hSrKPD}VQf#euJ?uEiK1SwQA zo;X*;HRU6eMJ8o%!w-R+rzk8`N^t!Sk|81^6Wp|t8g~eVy@l?yIYh<1%W23w4lw8Q zLg&+ro?ZI}i{D?LN2bBX>j4}z_H+EqP@)xZmx4t*G(6Z2D5`=a@&yF?HAJa4|H!9$ zl!BFQTmX`oI`sRbV{T>FrCe+~(i0B-73V1ub>=4~y6>NdZy5Bempfk^`z~=d^pf-{ zIY8Lgi?$q?bB6jg5xghB+GN2yL9`l^V@+6NC#n~Dln_!v3-X$}HIy_I^bY6)<-r%f zY_Lv27zY8H!fW5mDbL8XC$F{GM5^Re(UzH(o9@uX$jl1>)tW;$!A{-tfPIMLdjo_! zQZ(8blWM+fB$asFum}^cG4r7b4N6GdL6c^*tsfwpd4SBe9V2D`(1<+u?mLk?<8o*i zz+!tD8^dXJuuB`Ptxy1O1N}6GrAgnRjy94RTI7&{I;KF3zd@Z~MZ+Q#LBYPG4l>tG zLW8KY9Jtq2;s zJEqfZGd95QG_xvemevHD2Idl-A(bRxs82{G4*vM~G*7fE(WcBI1ZpVm1#k!hU`q^} zGGnJoIDDj3;c(fz3A(WJ$kn`#`Bt_4ECy~iqXky9a+Ty#*~psExo-#Mdd<+Q?+%g> zK&n+`Q|sXUxUcM^m9rLo$dQf?sF(%wjPN6@U2AE24!4A;fWrflXww}F`PUgH-4Lp6 zZlqXe3LU#W3i z@i5G?*aOJraxfOC7Our4vKLDrf;Lzm4$kQS564Pi-Vzld8nj{}f$xQ!gdQG<(2ag@ z1mT+I6y!31vg?hLZrCG|z0igczqooUdDhhKuC=YYlpEkQ+##)=V-b``Tk}kCw5BB& z>IrWDkzNHa`=~2!ki+=0qc{_(5HUDlAW8JO8~QQA=mi3tYXmxW2zvy~)WWdR7>KZ~ zMrnIxKkN#dLv<{w*lRyn3YyxVD3iU62N|Adb|UR2YRoM>fp*Va@{ixadp%NiS`?c6 zW$9IFg%);KYTIk1Hvv7SQ?#@q(Q=9405uq%Fi3!$dyz~^2n~k|-@6PiNhGerf}{iq zWt`^fFv_r&NxuWH&f$-!&uH_-*pe}f0`n##z5uBcZI{0V_WuCS)K^j~;7t?14EHo+ z<<<|Ev#EfWw5tDUjqeCHG=T%} z&F&LDcZGb+2XFl5OSgH35{qsy#=BSuo0h(xP}&I0ZYEFVa+el^zFtkH4o?$PN!h5E zsn;h!t^muDVvZXQ7R%$$KMOH@UATYnRu>;NG7+H2y@6oOI^pUv1xz?DgBZw>-#(>d ztKAmIA~J(}4-x^`d|gQmlvF_Pz7JiOjL1x^xPb~a!J!)IZkwBltkCdCAR7qMz0vvs z7rEQt!skA%0CS`iQaN0)-Hi^)4&4yO;K@FE^Ob)U_z?vRhtlTQ#r zc3Q=u_z%%&Q^?DfXTnh#>DK-I*OLgv@l5tEsNMdYF7dSt2?cm&f)mJR1|x?wvF?!; z!pn*+B_1T*X){l!%CPJ<(0(NB3_I|~kF!d4W@);Tq1#>3HMNm&=@^%Ii4}=PIqes1 za5I{$2bB%C3qIAKcd^g$YoX*^YNG_mI(OMg~(NeK2zMi+P2K@eE4=LACJ2}%y*!HkDLo{XOHLhUu1 zb)uH3(R(-Q0%c&bQE&3QS$wM$W{v_$u0f~`ikKu7!XO*yv2Vyc?a(s(-%mkokDt7F zWUxD+XlmCPR;0zLtt9`tje6aIHE^)P%`pSu#yUoN5$q-0P4wVTj3Zja!OK1hnXI6Y$i}vq`dXK1kXO#)1cA@P`)3LQ7}QGsKM76K%nMgxT5#hHd63^lX`%yiAf}Cy2&#ebYH5?f@}vcSVh(6xUAP{ z0<>K_=nWmF$^R?DQw-)5x;89FS^#0erYZwW(H;Y|U1m=n zLiNi5i~}1g%(CR-kA3OAu@R&#lO} zyRG*5eQc3!-BCX3*?8MPp=x5!%WaI=2hX?TXFwe&9SDEfQ|dlNX={>s#BDl zjTvN4#^&yTbP5BjDrDYY8x>(@G#H#*vby*X<`ZxU^Zc*`!mr<3gwpSvV&Kd_iiG0; zUzARHUD2n70%b#F8)1ZjbVrGs%A<~A1|S?zw?IFB;E$(s$2UO+BO>qd6ZxLQ- zSCcmqC9K6+q5brZW$&B63F;oj1YXGgIdR&8_dU?-?q}w8cot(wpKO^ezZcqDljL2o z!yf^Se>Ze$n#)*oK#3f5-3zJcxo2JP{B;7Og+1V<^Z}7gti{NX?`txs4^#e2=qd%- z@nWN~ZJ&i0uhh`(Vy|Ojyt8Hav*Piw@WPKdUqHiI-*-G|XG^!O%{PR854~aa=X(xr z{8g_KGCKa@(s<%namvJjVm+1d3Q%bR>jk&(15m>9)VXF(DuHk{JxM9z|7!0#+nP+b zZa`)j1jPYSVMLFEfMOJ+Clo0nNC`s;y@(JQKwvPTH-{JF8I&d@5c)_>gdmY3{Z)=2 zkOUAz1O${4NH9hT#SjDM&iN7N)A{s#$@N^h_FeXR)?RDx*{zjEu|`el#Q5=xpa*~E z)RK4(M-+heN*FVMyH~eR8sIah2N4emB&{Fva9btF98MW)u?#r?6o{pGVi zIE4w;AEa0#bd}?F=DYQhR}E9lhq0aUp&g;2w^msxf^xKO;qK<7^S*UzKUkhI;NAQ> zb-O-T%%9VotVd2V!NL1hJx%}W2q`_h4wSQT8V&5N5=#lxB>K^B=NRSFh@Z;n!Lfav zn3PGjbE%@rT*6Xzp!SQa1E;E9Gps=fwOB0_IxV(!L~P#ov=ABg6`AC2YaID z`%SNa&{?B|V5a!q?Nj23Zq8_~n7+D^R!MqG6%b%+N&Y-V1Jb&dQU^c`etBG};~jHx zvqd>@PQyNH)qQBCjbQ$d7dBSh%!7>a_NL&88dYHWEK7SIGbGZp&KXT!5&C6hfvRp< zDc`$Ef!yBxdr~hm_m$bsdp;qexp&)FW`08iT7HbTwg!XaFU#xU)5lixQ-NZ!?@T58 zwOa1?Kvp&_bq((uB^Ws%Z~EmgfEjsB^l9U)IK*a|I&?Ih-#aSOn;ir1?9MgcUE6<~ z%f9-MqY}LoJ=(ci(XAFa8uzkY?!5L#AIYxoy`x`81zlfW%BENBG(8E87GCBE zkp;_|YphEVpTMoSZ4em^zh?CQj{y$mA?O;_l>kmU`c(3#7Ww)E`cz@y~f#tXj*PZMLB4uvO-k zC)RZe`%+*IMFIK_iT*#>Q!=)p8i`Rit{f+kHbvJeY+eU?k?rjIa|rP(8|

rqwL}-))m6fxij!j&|I*yMn66C*f8g|4_tDKW477*A z1X!|7uw?wX%dLpY; z<3nQW%-jUI$*AVwSsY9mf!D&x4LjVMy1H<|n)Qb5_(QN28S|d>09Ioy02?pm>@2&m zqw|IniLg_O{B*beVi9&Hpea z$vT4W4?%6I{wsPKPZ0)4t$x>Xe1!R*^Rn7KU+8`&L|4+`N<_k2o(OAp%xTs|^`_4u zZB8G*M8S2cEmhwB|B;7$v!t|O$JD(XK1{7I*p0hkt2HqyNE1!|u4-<3^H;+hPvXgJ zOQt75{&{84p5e99g-Mq(Ui)W8^)4MUUJCTDM)!hPS&m!RrxCU-%oMZ@+yrH!bU`sX zD4kew{ccef9<$;4@zG&URZip;_QN{KRfCAnUF+nr+Fgx-HP?JJKzZqE!jMaCnU5pW zuwCwF%44Uz`)SpCe#fZ8wdyI+ z*c)OJtr9vQFW%2`hc3+qa|2bgigl`(<^{dKCY3UgIXq&0#cur_@-yQ>kRaOC{a$|^ z3mx4m&?2`;7N6Mm(vP&=@=?Vgqz~Cf2~QP1ZCY5rKOODPE&H?{Z#vU6IBOihNWNBZ z?-jP(wv)zVpQFe7?r>bd@n3TSm@c&@X>nMy^1DU5oBE^S{qArFtjevlHZXpSOFz;F zRmj&G4Z`9A(KLevryqi`1E@8B?9p2*Gp0p{Z^=l_<|R(J(!}G~5{cVv&x>xj-wgRl zH~|wBkPZ4xncFZJpQ@K$G~{G7x5?P(mRs-z_Tmw_30ewDvod8P5C{m2p3s<6s6Gm` zu#npmHJ*x-`p-+yJ2g!2zv1lb^U}Z?^$FVCfC; z{@;RU$ha-MOnDGbcZAn?L;q$zeGc@6R6A+SGdC;7#^($@1Z0OcCy&$s01@f{H=*q$ z#5T>_={)+Nhf6?_$(Rsc@6Nn)$23bWo9b6MP5Nh zryt?n4n?$4-Hg^!HGO|!B4ZOGn%7ON?ewC<2$R~o$U?)3R#ia-9(F*{s`e!rs^uDT zNlYR&ahX_RoIL#GjCZ-S4g>3SoKB2b0{I~U#rWoqxn;8R(7jgkTvMO9EbT0n+EyY^ zL|?fiyQFV`?5pq9?;Pt;Wl8E>wz7w;sVTm%UlLC)@Fyk>r-TSnv9lT$_CqaQKA{?d zv6QUp!_uHW-3lF;BtKuw%GU1twrGM)%$1997;1v+#{dcR17KC}?C-^&in*HOk8P-5 zJf~!*eA83))^YaHI(wf%&PU$fm}$vz%lId?94}C>OyUrCLMI;dq-#L|(aPwk8KJ;W`@;7Lip>k0 zHUF@su95Nal+Oxx&O)vu7ag>FH@7L_XvrD(!a9oa70}~94*7DntUB{!WD4GJCjY#w zLS{%zz5-qyI+BdH2mv1rfyuP4fXHIfP8IPzouYzi*E6`bmz{E7x6BAR9qBP|g**KFS539nG5lyL#Rd0{`K^TM}c^zi|9<0&9P**~%U%;s3Y zIi>qs;ZFiC0nX_3t&M#-(WQO|1Nzl@J=Ja7)2Wy!4-zdDw)9XhEpS0o$$I5oNb+Lk zr!7P(i$IOjy8kB3X~? zSwlksrhHaUV`^Y74(Y0{?DE+bnhn%AtaRvQTv@5qgtBXiQWW28%_ukU7p5@b;cl1x zw?_vXGTUVEcbd-rF`VZ8b2q%v;EXjreVYLKPX4J|)0G`Oam|GC`uZv2+Yw0@nQIFA zD>KwDlbOE~ceQwvPnw*XcQ~Pq^iZGp^`?%rPN|Qgmppf#y2WT*YTL5m?DX>P9N?&w z2qwA@CYRr@B*(v$(fr;E?^yEESel<6T);!C@P^BMCELsCQY(EW>sk^)pKW?)43+v$ zN45ryo3#!1CQL0LzA5C;zHXwSbj4kRalZ+}vZ@m3L_hRf{twB9M(k$PN zc@2e_@(720nh`$v^d%kH&CP-wzZnDSDz|nRcHPz->6z#_7@>IwsyO9w!4Bl~_1?f)dN{QMJT zG_BBw1ai}CpiWEd!%x7J Date: Tue, 30 Jan 2024 01:46:31 -0500 Subject: [PATCH 14/81] Rename standards/core/noise-sessions/N11M.png to standards/core/noise-sessions/images/N11M.png --- standards/core/noise-sessions/{ => images}/N11M.png | Bin 1 file changed, 0 insertions(+), 0 deletions(-) rename standards/core/noise-sessions/{ => images}/N11M.png (100%) diff --git a/standards/core/noise-sessions/N11M.png b/standards/core/noise-sessions/images/N11M.png similarity index 100% rename from standards/core/noise-sessions/N11M.png rename to standards/core/noise-sessions/images/N11M.png From 3ca5912878418a73dd7fcd1c2cffb92249d0070c Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Tue, 30 Jan 2024 01:46:58 -0500 Subject: [PATCH 15/81] Rename standards/core/noise-sessions/NM.png to standards/core/noise-sessions/images/NM.png --- standards/core/noise-sessions/{ => images}/NM.png | Bin 1 file changed, 0 insertions(+), 0 deletions(-) rename standards/core/noise-sessions/{ => images}/NM.png (100%) diff --git a/standards/core/noise-sessions/NM.png b/standards/core/noise-sessions/images/NM.png similarity index 100% rename from standards/core/noise-sessions/NM.png rename to standards/core/noise-sessions/images/NM.png From 7aa2ed0a3dbe31afe6edf2952f397b6427b1fcf7 Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Tue, 30 Jan 2024 12:25:36 -0500 Subject: [PATCH 16/81] Create device-pairing.md --- standards/core/device-pairing.md | 358 +++++++++++++++++++++++++++++++ 1 file changed, 358 insertions(+) create mode 100644 standards/core/device-pairing.md diff --git a/standards/core/device-pairing.md b/standards/core/device-pairing.md new file mode 100644 index 0000000..8a215ec --- /dev/null +++ b/standards/core/device-pairing.md @@ -0,0 +1,358 @@ +--- +title: WAKU2-DEVICE-PAIRING +name: Device pairing and secure transfers with Noise +category: Standards Track +tags: waku/core-protocol +editor: Giuseppe +contributors: +--- + +## Abstract + +In this document we describe a compound protocol +for enabling two devices to mutually authenticate +and securely exchange (arbitrary) information over the Waku network. + +## Background / Rationale / Motivation + +In order to implement multi-device communications using one of the Noise session management mechanisms proposed in [37/WAKU2-NOISE-SESSIONS](https://rfc.vac.dev/spec/37/), +we require a protocol to securely exchange (cryptographic) information between 2 or more devices possessed by a user. + +Since, in this scenario, the devices would be close to each other, +authentication can be initialized by exchanging a QR code out-of-band +and then securely completed over the Waku network. + +The protocol we propose consists of two main subprotocols or *phases*: + +- [Device Pairing](#Device-Pairing): two phisically close devices initialize the *pairing* by exchanging a QR code out-of-band. The devices then exchange and authenticate their respective long-term device ID static key by exchanging handshake messages over the Waku network; +- [Secure Transfer](#Secure-Transfer): the devices securely exchange information in encrypted form using key material obtained during a successful pairing phase. The communication will happen over the Waku network, hence the devices do not need to be phisically close in this phase. + +## Theory / Semantics + +### Device Pairing + +In the pairing phase, device `B` requests to be paired to a device `A`. +Once the two devices are paired, the devices will be mutually authenticated +and will share a Noise session within which they can securely exchange information. + +The request is made by exposing a QR code that, by default, has to be scanned by device `A`. +If device `A` doesn't have a camera while device `B` does, +[it is possible](#Rationale) to execute a slightly different pairing (with same security guarantees), +where `A` is exposing a QR code instead. + +This protocol is designed in order to achieve two main security objectives: + +- resistance to Man-in-the-Middle attacks; +- provide network anonymity on devices' static keys, i.e. only paired devices will learn each other static key. + +#### Employed Cryptographic Primitives + +- `H`: the underlying cryptographically-secure hash function, e.g. SHA-256; +- `HKDF`: the key derivation function (based on `H`); +- `Curve25519`: the underlying elliptic curve for Diffie-Hellman (DH) operations. + +#### The `WakuPairing` Noise Handshake + +The devices execute a custom handshake derived from `XX`, +where they mutually exchange and authenticate their respective device static key +by exchanging messages over the content topic with the following [format](https://rfc.vac.dev/spec/23/#content-topic-format) + +``` +contentTopic = /{application-name}/{application-version}/wakunoise/1/sessions_shard-{shard-id}/proto +``` + +The handshake, detailed in next section, can be summarized as: + +``` +WakuPairing: +a. <- eB {H(sB||r), contentTopicParams, messageNametag} + ... +b. -> eA, eAeB {H(sA||s)} [authcode] +c. <- sB, eAsB {r} +d. -> sA, sAeB, sAsB {s} + +{}: payload, []: user interaction +``` + +#### Protocol Flow + +1. The device `B` exposes through a QR code a [base64 (url safe)](https://datatracker.ietf.org/doc/html/rfc4648#section-5) serialization of: + - An ephemeral public key `eB`; + - The content topic parameters `contentTopicParams = {application-name}, {application-version}, {shard-id}`. + - A (randomly generated) 16-bytes long `messageNametag`. + - A commitment `H(sB||r)` for its static key `sB` where `r` is a random fixed-lenght value. + +2. The device `A`: + - scans the QR code; + - obtains `eB`, `contentTopicParams`, `messageNametag`, `Hash(sB||r)`; + - checks if `{application-name}` and `{application-version}` from `contentTopicParams` match the local application name and version: if not, aborts the pairing. Sets `contentTopic = /{application-name}/{application-version}/wakunoise/1/sessions_shard-{shard-id}/proto`; + - initializes the Noise handshake by passing `contentTopicParams`, `messageNametag` and `Hash(sB||r)` to the handshake prologue; + - executes the pre-handshake message, i.e. processes the key `eB`; + - executes the first handshake message over `contentTopic`, i.e. + - processes and sends a Waku message containing an ephemeral key `eA`; + - performs `DH(eA,eB)` (which computes a symmetric encryption key); + - attaches as payload to the handshake message the (encrypted) commitment `H(sA||s)` for `A`'s static key `sA`, where `s` is a random fixed-length value; + - an 8-digits authorization code `authcode` obtained as `HKDF(h) mod 10^8` is displayed on the device, where `h` is the [handshake hash value](https://noiseprotocol.org/noise.html#overview-of-handshake-state-machine) obtained once the first handshake message is processed. + +3. The device `B`: + - sets `contentTopic = /{application-name}/{application-version}/wakunoise/1/sessions_shard-{shard-id}/proto`; + - listens to messages sent to `contentTopic` and locally filters only those with [Waku payload](https://rfc.vac.dev/spec/35/#abnf) starting with `messageNametag`. If any, continues. + - initializes the Noise handshake by passing `contentTopicParams`, `messageNametag` and `Hash(sB||r)` to the handshake prologue; + - executes the pre-handshake message, i.e. processes its ephemeral key `eB`; + - executes the first handshake message, i.e. + - obtains from the received message a public key `eA`. If `eA` is not a valid public key, the protocol is aborted. + - performs `DH(eA,eB)` (which computes a symmetric encryption key); + - decrypts the commitment `H(sA||s)` for `A`'s static key `sA`. + - an 8 decimal digits authorization code `authcode` obtained as `HKDF(h) mod 10^8` is displayed on the device, where `h`is the [handshake hash value](https://noiseprotocol.org/noise.html#overview-of-handshake-state-machine) obtained once the first handshake message is processed. + +4. Device `A` and `B` wait for the user to confirm with an interaction (button press) +that the authorization code displayed on both devices are the same. +If not, the protocol is aborted. + +5. The device `B`: + - executes the second handshake message, i.e. + - processes and sends his (encrypted) device static key `sB` over `contentTopic`; + - performs `DH(eA,sB)` (which updates the symmetric encryption key); + - attaches as payload the (encrypted) commitment randomness `r` used to compute `H(sB||r)`. + +6. The device `A`: + - listens to messages sent to `contentTopic` and locally filters only those with Waku payload starting with `messageNametag`. If any, continues. + - decrypts the received message and obtains the public key `sB`. If `sB` is not a valid public key, the protocol is aborted. + - performs `DH(eA,sB)` (which updates a symmetric encryption key); + - decrypts the payload to obtain the randomness `r`. + - computes `H(sB||r)` and checks if this value corresponds to the commitment obtained in step 2. If not, the protocol is aborted. + - executes the third handshake message, i.e. + - processes and sends his (encrypted) device static key `sA` over `contentTopic`; + - performs `DH(sA,eB)` (which updates the symmetric encryption key); + - performs `DH(sA,sB)` (which updates the symmetric encryption key); + - attaches as payload the (encrypted) commitment randomness `s` used to compute `H(sA||s)`. + - calls [Split()](http://www.noiseprotocol.org/noise.html#the-symmetricstate-object) and obtains two cipher states to encrypt inbound and outbound messages. + +7. The device `B`: + + - listens to messages sent to `contentTopic` and locally filters only those with Waku payload starting with `messageNametag`. If any, continues. + - obtains from decrypting the received message a public key `sA`. If `sA` is not a valid public key, the protocol is aborted. + - performs `DH(sA,eB)` (which updates a symmetric encryption key); + - performs `DH(sA,sB)` (which updates a symmetric encryption key); + - decrypts the payload to obtain the randomness `s`. + - Computes `H(sA||s)` and checks if this value corresponds to the commitment obtained in step 3. If not, the protocol is aborted. + - Calls [Split()](http://www.noiseprotocol.org/noise.html#the-symmetricstate-object) and obtains two cipher states to encrypt inbound and outbound messages. + +#### The `WakuPairing` for Devices without a Camera + +In the above pairing handshake, the QR is by default exposed by device `B` and not by `A` +because in most use-cases we foresee, the secure transfer phase would consist in +exchanging a single message (e.g., Noise sessions, cryptographic keys, signatures, etc.) from device `A` to `B`. + +However, since the user(s) confirm(s) at the end of message `b.` that the authorization code is the same on both devices, +the role of the handhsake initiator and responder can be safely swapped in message `a.` and `b.`. + +Indeed, if the pairing phase successfully completes on both devices, +the authentication code, the committed static keys and the Noise processing rules will ensure that no Man-in-the-Middle attack took place +and that messages can be securely exchanged bi-directionally in the transfer phase. + +This allows pairing in case device `A` does not have a camera to scan a QR (e.g. a desktop client) while device `B` has. + +The resulting handshake would then be: +``` +WakuPairing2: +a. -> eA {H(sB||r), contentTopicParams, messageNametag} + ... +b. <- eB, eAeB {H(sB||r)} [authcode] +c. <- sB, eAsB {r} +d. -> sA, sAeB, sAsB {s} + +{}: payload, []: user interaction +``` + +## Secure Transfer + +The pairing phase is designed to be application-agnostic +and should be flexible enough to mutually authenticate +and allow exchange of cryptographic key material +between two devices over a distributed network of Waku2 nodes. + +Once the handshake is concluded, +(privacy-sensitive) information can be exchanged using the encryption keys agreed upon the pairing phase. +If stronger security guarantees are required, +some [additional tweaks](#Implementation-Suggestions) are possible. + +## Implementation Suggestions + +### Timebox QR exposure + +We suggest to timebox the exposure of each pairing QR code to few seconds, e.g. 30. +After this time limit, a QR code containing a new ephemeral key, random static key commitment and message nametag (content topic parameters could remain the same) +should replace the previously exposed QR, which can then be discarded. + +The reason for such suggestion is due to the fact that if an attacker is able to compromise one of the ephemeral keys, +he might successfully realize an undetected MitM attack up to the `authcode` confirmation +(we note that compromising ephemeral keys is outside our and Noise security assumptions). + +The attacker could indeed proceed as follows: +- intercepts the QR; +- blocks/delays the delivery of the pairing message `b.`; +- compromises `A` or `B` ephemeral key; +- recovers the genuine `authcode` that would have been generated by `A` and `B`; +- generates ~`10^8` random `t` values until the Noise processing of the message `b'. -> eC, eCeB {H(sC||t)} `, where `eC` and `sC` are the attacker ephemeral and static key, respectively, results in computing the same `authcode` as the one between `A` and `B`; +- delivers the message `b'. -> eC, eCeB {H(sC||t)}` to `B` (before `A` is able to deliver its message `b.`). + +At this point `A` and `B` will observe the same `authcode` (and would then confirm it), +but `B` will process the attacker's ephemeral key `eC` instead of `eA`. + +However, the attacker would not be able to open to device `A` the static key commitment `H(sB||s)` sent by device `B` out-of-band, +and the pairing will abort on `A` side before it reveals its static key. +Device `B`, instead, will successfully complete the pairing with the attacker. + +Hence, timeboxing the QR exposure, +also in combination with increasing the number of decimal digits of the `authcode`, +will strongly limit the probability that an attacker can successfully impersonate device `A` to `B`. + +We stress once more, that such attack requires the compromise of an ephemeral key (outside our security model) +and that device `A` will in any case detect a mismatch and abort the pairing, +regardless of the fact that the QR timeboxing mitigation is implemented or not. + +### Randomized Rekey + +The Noise Protocol framework supports [`Rekey()`](http://www.noiseprotocol.org/noise.html#rekey) +in order to update encryption keys *"so that a compromise of cipherstate keys will not decrypt older* \[exchanged\] *messages"*. +However, if a certain cipherstate key is compromised, +it will be possible for the attacker not only to decrypt messages encrypted under that key, +but also all those messages encrypted under any successive new key obtained through a call to `Rekey()`. + +This could be mitigated by attaching an ephemeral key to messages sent after a [Split()](http://www.noiseprotocol.org/noise.html#the-symmetricstate-object) +so that a new random symmetric key can be derived, +in a similar fashion to [Double-Ratchet](https://signal.org/docs/specifications/doubleratchet/). + +This can be practically achieved by: +- keeping the full Handhshake State even after the handshake is complete (*by Noise specification a call to [`Split()`](http://www.noiseprotocol.org/noise.html#the-symmetricstate-object) should delete the Handshake State*) +- continuing updating the Handshake State by processing every after-handshake exchanged message (i.e. the `payload`) according to the Noise [processing rules](http://www.noiseprotocol.org/noise.html#processing-rules) (i.e. by calling `EncryptAndHash(payload)` and `DecryptAndHash(payload)`); +- adding to each (or every few) message exchanged in the transfer phase a random ephemeral key `e` and perform Diffie-Hellman operations with the other party's ephemeral/static keys in order to update the underlying CipherState and recover new random inbound/outbound encryption keys by calling [`Split()`](http://www.noiseprotocol.org/noise.html#the-symmetricstate-object). + +In short, the transfer phase would look like (but not necessarily the same as): + +``` +TransferPhase: + -> eA, eAeB, eAsB {payload} + <- eB, eAeB, sAeB {payload} + ... + +{}: payload +``` + +### Messages Nametag Derivation + +To reduce metadata leakages and increase devices's anonymity over the p2p network, +[35/WAKU2-NOISE](https://rfc.vac.dev/spec/37/#session-states) suggests to use some common secrets `mntsInbound, mntsOutbound` (e.g. `mntsInbound, mntsOutbound = HKDF(h)` +where `h` is the [handshake hash value](https://noiseprotocol.org/noise.html#overview-of-handshake-state-machine) of the Handshake State at some point of the pairing phase) +in order to frequently and deterministically change the `messageNametag` of messages exchanged during the pairing and transfer phase - +ideally, at each message exchanged. + +Given the proposed construction, +the `mntsInbound` and `mntsOutbound` secrets can be used to iteratively generate the `messageNametag` field of Waku payloads +for inbound and outbound messages, respectively. + +The derivation of `messageNametag` should be deterministic only for communicating devices +and independent from message content, +otherwise lost messages will prevent computing the next message nametag. +A possible approach consists in computing the `n`-th `messageNametag` as `H( mntsInbound || n)`, +where `n` is serialized as `uint64`. + +In this way, sender's and recipient's devices +can keep updated a buffer of `messageNametag` to sieve +while listening to messages sent over `/{application-name}/{application-version}/wakunoise/1/sessions-{shard-id}/` (i.e., the next 50 not yet seen). +They will then be able to further identify if one or more messages were eventually lost +or not-yet-delivered during the communication. +This approach brings also the advantage that +communicating devices can efficiently identify encrypted messages addressed to them. + +We note that since the `ChaChaPoly` cipher used to encrypt messages supports *additional data*, +an encrypted payload can be further authenticated by passing the `messageNametag` as additional data to the encryption/decryption routine. +In this way, an attacker would be unable to craft an authenticated Waku message +even in case the currently used symmetric encryption key is compromised, +unless `mntsInbound`, `mntsOutbound` or the `messageNametag` buffer lists were compromised too. + +## Security/Privacy Considerations + +### Assumptions + +- The attacker is active, i.e. can interact with both devices `A` and `B` by sending messages over `contentTopic`. + +- The attacker has access to the QR code, that is knows the ephemeral key `eB`, the commitment `H(sB||r)` and the `contentTopic` exposed by the device `B`. + +- Devices `A` and `B` are considered trusted (otherwise the attacker will simply exfiltrate the relevant information from the attacked device). + +- As common for Noise, we assume that ephemeral keys cannot be compromised, while static keys might be later compromised. However, we enforce in the pairing phase extra security mechanisms (i.e. use of commitments for static keys) that will prevent some attacks possible when ephemeral keys are weak or get compromised. + +### Rationale + +- The device `B` exposes a commitment to its static key `sB` because: + - it can commit to its static key before the authentication code is confirmed without revealing it. + - If the private key of `eB` is weak or gets compromised, an attacker can impersonate `B` by sending in message `c.` to device `A` his own static key and successfully complete the pairing phase. Note that being able to compromise `eB` is not contemplated by our security assumptions. + - `B` cannot adaptively choose a static key based on the state of the Noise handshake at the end of message `b.`, i.e. after the authentication code is confirmed. Note that device `B` is trusted in our security assumptions. + - Confirming the authentication code after processing message `b.` will ensure that no Man-in-the-Middle (MitM) can later send a static key different than `sB`. + +- The device `A` sends a commitment to its static key `sA` because: + - it can commit to its static key before the authentication code is confirmed without revealing it. + - `A` cannot adaptively choose a static key based on the state of the Noise handshake at the end of message `b.`, i.e. after the authentication code is confirmed. Note that device `A` is trusted in our security assumptions. + - Confirming the authentication code after processing message `b.` will ensure that no MitM can later send a static key different than `sA`. + +- The authorization code is shown and has to be confirmed at the end of message `b.` because: + - an attacker that frontruns device `A` by sending faster his own ephemeral key would be detected before he's able to know device `B` static key `sB`; + - it ensures that no MitM attacks will happen during *the whole* pairing handshake, since commitments to the (later exchanged) device static keys will be implicitly acknowledged by the authorization code confirmation; + - it enables to safely swap the role of handshake initiator and responder (see above); + +- Device `B` sends his static key first because: + - by being the pairing requester, it cannot probe device `A` identity without revealing its own (static key) first. Note that device `B` static key and its commitment can be bound to other cryptographic material (e.g., seed phrase). + +- Device `B` opens a commitment to its static key at message `c.` because: + - if device `A` replies concluding the handshake according to the protocol, device `B` acknowledges that device `A` correctly received his static key `sB`, since `r` was encrypted under an encryption key derived from the static key `sB` and the genuine (due to the previous `authcode` verification) ephemeral keys `eA` and `eB`. + +- Device `A` opens a commitment to its static key at message `d.` because: + - if device `B` doesn't abort the pairing, device `A` acknowledges that device `B` correctly received his static key `sA`, since `s` was encrypted under an encryption key derived from the static keys `sA` and `sB` and the genuine (due to the previous `authcode` verification) ephemeral keys `eA` and `eB`. + +## Application to Noise Sessions + +### The N11M session management mechanism + +In the [`N11M` session management mechanism](https://rfc.vac.dev/spec/37/#the-n11m-session-management-mechanism), +one of Alice's devices is already communicating with one of Bob's devices within an active Noise session, +e.g. after a successful execution of a Noise handshake. + +Alice and Bob would then share some cryptographic key material, +used to encrypt their communications. +According to [37/WAKU2-NOISE-SESSIONS](https://rfc.vac.dev/spec/37/) this information consists of: +- A `session-id` (32 bytes) +- Two cipher state `CSOutbound`, `CSInbound`, where each of them contains: + - an encryption key `k` (2x32bytes) + - a nonce `n` (2x8bytes) + - (optionally) an internal state hash `h` (2x32bytes) + +for a total of **176 bytes** of information. + +In a [`N11M`](https://rfc.vac.dev/spec/37/#the-n11m-session-management-mechanism) session mechanism scenario, +all (synced) Alice's devices that are communicating with Bob +share the same Noise session cryptographic material. +Hence, if Alice wishes to add a new device, +she must securely transfer a copy of such data from one of her device `A` to a new device `B` in her possession. + +In order to do so she can: +- pair device `A` with `B` in order to have a Noise session between them; +- securely transfer within such session the 176 bytes serializing the active session with Bob; +- manually instantiate in `B` a Noise session with Bob from the received session serialization. + +## Copyright + +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). + +## References + +### Normative +- [35/WAKU2-NOISE](https://rfc.vac.dev/spec/37/#session-states) +- [37/WAKU2-NOISE-SESSIONS](https://rfc.vac.dev/spec/37/) + +### Informative +- [26/WAKU2-PAYLOAD](https://rfc.vac.dev/spec/35/#abnf) +- [The Double-Ratchet Algorithm](https://signal.org/docs/specifications/doubleratchet/) +- [The Noise Protocol Framework specifications](http://www.noiseprotocol.org/noise.html) +- [IETF RFC 4648 - The Base16, Base32, and Base64 Data Encodings](https://datatracker.ietf.org/doc/html/rfc4648) From 65efc49ad35604ec4ee58e9edf338b4d932c7990 Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Tue, 30 Jan 2024 12:32:52 -0500 Subject: [PATCH 17/81] Create dandelion.md --- standards/application/dandelion.md | 296 +++++++++++++++++++++++++++++ 1 file changed, 296 insertions(+) create mode 100644 standards/application/dandelion.md diff --git a/standards/application/dandelion.md b/standards/application/dandelion.md new file mode 100644 index 0000000..5316169 --- /dev/null +++ b/standards/application/dandelion.md @@ -0,0 +1,296 @@ +--- +title: DANDELION +name: Waku v2 Dandelion +category: Standards Track +tags: waku/anonymity +editor: Daniel Kaiser +contributors: +--- + +## Abstract + +This document specifies a deanonymization mitigation technique, +based on [Dandelion](https://arxiv.org/abs/1701.04439) and [Dandelion++](https://arxiv.org/abs/1805.11060), +for Waku Relay. +It mitigates mass deanonymization in the [multi-node (botnet) attacker model](/spec/45/#multi-node), +even when the number of malicious nodes is linear in the number of total nodes in the network. + +Based on the insight that symmetric message propagation makes deanonymization easier, +it introduces a probability for nodes to simply forward the message to one select relay node +instead of disseminating messages as per usual relay operation. + +## Background and Motivation + +[Waku Relay](/spec/11/), offers privacy, pseudonymity, and a first layer of anonymity protection by design. +Being a modular protocol family [Waku v2](/spec/10/) +offers features that inherently carry trade-offs as separate building blocks. +Anonymity protection is such a feature. +The [Anonymity Trilemma](https://freedom.cs.purdue.edu/projects/trilemma.html) +states that an anonymous communication network can only have two out of +low bandwidth consumption, low latency, and strong anonymity. +Even when choosing low bandwidth and low latency, which is the trade-off that basic Waku Relay takes, +better anonymity properties (even though not strong per definition) can be achieved by sacrificing some of the efficiency properties. +44/WAKU2-DANDELION specifies one such technique, and aims at gaining the best "bang for the buck" +in terms of efficiency paid for anonymity gain. +44/WAKU2-DANDELION is based on [Dandelion](https://arxiv.org/abs/1701.04439) +and [Dandelion++](https://arxiv.org/abs/1805.11060). + +Dandelion is a message spreading method, which, compared to other methods, +increases the uncertainty of an attacker when trying to link messages to senders. +Libp2p gossipsub aims at spanning a [d-regular graph](https://en.wikipedia.org/wiki/Regular_graph) topology, with d=6 as the [default value](/spec/29/#gossipsub-v10-parameters). +Messages are forwarded within this (expected) symmetric topology, +which reduces uncertainty when trying to link messages to senders. +Dandelion breaks this symmetry by subdividing message spreading into a "stem" and a "fluff" phase. + +In the "stem" phase, the message is sent to a single select relay node. +With a certain probability, this message is relayed further on the "stem", +or enters the fluff phase. +On the stem, messages are relayed to single peers, respectively, +while in fluff phase, messages are spread as per usual relay operation (optionally augmented by random delays to further reduce symmetry). +The graph spanned by stem connections is referred to as the anonymity graph. + +Note: This is an early raw version of the specification. +It does not strictly follow the formally evaluated Dandelion++ paper, +as we want to experiment with relaxing (and strengthening) certain model properties. +In specific, we aim at a version that has tighter latency bounds. +[Further research](https://arxiv.org/pdf/2201.11860.pdf) suggests that Dandelion++'s design choices are not optimal, +which further assures that tweaking design choices makes sense. +We will refine design decisions in future versions of this specification. + +Further information on Waku anonymity may be found in our [Waku Privacy and Anonymity Analysis](https://vac.dev/wakuv2-relay-anon). + +## Theory and Functioning + +44/WAKU2-DANDELION can be seen as an anonymity enhancing add-on to [Waku Relay](https://rfc.vac.dev/spec/11/) message dissemination, +which is based on [libp2p gossipsub](https://github.com/libp2p/specs/blob/master/pubsub/gossipsub/README.md). +44/WAKU2-DANDELION subdivides message dissemination into a "stem" and a "fluff" phase. +This specification is mainly concerned with specifying the stem phase. +The fluff phase corresponds to [Waku Relay](/spec/11/), +with optional fluff phase augmentations such as random delays. +Adding random delay in the fluff phase further reduces symmetry in dissemination patterns and +introduces more uncertainty for the attacker. +Specifying fluff phase augmentations is out of scope for this document. + +*Note: +We plan to add a separate specification for fluff phase augmentations. +We envision stem and fluff phase as abstract concepts. +The Dandelion stem and fluff phases instantiate these concepts. +Future stem specifications might comprise: none (standard relay), Dandelion stem, Tor, and mix-net. +As for future fluff specifications: none (standard relay), diffusion (random delays), and mix-net.* + +Messages relayed by nodes supporting 44/WAKU2-DANDELION are either in stem phase or in fluff phase. +We refer to the former as a stem message and to the latter as a fluff message. +A message starts in stem phase, and at some point, transitions to fluff phase. +Nodes, on the other hand, are in stem state or fluff state. +Nodes in stem state relay stem messages to a single relay node, randomly selected per epoch for each incoming stem connection. +Nodes in fluff state transition stem messages into fluff phase and relay them accordingly. +Fluff messages are always disseminated via Waku Relay, +by both nodes in stem state and nodes in fluff state. + +Messages originated in the node (i.e. messages coming from the application layer of our node), +are always sent as stem messages. + +The stem phase can be seen as a different protocol, and messages are introduced into Waku Relay, and by extension gossipsub, +once they arrive at a node in fluff state for the first time. +44/WAKU2-DANDELION uses [19/WAKU2-LIGHTPUSH](/spec/19/) as the protocol for relaying stem messages. + +There are no negative effects on gossipsub peer scoring, +because Dandelion nodes in *stem state* still normally relay Waku Relay (gossipsub) messages. + +## Specification + +Nodes $v$ supporting 44/WAKU2-DANDELION MUST either be in stem state or in fluff state. +This does not include relaying messages originated in $v$, for which $v$ SHOULD always be in stem state. + +### Choosing the State + +On startup and when a new epoch starts, +node $v$ randomly selects a number $r$ between 0 and 1. +If $r < q$, for $q = 0.2$, the node enters fluff state, otherwise, it enters stem state. + +New epochs start when `unixtime` (in seconds) $\equiv 0 \mod 600$, +corresponding to 10 minute epochs. + +### Stem State + +On entering stem state, +nodes supporting 44/WAKU2-DANDELION MUST randomly select two nodes for each pubsub topic from the respective gossipsub mesh node set. +These nodes are referred to as stem relays. +Stem relays MUST support [19/WAKU2-LIGHTPUSH](/spec/19/). +If a chosen peer does not support [19/WAKU2-LIGHTPUSH](/spec/19/), +the node SHOULD switch to fluff state. +(We may update this strategy in future versions of this document.) + +Further, the node establishes a map that maps each incoming stem connection +to one of its stem relays chosen at random (but fixed per epoch). +Incoming stem connections are identified by the [Peer IDs](https://docs.libp2p.io/concepts/peers/#peer-id/) +of peers the node receives [19/WAKU2-LIGHTPUSH](/spec/19/) messages from. +Incoming [19/WAKU2-LIGHTPUSH](/spec/19/) connections from peers that do not support 44/WAKU2-DANDELION are identified and mapped in the same way. +This makes the protocol simpler, increases the anonymity set, and offers Dandelion anonymity properties to such peers, too. + +The node itself is mapped in the same way, so that all messages originated by the node are relayed via a per-epoch-fixed Dandelion relay, too. + +While in stem state, nodes MUST relay stem messages to the respective stem relay. +Received fluff messages MUST be relayed as specified in the fluff state section. + +The stem protocol ([19/WAKU2-LIGHTPUSH](/spec/19/)) is independent of the fluff protocol ([Waku Relay](/spec/11/)). +While in stem state, nodes MUST NOT gossip about stem messages, +and MUST NOT send control messages related to stem messages. +(An existing gossipsub implementation does *not* have to be adjusted to not send gossip about stem messages, +because these messages are only handed to gossipsub once they enter fluff phase.) + +#### Fail Safe + +Nodes $v$ in stem state SHOULD store messages attached with a random timer between $t_1 = 5 * 100ms$ and $t_2 = 2 * t_1$. +This time interval is chosen because + +* we assume $100\,ms$ as an average per hop delay, and +* using $q=0.2$ will lead to an expected number of 5 stem hops per message. + +If $v$ does not receive a given message via Waku Relay (fluff) before the respective timer runs out, +$v$ will disseminate the message via Waku Relay. + +### Fluff State + +In fluff state, nodes operate as usual Waku Relay nodes. +The Waku Relay functionality might be augmented by a future specification, e.g. adding random delays. + +Note: The [Dandelion](https://arxiv.org/abs/1701.04439) paper describes the fluff phase as regular forwarding. +Since Dandelion is designed as an update to the Bitcoin network using diffusion spreading, +this regular forwarding already comprises random delays. + +## Implementation Notes + +Handling of the 44/WAKU2-DANDELION stem phase can be implemented as an extension to an existing [19/WAKU2-LIGHTPUSH](/spec/19/) implementation. + +Fluff phase augmentations might alter gossipsub message dissemination (e.g. adding random delays). +If this is the case, they have to be implemented on the libp2p gossipsub layer. + +## Security/Privacy Considerations + +### Denial of Service: Black Hole Attack + +In a [black hole attack](/spec/45/#black-hole-internal), malicious nodes prevent messages from being spread, +metaphorically not allowing messages to leave once they entered. +This requires the attacker to control nodes on all dissemination paths. +Since the number of dissemination paths is significantly reduced in the stem phase, +Dandelion spreading reduces the requirements for a black hole attack. + +The fail-safe mechanism specified in this document (proposed in the Dandelion paper), mitigates this. + +### Anonymity Considerations + +#### Attacker Model and Anonymity Goals + +44/WAKU2-DANDELION provides significant mitigation against mass deanonymization in the +passive [scaling multi node model](/spec/45/#scaling-multi-node). +in which the attacker controls a certain percentage of nodes in the network. +44/WAKU2-DANDELION provides significant mitigation against mass deanonymization +even if the attacker knows the network topology, i.e. the anonymity graph and the relay mesh graph. + +Mitigation in stronger models, including the *active scaling multi-node* model, is weak. +We will elaborate on this in future versions of this document. + +44/WAKU2-DANDELION does not protect against targeted deanonymization attacks. + +#### Non-Dandelion Peers + +Stem relays receiving messages can either be in stem state or in fluff state themselves. +They might also not support 44/WAKU2-DANDELION, +and interpret the message as classical [19/WAKU2-LIGHTPUSH](/spec/19/), +which effectively makes them act as fluff state relays. +While such peers lower the overall anonymity properties, +the [Dandelion++ paper](https://arxiv.org/abs/1805.11060) +showed that including those peers yields more anonymity compared to excluding these peers. + +### Future Analysis + +The following discusses potential relaxations in favour of reduced latency, +as well as their impact on anonymity. +This is still work in progress and will be elaborated on in future versions of this document. + +Generally, there are several design choices to be made for the stem phase of a Dandelion-based specification: + +1) the probability of continuing the stem phase, which determines the expected stem lengh, +2) the out degree in the stem phase, which set to 1 in this document (also in the Dandelion papers), +3) the rate of re-selecting stem relays among all gossipsub mesh peers (for a given pubsub topic), and +4) the mapping of incoming connections to outgoing connections. + +#### Bound Stem Length + +Choosing $q = 0.2$, 44/WAKU2-DANDELION has an expected stem length of 5 hops, +Assuming $100ms$ added delay per hop, the stem phase adds around 500ms delay on average. + +There is a possibility for the stem to grow longer, +but some applications need tighter bounds on latency. + +While fixing the stem length would yield tighter latency bounds, +it also reduces anonymity properties. +A fixed stem length requires the message to carry information about the remaining stem length. +This information reduces the uncertainty of attackers +when calculating the probability distribution assigning each node a probability for having sent a specific message. +We will quantify the resulting loss of anonymity in future versions of this document. + +#### Stem Relay Selection + +In its current version, 44/WAKU2-DANDELION nodes default to fluff state +if the random stem relay selection yields at least one peer that does not support [19/WAKU2-LIGHTPUSH](/spec/19/) (which is the stem protocol used in 44/WAKU2-DANDELION). +If nodes would reselect peers until they find peers supporting [19/WAKU2-LIGHTPUSH](/spec/19/), +malicious nodes would get an advantage if a significant number of honest nodes would not support [19/WAKU2-LIGHTPUSH](/spec/19/). +Even though this causes messages to enter fluff phase earlier, +we choose the trade-off in favour of protocol stability and sacrifice a bit of anonymity. +(We will look into improving this in future versions of this document.) + +#### Random Delay in Fluff Phase + +[Dandelion](https://arxiv.org/abs/1701.04439) and [Dandelion++](https://arxiv.org/abs/1805.11060) +assume adding random delays in the fluff phase as they build on Bitcoin diffusion. +44/WAKU2-DANDELION (in its current state) allows for zero delay in the fluff phase and outsources fluff augmentations to dedicated specifications. +While this lowers anonymity properties, it allows making Dandelion an opt-in solution in a given network. +Nodes that do not want to use Dandelion do not experience any latency increase. +We will quantify and analyse this in future versions of this specification. + +We plan to add a separate fluff augmentation specification that will introduce random delays. +Optimal delay times depend on the message frequency and patterns. +This delay fluff augmentation specification will be oblivious to the actual message content, +because Waku Dandelion specifications add anonymity on the routing layer. +Still, it is important to note that [Waku2 messages](https://rfc.vac.dev/spec/14/#payloads) (in their current version) carry an originator timestamp, +which works against fluff phase random delays. +An analysis of the benefits of this timestamp versus anonymity risks is on our roadmap. + +By adding a delay, the fluff phase modifies the behaviour of [libp2p gossipsub](https://github.com/libp2p/specs/blob/master/pubsub/gossipsub/README.md), +which Waku Relay builds upon. + +Note: Introducing random delays can have a negative effect on +[peer scoring](https://github.com/libp2p/specs/blob/master/pubsub/gossipsub/gossipsub-v1.1.md#peer-scoring). + +#### Stem Flag + +While 44/WAKU2-DANDELION without fluff augmentation does not effect Waku Relay nodes, +messages sent by nodes that only support [19/WAKU2-LIGHTPUSH](/spec/19/) might be routed through a Dandelion stem without them knowing. +While this improves anonymity, as discussed above, it also introduces additional latency and lightpush nodes cannot opt out of this. + +In future versions of this specification we might + +* add a flag to [14/WAKU2-MESSAGE](/spec/14/) indicating a message should be routed over a Dandelion stem (opt-in), or +* add a flag to [14/WAKU2-MESSAGE](/spec/14/) indicating a message should *not* be routed over a Dandelion stem (opt-out), or +* introducing a fork of [19/WAKU2-LIGHTPUSH](/spec/19/) exclusively used for Dandelion stem. + +In the current version, we decided against these options in favour of a simpler protocol and an increased anonymity set. + +## Copyright + +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). + +## References + +* [Dandelion](https://arxiv.org/abs/1701.04439) +* [Dandelion++](https://arxiv.org/abs/1805.11060) +* [Waku Relay](https://rfc.vac.dev/spec/11/) +* [Waku v2](https://rfc.vac.dev/spec/10/) +* [d-regular graph](https://en.wikipedia.org/wiki/Regular_graph) +* [Anonymity Trilemma](https://freedom.cs.purdue.edu/projects/trilemma.html) +* [Waku Privacy and Anonymity Analysis](https://vac.dev/wakuv2-relay-anon). +* [On the Anonymity of Peer-To-Peer Network Anonymity Schemes Used by Cryptocurrencies](https://arxiv.org/pdf/2201.11860.pdf) +* [Adversarial Models](/spec/45/) +* [14/WAKU2-MESSAGE](/spec/14/) From 3bd5587771ca6797fa56372364133b192352f7e5 Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Tue, 30 Jan 2024 13:02:00 -0500 Subject: [PATCH 18/81] Create adversarial-models.md --- informational/adversarial-models.md | 335 ++++++++++++++++++++++++++++ 1 file changed, 335 insertions(+) create mode 100644 informational/adversarial-models.md diff --git a/informational/adversarial-models.md b/informational/adversarial-models.md new file mode 100644 index 0000000..c55467c --- /dev/null +++ b/informational/adversarial-models.md @@ -0,0 +1,335 @@ +--- +title: ADVERSARIAL-MODELS +name: Waku v2 Adversarial Models and Attack-based Threat List +category: Informational +tags: +editor: Daniel Kaiser +contributors: +--- + +## Abstract + +This document lists adversarial models and attack-based threats relevant in the context of Waku v2. + +## Motivation and Background + +Future versions of this document will serve as a comprehensive list of adversarial models and attack based threats relevant for [Waku v2](/spec/10/). +The main purpose of this document is being a linkable resource for specifications that address protection as well as mitigation mechanisms within the listed models. + +Discussing and introducing countermeasures to specific attacks in specific models is out of scope for this document. +Analyses and further information about Waku's properties within these models may be found in our *Waku v2 Anonymity Analysis* series of research log posts: + +* [Part I: Definitions and Waku Relay](https://vac.dev/wakuv2-relay-anon) + +Note: This document adds to the adversarial models and threat list discussed in our [research log post](https://vac.dev/wakuv2-relay-anon). +It does not cover analysis of Waku, as the research log post does. +Future versions of this document will extend the adversarial models and threat list. + +## Informal Definitions: Security, Privacy, and Anonymity + +The concepts of security, privacy, and anonymity are linked and have quite a bit of overlap. + +### Security + +Of the three, [Security](https://en.wikipedia.org/wiki/Information_security) has the clearest agreed upon definition, +at least regarding its key concepts: *confidentiality*, *integrity*, and *availability*. + +* confidentiality: data is not disclosed to unauthorized entities. +* integrity: data is not modified by unauthorized entities. +* availability: data is available, i.e. accessible by authorized entities. + +While these are the key concepts, the definition of information security has been extended over time including further concepts, +e.g. [authentication](https://en.wikipedia.org/wiki/Authentication) and [non-repudiation](https://en.wikipedia.org/wiki/Non-repudiation). + +### Privacy + +Privacy allows users to choose which data and information + +* they want to share +* and with whom they want to share it. + +This includes data and information that is associated with and/or generated by users. +Protected data also comprises metadata that might be generated without users being aware of it. +This means, no further information about the sender or the message is leaked. +Metadata that is protected as part of the privacy-preserving property does not cover protecting the identities of sender and receiver. +Identities are protected by the [anonymity property](#anonymity). + +Often privacy is realized by the confidentiality property of security. +This neither makes privacy and security the same, nor the one a sub category of the other. +While security is abstract itself (its properties can be realized in various ways), privacy lives on a more abstract level using security properties. +Privacy typically does not use integrity and availability. +An adversary who has no access to the private data, because the message has been encrypted, could still alter the message. + +### Anonymity + +Privacy and anonymity are closely linked. +Both the identity of a user and data that allows inferring a user's identity should be part of the privacy policy. +For the purpose of analysis, we want to have a clearer separation between these concepts. + +We define anonymity as *unlinkablity of users' identities and their shared data and/or actions*. + +We subdivide anonymity into *receiver anonymity* and *sender anonymity*. + +#### Receiver Anonymity + +We define receiver anonymity as *unlinkability of users' identities and the data they receive and/or related actions*. +Because each [Waku message](/spec/14/) is associated with a content topic, and each receiver is interested in messages with specific content topics, +receiver anonymity in the context of Waku corresponds to *subscriber-topic unlinkability*. +An example for the "action" part of our receiver anonymity definition is subscribing to a specific topic. + +#### Sender Anonymity + +We define sender anonymity as *unlinkability of users' identities and the data they send and/or related actions*. +Because the data in the context of Waku is Waku messages, sender anonymity corresponds to *sender-message unlinkability*. + +#### Anonymity Trilemma + +[The Anonymity trilemma](https://freedom.cs.purdue.edu/projects/trilemma.html) states that only two out of *strong anonymity*, *low bandwidth*, and *low latency* can be guaranteed in the *global attacker* model. +Waku's goal, being a modular set of protocols, is to offer any combination of two out of these three properties, as well as blends. + +A fourth factor that influences [the anonymity trilemma](https://freedom.cs.purdue.edu/projects/trilemma.html) is *frequency and patterns* of messages. +The more messages there are, and the more randomly distributed they are, the better the anonymity protection offered by a given anonymous communication protocol. +So, incentivising users to use the protocol, for instance by lowering entry barriers, helps protecting the anonymity of all users. +The frequency/patterns factor is also related to [k-anonymity](https://en.wikipedia.org/wiki/K-anonymity). + +### Censorship Resistance + +Another security related property that Waku aims to offer is censorship resistance. +Censorship resistance guarantees that users can participate even if an attacker tries to deny them access. +So, censorship resistance ties into the availability aspect of security. +In the context of Waku that means users should be able to send messages as well as receive all messages they are interested in, +even if an attacker tries to prevent them from disseminating messages or tries to deny them access to messages. + +An example for a censorship resistance technique is Tor's [Pluggable Transports](https://www.pluggabletransports.info/about/). + +## Adversarial Models + +The following lists various attacker types with varying degrees of power. +The more power an attacker has, the more difficult it is to gain the respective attacker position. + +Each attacker type comes in a passive and an active variant. +While a passive attacker can stay hidden and is not suspicious, +the respective active attacker has more (or at least the same) deanonymization power. + +We also distinguish between internal and external attackers. +Since in permissionless protocols it is easy to obtain an internal position, +in practice attackers are expected to mount combined attacks that leverage both internal and external attacks. + +### Internal + +In the passive variant, an internal attacker behaves like an honest node towards peers. +The passive internal attacker has the same access rights as any honest node. +In the active variant, an internal attacker can additionally drop, inject, and alter messages. +With respect to Waku relay, for example, an internal attacker participates in the same pubsub topic as its victims, +and can read messages related to that topic. + +#### Single Node + +This attacker controls a single node. + +#### Multi Node + +This attacker controls a fixed number of nodes (not scaling with the total number of nodes in the network). +The multi node position can be achieved by setting up multiple nodes. +Botnets might be leveraged to increase the number of available hosts. +Multi node attackers could use [Sybil attacks](https://en.wikipedia.org/wiki/Sybil_attack) to increase the number of controlled nodes. +A countermeasure is for nodes to only accept libp2p gossipsub graft requests from peers with different IP addresses, or even different subnets. + +Nodes controlled by the attacker can efficiently communicate out-of-band to coordinate. + +#### Scaling Multi Node + +This attacker controls a number of nodes that scales linearly with the number of nodes in the network. +The attacker controls $p%$ of all nodes in the network. + +Nodes controlled by the attacker can efficiently communicate out-of-band to coordinate. + +### External + +An external attacker can only see encrypted traffic. +Waku protocols are protected by a secure channel set up with [Noise](/spec/35/). + +#### Local + +A local attacker has access to communication links in a local network segment. +This could be a rogue access point (with routing capability). + +#### AS + +An AS attacker controls a single AS (autonomous system). +A passive AS attacker can listen to traffic on arbitrary links within the AS. +An active AS attacker can drop, delay, inject, and alter traffic on arbitrary links within the AS. + +In practice, a malicious ISP would be considered as an AS attacker. +A malicious ISP could also easily setup a set of nodes at specific points in the network, +gaining internal attack power similar to a strong *multi node* or even *scaling multi node* attacker. + +#### Global (On-Net) + +A global (on-net) attacker has complete overview over the whole network. +A passive global attacker can listen to traffic on all links, +while the active global attacker basically carries the traffic: it can freely drop, delay, inject, and alter traffic at all positions in the network. +This basically corresponds to the [Dolev-Yao model](https://en.wikipedia.org/wiki/Dolev%E2%80%93Yao_model). + +An entity with this power would, in practice, also have the power of the internal *scaling multi node* attacker. + +## Attack-based Threats + +The following lists various attacks against [Waku v2](/spec/10/) protocols. +If not specifically mentioned, the attacks refer to [Waku relay](/spec/11) and the underlying [libp2p GossipSub](https://github.com/libp2p/specs/blob/master/pubsub/gossipsub/README.md). +We also list the weakest attacker model in which the attack can be successfully performed against. + +An attack is considered more powerful if it can be successfully performed in a weaker attacker model. + +Note: This list is work in progress. +We will either expand this list adding more attacks in future versions of this document, +or remove it and point to the "Security Considerations" sections of respective RFCs. + +### Prerequisite: Get a Specific Position in the Network + +Some attacks require the attacker node(s) to be in a specific position in the network. +In most cases, this corresponds to trying to get into the mesh peer list for the desired pubsub topic of the victim node. + +In libp2p gossipsub, and by extension Waku v2 relay, nodes can simply send a graft message for the desired topic to the victim node. +If the victim node still has open slots, the attacker gets the desired position. +This only requires the attacker to know the gossipsub multiaddress of the victim node. + +A *scaling multi node* attacker can leverage DHT based discovery systems to boost the probability of malicious nodes being returned, +which in turn significantly increases the probability of attacker nodes ending up in the peer lists of victim nodes. + +### Sender Deanonymization + +This section lists attacks that aim at deanonymizing a message sender. + +We assume that protocol messages are transmitted within a secure channel set up using the [Noise Protocol Framework](https://noiseprotocol.org/). +For [Waku Relay](/spec/11) this means we only consider messages with version field `2`, +which indicates that the payload has to be encoded using [35/WAKU2-NOISE](/spec/35/). + +Note: The currently listed attacks are against libp2p in general. +The [data field of Waku v2 relay](/spec/11/#message-fields) must be a [Waku v2 message](/spec/14/). +The attacks listed in the following do not leverage that fact. + +#### Replay Attack + +In a replay attack, the attacker replays a valid message it received. + +Waku relay is inherently safe against replay attack, +because GossipSub nodes, and by extension Waku relay nodes, +feature a `seen` cache, and only relay messages they have not seen before. + +Further, replay attacks will be punished by [RLN Relay](/spec/17/). + +#### Observing Messages + +If Waku relay was not protected with Noise, the AS attacker could simply check for messages leaving $v$ which have not been relayed to $v$. +These are the messages sent by $v$. +Waku relay protects against this attack by employing secure channels setup using Noise. + +#### Neighbourhood Surveillance + +This attack can be performed by a single node attacker that is connected to all peers of the victim node $v$ with respect to a specific topic mesh. +The attacker also has to be connected to $v$. +In this position, the attacker will receive messages $m_v$ sent by $v$ both on the direct path from $v$, and on indirect paths relayed by peers of $v$. +It will also receive messages $m_x$ that are not sent by $v$. These messages $m_x$ are relayed by both $v$ and the peers of $v$. +Messages that are received (significantly) faster from $v$ than from any other of $v$'s peers are very likely messages that $v$ sent, +because for these messages the attacker is one hop closer to the source. + +The attacker can (periodically) measure latency between itself and $v$, and between itself and the peers of $v$ to get more accurate estimates for the expected timings. +An AS attacker (and if the topology allows, even a local attacker) could also learn the latency between $v$ and its well-behaving peers. +An active AS attacker could also increase the latency between $v$ and its peers to make the timing differences more prominent. +This, however, might lead to $v$ switching to other peers. + +This attack cannot (reliably) distinguish messages $m_v$ sent by $v$ from messages $m_y$ relayed by peers of $v$ the attacker is not connected to. +Still, there are hop-count variations that can be leveraged. +Messages $m_v$ always have a hop-count of 1 on the path from $v$ to the attacker, while all other paths are longer. +Messages $m_y$ might have the same hop-count on the path from $v$ as well as on other paths. +Further techniques that are part of the *mass deanonymization* category, such as [bayesian analysis](#bayesian-analysis), can be used here as well. + +#### Controlled Neighbourhood + +If a multi node attacker manages to control all peers of the victim node, it can trivially tell which messages originated from $v$. + +#### Correlation + +Monitoring all traffic (in an AS or globally), allows the attacker to identify traffic correlated with messages originating from $v$. +This (alone) does not allow an external attacker to learn which message $v$ sent, but it allows identifying the respective traffic propagating through the network. +The more traffic in the network, the lower the success rate of this attack. + +Combined with just a few nodes controlled by the attacker, the actual message associated with the correlated traffic can eventually be identified. + +### Mass Deanonymization + +While attacks in the *sender deanonymization* category target a set of either specific or arbitrary users, +attacks in the *mass deanonymization* category aim at deanonymizing (parts of) the whole network. +Mass deanonymization attacks do not necessarily link messages to senders. +They might only reduce the anonymity set in which senders hide, +or infer information about the network topology. + +#### Graph Learning + +Graph learning attacks are a prerequisite for some mass deanonymization attacks, +in which the attacker learns the overlay network topology. +Graph learning attacks require a *scaling multinode* attacker + +For gossipsub this means an attacker learns the topic mesh for specific pubsub topics. +[Dandelion++](https://arxiv.org/abs/1805.11060) describes ways to perform this attack. + +#### Bayesian Analysis + +Bayesian analysis allows attackers to assign each node in the network a likelihood of having sent (originated) a specific message. +Bayesian analysis for mass deanonymization is detailed in [On the Anonymity of Peer-To-Peer Network Anonymity Schemes Used by Cryptocurrencies](https://arxiv.org/pdf/2201.11860). +It requires a *scaling node* attacker as well as knowledge of the network topology, +which can be learned via *graph learning* attacks. + +### Denial of Service (DoS) + +#### Flooding + +In a flooding attack, attackers flood the network with bogus messages. + +Waku employs [RLN Relay](/spec/17/) as the main countermeasure to flooding. +[SWAP](/spec/18/) also helps mitigating DoS attacks. + +#### Black Hole (internal) + +In a black hole attack, the attacker does not relay messages it is supposed to relay. +Analogous to a black hole, attacker nodes do not allow messages to leave once they entered. + +While *single node* and smaller *multi node* attackers can have a negative effect on availability, the impact is not significant. +A *scaling multi node* attacker, however, can significantly disrupt the network with such an attack. + +The effects of this attack are especially severe in conjunction with deanonymization mitigation techniques that reduce the out-degree of the overlay, +such as [Waku Dandelion](/spec/44/). +([Waku Dandelion](/spec/44/) also discusses mitigation techniques compensating the amplified black hole potential.) + +#### Traffic Filtering (external) + +A local attacker can filter and drop all Waku traffic within its controlled network segment. +An AS attacker can filter and drop all Waku traffic within its authority, while a global attacker can censor the whole network. +A countermeasure are censorship resistance techniques like [Pluggable Transports](https://www.pluggabletransports.info/about/). + +An entity trying to censor Waku can employ both the *black hole* attack and *traffic filtering*; +the former is internal while the latter is external. + +## Copyright + +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). + +## References + +* [10/WAKU2](/spec/10/) +* [11/WAKU2-RELAY](/spec/11/) +* [libp2p GossipSub](https://github.com/libp2p/specs/blob/master/pubsub/gossipsub/README.md) +* [Security](https://en.wikipedia.org/wiki/Information_security) +* [Authentication](https://en.wikipedia.org/wiki/Authentication) +* [Anonymity Trilemma](https://freedom.cs.purdue.edu/projects/trilemma.html) +* [Waku v2 message](/spec/14/) +* [Pluggable Transports](https://www.pluggabletransports.info/about/) +* [Sybil attack](https://en.wikipedia.org/wiki/Sybil_attack) +* [Dolev-Yao model](https://en.wikipedia.org/wiki/Dolev%E2%80%93Yao_model) +* [Noise Protocol Framework](https://noiseprotocol.org/) +* [35/WAKU2-NOISE](/spec/35/) +* [17/WAKU-RLN-RELAY](/spec/17/) +* [18/WAKU2-SWAP](/spec/18/) +* [Dandelion++](https://arxiv.org/abs/1805.11060) +* [On the Anonymity of Peer-To-Peer Network Anonymity Schemes Used by Cryptocurrencies](https://arxiv.org/pdf/2201.11860) From 9205715dce0e99b3b7b0f9c5f77e487b8929bf5a Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Tue, 30 Jan 2024 13:17:14 -0500 Subject: [PATCH 19/81] Create tor-push.md --- standards/application/tor-push.md | 43 +++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 standards/application/tor-push.md diff --git a/standards/application/tor-push.md b/standards/application/tor-push.md new file mode 100644 index 0000000..7620ab6 --- /dev/null +++ b/standards/application/tor-push.md @@ -0,0 +1,43 @@ +--- +title: TOR-PUSH +name: Waku v2 Tor Push +category: Best Current Practice +tags: waku/application +editor: Daniel Kaiser +contributors: +--- + +## Abstract + +This document extends the [11/WAKU2-RELAY](/spec/11/), specifying Waku Tor Push, +which allows nodes to push messages via Tor into the Waku relay network. + +Waku Tor Push builds on [46/GOSSIPSUB-TOR-PUSH](/spec/46). + +**Protocol identifier**: /vac/waku/relay/2.0.0 + +Note: Waku Tor Push does not have a dedicated protocol identifier. +It uses the same identifier as Waku relay. +This allows Waku relay nodes that are oblivious to Tor Push to process messages received via Tor Push. + + +## Functional Operation + +In its current version, Waku Tor Push corresponds to [46/GOSSIPSUB-TOR-PUSH](/spec/46) +applied to [11/WAKU2-RELAY](/spec/11/), +instead of [libp2p gossipsub](https://github.com/libp2p/specs/blob/master/pubsub/gossipsub/README.md). + +## Security/Privacy Considerations + +see [46/GOSSIPSUB-TOR-PUSH](/spec/46) + +## Copyright + +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). + +## References + +* [11/WAKU2-RELAY](/spec/11/) +* [libp2p gossipsub](https://github.com/libp2p/specs/blob/master/pubsub/gossipsub/README.md) +* [46/GOSSIPSUB-TOR-PUSH](/spec/46) +* [Tor](https://www.torproject.org/) From bb8be761997528ed56a41666c0ada0470de6eeab Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Tue, 30 Jan 2024 13:37:56 -0500 Subject: [PATCH 20/81] Create relay-sharding.md --- standards/core/relay-sharding.md | 279 +++++++++++++++++++++++++++++++ 1 file changed, 279 insertions(+) create mode 100644 standards/core/relay-sharding.md diff --git a/standards/core/relay-sharding.md b/standards/core/relay-sharding.md new file mode 100644 index 0000000..78078d2 --- /dev/null +++ b/standards/core/relay-sharding.md @@ -0,0 +1,279 @@ +--- +title: RELAY-SHARDING +name: Waku v2 Relay Sharding +status: raw +category: Standards Track +tags: waku/core +editor: Daniel Kaiser +contributors: +- Simon-Pierre Vivier +--- + +## Abstract + +This document describes ways of sharding the [Waku relay](/spec/11/) topic, +allowing Waku networks to scale in the number of content topics. + +> *Note*: Scaling in the size of a single content topic is out of scope for this document. + +## Background and Motivation + +[Unstructured P2P networks](https://en.wikipedia.org/wiki/Peer-to-peer#Unstructured_networks) +are more robust and resilient against DoS attacks compared to +[structured P2P networks](https://en.wikipedia.org/wiki/Peer-to-peer#Structured_networks)). +However, they do not scale to large traffic loads. +A single [libp2p gossipsub mesh](https://github.com/libp2p/specs/blob/master/pubsub/gossipsub/gossipsub-v1.0.md#gossipsub-the-gossiping-mesh-router), +which carries messages associated with a single pubsub topic, can be seen as a separate unstructured P2P network +(control messages go beyond these boundaries, but at its core, it is a separate P2P network). +With this, the number of [Waku relay](/spec/11/) content topics that can be carried over a pubsub topic is limited. +This prevents app protocols that aim to span many multicast groups (realized by content topics) from scaling. + +This document specifies three pubsub topic sharding methods (with varying degrees of automation), +which allow application protocols to scale in the number of content topics. +This document also covers discovery of topic shards. + +## Named Sharding + +*Named sharding* offers apps to freely choose pubsub topic names. +It is RECOMMENDED for App protocols to follow the naming structure detailed in [23/WAKU2-TOPICS](/spec/23/). +With named sharding, managing discovery falls into the responsibility of apps. + +From an app protocol point of view, a subscription to a content topic `waku2/xxx` on a shard named /mesh/v1.1.1/xxx would look like: + +`subscribe("/waku2/xxx", "/mesh/v1.1.1/xxx")` + +## Static Sharding + +*Static sharding* offers a set of shards with fixed names. +Assigning content topics to specific shards is up to app protocols, +but the discovery of these shards is managed by Waku. + +Static shards are managed in shard clusters of 1024 shards per cluster. +Waku static sharding can manage $2^16$ shard clusters. +Each shard cluster is identified by its index (between $0$ and $2^16-1$). + +A specific shard cluster is either globally available to all apps, +specific for an app protocol, +or reserved for automatic sharding (see next section). + +> *Note:* This leads to $2^16 * 1024 = 2^26$ shards for which Waku manages discovery. + +App protocols can either choose to use global shards, or app specific shards. + +Like the [IANA ports](https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml), +shard clusters are divided into ranges: + +| index (range) | usage | +| --- | --- | +| 0 - 15 | reserved | +| 16 - 65535| app-defined networks | + +The informational RFC [52/WAKU2-RELAY-STATIC-SHARD-ALLOC](/spec/52) lists the current index allocations. + +The global shard with index 0 and the "all app protocols" range are treated in the same way, +but choosing shards in the global cluster has a higher probability of sharing the shard with other apps. +This offers k-anonymity and better connectivity, but comes at a higher bandwidth cost. + +The name of the pubsub topic corresponding to a given static shard is specified as + +`/waku/2/rs//`, + +an example for the 2nd shard in the global shard cluster: + +`/waku/2/rs/0/2`. + +> *Note*: Because *all* shards distribute payload defined in [14/WAKU2-MESSAGE](spec/14/) via [protocol buffers](https://developers.google.com/protocol-buffers/), +the pubsub topic name does not explicitly add `/proto` to indicate protocol buffer encoding. +We use `rs` to indicate these are *relay shard* clusters; further shard types might follow in the future. + +From an app point of view, a subscription to a content topic `waku2/xxx` on a static shard would look like: + +`subscribe("/waku2/xxx", 43)` + +for global shard 43. +And for shard 43 of the Status app (which has allocated index 16): + +`subscribe("/waku2/xxx", 16, 43)` + +### Discovery + +Waku v2 supports the discovery of peers within static shards, +so app protocols do not have to implement their own discovery method. + +Nodes add information about their shard participation in their [31/WAKU2-ENR](https://rfc.vac.dev/spec/31/). +Having a static shard participation indication as part of the ENR allows nodes +to discover peers that are part of shards via [33/WAKU2-DISCV5](/spec/33/) as well as via DNS. + +> *Note:* In the current version of this document, +sharding information is directly added to the ENR. +(see Ethereum ENR sharding bit vector [here](https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/p2p-interface.md#metadata) +Static relay sharding supports 1024 shards per cluster, leading to a flag field of 128 bytes. +This already takes half (including index and key) of the ENR space of 300 bytes. +For this reason, the current specification only supports a single shard cluster per node. +In future versions, we will add further (hierarchical) discovery methods. +We will update [31/WAKU2-ENR](https://rfc.vac.dev/spec/31/) accordingly, once this RFC moves forward. + +This document specifies two ways of indicating shard cluster participation. +The index list SHOULD be used for nodes that participante in fewer than 64 shards, +the bit vector representation SHOULD be used for nodes participating in 64 or more shards. +Nodes MUST NOT use both index list (`rs`) and bit vector (`rsv`) in a single ENR. +ENRs with both `rs` and `rsv` keys SHOULD be ignored. +Nodes MAY interpret `rs` in such ENRs, but MUST ignore `rsv`. + +#### Index List + +| key | value | +|--- |--- | +| `rs` | <2-byte shard cluster index> | <1-byte length> | <2-byte shard index> | ... | <2-byte shard index> | + +The ENR key is `rs`. +The value is comprised of +* a two-byte shard cluster index in network byte order, concatenated with +* a one-byte length field holding the number of shards in the given shard cluster, concatenated with +* two-byte shard indices in network byte order + +Example: + +| key | value | +|--- |--- | +| `rs` | 16u16 | 3u8 | 13u16 | 14u16 | 45u16 | + +This example node is part of shards `13`, `14`, and `45` in the Status main-net shard cluster (index 16). + +#### Bit Vector + +| key | value | +|--- |--- | +| `rsv` | <2-byte shard cluster index> | <128-byte flag field> | + +The ENR key is `rsv`. +The value is comprised of a two-byte shard cluster index in network byte order concatenated with a 128-byte wide bit vector. +The bit vector indicates which shards of the respective shard cluster the node is part of. +The right-most bit in the bit vector represents shard `0`, the left-most bit represents shard `1023`. +The representation in the ENR is inspired by [Ethereum shard ENRs](https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/validator.md#sync-committee-subnet-stability)), +and [this](https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/validator.md#sync-committee-subnet-stability)). + +Example: + +| key | value | +|--- |--- | +| `rsv` | 16u16 | `0x[...]0000100000003000` | + +The `[...]` in the example indicates 120 `0` bytes. +This example node is part of shards `13`, `14`, and `45` in the Status main-net shard cluster (index 16). +(This is just for illustration purposes, a node that is only part of three shards should use the index list method specified above.) + +## Automatic Sharding + +Autosharding selects shards automatically and is the default behavior for shard choice. +The other choices being static and named sharding as seen in previous sections. +Shards (pubsub topics) SHOULD be computed from content topics with the procedure below. + +#### Algorithm + +Hash using Sha2-256 the concatenation of +the content topic `application` field (UTF-8 string of N bytes) and +the `version` (UTF-8 string of N bytes). +The shard to use is the modulo of the hash by the number of shards in the network. + +#### Example +| Field | Value | Hex +|--- |--- |--- +| `application` | "myapp"| 0x6d79617070 +| `version` | "1" | 0x31 +| `network shards`| 8 | 0x8 + +- SHA2-256 of `0x6d7961707031` is `0x8e541178adbd8126068c47be6a221d77d64837221893a8e4e53139fb802d4928` +- `0x8e541178adbd8126068c47be6a221d77d64837221893a8e4e53139fb802d4928` MOD `8` equals `0` +- The shard to use has index 0 + +### Content Topics Format for Autosharding +Content topics MUST follow the format in [23/WAKU2-TOPICS](https://rfc.vac.dev/spec/23/#content-topic-format). +In addition, a generation prefix MAY be added to content topics. +When omitted default values are used. +Generation default value is `0`. + +- The full length format is `/{generation}/{application-name}/{version-of-the-application}/{content-topic-name}/{encoding}` +- The short length format is `/{application-name}/{version-of-the-application}/{content-topic-name}/{encoding}` + +#### Example + +- Full length `/0/myapp/1/mytopic/cbor` +- Short length `/myapp/1/mytopic/cbor` + +#### Generation +The generation number monotonously increases and indirectly refers to the total number of shards of the Waku Network. + + + +#### Topic Design +Content topics have 2 purposes: filtering and routing. +Filtering is done by changing the `{content-topic-name}` field. +As this part is not hashed, it will not affect routing (shard selection). +The `{application-name}` and `{version-of-the-application}` fields do affect routing. +Using multiple content topics with different `{application-name}` field has advantages and disadvantages. +It increases the traffic a relay node is subjected to when subscribed to all topics. +It also allows relay and light nodes to subscribe to a subset of all topics. + +### Problems + +#### Hot Spots + +Hot spots occur (similar to DHTs), when a specific mesh network (shard) becomes responsible for (several) large multicast groups (content topics). +The opposite problem occurs when a mesh only carries multicast groups with very few participants: this might cause bad connectivity within the mesh. + +The current autosharding method does not solve this problem. + +> *Note:* Automatic sharding based on network traffic measurements to avoid hot spots in not part of this specification. + +#### Discovery + +For the discovery of automatic shards this document specifies two methods (the second method will be detailed in a future version of this document). + +The first method uses the discovery introduced above in the context of static shards. + +The second discovery method will be a successor to the first method, +but is planned to preserve the index range allocation. +Instead of adding the data to the ENR, it will treat each array index as a capability, +which can be hierarchical, having each shard in the indexed shard cluster as a sub-capability. +When scaling to a very large number of shards, this will avoid blowing up the ENR size, and allows efficient discovery. +We currently use [33/WAKU2-DISCV5](https://rfc.vac.dev/spec/33/) for discovery, +which is based on Ethereum's [discv5](https://github.com/ethereum/devp2p/blob/master/discv5/discv5.md). +While this allows to sample nodes from a distributed set of nodes efficiently and offers good resilience, +it does not allow to efficiently discover nodes with specific capabilities within this node set. +Our [research log post](https://vac.dev/wakuv2-apd) explains this in more detail. +Adding efficient (but still preserving resilience) capability discovery to discv5 is ongoing research. +[A paper on this](https://github.com/harnen/service-discovery-paper) has been completed, +but the [Ethereum discv5 specification](https://github.com/ethereum/devp2p/blob/master/discv5/discv5-theory.md) +has yet to be updated. +When the new capability discovery is available, +this document will be updated with a specification of the second discovery method. +The transition to the second method will be seamless and fully backwards compatible because nodes can still advertise and discover shard memberships in ENRs. + +## Security/Privacy Considerations + +See [45/WAKU2-ADVERSARIAL-MODELS](/spec/45), especially the parts on k-anonymity. +We will add more on security considerations in future versions of this document. + +### Receiver Anonymity + +The strength of receiver anonymity, i.e. topic receiver unlinkablity, +depends on the number of content topics (`k`), as a proxy for the number of peers and messages, that get mapped onto a single pubsub topic (shard). +For *named* and *static* sharding this responsibility is at the app protocol layer. + +## Copyright + +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). + +## References + +* [11/WAKU2-RELAY](/spec/11/) +* [Unstructured P2P network](https://en.wikipedia.org/wiki/Peer-to-peer#Unstructured_networks) +* [33/WAKU2-DISCV5](/spec/33/) +* [31/WAKU2-ENR](https://rfc.vac.dev/spec/31/) +* [23/WAKU2-TOPICS](/spec/23/) +* [51/WAKU2-RELAY-SHARDING](/spec/51/) +* [Ethereum ENR sharding bit vector](https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/p2p-interface.md#metadata) +* [Ethereum discv5 specification](https://github.com/ethereum/devp2p/blob/master/discv5/discv5-theory.md) +* [Research log: Waku Discovery](https://vac.dev/wakuv2-apd) +* [45/WAKU2-ADVERSARIAL-MODELS](/spec/45) From e1a8a85789d1a5aa714ad6b44519ed5bfc3fe089 Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Tue, 30 Jan 2024 13:43:58 -0500 Subject: [PATCH 21/81] Update and rename standards/core/relay-sharding.md to informational/relay-sharding.md --- {standards/core => informational}/relay-sharding.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename {standards/core => informational}/relay-sharding.md (99%) diff --git a/standards/core/relay-sharding.md b/informational/relay-sharding.md similarity index 99% rename from standards/core/relay-sharding.md rename to informational/relay-sharding.md index 78078d2..2b69169 100644 --- a/standards/core/relay-sharding.md +++ b/informational/relay-sharding.md @@ -3,7 +3,7 @@ title: RELAY-SHARDING name: Waku v2 Relay Sharding status: raw category: Standards Track -tags: waku/core +tags: informational editor: Daniel Kaiser contributors: - Simon-Pierre Vivier From 8d60cbe3244388066ccaf110fd6e7eddb2c81dd7 Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Tue, 30 Jan 2024 13:45:44 -0500 Subject: [PATCH 22/81] Update and rename informational/relay-sharding.md to standards/core/relay-sharding.md --- {informational => standards/core}/relay-sharding.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename {informational => standards/core}/relay-sharding.md (99%) diff --git a/informational/relay-sharding.md b/standards/core/relay-sharding.md similarity index 99% rename from informational/relay-sharding.md rename to standards/core/relay-sharding.md index 2b69169..78078d2 100644 --- a/informational/relay-sharding.md +++ b/standards/core/relay-sharding.md @@ -3,7 +3,7 @@ title: RELAY-SHARDING name: Waku v2 Relay Sharding status: raw category: Standards Track -tags: informational +tags: waku/core editor: Daniel Kaiser contributors: - Simon-Pierre Vivier From f937953961c080df16919e535c39d59023029414 Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Tue, 30 Jan 2024 13:47:04 -0500 Subject: [PATCH 23/81] Create relay-static-shard-alloc.md --- informational/relay-static-shard-alloc.md | 56 +++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 informational/relay-static-shard-alloc.md diff --git a/informational/relay-static-shard-alloc.md b/informational/relay-static-shard-alloc.md new file mode 100644 index 0000000..545975d --- /dev/null +++ b/informational/relay-static-shard-alloc.md @@ -0,0 +1,56 @@ +--- +title: RELAY-STATIC-SHARD-ALLOC +name: Waku v2 Relay Static Shard Allocation +status: raw +category: Informational +tags: waku/informational +editor: Daniel Kaiser +contributors: +--- + +## Abstract + +This document lists static shard flag index assignments (see [51/WAKU2-RELAY-SHARDING](/spec/51/). + +## Background + +Similar to the [IANA port allocation](https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml), +this document lists static shard index assignments (see [51/WAKU2-RELAY-SHARDING](/spec/51/). + +## Assingment Process + +> *Note*: Future versions of this document will specify the assignment process. + +### List of Cluster Ids + +| index | Protocol/App | Description | +| --- | --- | --- | +| 0 | global | global use | +| 1 | reserved | [The Waku Network](https://rfc.vac.dev/spec/64/#network-shards) | +| 2 | reserved | | +| 3 | reserved | | +| 4 | reserved | | +| 5 | reserved | | +| 6 | reserved | | +| 7 | reserved | | +| 8 | reserved | | +| 9 | reserved | | +| 10 | reserved | | +| 11 | reserved | | +| 12 | reserved | | +| 13 | reserved | | +| 14 | reserved | | +| 15 | reserved | | +| 16 | Status | Status main net | +| 17 | Status | | +| 18 | Status | | + + +## Copyright + +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). + +# References + +* [51/WAKU2-RELAY-SHARDING](/spec/51/) +* [IANA port allocation](https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml) From 7e4ebf97ae1f91d9b370bdd52262dda70eb92109 Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Tue, 30 Jan 2024 14:06:13 -0500 Subject: [PATCH 24/81] Create network.md --- standards/application/network.md | 304 +++++++++++++++++++++++++++++++ 1 file changed, 304 insertions(+) create mode 100644 standards/application/network.md diff --git a/standards/application/network.md b/standards/application/network.md new file mode 100644 index 0000000..22d6fd6 --- /dev/null +++ b/standards/application/network.md @@ -0,0 +1,304 @@ +--- +slug: 64 +title: 64/WAKU2-NETWORK +name: Waku v2 Network +status: raw +category: Best Current Practice +editor: Hanno Cornelius +contributors: +--- + +# Abstract + +This RFC specifies an opinionated deployment of [10/WAKU2](https://rfc.vac.dev/spec/10/) protocols +to form a coherent and shared decentralized messaging network +that is open-access, +useful for generalized messaging, +privacy-preserving, +scalable and +accessible even to resource-restricted devices. +We'll refer to this opinionated deployment simply as +_the public Waku Network_, _the Waku Network_ or, if the context is clear, _the network_ +in the rest of this document. + +# Theory / Semantics + +## Routing protocol + +The Waku Network is built on the [17/WAKU2-RLN-RELAY](https://rfc.vac.dev/spec/17/) routing protocol, +which in turn is an extension of [11/WAKU2-RELAY](https://rfc.vac.dev/spec/11/) with spam protection measures. + +## Network shards + +Traffic in the Waku Network is sharded into eight [17/WAKU2-RLN-RELAY](https://rfc.vac.dev/spec/17/) pubsub topics. +Each pubsub topic is named according to the static shard naming format +defined in [51/WAKU2-RELAY-SHARDING](https://rfc.vac.dev/spec/51/) +with: +* `` set to `1` +* `` occupying the range `0` to `7`. +In other words, the Waku Network is a [17/WAKU2-RLN-RELAY](https://rfc.vac.dev/spec/17/) network +routed on the combination of the eight pubsub topics: +``` +/waku/2/rs/1/0 +/waku/2/rs/1/1 +... +/waku/2/rs/1/7 +``` + +A node MUST use [WAKU-METADATA](https://rfc.vac.dev/spec/66/) protocol to identify the `` that every +inbound/outbound peer that attempts to connect supports. In any of the following cases, the node MUST trigger a disconnection: +* [WAKU-METADATA](https://rfc.vac.dev/spec/66/) dial fails. +* [WAKU-METADATA](https://rfc.vac.dev/spec/66/) reports an empty ``. +* [WAKU-METADATA](https://rfc.vac.dev/spec/66/) reports a `` different than `1`. + +## Roles + +There are two distinct roles evident in the network, those of: +1) nodes, and +2) applications. + +### Nodes + +Nodes are the individual software units +using [10/WAKU2](https://rfc.vac.dev/spec/10/) protocols to form a p2p messaging network. +Nodes, in turn, can participate in a shard as full relayers, i.e. _relay nodes_, +or by running a combination of protocols suitable for resource-restricted environments, i.e. _non-relay nodes_. +Nodes can also provide various services to the network, +such as storing historical messages or protecting the network against spam. +See the section on [default services](#default-services) for more. + +#### Relay nodes + +Relay nodes MUST follow [17/WAKU2-RLN-RELAY](https://rfc.vac.dev/spec/17/) +to route messages to other nodes in the network +for any of the pubsub topics [defined as the Waku Network shards](#network-shards). +Relay nodes MAY choose to subscribe to any of these shards, +but MUST be subscribed to at least one defined shard. +Each relay node SHOULD be subscribed to as many shards as it has resources to support. +If a relay node supports an encapsulating application, +it SHOULD be subscribed to all the shards servicing that application. +If resource restrictions prevent a relay node from servicing all shards used by the encapsulating application, +it MAY choose to support some shards as a non-relay node. + +#### Bootstrapping and discovery + +Nodes MAY use any method to bootstrap connection to the network, +but it is RECOMMENDED that each node retrieves a list of bootstrap peers to connect to using [EIP-1459 DNS-based discovery](https://eips.ethereum.org/EIPS/eip-1459). +Relay nodes SHOULD use [33/WAKU2-DISCV5](https://rfc.vac.dev/spec/33/) to continually discover other peers in the network. +Each relay node MUST encode its supported shards into its discoverable ENR +as described in [51/WAKU2-RELAY-SHARDING](https://rfc.vac.dev/spec/51/#discovery). +The ENR MUST be updated if the set of supported shards change. +A node MAY choose to ignore discovered peers that do not support any of the shards in its own subscribed set. + +#### Transports + +Relay nodes MUST follow [10/WAKU2](https://rfc.vac.dev/spec/10/) specifications with regards to supporting different transports. +If TCP transport is available, each relay node MUST support it as transport for both dialing and listening. +In addition, a relay node SHOULD support secure websockets for bidirectional communication streams, +for example to allow connections from and to web browser-based clients. +A relay node MAY support unsecure websockets if required by the application or running environment. + +#### Default services + +For each supported shard, +each relay node SHOULD enable and support the following protocols as a service node: +1. [12/WAKU2-FILTER](https://rfc.vac.dev/spec/12/) to allow resource-restricted peers to subscribe to messages matching a specific content filter. +2. [13/WAKU2-STORE](https://rfc.vac.dev/spec/13/) to allow other peers to request historical messages from this node. +3. [19/WAKU2-LIGHTPUSH](https://rfc.vac.dev/spec/19/) to allow resource-restricted peers to request publishing a message to the network on their behalf. +4. [34/WAKU2-PEER-EXCHANGE](https://rfc.vac.dev/spec/34/) to allow resource-restricted peers to discover more peers in a resource efficient way. + +#### Store service nodes + +Each relay node SHOULD support [13/WAKU2-STORE](https://rfc.vac.dev/spec/13/) as a store service node, +for each supported shard. +The store SHOULD be configured to retain at least `12` hours of messages per supported shard. +Store service nodes SHOULD only store messages with a valid [`rate_limit_proof`](#message-attributes) attribute. + +#### Non-relay nodes + +Nodes MAY opt out of relay functionality on any network shard +and instead request services from relay nodes as clients +using any of the defined service protocols: +1. [12/WAKU2-FILTER](https://rfc.vac.dev/spec/12/) to subscribe to messages matching a specific content filter. +2. [13/WAKU2-STORE](https://rfc.vac.dev/spec/13/) to request historical messages matching a specific content filter. +3. [19/WAKU2-LIGHTPUSH](https://rfc.vac.dev/spec/19/) to request publishing a message to the network. +4. [34/WAKU2-PEER-EXCHANGE](https://rfc.vac.dev/spec/34/) to discover more peers in a resource efficient way. + +#### Store client nodes + +Nodes MAY request historical messages from [13/WAKU2-STORE](https://rfc.vac.dev/spec/13/) service nodes as store clients. +A store client SHOULD discard any messages retrieved from a store service node that do not contain a valid [`rate_limit_proof`](#message-attributes) attribute. +The client MAY consider service nodes returning messages without a valid [`rate_limit_proof`](#message-attributes) attribute as untrustworthy. +The mechanism by which this may happen is currently underdefined. + +### Applications + +Applications are the higher-layer projects or platforms that make use of the generalized messaging capability of the network. +In other words, an application defines a payload used in the various [10/WAKU2](https://rfc.vac.dev/spec/10/) protocols. +Any participant in an application SHOULD make use of an underlying node in order to communicate on the network. +Applications SHOULD make use of an [autosharding](#autosharding) API +to allow the underlying node to automatically select the target shard on the Waku Network. See the section on [autosharding](#autosharding) for more. + +## RLN rate-limiting + +The [17/WAKU2-RLN-RELAY](https://rfc.vac.dev/spec/17/) network uses [32/RLN-V1](https://rfc.vac.dev/spec/32/) proofs +to ensure that a pre-agreed rate limit is not exceeded by any publisher. +While the network is under capacity, +individual relayers MAY choose to freely route messages without RLN proofs +up to a discretionary bandwidth limit after which messages without proofs MUST be discarded. +This bandwidth limit SHOULD be enforced using [bandwidth validation mechanism](#free-bandwidth-exceeded) separate from RLN rate-limiting. +This implies that quality of service and reliability is significantly lower for messages without proofs +and at times of high network utilization these messages may not be relayed at all. + +### RLN Parameters + +For the Waku Network, +the `epoch` is set to `1` second +and the maximum number of messages published per `epoch` is limited to `1` per publisher. +The `max_epoch_gap` is set to `20` seconds, +meaning that validators MUST _reject_ messages with an `epoch` more than 20 seconds into the past or future compared to the validator's own clock. +All nodes, validators and publishers, +SHOULD use Network Time Protocol (NTP) to synchronize their own clocks, +thereby ensuring valid timestamps for proof generation and validation. + +### Memberships + +Each publisher to the Waku Network SHOULD register an RLN membership +with one of the RLN storage contracts +moderated in the Sepolia registry contract with address [0xF1935b338321013f11068abCafC548A7B0db732C](https://sepolia.etherscan.io/address/0xF1935b338321013f11068abCafC548A7B0db732C#code). +Initial memberships are registered in the Sepolia RLN storage contract with address [0x58322513A35a8f747AF5A385bA14C2AbE602AA59](https://sepolia.etherscan.io/address/0x58322513A35a8f747AF5A385bA14C2AbE602AA59#code). +RLN membership setup and registration MUST follow [17/WAKU-RLN-RELAY](https://rfc.vac.dev/spec/17/#setup-and-registration), +with the `staked_fund` set to `0`. +In other words, the Waku Network does not use RLN staking. + +### RLN Proofs + +Each RLN member MUST generate and attach an RLN proof to every published message +as described in [17/WAKU-RLN-RELAY](https://rfc.vac.dev/spec/17/#publishing). +Slashing is not implemented for the Waku Network. +Instead, validators will penalise peers forwarding messages exceeding the rate limit +as specified for [the rate-limiting validation mechanism](#rate-limit-exceeded). +This incentivizes all nodes to validate RLN proofs +and reject messages violating rate limits +in order to continue participating in the network. + +## Network traffic + +All payload on the Waku Network MUST be encapsulated in a [14/WAKU2-MESSAGE](https://rfc.vac.dev/spec/14/) +with rate limit proof extensions defined for [17/WAKU2-RLN-RELAY](https://rfc.vac.dev/spec/17/#payloads). +Each message on the Waku Network SHOULD be validated by each relayer, +according to the rules discussed under [message validation](#message-validation). + +### Message Attributes + +- The mandatory `payload` attribute MUST contain the message data payload as crafted by the application. +- The mandatory `content_topic` attribute MUST specify a string identifier that can be used for content-based filtering. This is also crafted by the application. See [Autosharding](#autosharding) for more on the content topic format. +- The optional `meta` attribute MAY be omitted. If present this will form part of the message uniqueness vector described in [14/WAKU2-MESSAGE](https://rfc.vac.dev/spec/14/). +- The optional `version` attribute SHOULD be set to `0`. It MUST be interpreted as `0` if not present. +- The mandatory `timestamp` attribute MUST contain the Unix epoch time at which the message was generated by the application. The value MUST be in nanoseconds. It MAY contain a fudge factor of up to 1 seconds in either direction to improve resistance to timing attacks. +- The optional `ephemeral` attribute MUST be set to `true` if the message should not be persisted by the Waku Network. +- The optional `rate_limit_proof` attribute SHOULD be populated with the RLN proof as set out in [RLN Proofs](#rln-proofs). Messages with this field unpopulated MAY be discarded from the network by relayers. This field MUST be populated if the message should be persisted by the Waku Network. + +### Message Size + +Any Waku Message published to the network MUST NOT exceed an absolute maximum size of `150` kilobytes. +This limit applies to the entire message after protobuf serialization, including attributes. +It is RECOMMENDED not to exceed an average size of `4` kilobytes for Waku Messages published to the network. + +### Message Validation + +Relay nodes MUST apply [gossipsub v1.1 validation](https://github.com/libp2p/specs/blob/c96c9ec5909d64fe020d7630f3fd982bc18fd06a/pubsub/gossipsub/gossipsub-v1.1.md#extended-validators) to each relayed message and +SHOULD apply all of the rules set out in the section below to determine the validity of a message. +Validation has one of three outcomes, +repeated here from the [gossipsub specification](https://github.com/libp2p/specs/blob/c96c9ec5909d64fe020d7630f3fd982bc18fd06a/pubsub/gossipsub/gossipsub-v1.1.md#extended-validators) for ease of reference: +1. Accept - the message is considered valid and it MUST be delivered and forwarded to the network. +2. Reject - the message is considered invalid, MUST be rejected and SHOULD trigger a gossipsub scoring penalty against the transmitting peer. +3. Ignore - the message SHOULD NOT be delivered and forwarded to the network, but this MUST NOT trigger a gossipsub scoring penalty against the transmitting peer. + +The following validation rules are defined: + +#### Decoding failure + +If a message fails to decode as a valid [14/WAKU2-MESSAGE](https://rfc.vac.dev/spec/14/). +the relay node MUST _reject_ the message. +This SHOULD trigger a penalty against the transmitting peer. + +#### Invalid timestamp + +If a message has a timestamp deviating by more than `20` seconds +either into the past or the future +when compared to the relay node's internal clock, +the relay node MUST _reject_ the message. +This allows for some deviation between internal clocks, +network routing latency and +an optional [fudge factor when timestamping new messages](#message-attributes). + +#### Free bandwidth exceeded + +If a message contains no RLN proof +and the current bandwidth utilization on the shard the message was published to +equals or exceeds `1` Mbps, +the relay node SHOULD _ignore_ the message. + +#### Invalid RLN epoch + +If a message contains an RLN proof +and the `epoch` attached to the proof deviates by more than `max_epoch_gap` seconds +from the relay node's own `epoch`, +the relay node MUST _reject_ the message. +`max_epoch_gap` is [set to `20` seconds](#rln-parameters) for the Waku Network. + +#### Invalid RLN proof + +If a message contains an RLN proof +and the zero-knowledge proof is invalid +according to the verification process described in [32/RLN-V1](https://rfc.vac.dev/spec/32/#verification), +the relay node MUST _ignore_ the message. + +#### Rate limit exceeded + +If a message contains an RLN proof +and the relay node detects double signaling +according to the verification process described in [32/RLN-V1](https://rfc.vac.dev/spec/32/#verification), +the relay node MUST _reject_ the message +for violating the agreed rate limit of `1` message every `1` second. +This SHOULD trigger a penalty against the transmitting peer. + +## Autosharding + +Nodes in the Waku Network SHOULD allow encapsulating applications to use autosharding, +as defined in [51/WAKU2-RELAY-SHARDING](https://rfc.vac.dev/spec/51/#automatic-sharding) +by automatically determining the appropriate pubsub topic +from the list [of defined Waku Network shards](#network-shards). +This allows the application to omit the target pubsub topic +when invoking any Waku protocol function. +Applications using autosharding MUST use content topics in the format +defined in [51/WAKU2-RELAY-SHARDING](https://rfc.vac.dev/spec/51/#content-topics-format-for-autosharding) +and SHOULD use the short length format: + +``` +/{application-name}/{version-of-the-application}/{content-topic-name}/{encoding}` +``` + +When an encapsulating application makes use of autosharding +the underlying node MUST determine the target pubsub topic(s) +from the content topics provided by the application +using the hashing mechanism defined in [51/WAKU2-RELAY-SHARDING](https://rfc.vac.dev/spec/51/#automatic-sharding). + + +# Copyright + +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). + +# References + +(TBD) + +## normative +(TBD) +A list of references that MUST be read to fully understand and/or implement this protocol. +See [RFC3967 Section 1.1](https://datatracker.ietf.org/doc/html/rfc3967#section-1.1). + +## informative +(TBD) +A list of additional references. From 0e2b38660a66b4b1e6ce45621e9f0a1062ed5fa9 Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Tue, 30 Jan 2024 14:06:57 -0500 Subject: [PATCH 25/81] Create metadata.md --- standards/application/metadata.md | 39 +++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 standards/application/metadata.md diff --git a/standards/application/metadata.md b/standards/application/metadata.md new file mode 100644 index 0000000..e034fc9 --- /dev/null +++ b/standards/application/metadata.md @@ -0,0 +1,39 @@ +--- +slug: 66 +title: 66/WAKU2-METADATA +name: Waku Metadata Protocol +status: raw +editor: Alvaro Revuelta +contributors: +--- + +# Metadata Protocol + +Waku specifies a req/resp protocol that provides information about the node's medatadata. Such metadata is meant to be used +by the node to decide if a peer is worth connecting or not. The node that makes the request, includes its metadata +so that the receiver is aware of it, without requiring an extra interaction. The parameters are the following: +* `clusterId`: Unique identifier of the cluster that the node is running in. +* `shards`: Shard indexes that the node is subscribed to. + + +## Protocol id + +`/vac/waku/metadata/1.0.0` + +## Request + +```proto +message WakuMetadataRequest { + optional uint32 cluster_id = 1; + repeated uint32 shards = 2; +} +``` + +## Response + +```proto +message WakuMetadataResponse { + optional uint32 cluster_id = 1; + repeated uint32 shards = 2; +} +``` From a336c055db4da571186a3cbe4ad8efd2f245a6d8 Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Tue, 30 Jan 2024 14:09:37 -0500 Subject: [PATCH 26/81] Rename standards/core/peer-exchange.md to standards/core/peer-exchange/peer-exchange.md --- standards/core/{ => peer-exchange}/peer-exchange.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename standards/core/{ => peer-exchange}/peer-exchange.md (100%) diff --git a/standards/core/peer-exchange.md b/standards/core/peer-exchange/peer-exchange.md similarity index 100% rename from standards/core/peer-exchange.md rename to standards/core/peer-exchange/peer-exchange.md From 1bd71238f628f60f6b48ddc2612d3072a3d2586d Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Tue, 30 Jan 2024 14:11:17 -0500 Subject: [PATCH 27/81] Add files via upload --- standards/core/peer-exchange/protocol.svg | 118 ++++++++++++++++++++++ 1 file changed, 118 insertions(+) create mode 100644 standards/core/peer-exchange/protocol.svg diff --git a/standards/core/peer-exchange/protocol.svg b/standards/core/peer-exchange/protocol.svg new file mode 100644 index 0000000..dda2157 --- /dev/null +++ b/standards/core/peer-exchange/protocol.svg @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 26b9a5c3debb83c2d17bb48a06494f83dafee961 Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Tue, 30 Jan 2024 14:11:51 -0500 Subject: [PATCH 28/81] Rename standards/core/peer-exchange/protocol.svg to standards/core/peer-exchange/images/protocol.svg --- standards/core/peer-exchange/{ => images}/protocol.svg | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename standards/core/peer-exchange/{ => images}/protocol.svg (100%) diff --git a/standards/core/peer-exchange/protocol.svg b/standards/core/peer-exchange/images/protocol.svg similarity index 100% rename from standards/core/peer-exchange/protocol.svg rename to standards/core/peer-exchange/images/protocol.svg From e9336d7da826bcda2f6817d967b93ff77a37443a Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Mon, 5 Feb 2024 14:14:21 -0500 Subject: [PATCH 29/81] Update dandelion.md --- standards/application/dandelion.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/standards/application/dandelion.md b/standards/application/dandelion.md index 5316169..da48cbb 100644 --- a/standards/application/dandelion.md +++ b/standards/application/dandelion.md @@ -12,7 +12,7 @@ contributors: This document specifies a deanonymization mitigation technique, based on [Dandelion](https://arxiv.org/abs/1701.04439) and [Dandelion++](https://arxiv.org/abs/1805.11060), for Waku Relay. -It mitigates mass deanonymization in the [multi-node (botnet) attacker model](/spec/45/#multi-node), +It mitigates mass deanonymization in the [multi-node (botnet) attacker model](../../informational/adversarial-models.md/#multi-node), even when the number of malicious nodes is linear in the number of total nodes in the network. Based on the insight that symmetric message propagation makes deanonymization easier, @@ -170,7 +170,7 @@ If this is the case, they have to be implemented on the libp2p gossipsub layer. ### Denial of Service: Black Hole Attack -In a [black hole attack](/spec/45/#black-hole-internal), malicious nodes prevent messages from being spread, +In a [black hole attack](../../informational/adversarial-models.md/#black-hole-internal), malicious nodes prevent messages from being spread, metaphorically not allowing messages to leave once they entered. This requires the attacker to control nodes on all dissemination paths. Since the number of dissemination paths is significantly reduced in the stem phase, @@ -183,7 +183,7 @@ The fail-safe mechanism specified in this document (proposed in the Dandelion pa #### Attacker Model and Anonymity Goals 44/WAKU2-DANDELION provides significant mitigation against mass deanonymization in the -passive [scaling multi node model](/spec/45/#scaling-multi-node). +passive [scaling multi node model](../../informational/adversarial-models.md/#scaling-multi-node). in which the attacker controls a certain percentage of nodes in the network. 44/WAKU2-DANDELION provides significant mitigation against mass deanonymization even if the attacker knows the network topology, i.e. the anonymity graph and the relay mesh graph. @@ -286,6 +286,7 @@ Copyright and related rights waived via [CC0](https://creativecommons.org/public * [Dandelion](https://arxiv.org/abs/1701.04439) * [Dandelion++](https://arxiv.org/abs/1805.11060) +* [multi-node (botnet) attacker model](../../informational/adversarial-models.md/#multi-node) * [Waku Relay](https://rfc.vac.dev/spec/11/) * [Waku v2](https://rfc.vac.dev/spec/10/) * [d-regular graph](https://en.wikipedia.org/wiki/Regular_graph) From 57dc6b2d46e64ec8fb1f0717cb6bbdadc3709f5b Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Mon, 5 Feb 2024 14:15:24 -0500 Subject: [PATCH 30/81] Update metadata.md --- standards/application/metadata.md | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/standards/application/metadata.md b/standards/application/metadata.md index e034fc9..0bd9660 100644 --- a/standards/application/metadata.md +++ b/standards/application/metadata.md @@ -1,13 +1,11 @@ --- -slug: 66 -title: 66/WAKU2-METADATA +title: WAKU2-METADATA name: Waku Metadata Protocol -status: raw editor: Alvaro Revuelta contributors: --- -# Metadata Protocol +## Metadata Protocol Waku specifies a req/resp protocol that provides information about the node's medatadata. Such metadata is meant to be used by the node to decide if a peer is worth connecting or not. The node that makes the request, includes its metadata @@ -16,11 +14,11 @@ so that the receiver is aware of it, without requiring an extra interaction. The * `shards`: Shard indexes that the node is subscribed to. -## Protocol id +### Protocol id `/vac/waku/metadata/1.0.0` -## Request +### Request ```proto message WakuMetadataRequest { @@ -29,7 +27,7 @@ message WakuMetadataRequest { } ``` -## Response +### Response ```proto message WakuMetadataResponse { From cf6b9203b9b9b0cb2dd0af7a07b59a20f7097733 Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Mon, 5 Feb 2024 14:22:22 -0500 Subject: [PATCH 31/81] Update network.md --- standards/application/network.md | 34 ++++++++++++++++---------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/standards/application/network.md b/standards/application/network.md index 22d6fd6..cb7dbae 100644 --- a/standards/application/network.md +++ b/standards/application/network.md @@ -1,14 +1,12 @@ --- -slug: 64 -title: 64/WAKU2-NETWORK +title: WAKU2-NETWORK name: Waku v2 Network -status: raw category: Best Current Practice editor: Hanno Cornelius contributors: --- -# Abstract +## Abstract This RFC specifies an opinionated deployment of [10/WAKU2](https://rfc.vac.dev/spec/10/) protocols to form a coherent and shared decentralized messaging network @@ -21,18 +19,18 @@ We'll refer to this opinionated deployment simply as _the public Waku Network_, _the Waku Network_ or, if the context is clear, _the network_ in the rest of this document. -# Theory / Semantics +## Theory / Semantics -## Routing protocol +### Routing protocol The Waku Network is built on the [17/WAKU2-RLN-RELAY](https://rfc.vac.dev/spec/17/) routing protocol, which in turn is an extension of [11/WAKU2-RELAY](https://rfc.vac.dev/spec/11/) with spam protection measures. -## Network shards +### Network shards Traffic in the Waku Network is sharded into eight [17/WAKU2-RLN-RELAY](https://rfc.vac.dev/spec/17/) pubsub topics. Each pubsub topic is named according to the static shard naming format -defined in [51/WAKU2-RELAY-SHARDING](https://rfc.vac.dev/spec/51/) +defined in [WAKU2-RELAY-SHARDING](../../core/relay-sharding.md) with: * `` set to `1` * `` occupying the range `0` to `7`. @@ -45,11 +43,11 @@ routed on the combination of the eight pubsub topics: /waku/2/rs/1/7 ``` -A node MUST use [WAKU-METADATA](https://rfc.vac.dev/spec/66/) protocol to identify the `` that every +A node MUST use [WAKU-METADATA](./metadata.md) protocol to identify the `` that every inbound/outbound peer that attempts to connect supports. In any of the following cases, the node MUST trigger a disconnection: -* [WAKU-METADATA](https://rfc.vac.dev/spec/66/) dial fails. -* [WAKU-METADATA](https://rfc.vac.dev/spec/66/) reports an empty ``. -* [WAKU-METADATA](https://rfc.vac.dev/spec/66/) reports a `` different than `1`. +* [WAKU-METADATA](./metadata.md) dial fails. +* [WAKU-METADATA](./metadata.md) reports an empty ``. +* [WAKU-METADATA](./metadata.md) reports a `` different than `1`. ## Roles @@ -105,7 +103,7 @@ each relay node SHOULD enable and support the following protocols as a service n 1. [12/WAKU2-FILTER](https://rfc.vac.dev/spec/12/) to allow resource-restricted peers to subscribe to messages matching a specific content filter. 2. [13/WAKU2-STORE](https://rfc.vac.dev/spec/13/) to allow other peers to request historical messages from this node. 3. [19/WAKU2-LIGHTPUSH](https://rfc.vac.dev/spec/19/) to allow resource-restricted peers to request publishing a message to the network on their behalf. -4. [34/WAKU2-PEER-EXCHANGE](https://rfc.vac.dev/spec/34/) to allow resource-restricted peers to discover more peers in a resource efficient way. +4. [34/WAKU2-PEER-EXCHANGE](../../core/peer-exchange/peer-exchange.md) to allow resource-restricted peers to discover more peers in a resource efficient way. #### Store service nodes @@ -122,7 +120,7 @@ using any of the defined service protocols: 1. [12/WAKU2-FILTER](https://rfc.vac.dev/spec/12/) to subscribe to messages matching a specific content filter. 2. [13/WAKU2-STORE](https://rfc.vac.dev/spec/13/) to request historical messages matching a specific content filter. 3. [19/WAKU2-LIGHTPUSH](https://rfc.vac.dev/spec/19/) to request publishing a message to the network. -4. [34/WAKU2-PEER-EXCHANGE](https://rfc.vac.dev/spec/34/) to discover more peers in a resource efficient way. +4. [34/WAKU2-PEER-EXCHANGE](../../core/peer-exchange/peer-exchange.md) to discover more peers in a resource efficient way. #### Store client nodes @@ -286,13 +284,15 @@ from the content topics provided by the application using the hashing mechanism defined in [51/WAKU2-RELAY-SHARDING](https://rfc.vac.dev/spec/51/#automatic-sharding). -# Copyright +## Copyright Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). -# References +## References + +* [WAKU2-RELAY-SHARDING](../../core/relay-sharding.md) +* [Peer-exchange](../../core/peer-exchange/peer-exchange.md) -(TBD) ## normative (TBD) From 30cd4bc29f4bb2c2120a297d809c9686318ebc8c Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Mon, 5 Feb 2024 14:26:18 -0500 Subject: [PATCH 32/81] Update noise-sessions.md --- standards/core/noise-sessions/noise-sessions.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/standards/core/noise-sessions/noise-sessions.md b/standards/core/noise-sessions/noise-sessions.md index 8aefa13..f0962d3 100644 --- a/standards/core/noise-sessions/noise-sessions.md +++ b/standards/core/noise-sessions/noise-sessions.md @@ -8,7 +8,7 @@ contributors: ## Introduction -In [35/WAKU2-NOISE](https://rfc.vac.dev/35/) we defined how Waku messages' payloads can be encrypted using key material derived from key agreements based on the [Noise Protocol Framework](http://www.noiseprotocol.org/noise.html). +In [WAKU2-NOISE](../noise.md) we defined how Waku messages' payloads can be encrypted using key material derived from key agreements based on the [Noise Protocol Framework](http://www.noiseprotocol.org/noise.html). Once two users complete a Noise handshake, an encryption/decryption session - _or a Noise session_ - would be instantiated. @@ -37,14 +37,14 @@ since it is required to either retrieve and encrypt/decrypt any further exchange Once a Noise session is instantiated, any further encrypted message between Alice and Bob within this session is exchanged on a `contentTopic` with name `/{application-name}/{application-version}/wakunoise/1/sessions/{ct-id}/proto`, where `ct-id = Hash(Hash(session-id))` -and `/{application-name}/{application-version}/` identifies the application currently employing [35/WAKU2-NOISE](https://rfc.vac.dev/35/). +and `/{application-name}/{application-version}/` identifies the application currently employing [WAKU2-NOISE](../noise.md). ## Session states A Noise session corresponding to a certain `session-id`: - is always **active** as long as it is not marked as **stale**. For an active `session-id`, new messages are published on the content topic `/{application-name}/{application-version}/wakunoise/1/sessions/{ct-id}/proto`; -- is marked as **stale** if a [session termination message](https://rfc.vac.dev/spec/35/#session-termination-message) containing `Hash(session-id)` is published on the content topic `/{application-name}/{application-version}/wakunoise/1/sessions/{ct-id}/proto`. +- is marked as **stale** if a [session termination message](../noise.md/#session-termination-message) containing `Hash(session-id)` is published on the content topic `/{application-name}/{application-version}/wakunoise/1/sessions/{ct-id}/proto`. Session information relative to stale sessions MAY be deleted from users' device, unless required for later channel binding purposes. When a Noise session is marked as stale, it means that one party requested its termination while being online, @@ -68,7 +68,7 @@ and parties are required to instantiate a new Noise session if they wish to comm However, parties can optionally persist and include the `session-id` corresponding to a stale Noise session in the [prologue information](https://noiseprotocol.org/noise.html#prologue) employed in the Noise handshake they execute to instantiate their new Noise session. This effectively emulates a mechanism to _"re-activate"_ a stale Noise session by binding it to a newly created active Noise session. -In order to reduce users' metadata leakage, it is desirable (as suggested in [35/WAKU2-NOISE](https://rfc.vac.dev/spec/35/#after-handshake)) that content topics used for communications change every time a new message is exchanged. +In order to reduce users' metadata leakage, it is desirable (as suggested in [WAKU2-NOISE](../noise.md/#after-handshake)) that content topics used for communications change every time a new message is exchanged. This can be easily realized by employing a key derivation function to compute a new `session-id` from the previously employed one (e.g. `session-id = HKDF(prev-session-id)`), while keeping the Inbound/outbound Cipher States, the content topic derivation mechanism and the stale mechanism the same as above. In this case, when one party sends **and** receives at least one message, @@ -113,7 +113,7 @@ such two devices stop to reciprocally propagate any information regarding Noise As regards security, an attacker that compromises an encrypted message propagating session information, might be able to compromise one or multiple messages exchanged within the session such information refers to. -This can be mitigated by adopting techniques similar to the the ones proposed in [35/WAKU2-NOISE](https://rfc.vac.dev/spec/35/#after-handshake), +This can be mitigated by adopting techniques similar to the the ones proposed in [WAKU2-NOISE](../noise.md/#after-handshake), where encryption keys are changed every time a new message is exchanged. This session management mechanism is loosely based on the paper ["Multi-Device for Signal"](https://eprint.iacr.org/2019/1363.pdf). @@ -149,7 +149,7 @@ This session management mechanism is loosely based on [Signal's Sesame Algorithm # References - [13/WAKU2-STORE](https://rfc.vac.dev/spec/13/) -- [35/WAKU2-NOISE](https://rfc.vac.dev/35/) +- [WAKU2-NOISE](../noise.md) - [The Noise Protocol Framework](http://www.noiseprotocol.org/noise.html) - [The Sesame Algorithm: Session Management for Asynchronous Message Encryption](https://signal.org/docs/specifications/sesame/) - ["Multi-Device for Signal"](https://eprint.iacr.org/2019/1363.pdf) From c9b5fd5cc4e1e5cd6b7f9b2ec265dac3e6d05468 Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Mon, 5 Feb 2024 14:29:06 -0500 Subject: [PATCH 33/81] Update peer-exchange.md --- standards/core/peer-exchange/peer-exchange.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/standards/core/peer-exchange/peer-exchange.md b/standards/core/peer-exchange/peer-exchange.md index 0441e17..f91d1e0 100644 --- a/standards/core/peer-exchange/peer-exchange.md +++ b/standards/core/peer-exchange/peer-exchange.md @@ -31,10 +31,10 @@ This protocol SHOULD only be used if [33/WAKU2-DISCV5](/spec/33/) is infeasible. The peer exchange protocol specified in this document is a simple request-response protocol. As Figure 1 illustrates, the requesting node sends a request to a peer, which acts as the responder. -The responder replies with a list of ENRs as specified in [31/WAKU2-ENR](/spec/31/). +The responder replies with a list of ENRs as specified in [WAKU2-ENR](../enr.md). The [multiaddresses](https://docs.libp2p.io/concepts/addressing/) used to connect to the respective peers can be extracted from the ENRs. -![Figure 1: The responder provides a list of ENRs to the requester. These ENRs contain the information necessary for connecting to the respective peers.](/rfcs/34/protocol.svg) +![Figure 1: The responder provides a list of ENRs to the requester. These ENRs contain the information necessary for connecting to the respective peers.](./images/protocol.svg) In order to protect its anonymity, the responder MUST NOT provide peers from its actively used peer list as this opens pathways to *Neighbourhood Surveillance* attacks, as described in the [Security/Privacy Considerations Section](#securityprivacy-considerations). @@ -81,7 +81,7 @@ message PeerExchangeRPC { ``` -The `enr` field contains a Waku ENR as specified in [31/WAKU2-ENR](/spec/31/). +The `enr` field contains a Waku ENR as specified in [WAKU2-ENR](../enr.md). Requesters send a `PeerExchangeQuery` to a peer. Responders SHOULD include a maximum of `num_peers` `PeerInfo` instances into a response. @@ -146,7 +146,7 @@ Still, frequent queries can tigger the refresh cycle more often. The `seen cache ### Further Considerations -The response field contains ENRs as specified in [31/WAKU2-ENR](/spec/31/). +The response field contains ENRs as specified in [WAKU2-ENR](../enr.md). While ENRs contain signatures, they do not violate the [Waku relay no-sign policy](/spec/11/#signature-policy)), because they are part of the discovery domain and are not propagated in the relay domain. However, there might still be some form of leakage: @@ -160,7 +160,7 @@ Copyright and related rights waived via [CC0](https://creativecommons.org/public ## References * [33/WAKU2-DISCV5](/spec/33/) -* [31/WAKU2-ENR](/spec/31/) +* [WAKU2-ENR](../enr.md) * [multiaddress](https://docs.libp2p.io/concepts/addressing/) * [libp2p discovery interface](https://github.com/status-im/nim-libp2p/issues/140) * [libp2p gossipsub](https://github.com/libp2p/specs/blob/master/pubsub/gossipsub/gossipsub-v1.1.md) From 3a3f17d01e92e4a05682a01ff94632841a1cd557 Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Mon, 5 Feb 2024 14:34:51 -0500 Subject: [PATCH 34/81] Update device-pairing.md --- standards/core/device-pairing.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/standards/core/device-pairing.md b/standards/core/device-pairing.md index 8a215ec..cca3de6 100644 --- a/standards/core/device-pairing.md +++ b/standards/core/device-pairing.md @@ -15,7 +15,7 @@ and securely exchange (arbitrary) information over the Waku network. ## Background / Rationale / Motivation -In order to implement multi-device communications using one of the Noise session management mechanisms proposed in [37/WAKU2-NOISE-SESSIONS](https://rfc.vac.dev/spec/37/), +In order to implement multi-device communications using one of the Noise session management mechanisms proposed in [WAKU2-NOISE-SESSIONS](./noise-sessions/noise-sessions.md), we require a protocol to securely exchange (cryptographic) information between 2 or more devices possessed by a user. Since, in this scenario, the devices would be close to each other, @@ -96,7 +96,7 @@ d. -> sA, sAeB, sAsB {s} 3. The device `B`: - sets `contentTopic = /{application-name}/{application-version}/wakunoise/1/sessions_shard-{shard-id}/proto`; - - listens to messages sent to `contentTopic` and locally filters only those with [Waku payload](https://rfc.vac.dev/spec/35/#abnf) starting with `messageNametag`. If any, continues. + - listens to messages sent to `contentTopic` and locally filters only those with [Waku payload](./noise.md/#abnf) starting with `messageNametag`. If any, continues. - initializes the Noise handshake by passing `contentTopicParams`, `messageNametag` and `Hash(sB||r)` to the handshake prologue; - executes the pre-handshake message, i.e. processes its ephemeral key `eB`; - executes the first handshake message, i.e. @@ -243,7 +243,7 @@ TransferPhase: ### Messages Nametag Derivation To reduce metadata leakages and increase devices's anonymity over the p2p network, -[35/WAKU2-NOISE](https://rfc.vac.dev/spec/37/#session-states) suggests to use some common secrets `mntsInbound, mntsOutbound` (e.g. `mntsInbound, mntsOutbound = HKDF(h)` +[WAKU2-NOISE](./noise.md/#session-states) suggests to use some common secrets `mntsInbound, mntsOutbound` (e.g. `mntsInbound, mntsOutbound = HKDF(h)` where `h` is the [handshake hash value](https://noiseprotocol.org/noise.html#overview-of-handshake-state-machine) of the Handshake State at some point of the pairing phase) in order to frequently and deterministically change the `messageNametag` of messages exchanged during the pairing and transfer phase - ideally, at each message exchanged. @@ -315,13 +315,13 @@ unless `mntsInbound`, `mntsOutbound` or the `messageNametag` buffer lists were c ### The N11M session management mechanism -In the [`N11M` session management mechanism](https://rfc.vac.dev/spec/37/#the-n11m-session-management-mechanism), +In the [`N11M` session management mechanism](./noise-sessions/noise-sessions.md/#the-n11m-session-management-mechanism), one of Alice's devices is already communicating with one of Bob's devices within an active Noise session, e.g. after a successful execution of a Noise handshake. Alice and Bob would then share some cryptographic key material, used to encrypt their communications. -According to [37/WAKU2-NOISE-SESSIONS](https://rfc.vac.dev/spec/37/) this information consists of: +According to [WAKU2-NOISE-SESSIONS](./noise-sessions/noise-sessions.md) this information consists of: - A `session-id` (32 bytes) - Two cipher state `CSOutbound`, `CSInbound`, where each of them contains: - an encryption key `k` (2x32bytes) @@ -330,7 +330,7 @@ According to [37/WAKU2-NOISE-SESSIONS](https://rfc.vac.dev/spec/37/) this inform for a total of **176 bytes** of information. -In a [`N11M`](https://rfc.vac.dev/spec/37/#the-n11m-session-management-mechanism) session mechanism scenario, +In a [`N11M`](./noise-sessions/noise-sessions.md/#the-n11m-session-management-mechanism) session mechanism scenario, all (synced) Alice's devices that are communicating with Bob share the same Noise session cryptographic material. Hence, if Alice wishes to add a new device, @@ -348,8 +348,8 @@ Copyright and related rights waived via [CC0](https://creativecommons.org/public ## References ### Normative -- [35/WAKU2-NOISE](https://rfc.vac.dev/spec/37/#session-states) -- [37/WAKU2-NOISE-SESSIONS](https://rfc.vac.dev/spec/37/) +- [35/WAKU2-NOISE](./noise.md/#session-states) +- [WAKU2-NOISE-SESSIONS](./noise-sessions/noise-sessions.md/) ### Informative - [26/WAKU2-PAYLOAD](https://rfc.vac.dev/spec/35/#abnf) From 933f8c29798845d1a97d49dbf99a27ea303f521a Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Mon, 5 Feb 2024 14:43:09 -0500 Subject: [PATCH 35/81] Update relay-sharding.md --- standards/core/relay-sharding.md | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/standards/core/relay-sharding.md b/standards/core/relay-sharding.md index 78078d2..03fdfaf 100644 --- a/standards/core/relay-sharding.md +++ b/standards/core/relay-sharding.md @@ -68,7 +68,7 @@ shard clusters are divided into ranges: | 0 - 15 | reserved | | 16 - 65535| app-defined networks | -The informational RFC [52/WAKU2-RELAY-STATIC-SHARD-ALLOC](/spec/52) lists the current index allocations. +The informational RFC [WAKU2-RELAY-STATIC-SHARD-ALLOC](../../informational/relay-static-shard-alloc.md) lists the current index allocations. The global shard with index 0 and the "all app protocols" range are treated in the same way, but choosing shards in the global cluster has a higher probability of sharing the shard with other apps. @@ -100,7 +100,7 @@ And for shard 43 of the Status app (which has allocated index 16): Waku v2 supports the discovery of peers within static shards, so app protocols do not have to implement their own discovery method. -Nodes add information about their shard participation in their [31/WAKU2-ENR](https://rfc.vac.dev/spec/31/). +Nodes add information about their shard participation in their [WAKU2-ENR](./enr.md/). Having a static shard participation indication as part of the ENR allows nodes to discover peers that are part of shards via [33/WAKU2-DISCV5](/spec/33/) as well as via DNS. @@ -111,7 +111,7 @@ Static relay sharding supports 1024 shards per cluster, leading to a flag field This already takes half (including index and key) of the ENR space of 300 bytes. For this reason, the current specification only supports a single shard cluster per node. In future versions, we will add further (hierarchical) discovery methods. -We will update [31/WAKU2-ENR](https://rfc.vac.dev/spec/31/) accordingly, once this RFC moves forward. +We will update [WAKU2-ENR](./enr.md) accordingly, once this RFC moves forward. This document specifies two ways of indicating shard cluster participation. The index list SHOULD be used for nodes that participante in fewer than 64 shards, @@ -252,7 +252,7 @@ The transition to the second method will be seamless and fully backwards compati ## Security/Privacy Considerations -See [45/WAKU2-ADVERSARIAL-MODELS](/spec/45), especially the parts on k-anonymity. +See [WAKU2-ADVERSARIAL-MODELS](../../informational/adersarial-models.md), especially the parts on k-anonymity. We will add more on security considerations in future versions of this document. ### Receiver Anonymity @@ -270,10 +270,9 @@ Copyright and related rights waived via [CC0](https://creativecommons.org/public * [11/WAKU2-RELAY](/spec/11/) * [Unstructured P2P network](https://en.wikipedia.org/wiki/Peer-to-peer#Unstructured_networks) * [33/WAKU2-DISCV5](/spec/33/) -* [31/WAKU2-ENR](https://rfc.vac.dev/spec/31/) +* [WAKU2-ENR](./enr.md) * [23/WAKU2-TOPICS](/spec/23/) -* [51/WAKU2-RELAY-SHARDING](/spec/51/) * [Ethereum ENR sharding bit vector](https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/p2p-interface.md#metadata) * [Ethereum discv5 specification](https://github.com/ethereum/devp2p/blob/master/discv5/discv5-theory.md) * [Research log: Waku Discovery](https://vac.dev/wakuv2-apd) -* [45/WAKU2-ADVERSARIAL-MODELS](/spec/45) +* [WAKU2-RELAY-STATIC-SHARD-ALLOC](../../informational/relay-static-shard-alloc.md) From 6f1e0d3aff4997f4327f0e08a161f5cd66c1b6c6 Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Mon, 5 Feb 2024 14:47:56 -0500 Subject: [PATCH 36/81] Update adversarial-models.md --- informational/adversarial-models.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/informational/adversarial-models.md b/informational/adversarial-models.md index c55467c..37ded9d 100644 --- a/informational/adversarial-models.md +++ b/informational/adversarial-models.md @@ -147,7 +147,7 @@ Nodes controlled by the attacker can efficiently communicate out-of-band to coor ### External An external attacker can only see encrypted traffic. -Waku protocols are protected by a secure channel set up with [Noise](/spec/35/). +Waku protocols are protected by a secure channel set up with [Noise](../standards/core/noise.md). #### Local @@ -203,7 +203,7 @@ This section lists attacks that aim at deanonymizing a message sender. We assume that protocol messages are transmitted within a secure channel set up using the [Noise Protocol Framework](https://noiseprotocol.org/). For [Waku Relay](/spec/11) this means we only consider messages with version field `2`, -which indicates that the payload has to be encoded using [35/WAKU2-NOISE](/spec/35/). +which indicates that the payload has to be encoded using [Noise](../standards/core/noise.md). Note: The currently listed attacks are against libp2p in general. The [data field of Waku v2 relay](/spec/11/#message-fields) must be a [Waku v2 message](/spec/14/). @@ -299,8 +299,8 @@ While *single node* and smaller *multi node* attackers can have a negative effec A *scaling multi node* attacker, however, can significantly disrupt the network with such an attack. The effects of this attack are especially severe in conjunction with deanonymization mitigation techniques that reduce the out-degree of the overlay, -such as [Waku Dandelion](/spec/44/). -([Waku Dandelion](/spec/44/) also discusses mitigation techniques compensating the amplified black hole potential.) +such as [Waku Dandelion](../standards/application/dandelion.md). +[Waku Dandelion](../standards/application/dandelion.md)) also discusses mitigation techniques compensating the amplified black hole potential.) #### Traffic Filtering (external) @@ -328,8 +328,9 @@ Copyright and related rights waived via [CC0](https://creativecommons.org/public * [Sybil attack](https://en.wikipedia.org/wiki/Sybil_attack) * [Dolev-Yao model](https://en.wikipedia.org/wiki/Dolev%E2%80%93Yao_model) * [Noise Protocol Framework](https://noiseprotocol.org/) -* [35/WAKU2-NOISE](/spec/35/) +* [Noise](../standards/core/noise.md) * [17/WAKU-RLN-RELAY](/spec/17/) * [18/WAKU2-SWAP](/spec/18/) * [Dandelion++](https://arxiv.org/abs/1805.11060) * [On the Anonymity of Peer-To-Peer Network Anonymity Schemes Used by Cryptocurrencies](https://arxiv.org/pdf/2201.11860) +* [Waku Dandelion](../standards/application/dandelion.md)) From 9026d9a1d5c568c8b89120928d976fbf567e4d0c Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Mon, 5 Feb 2024 14:50:39 -0500 Subject: [PATCH 37/81] Update relay-static-shard-alloc.md --- informational/relay-static-shard-alloc.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/informational/relay-static-shard-alloc.md b/informational/relay-static-shard-alloc.md index 545975d..f9708f6 100644 --- a/informational/relay-static-shard-alloc.md +++ b/informational/relay-static-shard-alloc.md @@ -10,12 +10,12 @@ contributors: ## Abstract -This document lists static shard flag index assignments (see [51/WAKU2-RELAY-SHARDING](/spec/51/). +This document lists static shard flag index assignments (see [WAKU2-RELAY-SHARDING](../standards/core/relay-sharding.md)). ## Background Similar to the [IANA port allocation](https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml), -this document lists static shard index assignments (see [51/WAKU2-RELAY-SHARDING](/spec/51/). +this document lists static shard index assignments (see [WAKU2-RELAY-SHARDING](../standards/core/relay-sharding.md). ## Assingment Process @@ -50,7 +50,7 @@ this document lists static shard index assignments (see [51/WAKU2-RELAY-SHARDING Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). -# References +## References -* [51/WAKU2-RELAY-SHARDING](/spec/51/) +* [WAKU2-RELAY-SHARDING](../standards/core/relay-sharding.md) * [IANA port allocation](https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml) From d9268d6281abd6d5b219ef16bcf11245b629336f Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Thu, 8 Feb 2024 02:28:27 -0500 Subject: [PATCH 38/81] Create incentivization.md --- standards/application/incentivization.md | 218 +++++++++++++++++++++++ 1 file changed, 218 insertions(+) create mode 100644 standards/application/incentivization.md diff --git a/standards/application/incentivization.md b/standards/application/incentivization.md new file mode 100644 index 0000000..52a4af9 --- /dev/null +++ b/standards/application/incentivization.md @@ -0,0 +1,218 @@ +--- +title: WAKU2-INCENTIVIZATION +name: Incentivization for Waku Light Protocols +category: Standards Track +tags: + - incentivization +editor: Sergei Tikhomirov +contributors: +--- +## Abstract + +This document describes an approach to incentivization of Waku request-response protocols. +Incentivization is necessary for economically sustainable growth of Waku. +In an incentivized request-response protocol, only eligible (e.g., paying) clients receive the service. +Clients include eligibility proofs in their requests. + +Eligibility proofs are designed to be used in multiple Waku protocols, such as Store, Lightpush, and Filter. +Store is planned to become the first Waku protocol to support incentivization. +We discuss the proof-of-concept implementation of incentivization for Store in a later section. + +## Background / Rationale / Motivation + +Decentralized protocols require incentivization to be economically sustainable. +While some aspects of a P2P network can successfully operate in a tit-for-tat model, +we believe that nodes that run the protocol in good faith need to be tangibly rewarded. +Motivating servers to expand resources on handling clients' requests allows us to scale the network beyond its initial altruism-based phase. + +Incentivization is not necessarily limited to monetary rewards. +Reputation may also play a role. +For Waku request-response (i.e., client-server) protocols, we envision a combination of monetary and reputation-based incentivization. +See a [write-up on incentivization](https://github.com/waku-org/research/blob/1e3ed6a5cc47e6d1e7cb99271ddef9bf38429518/docs/incentivization.md) for our high-level reasoning on the topic. + +## Theory / Semantics + +The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “NOT RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in [RFC 2119](https://www.ietf.org/rfc/rfc2119.txt). + +Consider a request-response protocol with two roles: a client and a server. +A server MAY indicate to a client that it expects certain eligibility criteria to be met. +In that case, a client MUST provide a valid eligibility proof as part of its request. + +Forms of eligibility proofs include: +- Proof of payment: for paid non-authenticated requests. A proof of payment, in turn, may also take different forms, such as a transaction hash or a ZK-proof. In order to interpret a proof of payment, the server needs information about its type. +- Proof of membership: for services for a predefined group of users. An example use case: an application developer pays in bulk for their users' requests. A client then prove that they belong to the user set of that application. A similar concept (RLN) is used in Waku Relay for spam prevention. +- Service credential: a proof of membership in a set of clients who have prepaid for the service (which may be considered a special case of proof of membership). + +Upon a receiving a request: +- the server SHOULD check if the eligibility proof is included and valid; +- if that proof is absent or invalid, the server SHOULD send back response with a corresponding error code and error description; +- if the proof is valid, the server SHOULD send back the response that the client has requested. + +Note that the protocol does not ensure atomicity. +It is technically possible for a server to fail to respond to an eligible request (in violation of the protocol). +Addressing this issue is left for future work. + +## Wire Format Specification / Syntax + +A client includes an `EligibilityProof` in its request. +A server includes an `EligibilityStatus` in its response. + +```protobuf +syntax = "proto3"; + +message EligibilityProof { + optional bytes proof_of_payment = 1; // e.g., a txid + // may be extended with other eligibility proof types, such as: + //optional bytes proof_of_membership = 2; // e.g., an RLN proof +} + +message EligibilityStatus { + optional uint32 status_code = 1; + optional string status_desc = 2; +} +``` + +We include the `other_eligibility_proof` field in `EligibilityProof` to reflect other types of eligibility proofs that could be added to the protocol later. + +## Implementation in Store (PoC version) + +This Section describes a proof-of-concept (PoC) implementation of incentivization in the Store protocol. +Note: this section may later be moved to Store RFC. + +Store is one of Waku's request-response protocols. +A Store client queries the server for historic messages. +A Store server responds with a list of messages that pass the user's filter. +See [13/WAKU2-STORE](/spec/13) for the definitions of `HistoryQuery` and `HistoryResponse`. + +The PoC Store incentivization makes the following simplifying assumptions: +- the client knows the server's on-chain address `A`; +- the client and the server have agreed on a constant price `r` per hour of message history. + +To query messages from a period of length `t`, the client: +1. calculates the total price `p` as `p = r * t`; +2. pays `p` to the server's address `A` with an on-chain transaction; +3. waits until the transaction is confirmed with identifier `txid`; +4. includes `txid` in the request as a proof of payment. + +It is the server's responsibility to keep track of the `txid`s from prior requests and to make sure they are not reused. + +Note that `txid` may not always be practical as proof of payment due to on-chain confirmation latency. +To address this issue, future versions of the protocol may involve: +- paying for multiple requests in one transaction; +- using faster (likely L2-based) payment mechanisms. + +### Wire Format Specifications for Store PoC incentivization + +#### Request + +We extend `HistoryQuery` to include an eligibility proof: +```protobuf +message HistoryQuery { + // the first field is reserved for future use + string pubsubtopic = 2; + repeated ContentFilter contentFilters = 3; + PagingInfo pagingInfo = 4; + // numbering gap left for non-eligibility-related protocol extensions + + optional bytes eligibility_proof = 10; +} +``` + +An example of usage with `txid` as a proof of payment: +```protobuf +HistoryQuery history_query { + // the first field is reserved for future use + pubsubtopic: "example_pubsub_topic" + contentFilters: [] + pagingInfo: { + // provide values for PagingInfo fields + } + eligibility_proof: { + proof_of_payment: 0xabc123 // txid for the client's payment + // eligibility proofs of other types are not included + }; +} +``` + +#### Response + +We extend the `HistoryResponse` to indicate the eligibility status: +```protobuf +message HistoryResponse { + // the first field is reserved for future use + repeated WakuMessage messages = 2; + PagingInfo pagingInfo = 3; + enum Error { + NONE = 0; + INVALID_CURSOR = 1; + + NON_ELIGIBLE = 2; + } + Error error = 4; + + EligibilityStatus eligibility_status = 5; +} +``` + +Example of a response if the client is eligible: +```protobuf +HistoryResponse response_example { + messages: [message_1, message_2] + pagingInfo: paging_info + error: NONE + eligibility_status: { + status_code: 200 + status_desc: "OK" + } +} +``` + +Example of a response if the client is not eligible: +```protobuf +HistoryResponse response_example { + messages: [] // no messages sent to non-eligible clients + pagingInfo: paging_info + error: NON_ELIGIBLE + eligibility_status: { + status_code: 402 + status_desc: "PAYMENT_REQUIRED" + } +} +``` + +## Security/Privacy Considerations + +Eligibility proofs may reveal private information about the client. +In particular, a transaction identifier used as a proof of payment links the client's query to their on-chain activity. +Potential countermeasures may include using one-time addresses or ZK-based privacy-preserving protocols. + +## Limitations and Future Work + +This document is intentionally simplified in its initial version. +It assumes a shared understanding of prices and the blockchain addresses of servers. +Additionally, the feasibility of paying for each query is hindered by on-chain fees and confirmation delays. + +We will address these challenges as the specification evolves alongside the corresponding PoC implementation. +The following ideas will be explored: +- Batch Payment: instead of paying for an individual query, the client would make a consolidated payment for multiple messages. +- Price Negotiation: rather than receiving prices off-band, the client would engage in negotiation with the server to determine costs. +- Dynamic Pricing: the price per message would be variable, based on the total size (in bytes) of all received messages. +- Subscriptions: the client would pay for a defined time period during which they can query any number of messages, subject to DoS protection. + +## Copyright + +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). + +## References + +### normative +- A high-level [incentivization outline](https://github.com/waku-org/research/blob/master/incentivization.md) +- [13/WAKU2-STORE](/spec/13) (for Store-specific sections) + +### informative + +RFCs of request-response protocols: +- [12/WAKU2-FILTER](/spec/12) +- [13/WAKU2-STORE](/spec/13) +- [19/WAKU2-LIGHTPUSH](/spec/19) + +RFCs of Relay and RLN-Relay: +- [11/WAKU2-RELAY](/spec/11) +- [17/WAKU2-RLN-RELAY](/spec/17) From 88bba0306a900c6eee9a9f5dd106323061e788bc Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Fri, 9 Feb 2024 10:32:46 -0500 Subject: [PATCH 39/81] Rename noise.md to noise.md --- standards/{core => application}/noise.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename standards/{core => application}/noise.md (100%) diff --git a/standards/core/noise.md b/standards/application/noise.md similarity index 100% rename from standards/core/noise.md rename to standards/application/noise.md From 4ea848d5845c18cfd30ab7e7ec520eed44c91f19 Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Fri, 9 Feb 2024 10:33:24 -0500 Subject: [PATCH 40/81] Rename device-pairing.md to device-pairing.md --- standards/{core => application}/device-pairing.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename standards/{core => application}/device-pairing.md (100%) diff --git a/standards/core/device-pairing.md b/standards/application/device-pairing.md similarity index 100% rename from standards/core/device-pairing.md rename to standards/application/device-pairing.md From 0a14c3ea8e52dfd60ed514fe18fb152216e278d4 Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Fri, 9 Feb 2024 10:34:29 -0500 Subject: [PATCH 41/81] Rename metadata.md to metadata.md --- standards/{application => core}/metadata.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename standards/{application => core}/metadata.md (100%) diff --git a/standards/application/metadata.md b/standards/core/metadata.md similarity index 100% rename from standards/application/metadata.md rename to standards/core/metadata.md From c25852f425655d2a2a5dd307d5261e1d7a8ce829 Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Tue, 13 Feb 2024 19:37:58 -0500 Subject: [PATCH 42/81] Update README.md --- README.md | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1fc0a66..d0e5888 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,26 @@ -# Waku RFCs +# Waku RFC (Request For Comments) -## Contributing +Waku builds a family of privacy-preserving, censorship-resistant communication protocols for web3 applications. +This repository contain RFCs from contributors wanting to imporve Waku protocols. + +## Resources +Relvant Waku resouces related to the specifications located in this repository: +- [Waku.org](https://waku.org/) +- [nWaku: Waku Node](https://github.com/waku-org/nwaku) + +## Contributions + +Contributions are welcome from any party. +Contributors can create specifcations relating to the Waku domain and +create a pull request to begin discussion. +There is no format/template for accepted specifications to the Waku RFC. + +New specifications that are considered a proof of concept, +should provide some implementation to help discussion. +If rough consensus is reached, +the specification could be considered to receive a draft status at the Vac RFC repository. + +**NOTE:** Specifications located in this repository should be considered not production ready. +Discussion should be conducted with the intention of maturing the specification. + +Head over to the [Vac RFC-Index](https://github.com/vacp2p/rfc-index) repository where other Waku specifcations live. From 42a20c4abee1d585d13d3949037fa1138ff380a5 Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Wed, 14 Feb 2024 10:32:14 -0500 Subject: [PATCH 43/81] Rename network.md to network.md --- standards/{application => core}/network.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename standards/{application => core}/network.md (100%) diff --git a/standards/application/network.md b/standards/core/network.md similarity index 100% rename from standards/application/network.md rename to standards/core/network.md From f15c02ccf9a6306f9bb7282ead72376a13f88352 Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Wed, 14 Feb 2024 16:08:44 -0500 Subject: [PATCH 44/81] Update adversarial-models.md --- informational/adversarial-models.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/informational/adversarial-models.md b/informational/adversarial-models.md index 37ded9d..4fe1114 100644 --- a/informational/adversarial-models.md +++ b/informational/adversarial-models.md @@ -13,7 +13,7 @@ This document lists adversarial models and attack-based threats relevant in the ## Motivation and Background -Future versions of this document will serve as a comprehensive list of adversarial models and attack based threats relevant for [Waku v2](/spec/10/). +Future versions of this document will serve as a comprehensive list of adversarial models and attack based threats relevant for [Waku v2](https://rfc.vac.dev/spec/10/). The main purpose of this document is being a linkable resource for specifications that address protection as well as mitigation mechanisms within the listed models. Discussing and introducing countermeasures to specific attacks in specific models is out of scope for this document. @@ -73,7 +73,7 @@ We subdivide anonymity into *receiver anonymity* and *sender anonymity*. #### Receiver Anonymity We define receiver anonymity as *unlinkability of users' identities and the data they receive and/or related actions*. -Because each [Waku message](/spec/14/) is associated with a content topic, and each receiver is interested in messages with specific content topics, +Because each [Waku message](https://rfc.vac.dev/spec/14/) is associated with a content topic, and each receiver is interested in messages with specific content topics, receiver anonymity in the context of Waku corresponds to *subscriber-topic unlinkability*. An example for the "action" part of our receiver anonymity definition is subscribing to a specific topic. @@ -175,7 +175,7 @@ An entity with this power would, in practice, also have the power of the interna ## Attack-based Threats -The following lists various attacks against [Waku v2](/spec/10/) protocols. +The following lists various attacks against [Waku v2](https://rfc.vac.dev/spec/10/) protocols. If not specifically mentioned, the attacks refer to [Waku relay](/spec/11) and the underlying [libp2p GossipSub](https://github.com/libp2p/specs/blob/master/pubsub/gossipsub/README.md). We also list the weakest attacker model in which the attack can be successfully performed against. @@ -202,11 +202,11 @@ which in turn significantly increases the probability of attacker nodes ending u This section lists attacks that aim at deanonymizing a message sender. We assume that protocol messages are transmitted within a secure channel set up using the [Noise Protocol Framework](https://noiseprotocol.org/). -For [Waku Relay](/spec/11) this means we only consider messages with version field `2`, +For [Waku Relay](https://rfc.vac.dev/spec/11/) this means we only consider messages with version field `2`, which indicates that the payload has to be encoded using [Noise](../standards/core/noise.md). Note: The currently listed attacks are against libp2p in general. -The [data field of Waku v2 relay](/spec/11/#message-fields) must be a [Waku v2 message](/spec/14/). +The [data field of Waku v2 relay](https://rfc.vac.dev/spec/11/#message-fields) must be a [Waku v2 message](https://rfc.vac.dev/spec/14/). The attacks listed in the following do not leverage that fact. #### Replay Attack @@ -217,7 +217,7 @@ Waku relay is inherently safe against replay attack, because GossipSub nodes, and by extension Waku relay nodes, feature a `seen` cache, and only relay messages they have not seen before. -Further, replay attacks will be punished by [RLN Relay](/spec/17/). +Further, replay attacks will be punished by [RLN Relay](https://rfc.vac.dev/spec/17/). #### Observing Messages @@ -287,8 +287,8 @@ which can be learned via *graph learning* attacks. In a flooding attack, attackers flood the network with bogus messages. -Waku employs [RLN Relay](/spec/17/) as the main countermeasure to flooding. -[SWAP](/spec/18/) also helps mitigating DoS attacks. +Waku employs [RLN Relay](https://rfc.vac.dev/spec/17/) as the main countermeasure to flooding. +[SWAP](https://rfc.vac.dev/spec/18/) also helps mitigating DoS attacks. #### Black Hole (internal) @@ -317,20 +317,20 @@ Copyright and related rights waived via [CC0](https://creativecommons.org/public ## References -* [10/WAKU2](/spec/10/) -* [11/WAKU2-RELAY](/spec/11/) +* [10/WAKU2](https://rfc.vac.dev/spec/10/) +* [11/WAKU2-RELAY](https://rfc.vac.dev/spec/11/) * [libp2p GossipSub](https://github.com/libp2p/specs/blob/master/pubsub/gossipsub/README.md) * [Security](https://en.wikipedia.org/wiki/Information_security) * [Authentication](https://en.wikipedia.org/wiki/Authentication) * [Anonymity Trilemma](https://freedom.cs.purdue.edu/projects/trilemma.html) -* [Waku v2 message](/spec/14/) +* [Waku v2 message](https://rfc.vac.dev/spec/14/) * [Pluggable Transports](https://www.pluggabletransports.info/about/) * [Sybil attack](https://en.wikipedia.org/wiki/Sybil_attack) * [Dolev-Yao model](https://en.wikipedia.org/wiki/Dolev%E2%80%93Yao_model) * [Noise Protocol Framework](https://noiseprotocol.org/) * [Noise](../standards/core/noise.md) -* [17/WAKU-RLN-RELAY](/spec/17/) -* [18/WAKU2-SWAP](/spec/18/) +* [17/WAKU-RLN-RELAY](https://rfc.vac.dev/spec/17/) +* [18/WAKU2-SWAP](https://rfc.vac.dev/spec/18/) * [Dandelion++](https://arxiv.org/abs/1805.11060) * [On the Anonymity of Peer-To-Peer Network Anonymity Schemes Used by Cryptocurrencies](https://arxiv.org/pdf/2201.11860) * [Waku Dandelion](../standards/application/dandelion.md)) From 64a94a9943bfa8b028e46179b472a72e191175db Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Wed, 14 Feb 2024 18:11:11 -0500 Subject: [PATCH 45/81] Update dandelion.md --- standards/application/dandelion.md | 42 +++++++++++++++--------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/standards/application/dandelion.md b/standards/application/dandelion.md index da48cbb..845c2e6 100644 --- a/standards/application/dandelion.md +++ b/standards/application/dandelion.md @@ -21,8 +21,8 @@ instead of disseminating messages as per usual relay operation. ## Background and Motivation -[Waku Relay](/spec/11/), offers privacy, pseudonymity, and a first layer of anonymity protection by design. -Being a modular protocol family [Waku v2](/spec/10/) +[Waku Relay](https://rfc.vac.dev/spec/11/), offers privacy, pseudonymity, and a first layer of anonymity protection by design. +Being a modular protocol family [Waku v2](https://rfc.vac.dev/spec/10/) offers features that inherently carry trade-offs as separate building blocks. Anonymity protection is such a feature. The [Anonymity Trilemma](https://freedom.cs.purdue.edu/projects/trilemma.html) @@ -37,7 +37,7 @@ and [Dandelion++](https://arxiv.org/abs/1805.11060). Dandelion is a message spreading method, which, compared to other methods, increases the uncertainty of an attacker when trying to link messages to senders. -Libp2p gossipsub aims at spanning a [d-regular graph](https://en.wikipedia.org/wiki/Regular_graph) topology, with d=6 as the [default value](/spec/29/#gossipsub-v10-parameters). +Libp2p gossipsub aims at spanning a [d-regular graph](https://en.wikipedia.org/wiki/Regular_graph) topology, with d=6 as the [default value](https://rfc.vac.dev/spec/29/#gossipsub-v10-parameters). Messages are forwarded within this (expected) symmetric topology, which reduces uncertainty when trying to link messages to senders. Dandelion breaks this symmetry by subdividing message spreading into a "stem" and a "fluff" phase. @@ -65,7 +65,7 @@ Further information on Waku anonymity may be found in our [Waku Privacy and Anon which is based on [libp2p gossipsub](https://github.com/libp2p/specs/blob/master/pubsub/gossipsub/README.md). 44/WAKU2-DANDELION subdivides message dissemination into a "stem" and a "fluff" phase. This specification is mainly concerned with specifying the stem phase. -The fluff phase corresponds to [Waku Relay](/spec/11/), +The fluff phase corresponds to [Waku Relay](https://rfc.vac.dev/spec/11/), with optional fluff phase augmentations such as random delays. Adding random delay in the fluff phase further reduces symmetry in dissemination patterns and introduces more uncertainty for the attacker. @@ -92,7 +92,7 @@ are always sent as stem messages. The stem phase can be seen as a different protocol, and messages are introduced into Waku Relay, and by extension gossipsub, once they arrive at a node in fluff state for the first time. -44/WAKU2-DANDELION uses [19/WAKU2-LIGHTPUSH](/spec/19/) as the protocol for relaying stem messages. +44/WAKU2-DANDELION uses [19/WAKU2-LIGHTPUSH](https://rfc.vac.dev/spec/19/) as the protocol for relaying stem messages. There are no negative effects on gossipsub peer scoring, because Dandelion nodes in *stem state* still normally relay Waku Relay (gossipsub) messages. @@ -116,16 +116,16 @@ corresponding to 10 minute epochs. On entering stem state, nodes supporting 44/WAKU2-DANDELION MUST randomly select two nodes for each pubsub topic from the respective gossipsub mesh node set. These nodes are referred to as stem relays. -Stem relays MUST support [19/WAKU2-LIGHTPUSH](/spec/19/). -If a chosen peer does not support [19/WAKU2-LIGHTPUSH](/spec/19/), +Stem relays MUST support [19/WAKU2-LIGHTPUSH](https://rfc.vac.dev/spec/19/). +If a chosen peer does not support [19/WAKU2-LIGHTPUSH](https://rfc.vac.dev/spec/19/), the node SHOULD switch to fluff state. (We may update this strategy in future versions of this document.) Further, the node establishes a map that maps each incoming stem connection to one of its stem relays chosen at random (but fixed per epoch). Incoming stem connections are identified by the [Peer IDs](https://docs.libp2p.io/concepts/peers/#peer-id/) -of peers the node receives [19/WAKU2-LIGHTPUSH](/spec/19/) messages from. -Incoming [19/WAKU2-LIGHTPUSH](/spec/19/) connections from peers that do not support 44/WAKU2-DANDELION are identified and mapped in the same way. +of peers the node receives [19/WAKU2-LIGHTPUSH](https://rfc.vac.dev/spec/19/) messages from. +Incoming [19/WAKU2-LIGHTPUSH](https://rfc.vac.dev/spec/19/) connections from peers that do not support 44/WAKU2-DANDELION are identified and mapped in the same way. This makes the protocol simpler, increases the anonymity set, and offers Dandelion anonymity properties to such peers, too. The node itself is mapped in the same way, so that all messages originated by the node are relayed via a per-epoch-fixed Dandelion relay, too. @@ -133,7 +133,7 @@ The node itself is mapped in the same way, so that all messages originated by th While in stem state, nodes MUST relay stem messages to the respective stem relay. Received fluff messages MUST be relayed as specified in the fluff state section. -The stem protocol ([19/WAKU2-LIGHTPUSH](/spec/19/)) is independent of the fluff protocol ([Waku Relay](/spec/11/)). +The stem protocol ([19/WAKU2-LIGHTPUSH](https://rfc.vac.dev/spec/19/)) is independent of the fluff protocol ([Waku Relay](https://rfc.vac.dev/spec/11/)). While in stem state, nodes MUST NOT gossip about stem messages, and MUST NOT send control messages related to stem messages. (An existing gossipsub implementation does *not* have to be adjusted to not send gossip about stem messages, @@ -161,7 +161,7 @@ this regular forwarding already comprises random delays. ## Implementation Notes -Handling of the 44/WAKU2-DANDELION stem phase can be implemented as an extension to an existing [19/WAKU2-LIGHTPUSH](/spec/19/) implementation. +Handling of the 44/WAKU2-DANDELION stem phase can be implemented as an extension to an existing [19/WAKU2-LIGHTPUSH](https://rfc.vac.dev/spec/19/) implementation. Fluff phase augmentations might alter gossipsub message dissemination (e.g. adding random delays). If this is the case, they have to be implemented on the libp2p gossipsub layer. @@ -197,7 +197,7 @@ We will elaborate on this in future versions of this document. Stem relays receiving messages can either be in stem state or in fluff state themselves. They might also not support 44/WAKU2-DANDELION, -and interpret the message as classical [19/WAKU2-LIGHTPUSH](/spec/19/), +and interpret the message as classical [19/WAKU2-LIGHTPUSH](https://rfc.vac.dev/spec/19/), which effectively makes them act as fluff state relays. While such peers lower the overall anonymity properties, the [Dandelion++ paper](https://arxiv.org/abs/1805.11060) @@ -234,9 +234,9 @@ We will quantify the resulting loss of anonymity in future versions of this docu #### Stem Relay Selection In its current version, 44/WAKU2-DANDELION nodes default to fluff state -if the random stem relay selection yields at least one peer that does not support [19/WAKU2-LIGHTPUSH](/spec/19/) (which is the stem protocol used in 44/WAKU2-DANDELION). -If nodes would reselect peers until they find peers supporting [19/WAKU2-LIGHTPUSH](/spec/19/), -malicious nodes would get an advantage if a significant number of honest nodes would not support [19/WAKU2-LIGHTPUSH](/spec/19/). +if the random stem relay selection yields at least one peer that does not support [19/WAKU2-LIGHTPUSH](https://rfc.vac.dev/spec/19/) (which is the stem protocol used in [44/WAKU2-DANDELION](https://rfc.vac.dev/spec/44/). +If nodes would reselect peers until they find peers supporting [19/WAKU2-LIGHTPUSH](https://rfc.vac.dev/spec/19/), +malicious nodes would get an advantage if a significant number of honest nodes would not support [19/WAKU2-LIGHTPUSH](https://rfc.vac.dev/spec/19). Even though this causes messages to enter fluff phase earlier, we choose the trade-off in favour of protocol stability and sacrifice a bit of anonymity. (We will look into improving this in future versions of this document.) @@ -267,14 +267,14 @@ Note: Introducing random delays can have a negative effect on #### Stem Flag While 44/WAKU2-DANDELION without fluff augmentation does not effect Waku Relay nodes, -messages sent by nodes that only support [19/WAKU2-LIGHTPUSH](/spec/19/) might be routed through a Dandelion stem without them knowing. +messages sent by nodes that only support [19/WAKU2-LIGHTPUSH](https://rfc.vac.dev/spec/19/) might be routed through a Dandelion stem without them knowing. While this improves anonymity, as discussed above, it also introduces additional latency and lightpush nodes cannot opt out of this. In future versions of this specification we might -* add a flag to [14/WAKU2-MESSAGE](/spec/14/) indicating a message should be routed over a Dandelion stem (opt-in), or -* add a flag to [14/WAKU2-MESSAGE](/spec/14/) indicating a message should *not* be routed over a Dandelion stem (opt-out), or -* introducing a fork of [19/WAKU2-LIGHTPUSH](/spec/19/) exclusively used for Dandelion stem. +* add a flag to [14/WAKU2-MESSAGE](https://rfc.vac.dev/spec/14/) indicating a message should be routed over a Dandelion stem (opt-in), or +* add a flag to [14/WAKU2-MESSAGE](https://rfc.vac.dev/spec/14/) indicating a message should *not* be routed over a Dandelion stem (opt-out), or +* introducing a fork of [19/WAKU2-LIGHTPUSH](https://rfc.vac.dev/spec/19/) exclusively used for Dandelion stem. In the current version, we decided against these options in favour of a simpler protocol and an increased anonymity set. @@ -293,5 +293,5 @@ Copyright and related rights waived via [CC0](https://creativecommons.org/public * [Anonymity Trilemma](https://freedom.cs.purdue.edu/projects/trilemma.html) * [Waku Privacy and Anonymity Analysis](https://vac.dev/wakuv2-relay-anon). * [On the Anonymity of Peer-To-Peer Network Anonymity Schemes Used by Cryptocurrencies](https://arxiv.org/pdf/2201.11860.pdf) -* [Adversarial Models](/spec/45/) -* [14/WAKU2-MESSAGE](/spec/14/) +* [Adversarial Models](https://rfc.vac.dev/spec/45/) +* [14/WAKU2-MESSAGE](https://rfc.vac.dev/spec/14/) From a89021a7f1feacdbef12dc0fcf90e122bc7a709b Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Wed, 14 Feb 2024 18:16:57 -0500 Subject: [PATCH 46/81] Update incentivization.md --- standards/application/incentivization.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/standards/application/incentivization.md b/standards/application/incentivization.md index 52a4af9..406bffc 100644 --- a/standards/application/incentivization.md +++ b/standards/application/incentivization.md @@ -82,7 +82,7 @@ Note: this section may later be moved to Store RFC. Store is one of Waku's request-response protocols. A Store client queries the server for historic messages. A Store server responds with a list of messages that pass the user's filter. -See [13/WAKU2-STORE](/spec/13) for the definitions of `HistoryQuery` and `HistoryResponse`. +See [13/WAKU2-STORE](https://rfc.vac.dev/spec/13/) for the definitions of `HistoryQuery` and `HistoryResponse`. The PoC Store incentivization makes the following simplifying assumptions: - the client knows the server's on-chain address `A`; @@ -204,15 +204,15 @@ Copyright and related rights waived via [CC0](https://creativecommons.org/public ### normative - A high-level [incentivization outline](https://github.com/waku-org/research/blob/master/incentivization.md) -- [13/WAKU2-STORE](/spec/13) (for Store-specific sections) +- [13/WAKU2-STORE](https://rfc.vac.dev/spec/13/) (for Store-specific sections) ### informative RFCs of request-response protocols: -- [12/WAKU2-FILTER](/spec/12) -- [13/WAKU2-STORE](/spec/13) -- [19/WAKU2-LIGHTPUSH](/spec/19) +- [12/WAKU2-FILTER](https://rfc.vac.dev/spec/12) +- [13/WAKU2-STORE](https://rfc.vac.dev/spec/13/) +- [19/WAKU2-LIGHTPUSH](https://rfc.vac.dev/spec/19/) RFCs of Relay and RLN-Relay: -- [11/WAKU2-RELAY](/spec/11) -- [17/WAKU2-RLN-RELAY](/spec/17) +- [11/WAKU2-RELAY](https://rfc.vac.dev/spec/11) +- [17/WAKU2-RLN-RELAY](https://rfc.vac.dev/spec/17) From 9ff5286eadf44602b682c090062ecb595a609b42 Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Wed, 14 Feb 2024 18:20:50 -0500 Subject: [PATCH 47/81] Update noise.md --- standards/application/noise.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/standards/application/noise.md b/standards/application/noise.md index e4a4204..e60dbd5 100644 --- a/standards/application/noise.md +++ b/standards/application/noise.md @@ -6,12 +6,12 @@ editor: Giuseppe contributors: --- -This specification describes how payloads of [Waku messages](spec/14/) with [version 2](/spec/14/#version2) can be encrypted +This specification describes how payloads of [Waku messages](https://rfc.vac.dev/spec/14/) with [version 2](https://rfc.vac.dev/spec/14/#version2) can be encrypted in order to achieve confidentiality, authenticity, and integrity as well as some form of identity-hiding on communicating parties. -This specification extends the functionalities provided by [26/WAKU-PAYLOAD](/spec/26), +This specification extends the functionalities provided by [26/WAKU-PAYLOAD](https://rfc.vac.dev/spec/26/), adding support to modern symmetric encryption primitives and asymmetric key-exchange protocols. @@ -63,7 +63,7 @@ We note that all [design requirements](#Design-requirements) on exchanged messag corresponding to a total of 1 Round Trip Time communication *(1-RTT)*. In particular, identity-hiding properties can be guaranteed only if the recommendation described in [After-handshake](#After-handshake) are implemented. -In the following, we assume that communicating parties reciprocally know an initial [`contentTopic`](/spec/14/#wakumessage) +In the following, we assume that communicating parties reciprocally know an initial [`contentTopic`](https://rfc.vac.dev/spec/14/#wakumessage) where they can send/receive the first handshake message(s). We further assume that messages sent over a certain `contentTopic` can be efficiently identified by their intended recipients thanks to an arbitrary 16 bytes long `message-nametag` field embedded in the message payload @@ -85,7 +85,7 @@ The symmetric primitives supported are: ## Specification -When [14/WAKU-MESSAGE version](/spec/14/#payload-encryption) is set to 2, +When [14/WAKU-MESSAGE version](https://rfc.vac.dev/spec/14/#payload-encryption) is set to 2, the corresponding `WakuMessage`'s `payload` will encapsulate the two fields `handshake-message` and `transport-message`. The `handshake-message` field MAY contain @@ -228,24 +228,24 @@ by hashing the result of an ephemeral-ephemeral Diffie-Hellman exchange every 1- ## Backward Support for Symmetric/Asymmetric Encryption -It is possible to have backward compatibility to symmetric/asymmetric encryption primitives from [26/WAKU-PAYLOAD](/spec/26), -effectively encapsulating payload encryption [14/WAKU-MESSAGE version 1](/spec/14/#version1) in [version 2](/spec/14/#version2). +It is possible to have backward compatibility to symmetric/asymmetric encryption primitives from [26/WAKU-PAYLOAD](https://rfc.vac.dev/spec/26/), +effectively encapsulating payload encryption [14/WAKU-MESSAGE version 1](https://rfc.vac.dev/spec/14/#version1) in [version 2](https://rfc.vac.dev/spec/14/#version2). It suffices to extend the list of supported `protocol-id` to: - `254`: AES-256-GCM symmetric encryption; - `255`: ECIES asymmetric encryption. -and set the `transport-message` field to the [26/WAKU-PAYLOAD](/spec/26) `data` field, whenever these `protocol-id` values are set. +and set the `transport-message` field to the [26/WAKU-PAYLOAD](https://rfc.vac.dev/spec/26) `data` field, whenever these `protocol-id` values are set. Namely, if `protocol-id = 254, 255` then: - `message-nametag`: is empty; - `handshake-message-len`: is set to `0`; - `handshake-message`: is empty; -- `transport-message`: contains the [26/WAKU-PAYLOAD](/spec/26) `data` field (AES-256-GCM or ECIES, depending on `protocol-id`); +- `transport-message`: contains the [26/WAKU-PAYLOAD](https://rfc.vac.dev/spec/26/) `data` field (AES-256-GCM or ECIES, depending on `protocol-id`); - `transport-message-len` is set accordingly to `transport-message` length; When a `transport-message` corresponding to `protocol-id = 254, 255` is retrieved, -it SHOULD be decoded as the `data` field in [26/WAKU-PAYLOAD](/spec/26) specification. +it SHOULD be decoded as the `data` field in [26/WAKU-PAYLOAD](https://rfc.vac.dev/spec/26/) specification. ## Appendix: Supported Handshakes Description @@ -331,9 +331,9 @@ The main difference with `XX` is that Alice's and Bob's static keys, when transm ## References 1. [5/SECURE-TRANSPORT](https://specs.status.im/spec/5) -2. [10/WAKU2](/spec/10) -3. [26/WAKU-PAYLOAD](/spec/26) -4. [14/WAKU-MESSAGE](/spec/14/#version1) +2. [10/WAKU2](https://rfc.vac.dev/spec/10) +3. [26/WAKU-PAYLOAD](https://rfc.vac.dev/spec/26) +4. [14/WAKU-MESSAGE](https://rfc.vac.dev/spec/14/#version1) 5. [Noise protocol](http://www.noiseprotocol.org/noise.html) 6. [Noise handshakes as key-exchange mechanism for Waku2](https://forum.vac.dev/t/noise-handshakes-as-key-exchange-mechanism-for-waku2/130) 7. [Augmented Backus-Naur form (ABNF)](https://tools.ietf.org/html/rfc5234) From d56fda76e89fffe3307a6dccdb840e5704b6381f Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Wed, 14 Feb 2024 18:45:24 -0500 Subject: [PATCH 48/81] Update tor-push.md --- standards/application/tor-push.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/standards/application/tor-push.md b/standards/application/tor-push.md index 7620ab6..7d6050d 100644 --- a/standards/application/tor-push.md +++ b/standards/application/tor-push.md @@ -9,10 +9,10 @@ contributors: ## Abstract -This document extends the [11/WAKU2-RELAY](/spec/11/), specifying Waku Tor Push, +This document extends the [11/WAKU2-RELAY](https://rfc.vac.dev/spec/11), specifying Waku Tor Push, which allows nodes to push messages via Tor into the Waku relay network. -Waku Tor Push builds on [46/GOSSIPSUB-TOR-PUSH](/spec/46). +Waku Tor Push builds on [46/GOSSIPSUB-TOR-PUSH](https://rfc.vac.dev/spec/46). **Protocol identifier**: /vac/waku/relay/2.0.0 @@ -23,13 +23,13 @@ This allows Waku relay nodes that are oblivious to Tor Push to process messages ## Functional Operation -In its current version, Waku Tor Push corresponds to [46/GOSSIPSUB-TOR-PUSH](/spec/46) -applied to [11/WAKU2-RELAY](/spec/11/), +In its current version, Waku Tor Push corresponds to [46/GOSSIPSUB-TOR-PUSH](https://rfc.vac.dev/spec/46) +applied to [11/WAKU2-RELAY](https://rfc.vac.dev/spec/11/), instead of [libp2p gossipsub](https://github.com/libp2p/specs/blob/master/pubsub/gossipsub/README.md). ## Security/Privacy Considerations -see [46/GOSSIPSUB-TOR-PUSH](/spec/46) +see [46/GOSSIPSUB-TOR-PUSH](https://rfc.vac.dev/spec/46) ## Copyright @@ -37,7 +37,7 @@ Copyright and related rights waived via [CC0](https://creativecommons.org/public ## References -* [11/WAKU2-RELAY](/spec/11/) +* [11/WAKU2-RELAY](https://rfc.vac.dev/spec/11) * [libp2p gossipsub](https://github.com/libp2p/specs/blob/master/pubsub/gossipsub/README.md) -* [46/GOSSIPSUB-TOR-PUSH](/spec/46) +* [46/GOSSIPSUB-TOR-PUSH](https://rfc.vac.dev/spec/46) * [Tor](https://www.torproject.org/) From b8e66d8145fe478a7da5994ada10e53414cd1472 Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Wed, 14 Feb 2024 18:58:12 -0500 Subject: [PATCH 49/81] Update peer-exchange.md --- standards/core/peer-exchange/peer-exchange.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/standards/core/peer-exchange/peer-exchange.md b/standards/core/peer-exchange/peer-exchange.md index f91d1e0..e199ed6 100644 --- a/standards/core/peer-exchange/peer-exchange.md +++ b/standards/core/peer-exchange/peer-exchange.md @@ -17,7 +17,7 @@ The main purpose of this protocol is providing resource restricted devices with ## Background and Motivation -It may not be feasible on resource restricted devices to take part in distributed random sampling ambient peer discovery protocols such as [33/WAKU2-DISCV5](/spec/33/). +It may not be feasible on resource restricted devices to take part in distributed random sampling ambient peer discovery protocols such as [33/WAKU2-DISCV5](https://rfc.vac.dev/spec/33/). The Waku peer discovery protocol specified in this document allows resource restricted devices to request a list of peers from a service node. Network parameters necessary to connect to this service node COULD be learned from a static bootstrapping method or using [EIP-1459: Node Discovery via DNS](https://eips.ethereum.org/EIPS/eip-1459). The advantage of using Waku peer exchange to discover new peers over using a static peer list or DNS discovery is a more even load distribution. @@ -25,7 +25,7 @@ If a lot of (resource restricted) nodes would use the same service nodes as rela Heavily used static nodes also add a centralized element. Downtime of such a node might significantly impact the network. However, the resource efficiency of this protocol comes at an anonymity cost, which is explained in the [Security/Privacy Considerations](#securityprivacy-considerations) section. -This protocol SHOULD only be used if [33/WAKU2-DISCV5](/spec/33/) is infeasible. +This protocol SHOULD only be used if [33/WAKU2-DISCV5](https://rfc.vac.dev/spec/33/) is infeasible. ## Theory and Protocol Semantics @@ -38,7 +38,7 @@ The [multiaddresses](https://docs.libp2p.io/concepts/addressing/) used to connec In order to protect its anonymity, the responder MUST NOT provide peers from its actively used peer list as this opens pathways to *Neighbourhood Surveillance* attacks, as described in the [Security/Privacy Considerations Section](#securityprivacy-considerations). -The responder SHOULD provide a set of peers that has been retrieved using ambient peer discovery methods supporting random sampling, e.g. [33/WAKU2-DISCV5](/spec/33/). +The responder SHOULD provide a set of peers that has been retrieved using ambient peer discovery methods supporting random sampling, e.g. [33/WAKU2-DISCV5](https://rfc.vac.dev/spec/33/). This both protects the responder's anonymity as well as helps distributing load. To allow for fast responses, responders SHOULD retrieve peers unsolicited (before receiving a query) @@ -98,7 +98,7 @@ Implementations can implement the libp2p discovery interface (e.g. [nim](https:/ The size of the (optional) exchange peer cache discussed in [Theory and Protocol Semantics](#theory-and-protocol-semantics) depends on the average number of requested peers, which is expected to be the outbound degree of the underlying [libp2p gossipsub](https://github.com/libp2p/specs/blob/master/pubsub/gossipsub/gossipsub-v1.1.md) mesh network. -The recommended value for this outbound degree is 6 (see parameter `D` in [29/WAKU2-CONFIG](/spec/29/)). +The recommended value for this outbound degree is 6 (see parameter `D` in [29/WAKU2-CONFIG](https://rfc.vac.dev/spec/29/)). It is recommended for the cache to hold at least 10 times as many peers (60). The recommended cache size also depends on the number of requesters a responder is expected to serve within a *refresh cycle*. @@ -134,7 +134,7 @@ As a weak mitigation the requester MAY ask several peers and select a subset of Responders that answer with active mesh peers are more vulnerable to a *neighbourhood surveillance* attack. Responding with the set of active mesh peers allows a malicious requester to get into the required position more easily. It takes away the first hurdle of the *neighbourhood surveillance* attack: The attacker knows which peers to try to connect to. -This increased vulnerability can be avoided by only responding with randomly sampled sets of peers, e.g. by requesting a random peer set via [33/WAKU2-DISCV5](/spec/33/). +This increased vulnerability can be avoided by only responding with randomly sampled sets of peers, e.g. by requesting a random peer set via [33/WAKU2-DISCV5](https://rfc.vac.dev/spec/33/). (As stated in the [Theory and Protocol Semantics Section](#theory-and-protocol-semantics), these peer sets SHOULD be retrieved unsolicitedly before receiving requests to achieve faster response times.) @@ -147,7 +147,7 @@ Still, frequent queries can tigger the refresh cycle more often. The `seen cache ### Further Considerations The response field contains ENRs as specified in [WAKU2-ENR](../enr.md). -While ENRs contain signatures, they do not violate the [Waku relay no-sign policy](/spec/11/#signature-policy)), +While ENRs contain signatures, they do not violate the [Waku relay no-sign policy](https://rfc.vac.dev/spec/11/#signature-policy)), because they are part of the discovery domain and are not propagated in the relay domain. However, there might still be some form of leakage: ENRs could be used to track peers and facilitate linking attacks. @@ -159,10 +159,10 @@ Copyright and related rights waived via [CC0](https://creativecommons.org/public ## References -* [33/WAKU2-DISCV5](/spec/33/) +* [33/WAKU2-DISCV5](https://rfc.vac.dev/spec/33/) * [WAKU2-ENR](../enr.md) * [multiaddress](https://docs.libp2p.io/concepts/addressing/) * [libp2p discovery interface](https://github.com/status-im/nim-libp2p/issues/140) * [libp2p gossipsub](https://github.com/libp2p/specs/blob/master/pubsub/gossipsub/gossipsub-v1.1.md) -* [29/WAKU2-CONFIG](/spec/29/) +* [29/WAKU2-CONFIG](https://rfc.vac.dev/spec/29/) * [Waku relay anonymity](https://vac.dev/wakuv2-relay-anon) From de6f3f2d6687d5bdc78ff480b1bc105266158c66 Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Wed, 14 Feb 2024 19:00:49 -0500 Subject: [PATCH 50/81] Update enr.md --- standards/core/enr.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/standards/core/enr.md b/standards/core/enr.md index 670c88d..569c5b8 100644 --- a/standards/core/enr.md +++ b/standards/core/enr.md @@ -8,7 +8,7 @@ contributors: ## Abstract -This RFC describes the usage of the ENR (Ethereum Node Records) format for [10/WAKU2](/specs/10) purposes. +This RFC describes the usage of the ENR (Ethereum Node Records) format for [10/WAKU2](https://rfc.vac.dev/spec/10/) purposes. The ENR format is defined in [EIP-778](https://eips.ethereum.org/EIPS/eip-778) [[3]](#references). This RFC is an extension of EIP-778, ENR used in Waku v2 MUST adhere to both EIP-778 and 31/WAKU2-ENR. @@ -40,7 +40,7 @@ Would carry some ambiguity: Is the certificate securing the websocket port valid the ipv4 address? the ipv6 address? -The [10/WAKU2](/specs/10) protocol family is built on the [libp2p](https://github.com/libp2p/specs) protocol stack. +The [10/WAKU2](https://rfc.vac.dev/spec/10/) protocol family is built on the [libp2p](https://github.com/libp2p/specs) protocol stack. Hence, it uses [multiaddr](https://github.com/multiformats/multiaddr) to format network addresses. Directly storing one or several multiaddresses in the ENR would fix the issues listed above: @@ -157,7 +157,7 @@ Copyright and related rights waived via [CC0](https://creativecommons.org/public ## References -- [1] https://github.com/status-im/nim-waku/pull/690 -- [2] https://github.com/vacp2p/rfc/issues/462#issuecomment-943869940 -- [3] https://eips.ethereum.org/EIPS/eip-778 -- [4] https://github.com/ethereum/devp2p/blob/master/discv5/discv5.md +- [1](https://github.com/status-im/nim-waku/pull/690) +- [2](https://github.com/vacp2p/rfc/issues/462#issuecomment-943869940) +- [3](https://eips.ethereum.org/EIPS/eip-778) +- [4](https://github.com/ethereum/devp2p/blob/master/discv5/discv5.md) From 02340a2774b244fb932bb8a484f79f389c69eedd Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Wed, 14 Feb 2024 19:10:05 -0500 Subject: [PATCH 51/81] Update relay-sharding.md --- standards/core/relay-sharding.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/standards/core/relay-sharding.md b/standards/core/relay-sharding.md index 03fdfaf..8372bd2 100644 --- a/standards/core/relay-sharding.md +++ b/standards/core/relay-sharding.md @@ -11,7 +11,7 @@ contributors: ## Abstract -This document describes ways of sharding the [Waku relay](/spec/11/) topic, +This document describes ways of sharding the [Waku relay](https://rfc.vac.dev/spec/11/) topic, allowing Waku networks to scale in the number of content topics. > *Note*: Scaling in the size of a single content topic is out of scope for this document. @@ -25,7 +25,7 @@ However, they do not scale to large traffic loads. A single [libp2p gossipsub mesh](https://github.com/libp2p/specs/blob/master/pubsub/gossipsub/gossipsub-v1.0.md#gossipsub-the-gossiping-mesh-router), which carries messages associated with a single pubsub topic, can be seen as a separate unstructured P2P network (control messages go beyond these boundaries, but at its core, it is a separate P2P network). -With this, the number of [Waku relay](/spec/11/) content topics that can be carried over a pubsub topic is limited. +With this, the number of [Waku relay](https://rfc.vac.dev/spec/11/) content topics that can be carried over a pubsub topic is limited. This prevents app protocols that aim to span many multicast groups (realized by content topics) from scaling. This document specifies three pubsub topic sharding methods (with varying degrees of automation), @@ -35,7 +35,7 @@ This document also covers discovery of topic shards. ## Named Sharding *Named sharding* offers apps to freely choose pubsub topic names. -It is RECOMMENDED for App protocols to follow the naming structure detailed in [23/WAKU2-TOPICS](/spec/23/). +It is RECOMMENDED for App protocols to follow the naming structure detailed in [23/WAKU2-TOPICS](https://rfc.vac.dev/spec/23/). With named sharding, managing discovery falls into the responsibility of apps. From an app protocol point of view, a subscription to a content topic `waku2/xxx` on a shard named /mesh/v1.1.1/xxx would look like: @@ -82,7 +82,7 @@ an example for the 2nd shard in the global shard cluster: `/waku/2/rs/0/2`. -> *Note*: Because *all* shards distribute payload defined in [14/WAKU2-MESSAGE](spec/14/) via [protocol buffers](https://developers.google.com/protocol-buffers/), +> *Note*: Because *all* shards distribute payload defined in [14/WAKU2-MESSAGE](https://rfc.vac.dev/spec/14/) via [protocol buffers](https://developers.google.com/protocol-buffers/), the pubsub topic name does not explicitly add `/proto` to indicate protocol buffer encoding. We use `rs` to indicate these are *relay shard* clusters; further shard types might follow in the future. @@ -102,7 +102,7 @@ so app protocols do not have to implement their own discovery method. Nodes add information about their shard participation in their [WAKU2-ENR](./enr.md/). Having a static shard participation indication as part of the ENR allows nodes -to discover peers that are part of shards via [33/WAKU2-DISCV5](/spec/33/) as well as via DNS. +to discover peers that are part of shards via [33/WAKU2-DISCV5](https://rfc.vac.dev/spec/33/) as well as via DNS. > *Note:* In the current version of this document, sharding information is directly added to the ENR. @@ -267,11 +267,11 @@ Copyright and related rights waived via [CC0](https://creativecommons.org/public ## References -* [11/WAKU2-RELAY](/spec/11/) +* [11/WAKU2-RELAY](https://rfc.vac.dev/spec/11/) * [Unstructured P2P network](https://en.wikipedia.org/wiki/Peer-to-peer#Unstructured_networks) -* [33/WAKU2-DISCV5](/spec/33/) +* [33/WAKU2-DISCV5](https://rfc.vac.dev/spec/33/) * [WAKU2-ENR](./enr.md) -* [23/WAKU2-TOPICS](/spec/23/) +* [23/WAKU2-TOPICS](https://rfc.vac.dev/spec/23/) * [Ethereum ENR sharding bit vector](https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/p2p-interface.md#metadata) * [Ethereum discv5 specification](https://github.com/ethereum/devp2p/blob/master/discv5/discv5-theory.md) * [Research log: Waku Discovery](https://vac.dev/wakuv2-apd) From 30bc0a7b0a5e9e80bc5a9416c556dd85cab53001 Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Wed, 14 Feb 2024 19:11:02 -0500 Subject: [PATCH 52/81] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d0e5888..9c336ed 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Waku RFC (Request For Comments) +# Waku Specifications Waku builds a family of privacy-preserving, censorship-resistant communication protocols for web3 applications. This repository contain RFCs from contributors wanting to imporve Waku protocols. From 20267fddbf65a26b563f9fa2cf09eda41e000514 Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Wed, 14 Feb 2024 19:31:29 -0500 Subject: [PATCH 53/81] Update README.md --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 9c336ed..830a5c1 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Waku Specifications Waku builds a family of privacy-preserving, censorship-resistant communication protocols for web3 applications. -This repository contain RFCs from contributors wanting to imporve Waku protocols. +This repository contain specification from contributors wanting to imporve Waku protocols. ## Resources Relvant Waku resouces related to the specifications located in this repository: @@ -15,12 +15,12 @@ Contributors can create specifcations relating to the Waku domain and create a pull request to begin discussion. There is no format/template for accepted specifications to the Waku RFC. -New specifications that are considered a proof of concept, -should provide some implementation to help discussion. -If rough consensus is reached, -the specification could be considered to receive a draft status at the Vac RFC repository. +New specifications are considered a proof of concept, +once a rough consensus is reached towards stabilzition, +the specification may be considered to receive the draft status and +further discussion will continue on the [Vac RFC-Index](https://github.com/vacp2p/rfc-index) repository. **NOTE:** Specifications located in this repository should be considered not production ready. -Discussion should be conducted with the intention of maturing the specification. +Discussion should be conducted with the intention of maturing each specifications. Head over to the [Vac RFC-Index](https://github.com/vacp2p/rfc-index) repository where other Waku specifcations live. From cb81c6782948a7470caa9b119a4229bf5f1720f1 Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Thu, 15 Feb 2024 11:48:10 -0500 Subject: [PATCH 54/81] Create spellcheck.yml --- .github/workflows/spellcheck.yml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 .github/workflows/spellcheck.yml diff --git a/.github/workflows/spellcheck.yml b/.github/workflows/spellcheck.yml new file mode 100644 index 0000000..834aeec --- /dev/null +++ b/.github/workflows/spellcheck.yml @@ -0,0 +1,25 @@ +# This is workflow for spell checking using PySpelling lib (https://pypi.org/project/pyspelling/) +name: Spellcheck +# Controls when the action will run. +on: + # Triggers the workflow on push or pull request events but only for the main branch + push: + branches: + - '**' + pull_request: + branches: + - '**' + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + # This workflow contains a single job called "build" + build: + # The type of runner that the job will run on + runs-on: ubuntu-latest + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + # Spellcheck + - uses: actions/checkout@v2 + - uses: igsekor/pyspelling-any@v0.0.2 + name: Spellcheck From b7d57fd103d6b97485a40080c6ca1893f4b7dbc9 Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Thu, 15 Feb 2024 11:52:54 -0500 Subject: [PATCH 55/81] Update spellcheck.yml --- .github/workflows/spellcheck.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/spellcheck.yml b/.github/workflows/spellcheck.yml index 834aeec..6bcb083 100644 --- a/.github/workflows/spellcheck.yml +++ b/.github/workflows/spellcheck.yml @@ -1,6 +1,6 @@ # This is workflow for spell checking using PySpelling lib (https://pypi.org/project/pyspelling/) -name: Spellcheck -# Controls when the action will run. +name: GitHub Spellcheck +# Controls when the action will run. on: # Triggers the workflow on push or pull request events but only for the main branch push: @@ -21,5 +21,5 @@ jobs: steps: # Spellcheck - uses: actions/checkout@v2 - - uses: igsekor/pyspelling-any@v0.0.2 + - uses: igsekor/pyspelling-any@v1.0.4 name: Spellcheck From 5812584335275dc41f643910361855755ab1fe45 Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Thu, 15 Feb 2024 13:16:37 -0500 Subject: [PATCH 56/81] Create spellcheck.yml --- spellcheck.yml | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 spellcheck.yml diff --git a/spellcheck.yml b/spellcheck.yml new file mode 100644 index 0000000..27a84d6 --- /dev/null +++ b/spellcheck.yml @@ -0,0 +1,7 @@ +matrix: + - name: Python Source + aspell: + lang: en + d: en_US + sources: + - pyspelling/**/*.py From b4e689b6ad5db562226efb6994f0f4cfb01923f8 Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Thu, 15 Feb 2024 13:19:40 -0500 Subject: [PATCH 57/81] Rename spellcheck.yml to spelling.yml --- .github/workflows/{spellcheck.yml => spelling.yml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/workflows/{spellcheck.yml => spelling.yml} (100%) diff --git a/.github/workflows/spellcheck.yml b/.github/workflows/spelling.yml similarity index 100% rename from .github/workflows/spellcheck.yml rename to .github/workflows/spelling.yml From 14d6b15ce22fecc6bee58bbe589a78512240f95e Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Thu, 15 Feb 2024 13:21:09 -0500 Subject: [PATCH 58/81] Update spellcheck.yml --- spellcheck.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/spellcheck.yml b/spellcheck.yml index 27a84d6..0e328d5 100644 --- a/spellcheck.yml +++ b/spellcheck.yml @@ -1,7 +1,7 @@ -matrix: - - name: Python Source - aspell: - lang: en - d: en_US - sources: - - pyspelling/**/*.py +- name: markdown + sources: + - README.md + aspell: + lang: en + d: en_US + mode: markdown From ed97c67f2a5ff899f9a19c3defc2bd08070bdf8f Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Thu, 15 Feb 2024 13:27:42 -0500 Subject: [PATCH 59/81] Update spellcheck.yml --- spellcheck.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spellcheck.yml b/spellcheck.yml index 0e328d5..53092d5 100644 --- a/spellcheck.yml +++ b/spellcheck.yml @@ -1,6 +1,6 @@ - name: markdown sources: - - README.md + - '**/*.md' aspell: lang: en d: en_US From da73c5521982deeac03de504d14fc8d24c63d04c Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Thu, 15 Feb 2024 13:30:47 -0500 Subject: [PATCH 60/81] Rename spellcheck.yml to pyspelling.yml --- spellcheck.yml => pyspelling.yml | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename spellcheck.yml => pyspelling.yml (100%) diff --git a/spellcheck.yml b/pyspelling.yml similarity index 100% rename from spellcheck.yml rename to pyspelling.yml From 7353872cc0cf3e0747b1f323017383f3233859ab Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Thu, 15 Feb 2024 13:37:21 -0500 Subject: [PATCH 61/81] Update spelling.yml --- .github/workflows/spelling.yml | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/.github/workflows/spelling.yml b/.github/workflows/spelling.yml index 6bcb083..06a93ca 100644 --- a/.github/workflows/spelling.yml +++ b/.github/workflows/spelling.yml @@ -1,25 +1,22 @@ # This is workflow for spell checking using PySpelling lib (https://pypi.org/project/pyspelling/) -name: GitHub Spellcheck -# Controls when the action will run. +name: Spellcheck + on: - # Triggers the workflow on push or pull request events but only for the main branch push: branches: - '**' pull_request: branches: - '**' - # Allows you to run this workflow manually from the Actions tab workflow_dispatch: -# A workflow run is made up of one or more jobs that can run sequentially or in parallel + jobs: - # This workflow contains a single job called "build" build: - # The type of runner that the job will run on runs-on: ubuntu-latest - # Steps represent a sequence of tasks that will be executed as part of the job steps: - # Spellcheck - uses: actions/checkout@v2 - uses: igsekor/pyspelling-any@v1.0.4 name: Spellcheck + env: + MATRIX: ${{ toJson(matrix) }} + run: pyspelling --matrix "$MATRIX" From 17782baffcd74b0bc83c395a7022b35a483aaf00 Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Thu, 15 Feb 2024 13:42:29 -0500 Subject: [PATCH 62/81] Rename pyspelling.yml to spellcheck.yaml --- pyspelling.yml => spellcheck.yaml | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename pyspelling.yml => spellcheck.yaml (100%) diff --git a/pyspelling.yml b/spellcheck.yaml similarity index 100% rename from pyspelling.yml rename to spellcheck.yaml From 77f69bba8b3f3494931e2e49ee7c33a8157924d6 Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Thu, 15 Feb 2024 13:44:14 -0500 Subject: [PATCH 63/81] Update spellcheck.yaml --- spellcheck.yaml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/spellcheck.yaml b/spellcheck.yaml index 53092d5..2225614 100644 --- a/spellcheck.yaml +++ b/spellcheck.yaml @@ -1,7 +1,3 @@ - name: markdown sources: - '**/*.md' - aspell: - lang: en - d: en_US - mode: markdown From 0eb3bfaf77426f379be0deebeb8983f3b3679131 Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Thu, 15 Feb 2024 13:50:04 -0500 Subject: [PATCH 64/81] Update spellcheck.yaml --- spellcheck.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/spellcheck.yaml b/spellcheck.yaml index 2225614..9d20cff 100644 --- a/spellcheck.yaml +++ b/spellcheck.yaml @@ -1,3 +1,4 @@ +matrix: - name: markdown sources: - '**/*.md' From aa809b2441737d74e261f61fa93a4a6ee4c81332 Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Thu, 15 Feb 2024 14:35:56 -0500 Subject: [PATCH 65/81] Rename incentivization.md to incentivization.md --- standards/{application => core}/incentivization.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename standards/{application => core}/incentivization.md (100%) diff --git a/standards/application/incentivization.md b/standards/core/incentivization.md similarity index 100% rename from standards/application/incentivization.md rename to standards/core/incentivization.md From 0815cf93099bb3e8f70e2292b8e06b2a850e447b Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Thu, 15 Feb 2024 14:36:44 -0500 Subject: [PATCH 66/81] Rename standards/core/noise-sessions/noise-sessions.md to standards/application/noise-sessions.md --- standards/{core/noise-sessions => application}/noise-sessions.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename standards/{core/noise-sessions => application}/noise-sessions.md (100%) diff --git a/standards/core/noise-sessions/noise-sessions.md b/standards/application/noise-sessions.md similarity index 100% rename from standards/core/noise-sessions/noise-sessions.md rename to standards/application/noise-sessions.md From e95bfb2f6cf2aa17f0971aaf2e47aada0e2af9e6 Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Thu, 15 Feb 2024 14:38:21 -0500 Subject: [PATCH 67/81] Rename standards/core/noise-sessions/images/N11M.png to assests/images/N11M.png --- .../core/noise-sessions => assests}/images/N11M.png | Bin 1 file changed, 0 insertions(+), 0 deletions(-) rename {standards/core/noise-sessions => assests}/images/N11M.png (100%) diff --git a/standards/core/noise-sessions/images/N11M.png b/assests/images/N11M.png similarity index 100% rename from standards/core/noise-sessions/images/N11M.png rename to assests/images/N11M.png From b96024556d0e1253f069e220f16e9d4eff777c28 Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Thu, 15 Feb 2024 14:38:58 -0500 Subject: [PATCH 68/81] Rename standards/core/noise-sessions/images/NM.png to assets/images/NM.png --- .../core/noise-sessions => assets}/images/NM.png | Bin 1 file changed, 0 insertions(+), 0 deletions(-) rename {standards/core/noise-sessions => assets}/images/NM.png (100%) diff --git a/standards/core/noise-sessions/images/NM.png b/assets/images/NM.png similarity index 100% rename from standards/core/noise-sessions/images/NM.png rename to assets/images/NM.png From 214ca4875ec2fcd8bd8c40d4aecc7299a239ab05 Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Thu, 15 Feb 2024 14:39:22 -0500 Subject: [PATCH 69/81] Rename N11M.png to N11M.png --- {assests => assets}/images/N11M.png | Bin 1 file changed, 0 insertions(+), 0 deletions(-) rename {assests => assets}/images/N11M.png (100%) diff --git a/assests/images/N11M.png b/assets/images/N11M.png similarity index 100% rename from assests/images/N11M.png rename to assets/images/N11M.png From bfbc4181e8d398fd1a148a57661043725e569101 Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Thu, 15 Feb 2024 14:40:13 -0500 Subject: [PATCH 70/81] Rename standards/core/peer-exchange/images/protocol.svg to assets/images/protocol.svg --- {standards/core/peer-exchange => assets}/images/protocol.svg | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {standards/core/peer-exchange => assets}/images/protocol.svg (100%) diff --git a/standards/core/peer-exchange/images/protocol.svg b/assets/images/protocol.svg similarity index 100% rename from standards/core/peer-exchange/images/protocol.svg rename to assets/images/protocol.svg From 1aff7f2b86bf6074bdaa8ea519582e066186033d Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Thu, 15 Feb 2024 14:40:33 -0500 Subject: [PATCH 71/81] Rename standards/core/peer-exchange/peer-exchange.md to standards/core/peer-exchange.md --- standards/core/{peer-exchange => }/peer-exchange.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename standards/core/{peer-exchange => }/peer-exchange.md (100%) diff --git a/standards/core/peer-exchange/peer-exchange.md b/standards/core/peer-exchange.md similarity index 100% rename from standards/core/peer-exchange/peer-exchange.md rename to standards/core/peer-exchange.md From 6ddda523df0155d6fc224c29561ce4faf63a1a77 Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Thu, 15 Feb 2024 14:47:13 -0500 Subject: [PATCH 72/81] Update README.md --- README.md | 64 +++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 55 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 830a5c1..0f7ed5a 100644 --- a/README.md +++ b/README.md @@ -1,26 +1,72 @@ # Waku Specifications Waku builds a family of privacy-preserving, censorship-resistant communication protocols for web3 applications. -This repository contain specification from contributors wanting to imporve Waku protocols. +This repository contains specifications for the Waku suite of protocols. + +## Index: +- Informational: +- Standards + - Core: + - Application: + +| Waku Specifications | Description | +| ---- | -------------- | +|[10/WAKU2](https://rfc.vac.dev/spec/10/)| Core | +|[11/WAKU2-RELAY](https://rfc.vac.dev/spec/11)| Core | +|[12/WAKU2-FILTER](https://rfc.vac.dev/spec/12)| Core| +|[13/WAKU2-STORE](https://rfc.vac.dev/spec/13/)| Core | +|[14/WAKU2-MESSAGE](https://rfc.vac.dev/spec/14/)| Core | +|[15/WAKU2-BRIDGE](https://rfc.vac.dev/spec/15)| Core | +|[16/WAKU2-RPC](https://rfc.vac.dev/spec/16)| Core | +|[17/WAKU2-RLN-RELAY](https://rfc.vac.dev/spec/17/)| Core | +|[18/WAKU2-SWAP](https://rfc.vac.dev/spec/18/)| Application | +|[19/WAKU2-LIGHTPUSH](https://rfc.vac.dev/spec/19/)| Core | +|[20/TOY-ETH-PM](https://rfc.vac.dev/spec/20/)| Application | +|[21/WAKU2-FAULT-TOLERANT-STORE](https://rfc.vac.dev/spec/21/)| Application | +|[22/TOY-CHAT](https://rfc.vac.dev/spec/22/)| Informational | +|[23/WAKU2-TOPICS](https://rfc.vac.dev/spec/23/)| Informational | +|[26/WAKU2-PAYLOAD](https://rfc.vac.dev/spec/26/)| Application | +|[27/WAKU2-PEERS](https://rfc.vac.dev/spec/27/)| Informational | +|[29/WAKU2-CONFIG](https://rfc.vac.dev/spec/29/)| Informational | +|[30/ADAPTIVE-NODES](https://rfc.vac.dev/spec/30/)| Informational | +|[33/WAKU2-DISCV5](https://rfc.vac.dev/spec/33/)| Core | +|[36/WAKU2-BINDINGS-API](https://rfc.vac.dev/spec/36/)| Core | +|[53/WAKU2-X3DH](https://rfc.vac.dev/spec/53/)| Application | +|[54/WAKU2-X3DH-SESSIONS](https://rfc.vac.dev/spec/54/)| Application | +|[ADVERSARIAL-MODELS](informational/adversarial-models.md)| Informational | +|[RELAY-STATIC-SHARD-ALLOC](informational/relay-static-shard-alloc.md)| Informational | +|[DANDELION](standards/application/dandelion.md)| Application | +|[WAKU2-DEVICE-PAIRING](standards/application/device-pairing.md)| Application | +|[WAKU2-PEER-EXCHANGE](standards/core/peer-exchange.md)| Core | +|[WAKU2-ENR](standards/core/enr.md)| Core | +|[WAKU2-NOISE](standards/application/noise.md)| Application | +|[TOR-PUSH](standards/application/tor-push.md)| Application | +|[WAKU2-INCENTIVIZATION](standards/core/incentivization.md)| Core | +|[WAKU2-METADATA](standards/core/metadata.md)| Core | +|[WAKU2-NETWORK](standards/core/network.md)| Core | +|[RELAY-SHARDING](standards/core/relay-sharding.md)| Core | +| WAKU2-STOREV3 | Coming Soon | + + ## Resources -Relvant Waku resouces related to the specifications located in this repository: +Relevant Waku resources related to the specifications located in this repository: - [Waku.org](https://waku.org/) -- [nWaku: Waku Node](https://github.com/waku-org/nwaku) +- [nwaku: Waku Node](https://github.com/waku-org/nwaku) ## Contributions Contributions are welcome from any party. -Contributors can create specifcations relating to the Waku domain and +Contributors can create specifications relating to the Waku domain and create a pull request to begin discussion. -There is no format/template for accepted specifications to the Waku RFC. +The recommended template may be used for new proposed specifications. -New specifications are considered a proof of concept, -once a rough consensus is reached towards stabilzition, +New specifications are considered a proof of concept. +Once a rough consensus is reached towards stabilization, the specification may be considered to receive the draft status and further discussion will continue on the [Vac RFC-Index](https://github.com/vacp2p/rfc-index) repository. **NOTE:** Specifications located in this repository should be considered not production ready. -Discussion should be conducted with the intention of maturing each specifications. +Discussion should be conducted with the intention of maturing each specification. -Head over to the [Vac RFC-Index](https://github.com/vacp2p/rfc-index) repository where other Waku specifcations live. +Head over to the [Vac RFC-Index](https://github.com/vacp2p/rfc-index) repository where other Waku specifications live. From 72ef66a829404809fd87674474b2424bea0990aa Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Thu, 15 Feb 2024 14:53:57 -0500 Subject: [PATCH 73/81] Rename assets/images/N11M.png to images/N11M.png --- {assets/images => images}/N11M.png | Bin 1 file changed, 0 insertions(+), 0 deletions(-) rename {assets/images => images}/N11M.png (100%) diff --git a/assets/images/N11M.png b/images/N11M.png similarity index 100% rename from assets/images/N11M.png rename to images/N11M.png From ddc374103a71a741c922c82df6cb0d261624d730 Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Thu, 15 Feb 2024 14:54:21 -0500 Subject: [PATCH 74/81] Rename assets/images/NM.png to images/NM.png --- {assets/images => images}/NM.png | Bin 1 file changed, 0 insertions(+), 0 deletions(-) rename {assets/images => images}/NM.png (100%) diff --git a/assets/images/NM.png b/images/NM.png similarity index 100% rename from assets/images/NM.png rename to images/NM.png From eca15c169fec591f1257761c70b29627d8367439 Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Thu, 15 Feb 2024 14:54:46 -0500 Subject: [PATCH 75/81] Rename assets/images/protocol.svg to images/protocol.svg --- {assets/images => images}/protocol.svg | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {assets/images => images}/protocol.svg (100%) diff --git a/assets/images/protocol.svg b/images/protocol.svg similarity index 100% rename from assets/images/protocol.svg rename to images/protocol.svg From 32b577eb32218ceef00a0ccfcfcff15a402f3286 Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Thu, 15 Feb 2024 14:55:52 -0500 Subject: [PATCH 76/81] Update peer-exchange.md --- standards/core/peer-exchange.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/standards/core/peer-exchange.md b/standards/core/peer-exchange.md index e199ed6..7b77f3e 100644 --- a/standards/core/peer-exchange.md +++ b/standards/core/peer-exchange.md @@ -34,7 +34,7 @@ As Figure 1 illustrates, the requesting node sends a request to a peer, which ac The responder replies with a list of ENRs as specified in [WAKU2-ENR](../enr.md). The [multiaddresses](https://docs.libp2p.io/concepts/addressing/) used to connect to the respective peers can be extracted from the ENRs. -![Figure 1: The responder provides a list of ENRs to the requester. These ENRs contain the information necessary for connecting to the respective peers.](./images/protocol.svg) +![Figure 1: The responder provides a list of ENRs to the requester. These ENRs contain the information necessary for connecting to the respective peers.](../../images/protocol.svg) In order to protect its anonymity, the responder MUST NOT provide peers from its actively used peer list as this opens pathways to *Neighbourhood Surveillance* attacks, as described in the [Security/Privacy Considerations Section](#securityprivacy-considerations). From 093a453d767cf9d9d8e2d218875b5547643ffb17 Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Thu, 15 Feb 2024 14:57:09 -0500 Subject: [PATCH 77/81] Update noise-sessions.md --- standards/application/noise-sessions.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/standards/application/noise-sessions.md b/standards/application/noise-sessions.md index f0962d3..9df19be 100644 --- a/standards/application/noise-sessions.md +++ b/standards/application/noise-sessions.md @@ -88,7 +88,7 @@ This is achieved through two main supported session management mechanisms that w In a $N11M$ setting, each party's device shares the same Noise session information used to encrypt and decrypt messages exchanged with the other party. -![](./images/N11M.png) +![](../../images/N11M.png) More precisely, once the first Noise session between any of Alice's and Bob's device is instantiated, its session information is securely propagated to all other devices, @@ -123,7 +123,7 @@ This session management mechanism is loosely based on the paper ["Multi-Device f In a $NM$ setting, we require all of $N$ Alice's devices to have an active Noise session with each of Bob's $M$ devices, for a total of $NM$ concurrently active Noise sessions between Alice and Bob. -![](./images/NM.png) +![](../../images/NM.png) A message is sent from the currently-in-use sender's device to all recipent's devices, by properly encrypting and sending it to the content topics of each corresponding active Noise session. From d83209187f853824c22c7b1d89aef14cdb117e7d Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Thu, 15 Feb 2024 15:54:41 -0500 Subject: [PATCH 78/81] Create LICENSE --- LICENSE | 674 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 674 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..f288702 --- /dev/null +++ b/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. From 596e061c42513602ac3139c026de595747c642d0 Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Thu, 15 Feb 2024 16:06:13 -0500 Subject: [PATCH 79/81] Create template.md --- template.md | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 template.md diff --git a/template.md b/template.md new file mode 100644 index 0000000..00c0793 --- /dev/null +++ b/template.md @@ -0,0 +1,69 @@ +--- +title: TEMPLATE +name: Specification Template +category: (Standards Track|Informational|Best Current Practice) +tags: an optional list of tags, not standard +editor: Jimmy Debe +contributors: +--- + +### (Info, remove this section) + +This section contains meta info about writing specifications. +This section (including its subsections) MUST be removed. + +[COSS](https://rfc.vac.dev/spec/1/) explains the Vac RFC process. + +### Tags + +The `tags` metadata SHOULD contain a list of tags if applicable. + +* `core` for Waku protocol definitions +* `application` for applications built on top of Waku protocol, +* `informational` for general guidelines, background information etc. + +## Abstract + + +## Background / Rationale / Motivation + +This section serves as an introduction providing background information and a motivation/rationale for the specification. + +## Theory / Semantics + +This section SHOULD explain in detail how the proposed protocol works. +It may touch on the wire format where necessary for the explanation. +This section MAY also specify endpoint behaviour when receiving specific messages, e.g. the behaviour of certain caches etc. + +## Wire Format Specification / Syntax +The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, +“NOT RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in [RFC 2119](https://www.ietf.org/rfc/rfc2119.txt). + +This section SHOULD not contain explanations of semantics and focus on concisely defining the wire format. +Implementations SHOULD adhere to these exact formats to interoperate with other implementations. +It is fine, if parts of the previous section that touch on the wire format are repeated. +The purpose of this section is having a concise definition of what an implementation sends and accepts. +Parts that are not specified here are considered implementation details. +Implementors are free to decide on how to implement these details. + + +## Implementation Suggestions (optional) +An optional *implementation suggestions* section may provide suggestions on how to approach implementation details, and, +if available, point to existing implementations for reference. + + +## (Further Optional Sections) + + +## Security/Privacy Considerations + +If there are none, this section MAY state that fact. +This section MAY contain additional relevant information, e.g. an explanation as to why there are no security consideration for the respective document. + +## Copyright + +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). + +## References + +A list of references. From 082c30fbcef88653c2b5f05bb7efc4046138542f Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Thu, 15 Feb 2024 16:15:03 -0500 Subject: [PATCH 80/81] Update README.md --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 0f7ed5a..06d4039 100644 --- a/README.md +++ b/README.md @@ -3,11 +3,11 @@ Waku builds a family of privacy-preserving, censorship-resistant communication protocols for web3 applications. This repository contains specifications for the Waku suite of protocols. -## Index: -- Informational: +## List of Specifications: +- Informational: Waku design issues, general guidelines or background information that does not constitute a new feature. - Standards - - Core: - - Application: + - Core: Standards and protocols for the core Waku p2p communications offering. + - Application: Standards and protocols that describe various applications or encryption use cases built on top of a Waku network. | Waku Specifications | Description | | ---- | -------------- | @@ -59,7 +59,7 @@ Relevant Waku resources related to the specifications located in this repository Contributions are welcome from any party. Contributors can create specifications relating to the Waku domain and create a pull request to begin discussion. -The recommended template may be used for new proposed specifications. +The recommended [template](./template.md) may be used for new proposed specifications. New specifications are considered a proof of concept. Once a rough consensus is reached towards stabilization, From 7ace67f1107d25396b7eecb5d9d733d769244dc2 Mon Sep 17 00:00:00 2001 From: Jimmy Debe <91767824+jimstir@users.noreply.github.com> Date: Tue, 20 Feb 2024 12:35:06 -0500 Subject: [PATCH 81/81] Update LICENSE --- LICENSE | 795 +++++++++----------------------------------------------- 1 file changed, 121 insertions(+), 674 deletions(-) diff --git a/LICENSE b/LICENSE index f288702..0e259d4 100644 --- a/LICENSE +++ b/LICENSE @@ -1,674 +1,121 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. +Creative Commons Legal Code + +CC0 1.0 Universal + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS + PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM + THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED + HEREUNDER. + +Statement of Purpose + +The laws of most jurisdictions throughout the world automatically confer +exclusive Copyright and Related Rights (defined below) upon the creator +and subsequent owner(s) (each and all, an "owner") of an original work of +authorship and/or a database (each, a "Work"). + +Certain owners wish to permanently relinquish those rights to a Work for +the purpose of contributing to a commons of creative, cultural and +scientific works ("Commons") that the public can reliably and without fear +of later claims of infringement build upon, modify, incorporate in other +works, reuse and redistribute as freely as possible in any form whatsoever +and for any purposes, including without limitation commercial purposes. +These owners may contribute to the Commons to promote the ideal of a free +culture and the further production of creative, cultural and scientific +works, or to gain reputation or greater distribution for their Work in +part through the use and efforts of others. + +For these and/or other purposes and motivations, and without any +expectation of additional consideration or compensation, the person +associating CC0 with a Work (the "Affirmer"), to the extent that he or she +is an owner of Copyright and Related Rights in the Work, voluntarily +elects to apply CC0 to the Work and publicly distribute the Work under its +terms, with knowledge of his or her Copyright and Related Rights in the +Work and the meaning and intended legal effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be +protected by copyright and related or neighboring rights ("Copyright and +Related Rights"). Copyright and Related Rights include, but are not +limited to, the following: + + i. the right to reproduce, adapt, distribute, perform, display, + communicate, and translate a Work; + ii. moral rights retained by the original author(s) and/or performer(s); +iii. publicity and privacy rights pertaining to a person's image or + likeness depicted in a Work; + iv. rights protecting against unfair competition in regards to a Work, + subject to the limitations in paragraph 4(a), below; + v. rights protecting the extraction, dissemination, use and reuse of data + in a Work; + vi. database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal + protection of databases, and under any national implementation + thereof, including any amended or successor version of such + directive); and +vii. other similar, equivalent or corresponding rights throughout the + world based on applicable law or treaty, and any national + implementations thereof. + +2. Waiver. To the greatest extent permitted by, but not in contravention +of, applicable law, Affirmer hereby overtly, fully, permanently, +irrevocably and unconditionally waives, abandons, and surrenders all of +Affirmer's Copyright and Related Rights and associated claims and causes +of action, whether now known or unknown (including existing as well as +future claims and causes of action), in the Work (i) in all territories +worldwide, (ii) for the maximum duration provided by applicable law or +treaty (including future time extensions), (iii) in any current or future +medium and for any number of copies, and (iv) for any purpose whatsoever, +including without limitation commercial, advertising or promotional +purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each +member of the public at large and to the detriment of Affirmer's heirs and +successors, fully intending that such Waiver shall not be subject to +revocation, rescission, cancellation, termination, or any other legal or +equitable action to disrupt the quiet enjoyment of the Work by the public +as contemplated by Affirmer's express Statement of Purpose. + +3. Public License Fallback. Should any part of the Waiver for any reason +be judged legally invalid or ineffective under applicable law, then the +Waiver shall be preserved to the maximum extent permitted taking into +account Affirmer's express Statement of Purpose. In addition, to the +extent the Waiver is so judged Affirmer hereby grants to each affected +person a royalty-free, non transferable, non sublicensable, non exclusive, +irrevocable and unconditional license to exercise Affirmer's Copyright and +Related Rights in the Work (i) in all territories worldwide, (ii) for the +maximum duration provided by applicable law or treaty (including future +time extensions), (iii) in any current or future medium and for any number +of copies, and (iv) for any purpose whatsoever, including without +limitation commercial, advertising or promotional purposes (the +"License"). The License shall be deemed effective as of the date CC0 was +applied by Affirmer to the Work. Should any part of the License for any +reason be judged legally invalid or ineffective under applicable law, such +partial invalidity or ineffectiveness shall not invalidate the remainder +of the License, and in such case Affirmer hereby affirms that he or she +will not (i) exercise any of his or her remaining Copyright and Related +Rights in the Work or (ii) assert any associated claims and causes of +action with respect to the Work, in either case contrary to Affirmer's +express Statement of Purpose. + +4. Limitations and Disclaimers. + + a. No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + b. Affirmer offers the Work as-is and makes no representations or + warranties of any kind concerning the Work, express, implied, + statutory or otherwise, including without limitation warranties of + title, merchantability, fitness for a particular purpose, non + infringement, or the absence of latent or other defects, accuracy, or + the present or absence of errors, whether or not discoverable, all to + the greatest extent permissible under applicable law. + c. Affirmer disclaims responsibility for clearing rights of other persons + that may apply to the Work or any use thereof, including without + limitation any person's Copyright and Related Rights in the Work. + Further, Affirmer disclaims responsibility for obtaining any necessary + consents, permissions or other rights required for any use of the + Work. + d. Affirmer understands and acknowledges that Creative Commons is not a + party to this document and has no duty or obligation with respect to + this CC0 or use of the Work.