/* Inexact source code package.
 *
 * Written in 2019 by <ben@hackade.org>.
 *
 * To the extent possible under law, the author have dedicated all copyright
 * and related and neighboring rights to this software to the public domain
 * worldwide. This software is distributed without any warranty.
 *
 * You should have received a copy of the CC0 Public Domain Dedication along with
 * this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
 */

#define __USE_MINGW_ANSI_STDIO 1

#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "tests.h"
#include "base64.h"
#include "binhex.h"
#include "curve25519.h"
#include "norx_inexact.h"
#include "sha3.h"
#include "argon2.h"
#include "inexact.h"
#include "chacha20_drng.h"

int test_all() {
    printf("**** Test base64 functions ****\n\n");

    printf("** Encoding **\n\n");

    unsigned char test1_in[] = "foob";
    size_t test1_in_len = 4;
    size_t test1_expected_len = 9;
    unsigned char test1_expected[] = "Zm9vYg==\n";
    size_t test1_out_len = 0;

    unsigned char *test1_out =
        base64_encode(test1_in, test1_in_len, &test1_out_len);

    printf("TEST 1\n");
    printf("IN[%zu]:%s\n", test1_in_len, test1_in);
    printf("OUT[%zu]:%s\n", test1_out_len, test1_out);
    printf("RESULT:");

    int test1_len_result = (test1_out_len == test1_expected_len);
    if (test1_len_result == 0) {
        printf("ERROR\n\n");
        free(test1_out);
        return 1;
    }
    int test1_result = memcmp(test1_out, test1_expected, test1_out_len);
    if (test1_result != 0) {
        printf("ERROR\n\n");
        free(test1_out);
        return 1;
    }
    printf("OK\n\n");
    free(test1_out);

    unsigned char test2_in[] = "foobar";
    size_t test2_in_len = 6;
    size_t test2_expected_len = 9;
    unsigned char test2_expected[] = "Zm9vYmFy\n";
    size_t test2_out_len = 0;

    unsigned char *test2_out =
        base64_encode(test2_in, test2_in_len, &test2_out_len);

    printf("TEST 2\n");
    printf("IN[%zu]:%s\n", test2_in_len, test2_in);
    printf("OUT[%zu]:%s\n", test2_out_len, test2_out);
    printf("RESULT:");

    int test2_len_result = (test2_out_len == test2_expected_len);
    if (test2_len_result == 0) {
        printf("ERROR\n\n");
        free(test2_out);
        return 1;
    }
    int test2_result = memcmp(test2_out, test2_expected, test2_out_len);
    if (test2_result != 0) {
        printf("ERROR\n\n");
        free(test2_out);
        return 1;
    }
    printf("OK\n\n");
    free(test2_out);

    printf("** Decoding **\n\n");

    unsigned char test3_in[] = "Zm9vYmE=\n";
    size_t test3_in_len = 9;
    size_t test3_expected_len = 5;
    unsigned char test3_expected[] = "fooba";
    size_t test3_out_len = 0;

    unsigned char *test3_out =
        base64_decode(test3_in, test3_in_len, &test3_out_len);

    printf("TEST 3\n");
    printf("IN[%zu]:%s\n", test3_in_len, test3_in);
    printf("OUT[%zu]:%s\n", test3_out_len, test3_out);
    printf("RESULT:");

    int test3_len_result = (test3_out_len == test3_expected_len);
    if (test3_len_result == 0) {
        printf("ERROR\n\n");
        free(test3_out);
        return 1;
    }
    int test3_result = memcmp(test3_out, test3_expected, test3_out_len);
    if (test3_result != 0) {
        printf("ERROR\n\n");
        free(test3_out);
        return 1;
    }
    printf("OK\n\n");
    free(test3_out);

    unsigned char test4_in[] = "QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB\nQUFBQUFBQUFBCg==\n";
    size_t test4_in_len = 94;
    size_t test4_expected_len = 67;
    unsigned char test4_expected[] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n";
    size_t test4_out_len = 0;

    unsigned char *test4_out =
        base64_decode(test4_in, test4_in_len, &test4_out_len);

    printf("TEST 4\n");
    printf("IN[%zu]:%s\n", test4_in_len, test4_in);
    printf("OUT[%zu]:%s\n", test4_out_len, test4_out);
    printf("RESULT:");

    int test4_len_result = (test4_out_len == test4_expected_len);
    if (test4_len_result == 0) {
        printf("ERROR\n\n");
        free(test4_out);
        return 1;
    }
    int test4_result = memcmp(test4_out, test4_expected, test4_out_len);
    if (test4_result != 0) {
        printf("ERROR\n\n");
        free(test4_out);
        return 1;
    }
    printf("OK\n\n");
    free(test4_out);

    printf("**** Test base64 transformation functions ****\n\n");

    printf("** Encoding **\n\n");

    unsigned char test5_in[] = "YWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFh\nYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFh\nYWFhYWFhYWFhYWFhYWFhYQ==\n";
    size_t test5_in_len = 179;
    size_t test5_expected_len = 174;
    unsigned char test5_expected[] = "YWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYQ";
    size_t test5_out_len = 0;

    unsigned char *test5_out =
        b64t_encode(test5_in, test5_in_len, &test5_out_len);

    printf("TEST 5\n");
    printf("IN[%zu]:%s\n", test5_in_len, test5_in);
    printf("OUT[%zu]:%s\n", test5_out_len, test5_out);
    printf("RESULT:");

    int test5_len_result = (test5_out_len == test5_expected_len);
    if (test5_len_result == 0) {
        printf("ERROR\n\n");
        free(test5_out);
        return 1;
    }
    int test5_result = memcmp(test5_out, test5_expected, test5_out_len);
    if (test5_result != 0) {
        printf("ERROR\n\n");
        free(test5_out);
        return 1;
    }
    printf("OK\n\n");
    free(test5_out);

    unsigned char test6_in[] = "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz";
    size_t test6_in_len = 36;
    size_t test6_expected_len = 36;
    unsigned char test6_expected[] = "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz";
    size_t test6_out_len = 0;

    unsigned char *test6_out =
        b64t_encode(test6_in, test6_in_len, &test6_out_len);

    printf("TEST 6\n");
    printf("IN[%zu]:%s\n", test6_in_len, test6_in);
    printf("OUT[%zu]:%s\n", test6_out_len, test6_out);
    printf("RESULT:");

    int test6_len_result = (test6_out_len == test6_expected_len);
    if (test6_len_result == 0) {
        printf("ERROR\n\n");
        free(test6_out);
        return 1;
    }
    int test6_result = memcmp(test6_out, test6_expected, test6_out_len);
    if (test6_result != 0) {
        printf("ERROR\n\n");
        free(test6_out);
        return 1;
    }
    printf("OK\n\n");

    printf("** Decoding **\n\n");

    unsigned char test7_in[] = "YWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYQ";
    size_t test7_in_len = 174;
    size_t test7_expected_len = 179;
    unsigned char test7_expected[] = "YWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFh\nYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFh\nYWFhYWFhYWFhYWFhYWFhYQ==\n";
    size_t test7_out_len = 0;

    unsigned char *test7_out =
        b64t_decode(test7_in, test7_in_len, &test7_out_len);

    printf("TEST 7\n");
    printf("IN[%zu]:%s\n", test7_in_len, test7_in);
    printf("OUT[%zu]:%s\n", test7_out_len, test7_out);
    printf("RESULT:");

    int test7_len_result = (test7_out_len == test7_expected_len);
    if (test7_len_result == 0) {
        printf("ERROR\n\n");
        free(test7_out);
        return 1;
    }
    int test7_result = memcmp(test7_out, test7_expected, test7_out_len);
    if (test7_result != 0) {
        printf("ERROR\n\n");
        free(test7_out);
        return 1;
    }
    printf("OK\n\n");
    free(test7_out);

    unsigned char test8_in[] = "test1234";
    size_t test8_in_len = 8;
    size_t test8_expected_len = 9;
    unsigned char test8_expected[] = "test1234\n";
    size_t test8_out_len = 0;

    unsigned char *test8_out =
        b64t_decode(test8_in, test8_in_len, &test8_out_len);

    printf("TEST 8\n");
    printf("IN[%zu]:%s\n", test8_in_len, test8_in);
    printf("OUT[%zu]:%s\n", test8_out_len, test8_out);
    printf("RESULT:");

    int test8_len_result = (test8_out_len == test8_expected_len);
    if (test8_len_result == 0) {
        printf("ERROR\n\n");
        free(test8_out);
        return 1;
    }
    int test8_result = memcmp(test8_out, test8_expected, test8_out_len);
    if (test8_result != 0) {
        printf("ERROR\n\n");
        free(test8_out);
        return 1;
    }
    printf("OK\n\n");
    free(test8_out);


    printf("TEST 8A\n");
    unsigned char test8a[] = "0UkjGe6z0M7h5tfLqlgCQ5MhJjuINZO0IAUSr9QwqeUsXhrpptTjhm2sv06PFZH2nMmWJ8DgK5dJDuWP8ZoOIDg7XAY94pHyn376v2uMwKWKxH4789rsPwfa5cEFGAZU";
    size_t test8a_len = 0;
    unsigned char *test8a_base64 = base64_encode(test8a, 128, &test8a_len );
    printf("IN[128]:%s\n", test8a);
    printf("BASE64[%zu]:%s\n", test8a_len, test8a_base64);
    size_t test8a_b64t_len = 0;
    unsigned char *test8a_b64t = b64t_encode(test8a_base64, test8a_len, &test8a_b64t_len);
    printf("B64T[%zu]:%s\n",test8a_b64t_len, test8a_b64t);
    size_t test8a_b64t_decode_len = 0;
    unsigned char *test8a_b64t_decode = b64t_decode(test8a_b64t, test8a_b64t_len, &test8a_b64t_decode_len);
    printf("B64TD[%zu]:%s\n",test8a_b64t_decode_len,test8a_b64t_decode);
    size_t test8a_origin_len = 0;
    unsigned char *test8a_origin = base64_decode(test8a_b64t_decode, test8a_b64t_decode_len, &test8a_origin_len);
    printf("DECODED[%zu]:%s\n", test8a_origin_len, test8a_origin);
    printf("RESULT:");
    if(test8a_origin_len != 128) {
        printf("ERROR\n\n");
        free(test8a_base64);
        free(test8a_b64t);
        free(test8a_b64t_decode);
        free(test8a_origin);
        return 1;
    }
    if(memcmp(test8a_origin,test8a,128) != 0) {
        printf("ERROR\n\n");
        free(test8a_base64);
        free(test8a_b64t);
        free(test8a_b64t_decode);
        free(test8a_origin);
        return 1;
    }
    free(test8a_base64);
    free(test8a_b64t);
    free(test8a_b64t_decode);
    free(test8a_origin);
    printf("OK\n\n");

    printf("**** Test binary-hexadecimal conversion functions ****\n\n");

    printf("** bin2hex **\n\n");

    unsigned char test9_in[] = {0x66, 0x68, 0x77, 0x78, 0x00};
    size_t test9_in_len = 4;
    size_t test9_expected_len = 8;
    unsigned char test9_expected[] = "66687778";

    char *test9_out = bin2hex(test9_in, test9_in_len);

    printf("TEST 9\n");
    printf("IN[%zu]:%s\n", test9_in_len, test9_in);
    printf("OUT:%s\n", test9_out);
    printf("RESULT:");

    int test9_result = memcmp(test9_out, test9_expected, test9_expected_len);
    if (test9_result != 0) {
        printf("ERROR\n\n");
        free(test9_out);
        return 1;
    }
    printf("OK\n\n");
    free(test9_out);

    printf("**** Test SHA3 functions ****\n\n");

    printf("** SHA3-256 **\n\n");

    unsigned char test10_in[] = "abc";
    size_t test10_in_len = 3;
    size_t test10_expected_len = 32;
    unsigned char test10_expected[] =
        "3A985DA74FE225B2045C172D6BD390BD855F086E3E9D525B46BFE24511431532";

    sha3_context test10_ctx;
    const uint8_t *test10_hash;
    sha3_Init256(&test10_ctx);
    sha3_Update(&test10_ctx, test10_in, test10_in_len);
    test10_hash = sha3_Finalize(&test10_ctx);

    char *test10_out = bin2hex(test10_hash, test10_expected_len);

    printf("TEST 10\n");
    printf("IN[%zu]:%s\n", test10_in_len, test10_in);
    printf("OUT:%s\n", test10_out);
    printf("RESULT:");

    int test10_result =
        memcmp(test10_out, test10_expected, test10_expected_len * 2);
    if (test10_result != 0) {
        printf("ERROR\n\n");
        free(test10_out);
        return 1;
    }
    printf("OK\n\n");
    free(test10_out);

    printf("**** Test curve 25519 functions ****\n\n");

    printf("** Diffie-Hellman **\n\n");

    curve25519_key S_a = {0x77, 0x07, 0x6d, 0x0a, 0x73, 0x18, 0xa5, 0x7d,
                          0x3c, 0x16, 0xc1, 0x72, 0x51, 0xb2, 0x66, 0x45,
                          0xdf, 0x4c, 0x2f, 0x87, 0xeb, 0xc0, 0x99, 0x2a,
                          0xb1, 0x77, 0xfb, 0xa5, 0x1d, 0xb9, 0x2c, 0x2a};
    curve25519_key P_a = {0};
    curve25519_key S_b = {0x5d, 0xab, 0x08, 0x7e, 0x62, 0x4a, 0x8a, 0x4b,
                          0x79, 0xe1, 0x7f, 0x8b, 0x83, 0x80, 0x0e, 0xe6,
                          0x6f, 0x3b, 0xb1, 0x29, 0x26, 0x18, 0xb6, 0xfd,
                          0x1c, 0x2f, 0x8b, 0x27, 0xff, 0x88, 0xe0, 0xeb};
    curve25519_key P_b = {0};
    curve25519_key shared_1 = {0};
    curve25519_key shared_2 = {0};
    curve25519_donna_basepoint(P_a, S_a);
    curve25519_donna_basepoint(P_b, S_b);
    curve25519_donna(shared_1, S_a, P_b);
    curve25519_donna(shared_2, S_b, P_a);
    char *S_a_str = bin2hex(S_a, sizeof(S_a));
    char *P_a_str = bin2hex(P_a, sizeof(P_a));
    char *S_b_str = bin2hex(S_b, sizeof(S_b));
    char *P_b_str = bin2hex(P_b, sizeof(P_b));
    char *shared_1_str = bin2hex(shared_1, sizeof(shared_1));
    char *shared_2_str = bin2hex(shared_2, sizeof(shared_2));
    printf("TEST 11\n");
    printf("S_a=%s\n", S_a_str);
    printf("P_a=%s\n", P_a_str);
    printf("S_b=%s\n", S_b_str);
    printf("P_b=%s\n", P_b_str);
    printf("shared_1=%s\n", shared_1_str);
    printf("shared_2=%s\n", shared_2_str);
    free(S_a_str);
    free(P_a_str);
    free(S_b_str);
    free(P_b_str);
    free(shared_1_str);
    free(shared_2_str);

    curve25519_key expected_P_a = {
        0x85, 0x20, 0xf0, 0x09, 0x89, 0x30, 0xa7, 0x54, 0x74, 0x8b, 0x7d,
        0xdc, 0xb4, 0x3e, 0xf7, 0x5a, 0x0d, 0xbf, 0x3a, 0x0d, 0x26, 0x38,
        0x1a, 0xf4, 0xeb, 0xa4, 0xa9, 0x8e, 0xaa, 0x9b, 0x4e, 0x6a};
    curve25519_key expected_P_b = {
        0xde, 0x9e, 0xdb, 0x7d, 0x7b, 0x7d, 0xc1, 0xb4, 0xd3, 0x5b, 0x61,
        0xc2, 0xec, 0xe4, 0x35, 0x37, 0x3f, 0x83, 0x43, 0xc8, 0x5b, 0x78,
        0x67, 0x4d, 0xad, 0xfc, 0x7e, 0x14, 0x6f, 0x88, 0x2b, 0x4f};
    curve25519_key expected_shared = {
        0x4a, 0x5d, 0x9d, 0x5b, 0xa4, 0xce, 0x2d, 0xe1, 0x72, 0x8e, 0x3b,
        0xf4, 0x80, 0x35, 0x0f, 0x25, 0xe0, 0x7e, 0x21, 0xc9, 0x47, 0xd1,
        0x9e, 0x33, 0x76, 0xf0, 0x9b, 0x3c, 0x1e, 0x16, 0x17, 0x42};

    int test11 = memcmp(P_a, expected_P_a, sizeof(curve25519_key));
    printf("RESULT:");
    if (test11 == 0) {
        printf("OK\n\n");
    } else {
        printf("ERROR\n\n");
        return 1;
    }
    int test12 = memcmp(P_b, expected_P_b, sizeof(curve25519_key));
    printf("TEST 12\n");
    printf("RESULT:");
    if (test12 == 0) {
        printf("OK\n\n");
    } else {
        printf("ERROR\n\n");
        return 1;
    }
    int test13 = memcmp(shared_1, expected_shared, sizeof(curve25519_key));
    printf("TEST 13\n");
    printf("RESULT:");
    if (test13 == 0) {
        printf("OK\n\n");
    } else {
        printf("ERROR\n\n");
        return 1;
    }
    int test14 = memcmp(shared_2, expected_shared, sizeof(curve25519_key));
    printf("TEST 14\n");
    printf("RESULT:");
    if (test14 == 0) {
        printf("OK\n\n");
    } else {
        printf("ERROR\n\n");
        return 1;
    }

    printf("**** Test norx functions ****\n\n");

    printf("** test vectors encrypt **\n\n");

    /* test vectors */
    printf("TEST 15\n");
    unsigned i;

    unsigned char K[32];
    for (i = 0; i < sizeof(K); ++i) K[i] = 255 & i;
    char *K_str = bin2hex(K, sizeof(K));
    printf("K: %s\n", K_str);
    free(K_str);

    unsigned char N[32];
    for (i = 0; i < sizeof(N); ++i) N[i] = 255 & (i + 0x20);
    char *N_str = bin2hex(N, sizeof(N));
    printf("N: %s\n", N_str);
    free(N_str);

    unsigned char A[128];
    for (i = 0; i < sizeof(A); ++i) A[i] = 255 & i;
    char *A_str = bin2hex(A, sizeof(A));
    printf("A: %s\n", A_str);
    free(A_str);

    unsigned char M[128];
    for (i = 0; i < sizeof(M); ++i) M[i] = 255 & i;
    char *M_str = bin2hex(M, sizeof(M));
    printf("M: %s\n", M_str);
    free(M_str);

    unsigned char Z[128];
    for (i = 0; i < sizeof(Z); ++i) Z[i] = 255 & i;
    char *Z_str = bin2hex(Z, sizeof(Z));
    printf("Z: %s\n", Z_str);
    free(Z_str);

    unsigned char C[160] = {0};
    size_t C_len = 0;

    norx_aead_encrypt(C, &C_len, A, sizeof(A), M, sizeof(M), Z, sizeof(Z), N, K,
                      256);

    char *C_str = bin2hex(C, C_len);
    printf("IN[%zu]:%s\n", C_len, C_str);
    free(C_str);

    unsigned char nox_test_vectors[] = {
        0x50, 0xCE, 0x69, 0x2C, 0x19, 0xCB, 0x91, 0x02, 0xC6, 0x12, 0x96, 0x6F,
        0x0F, 0x62, 0x6B, 0x62, 0x96, 0xDE, 0x89, 0x27, 0x1C, 0x98, 0x29, 0x10,
        0xAA, 0xC1, 0xC3, 0x55, 0x52, 0x2E, 0x8F, 0xA7, 0x13, 0x03, 0xF8, 0xD5,
        0xC9, 0xDE, 0x39, 0x04, 0x84, 0xBA, 0x91, 0xA9, 0x94, 0xCF, 0xF9, 0x1B,
        0xF7, 0x15, 0xD6, 0xCB, 0x22, 0xCC, 0x00, 0xF3, 0x64, 0x02, 0x10, 0x03,
        0x17, 0x19, 0x61, 0x68, 0x72, 0x39, 0xDD, 0x94, 0x53, 0x02, 0x9B, 0x87,
        0x85, 0x9C, 0x10, 0x93, 0x21, 0x13, 0x59, 0x40, 0xBC, 0x1B, 0xC8, 0x1A,
        0x55, 0xA9, 0x51, 0xC7, 0x1B, 0x29, 0x42, 0xFF, 0xDE, 0xBF, 0x8D, 0x13,
        0xC4, 0xF3, 0x87, 0x2B, 0x78, 0xD4, 0x50, 0x6F, 0x40, 0xDB, 0x65, 0x3C,
        0xE3, 0xB8, 0xD2, 0xBE, 0xA7, 0xA2, 0xF9, 0xE9, 0x7F, 0xF4, 0x56, 0xB7,
        0xF0, 0xDB, 0x8C, 0x92, 0x27, 0xE2, 0x2F, 0x23, 0xA0, 0xD1, 0x0D, 0x28,
        0x52, 0x91, 0xBE, 0xDB, 0x7B, 0x7C, 0xBD, 0xC4, 0x7E, 0x0F, 0xE2, 0x38,
        0x5B, 0xF5, 0x5B, 0xC5, 0xF0, 0x57, 0xBC, 0xAB, 0x2C, 0x57, 0xCC, 0xD0,
        0x83, 0xD2, 0x9B, 0x2C};

    int test15 = memcmp(C, nox_test_vectors, sizeof(nox_test_vectors));
    printf("RESULT:");
    if (test15 == 0) {
        printf("OK\n\n");
    } else {
        printf("ERROR\n\n");
        return 1;
    }

    printf("** encrypt/decrypt 256 bits **\n\n");

    unsigned char crypted[1024] = {0};
    unsigned char header[1024] = {'Z'};
    size_t crypted_len = 0;
    unsigned char message[] = "Alice and Bob message's are secret";
    unsigned char nonce[32] = {0};
    struct chacha20_drng *drng;
    int ret = drng_chacha20_init(&drng);
    if (ret) {
        printf("Allocation failed: %d\n", ret);
        return 1;
    }
    if (drng_chacha20_get(drng, nonce, sizeof(nonce))) {
        printf("Getting random numbers failed\n");
        return 1;
    }
    unsigned char key[] = "AA0123456789ABCDEF0123456789AZERTY";

    norx_aead_encrypt(crypted, &crypted_len, header, 8, message,
                      sizeof(message) - 1, NULL, 0, nonce, key, 256);

    printf("TEST 16\n");
    printf("IN[%zu]:%s\n", sizeof(message) - 1, message);
    char *nonce_str = bin2hex(nonce, sizeof(nonce));
    printf("NONCE[%zu]:%s\n", sizeof(nonce), nonce_str);
    free(nonce_str);
    printf("KEY[%zu]:%s\n", sizeof(key) - 1, key);

    char *crypted_str = bin2hex(crypted, crypted_len);
    printf("OUT[%zu]: %s\n", crypted_len, crypted_str);
    free(crypted_str);

    unsigned char clear[1024] = {0};
    size_t clear_len = 0;

    int test16 = norx_aead_decrypt(clear, &clear_len, header, 8, crypted,
                                   crypted_len, NULL, 0, nonce, key, 256);

    printf("RESULT:");
    if (test16 == 0) {
        printf("OK\n\n");
    } else {
        printf("ERROR\n\n");
        return 1;
    }
    drng_chacha20_destroy(drng);

    printf("TEST 17\n");
    char *clear_str = bin2hex(clear, clear_len);
    printf("CLEAR[%zu]:%s\n", clear_len, clear);
    free(clear_str);

    int test17 = memcmp(clear, message, sizeof(message));
    printf("RESULT:");
    if (test17 == 0) {
        printf("OK\n\n");
    } else {
        printf("ERROR\n\n");
        return 1;
    }

    printf("TEST 18\n");
    header[2] = 1;  // corrupted buffer test
    int test18 = norx_aead_decrypt(clear, &clear_len, header, 8, crypted,
                                   crypted_len, NULL, 0, nonce, key, 256);

    printf("RESULT:");
    if (test18 != 0) {
        printf("OK\n\n");
    } else {
        printf("ERROR\n\n");
        return 1;
    }

    printf("** encrypt/decrypt 256 bits with 32 bits tag **\n\n");

    unsigned char cryptedt0[1024] = {0};
    size_t crypted_lent0 = 0;
    unsigned char messaget0[] = "Simple message encryption";
    unsigned char noncet0[32] = {0};
    struct chacha20_drng *drng0;
    int ret0 = drng_chacha20_init(&drng0);
    if (ret0) {
        printf("Allocation failed: %d\n", ret);
        return 1;
    }
    if (drng_chacha20_get(drng, noncet0, sizeof(noncet0))) {
        printf("Getting random numbers failed\n");
        return 1;
    }
    unsigned char keyt0[] = "AA0123456789ABCDEF0123456789AZERTY";

    norx_aead_encrypt(cryptedt0, &crypted_lent0, NULL, 0, messaget0,
                      sizeof(messaget0) - 1, NULL, 0, noncet0, keyt0, 32);

    printf("TEST 19\n");
    printf("IN[%zu]:%s\n", sizeof(messaget0) - 1, messaget0);
    char *nonce_strt0 = bin2hex(noncet0, sizeof(noncet0));
    printf("NONCE[%zu]:%s\n", sizeof(noncet0), nonce_strt0);
    free(nonce_strt0);
    printf("KEY[%zu]:%s\n", sizeof(key) - 1, key);

    char *crypted_strt0 = bin2hex(cryptedt0, crypted_lent0);
    printf("OUT[%zu]:%s\n", crypted_lent0, crypted_strt0);
    free(crypted_strt0);

    unsigned char cleart0[1024] = {0};
    size_t clear_lent0 = 0;

    int test19 = norx_aead_decrypt(cleart0, &clear_lent0, NULL, 0, cryptedt0,
                                   crypted_lent0, NULL, 0, noncet0, keyt0, 32);

    printf("RESULT:");
    if (test19 == 0) {
        printf("OK\n\n");
    } else {
        printf("ERROR\n\n");
        return 1;
    }

    printf("TEST 20\n");
    char *clear_strt0 = bin2hex(cleart0, clear_lent0);
    printf("CLEAR[%zu]:%s\n", clear_lent0, cleart0);
    free(clear_strt0);

    int test20 = memcmp(cleart0, messaget0, sizeof(messaget0));
    printf("RESULT:");
    if (test20 == 0) {
        printf("OK\n\n");
    } else {
        printf("ERROR\n\n");
        return 1;
    }
    drng_chacha20_destroy(drng0);
    
    printf("**** Test argon2 functions ****\n\n");

    printf("** Argon2i -t 2 -m 16 -p 4 -l 24 **\n\n");
    
    unsigned char test21_password[] = "password";
    size_t test21_password_len = 8;
    unsigned char test21_salt[] = "somesalt";
    size_t test21_salt_len = 8;
    unsigned char test21_out[24];
    size_t test21_out_len = 24;
    printf("TEST 21\n");
    printf("PASS[8]:%s\n", test21_password);
    printf("SALT[4]:%s\n", test21_salt);

    int test21 = argon2i_hash_raw( 2,
                                   1<<16,
                                   4,
                                   test21_password,
                                   test21_password_len,
                                   test21_salt,
                                   test21_salt_len,
                                   test21_out,
                                   test21_out_len);

    char *test21_out_str = bin2hex(test21_out, test21_out_len);
    printf("OUT[24]:%s\n", test21_out_str);
    printf("RESULT:");
    if (test21 != 0) {
        printf("ERROR\n\n");
        free(test21_out_str);
        return 1;
    }
    if(memcmp(test21_out_str, "45D7AC72E76F242B20B77B9BF9BF9D5915894E669A24E6C6", 48) == 0){
        printf("OK\n\n");
    } else {
        printf("ERROR\n\n");
        free(test21_out_str);
        return 1;
    }
    free(test21_out_str);
    
    printf("**** Test random number generator functions ****\n\n");

    printf("** ChaCha20 DRNG **\n\n");

    struct chacha20_drng *drng2;
    uint8_t buf[40];
    char version[30];
    int ret2;

    drng_chacha20_versionstring(version, sizeof(version));
	printf("Obtained version string: %s\n", version);
	printf("Obtained version number: %u\n", drng_chacha20_version());

    ret2 = drng_chacha20_init(&drng2);
	if (ret2) {
		printf("Allocation failed: %d\n", ret2);
		return 1;
	}

	if (drng_chacha20_get(drng2, buf, 32)) {
		printf("Getting random numbers failed\n");
		return 1;
    }
    
    char *test22 = bin2hex(buf,40);
    printf("Random number:%s\n", test22);
    free(test22);
	
    if (drng_chacha20_get(drng2, buf, 32)) {
		printf("Getting random numbers failed\n");
		return 1;
    }
    
    test22 = bin2hex(buf,40);
    printf("Random number:%s\n\n", test22);
    free(test22);
    drng_chacha20_destroy(drng2);


    
    printf("**** Test inexact functions ****\n\n");

    printf("** encrypt/decrypt n=32 t=32 **\n\n");

    unsigned char testinexact1_in[] = "simple test message";
    size_t testinexact1_in_len = 19;
    curve25519_key testinexact1_seckey;
    curve25519_key testinexact1_pubkey;
    struct chacha20_drng *drng1;
    int ret1 = drng_chacha20_init(&drng1);
    if (ret1) {
        printf("Allocation failed: %d\n", ret);
        return 1;
    }
    if (drng_chacha20_get(drng, testinexact1_seckey, sizeof(curve25519_key))) {
        printf("Getting random numbers failed\n");
        return 1;
    }
    drng_chacha20_destroy(drng1);
    curve25519_donna_basepoint(testinexact1_pubkey, testinexact1_seckey);
    size_t testinexact1_out_len = 0;
    
    printf("TEST INEXACT\n");
    printf("IN[%zu]=%s\n", testinexact1_in_len, testinexact1_in);
    char *testinexact1_seckey_str = bin2hex(testinexact1_seckey,32);
    char *testinexact1_pubkey_str = bin2hex(testinexact1_pubkey,32);
    printf("SECKEY[%zu]:%s\n", sizeof(curve25519_key), testinexact1_seckey_str);
    printf("PUBKEY[%zu]:%s\n", sizeof(curve25519_key), testinexact1_pubkey_str);
    free(testinexact1_seckey_str);
    free(testinexact1_pubkey_str);
    
    unsigned char *testinexact1_out = encrypt_data(testinexact1_seckey,
                                             testinexact1_pubkey,
                                             NULL,
                                             testinexact1_in,
                                             testinexact1_in_len,
                                             32,
                                             32,
                                             0,
                                             &testinexact1_out_len);

    printf("OUT[%zu]=%s\n", testinexact1_out_len, testinexact1_out);

    size_t testinexact1_clear_len = 0;
    unsigned char *testinexact1_clear = decrypt_data(testinexact1_seckey,
                                               testinexact1_pubkey,
                                               testinexact1_out,
                                               testinexact1_out_len,
                                               0,
                                               &testinexact1_clear_len);

    testinexact1_clear[testinexact1_clear_len] = 0;
    printf("CLEAR[%zu]=%s\n", testinexact1_clear_len, testinexact1_clear);
    
    int testinexact1 = memcmp(testinexact1_clear, testinexact1_in, testinexact1_in_len);
    printf("RESULT:");
    if (testinexact1 == 0) {
        printf("OK\n\n");
    } else {
        printf("ERROR\n\n");
        return 1;
    }

    return 0;
}