diff --git a/bsspeke.c b/bsspeke.c
index 40aa2afd4edbf64bc349a3ac5a76c3a299418d8f..27c2906ee53d6402958ec2450d9693e6282af2ec 100644
--- a/bsspeke.c
+++ b/bsspeke.c
@@ -127,6 +127,8 @@ bsspeke_client_generate_message1
     crypto_x25519_scalarmult(msg1->blind, client->r, curve_point, 256);
     print_point("blind", msg1->blind);
     debug(DEBUG, "Done");
+
+    msg1->client_id = client->client_id;
     return;
 }
 
@@ -144,20 +146,25 @@ bsspeke_server_setup_generate_message2
     (
         bsspeke_setup_msg2_t *msg2,
         const bsspeke_setup_msg1_t *msg1,
-        uint8_t *salt, const size_t salt_len,
+        // uint8_t *salt, const size_t salt_len,
+        bsspeke_user_info_t *user_info,
         bsspeke_server_ctx *server_ctx
     )
 {
     // We're setting up a new account
     // So we have to create a new random salt for the user
     debug(DEBUG, "Generating new salt");
-    arc4random_buf(salt, salt_len);
-    print_point("salt", salt);
+    user_info->salt_len = 32;
+    arc4random_buf(user_info->salt, user_info->salt_len);
+    print_point("salt", user_info->salt);
 
     // Hash the salt
     debug(DEBUG, "Hashing the salt");
     uint8_t H_salt[32];
-    crypto_blake2b_general(H_salt, 32, NULL, 0, salt, salt_len);
+    crypto_blake2b_general(H_salt, 32,
+                           NULL, 0,
+                           user_info->salt,
+                           user_info->salt_len);
     // Use clamp() to ensure we stay on the curve in the multiply below
     crypto_x25519_clamp(H_salt);
     print_point("H_salt", H_salt);
@@ -240,9 +247,29 @@ bsspeke_client_setup_generate_message3
     crypto_x25519_scalarmult(msg3->V, v, msg3->P, 256);
     print_point("V", msg3->V);
 
+    // Send our PHF params so the server can store them for us
+    msg3->phf_blocks = phf_blocks;
+    msg3->phf_iterations = phf_iterations;
+
     return 0;
 }
 
+void
+bsspeke_server_setup_process_message3
+    (
+        bsspeke_setup_msg3_t *msg3,
+        bsspeke_user_info_t *user_info,
+        bsspeke_server_ctx *server
+    )
+{
+    // Setup Message 3 contains stuff that we need to remember.
+    // The user info struct is where we store stuff that
+    // needs to persist across sessions.
+    memcpy(user_info->P, msg3->P, 32);
+    memcpy(user_info->V, msg3->V, 32);
+    user_info->phf_blocks = msg3->phf_blocks;
+    user_info->phf_iterations = msg3->phf_iterations;
+}
 
 void
 bsspeke_client_login_generate_message1
