#include <stdlib.h>
#include <string.h>
#include "libbitcoinpqc/slh_dsa.h"
#include "../../sphincsplus/ref/api.h"
#include "../../sphincsplus/ref/randombytes.h"
#include "../../sphincsplus/ref/params.h"
#include "../../sphincsplus/ref/fips202.h"
#define CRYPTO_ALGNAME "SPHINCS+-shake-128s"
static uint8_t *g_random_data = NULL;
static size_t g_random_data_size = 0;
static size_t g_random_data_offset = 0;
static void init_random_source(const uint8_t *random_data, size_t random_data_size) {
g_random_data = (uint8_t *)random_data;
g_random_data_size = random_data_size;
g_random_data_offset = 0;
}
static void custom_randombytes(uint8_t *out, size_t outlen) {
if (g_random_data == NULL || g_random_data_size == 0) {
memset(out, 0, outlen);
return;
}
size_t remaining = g_random_data_size - g_random_data_offset;
if (outlen > remaining) {
size_t position = 0;
while (position < outlen) {
size_t to_copy = (outlen - position < remaining) ? outlen - position : remaining;
memcpy(out + position, g_random_data + g_random_data_offset, to_copy);
position += to_copy;
g_random_data_offset = (g_random_data_offset + to_copy) % g_random_data_size;
remaining = g_random_data_size - g_random_data_offset;
}
} else {
memcpy(out, g_random_data + g_random_data_offset, outlen);
g_random_data_offset = (g_random_data_offset + outlen) % g_random_data_size;
}
}
static void (*original_randombytes)(uint8_t *, size_t) = NULL;
static void setup_custom_random() {
if (original_randombytes == NULL) {
original_randombytes = randombytes;
}
randombytes = custom_randombytes;
}
static void restore_original_random() {
if (original_randombytes != NULL) {
randombytes = original_randombytes;
}
g_random_data = NULL;
g_random_data_size = 0;
g_random_data_offset = 0;
}
int slh_dsa_shake_128s_keygen(
uint8_t *pk,
uint8_t *sk,
const uint8_t *random_data,
size_t random_data_size
) {
if (!pk || !sk || !random_data || random_data_size < 128) {
return -1;
}
init_random_source(random_data, random_data_size);
setup_custom_random();
int result = crypto_sign_keypair(pk, sk);
restore_original_random();
return result;
}
int slh_dsa_shake_128s_sign(
uint8_t *sig,
size_t *siglen,
const uint8_t *m,
size_t mlen,
const uint8_t *sk,
const uint8_t *random_data,
size_t random_data_size
) {
if (!sig || !siglen || !m || !sk) {
return -1;
}
if (random_data && random_data_size >= 64) {
init_random_source(random_data, random_data_size);
setup_custom_random();
}
unsigned long long temp_siglen;
int result = crypto_sign_signature(sig, &temp_siglen, m, mlen, sk);
*siglen = (size_t)temp_siglen;
if (random_data && random_data_size >= 64) {
restore_original_random();
}
return result;
}
int slh_dsa_shake_128s_verify(
const uint8_t *sig,
size_t siglen,
const uint8_t *m,
size_t mlen,
const uint8_t *pk
) {
if (!sig || !m || !pk) {
return -1;
}
return crypto_sign_verify(sig, siglen, m, mlen, pk);
}