/*
 * Copyright (C) 2023 - 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 "cpufeatures.h"
#include "ext_headers_internal.h"
#include "lc_x448.h"
#include "compare.h"
#include "ret_checkers.h"
#include "static_rng.h"
#include "test_helper_common.h"
#include "visibility.h"

/* Test vector obtained from RFC 7748 section 5.2 */
static int x448_ss_tester(unsigned int loops)
{
	static const struct lc_x448_pk pk = {
		.pk = { 0x06, 0xfc, 0xe6, 0x40, 0xfa, 0x34, 0x87, 0xbf,
			0xda, 0x5f, 0x6c, 0xf2, 0xd5, 0x26, 0x3f, 0x8a,
			0xad, 0x88, 0x33, 0x4c, 0xbd, 0x07, 0x43, 0x7f,
			0x02, 0x0f, 0x08, 0xf9, 0x81, 0x4d, 0xc0, 0x31,
			0xdd, 0xbd, 0xc3, 0x8c, 0x19, 0xc6, 0xda, 0x25,
			0x83, 0xfa, 0x54, 0x29, 0xdb, 0x94, 0xad, 0xa1,
			0x8a, 0xa7, 0xa7, 0xfb, 0x4e, 0xf8, 0xa0, 0x86 }
	};
	static const struct lc_x448_sk sk = {
		.sk = { 0x3d, 0x26, 0x2f, 0xdd, 0xf9, 0xec, 0x8e, 0x88,
			0x49, 0x52, 0x66, 0xfe, 0xa1, 0x9a, 0x34, 0xd2,
			0x88, 0x82, 0xac, 0xef, 0x04, 0x51, 0x04, 0xd0,
			0xd1, 0xaa, 0xe1, 0x21, 0x70, 0x0a, 0x77, 0x9c,
			0x98, 0x4c, 0x24, 0xf8, 0xcd, 0xd7, 0x8f, 0xbf,
			0xf4, 0x49, 0x43, 0xeb, 0xa3, 0x68, 0xf5, 0x4b,
			0x29, 0x25, 0x9a, 0x4f, 0x1c, 0x60, 0x0a, 0xd3 }
	};
	static const struct lc_x448_ss ss = {
		.ss = { 0xce, 0x3e, 0x4f, 0xf9, 0x5a, 0x60, 0xdc, 0x66,
			0x97, 0xda, 0x1d, 0xb1, 0xd8, 0x5e, 0x6a, 0xfb,
			0xdf, 0x79, 0xb5, 0x0a, 0x24, 0x12, 0xd7, 0x54,
			0x6d, 0x5f, 0x23, 0x9f, 0xe1, 0x4f, 0xba, 0xad,
			0xeb, 0x44, 0x5f, 0xc6, 0x6a, 0x01, 0xb0, 0x77,
			0x9d, 0x98, 0x22, 0x39, 0x61, 0x11, 0x1e, 0x21,
			0x76, 0x62, 0x82, 0xf7, 0x3d, 0xd9, 0x6b, 0x6f }
	};
	struct lc_x448_ss act;
	unsigned int i;
	int ret = 0;

	for (i = 0; i < loops; i++)
		CKINT_LOG(lc_x448_ss(&act, &pk, &sk),
			  "X448 scalar multiplication failed\n");
	lc_compare(act.ss, ss.ss, sizeof(ss.ss),
		   "X448 scalar multiplication\n");

out:
	return !!ret;
}

LC_TEST_FUNC(int, main, int argc, char *argv[])
{
	unsigned int loops = 1;
	unsigned int cpu_feature_enable = 0;
	int argc_p = 1;
	int ret = 0;

	while (argc_p < argc) {
		/* p */
		if (*argv[argc_p] == 0x70)
			loops = 100000;
		/* c */
		if (*argv[argc_p] == 0x63) {
			lc_cpu_feature_disable();
			cpu_feature_enable = 1;
		}

		argc_p++;
	}

	ret |= x448_ss_tester(loops);

#ifdef LINUX_KERNEL
	lc_cpu_feature_disable();
	cpu_feature_enable = 1;
	ret |= x448_ss_tester(loops);
#endif

	if (cpu_feature_enable)
		lc_cpu_feature_enable();

	ret = test_validate_status(
		ret, lc_x448_alg_status(lc_alg_operation_x448_ss), 0);
	ret += test_print_status();

	return ret;
}
