diff --git a/bsspeke.c b/bsspeke.c
index b95bb42aa2d63ba71e15081a98d72ead54c81a35..677c2b7f5f0c7e9b88bffca3199a883b4f20b98e 100644
--- a/bsspeke.c
+++ b/bsspeke.c
@@ -81,16 +81,20 @@ bsspeke_client_init(bsspeke_client_ctx *ctx,
 
 void
 bsspeke_server_init(bsspeke_server_ctx *ctx,
-                    const char* server_id, const size_t server_id_len
+                    const char* server_id, const size_t server_id_len,
+                    const char* client_id, const size_t client_id_len
 ) {
     ctx->server_id = (uint8_t *)server_id;
     ctx->server_id_len = server_id_len;
+
+    ctx->client_id = (uint8_t *)client_id;
+    ctx->client_id_len = client_id_len;
 }
 
 void
-bsspeke_client_generate_message1
+bsspeke_client_generate_blind
 (
-    bsspeke_login_msg1_t *msg1,
+    uint8_t blind[32],
     bsspeke_client_ctx *client
 ) {
     debug(DEBUG, "Hashing client's password");
@@ -135,71 +139,81 @@ bsspeke_client_generate_message1
 
     debug(DEBUG, "Multiplying curve point by r");
     // 3. Multiply our curve point by r
-    crypto_x25519_scalarmult(msg1->blind, client->r, curve_point, 256);
-    print_point("blind", msg1->blind);
+    crypto_x25519_scalarmult(blind, client->r, curve_point, 256);
+    print_point("blind", blind);
     debug(DEBUG, "Done");
 
-    msg1->client_id = client->client_id;
     return;
 }
 
 void
-bsspeke_client_setup_generate_message1
-(
-    bsspeke_setup_msg1_t *msg1,
-    bsspeke_client_ctx *client
-) {
-    bsspeke_client_generate_message1(msg1, client);
-}
-
-void
-bsspeke_server_setup_generate_message2
+bsspeke_server_blind_salt
     (
-        bsspeke_setup_msg2_t *msg2,
-        const bsspeke_setup_msg1_t *msg1,
-        // uint8_t *salt, const size_t salt_len,
-        bsspeke_user_info_t *user_info,
-        bsspeke_server_ctx *server_ctx
+        uint8_t blind_salt[32],
+        const uint8_t blind[32],
+        const uint8_t *salt, const size_t salt_len
     )
 {
+    /*
+    // FIXME This function no longer generates its own salt!
+    //       We MUST do this before calling the function!!!
     // We're setting up a new account
     // So we have to create a new random salt for the user
     debug(DEBUG, "Generating new salt");
-    user_info->salt_len = 32;
-    //arc4random_buf(user_info->salt, user_info->salt_len);
+    salt_len = 32;
     generate_random_bytes(user_info->salt, user_info->salt_len);
-    print_point("salt", user_info->salt);
+    */
+    print_point("salt", salt);
 
     // Hash the salt
     debug(DEBUG, "Hashing the salt");
     uint8_t H_salt[32];
     crypto_blake2b_general(H_salt, 32,
                            NULL, 0,
-                           user_info->salt,
-                           user_info->salt_len);
+                           salt,
+                           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);
-    // Multiply H(salt) by msg1->blind, save into msg2->blind_salt
+    // Multiply H(salt) by blind, save into blind_salt
     debug(DEBUG, "Multiplying H_salt by the user's blind");
-    crypto_x25519_scalarmult(msg2->blind_salt, H_salt, msg1->blind, 256);
-    print_point("blndsalt", msg2->blind_salt);
+    crypto_x25519_scalarmult(blind_salt, H_salt, blind, 256);
+    print_point("blndsalt", blind_salt);
+}
+
+void
+bsspeke_server_generate_B(const uint8_t P[32],
+                          bsspeke_server_ctx *server)
+{
+    // Generate random ephemeral private key b, save it in server->b
+    debug(DEBUG, "Generating ephemeral private key b");
+    //arc4random_buf(server->b, 32);
+    generate_random_bytes(server->b, 32);
+    crypto_x25519_clamp(server->b);
+    print_point("b", server->b);
+
+    debug(DEBUG, "Using user's base point P");
+    print_point("P", 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);
+    print_point("B", server->B);
+
 }
 
 int
