int scannable_fingerprint_compare(scannable_fingerprint *scannable, const scannable_fingerprint *other_scannable)
{
    if(!other_scannable->remote_identity_key || !other_scannable->local_identity_key ||
            other_scannable->version != scannable->version) {
        return SG_ERR_FP_VERSION_MISMATCH;
    }

    if(strcmp(scannable->local_stable_identifier, other_scannable->remote_stable_identifier) != 0) {
        return SG_ERR_FP_IDENT_MISMATCH;
    }

    if(strcmp(scannable->remote_stable_identifier, other_scannable->local_stable_identifier) != 0) {
        return SG_ERR_FP_IDENT_MISMATCH;
    }

    if(ec_public_key_compare(scannable->local_identity_key, other_scannable->remote_identity_key) != 0) {
        return 0;
    }

    if(ec_public_key_compare(scannable->remote_identity_key, other_scannable->local_identity_key) != 0) {
        return 0;
    }

    return 1;
}
END_TEST

START_TEST(test_curve25519_generate_public)
{
    int result;

    uint8_t alicePublic[] = {
            0x05, 0x1b, 0xb7, 0x59, 0x66,
            0xf2, 0xe9, 0x3a, 0x36, 0x91,
            0xdf, 0xff, 0x94, 0x2b, 0xb2,
            0xa4, 0x66, 0xa1, 0xc0, 0x8b,
            0x8d, 0x78, 0xca, 0x3f, 0x4d,
            0x6d, 0xf8, 0xb8, 0xbf, 0xa2,
            0xe4, 0xee, 0x28};

    uint8_t alicePrivate[] = {
            0xc8, 0x06, 0x43, 0x9d, 0xc9,
            0xd2, 0xc4, 0x76, 0xff, 0xed,
            0x8f, 0x25, 0x80, 0xc0, 0x88,
            0x8d, 0x58, 0xab, 0x40, 0x6b,
            0xf7, 0xae, 0x36, 0x98, 0x87,
            0x90, 0x21, 0xb9, 0x6b, 0xb4,
            0xbf, 0x59};

    ec_private_key *alice_private_key = 0;
    ec_public_key *alice_expected_public_key = 0;
    ec_public_key *alice_public_key = 0;

    /* Initialize Alice's private key */
    result = curve_decode_private_point(&alice_private_key, alicePrivate, sizeof(alicePrivate), global_context);
    ck_assert_int_eq(result, 0);
    ck_assert_ptr_ne(alice_private_key, 0);

    /* Initialize Alice's expected public key */
    result = curve_decode_point(&alice_expected_public_key, alicePublic, sizeof(alicePublic), global_context);
    ck_assert_int_eq(result, 0);
    ck_assert_ptr_ne(alice_expected_public_key, 0);

    /* Generate Alice's actual public key */
    result = curve_generate_public_key(&alice_public_key, alice_private_key);
    ck_assert_int_eq(result, 0);
    ck_assert_ptr_ne(alice_public_key, 0);

    /* Assert that expected and actual public keys match */
    ck_assert_int_eq(ec_public_key_compare(alice_expected_public_key, alice_public_key), 0);

    /* Cleanup */
    SIGNAL_UNREF(alice_public_key);
    SIGNAL_UNREF(alice_expected_public_key);
    SIGNAL_UNREF(alice_private_key);
}
END_TEST

