Table of Contents
All DDRP nodes identify themselves on the network using a secp256k1 public
key. These identity keys are used to establish authenticated communication
channels between pairs of nodes. These channels are currently unencrypted,
though an encrypted transport (e.g., Noise) could be added at a later date.
Once a channel is established, the same identity keys are then used to
authenticate individual DDRP messages as they cross the wire.
DDRP is a decentralized network with no global consensus mechanism. As such, the duty of enforcing compliance with the protocol's rules fall to each node individually. "Enforcement" in this case usually means disconnecting from faulty or deliberately misbehaving peers and blocking connections with them in the future. To enable this type of enforcement, peers need to identify both themselves and any messages they send. DDRP's authenticated transport mechanism is designed to solve this problem.
DDRP's authenticated transport is defined for pairs of nodes only. It operates in two phases:
- A handshake phase, in which both nodes prove ownership over their respective identity key.
- A messaging phase, in which nodes exchange DDRP messages after signing them with their identity key.
A node's "identity key" refers to a secp256k1 key pair that identifies the
node to the rest of the network. It is distinct from the secp256k1 key pair
used by blob owners to authenticate data.
The handshake works as follows. We will use the standard "Alice and Bob" notation to denote each participant:
- Alice knows Bob's identity key
Bob_ikbeforehand. Alice signs aHellomessage using her identity keyAlice_ikcontaining her random nonce
Alice_nonce.
- Bob receives the
Hellomessage from Alice, and verifies that its signature is valid. If it is, Bob responds with aHellomessage of his own that includes bothAlice_nonceand his random nonceBob_nonce. - Alice receives the
Hellomessage from Bob, and verifies that its signature is correct. She also verifies that theAlice_noncevalue inside the message equals the one that she generated earlier. If both the signature and the nonce are valid, she responds with a signedHelloAckmessage containingBob_nonce. - Bob receives the
HelloAckmessage, and verifies that its signature is correct. He also verifies that theBob_noncevalue inside the message equals the one that he generated earlier. No further messages are exchanged.
To reiterate, the primary goal of the handshake phase is for both Alice and Bob to prove that they own their respective identity keys. In this case, the nonce values are used for this purpose: Both Alice and Bob must generate a never-before-seen signature that signs over nonce data chosen by their counterparty.
Note that DDRP's threat model excludes certain common attack scenarios. See the [Security Considerations](#security-considerations) for more detail both on the threat model as well as known vulnerabilities.
Once the handshake is complete, nodes begin exchanging messages with one another. All messages are placed in an envelope prior to being sent over the wire. Envelopes are signed with the sending node's identity key prior to being sent.
DDRP messages MUST be sent inside an envelope with the following schema:
magic: Auint32field that contains a magic number representing the current DDRP network.type: Auint8field that represents the type of the message.timestamp: Atime.Timefield that represents the message's time of creation.message: A[]bytefield containing the message itself.signature:ASignaturefield over thetype,timestamp, andmessagefields.
The magic field MUSt be set to 0xcafecafe.
The type field is used to determine the schema of the message field. The
value of the type field MUST correspond to a message type defined as part of
a DDRP sub-protocol.
The timestamp field is used to prevent replay attacks. It MUST be set.
The message field MUST be a PIP-1 encoded message whose type matches the
type described by the type field.
The signature field is generated according to the following procedure:
- The
typeandmessagefields are PIP-1 encoded into a structure with the schema[type, timestamp, message]. - The
BLAKE2B-256hash of the above structure is calculated. - The sender's key identity signs the resulting hash.
Nodes MUST ignore messages with an invalid type or signature field.
Nodes SHOULD disconnect if mal-formed messages are received.
Hello messages are used by DDRP nodes during the handshake phase. They have
the following schema:
type:0x00- Data:
protocol_version:uint32local_nonce:[32]byteremote_nonce:[32]bytepublic_key:PublicKeyexternal_ip:IPexternal_port:uint16user_agent:string
The protocol_version field MUST be set to 0x01. This value will be
incremented if changes are made to the protocol. Node implementations SHOULD try
to remain backwards-compatible unless incompatible protocol changes are made.
The local_nonce field represents the nonce value expected by the local
(i.e., sending) node. It MUST be set to a 32-byte random value.
The remote_nonce field represents the nonce value expected by the remote
(i.e., receiving) node. It MUST be set to either a the value provided by the
counterparty node, or all zeroes.
The public_key field represents the sending node's identity key. It MUST be
set to a valid secp256k1 public key.
The external_ip field represents the sending node's externally-visible IP.
The external_port field represents the sending node's listen port. If the
sending node is not Internet-accessible, this SHOULD be set to zero.
The user_agent field is a user-defined field that allows nodes to identify
the software they are running.
HelloAck messages are used by DDRP nodes during the handshake phase. They
have the following schema:
type:0x01Data:
nonce:[32]byte
The nonce field MUST be set to the counterparty node's nonce as defined by
their Hello message.
For the handshake phase, we will assume two nodes named Alice and Bob, respectively. Both nodes start with the following state:
Alice_ik: Alice's identity key pair.Alice_nonce: Alice's nonce. Set to zero initially.Bob_ik: Bob's identity key pair.Bob_nonce: Bob's nonce. Set to zero initially.
We will assume that Alice is initiating the handshake with Bob. The initiating
node MUST know the counterparty node's ik prior to initiating the handshake.
While all messages in the below description are enveloped using the procedure
described above, we will reiterate the process for clarity.
Upon initiation, Alice:
- Generates a random 32-byte nonce
Alice_nonce. - Constructs a
Hellomessage as per the specification above. Since Alice is sending theHellomessage, she will set thelocal_noncefield toAlice_nonce. - Generates a message envelope for the
Hellomessage, and signs it withAlice_ik. - Sends the envelope to Bob.
Upon receipt of Alice's Hello envelope, Bob:
Verifies Alice's signature of the received envelope by comparing the
secp256k1public key recovered from the envelope's signature against thepublic_keyfield.- Bob MUST disconnect from Alice and abort the handshake process if the
- signature fails verification.
- Bob MUST disconnect from Alice if the provided
protocol_versionfield
- Bob MUST disconnect from Alice if the provided
does not equal
0x02.Constructs a
Hellomessage as per the specification above. Since Bob is sending theHellomessage, he will set thelocal_noncefield toBob_nonceand theremote_noncefield toAlice_nonceas provided by thelocal_noncefield in Alice'sHellomessage.Generates a message envelope for the
Hellomessage, and signs it withBob_ik.Sends the envelope to Alice.
Upon receipt of Bob's Hello envelope, Alice:
Verifies Bob's signature of the received envelope by comparing the
secp256k1public key recovered fron the envelope's signature against thepublic_keyfield.- Alice MUST disconnect from Bob and abort the handshake process if the
- signature fails verification.
- Alice MUST disconnect from Bob if the provided
protocol_versionfield
- Alice MUST disconnect from Bob if the provided
- does not equal
0x02. - Alice MUST disconnect from Bob if the provided
remote_noncevalue
- Alice MUST disconnect from Bob if the provided
does not match
Alice_nonce.Sets the value of
Bob_nonceto the value of thelocal_noncefield.Constructs a
HelloAckmessage as per the specification above. Since Alice is sending theHelloAckmessage, she will set thenoncefield toBob_nonce.
Upon receipt of Alice's HelloAck envelope, Bob:
Verifies Alice's signature of the received envelope by comparing the
secp256k1public key recovered from the envelope's signature againstAlice_ik.- Bob MUST disconnect from Alice and abort the handshake process if the
- signature fails verification.
- Bob MUST disconnect from Alice if the provided
noncevalue does not
- Bob MUST disconnect from Alice if the provided
match
Bob_nonce.
The handshake phase is complete at this point, and the protocol can enter the messaging phase.
Once two DDRP nodes have finished handshaking, all following messages MUST be included in a message envelope. The schema for the message envelope is described in the Message Envelope section above.
Nodes:
- MUST disconnect from any node that sends an envelope with a mal-formed signature.
- MUST disconnect from any node that sends an envelope whose
timestampfield is more than thirty seconds in the past or future.
This protocol is designed for the following threat model:
- Malicious actors may not impersonate an honest node.
- Malicious nodes are to be blacklisted on a per-node basis.
As such, it is explicitly not designed to be resistant against man-in-the-middle attacks, since such an attack would imply that nodes would be communicating with the "man in the middle" rather than each other. Furthermore, it is not designed to provide resistance against deep packet inspection or other traffic analysis techniques.