+ mgf = GC_INIT(algs.mgf, k, ksz);
+ IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, {
+ trace_block(T_CRYPTO, "unmasking key", k, ksz);
+ trace_block(T_CRYPTO, "masked ciphertext", p, n);
+ }))
+ GC_DECRYPT(mgf, p, buf_t, n);
+ d = mp_loadb(d, buf_t, n);
+ IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, {
+ trace_block(T_CRYPTO, "index plaintext", buf_t, n);
+ trace(T_CRYPTO, "unmasked index = %s", mpstr(d));
+ }))
+ GC_DESTROY(mgf);
+ return (d);
+}
+
+/* --- @hashcheck@ --- *
+ *
+ * Arguments: @ge *kpub@ = sender's public key
+ * @ge *cc@ = receiver's challenge
+ * @ge *c@ = sender's challenge
+ * @ge *y@ = reply to sender's challenge
+ *
+ * Returns: Pointer to the hash value (in @buf_t@)
+ *
+ * Use: Computes the check-value hash, used to mask or unmask
+ * indices to prove the validity of challenges. This computes
+ * the masking key used in challenge check values. This is
+ * really the heart of the whole thing, since it ensures that
+ * the index can be recovered from the history of hashing
+ * queries, which gives us (a) a proof that the authentication
+ * process is zero-knowledge, and (b) a proof that the whole
+ * key-exchange is deniable.
+ */
+
+static const octet *hashcheck(ge *kpub, ge *cc, ge *c, ge *y)
+{
+ ghash *h = GH_INIT(algs.h);
+
+ HASH_STRING(h, "tripe-expected-reply");
+ hashge(h, kpub);
+ hashge(h, cc);
+ hashge(h, c);
+ hashge(h, y);
+ GH_DONE(h, buf_t);
+ IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, {
+ trace(T_CRYPTO, "computing challenge check hash");
+ trace(T_CRYPTO, "public key = %s", gestr(gg, kpub));
+ trace(T_CRYPTO, "receiver challenge = %s", gestr(gg, cc));
+ trace(T_CRYPTO, "sender challenge = %s", gestr(gg, c));
+ trace(T_CRYPTO, "sender reply = %s", gestr(gg, y));
+ trace_block(T_CRYPTO, "hash output", buf_t, algs.hashsz);
+ }))
+ GH_DESTROY(h);
+ return (buf_t);
+}
+
+/* --- @sendchallenge@ --- *
+ *
+ * Arguments: @keyexch *kx@ = pointer to key exchange block
+ * @buf *b@ = output buffer for challenge
+ * @ge *c@ = peer's actual challenge
+ * @const octet *hc@ = peer's challenge cookie
+ *
+ * Returns: ---
+ *
+ * Use: Writes a full challenge to the message buffer.
+ */
+
+static void sendchallenge(keyexch *kx, buf *b, ge *c, const octet *hc)
+{
+ G_TOBUF(gg, b, kx->c);
+ buf_put(b, hc, algs.hashsz);
+ mpmask(b, kx->alpha, indexsz,
+ hashcheck(kpub, c, kx->c, kx->rx), algs.hashsz);