/*
 * Copyright (C) 2022 - 2026, Stephan Mueller <smueller@chronox.de>
 *
 * License: see LICENSE file in root directory
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
 * WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
 * DAMAGE.
 */

#include "compare.h"
#include "fips_mode.h"
#include "hash_common.h"
#include "lc_cshake.h"
#include "lc_sha3.h"
#include "sha3_selftest.h"

void sha3_224_selftest_common(const struct lc_hash *sha3_224)
{
	LC_FIPS_RODATA_SECTION
	static const uint8_t msg_224[] = { FIPS140_MOD(0x50), 0xEF, 0x73 };
	LC_FIPS_RODATA_SECTION
	static const uint8_t exp_224[] = { 0x42, 0xF9, 0xE4, 0xEA, 0xE8, 0x55,
					   0x49, 0x61, 0xD1, 0xD2, 0x7D, 0x47,
					   0xD9, 0xAF, 0x08, 0xAF, 0x98, 0x8F,
					   0x18, 0x9F, 0x53, 0x42, 0x2A, 0x07,
					   0xD8, 0x7C, 0x68, 0xC1 };
	uint8_t act[LC_SHA3_224_SIZE_DIGEST];

	LC_SELFTEST_RUN(LC_ALG_STATUS_SHA3);

	lc_hash_nocheck(sha3_224, msg_224, sizeof(msg_224), act);
	lc_compare_selftest(LC_ALG_STATUS_SHA3, act, exp_224, sizeof(exp_224),
			    "SHA3-224");
}

void sha3_256_selftest_common(const struct lc_hash *sha3_256)
{
	LC_FIPS_RODATA_SECTION
	static const uint8_t msg_256[] = { FIPS140_MOD(0x5E), 0x5E, 0xD6 };
	LC_FIPS_RODATA_SECTION
	static const uint8_t exp_256[] = { 0xF1, 0x6E, 0x66, 0xC0, 0x43, 0x72,
					   0xB4, 0xA3, 0xE1, 0xE3, 0x2E, 0x07,
					   0xC4, 0x1C, 0x03, 0x40, 0x8A, 0xD5,
					   0x43, 0x86, 0x8C, 0xC4, 0x0E, 0xC5,
					   0x5E, 0x00, 0xBB, 0xBB, 0xBD, 0xF5,
					   0x91, 0x1E };
	uint8_t act[LC_SHA3_256_SIZE_DIGEST];
	int ongoing = 0;

	/*
	 * SHA3-256 is special:
	 */
	switch (alg_status_get_result(LC_ALG_STATUS_LIB)) {
	case lc_alg_status_result_pending:
		/*
		 * If the library is in pending state, do not perform any test
		 * and keep the algorithm in the existing state (during
		 * startup it would be failed)
		 */
		return;
	case lc_alg_status_result_ongoing:
		/*
		 * If the library is starting up, its self test is performed
		 * unconditionally as the algorithm is used for the FIPS
		 * integrity check.
		 */
		ongoing = 1;
		break;
	case lc_alg_status_result_failed:
	case lc_alg_status_result_passed:
	default:
		/*
		 * We are in the common case
		 */
		LC_SELFTEST_RUN(LC_ALG_STATUS_SHA3);
		break;
	}

	lc_hash_nocheck(sha3_256, msg_256, sizeof(msg_256), act);
	if (lc_compare_selftest(LC_ALG_STATUS_SHA3, act, exp_256,
				sizeof(exp_256), "SHA3-256") &&
	    ongoing) {
		alg_status_set_result(lc_alg_status_result_failed,
				      LC_ALG_STATUS_LIB);
	}
}

void sha3_384_selftest_common(const struct lc_hash *sha3_384)
{
	LC_FIPS_RODATA_SECTION
	static const uint8_t msg_384[] = { FIPS140_MOD(0xE7), 0x3B, 0xAD };
	LC_FIPS_RODATA_SECTION
	static const uint8_t exp_384[] = {
		0xc4, 0x02, 0xc8, 0x29, 0x90, 0x68, 0xaa, 0x30, 0x28, 0xa9,
		0xa4, 0x1c, 0xff, 0x9a, 0x0b, 0x74, 0x27, 0x31, 0x92, 0x70,
		0xf2, 0x42, 0x18, 0xda, 0xe8, 0x68, 0x1a, 0x89, 0x01, 0x51,
		0x0c, 0x47, 0x5a, 0x5f, 0xb9, 0x6b, 0x5c, 0xbc, 0x32, 0xdc,
		0xa1, 0x5f, 0x28, 0x53, 0xa0, 0xce, 0x55, 0xf6
	};
	uint8_t act[LC_SHA3_384_SIZE_DIGEST];

	LC_SELFTEST_RUN(LC_ALG_STATUS_SHA3);

	lc_hash_nocheck(sha3_384, msg_384, sizeof(msg_384), act);
	lc_compare_selftest(LC_ALG_STATUS_SHA3, act, exp_384, sizeof(exp_384),
			    "SHA3-384");
}

