// 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;
|
}
|