#include "wiz_bignum_tool.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/*
 * Convert an ASCII character to digit value
 */
static int bn_get_digit(uint32_t *d, char c) {
  *d = 255;

  if (c >= 0x30 && c <= 0x39)
    *d = c - 0x30;
  if (c >= 0x41 && c <= 0x46)
    *d = c - 0x37;
  if (c >= 0x61 && c <= 0x66)
    *d = c - 0x57;

  if (*d >= (uint32_t)16)
    return (-1);

  return (0);
}

/*
 * Import from an ASCII string
 */
int bn_read_string(uint32_t *r, uint32_t len, const char *s) {
  uint32_t i, j, slen;
  uint32_t d;

  slen = strlen(s);

  if ((len * 8) < slen)
    return (-1);

  memset(r, 0, (len * sizeof(uint32_t)));

  for (i = slen, j = 0; i > 0; i--, j++) {
    if (-1 == bn_get_digit(&d, s[i - 1]))
      return (-1);
    r[j / 8] |= d << ((j % 8) << 2);
  }

  return (0);
}

/*
 * Export into an HEX ASCII string
 */
int bn_write_string(char *s, uint32_t *slen, const uint32_t *content,
                    uint32_t len) {
  int32_t ret = 0;
  uint32_t n;
  char *p;

  int32_t c;
  uint32_t i, j, k;

  n = len * 8;
  n += 2; //"\0"

  if (*slen < n) {
    *slen = n;
    return (-1);
  }

  p = s;

  for (i = len, k = 0; i > 0; i--) {
    for (j = 4; j > 0; j--) {
      c = (content[i - 1] >> ((j - 1) << 3)) & 0xFF;

      if (c == 0 && k == 0 && (i + j + 3) != 0)
        continue;

      *(p++) = "0123456789ABCDEF"[c / 16];
      *(p++) = "0123456789ABCDEF"[c % 16];
      k = 1;
    }
  }

  *p++ = '\0';
  *slen = p - s;

  return (ret);
}

/*
 *	Print bignum with HEX string
int bn_printf(const uint32_t *r, uint32_t len)
{
        char *s = NULL;
        uint32_t s_len;
        if(r == NULL || len == 0)
                return -1;
        //the X most significant bits number
        s_len = len;
        //radix is 16
        s_len = (s_len * 32) >> 2;
        s_len += 4;
        s = (char *)malloc(s_len);
        bn_write_string(s, &s_len, r, len);
        if(s_len <= 1)
                wiz_printf("0");
        else
                wiz_printf("%s", s);

        free(s);
        return 0;
}
 */

/*
 * Import from an ASCII string to an big endian data array
 */
int bn_read_string_to_bytes(uint8_t *r, uint32_t len, const char *s) {
  uint32_t i, j, slen;
  uint32_t d;

  slen = strlen(s);

  if ((len * 2) < slen)
    return (-1);

  memset(r, 0, len);

  len = len - 1;

  for (i = slen, j = 0; i > 0; i--, j++) {
    if (-1 == bn_get_digit(&d, s[i - 1]))
      return (-1);
    r[len - j / 2] |= d << ((j % 2) << 2);
  }

  return (0);
}

int bn_read_string_from_head(uint8_t *r, uint32_t len, const char *s) {
  int32_t i, j, slen;
  uint32_t d;

  if ((slen = strlen(s)) < 0) {
    return -1;
  }

  if ((len * 2) < slen)
    return (-1);

  if (slen & 1) {
    slen += 1;
  }

  memset(r, 0, len);

  len = slen >> 1;

  for (i = slen, j = 0; i > 0; i--, j++) {
    if (-1 == bn_get_digit(&d, s[i - 1]))
      return (-1);
    r[len - 1 - j / 2] |= d << ((j % 2) << 2);
  }

  return (len);
}