START_TEST(test_serialize_sender_key_distribution_message)
{
    int result = 0;
    sender_key_distribution_message *message = 0;
    sender_key_distribution_message *result_message = 0;
    static const char chain_key[] = "WhisperChainKey";
    ec_public_key *signature_key = create_test_ec_public_key(global_context);

    result = sender_key_distribution_message_create(&message,
             10, /* id */
             1,  /* iteration */
             (uint8_t *)chain_key, sizeof(chain_key) - 1,
             signature_key,
             global_context);
    ck_assert_int_eq(result, 0);

    signal_buffer *serialized = ciphertext_message_get_serialized((ciphertext_message *)message);
    ck_assert_ptr_ne(serialized, 0);

    result = sender_key_distribution_message_deserialize(&result_message,
             signal_buffer_data(serialized),
             signal_buffer_len(serialized),
             global_context);
    ck_assert_int_eq(result, 0);

    int id1 = sender_key_distribution_message_get_id(message);
    int id2 = sender_key_distribution_message_get_id(result_message);
    ck_assert_int_eq(id1, id2);

    int iteration1 = sender_key_distribution_message_get_iteration(message);
    int iteration2 = sender_key_distribution_message_get_iteration(result_message);
    ck_assert_int_eq(iteration1, iteration2);

    signal_buffer *chain_key1 = sender_key_distribution_message_get_chain_key(message);
    signal_buffer *chain_key2 = sender_key_distribution_message_get_chain_key(result_message);
    ck_assert_int_eq(signal_buffer_compare(chain_key1, chain_key2), 0);

    ec_public_key *signature_key1 = sender_key_distribution_message_get_signature_key(message);
    ec_public_key *signature_key2 = sender_key_distribution_message_get_signature_key(result_message);
    ck_assert_int_eq(ec_public_key_compare(signature_key1, signature_key2), 0);

    /* Cleanup */
    SIGNAL_UNREF(message);
    SIGNAL_UNREF(result_message);
    SIGNAL_UNREF(signature_key);
}
void compare_signal_messages(signal_message *message1, signal_message *message2)
{
    ec_public_key *sender_ratchet_key1 = signal_message_get_sender_ratchet_key(message1);
    ec_public_key *sender_ratchet_key2 = signal_message_get_sender_ratchet_key(message2);
    ck_assert_int_eq(ec_public_key_compare(sender_ratchet_key1, sender_ratchet_key2), 0);

    int version1 = signal_message_get_message_version(message1);
    int version2 = signal_message_get_message_version(message2);
    ck_assert_int_eq(version1, version2);

    int counter1 = signal_message_get_counter(message1);
    int counter2 = signal_message_get_counter(message2);
    ck_assert_int_eq(counter1, counter2);

    signal_buffer *body1 = signal_message_get_body(message1);
    signal_buffer *body2 = signal_message_get_body(message2);
    ck_assert_int_eq(signal_buffer_compare(body1, body2), 0);
}
void compare_sender_key_states(sender_key_state *state1, sender_key_state *state2)
{
    /* Compare key IDs */
    int key_id1 = sender_key_state_get_key_id(state1);
    int key_id2 = sender_key_state_get_key_id(state2);
    ck_assert_int_eq(key_id1, key_id2);

    /* Compare chain keys */
    sender_chain_key *chain_key1 = sender_key_state_get_chain_key(state1);
    sender_chain_key *chain_key2 = sender_key_state_get_chain_key(state2);
    compare_sender_chain_keys(chain_key1, chain_key2);

    /* Compare public signing keys */
    ec_public_key *key_public1 = sender_key_state_get_signing_key_public(state1);
    ec_public_key *key_public2 = sender_key_state_get_signing_key_public(state2);
    ck_assert_int_eq(ec_public_key_compare(key_public1, key_public2), 0);

    /* Compare private signing keys */
    ec_private_key *key_private1 = sender_key_state_get_signing_key_private(state1);
    ec_private_key *key_private2 = sender_key_state_get_signing_key_private(state2);
    ck_assert_int_eq(ec_private_key_compare(key_private1, key_private2), 0);

    /* Message keys are not compared here */
}
END_TEST