-bsspeke_client_setup_generate_message3
-    (
-        bsspeke_setup_msg3_t *msg3,
-        const bsspeke_setup_msg2_t *msg2,
-        uint32_t phf_blocks, uint32_t phf_iterations,
-        bsspeke_client_ctx *client
-    )
+bsspeke_client_generate_keys_from_password(const uint8_t blind_salt[32],
+                                           uint32_t phf_blocks, uint32_t phf_iterations,
+                                           bsspeke_client_ctx *client)
 {
     // Sanity checks first, before we do any work
     if( phf_blocks < BSSPEKE_ARGON2_MIN_PHF_BLOCKS ) {
+        debug(ERROR, "Requested PHF blocks below the minimum");
         return -1;
     }
     if( phf_iterations < BSSPEKE_ARGON2_MIN_PHF_ITERATIONS ) {
+        debug(ERROR, "Requested PHF iterations below the minimum");
         return -1;
     }
 
@@ -207,12 +221,10 @@ bsspeke_client_setup_generate_message3
     // Multiply the blinded salt by 1/r to get the oblivious salt
     // Here we rely on Monocypher to do the heavy lifting for us
     debug(DEBUG, "Removing the blind from the oblivious salt");
-    crypto_x25519_inverse(oblivious_salt, client->r, msg2->blind_salt);
+    crypto_x25519_inverse(oblivious_salt, client->r, blind_salt);
     print_point("obv_salt", oblivious_salt);
 
     // Hash the oblivious salt together with the id's to create the salt for the PHF
-    uint8_t password_hash[64];
-
     debug(DEBUG, "Creating the salt for the PHF");
     uint8_t phf_salt[32];
     {
@@ -230,6 +242,7 @@ bsspeke_client_setup_generate_message3
     print_point("phf_salt", phf_salt);
 
     debug(DEBUG, "Running the PHF to generate p and v");
+    uint8_t password_hash[64];
     void *work_area;
     if ((work_area = malloc(phf_blocks * 1024)) == NULL) {
         return -1;
@@ -241,180 +254,71 @@ bsspeke_client_setup_generate_message3
     free(work_area);
 
     // p || v = pwKdf(password, BlindSalt, idC, idS, settings)
-    uint8_t *p = &(password_hash[0]);
-    uint8_t *v = &(password_hash[32]);
-    // FIXME Should we clamp() v before we multiply???
-    crypto_x25519_clamp(v);
-    print_point("p", p);
-    print_point("v", v);
+    uint8_t *tmp_p = &(password_hash[0]);
+    uint8_t *tmp_v = &(password_hash[32]);
+    // clamp() v before we do anything else with it
+    crypto_x25519_clamp(tmp_v);
 
-    // Hash p onto the curve to get this user's base point P
-    //uint8_t P[32];
-    debug(DEBUG, "Hashing p onto the curve to get P");
-    crypto_hidden_to_curve(msg3->P, p);
-    print_point("P", msg3->P);
+    memcpy(client->p, tmp_p, 32);
+    memcpy(client->v, tmp_v, 32);
+    crypto_wipe(password_hash, 64);
 
-    // Generate our long-term public key V = v * P
-    debug(DEBUG, "V = v * P");
-    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;
+    print_point("p", client->p);
+    print_point("v", client->v);
 
     return 0;
 }
+        
 
-void
-bsspeke_server_setup_process_message3
+int
+bsspeke_client_generate_P_and_V
     (
-        bsspeke_setup_msg3_t *msg3,
-        bsspeke_user_info_t *user_info,
-        bsspeke_server_ctx *server
+        uint8_t P[32], uint8_t V[32],
+        const uint8_t blind_salt[32],
+        uint32_t phf_blocks, uint32_t phf_iterations,
+        bsspeke_client_ctx *client
     )
 {
-    // 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
-(
-    bsspeke_login_msg1_t *msg1,
-    bsspeke_client_ctx *client
-) {
-    bsspeke_client_generate_message1(msg1, client);
-}
-
-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 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,
-                           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);
-    // Multiply H(salt) by msg1->blind, save into msg2->blind_salt
-    debug(DEBUG, "Multiplying H_salt by the user's blind");
-    crypto_x25519_scalarmult(msg2->blind_salt, H_salt, msg1->blind, 256);
-    print_point("blndsalt", msg2->blind_salt);
-
-    // Generate random ephemeral private key b, save it in ctx->b
-    debug(DEBUG, "Generating ephemeral private key b");
-    //arc4random_buf(server->b, 32);
-    generate_random_bytes(server->b, 32);
-    crypto_x25519_clamp(server->b);
-    print_point("b", server->b);
-
-    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, user_info->P, 256);
-    print_point("B", server->B);
+    int rc = bsspeke_client_generate_keys_from_password(blind_salt,
+                                                        phf_blocks, phf_iterations,
+                                                        client);
+    if( rc != 0 ) {
+        debug(ERROR, "Password hashing function failed");
+        return -1;
+    }
 
-    // Copy the public key into the outgoing message as well
-    memcpy(msg2->B, server->B, 32);
+    // Hash p onto the curve to get this user's base point P
+    //uint8_t P[32];
+    debug(DEBUG, "Hashing p onto the curve to get P");
+    crypto_hidden_to_curve(P, client->p);
+    print_point("P", P);
 
-    // Copy the PHF params too
-    msg2->phf_blocks = user_info->phf_blocks;
-    msg2->phf_iterations = user_info->phf_iterations;
+    // Generate our long-term public key V = v * P
+    debug(DEBUG, "V = v * P");
+    crypto_x25519_scalarmult(V, client->v, P, 256);
+    print_point("V", V);
 
-    return;
+    return 0;
 }
 
 
 int
