/* SPDX-License-Identifier: GPL-2.0-or-later */


#ifndef _CRYPTO_POLYVAL_H
#define _CRYPTO_POLYVAL_H

#include <linux/string.h>
#include <linux/types.h>

#define POLYVAL_BLOCK_SIZE	16
#define POLYVAL_DIGEST_SIZE	16


struct polyval_elem {
	union {
		u8 bytes[POLYVAL_BLOCK_SIZE];
		struct {
			__le64 lo;
			__le64 hi;
		};
	};
};


struct polyval_key {
#ifdef CONFIG_CRYPTO_LIB_POLYVAL_ARCH
#ifdef CONFIG_ARM64
	
	struct polyval_elem h_powers[8];
#elif defined(CONFIG_X86)
	
	struct polyval_elem h_powers[8];
#else
#error "Unhandled arch"
#endif
#else 
	
	struct polyval_elem h;
#endif 
};


struct polyval_ctx {
	const struct polyval_key *key;
	struct polyval_elem acc;
	size_t partial;
};


#ifdef CONFIG_CRYPTO_LIB_POLYVAL_ARCH
void polyval_preparekey(struct polyval_key *key,
			const u8 raw_key[POLYVAL_BLOCK_SIZE]);

#else
static inline void polyval_preparekey(struct polyval_key *key,
				      const u8 raw_key[POLYVAL_BLOCK_SIZE])
{
	
	memcpy(key->h.bytes, raw_key, POLYVAL_BLOCK_SIZE);
}
#endif


static inline void polyval_init(struct polyval_ctx *ctx,
				const struct polyval_key *key)
{
	*ctx = (struct polyval_ctx){ .key = key };
}


static inline void
polyval_import_blkaligned(struct polyval_ctx *ctx,
			  const struct polyval_key *key,
			  const struct polyval_elem *acc)
{
	*ctx = (struct polyval_ctx){ .key = key, .acc = *acc };
}


static inline void polyval_export_blkaligned(const struct polyval_ctx *ctx,
					     struct polyval_elem *acc)
{
	*acc = ctx->acc;
}


void polyval_update(struct polyval_ctx *ctx, const u8 *data, size_t len);


void polyval_final(struct polyval_ctx *ctx, u8 out[POLYVAL_BLOCK_SIZE]);


static inline void polyval(const struct polyval_key *key,
			   const u8 *data, size_t len,
			   u8 out[POLYVAL_BLOCK_SIZE])
{
	struct polyval_ctx ctx;

	polyval_init(&ctx, key);
	polyval_update(&ctx, data, len);
	polyval_final(&ctx, out);
}

#endif 