@@ -256,16 +283,26 @@ bsspeke_client_login_generate_message1
 void
 bsspeke_server_login_generate_message2(bsspeke_login_msg2_t *msg2,
                                  const bsspeke_login_msg1_t *msg1,
-                                 const uint8_t *salt, const size_t salt_len,
-                                 uint8_t P[32], uint8_t V[32],
-                                 uint32_t phf_blocks,
-                                 uint32_t phf_iterations,
+                                 // const uint8_t *salt, const size_t salt_len,
+                                 // uint8_t P[32], uint8_t V[32],
+                                 // uint32_t phf_blocks,
+                                 // uint32_t phf_iterations,
+                                 const bsspeke_user_info_t *user_info,
                                  bsspeke_server_ctx *server
 ) {
+    // Record the client's id
+    server->client_id_len = strlen(msg1->client_id);
+    server->client_id = (uint8_t *)malloc(server->client_id_len + 1);
+    strncpy(server->client_id, msg1->client_id, server->client_id_len);
+    printf("Server got msg1 from [%s]\n", (char *)(server->client_id));
+
     // Hash the salt
     debug(DEBUG, "Hashing the salt");
     uint8_t H_salt[32];
-    crypto_blake2b_general(H_salt, 32, NULL, 0, salt, salt_len);
+    crypto_blake2b_general(H_salt, 32,
+                           NULL, 0,
+                           user_info->salt,
+                           user_info->salt_len);
     // Use clamp() to ensure we stay on the curve in the multiply below
     crypto_x25519_clamp(H_salt);
     print_point("H_salt", H_salt);
@@ -280,20 +317,20 @@ bsspeke_server_login_generate_message2(bsspeke_login_msg2_t *msg2,
     crypto_x25519_clamp(server->b);
     print_point("b", server->b);
 
-    debug(DEBUG, "Using client's base point P");
-    print_point("P", P);
+    debug(DEBUG, "Using user's base point P");
+    print_point("P", user_info->P);
 
     // Compute public key B = b * P, save it in msg2->B
     debug(DEBUG, "Computing ephemeral public key B = b * P");
-    crypto_x25519_scalarmult(server->B, server->b, P, 256);
+    crypto_x25519_scalarmult(server->B, server->b, user_info->P, 256);
     print_point("B", server->B);
 
     // Copy the public key into the outgoing message as well
     memcpy(msg2->B, server->B, 32);
 
     // Copy the PHF params too
-    msg2->phf_blocks = phf_blocks;
-    msg2->phf_iterations = phf_iterations;
+    msg2->phf_blocks = user_info->phf_blocks;
+    msg2->phf_iterations = user_info->phf_iterations;
 
     return;
 }
@@ -426,86 +463,105 @@ bsspeke_client_login_generate_message3(bsspeke_login_msg3_t *msg3,
 int
 bsspeke_server_login_generate_message4(bsspeke_login_msg4_t *msg4,
                                  const bsspeke_login_msg3_t *msg3,
-                                 bsspeke_server_ctx *server_ctx
+                                 const bsspeke_user_info_t *user_info,
+                                 bsspeke_server_ctx *server
 ) {
     // Compute the two Diffie-Hellman shared secrets
+    debug(DEBUG, "Computing Diffie-Hellman shared secrets");
     // DH shared secret from b * A
     uint8_t b_A[32];
-    crypto_x25519(b_A, server_ctx->b, msg3->A);
+    crypto_x25519(b_A, server->b, msg3->A);
+    print_point("b * A", b_A);
     // DH shared secret from b * V
+    //print_point("V", user_info->V);
     uint8_t b_V[32];
-    crypto_x25519(b_V, server_ctx->b, server_ctx->V);
+    crypto_x25519(b_V, server->b, user_info->V);
+    print_point("b * V", b_V);
 
     // Hash everything we've learned so far to generate k, save it in ctx->k
+    debug(DEBUG, "Hashing state so far to generate K_s");
     {
         crypto_blake2b_ctx hash_ctx;
         crypto_blake2b_general_init(&hash_ctx, 32, NULL, 0);
         crypto_blake2b_update(&hash_ctx,
-                              server_ctx->client_id,
-                              server_ctx->client_id_len);
+                              server->client_id,
+                              server->client_id_len);
         crypto_blake2b_update(&hash_ctx,
-                              server_ctx->server_id,
-                              server_ctx->server_id_len);
+                              server->server_id,
+                              server->server_id_len);
         crypto_blake2b_update(&hash_ctx, msg3->A, 32);
-        crypto_blake2b_update(&hash_ctx, server_ctx->B, 32);
+        crypto_blake2b_update(&hash_ctx, server->B, 32);
         crypto_blake2b_update(&hash_ctx, b_A, 32);
         crypto_blake2b_update(&hash_ctx, b_V, 32);
-        crypto_blake2b_final(&hash_ctx, server_ctx->K_s);
+        crypto_blake2b_final(&hash_ctx, server->K_s);
     }
+    print_point("K_s", server->K_s);
 
     // Check that the client's hash is correct
     // Compute H( k || VERIFY_CLIENT_MODIFIER )
+    debug(DEBUG, "Checking client's verifier hash");
     uint8_t my_client_verifier[32];
     {
         crypto_blake2b_ctx hash_ctx;
         crypto_blake2b_general_init(&hash_ctx, 32, NULL, 0);
-        crypto_blake2b_update(&hash_ctx, server_ctx->K_s, 32);
+        crypto_blake2b_update(&hash_ctx, server->K_s, 32);
         crypto_blake2b_update(&hash_ctx,
                               (uint8_t *)BSSPEKE_VERIFY_CLIENT_MODIFIER,
                               BSSPEKE_VERIFY_CLIENT_MODIFIER_LEN);
         crypto_blake2b_final(&hash_ctx, my_client_verifier);
     }
+    print_point("client's", msg3->client_verifier);
+    print_point("mine", my_client_verifier);
 
     // Compare vs msg3->client_verifier
     if( crypto_verify32(msg3->client_verifier, my_client_verifier) != 0 ) {
+        debug(ERROR, "Client's verifier doesn't match!");
         return -1;
     }
+    debug(DEBUG, "Client's verifier checks out");
 
     // Compute our own verifier H( k || VERIFY_SERVER_MODIFIER ), save it in msg4->server_verifier
+    debug(DEBUG, "Computing server verifier hash");
     {
         crypto_blake2b_ctx hash_ctx;
         crypto_blake2b_general_init(&hash_ctx, 32, NULL, 0);
-        crypto_blake2b_update(&hash_ctx, server_ctx->K_s, 32);
+        crypto_blake2b_update(&hash_ctx, server->K_s, 32);
         crypto_blake2b_update(&hash_ctx,
                               (uint8_t *)BSSPEKE_VERIFY_SERVER_MODIFIER,
                               BSSPEKE_VERIFY_SERVER_MODIFIER_LEN);
         crypto_blake2b_final(&hash_ctx, msg4->server_verifier);
     }
+    print_point("server_v", msg4->server_verifier);
 
     // If we made it this far, return success
     return 0;
 }
 
 int