-bsspeke_client_login_generate_message3(bsspeke_login_msg3_t *msg3,
-                                 const bsspeke_login_msg2_t *msg2,
-                                 bsspeke_client_ctx *client
+bsspeke_client_generate_A(const uint8_t blind_salt[32],
+                          uint32_t phf_blocks, uint32_t phf_iterations,
+                          bsspeke_client_ctx *client
 ) {
-    // Sanity checks first, before we do any work
-    if( msg2->phf_blocks < BSSPEKE_ARGON2_MIN_PHF_BLOCKS ) {
-        debug(ERROR, "phf_blocks is too low.  Aborting.");
-        return -1;
-    }
-    if( msg2->phf_iterations < BSSPEKE_ARGON2_MIN_PHF_ITERATIONS ) {
-        debug(ERROR, "phf_iterations is too low.  Aborting.");
+    int rc = bsspeke_client_generate_keys_from_password(blind_salt,
+                                                        phf_blocks, phf_iterations,
+                                                        client);
+    if( rc != 0 ) {
+        debug(ERROR, "Password hashing failed");
         return -1;
     }
 
-    uint8_t oblivious_salt[32];
-    // Multiply the blinded salt by 1/r to get the oblivious salt
-    // Here we rely on Monocypher to do the heavy lifting for us
-    debug(DEBUG, "Removing the blind from the oblivious salt");
-    crypto_x25519_inverse(oblivious_salt, client->r, msg2->blind_salt);
-    print_point("obv_salt", oblivious_salt);
-
-    // Hash the oblivious salt together with the id's to create the salt for the PHF
-    uint8_t password_hash[64];
-
-    debug(DEBUG, "Creating the salt for the PHF");
-    uint8_t phf_salt[32];
-    {
-        crypto_blake2b_ctx hash_ctx;
-        crypto_blake2b_general_init(&hash_ctx, 32, NULL, 0);
-        crypto_blake2b_update(&hash_ctx, oblivious_salt, 32);
-        crypto_blake2b_update(&hash_ctx,
-                              client->client_id,
-                              client->client_id_len);
-        crypto_blake2b_update(&hash_ctx,
-                              client->server_id,
-                              client->server_id_len);
-        crypto_blake2b_final(&hash_ctx, phf_salt);
-    }
-    print_point("phf_salt", phf_salt);
-
-    debug(DEBUG, "Running the PHF to generate p and v");
-    void *work_area;
-    if ((work_area = malloc(msg2->phf_blocks * 1024)) == NULL) {
-        debug(ERROR, "Failed to malloc() memory for PHF work area");
-        return -1;
-    }
-    crypto_argon2i(password_hash, 64, work_area,
-                   msg2->phf_blocks, msg2->phf_iterations,
-                   client->password, client->password_len,
-                   phf_salt, 32);
-    free(work_area);
-
-    // p || v = pwKdf(password, BlindSalt, idC, idS, settings)
-    uint8_t *p = &(password_hash[0]);
-    uint8_t *v = &(password_hash[32]);
-    // In the setup protocol, we clamped v before using it
-    // So we should do the same here
-    crypto_x25519_clamp(v);
-    print_point("p", p);
-    print_point("v", v);
-
     // Hash p onto the curve to get this user's base point P
     uint8_t P[32];
     debug(DEBUG, "Hashing p onto the curve to get P");
-    crypto_hidden_to_curve(P, p);
+    crypto_hidden_to_curve(P, client->p);
     print_point("P", P);
 
     // Generate a random ephemeral private key a, store it in ctx->a
@@ -425,18 +329,25 @@ bsspeke_client_login_generate_message3(bsspeke_login_msg3_t *msg3,
     print_point("a", client->a);
     // Generate the ephemeral public key A = a * P, store it in msg3->A
     debug(DEBUG, "Generating ephemeral public key A = a * P");
-    crypto_x25519_scalarmult(msg3->A, client->a, P, 256);
-    print_point("A", msg3->A);
+    crypto_x25519_scalarmult(client->A, client->a, P, 256);
+    print_point("A", client->A);
 
+    return 0;
+}
+
+void
+bsspeke_client_derive_shared_key(const uint8_t B[32],
+                                 bsspeke_client_ctx *client)
+{
     // Compute the two Diffie-Hellman shared secrets 
     debug(DEBUG, "Computing Diffie-Hellman shared secrets");
     // DH shared secret from a * B
     uint8_t a_B[32];
-    crypto_x25519(a_B, client->a, msg2->B);
+    crypto_x25519(a_B, client->a, B);
     print_point("a * B", a_B);
     // DH shared secret from v * B
     uint8_t v_B[32];
-    crypto_x25519(v_B, v, msg2->B);
+    crypto_x25519(v_B, client->v, B);
     print_point("v * B", v_B);
 
     // Hash everything we know so far to generate our key, save it in ctx->K_c
@@ -450,14 +361,19 @@ bsspeke_client_login_generate_message3(bsspeke_login_msg3_t *msg3,
         crypto_blake2b_update(&hash_ctx,
                               client->server_id,
                               client->server_id_len);
-        crypto_blake2b_update(&hash_ctx, msg3->A, 32);
-        crypto_blake2b_update(&hash_ctx, msg2->B, 32);
+        crypto_blake2b_update(&hash_ctx, client->A, 32);
+        crypto_blake2b_update(&hash_ctx, B, 32);
         crypto_blake2b_update(&hash_ctx, a_B, 32);
         crypto_blake2b_update(&hash_ctx, v_B, 32);
         crypto_blake2b_final(&hash_ctx, client->K_c);
     }
     print_point("K_c", client->K_c);
+}
 
+void
+bsspeke_client_generate_verifier(uint8_t client_verifier[32],
+                                 bsspeke_client_ctx *client)
+{
     // Hash k and the client modifier to get our verifier, save it in msg3->client_verifier
     debug(DEBUG, "Hashing K_c and modifier to get our verifier");
     {
@@ -467,29 +383,25 @@ bsspeke_client_login_generate_message3(bsspeke_login_msg3_t *msg3,
         crypto_blake2b_update(&hash_ctx,
                               (uint8_t *)BSSPEKE_VERIFY_CLIENT_MODIFIER,
                               BSSPEKE_VERIFY_CLIENT_MODIFIER_LEN);
-        crypto_blake2b_final(&hash_ctx, msg3->client_verifier);
+        crypto_blake2b_final(&hash_ctx, client_verifier);
     }
-    print_point("client_v", msg3->client_verifier);
-
-    return 0;
+    print_point("client_v", client_verifier);
 }
 
-int
-bsspeke_server_login_generate_message4(bsspeke_login_msg4_t *msg4,
-                                 const bsspeke_login_msg3_t *msg3,
-                                 const bsspeke_user_info_t *user_info,
+void
+bsspeke_server_derive_shared_key(const uint8_t A[32],
+                                 const uint8_t V[32],
                                  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->b, msg3->A);
+    crypto_x25519(b_A, server->b, 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->b, user_info->V);
+    crypto_x25519(b_V, server->b, V);
     print_point("b * V", b_V);
 
     // Hash everything we've learned so far to generate k, save it in ctx->k
@@ -503,13 +415,19 @@ bsspeke_server_login_generate_message4(bsspeke_login_msg4_t *msg4,
         crypto_blake2b_update(&hash_ctx,
                               server->server_id,
                               server->server_id_len);
-        crypto_blake2b_update(&hash_ctx, msg3->A, 32);
+        crypto_blake2b_update(&hash_ctx, A, 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->K_s);
     }
     print_point("K_s", server->K_s);
+}
+
+int
+bsspeke_server_verify_client(uint8_t client_verifier[32],
+                             bsspeke_server_ctx *server
+) {
 
     // Check that the client's hash is correct
     // Compute H( k || VERIFY_CLIENT_MODIFIER )
@@ -524,17 +442,24 @@ bsspeke_server_login_generate_message4(bsspeke_login_msg4_t *msg4,
                               BSSPEKE_VERIFY_CLIENT_MODIFIER_LEN);
         crypto_blake2b_final(&hash_ctx, my_client_verifier);
     }
-    print_point("client's", msg3->client_verifier);
+    print_point("client's", client_verifier);
     print_point("mine", my_client_verifier);
 
     // Compare vs msg3->client_verifier
-    if( crypto_verify32(msg3->client_verifier, my_client_verifier) != 0 ) {
+    if( crypto_verify32(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
+    return 0;
+}
+
+void
+bsspeke_server_generate_verifier(uint8_t server_verifier[32],
+                                 bsspeke_server_ctx *server
+) {
+    // Compute our own verifier H( k || VERIFY_SERVER_MODIFIER ), save it in server_verifier
     debug(DEBUG, "Computing server verifier hash");
     {
         crypto_blake2b_ctx hash_ctx;
@@ -543,17 +468,14 @@ bsspeke_server_login_generate_message4(bsspeke_login_msg4_t *msg4,
         crypto_blake2b_update(&hash_ctx,
                               (uint8_t *)BSSPEKE_VERIFY_SERVER_MODIFIER,
                               BSSPEKE_VERIFY_SERVER_MODIFIER_LEN);
-        crypto_blake2b_final(&hash_ctx, msg4->server_verifier);
+        crypto_blake2b_final(&hash_ctx, server_verifier);
     }
-    print_point("server_v", msg4->server_verifier);
-
-    // If we made it this far, return success
-    return 0;
+    print_point("server_v", server_verifier);
 }
 
 int
-bsspeke_client_login_verify_message4(const bsspeke_login_msg4_t *msg4,
-                               const bsspeke_client_ctx *client
+bsspeke_client_verify_server(const uint8_t server_verifier[32],
+                             const bsspeke_client_ctx *client
 ) {
     // Compute our own version of the server's verifier hash
     debug(DEBUG, "Verifying hash from the server");
@@ -568,10 +490,10 @@ bsspeke_client_login_verify_message4(const bsspeke_login_msg4_t *msg4,
         crypto_blake2b_final(&hash_ctx, my_server_verifier);
     }
     print_point("mine", my_server_verifier);
-    print_point("server's", msg4->server_verifier);
+    print_point("server's", server_verifier);
 
     // If the hashes don't match, return failure
-    if( crypto_verify32(msg4->server_verifier, my_server_verifier) != 0 ) {
+    if( crypto_verify32(server_verifier, my_server_verifier) != 0 ) {
         debug(WARN, "Server's hash doesn't match.  Aborting.");
         return -1;
     }
diff --git a/bsspeke.h b/bsspeke.h
index 099c8e72e818d53fa75ecc44611e157414ca3cc8..6acc212ea0114ce2c4e7c3f3454196107684dc90 100644
--- a/bsspeke.h
+++ b/bsspeke.h
@@ -47,9 +47,12 @@ typedef struct {
     uint8_t r[32];
     // Server's ephemeral public key
     uint8_t B[32];
-    // Ephemeral keypair
+    // Ephemeral keys
     uint8_t a[32];
-    //uint8_t A[32];
+    uint8_t A[32];
+    // Long term keys
+    uint8_t v[32];
+    uint8_t p[32];
     // Session key
     uint8_t K_c[32];
 } bsspeke_client_ctx;
@@ -88,6 +91,7 @@ typedef struct {
     uint8_t blind[32];
 } bsspeke_msg1_t;
 
+/*
 typedef bsspeke_msg1_t bsspeke_setup_msg1_t;
 
 typedef struct {
@@ -100,8 +104,9 @@ typedef struct {
     uint32_t phf_blocks;
     uint32_t phf_iterations;
 } bsspeke_setup_msg3_t;
+*/
 
-
+/*
 typedef bsspeke_msg1_t bsspeke_login_msg1_t;
 
 typedef struct {
@@ -119,6 +124,7 @@ typedef struct {
 typedef struct {
     uint8_t server_verifier[32];
 } bsspeke_login_msg4_t;
+*/
 
 void
 bsspeke_client_init(bsspeke_client_ctx *ctx,
@@ -128,71 +134,59 @@ bsspeke_client_init(bsspeke_client_ctx *ctx,
 
 void
 bsspeke_server_init(bsspeke_server_ctx *ctx,
-                    const char* server_id, const size_t server_id_len);
+                    const char* server_id, const size_t server_id_len,
+                    const char* client_id, const size_t client_id_len);
 
 void
-bsspeke_client_setup_generate_message1
-(
-    bsspeke_setup_msg1_t *msg1,
-    bsspeke_client_ctx *client
-);
+bsspeke_client_generate_blind(uint8_t blind[32],
+                              bsspeke_client_ctx *client);
+
 
+void
+bsspeke_server_blind_salt(uint8_t blind_salt[32],
+                          const uint8_t blind[32],
+                          const uint8_t *salt, const size_t salt_len);
 
 void
-bsspeke_server_setup_generate_message2
-(
-    bsspeke_setup_msg2_t *msg2,
-    const bsspeke_setup_msg1_t *msg1,
-    // uint8_t *salt, const size_t salt_len,
-    bsspeke_user_info_t *user_info,
-    bsspeke_server_ctx *server_ctx
-);
+bsspeke_server_generate_B(const uint8_t P[32],
+                          bsspeke_server_ctx *server);
 
 int
-bsspeke_client_setup_generate_message3
-(
-    bsspeke_setup_msg3_t *msg3,
-    const bsspeke_setup_msg2_t *msg2,
-    uint32_t phf_blocks, uint32_t phf_iterations,
-    bsspeke_client_ctx *client
-);
+bsspeke_client_generate_P_and_V(uint8_t P[32], uint8_t V[32],
+                                const uint8_t blind_salt[32],
+                                uint32_t phf_blocks, uint32_t phf_iterations,
+                                bsspeke_client_ctx *client);
+
+int
+bsspeke_client_generate_A(const uint8_t blind_salt[32],
+                          uint32_t phf_blocks, uint32_t phf_iterations,
+                          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
-);
+bsspeke_client_derive_shared_key(const uint8_t B[32],
+                                 bsspeke_client_ctx *client);
 
 void
-bsspeke_client_login_generate_message1(bsspeke_login_msg1_t *msg1,
+bsspeke_client_generate_verifier(uint8_t client_verifier[32],
                                  bsspeke_client_ctx *client);
 
+
 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 bsspeke_user_info_t *user,
+bsspeke_server_derive_shared_key(const uint8_t A[32],
+                                 const uint8_t V[32],
                                  bsspeke_server_ctx *server);
 
 int
-bsspeke_client_login_generate_message3(bsspeke_login_msg3_t *msg3,
-                                 const bsspeke_login_msg2_t *msg2,
-                                 bsspeke_client_ctx *client_ctx);
+bsspeke_server_verify_client(uint8_t client_verifier[32],
+                             bsspeke_server_ctx *server);
 
-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);
+void
+bsspeke_server_generate_verifier(uint8_t server_verifier[32],
+                                 bsspeke_server_ctx *server);
 
 int
-bsspeke_client_login_verify_message4(const bsspeke_login_msg4_t *msg4,
-                               const bsspeke_client_ctx *client);
+bsspeke_client_verify_server(const uint8_t server_verifier[32],
+                             const bsspeke_client_ctx *client);
 
 #ifdef __cplusplus
 }
diff --git a/demo.c b/demo.c
index b2f053d123779d3bddf85d2f37326e03eb7b5265..e7686d239a330fcfa4dc76b40e7fca83463c6749 100644
--- a/demo.c
+++ b/demo.c
@@ -36,6 +36,17 @@ int demo_setup(bsspeke_user_info_t *user_info)
     const char *server_id = "bob.example.com";
     const char *password = "P@ssword1";
 
+    // Also, because we got rid of all the 
+    // custom message structs, we need to pretend
+    // to be the network ferrying messages back
+    // and forth between the client and server.
+    // More than that, we have to pretend to be the
+    // network interface code that marshals and
+    // unmarshals all of these variables out of
+    // JSON or whatever.
+    uint8_t blind[32];
+    uint8_t blind_salt[32];
+
     puts("");
     puts("Setup: Initializing client");
     bsspeke_client_init(&client,
@@ -45,31 +56,36 @@ int demo_setup(bsspeke_user_info_t *user_info)
 
     puts("Setup: Initializing server");
     bsspeke_server_init(&server,
-                        server_id, strlen(server_id));
-
-    bsspeke_setup_msg1_t msg1;
-    bsspeke_setup_msg2_t msg2;
-    bsspeke_setup_msg3_t msg3;
+                        server_id, strlen(server_id),
+                        client_id, strlen(client_id));
 
     puts("");
     puts("Setup: Client generating message 1");
-    bsspeke_client_setup_generate_message1(&msg1, &client);
+    bsspeke_client_generate_blind(blind, &client);
 
     puts("");
     puts("Setup: Server generating message 2");
-    bsspeke_server_setup_generate_message2(&msg2, &msg1,
-                                           user_info,
-                                           &server);
+    memset(user_info->salt, '\xff', 32);
+    user_info->salt_len = 32;
+    bsspeke_server_blind_salt(blind_salt,
+                              blind,
+                              user_info->salt, user_info->salt_len);
 
     puts("");
     puts("Setup: Client generating message 3");
-    bsspeke_client_setup_generate_message3(&msg3, &msg2,
-                                           100000, 3,
-                                           &client);
-    
+    user_info->phf_blocks = 100000;
+    user_info->phf_iterations = 3;
+    bsspeke_client_generate_P_and_V(user_info->P,
+                                    user_info->V,
+                                    blind_salt,
+                                    user_info->phf_blocks,
+                                    user_info->phf_iterations,
+                                    &client);
+    /*
     puts("");
     puts("Setup: Server processing message 3");
     bsspeke_server_setup_process_message3(&msg3, user_info, &server);
+    */
 
     puts("");
     puts("Setup: Done");
@@ -98,37 +114,65 @@ int demo_login(bsspeke_user_info_t *user_info)
 
     puts("Login: Initializing server");
     bsspeke_server_init(&server,
-                        server_id, strlen(server_id));
+                        server_id, strlen(server_id),
+                        client_id, strlen(client_id));
 
-    bsspeke_login_msg1_t msg1;
-    bsspeke_login_msg2_t msg2;
-    bsspeke_login_msg3_t msg3;
-    bsspeke_login_msg4_t msg4;
+    // Again we have to pretend to be the network and the
+    // data marshalling layers
+    uint8_t blind[32];
+    uint8_t blind_salt[32];
+
+    uint8_t client_verifier[32];
+    uint8_t server_verifier[32];
 
     puts("");
     puts("Login: Client generating message 1");
-    bsspeke_client_login_generate_message1(&msg1, &client);
+    bsspeke_client_generate_blind(blind, &client);
 
     puts("");
     puts("Login: Server generating message 2");
-    bsspeke_server_login_generate_message2(&msg2, &msg1,
-                                           // salt, 32,
-                                           // P, V,
-                                           // 100000, 3,
-                                           user_info,
-                                           &server);
+    bsspeke_server_blind_salt(blind_salt, blind,
+                              user_info->salt,
+                              user_info->salt_len);
+    bsspeke_server_generate_B(user_info->P, &server);
 
     puts("");
     puts("Login: Client generating message 3");
-    bsspeke_client_login_generate_message3(&msg3, &msg2, &client);
+    int rc_A = bsspeke_client_generate_A(blind_salt,
+                                         user_info->phf_blocks,
+                                         user_info->phf_iterations,
+                                         &client);
+    if( rc_A != 0 ) {
+        puts("Login failed to hash user's password");
+        return -1;
+    }
+    bsspeke_client_derive_shared_key(server.B, &client);
+    bsspeke_client_generate_verifier(client_verifier, &client);
 
     puts("");
     puts("Login: Server generating message 4");
-    bsspeke_server_login_generate_message4(&msg4, &msg3, user_info, &server);
+    bsspeke_server_derive_shared_key(client.A,
+                                     user_info->V,
+                                     &server);
+    int rc_s = bsspeke_server_verify_client(client_verifier,
+                                            &server);
+    if( rc_s != 0 ) {
+        puts("Server failed to verify client.");
+        puts("LOGIN FAILED");
+        return -1;
+    }
+    bsspeke_server_generate_verifier(server_verifier,
+                                     &server);
 
     puts("");
     puts("Login: Client verifying message 4");
-    bsspeke_client_login_verify_message4(&msg4, &client);
+    int rc_c = bsspeke_client_verify_server(server_verifier,
+                                            &client);
+    if( rc_c != 0 ) {
+        puts("Client failed to verify server.");
+        puts("LOGIN FAILED");
+        return -1;
+    }
 
     return 0;