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

#ifndef __CRYPTO_SHA3_H__
#define __CRYPTO_SHA3_H__

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

#define SHA3_224_DIGEST_SIZE	(224 / 8)
#define SHA3_224_BLOCK_SIZE	(200 - 2 * SHA3_224_DIGEST_SIZE)
#define SHA3_224_EXPORT_SIZE	SHA3_STATE_SIZE + SHA3_224_BLOCK_SIZE + 1

#define SHA3_256_DIGEST_SIZE	(256 / 8)
#define SHA3_256_BLOCK_SIZE	(200 - 2 * SHA3_256_DIGEST_SIZE)
#define SHA3_256_EXPORT_SIZE	SHA3_STATE_SIZE + SHA3_256_BLOCK_SIZE + 1

#define SHA3_384_DIGEST_SIZE	(384 / 8)
#define SHA3_384_BLOCK_SIZE	(200 - 2 * SHA3_384_DIGEST_SIZE)
#define SHA3_384_EXPORT_SIZE	SHA3_STATE_SIZE + SHA3_384_BLOCK_SIZE + 1

#define SHA3_512_DIGEST_SIZE	(512 / 8)
#define SHA3_512_BLOCK_SIZE	(200 - 2 * SHA3_512_DIGEST_SIZE)
#define SHA3_512_EXPORT_SIZE	SHA3_STATE_SIZE + SHA3_512_BLOCK_SIZE + 1


#define SHAKE128_DEFAULT_SIZE	(128 / 8)
#define SHAKE128_BLOCK_SIZE	(200 - 2 * SHAKE128_DEFAULT_SIZE)
#define SHAKE256_DEFAULT_SIZE	(256 / 8)
#define SHAKE256_BLOCK_SIZE	(200 - 2 * SHAKE256_DEFAULT_SIZE)

#define SHA3_STATE_SIZE		200


struct sha3_state {
	union {
		__le64 words[SHA3_STATE_SIZE / 8];
		u8 bytes[SHA3_STATE_SIZE];

		u64 native_words[SHA3_STATE_SIZE / 8]; 
	};
};


struct __sha3_ctx {
	struct sha3_state state;
	u8 digest_size;		
	u8 block_size;		
	u8 absorb_offset;	
	u8 squeeze_offset;	
};

void __sha3_update(struct __sha3_ctx *ctx, const u8 *in, size_t in_len);


struct sha3_ctx {
	struct __sha3_ctx ctx;
};


static inline void sha3_zeroize_ctx(struct sha3_ctx *ctx)
{
	memzero_explicit(ctx, sizeof(*ctx));
}


struct shake_ctx {
	struct __sha3_ctx ctx;
};


static inline void shake_zeroize_ctx(struct shake_ctx *ctx)
{
	memzero_explicit(ctx, sizeof(*ctx));
}


static inline void sha3_224_init(struct sha3_ctx *ctx)
{
	*ctx = (struct sha3_ctx){
		.ctx.digest_size = SHA3_224_DIGEST_SIZE,
		.ctx.block_size = SHA3_224_BLOCK_SIZE,
	};
}


static inline void sha3_256_init(struct sha3_ctx *ctx)
{
	*ctx = (struct sha3_ctx){
		.ctx.digest_size = SHA3_256_DIGEST_SIZE,
		.ctx.block_size = SHA3_256_BLOCK_SIZE,
	};
}


static inline void sha3_384_init(struct sha3_ctx *ctx)
{
	*ctx = (struct sha3_ctx){
		.ctx.digest_size = SHA3_384_DIGEST_SIZE,
		.ctx.block_size = SHA3_384_BLOCK_SIZE,
	};
}


static inline void sha3_512_init(struct sha3_ctx *ctx)
{
	*ctx = (struct sha3_ctx){
		.ctx.digest_size = SHA3_512_DIGEST_SIZE,
		.ctx.block_size = SHA3_512_BLOCK_SIZE,
	};
}


static inline void sha3_update(struct sha3_ctx *ctx,
			       const u8 *in, size_t in_len)
{
	__sha3_update(&ctx->ctx, in, in_len);
}


void sha3_final(struct sha3_ctx *ctx, u8 *out);


static inline void shake128_init(struct shake_ctx *ctx)
{
	*ctx = (struct shake_ctx){
		.ctx.block_size = SHAKE128_BLOCK_SIZE,
	};
}


static inline void shake256_init(struct shake_ctx *ctx)
{
	*ctx = (struct shake_ctx){
		.ctx.block_size = SHAKE256_BLOCK_SIZE,
	};
}


static inline void shake_update(struct shake_ctx *ctx,
				const u8 *in, size_t in_len)
{
	__sha3_update(&ctx->ctx, in, in_len);
}


void shake_squeeze(struct shake_ctx *ctx, u8 *out, size_t out_len);


void sha3_224(const u8 *in, size_t in_len, u8 out[SHA3_224_DIGEST_SIZE]);


void sha3_256(const u8 *in, size_t in_len, u8 out[SHA3_256_DIGEST_SIZE]);


void sha3_384(const u8 *in, size_t in_len, u8 out[SHA3_384_DIGEST_SIZE]);


void sha3_512(const u8 *in, size_t in_len, u8 out[SHA3_512_DIGEST_SIZE]);


void shake128(const u8 *in, size_t in_len, u8 *out, size_t out_len);


void shake256(const u8 *in, size_t in_len, u8 *out, size_t out_len);

#endif 
