/*
 * datatypes_driver.c
 *
 * a test driver for crypto/math datatypes
 *
 * David A. McGrew
 * Cisco Systems, Inc.
 */

/*
 *
 * Copyright (c) 2001-2017, Cisco Systems, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 *   Redistributions in binary form must reproduce the above
 *   copyright notice, this list of conditions and the following
 *   disclaimer in the documentation and/or other materials provided
 *   with the distribution.
 *
 *   Neither the name of the Cisco Systems, Inc. nor the names of its
 *   contributors may be used to endorse or promote products derived
 *   from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdio.h>  /* for printf() */
#include <string.h> /* for strlen() */
#include "datatypes.h"
#include "util.h"

void byte_order(void);

void test_hex_string_funcs(void);

void print_string(char *s);

void test_bswap(void);

void test_set_to_zero(void);

int main(void)
{
    /*
     * this program includes various and sundry tests for fundamental
     * datatypes.  it's a grab-bag of throwaway code, retained only in
     * case of future problems
     */

    int i, j;
    v128_t x;
    char *r = "The Moving Finger writes; and, having writ,\n"
              "Moves on: nor all thy Piety nor Wit\n"
              "Shall lure it back to cancel half a Line,\n"
              "Nor all thy Tears wash out a Word of it.";
    char *s = "incomplet";

    print_string(r);
    print_string(s);

    byte_order();
    test_hex_string_funcs();

    for (j = 0; j < 128; j++) {
        v128_set_to_zero(&x);
        /*      x.v32[0] = (1 << j); */
        v128_set_bit(&x, j);
        printf("%s\n", v128_bit_string(&x));
        v128_clear_bit(&x, j);
        printf("%s\n", v128_bit_string(&x));
    }

    printf("----------------------------------------------\n");
    v128_set_to_zero(&x);
    for (i = 0; i < 128; i++) {
        v128_set_bit(&x, i);
    }
    printf("%s\n", v128_bit_string(&x));

    printf("----------------------------------------------\n");
    v128_set_to_zero(&x);
    v128_set_bit(&x, 127);
    for (i = 0; i < 128; i++) {
        printf("%s\n", v128_bit_string(&x));
        v128_left_shift(&x, 1);
    }
    printf("----------------------------------------------\n");
    for (i = 0; i < 128; i++) {
        v128_set_to_zero(&x);
        v128_set_bit(&x, 127);
        v128_left_shift(&x, i);
        printf("%s\n", v128_bit_string(&x));
    }
    printf("----------------------------------------------\n");
    v128_set_to_zero(&x);
    for (i = 0; i < 128; i += 2) {
        v128_set_bit(&x, i);
    }
    printf("bit_string: { %s }\n", v128_bit_string(&x));
    printf("get_bit:    { ");
    for (i = 0; i < 128; i++) {
        if (v128_get_bit(&x, i) == 1)
            printf("1");
        else
            printf("0");
    }
    printf(" } \n");

    test_bswap();
    test_set_to_zero();

    return 0;
}

/* byte_order() prints out byte ordering of datatypes */

void byte_order(void)
{
    int i;
    v128_t e;

    printf("byte ordering of crypto/math datatypes:\n");
    for (i = 0; i < sizeof(e); i++)
        e.v8[i] = i;
    printf("v128_t: %s\n", v128_hex_string(&e));
}

void test_hex_string_funcs(void)
{
    char hex1[] = "abadcafe";
    char hex2[] = "0123456789abcdefqqqqq";
    char raw[10];
    int len;

    len = hex_string_to_octet_string(raw, hex1, strlen(hex1));
    printf("computed length: %d\tstring: %s\n", len,
           octet_string_hex_string(raw, len / 2));
    printf("expected length: %u\tstring: %s\n", (unsigned)strlen(hex1), hex1);

    len = hex_string_to_octet_string(raw, hex2, strlen(hex2));
    printf("computed length: %d\tstring: %s\n", len,
           octet_string_hex_string(raw, len / 2));
    printf("expected length: %d\tstring: %s\n", 16, "0123456789abcdef");
}

void print_string(char *s)
{
    size_t i;
    printf("%s\n", s);
    printf("strlen(s) = %u\n", (unsigned)strlen(s));
    printf("{ ");
    for (i = 0; i < strlen(s); i++) {
        printf("0x%x, ", s[i]);
        if (((i + 1) % 8) == 0)
            printf("\n   ");
    }
    printf("}\n");
}

void test_bswap(void)
{
    uint32_t x = 0x11223344;
    uint64_t y = 0x1122334455667788LL;

    printf("before: %0x\nafter:  %0x\n", x, (unsigned int)be32_to_cpu(x));
    printf("before: %0llx\nafter:  %0llx\n", (unsigned long long)y,
           (unsigned long long)be64_to_cpu(y));

    y = 1234;

    printf("1234: %0llx\n", (unsigned long long)y);
    printf("as octet string: %s\n", octet_string_hex_string((uint8_t *)&y, 8));
    y = be64_to_cpu(y);
    printf("bswapped octet string: %s\n",
           octet_string_hex_string((uint8_t *)&y, 8));
}

void test_set_to_zero(void)
{
#define BUFFER_SIZE (16)
    uint8_t buffer[BUFFER_SIZE];
    size_t i;

    for (i = 0; i < BUFFER_SIZE; i++) {
        buffer[i] = i & 0xff;
    }
    printf("Buffer before: %s\n", octet_string_hex_string(buffer, BUFFER_SIZE));
    octet_string_set_to_zero(buffer, BUFFER_SIZE);
    printf("Buffer after: %s\n", octet_string_hex_string(buffer, BUFFER_SIZE));
    for (i = 0; i < BUFFER_SIZE; i++) {
        if (buffer[i]) {
            fprintf(stderr,
                    "Buffer contents not zero at position %zu (is %d)\n", i,
                    buffer[i]);
            abort();
        }
    }
#undef BUFFER_SIZE
}