void sha3_512_selftest_common(const struct lc_hash *sha3_512)
{
	LC_FIPS_RODATA_SECTION
	static const uint8_t msg_512[] = { FIPS140_MOD(0x82), 0xD9, 0x19 };
	LC_FIPS_RODATA_SECTION
	static const uint8_t exp_512[] = {
		0x76, 0x75, 0x52, 0x82, 0xA9, 0xC5, 0x0A, 0x67, 0xFE, 0x69,
		0xBD, 0x3F, 0xCE, 0xFE, 0x12, 0xE7, 0x1D, 0xE0, 0x4F, 0xA2,
		0x51, 0xC6, 0x7E, 0x9C, 0xC8, 0x5C, 0x7F, 0xAB, 0xC6, 0xCC,
		0x89, 0xCA, 0x9B, 0x28, 0x88, 0x3B, 0x2A, 0xDB, 0x22, 0x84,
		0x69, 0x5D, 0xD0, 0x43, 0x77, 0x55, 0x32, 0x19, 0xC8, 0xFD,
		0x07, 0xA9, 0x4C, 0x29, 0xD7, 0x46, 0xCC, 0xEF, 0xB1, 0x09,
		0x6E, 0xDE, 0x42, 0x91
	};
	uint8_t act[LC_SHA3_512_SIZE_DIGEST];

	LC_SELFTEST_RUN(LC_ALG_STATUS_SHA3);

	lc_hash_nocheck(sha3_512, msg_512, sizeof(msg_512), act);
	lc_compare_selftest(LC_ALG_STATUS_SHA3, act, exp_512, sizeof(exp_512),
			    "SHA3-512");
}

void shake128_selftest_common(const struct lc_hash *shake128)
{
	LC_FIPS_RODATA_SECTION
	static const uint8_t msg[] = { FIPS140_MOD(0xBE),
				       0x94,
				       0xD8,
				       0x3D,
				       0x37,
				       0x66,
				       0xCF,
				       0x3E,
				       0xD3,
				       0x0A,
				       0x11,
				       0x0C,
				       0x47,
				       0xA2 };
	LC_FIPS_RODATA_SECTION
	static const uint8_t exp[] = { 0xB0, 0x46, 0x01, 0xAA, 0x4D, 0x2C,
				       0x30, 0xF6, 0x5F, 0x94, 0xD7, 0x02,
				       0x5D, 0xBD, 0x22, 0x39 };
	uint8_t act[sizeof(exp)];

	LC_SELFTEST_RUN(LC_ALG_STATUS_SHAKE);

	lc_xof_nocheck(shake128, msg, sizeof(msg), act, sizeof(act));
	lc_compare_selftest(LC_ALG_STATUS_SHAKE, act, exp, sizeof(exp),
			    "SHAKE-128");
}

void shake256_selftest_common(const struct lc_hash *shake256)
{
	LC_FIPS_RODATA_SECTION
	static const uint8_t msg[] = { FIPS140_MOD(0x6C),
				       0x9E,
				       0xC8,
				       0x5C,
				       0xBA,
				       0xBA,
				       0x62,
				       0xF5,
				       0xBC,
				       0xFE,
				       0xA1,
				       0x9E,
				       0xB9,
				       0xC9,
				       0x20,
				       0x52,
				       0xD8,
				       0xFF,
				       0x18,
				       0x81,
				       0x52,
				       0xE9,
				       0x61,
				       0xC1,
				       0xEC,
				       0x5C,
				       0x75,
				       0xBF,
				       0xC3,
				       0xC9,
				       0x1C,
				       0x8D };
	LC_FIPS_RODATA_SECTION
	static const uint8_t exp[] = { 0x7d, 0x6a, 0x09, 0x6e, 0x13, 0x66, 0x1d,
				       0x9d, 0x0e, 0xca, 0xf5, 0x38, 0x30, 0xa1,
				       0x92, 0x87, 0xe0, 0xb3, 0x6e, 0xce, 0x48,
				       0x82, 0xeb, 0x58, 0x0b, 0x78, 0x5c, 0x1d,
				       0xef, 0x2d, 0xe5, 0xaa, 0x6c };
	uint8_t act[sizeof(exp)];

	LC_SELFTEST_RUN(LC_ALG_STATUS_SHAKE);

	lc_xof_nocheck(shake256, msg, sizeof(msg), act, sizeof(act));
	lc_compare_selftest(LC_ALG_STATUS_SHAKE, act, exp, sizeof(exp),
			    "SHAKE-256");
}

