diff --git a/docs/protocol.rst b/docs/protocol.rst
index 3c159565..967ab363 100644
--- a/docs/protocol.rst
+++ b/docs/protocol.rst
@@ -500,13 +500,201 @@ getpubkey
 When a node has the hash of a public key (from an address) but not the public
 key itself, it must send out a request for the public key.
 
+.. list-table::
+   :header-rows: 1
+   :widths: auto
+
+   * - Field Size
+     - Description
+     - Data type
+     - Comments
+   * - 20
+     - ripe
+     - uchar[]
+     - The ripemd hash of the public key. This field is only included when the
+       address version is <= 3.
+   * - 32
+     - tag
+     - uchar[]
+     - The tag derived from the address version, stream number, and ripe. This
+       field is only included when the address version is >= 4.
 
 pubkey
 ^^^^^^
 
 A version 2 pubkey. This is still in use and supported by current clients but
-new v2 addresses are not generated by clients.
+*new* v2 addresses are not generated by clients.
 
+.. list-table::
+   :header-rows: 1
+   :widths: auto
+
+   * - Field Size
+     - Description
+     - Data type
+     - Comments
+   * - 4
+     - behavior bitfield
+     - uint32_t
+     - A bitfield of optional behaviors and features that can be expected from
+       the node receiving the message.
+   * - 64
+     - public signing key
+     - uchar[]
+     - The ECC public key used for signing (uncompressed format;
+       normally prepended with \x04 )
+   * - 64
+     - public encryption key
+     - uchar[]
+     - The ECC public key used for encryption (uncompressed format;
+       normally prepended with \x04 )
+
+.. list-table:: A version 3 pubkey
+   :header-rows: 1
+   :widths: auto
+
+   * - Field Size
+     - Description
+     - Data type
+     - Comments
+   * - 4
+     - behavior bitfield
+     - uint32_t
+     - A bitfield of optional behaviors and features that can be expected from
+       the node receiving the message.
+   * - 64
+     - public signing key
+     - uchar[]
+     - The ECC public key used for signing (uncompressed format;
+       normally prepended with \x04 )
+   * - 64
+     - public encryption key
+     - uchar[]
+     - The ECC public key used for encryption (uncompressed format;
+       normally prepended with \x04 )
+   * - 1+
+     - nonce_trials_per_byte
+     - var_int
+     - Used to calculate the difficulty target of messages accepted by this
+       node. The higher this value, the more difficult the Proof of Work must
+       be before this individual will accept the message. This number is the
+       average number of nonce trials a node will have to perform to meet the
+       Proof of Work requirement. 1000 is the network minimum so any lower
+       values will be automatically raised to 1000.
+   * - 1+
+     - extra_bytes
+     - var_int
+     - Used to calculate the difficulty target of messages accepted by this
+       node. The higher this value, the more difficult the Proof of Work must
+       be before this individual will accept the message. This number is added
+       to the data length to make sending small messages more difficult.
+       1000 is the network minimum so any lower values will be automatically
+       raised to 1000.
+   * - 1+
+     - sig_length
+     - var_int
+     - Length of the signature
+   * - sig_length
+     - signature
+     - uchar[]
+     - The ECDSA signature which, as of protocol v3, covers the object
+       header starting with the time, appended with the data described in this
+       table down to the extra_bytes.
+
+.. list-table:: A version 4 pubkey
+   :header-rows: 1
+   :widths: auto
+
+   * - Field Size
+     - Description
+     - Data type
+     - Comments
+   * - 32
+     - tag
+     - uchar[]
+     - The tag, made up of bytes 32-64 of the double hash of the address data
+       (see example python code below)
+   * - ?
+     - encrypted
+     - uchar[]
+     - Encrypted pubkey data.
+
+When version 4 pubkeys are created, most of the data in the pubkey is encrypted.
+This is done in such a way that only someone who has the Bitmessage address
+which corresponds to a pubkey can decrypt and use that pubkey. This prevents
+people from gathering pubkeys sent around the network and using the data from
+them to create messages to be used in spam or in flooding attacks.
+
+In order to encrypt the pubkey data, a double SHA-512 hash is calculated from
+the address version number, stream number, and ripe hash of the Bitmessage
+address that the pubkey corresponds to. The first 32 bytes of this hash are used
+to create a public and private key pair with which to encrypt and decrypt the
+pubkey data, using the same algorithm as message encryption
+(see :doc:`encryption`). The remaining 32 bytes of this hash are added to the
+unencrypted part of the pubkey and used as a tag, as above. This allows nodes to
+determine which pubkey to decrypt when they wish to send a message.
+
+In PyBitmessage, the double hash of the address data is calculated using the
+python code below:
+
+.. code-block:: python
+
+    doubleHashOfAddressData = hashlib.sha512(hashlib.sha512(
+        encodeVarint(addressVersionNumber) + encodeVarint(streamNumber) + hash
+    ).digest()).digest()
+
+
+.. list-table:: Encrypted data in version 4 pubkeys:
+   :header-rows: 1
+   :widths: auto
+
+   * - Field Size
+     - Description
+     - Data type
+     - Comments
+   * - 4
+     - behavior bitfield
+     - uint32_t
+     - A bitfield of optional behaviors and features that can be expected from
+       the node receiving the message.
+   * - 64
+     - public signing key
+     - uchar[]
+     - The ECC public key used for signing (uncompressed format;
+       normally prepended with \x04 )
+   * - 64
+     - public encryption key
+     - uchar[]
+     - The ECC public key used for encryption (uncompressed format;
+       normally prepended with \x04 )
+   * - 1+
+     - nonce_trials_per_byte
+     - var_int
+     - Used to calculate the difficulty target of messages accepted by this
+       node. The higher this value, the more difficult the Proof of Work must
+       be before this individual will accept the message. This number is the
+       average number of nonce trials a node will have to perform to meet the
+       Proof of Work requirement. 1000 is the network minimum so any lower
+       values will be automatically raised to 1000.
+   * - 1+
+     - extra_bytes
+     - var_int
+     - Used to calculate the difficulty target of messages accepted by this
+       node. The higher this value, the more difficult the Proof of Work must
+       be before this individual will accept the message. This number is added
+       to the data length to make sending small messages more difficult.
+       1000 is the network minimum so any lower values will be automatically
+       raised to 1000.
+   * - 1+
+     - sig_length
+     - var_int
+     - Length of the signature
+   * - sig_length
+     - signature
+     - uchar[]
+     - The ECDSA signature which covers everything from the object header
+       starting with the time, then appended with the decrypted data down to
+       the extra_bytes. This was changed in protocol v3.
 
 msg
 ^^^