// SPDX-License-Identifier: BSD-2-Clause
// SPDX-FileCopyrightText: Copyright (c) 2025 Runxi Yu <https://runxiyu.org>

package main

const solverProgram = `// This is a reference implementation of the proof of work solver in C.
// For security reasons, it is recommended that you read and understand the
// entire program first if you actually want to run it.
//
// You need to have OpenSSL, and link with -lcrypto

#include <openssl/evp.h>
#include <openssl/bio.h>
#include <openssl/buffer.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>

bool validate_bit_zeros(const unsigned char *bs, unsigned long n)
{
	unsigned long q = n / CHAR_BIT;
	unsigned char r = n % CHAR_BIT;

	for (unsigned long i = 0; i < q; i++) {
		if (bs[i] != 0)
			return false;
	}

	if (r > 0) {
		unsigned char mask =
		    (unsigned char)(UCHAR_MAX << (CHAR_BIT - r));
		if (bs[q] & mask)
			return false;
	}

	return true;
}

int main(int argc, char **argv)
{
	if (argc < 3) {
		fprintf(stderr, "usage: %s <base64_data> <difficulty>\n",
			argv[0]);
		return 1;
	}

	size_t base64_data_len = strlen(argv[1]);
	unsigned char *base64_data = malloc(base64_data_len);
	if (!base64_data) {
		perror("malloc");
		return 1;
	}
	memcpy(base64_data, argv[1], base64_data_len);

	char *endptr = NULL;
	errno = 0;
	unsigned long difficulty = strtoul(argv[2], &endptr, 10);
	if ((difficulty == ULONG_MAX && errno == ERANGE) || *endptr != '\0'
	    || difficulty > 256) {
		fprintf(stderr, "invalid difficulty value\n");
		free(base64_data);
		return 1;
	}

	BIO *b64 = BIO_new(BIO_f_base64());
	BIO *bmem = BIO_new_mem_buf(base64_data, (int)base64_data_len);
	if (!b64 || !bmem) {
		fprintf(stderr, "BIO_new/BIO_new_mem_buf\n");
		free(base64_data);
		return 1;
	}

	BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
	b64 = BIO_push(b64, bmem);

	size_t decoded_cap = base64_data_len;
	unsigned char *decoded = malloc(decoded_cap);
	if (!decoded) {
		perror("malloc");
		BIO_free_all(b64);
		free(base64_data);
		return 1;
	}

	int decoded_len = BIO_read(b64, decoded, (int)decoded_cap);
	if (decoded_len < 0) {
		fprintf(stderr, "BIO_read\n");
		BIO_free_all(b64);
		free(base64_data);
		free(decoded);
		return 1;
	}
	BIO_free_all(b64);
	free(base64_data);

	EVP_MD_CTX *mdctx = EVP_MD_CTX_new();
	if (!mdctx) {
		fprintf(stderr, "EVP_MD_CTX_new\n");
		free(decoded);
		return 1;
	}

	size_t len = EVP_MD_size(EVP_sha256());
	unsigned char digest[len];
	size_t next = 0;

	while (1) {
		if (EVP_DigestInit_ex(mdctx, EVP_sha256(), NULL) != 1) {
			fprintf(stderr, "EVP_DigestInit_ex\n");
			EVP_MD_CTX_free(mdctx);
			free(decoded);
			return 1;
		}
		if (EVP_DigestUpdate(mdctx, decoded, decoded_len) != 1) {
			fprintf(stderr, "EVP_DigestUpdate(data)\n");
			EVP_MD_CTX_free(mdctx);
			free(decoded);
			return 1;
		}
		if (EVP_DigestUpdate(mdctx, &next, sizeof(next)) != 1) {
			fprintf(stderr, "EVP_DigestUpdate(next)\n");
			EVP_MD_CTX_free(mdctx);
			free(decoded);
			return 1;
		}
		if (EVP_DigestFinal_ex(mdctx, digest, NULL) != 1) {
			fprintf(stderr, "EVP_DigestFinal_ex\n");
			EVP_MD_CTX_free(mdctx);
			free(decoded);
			return 1;
		}
		if (validate_bit_zeros(digest, difficulty)) {
			break;
		}
		next++;
		if (!next) {
			fprintf(stderr, "unsigned integer overflow\n");
			EVP_MD_CTX_free(mdctx);
			free(decoded);
			return 1;
		}
	}
	EVP_MD_CTX_free(mdctx);
	free(decoded);

	BIO *b64_out = BIO_new(BIO_f_base64());
	BIO *bmem_out = BIO_new(BIO_s_mem());
	if (!b64_out || !bmem_out) {
		fprintf(stderr, "BIO_new\n");
		if (b64_out)
			BIO_free_all(b64_out);
		if (bmem_out)
			BIO_free(bmem_out);
		return 1;
	}
	BIO_set_flags(b64_out, BIO_FLAGS_BASE64_NO_NL);
	b64_out = BIO_push(b64_out, bmem_out);

	if (BIO_write(b64_out, &next, sizeof(next)) < 0) {
		fprintf(stderr, "BIO_write\n");
		BIO_free_all(b64_out);
		return 1;
	}
	if (BIO_flush(b64_out) < 1) {
		fprintf(stderr, "BIO_flush\n");
		BIO_free_all(b64_out);
		return 1;
	}

	BUF_MEM *bptr = NULL;
	BIO_get_mem_ptr(b64_out, &bptr);
	if (!bptr || !bptr->data) {
		fprintf(stderr, "BIO_get_mem_ptr\n");
		BIO_free_all(b64_out);
		return 1;
	}

	write(STDOUT_FILENO, bptr->data, bptr->length);
	write(STDOUT_FILENO, "\n", 1);

	BIO_free_all(b64_out);
	return 0;
}`