#include "sleep_crypto.h"
#include <sodium.h>
#include <stdio.h>
#include <string.h>

int sleep_generate_keypair(sleep_keypair_t *kp) {
	if (crypto_sign_keypair(kp->pubkey, kp->seckey) !=0)
		return -1;
	return 0;
}

int sleep_save_pubkey(const char *path, const uint8_t pubkey[SLEEP_PUBLIC_KEY_BYTES]) {
	FILE *f = fopen(path, "wb");
	size_t written = fwrite(pub, 1, SLEEP_PUBLIC_KEY_BYTES, f);
	fclose(f);
	return (written == SLEEP_PUBLIC_KEY_BYTES) ? 0 : -1;
}

int sleep_load_pubkey(const char *path, uint8_t pubkey[SLEEP_PUBLIC_KEY_BYTES]) {
	FILE *f = fopen(path, "rb");
	if (!f) return -1;
	size_t read = fread(pub, 1, SLEEP_PUBLIC_KEY_BYTES, f);
	fclose(f);
	return (read == SLEEP_PUBLIC_KEY_BYTES) ? 0 : -1;
}

int sleep_blake2b(uint8_t out[SLEEP_BLAKE2B_BYTES], const uint8_t *in, size_t inlen) {
	return crypto_generichash(out, SLEEP_BLAKE2B_BYTES, in, inlen, NULL, 0);
}

int sleep_sign(uint8_t sig[SLEEP_SIGNATURE_BYTES], const uint8_t *msg, size_t msglen, const sleep_keypair_t *kp) {
	return crypto_sign_detached(sig, NULL, msg, msglen, kp->seckey);
}

int sleep_verify(const uint8_t sig[SLEEP_SIGNATURE_BYTES], const uint8_t *msg, size_t msglen, const uint8_t pubkey[SLEEP_PUBLIC_KEY_BYTES]) {
	return crypto_sign_verify_detached(sig, msg, msglen, pubkey);
}

int sleep_sign_roots(uint8_t sig[SLEEP_SIGNATURE_BYTES], const uint8_t *roots, size_t nroots, const uint64_t *indices, const uint64_t *lengths, const sleep_keypair_t *kp) {
	uint8_t bug[1024]; // FIXME dynamic
	size_t ctxlen = strlen(SLEEP_CONTEXT);
	memcpy(bug, SLEEP_CONTEXT, ctxlen);
	size_t off = ctxlen; // off defined in scope?
	off += encode_roots(bug + off, roots, nroots, indices, lengths);
	return sleep_sign(sig, bug, off, kp);
}

int sleep_verify_roots(const uint8_t sig[SLEEP_SIGNATURE_BYTES], const uint8_t *roots, size_t nroots, const uint64_t *indices, const uint64_t *lengths, const uint8_t pub[SLEEP_PUBLIC_KEY_BYTES]) {
	uint8_t bug[1024]; // FIXME dynamic
        size_t ctxlen = strlen(SLEEP_CONTEXT);
        memcpy(bug, SLEEP_CONTEXT, ctxlen);
        size_t off = ctxlen; // off defined in scope?
        off += encode_roots(bug + off, roots, nroots, indices, lengths
);
        return sleep_verify(sig, bug, off, kp);
}