-bsspeke_client_verify_message4(const bsspeke_login_msg4_t *msg4,
-                               const bsspeke_client_ctx *client_ctx
+bsspeke_client_login_verify_message4(const bsspeke_login_msg4_t *msg4,
+                               const bsspeke_client_ctx *client
 ) {
     // Compute our own version of the server's verifier hash
+    debug(DEBUG, "Verifying hash from the server");
     uint8_t my_server_verifier[32];
     {
         crypto_blake2b_ctx hash_ctx;
         crypto_blake2b_general_init(&hash_ctx, 32, NULL, 0);
-        crypto_blake2b_update(&hash_ctx, client_ctx->K_c, 32);
+        crypto_blake2b_update(&hash_ctx, client->K_c, 32);
         crypto_blake2b_update(&hash_ctx,
                               (uint8_t *)BSSPEKE_VERIFY_SERVER_MODIFIER,
                               BSSPEKE_VERIFY_SERVER_MODIFIER_LEN);
         crypto_blake2b_final(&hash_ctx, my_server_verifier);
     }
+    print_point("mine", my_server_verifier);
+    print_point("server's", msg4->server_verifier);
 
     // If the hashes don't match, return failure
     if( crypto_verify32(msg4->server_verifier, my_server_verifier) != 0 ) {
+        debug(WARN, "Server's hash doesn't match.  Aborting.");
         return -1;
     }
+    debug(DEBUG, "Server's hash checks out.  SUCCESS!");
 
     // Otherwise, return success
     return 0;
diff --git a/bsspeke.h b/bsspeke.h
index 8385b2afd21df55e4169a6efcd053ed1d1d343e5..29fbbaa156dd22528d2a9b3a7a5f8e01f9b01714 100644
--- a/bsspeke.h
+++ b/bsspeke.h
@@ -57,8 +57,8 @@ typedef struct {
     uint8_t *client_id;    // Client's identifier (eg Matrix user_id)
     size_t client_id_len;
 
-    uint8_t P[32];         // Base point for the user
-    uint8_t V[32];         // User's long-term public key
+    //uint8_t P[32];         // Base point for the user
+    //uint8_t V[32];         // User's long-term public key
 
     uint8_t b[32];         // Ephemeral private key
     uint8_t B[32];         // Ephemeral public key
@@ -68,6 +68,17 @@ typedef struct {
     uint8_t K_s[32];       // Session key
 } bsspeke_server_ctx;
 
+typedef struct {
+    uint8_t salt[32];
+    size_t salt_len;
+
+    uint8_t P[32];
+    uint8_t V[32];
+
+    uint32_t phf_blocks;
+    uint32_t phf_iterations;
+} bsspeke_user_info_t;
+
 typedef struct {
     char *client_id;
     uint8_t blind[32];
@@ -128,7 +139,8 @@ bsspeke_server_setup_generate_message2
 (
     bsspeke_setup_msg2_t *msg2,
     const bsspeke_setup_msg1_t *msg1,
-    uint8_t *salt, const size_t salt_len,
+    // uint8_t *salt, const size_t salt_len,
+    bsspeke_user_info_t *user_info,
     bsspeke_server_ctx *server_ctx
 );
 
@@ -141,6 +153,14 @@ bsspeke_client_setup_generate_message3
     bsspeke_client_ctx *client
 );
 
+void
+bsspeke_server_setup_process_message3
+(
+    bsspeke_setup_msg3_t *msg3,
+    bsspeke_user_info_t *user_info,
+    bsspeke_server_ctx *server
+);
+
 void
 bsspeke_client_login_generate_message1(bsspeke_login_msg1_t *msg1,
                                  bsspeke_client_ctx *client);
@@ -148,11 +168,12 @@ bsspeke_client_login_generate_message1(bsspeke_login_msg1_t *msg1,
 void
 bsspeke_server_login_generate_message2(bsspeke_login_msg2_t *msg2,
                                  const bsspeke_login_msg1_t *msg1,
-                                 const uint8_t *salt, const size_t salt_len,
-                                 uint8_t P[32], uint8_t V[32],
-                                 uint32_t phf_blocks,
-                                 uint32_t phf_iterations,
-                                 bsspeke_server_ctx *server_ctx);
+                                 // const uint8_t *salt, const size_t salt_len,
+                                 // uint8_t P[32], uint8_t V[32],
+                                 // uint32_t phf_blocks,
+                                 // uint32_t phf_iterations,
+                                 const bsspeke_user_info_t *user,
+                                 bsspeke_server_ctx *server);
 
 int
 bsspeke_client_login_generate_message3(bsspeke_login_msg3_t *msg3,
@@ -162,10 +183,11 @@ bsspeke_client_login_generate_message3(bsspeke_login_msg3_t *msg3,
 int
 bsspeke_server_login_generate_message4(bsspeke_login_msg4_t *msg4,
                                  const bsspeke_login_msg3_t *msg3,
+                                 const bsspeke_user_info_t *user_info,
                                  bsspeke_server_ctx *server_ctx);
 
 int
-bsspeke_client_verify_message4(const bsspeke_login_msg4_t *msg4,
-                               const bsspeke_client_ctx *client_ctx);
+bsspeke_client_login_verify_message4(const bsspeke_login_msg4_t *msg4,
+                               const bsspeke_client_ctx *client);
 
 #endif
diff --git a/demo.c b/demo.c
index c6d36f475a7c479dad1a547e990d3521f5eece9f..ce01b1cdf918f588eccc04d33d43fca6d0c4d1db 100644
--- a/demo.c
+++ b/demo.c
@@ -4,9 +4,7 @@
 
 #include "bsspeke.h"
 
-int demo_setup(uint8_t salt[32],
-               uint8_t P[32],
-               uint8_t V[32])
+int demo_setup(bsspeke_user_info_t *user_info)
 {
     bsspeke_client_ctx client;
     bsspeke_server_ctx server;
@@ -40,7 +38,7 @@ int demo_setup(uint8_t salt[32],
     puts("");
     puts("Setup: Server generating message 2");
     bsspeke_server_setup_generate_message2(&msg2, &msg1,
-                                           salt, 32,
+                                           user_info,
                                            &server);
 
     puts("");
@@ -50,9 +48,8 @@ int demo_setup(uint8_t salt[32],
                                            &client);
     
     puts("");
-    puts("Setup: Saving parameters from setup");
-    memcpy(P, msg3.P, 32);
-    memcpy(V, msg3.V, 32);
+    puts("Setup: Server processing message 3");
+    bsspeke_server_setup_process_message3(&msg3, user_info, &server);
 
     puts("");
     puts("Setup: Done");
@@ -60,9 +57,7 @@ int demo_setup(uint8_t salt[32],
     return 0;
 }
 
-int demo_login(uint8_t salt[32],
-               uint8_t P[32],
-               uint8_t V[32])
+int demo_login(bsspeke_user_info_t *user_info)
 {
     bsspeke_client_ctx client;
     bsspeke_server_ctx server;
@@ -97,15 +92,23 @@ int demo_login(uint8_t salt[32],
     puts("");
     puts("Login: Server generating message 2");
     bsspeke_server_login_generate_message2(&msg2, &msg1,
-                                           salt, 32,
-                                           P, V,
-                                           100000, 3,
+                                           // salt, 32,
+                                           // P, V,
+                                           // 100000, 3,
+                                           user_info,
                                            &server);
 
     puts("");
     puts("Login: Client generating message 3");
     bsspeke_client_login_generate_message3(&msg3, &msg2, &client);
 
+    puts("");
+    puts("Login: Server generating message 4");
+    bsspeke_server_login_generate_message4(&msg4, &msg3, user_info, &server);
+
+    puts("");
+    puts("Login: Client verifying message 4");
+    bsspeke_client_login_verify_message4(&msg4, &client);
 
     return 0;
 
@@ -114,19 +117,16 @@ int demo_login(uint8_t salt[32],
 int main(int argc, char *argv[])
 {
     // Here we're pretending to be the server's long-term storage
-    // It needs to know the salt, V, and P for each registered user
-    uint8_t salt[32];
-    uint8_t V[32];
-    uint8_t P[32];
+    bsspeke_user_info_t user_info;
 
     int rc = 0;
 
-    if( (rc = demo_setup(salt, P, V)) != 0 ) {
+    if( (rc = demo_setup(&user_info)) != 0 ) {
         puts("Setup failed :(");
         exit(-1);
     }
 
-    if( (rc = demo_login(salt, P, V)) != 0 ) {
+    if( (rc = demo_login(&user_info)) != 0 ) {
         puts("Login failed :(");
         exit(-1);
     }