text: #include <stddef.h>
  #include <stdint.h>
  #include <stdio.h>
  #include <string.h>
  #include <unistd.h>
  
  #include <oqs/aes.h>
  #include <oqs/sha2.h>
  #include <oqs/sha3.h>
  
  #include "system_info.c"
  
  #define BUFFER_SIZE 10000
  
  static int read_stdin(uint8_t **msg, size_t *msg_len) {
  	*msg = malloc(BUFFER_SIZE);
  	if (*msg == NULL) {
  		return -1;
  	}
  	uint8_t *msg_next_read = *msg;
  	ssize_t bytes_read;
  	*msg_len = 0;
  	while (1) {
  		bytes_read = read(0, msg_next_read, BUFFER_SIZE);
  		if (bytes_read == -1) {
  			return -1;
  		}
  		*msg_len += (size_t)bytes_read;
  		if (bytes_read < BUFFER_SIZE) {
  			break;
  		} else {
  			uint8_t *msgprime = malloc(*msg_len + BUFFER_SIZE);
  			if (msgprime == NULL) {
  				return -1;
  			}
  			memcpy(msgprime, *msg, *msg_len);
  			free(*msg);
  			*msg = msgprime;
  			msg_next_read = &((*msg)[*msg_len]);
  		}
  	}
  	return 0;
  }
  
  static void print_hex(uint8_t *s, size_t l) {
  	for (size_t i = 0; i < l; i++) {
  		printf("%02x", s[i]);
  	}
  	printf("\n");
  }
  
  static int do_sha256(void) {
  	// read message from stdin
  	uint8_t *msg;
  	size_t msg_len;
  	if (read_stdin(&msg, &msg_len) != 0) {
  		fprintf(stderr, "ERROR: malloc failure\n");
  		return -1;
  	}
  	// run main SHA-256 API
  	uint8_t output[32];
  	OQS_SHA2_sha256(output, msg, msg_len);
  	// run incremental SHA-256 API
  	uint8_t output_inc[32];
  	OQS_SHA2_sha256_ctx state;
  	OQS_SHA2_sha256_inc_init(&state);
  	// clone state
  	OQS_SHA2_sha256_ctx state2;
  	OQS_SHA2_sha256_inc_ctx_clone(&state2, &state);
  	// hash with first state
  	if (msg_len > 64) {
  		OQS_SHA2_sha256_inc_blocks(&state, msg, 1);
  		OQS_SHA2_sha256_inc_finalize(output_inc, &state, &msg[64], msg_len - 64);
  	} else {
  		OQS_SHA2_sha256_inc_finalize(output_inc, &state, msg, msg_len);
  	}
  	if (memcmp(output, output_inc, 32) != 0) {
  		fprintf(stderr, "ERROR: Incremental API does not match main API\n");
  		free(msg);
  		return -2;
  	}
  	// hash with second state
  	if (msg_len > 64) {
  		OQS_SHA2_sha256_inc_blocks(&state2, msg, 1);
  		OQS_SHA2_sha256_inc_finalize(output_inc, &state2, &msg[64], msg_len - 64);
  	} else {
  		OQS_SHA2_sha256_inc_finalize(output_inc, &state2, msg, msg_len);
  	}
  	if (memcmp(output, output_inc, 32) != 0) {
  		fprintf(stderr, "ERROR: Incremental API with cloned state does not match main API\n");
  		free(msg);
  		return -3;
  	}
  	print_hex(output, 32);
  	free(msg);
  	return 0;
  }
  
  static int do_sha384(void) {
  	// read message from stdin
  	uint8_t *msg;
  	size_t msg_len;
  	if (read_stdin(&msg, &msg_len) != 0) {
  		fprintf(stderr, "ERROR: malloc failure\n");
  		return -1;
  	}
  	// run main SHA-384 API
  	uint8_t output[48];
  	OQS_SHA2_sha384(output, msg, msg_len);
  	// run incremental SHA-384 API
  	uint8_t output_inc[48];
  	OQS_SHA2_sha384_ctx state;
  	OQS_SHA2_sha384_inc_init(&state);
  	// clone state
  	OQS_SHA2_sha384_ctx state2;
  	OQS_SHA2_sha384_inc_ctx_clone(&state2, &state);
  	// hash with first state
  	if (msg_len > 64) {
  		OQS_SHA2_sha384_inc_blocks(&state, msg, 1);
  		OQS_SHA2_sha384_inc_finalize(output_inc, &state, &msg[64], msg_len - 64);
  	} else {
  		OQS_SHA2_sha384_inc_finalize(output_inc, &state, msg, msg_len);
  	}
  	if (memcmp(output, output_inc, 48) != 0) {
  		fprintf(stderr, "ERROR: Incremental API does not match main API\n");
  		free(msg);
  		return -2;
  	}
  	// hash with second state
  	if (msg_len > 64) {
  		OQS_SHA2_sha384_inc_blocks(&state2, msg, 1);
  		OQS_SHA2_sha384_inc_finalize(output_inc, &state2, &msg[64], msg_len - 64);
  	} else {
  		OQS_SHA2_sha384_inc_finalize(output_inc, &state2, msg, msg_len);
  	}
  	if (memcmp(output, output_inc, 48) != 0) {
  		fprintf(stderr, "ERROR: Incremental API with cloned state does not match main API\n");
  		free(msg);
  		return -3;
  	}
  	print_hex(output, 48);
  	free(msg);
  	return 0;
  }
  
  static int do_sha512(void) {
  	// read message from stdin
  	uint8_t *msg;
  	size_t msg_len;
  	if (read_stdin(&msg, &msg_len) != 0) {
  		fprintf(stderr, "ERROR: malloc failure\n");
  		return -1;
  	}
  	// run main SHA-512 API
  	uint8_t output[64];
  	OQS_SHA2_sha512(output, msg, msg_len);
  	// run incremental SHA-512 API
  	uint8_t output_inc[64];
  	OQS_SHA2_sha512_ctx state;
  	OQS_SHA2_sha512_inc_init(&state);
  	// clone state
  	OQS_SHA2_sha512_ctx state2;
  	OQS_SHA2_sha512_inc_ctx_clone(&state2, &state);
  	// hash with first state
  	if (msg_len > 64) {
  		OQS_SHA2_sha512_inc_blocks(&state, msg, 1);
  		OQS_SHA2_sha512_inc_finalize(output_inc, &state, &msg[64], msg_len - 64);
  	} else {
  		OQS_SHA2_sha512_inc_finalize(output_inc, &state, msg, msg_len);
  	}
  	if (memcmp(output, output_inc, 64) != 0) {
  		fprintf(stderr, "ERROR: Incremental API does not match main API\n");
  		free(msg);
  		return -2;
  	}
  	// hash with second state
  	if (msg_len > 64) {
  		OQS_SHA2_sha512_inc_blocks(&state2, msg, 1);
  		OQS_SHA2_sha512_inc_finalize(output_inc, &state2, &msg[64], msg_len - 64);
  	} else {
  		OQS_SHA2_sha512_inc_finalize(output_inc, &state2, msg, msg_len);
  	}
  	if (memcmp(output, output_inc, 64) != 0) {
  		fprintf(stderr, "ERROR: Incremental API with cloned state does not match main API\n");
  		free(msg);
  		return -3;
  	}
  	print_hex(output, 64);
  	free(msg);
  	return 0;
  }
  
  static int do_arbitrary_hash(void (*hash)(uint8_t *, const uint8_t *, size_t), size_t hash_len) {
  	// read message from stdin
  	uint8_t *msg;
  	size_t msg_len;
  	if (read_stdin(&msg, &msg_len) != 0) {
  		fprintf(stderr, "ERROR: malloc failure\n");
  		return -1;
  	}
  	// run main SHA-256 API
  	uint8_t *output = malloc(hash_len);
  	hash(output, msg, msg_len);
  	print_hex(output, hash_len);
  	free(output);
  	free(msg);
  	return 0;
  }
  
  int main(int argc, char **argv) {
  	if (argc != 2) {
  		fprintf(stderr, "Usage: test_hash algname\n");
  		fprintf(stderr, "  algname: sha256, sha384, sha512, sha256inc, sha384inc, sha512inc\n");
  		fprintf(stderr, "  test_hash reads input from stdin and outputs hash value as hex string to stdout");
  		printf("\n");
  		print_system_info();
  		return EXIT_FAILURE;
  	}
  
  	char *hash_alg = argv[1];
  
  	if (strcmp(hash_alg, "sha256inc") == 0) {
  		return do_sha256();
  	} else if (strcmp(hash_alg, "sha384inc") == 0) {
  		return do_sha384();
  	} else if (strcmp(hash_alg, "sha512inc") == 0) {
  		return do_sha512();
  	} else if (strcmp(hash_alg, "sha256") == 0) {
  		return do_arbitrary_hash(&OQS_SHA2_sha256, 32);
  	} else if (strcmp(hash_alg, "sha384") == 0) {
  		return do_arbitrary_hash(&OQS_SHA2_sha384, 48);
  	} else if (strcmp(hash_alg, "sha512") == 0) {
  		return do_arbitrary_hash(&OQS_SHA2_sha512, 64);
  	} else {
  		fprintf(stderr, "ERROR: Test not implemented\n");
  		return EXIT_FAILURE;
  	}
  }
  