/* Copyright (c) 2025 Jakub Juszczakiewicz
 * All rights reserved.
 */

#include "random.h"
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <kitcryptoc/ung.h>
#include <kitcryptoc/sha2.h>
#include <semaphore.h>

#define SEED_BUF_SIZE 64

static struct kit_ung_512 seeddata;
static sem_t seedsem;

void random_init(void)
{
  uint8_t seedbuf[SEED_BUF_SIZE];
  FILE * f = fopen("/dev/urandom", "rb");
  if (!f) {
    (void)fread(seedbuf, SEED_BUF_SIZE, 1, f);
  } else {
    srand(time(NULL));
    for (size_t i = 0; i < SEED_BUF_SIZE; i++)
      seedbuf[i] = rand();
  }
  kit_ung_512_init(&seeddata, kit_sha512, seedbuf);
  sem_init(&seedsem, 0, 1);
}

void random_done(void)
{
  sem_close(&seedsem);
  kit_ung_512_finish(&seeddata);
}

int random_bytes(size_t bytes, unsigned char * data)
{
  sem_wait(&seedsem);
  kit_ung_512_next(&seeddata, data, bytes);
  sem_post(&seedsem);
  return 0;
}

int gmp_random(size_t bits, mpz_t output)
{
  size_t bytes = (bits + 7) / 8;
  char * buffer = malloc(bytes);
  random_bytes(bytes, buffer);

  if (bits & 7) {
    buffer[bytes - 1] &= 0xFF >> (8 - (bytes & 7));
  }

  mpz_import(output, bytes, 1, 1, 0, 0, buffer);

  free(buffer);
  return 0;
}
