diff --git a/docs/pow.rst b/docs/pow.rst
new file mode 100644
index 00000000..3786b075
--- /dev/null
+++ b/docs/pow.rst
@@ -0,0 +1,77 @@
+Proof of work
+=============
+
+This page describes Bitmessage's Proof of work ("POW") mechanism as it exists in
+Protocol Version 3. In this document, hash() means SHA512(). SHA512 was chosen
+as it is widely supported and so that Bitcoin POW hardware cannot trivially be
+used for Bitmessage POWs. The author acknowledges that they are essentially the
+same algorithm with a different key size.
+
+Both ``averageProofOfWorkNonceTrialsPerByte`` and ``payloadLengthExtraBytes``
+are set by the owner of a Bitmessage address. The default and minimum for each
+is 1000. (This is the same as difficulty 1. If the difficulty is 2, then this
+value is 2000). The purpose of ``payloadLengthExtraBytes`` is to add some extra
+weight to small messages.
+
+Do a POW
+--------
+
+Let us use a ``msg`` message as an example::
+
+   payload = embeddedTime + encodedObjectVersion + encodedStreamNumber + encrypted
+
+``payloadLength``
+   the length of payload, in bytes, + 8
+   (to account for the nonce which we will append later)
+``TTL``
+   the number of seconds in between now and the object expiresTime.
+
+.. include:: pow_formula.rst
+
+::
+
+   initialHash = hash(payload)
+
+start with ``trialValue = 99999999999999999999``
+
+also start with ``nonce = 0`` where nonce is 8 bytes in length and can be
+hashed as if it is a string.
+
+::
+
+   while trialValue > target:
+       nonce = nonce + 1
+       resultHash = hash(hash( nonce || initialHash ))
+       trialValue = the first 8 bytes of resultHash, converted to an integer
+
+When this loop finishes, you will have your 8 byte nonce value which you can
+prepend onto the front of the payload. The message is then ready to send.
+
+Check a POW
+-----------
+
+Let us assume that ``payload`` contains the payload for a msg message (the nonce
+down through the encrypted message data).
+
+``nonce``
+   the first 8 bytes of payload
+``dataToCheck``
+   the ninth byte of payload on down (thus it is everything except the nonce)
+
+::
+
+   initialHash = hash(dataToCheck)
+
+   resultHash = hash(hash( nonce || initialHash ))
+
+``POWValue``
+   the first eight bytes of resultHash converted to an integer
+``TTL``
+   the number of seconds in between now and the object ``expiresTime``.
+
+.. include:: pow_formula.rst
+
+If ``POWValue`` is less than or equal to ``target``, then the POW check passes.
+
+
+
diff --git a/docs/pow_formula.rst b/docs/pow_formula.rst
new file mode 100644
index 00000000..16c3f174
--- /dev/null
+++ b/docs/pow_formula.rst
@@ -0,0 +1,7 @@
+
+.. math::
+
+   target = \frac{2^{64}}{{\displaystyle
+   nonceTrialsPerByte (payloadLength + payloadLengthExtraBytes + \frac{
+   TTL (payloadLength + payloadLengthExtraBytes)}{2^{16}})
+   }}
diff --git a/docs/protocol.rst b/docs/protocol.rst
index 5a7045fb..c814ecaf 100644
--- a/docs/protocol.rst
+++ b/docs/protocol.rst
@@ -289,12 +289,53 @@ object
 
 An object is a message which is shared throughout a stream. It is the only
 message which propagates; all others are only between two nodes. Objects have a
-type, like 'msg', or 'broadcast'. To be a valid object, the Proof Of Work must
-be done. The maximum allowable length of an object (not to be confused with the
-objectPayload) is |2^18| bytes.
+type, like 'msg', or 'broadcast'. To be a valid object, the
+:doc:`pow` must be done. The maximum allowable length of an object
+(not to be confused with the ``objectPayload``) is |2^18| bytes.
 
 .. |2^18| replace:: 2\ :sup:`18`\
 
+.. list-table:: Message structure
+   :header-rows: 1
+   :widths: auto
+
+   * - Field Size
+     - Description
+     - Data type
+     - Comments
+   * - 8
+     - nonce
+     - uint64_t
+     - Random nonce used for the :doc:`pow`
+   * - 8
+     - expiresTime
+     - uint64_t
+     - The "end of life" time of this object (be aware, in version 2 of the
+       protocol this was the generation time). Objects shall be shared with
+       peers until its end-of-life time has been reached. The node should store
+       the inventory vector of that object for some extra period of time to
+       avoid reloading it from another node with a small time delay. The time
+       may be no further than 28 days + 3 hours in the future.
+   * - 4
+     - objectType
+     - uint32_t
+     - Four values are currently defined: 0-"getpubkey", 1-"pubkey", 2-"msg",
+       3-"broadcast". All other values are reserved. Nodes should relay objects
+       even if they use an undefined object type.
+   * - 1+
+     - version
+     - var_int
+     - The object's version. Note that msg objects won't contain a version
+       until Sun, 16 Nov 2014 22:00:00 GMT.
+   * - 1+
+     - stream number
+     - var_int
+     - The stream number in which this object may propagate
+   * - ?
+     - objectPayload
+     - uchar[]
+     - This field varies depending on the object type; see below.
+
 
 Object types
 ------------