#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "argon2.h"
#include "random.h"
#include "util.h"

static void
die(int check, char *why)
{
	if (check) {
		fprintf(stderr, "Error: %s\n", why);
		exit(1);
	}
}

int
main(int argc, char *argv[])
{
	if (argc != 3) {
		fprintf(stderr, "Usage: %s <challenge> <proof>\n", argv[0]);
		return 1;
	}

	int iters, memory, digits;
	unsigned char salt[16];

	char *challenge = argv[1];
	char *algo = strtok(challenge, ":");
	if (strcmp(algo, "argon2id") != 0) {
		fprintf(stderr, "Error: unknown challenge type %s\n", algo);
		return 1;
	}
	char *endptr;

	char *iterstr = strtok(NULL, ":");
	iters = strtoul(iterstr, &endptr, 10);
	die(*endptr, "Invalid challenge");

	char *memorystr = strtok(NULL, ":");
	memory = strtoul(memorystr, &endptr, 10);
	die(*endptr, "Invalid challenge");

	char *digitsstr = strtok(NULL, ":");
	digits = strtoul(digitsstr, &endptr, 10);
	die(*endptr, "Invalid challenge");

	char *saltstr = strtok(NULL, ":");
	die(strlen(saltstr) != 32, "Invalid challenge");
	int r = dechex(saltstr, strlen(saltstr), salt, sizeof(salt));
	die(r == -1, "Invalid challenge");

	unsigned char password[16];
	unsigned char hash[32];
	argon2_context context = {
		.out = hash,
		.outlen = sizeof(hash),
		.salt = salt,
		.saltlen = sizeof(salt),
		.pwd = password,
		.pwdlen = sizeof(password),
		.t_cost = iters,
		.m_cost = memory,
		.lanes = 1,
		.threads = 1,
		.flags = ARGON2_DEFAULT_FLAGS,
	};

	die(strlen(argv[2]) != 32, "Invalid proof");
	r = dechex(argv[2], strlen(argv[2]) + 1, password, sizeof(password));
	die(r == -1, "Invalid challenge");

	r = argon2id_ctx(&context);
	die(r != 0, "argon2id failed\n");

	for (int i = 0; i < digits / 2; ++i) {
		if (hash[i] != 0) {
			printf("proof: failed\n");
			return 1;
		}
	}

	printf("proof: ok\n");
	return 0;
}