void shake512_selftest_common(const struct lc_hash *shake512)
{
	LC_FIPS_RODATA_SECTION
	static const uint8_t msg[] = { FIPS140_MOD(0x6C),
				       0x9E,
				       0xC8,
				       0x5C,
				       0xBA,
				       0xBA,
				       0x62,
				       0xF5,
				       0xBC,
				       0xFE,
				       0xA1,
				       0x9E,
				       0xB9,
				       0xC9,
				       0x20,
				       0x52,
				       0xD8,
				       0xFF,
				       0x18,
				       0x81,
				       0x52,
				       0xE9,
				       0x61,
				       0xC1,
				       0xEC,
				       0x5C,
				       0x75,
				       0xBF,
				       0xC3,
				       0xC9,
				       0x1C,
				       0x8D };
	LC_FIPS_RODATA_SECTION
	static const uint8_t exp[] = { 0xc7, 0x9e, 0xcf, 0x01, 0xff, 0x17, 0xbd,
				       0x81, 0x22, 0x99, 0xae, 0x46, 0xb1, 0x09,
				       0x7b, 0x93, 0x32, 0x73, 0x40, 0x60, 0x81,
				       0x30, 0xf3, 0x0b, 0xb5, 0xc6, 0x5d, 0x95,
				       0x41, 0xb5, 0x33, 0x10 };
	uint8_t act[sizeof(exp)];

	LC_SELFTEST_RUN(LC_ALG_STATUS_SHAKE512);

	lc_xof_nocheck(shake512, msg, sizeof(msg), act, sizeof(act));
	lc_compare_selftest(LC_ALG_STATUS_SHAKE512, act, exp, sizeof(exp),
			    "SHAKE-512");
}

void cshake128_selftest_common(const struct lc_hash *cshake128)
{
	LC_FIPS_RODATA_SECTION
	static const uint8_t msg[] = { FIPS140_MOD(0x0C),
				       0x77,
				       0x8C,
				       0x22,
				       0x60,
				       0xCA,
				       0xE8,
				       0x28,
				       0xA0 };
	LC_FIPS_RODATA_SECTION
	static const uint8_t cust[] = {
		0xD8, 0x3E, 0x11, 0x1C, 0xA8, 0x8A, 0x8D, 0xCE, 0xC6, 0xDE,
		0xCD, 0x33, 0x4D, 0x27, 0x45, 0x33, 0x47, 0xA1, 0x58, 0x1B,
		0x6B, 0x88, 0x91, 0x40, 0x73, 0xBA, 0x59, 0x90, 0x05, 0x4D,
		0xC0, 0xE4, 0xDE, 0x22, 0x08, 0xF8, 0x63, 0x31, 0x79, 0xB9,
		0xB6, 0xE8, 0x17, 0x4E, 0xC7, 0xC9, 0x7B, 0xD6, 0xFF, 0x55,
		0x5D, 0xEE, 0x6F, 0x4A, 0x2C, 0xE1, 0x37, 0x75, 0x4D, 0x21,
		0x43, 0x44, 0xB7, 0xDE, 0x2C, 0x95, 0xFD, 0xC8, 0xFE, 0x44,
		0x88, 0xA4, 0x90, 0xC7, 0x65, 0x98, 0x69, 0xC9, 0xB5, 0xC1,
		0xDC, 0x9D, 0xD4, 0xBD, 0x2B, 0xED, 0x7A, 0xDC, 0xEA, 0x06,
		0x3D, 0xEC, 0xD6, 0x09, 0x80, 0x1C, 0x81, 0x80, 0x17, 0x7D,
		0x8B, 0x57, 0x73, 0xD3, 0x12, 0x89, 0xDB, 0xE9, 0x26, 0x17,
		0xE7, 0x75, 0x61, 0x24, 0x2B, 0xC3, 0x60, 0x38, 0x5E, 0x43,
		0x13, 0x89, 0x20, 0x72, 0x18, 0x9A, 0x2D, 0x6B, 0xB0, 0x8C,
		0xAF, 0x51, 0x3E, 0x17, 0xE6, 0x07, 0x61, 0x34, 0xF5, 0x8A,
		0x30, 0x8D, 0x65, 0x0B, 0x79, 0x55, 0x86, 0x04, 0x75, 0x31,
		0xA9, 0x31, 0xD1, 0x55, 0x94, 0x71, 0x5F, 0xD5, 0x08, 0x07,
		0x13
	};
	static const uint8_t exp[] = { 0x77, 0x6e, 0x75, 0x95, 0x0d, 0xdd,
				       0x3b, 0xf8, 0xc6, 0xcd, 0x35, 0xfe };
	uint8_t act[sizeof(exp)];

	LC_SELFTEST_RUN(LC_ALG_STATUS_CSHAKE);

	LC_HASH_CTX_ON_STACK(ctx, cshake128);

	if (lc_cshake_init_nocheck(ctx, NULL, 0, cust, sizeof(cust)))
		goto out;
	lc_hash_update(ctx, msg, sizeof(msg));
	lc_hash_set_digestsize(ctx, sizeof(act));
	lc_hash_final(ctx, act);

out:
	lc_compare_selftest(LC_ALG_STATUS_CSHAKE, act, exp, sizeof(exp),
			    "cSHAKE-128");
	lc_hash_zero(ctx);
}