START_TEST(test_serialize_pre_key_signal_message)
{
    int result = 0;

    static const char ciphertext[] = "WhisperCipherText";
    ec_public_key *sender_ratchet_key = create_test_ec_public_key(global_context);
    ec_public_key *sender_identity_key = create_test_ec_public_key(global_context);
    ec_public_key *receiver_identity_key = create_test_ec_public_key(global_context);
    ec_public_key *base_key = create_test_ec_public_key(global_context);
    ec_public_key *identity_key = create_test_ec_public_key(global_context);
    uint8_t mac_key[RATCHET_MAC_KEY_LENGTH];
    memset(mac_key, 1, sizeof(mac_key));

    signal_message *message = 0;
    pre_key_signal_message *pre_key_message = 0;
    pre_key_signal_message *result_pre_key_message = 0;

    result = signal_message_create(&message, 3,
                                   mac_key, sizeof(mac_key),
                                   sender_ratchet_key,
                                   2, /* counter */
                                   1, /* previous counter */
                                   (uint8_t *)ciphertext, sizeof(ciphertext) - 1,
                                   sender_identity_key, receiver_identity_key,
                                   global_context);
    ck_assert_int_eq(result, 0);

    uint32_t pre_key_id = 56;
    result = pre_key_signal_message_create(&pre_key_message,
                                           3,  /* message version */
                                           42, /* registration ID */
                                           &pre_key_id, /* pre key ID */
                                           72, /* signed pre key ID */
                                           base_key, identity_key,
                                           message,
                                           global_context);
    ck_assert_int_eq(result, 0);

    signal_buffer *serialized = ciphertext_message_get_serialized((ciphertext_message *)pre_key_message);
    ck_assert_ptr_ne(serialized, 0);

    result = pre_key_signal_message_deserialize(&result_pre_key_message,
             signal_buffer_data(serialized),
             signal_buffer_len(serialized),
             global_context);
    ck_assert_int_eq(result, 0);

    int version1 = pre_key_signal_message_get_message_version(pre_key_message);
    int version2 = pre_key_signal_message_get_message_version(result_pre_key_message);
    ck_assert_int_eq(version1, version2);

    ec_public_key *identity_key1 = pre_key_signal_message_get_identity_key(pre_key_message);
    ec_public_key *identity_key2 = pre_key_signal_message_get_identity_key(result_pre_key_message);
    ck_assert_int_eq(ec_public_key_compare(identity_key1, identity_key2), 0);

    int registration_id1 = pre_key_signal_message_get_registration_id(pre_key_message);
    int registration_id2 = pre_key_signal_message_get_registration_id(result_pre_key_message);
    ck_assert_int_eq(registration_id1, registration_id2);

    int has_pre_key_id1 = pre_key_signal_message_has_pre_key_id(pre_key_message);
    int has_pre_key_id2 = pre_key_signal_message_has_pre_key_id(result_pre_key_message);
    ck_assert_int_eq(has_pre_key_id1, has_pre_key_id2);

    if(has_pre_key_id1) {
        int pre_key_id1 = pre_key_signal_message_get_pre_key_id(pre_key_message);
        int pre_key_id2 = pre_key_signal_message_get_pre_key_id(result_pre_key_message);
        ck_assert_int_eq(pre_key_id1, pre_key_id2);
    }

    int signed_pre_key_id1 = pre_key_signal_message_get_signed_pre_key_id(pre_key_message);
    int signed_pre_key_id2 = pre_key_signal_message_get_signed_pre_key_id(result_pre_key_message);
    ck_assert_int_eq(signed_pre_key_id1, signed_pre_key_id2);

    ec_public_key *base_key1 = pre_key_signal_message_get_base_key(pre_key_message);
    ec_public_key *base_key2 = pre_key_signal_message_get_base_key(result_pre_key_message);
    ck_assert_int_eq(ec_public_key_compare(base_key1, base_key2), 0);

    signal_message *message1 = pre_key_signal_message_get_signal_message(pre_key_message);
    signal_message *message2 = pre_key_signal_message_get_signal_message(result_pre_key_message);
    compare_signal_messages(message1, message2);

    /* Cleanup */
    SIGNAL_UNREF(message);
    SIGNAL_UNREF(result_pre_key_message);
    SIGNAL_UNREF(pre_key_message);
    SIGNAL_UNREF(sender_ratchet_key);
    SIGNAL_UNREF(sender_identity_key);
    SIGNAL_UNREF(receiver_identity_key);
    SIGNAL_UNREF(base_key);
    SIGNAL_UNREF(identity_key);
}