hc
2024-12-19 9370bb92b2d16684ee45cf24e879c93c509162da
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// 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;
}