xref: /OK3568_Linux_fs/kernel/drivers/crypto/rockchip/rk_crypto_bignum.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * bignum support for Rockchip crypto
4  *
5  * Copyright (c) 2020 Rockchip Electronics Co., Ltd.
6  *
7  * Author: Lin Jinhan <troy.lin@rock-chips.com>
8  *
9  */
10 #include <linux/slab.h>
11 
12 #include "rk_crypto_bignum.h"
13 
14 #define DEFAULT_ENDIAN		RK_BG_LITTILE_ENDIAN
15 
16 #define BYTES2WORDS(bytes)	(round_up((bytes), sizeof(u32)) / sizeof(u32))
17 #define WORDS2BYTES(words)	((words) * sizeof(u32))
18 #define RK_WORD_SIZE		32
19 
rk_reverse_memcpy(void * dst,const void * src,u32 size)20 static void rk_reverse_memcpy(void *dst, const void *src, u32 size)
21 {
22 	char *_dst = (char *)dst, *_src = (char *)src;
23 	u32 i;
24 
25 	if (!dst || !src || !size)
26 		return;
27 
28 	for (i = 0; i < size; ++i)
29 		_dst[size - i - 1] = _src[i];
30 }
31 
rk_bn_alloc(u32 max_size)32 struct rk_bignum *rk_bn_alloc(u32 max_size)
33 {
34 	struct rk_bignum *bn;
35 
36 	bn = kzalloc(sizeof(*bn), GFP_KERNEL);
37 	if (!bn)
38 		return NULL;
39 
40 	bn->data = kzalloc(round_up(max_size, sizeof(u32)), GFP_KERNEL);
41 	if (!bn->data) {
42 		kfree(bn);
43 		return NULL;
44 	}
45 
46 	bn->n_words = BYTES2WORDS(max_size);
47 
48 	return bn;
49 }
50 
rk_bn_free(struct rk_bignum * bn)51 void rk_bn_free(struct rk_bignum *bn)
52 {
53 	if (!bn)
54 		return;
55 
56 	if (bn->data) {
57 		memset(bn->data, 0x00, WORDS2BYTES(bn->n_words));
58 		kfree(bn->data);
59 	}
60 
61 	kfree(bn);
62 }
63 
rk_bn_set_data(struct rk_bignum * bn,const u8 * data,u32 size,enum bignum_endian endian)64 int rk_bn_set_data(struct rk_bignum *bn, const u8 *data, u32 size, enum bignum_endian endian)
65 {
66 	if (!bn || !data)
67 		return -EINVAL;
68 
69 	if (BYTES2WORDS(size) > bn->n_words)
70 		return -EINVAL;
71 
72 	if (endian == DEFAULT_ENDIAN)
73 		memcpy(bn->data, data, size);
74 	else
75 		rk_reverse_memcpy(bn->data, data, size);
76 
77 	return 0;
78 }
79 
rk_bn_get_data(const struct rk_bignum * bn,u8 * data,u32 size,enum bignum_endian endian)80 int rk_bn_get_data(const struct rk_bignum *bn, u8 *data, u32 size, enum bignum_endian endian)
81 {
82 	if (!bn || !data)
83 		return -EINVAL;
84 
85 	if (size < WORDS2BYTES(bn->n_words))
86 		return -EINVAL;
87 
88 	memset(data, 0x00, size);
89 
90 	if (endian == DEFAULT_ENDIAN)
91 		memcpy(data + size - WORDS2BYTES(bn->n_words), bn->data, bn->n_words);
92 	else
93 		rk_reverse_memcpy(data + size - WORDS2BYTES(bn->n_words),
94 				  bn->data, WORDS2BYTES(bn->n_words));
95 
96 	return 0;
97 }
98 
rk_bn_get_size(const struct rk_bignum * bn)99 u32 rk_bn_get_size(const struct rk_bignum *bn)
100 {
101 	if (!bn)
102 		return 0;
103 
104 	return WORDS2BYTES(bn->n_words);
105 }
106 
107 /*
108  * @brief  Returns the index of the highest 1 in |bn|.
109  * @param  bn: the point of input data bignum.
110  * @return The index starts at 0 for the least significant bit.
111  *         If src == zero, it will return -1
112  */
rk_bn_highest_bit(const struct rk_bignum * bn)113 int rk_bn_highest_bit(const struct rk_bignum *bn)
114 {
115 	u32 w;
116 	u32 b;
117 
118 	if (!bn || !bn->data || !bn->n_words)
119 		return -1;
120 
121 	w = bn->data[bn->n_words - 1];
122 
123 	for (b = 0; b < RK_WORD_SIZE; b++) {
124 		w >>= 1;
125 		if (w == 0)
126 			break;
127 	}
128 
129 	return (int)(bn->n_words - 1) * RK_WORD_SIZE + b;
130 }
131