Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
// SPDX-License-Identifier: GPL-2.0
/*
 * bignum support for Rockchip crypto
 *
 * Copyright (c) 2020 Rockchip Electronics Co., Ltd.
 *
 * Author: Lin Jinhan <troy.lin@rock-chips.com>
 *
 */
#include <linux/slab.h>

#include "rk_crypto_bignum.h"

#define DEFAULT_ENDIAN		RK_BG_LITTILE_ENDIAN

#define BYTES2WORDS(bytes)	(round_up((bytes), sizeof(u32)) / sizeof(u32))
#define WORDS2BYTES(words)	((words) * sizeof(u32))
#define RK_WORD_SIZE		32

static void rk_reverse_memcpy(void *dst, const void *src, u32 size)
{
	char *_dst = (char *)dst, *_src = (char *)src;
	u32 i;

	if (!dst || !src || !size)
		return;

	for (i = 0; i < size; ++i)
		_dst[size - i - 1] = _src[i];
}

struct rk_bignum *rk_bn_alloc(u32 max_size)
{
	struct rk_bignum *bn;

	bn = kzalloc(sizeof(*bn), GFP_KERNEL);
	if (!bn)
		return NULL;

	bn->data = kzalloc(round_up(max_size, sizeof(u32)), GFP_KERNEL);
	if (!bn->data) {
		kfree(bn);
		return NULL;
	}

	bn->n_words = BYTES2WORDS(max_size);

	return bn;
}

void rk_bn_free(struct rk_bignum *bn)
{
	if (!bn)
		return;

	if (bn->data) {
		memset(bn->data, 0x00, WORDS2BYTES(bn->n_words));
		kfree(bn->data);
	}

	kfree(bn);
}

int rk_bn_set_data(struct rk_bignum *bn, const u8 *data, u32 size, enum bignum_endian endian)
{
	if (!bn || !data)
		return -EINVAL;

	if (BYTES2WORDS(size) > bn->n_words)
		return -EINVAL;

	if (endian == DEFAULT_ENDIAN)
		memcpy(bn->data, data, size);
	else
		rk_reverse_memcpy(bn->data, data, size);

	return 0;
}

int rk_bn_get_data(const struct rk_bignum *bn, u8 *data, u32 size, enum bignum_endian endian)
{
	if (!bn || !data)
		return -EINVAL;

	if (size < WORDS2BYTES(bn->n_words))
		return -EINVAL;

	memset(data, 0x00, size);

	if (endian == DEFAULT_ENDIAN)
		memcpy(data + size - WORDS2BYTES(bn->n_words), bn->data, bn->n_words);
	else
		rk_reverse_memcpy(data + size - WORDS2BYTES(bn->n_words),
				  bn->data, WORDS2BYTES(bn->n_words));

	return 0;
}

u32 rk_bn_get_size(const struct rk_bignum *bn)
{
	if (!bn)
		return 0;

	return WORDS2BYTES(bn->n_words);
}

/*
 * @brief  Returns the index of the highest 1 in |bn|.
 * @param  bn: the point of input data bignum.
 * @return The index starts at 0 for the least significant bit.
 *         If src == zero, it will return -1
 */
int rk_bn_highest_bit(const struct rk_bignum *bn)
{
	u32 w;
	u32 b;

	if (!bn || !bn->data || !bn->n_words)
		return -1;

	w = bn->data[bn->n_words - 1];

	for (b = 0; b < RK_WORD_SIZE; b++) {
		w >>= 1;
		if (w == 0)
			break;
	}

	return (int)(bn->n_words - 1) * RK_WORD_SIZE + b;
}