             (serial/decompose templates/black-box-dscr vouch-buf)))))))
 
 (s/fdef open-client-crypto-box
-        :args (s/cat :initiate ::K/initiate-packet-spec
+  :args (s/cat :log-state ::log2/state
+               :initiate ::K/initiate-packet-spec
                      :current-client ::client-state)
-        :ret ::K/initiate-client-vouch-wrapper)
+  :ret (s/keys :req [::log2/state]
+               :opt [::K/initiate-client-vouch-wrapper]))
 (defn open-client-crypto-box
-  [{:keys [::K/outer-i-nonce]
+  [log-state
+   {:keys [::K/outer-i-nonce]
     ^bytes vouch-wrapper ::K/vouch-wrapper
     :as initiate}
    current-client]

          (.getBytes inner-pk-buf 0 inner-pk)
          (b-t/bytes= short-pk inner-pk))))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Public

(s/fdef handle!
        :args (s/cat :state ::state/state
                     :packet ::shared/network-packet))
(defn handle!
  [state
   {:keys [:host :port]
    message :message
    :as packet}]
  (log/info "Handling incoming initiate packet: " packet)
  (let [message (bytes message)]
    (or
     (let [n (count message)]
       (if (>= n (+ K/box-zero-bytes packet-header-length))
         ;; Note the extra 16 bytes
         ;; The minimum packet length is actually
         ;; (+ 544 K/box-zero-bytes)
         ;; Because the message *has* to have the bytes for 0
         ;; padding, even if it's 0 length.
         (let [tmplt (update-in K/initiate-packet-dscr
                                [::K/vouch-wrapper ::K/length]
                                +
                                (- n packet-header-length))
               initiate (serial/decompose-array tmplt message)
               client-short-pk (bytes (::K/clnt-short-pk initiate))]
           (if-not (possibly-re-initiate-existing-client-connection! state initiate)
             (let [active-client (state/find-client state client-short-pk)]
               (if-let [cookie (extract-cookie (::state/cookie-cutter state)
                                               initiate)]
                 (do
                   (log/info (str "Succssfully extracted cookie"))
                   (let [server-short-sk (bytes (::templates/srvr-short-sk cookie))
                         _ (assert server-short-sk (str "Missing ::templates/srvr-short-sk among "
                                                        (keys cookie)))
                         active-client (state/configure-shared-secrets active-client
                                                                       client-short-pk
                                                                       server-short-sk)]
                     (state/alter-client-state! state active-client)
                     ;; Now we've verified that the Initiate packet came from a
                     ;; client that has the secret key associated with the short-term
                     ;; public key.
                     ;; It included a secret cookie that we generated sometime within the
                     ;; past couple of minutes.
                     ;; Now we're ready to tackle handling the main message body cryptobox.
                     ;; This corresponds to line 373 in the reference implementation.
                     (try
                       (when-let [client-message-box (open-client-crypto-box initiate active-client)]
                         (let [client-long-pk (bytes (::K/long-term-public-key client-message-box))]
                           (try
                             (log/info (str "Extracted message box from client's Initiate packet.\n"
                                            "Keys:\n"
                                            (keys client-message-box)
                                            "\nThe long-term public key:\n"
                                            (do
                                              ;; This matches both the original log
                                              ;; message and what we see below when we
                                              ;; try to extract the inner hidden key
                                              #_[0x63 0xA4 0x65 0xDE
                                                 ,,,
                                                 0x91 0xCC 0xE3 0x02]
                                              (b-t/->string client-long-pk))))
                             (if (validate-server-name state client-message-box)
                               ;; This takes us down to line 381
                               (when (verify-client-public-key-triad state client-short-pk client-message-box)
                                 (let [^ByteBuf rcvd-nonce-buffer (::K/outer-i-nonce initiate)
                                       rcvd-nonce-array (byte-array specs/client-nonce-suffix-length)
                                       _ (.getBytes rcvd-nonce-buffer 0 rcvd-nonce-array)
                                       _ (.release rcvd-nonce-buffer)
                                       rcvd-nonce (b-t/uint64-unpack rcvd-nonce-array)
                                       active-client (assoc active-client
                                                            ;; Seems very likely that I should convert this
                                                            ;; to a byte-array
                                                            ::client-extension (::K/clnt-xtn initiate)
                                                            ::client-ip host
                                                            ::client-port port
                                                            ::state/received-nonce rcvd-nonce)
                                       ;; API/design Q: Does it make sense for me to supply this?
                                       ;; I'm responsible for writing to it, which means I should control
                                       ;; when it closes...but it feels more than a little silly
                                       writer (strm/stream)
                                       spawner (::state/child-spawner! state)
                                       child (spawner writer)
                                       client-with-child (assoc active-client
                                                                ::state/child-interaction (assoc child
                                                                                                 ::state/reader-consumed (message/add-listener! state child))
                                                                ;; Q: What is this for?
                                                                ;; It doesn't seem to match
                                                                ::state/message-len 0
                                                                ;; Reference implementation stores the client-short<->server-short
                                                                ;; keypair here again.
                                                                ;; But I already did that during a call to configure-shared-secrets
                                                                ::state/client-security (into (::state/client-security state)
                                                                                              #:frereth-cp.shared.specs {:public-long client-long-pk
                                                                                                                         :public-short client-short-pk
                                                                                                                         :frereth-cp.server/server-short-sk server-short-sk}))
                                       child-reader (::state/write->child child)]
                                   ;; This doesn't actually matter. That field should probably be
                                   ;; considered a private black-box member from our perspective.
                                   ;; But it seems helpful for keeping which is what straight
                                   (assert (= writer child-reader))
                                   (state/alter-client-state! state client-with-child)

                                   ;; And then forward the message to our new(?) child
                                   (log/debug (str "Trying to send child-message from "
                                                   (keys client-message-box)))
                                   (let [sent (strm/try-put! writer
                                                             (::K/message client-message-box)
                                                             K/send-child-message-timeout
                                                             ::timeout)]
                                     (dfrd/on-realized sent
                                                       (fn [x]
                                                         (if (not= x ::timeout)
                                                           (log/info "Message forwarded to new child: " x)
                                                           (log/error "Timed out trying to send message to" child)))
                                                       (fn [x] (log/info "Forwarding message to new child failed: " x))))
                                   ;; Q: Will there ever be an opportunity for calling this in
                                   ;; a purely functional manner?
                                   ;; Surely there's more to this than just the side-effects
                                   nil)))
                             (catch ExceptionInfo ex
                               (log/error ex "Failure after decrypting inner client cryptobox")))))
                       (catch ExceptionInfo ex
                         (log/error ex "Initiate packet looked good enough to establish client session, but failed later")))))
                 (log/error "FIXME: Debug only: cookie extraction failed")))
             (log/warn "TODO: Handle additional Initiate packet from " client-short-pk)))
         (log/warn (str "Truncated initiate packet. Only received " n " bytes"))))
     ;; If nothing's changing, just maintain status quo
     state)))

             [bit-twiddling :as b-t]
             [constants :as K]
             [crypto :as crypto]
             [logging :as log2]
             [serialization :as serial]
             [specs :as specs]
             [templates :as templates]]
