#include <bearssl.h> /* -lbearssl */
#include <lib25519.h> /* -l25519 */
#include <assert.h>
#include <string.h>
#include <stdio.h>

int bearssl_dh_x25519_keypair(unsigned char *pk, unsigned char *sk) {

    static br_hmac_drbg_context rng;
    unsigned char tmpsk[BR_EC_KBUF_PRIV_MAX_SIZE];
    unsigned char tmppk[BR_EC_KBUF_PUB_MAX_SIZE];
    br_ec_private_key brsk;
    br_ec_public_key brpk;
    br_prng_seeder seeder;
    const br_ec_impl *impl = br_ec_get_default();
    size_t ret;

    /* initialize rng */
    br_hmac_drbg_init(&rng, &br_sha512_vtable, 0, 0);
    seeder = br_prng_seeder_system(0);
    if (!seeder) return -1;
    if (!seeder(&rng.vtable)) return -1;

    /* generate random secret-key */
    ret = br_ec_keygen(&rng.vtable, impl, &brsk, tmpsk, BR_EC_curve25519);
    if (ret != 32) return -1;

    /* generate public-key */ 
    ret = br_ec_compute_pub(impl, &brpk, tmppk, &brsk);
    if (ret != 32) return -1;

    memcpy(pk, tmppk, 32);
    memcpy(sk, tmpsk, 32);
    return 0;
}

int bearssl_dh_x25519(unsigned char *k, const unsigned char *pk, const unsigned char *sk) {

    unsigned char tmpsk[32];
    unsigned char tmppk[32];
    uint32_t ret;

    memcpy(tmppk, pk, 32);
    memcpy(tmpsk, sk, 32);

    ret = br_ec_get_default()->mul(tmppk, 32, tmpsk, 32, BR_EC_curve25519);
    if (ret != 1) return -1;

    memcpy(k, tmppk, 32);
    return 0;
}

void h_print(const char *text, unsigned char *h) {
    long long i;
    printf("%s: ", text);
    for (i = 0; i < 32; ++i) printf("%02x", 255 & (int) h[i]);
    printf("\n");
}


#define LOOPS 100

int main(void) {
    unsigned char k1[32], pk1[32], sk1[32];
    unsigned char k2[32], pk2[32], sk2[32];
    long long i;
    int ret = 1;

    for (i = 0; i < LOOPS; ++i) {

        /* alice - bearssl keypair */
        assert(!bearssl_dh_x25519_keypair(pk1, sk1));

        /* bob - lib25519 keypair */
        lib25519_dh_x25519_keypair(pk2, sk2);

        /* alice - bearssl dh */
        assert(!bearssl_dh_x25519(k1, pk2, sk1));

        /* bob  - lib25519 dh */
        lib25519_dh_x25519(k2, pk1, sk2);

        ret = !!memcmp(k1, k2, 32);
    }
    if (ret) {
        printf("failed:\n");
    }
    else {
        printf("OK:\n");
    }
    h_print("bearssl  pk", pk1);
    h_print("bearssl  sk", sk1);
    h_print("lib25519 pk", pk2);
    h_print("lib25519 sk", sk2);
    h_print("bearssl   k", k1);
    h_print("lib25519  k", k2);
    return 0;
}