void cshake256_selftest_common(const struct lc_hash *cshake256)
{
	LC_FIPS_RODATA_SECTION
	static const uint8_t msg[] = { FIPS140_MOD(0xAF),
				       0x98,
				       0xC2,
				       0x12,
				       0x96,
				       0x1A,
				       0xAA,
				       0x55,
				       0xBD,
				       0x3C,
				       0x61,
				       0xF1 };
	LC_FIPS_RODATA_SECTION
	static const uint8_t cust[] = {
		0x41, 0xE6, 0x62, 0x6C, 0x45, 0x41, 0x10, 0x9D, 0x57, 0x77,
		0x17, 0x40, 0x80, 0x09, 0xB0, 0x6B, 0x0C, 0x01, 0xF3, 0x5A,
		0xC1, 0xAA, 0xB1, 0xDB, 0x57, 0x9E, 0x7D, 0xE6, 0x7B, 0xD2,
		0xDF, 0xFB, 0x43, 0x7A, 0x65, 0x62, 0xF3, 0x81, 0x9D, 0xE5,
		0x01, 0x8C, 0xBC, 0xB6, 0x66, 0x7D, 0x90, 0xF1, 0x21, 0x05,
		0x6E, 0xB0, 0xC3, 0x60, 0x65, 0xA6, 0x48, 0x56, 0xED, 0xE2,
		0x27, 0x12, 0x29, 0x14, 0x2D, 0x7D, 0xBD, 0x10, 0xFB, 0xD1,
		0x71, 0x7A, 0xB2, 0xB6, 0xBB, 0x27, 0x50, 0xF9, 0x32, 0x45,
		0x81, 0xA4, 0xF9, 0xA4, 0xE7, 0x0D, 0x79, 0x00, 0x8B, 0x60,
		0x34, 0x65, 0xFB, 0x50, 0x9C, 0xBC, 0xB3, 0x0D
	};
	static const uint8_t exp[] = {
		0x90, 0x67, 0x5B, 0x96, 0x09, 0x63, 0xE9, 0x2A, 0x5D, 0x2E,
		0x66, 0xE3, 0x15, 0x8D, 0x0E, 0xE5, 0xC0, 0x7B, 0x83, 0xBB,
		0x23, 0x7B, 0x2A, 0x51, 0xE7, 0xE1, 0x24, 0x03, 0x68, 0xBD,
		0x9F, 0x39, 0xC0, 0x96, 0x6E, 0x94, 0x37, 0x3B, 0x52, 0x6A,
		0x79, 0x1F, 0xD4, 0x03, 0x4E, 0x46, 0xFD, 0x46, 0xEA, 0xAF,
		0x57, 0x92, 0xB8, 0x4E, 0x50, 0x92, 0x81, 0xB6, 0x11, 0xD2,
		0x72, 0x14, 0xC7, 0xEE, 0x2F, 0x93, 0xDD, 0x46, 0x62, 0x7D,
		0x09, 0x2D, 0xD8, 0xA1, 0x58, 0x87, 0xEF, 0x5A, 0xAA, 0x3C,
		0x46, 0x8D, 0x7A, 0x4C, 0x57, 0x71, 0x7B, 0x9A, 0x4C, 0x92,
		0xEA
	};
	uint8_t act[sizeof(exp)];

	LC_SELFTEST_RUN(LC_ALG_STATUS_CSHAKE);

	LC_HASH_CTX_ON_STACK(ctx, cshake256);

	if (lc_cshake_init_nocheck(ctx, NULL, 0, cust, sizeof(cust)))
		goto out;
	lc_hash_update(ctx, msg, sizeof(msg));
	lc_hash_set_digestsize(ctx, sizeof(act));
	lc_hash_final(ctx, act);

out:
	lc_compare_selftest(LC_ALG_STATUS_CSHAKE, act, exp, sizeof(exp),
			    "cSHAKE-256");
	lc_hash_zero(ctx);
}
