1 /*
2 * This file is part of the openHiTLS project.
3 *
4 * openHiTLS is licensed under the Mulan PSL v2.
5 * You can use this software according to the terms and conditions of the Mulan PSL v2.
6 * You may obtain a copy of Mulan PSL v2 at:
7 *
8 * http://license.coscl.org.cn/MulanPSL2
9 *
10 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
11 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
12 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
13 * See the Mulan PSL v2 for more details.
14 */
15
16 #include "hitls_build.h"
17 #ifdef HITLS_CRYPTO_BN
18
19 #include <stdint.h>
20 #include "securec.h"
21 #include "bn_bincal.h"
22
23 /* r = a + w, the length of r and a array is 'size'. The return value is the carry. */
BinInc(BN_UINT * r,const BN_UINT * a,uint32_t size,BN_UINT w)24 BN_UINT BinInc(BN_UINT *r, const BN_UINT *a, uint32_t size, BN_UINT w)
25 {
26 uint32_t i;
27 BN_UINT carry = w;
28 for (i = 0; i < size && carry != 0; i++) {
29 ADD_AB(carry, r[i], a[i], carry);
30 }
31 if (r != a) {
32 for (; i < size; i++) {
33 r[i] = a[i];
34 }
35 }
36
37 return carry;
38 }
39 /* r = a - w, the length of r and a array is 'size'. The return value is the borrow-digit. */
BinDec(BN_UINT * r,const BN_UINT * a,uint32_t n,BN_UINT w)40 BN_UINT BinDec(BN_UINT *r, const BN_UINT *a, uint32_t n, BN_UINT w)
41 {
42 uint32_t i;
43 BN_UINT borrow = w;
44 for (i = 0; (i < n) && (borrow > 0); i++) {
45 SUB_AB(borrow, r[i], a[i], borrow);
46 }
47 if (r != a) {
48 for (; i < n; i++) {
49 r[i] = a[i];
50 }
51 }
52 return borrow;
53 }
54 /* r = a >> bits, the return value is the valid length of r after the shift.
55 * The array length of a is n. The length of the r array must meet the requirements of the accepted calculation result,
56 * which is guaranteed by the input parameter.
57 */
BinRshift(BN_UINT * r,const BN_UINT * a,uint32_t n,uint32_t bits)58 uint32_t BinRshift(BN_UINT *r, const BN_UINT *a, uint32_t n, uint32_t bits)
59 {
60 uint32_t nw = bits / BN_UINT_BITS; /* shift words */
61 uint32_t nb = bits % BN_UINT_BITS; /* shift bits */
62 /**
63 * unsigned shift operand cannot be greater than or equal to the data bit width
64 * Otherwise, undefined behavior is triggered.
65 */
66 uint32_t na = (BN_UINT_BITS - nb) % BN_UINT_BITS;
67 uint32_t rsize = n - nw;
68 uint32_t i;
69 BN_UINT hi;
70 BN_UINT lo = a[nw];
71 /* When nb == 0, discard the value of (hi << na) with the all-zero mask. */
72 BN_UINT mask = ~BN_IsZeroUintConsttime(nb);
73 /* Assigns values from the lower bits. */
74 for (i = nw; i < n - 1; i++) {
75 hi = a[i + 1];
76 r[i - nw] = (lo >> nb) | ((hi << na) & mask);
77 lo = hi;
78 }
79 lo >>= nb;
80 if (lo != 0) {
81 r[rsize - 1] = lo;
82 } else {
83 rsize--;
84 }
85 return rsize;
86 }
87 /* r = a << bits. The return value is the valid length of r after the shift.
88 * The array length of a is n. The length of the r array must meet the requirements of the accepted calculation result,
89 * which is guaranteed by the input parameter.
90 */
BinLshift(BN_UINT * r,const BN_UINT * a,uint32_t n,uint32_t bits)91 uint32_t BinLshift(BN_UINT *r, const BN_UINT *a, uint32_t n, uint32_t bits)
92 {
93 uint32_t nw = bits / BN_UINT_BITS; /* shift words */
94 uint32_t nb = bits % BN_UINT_BITS; /* shift bits */
95 /**
96 * unsigned shift operand cannot be greater than or equal to the data bit width
97 * Otherwise, undefined behavior is triggered.
98 */
99 uint32_t na = (BN_UINT_BITS - nb) % BN_UINT_BITS;
100 uint32_t rsize = n + nw;
101 uint32_t i;
102 BN_UINT hi = a[n - 1];
103 BN_UINT lo;
104 /* When nb == 0, discard the value of (hi << na) with the all-zero mask. */
105 BN_UINT mask = ~BN_IsZeroUintConsttime(nb);
106 lo = (hi >> na) & mask;
107 /* Assign a value to the most significant bit. */
108 if (lo != 0) {
109 r[rsize++] = lo;
110 }
111 /* Assign a value from the most significant bits. */
112 for (i = n - 1; i > 0; i--) {
113 lo = a[i - 1];
114 r[i + nw] = (hi << nb) | ((lo >> na) & mask);
115 hi = lo;
116 }
117 r[nw] = a[0] << nb;
118 /* Clear the lower bits to 0. */
119 if (nw != 0) {
120 (void)memset_s(r, nw * sizeof(BN_UINT), 0, nw * sizeof(BN_UINT));
121 }
122
123 return rsize;
124 }
125 /* r = a * b + r. The return value is a carry. */
BinMulAcc(BN_UINT * r,const BN_UINT * a,uint32_t aSize,BN_UINT b)126 BN_UINT BinMulAcc(BN_UINT *r, const BN_UINT *a, uint32_t aSize, BN_UINT b)
127 {
128 BN_UINT c = 0;
129 BN_UINT *rr = r;
130 const BN_UINT *aa = a;
131 uint32_t size = aSize;
132 #ifndef HITLS_CRYPTO_BN_SMALL_MEM
133 while (size >= 4) { /* a group of 4 */
134 MULADD_ABC(c, rr[0], aa[0], b); /* offset 0 */
135 MULADD_ABC(c, rr[1], aa[1], b); /* offset 1 */
136 MULADD_ABC(c, rr[2], aa[2], b); /* offset 2 */
137 MULADD_ABC(c, rr[3], aa[3], b); /* offset 3 */
138 aa += 4; /* a group of 4 */
139 rr += 4; /* a group of 4 */
140 size -= 4; /* a group of 4 */
141 }
142 #endif
143 while (size > 0) {
144 MULADD_ABC(c, rr[0], aa[0], b);
145 aa++;
146 rr++;
147 size--;
148 }
149 return c;
150 }
151 /* r = a * b rRoom >= aSize + bSize. The length is guaranteed by the input parameter. r != a, r != b.
152 * The return value is the valid length of the result. */
BinMul(BN_UINT * r,uint32_t rRoom,const BN_UINT * a,uint32_t aSize,const BN_UINT * b,uint32_t bSize)153 uint32_t BinMul(BN_UINT *r, uint32_t rRoom, const BN_UINT *a, uint32_t aSize, const BN_UINT *b, uint32_t bSize)
154 {
155 BN_UINT carry = 0;
156 (void)memset_s(r, rRoom * sizeof(BN_UINT), 0, rRoom * sizeof(BN_UINT));
157 /* Result combination of cyclic calculation data units. */
158 for (uint32_t i = 0; i < bSize; i++) {
159 carry = 0;
160 uint32_t j = 0;
161 BN_UINT t = b[i];
162 for (; j < aSize; j++) {
163 MULADC_AB(r[i + j], a[j], t, carry);
164 }
165 if (carry != 0) {
166 r[i + j] = carry;
167 }
168 }
169 return aSize + bSize - (carry == 0);
170 }
171
172 /* r = a * a rRoom >= aSize * 2. The length is guaranteed by the input parameter. r != a.
173 * The return value is the valid length of the result. */
BinSqr(BN_UINT * r,uint32_t rRoom,const BN_UINT * a,uint32_t aSize)174 uint32_t BinSqr(BN_UINT *r, uint32_t rRoom, const BN_UINT *a, uint32_t aSize)
175 {
176 uint32_t i;
177 BN_UINT carry;
178
179 (void)memset_s(r, rRoom * sizeof(BN_UINT), 0, rRoom * sizeof(BN_UINT));
180 /* Calculate unequal data units, similar to trapezoid. */
181 for (i = 0; i < aSize - 1; i++) {
182 BN_UINT t = a[i];
183 uint32_t j;
184 for (j = i + 1, carry = 0; j < aSize; j++) {
185 MULADC_AB(r[i + j], a[j], t, carry);
186 }
187 r[i + j] = carry;
188 }
189 /* In the square, the multiplier unit is symmetrical. r = r * 2 */
190 BinLshift(r, r, 2 * aSize - 1, 1);
191 /* Calculate the direct squared data unit and add it to the result. */
192 for (i = 0, carry = 0; i < aSize; i++) {
193 BN_UINT rh, rl;
194 SQR_A(rh, rl, a[i]);
195 ADD_ABC(carry, r[i << 1], r[i << 1], rl, carry);
196 ADD_ABC(carry, r[(i << 1) + 1], r[(i << 1) + 1], rh, carry);
197 }
198 return aSize + aSize - (r[(aSize << 1) - 1] == 0);
199 }
200
201 /* refresh the size */
BinFixSize(const BN_UINT * data,uint32_t size)202 uint32_t BinFixSize(const BN_UINT *data, uint32_t size)
203 {
204 uint32_t fix = size;
205 uint32_t i = size;
206 for (; i > 0; i--) {
207 if (data[i - 1] != 0) {
208 return fix;
209 };
210 fix--;
211 }
212 return fix;
213 }
214
215 /* compare BN array. Maybe aSize != bSize;
216 * return 0, if a == b
217 * return 1, if a > b
218 * return -1, if a < b
219 */
BinCmp(const BN_UINT * a,uint32_t aSize,const BN_UINT * b,uint32_t bSize)220 int32_t BinCmp(const BN_UINT *a, uint32_t aSize, const BN_UINT *b, uint32_t bSize)
221 {
222 if (aSize == bSize) {
223 uint32_t len = aSize;
224
225 while (len > 0) {
226 len--;
227 if (a[len] != b[len]) {
228 return a[len] > b[len] ? 1 : -1;
229 }
230 }
231 return 0;
232 }
233 return aSize > bSize ? 1 : -1;
234 }
235
236 /* obtain bits */
BinBits(const BN_UINT * data,uint32_t size)237 uint32_t BinBits(const BN_UINT *data, uint32_t size)
238 {
239 if (size == 0) {
240 return 0;
241 }
242 return (size * BN_UINT_BITS - GetZeroBitsUint(data[size - 1]));
243 }
244
245 /**
246 * Try to reduce the borrowing cost, guarantee h|l >= q * yl. If q is too large, reduce q.
247 * Each time q decreases by 1, h increases by yh. y was previously offset, and the most significant bit of yh is 1.
248 * Therefore (q * yl << BN_UINT_BITS) < (yh * 2), number of borrowing times ≤ 2.
249 */
TryDiv(BN_UINT q,BN_UINT h,BN_UINT l,BN_UINT yh,BN_UINT yl)250 static BN_UINT TryDiv(BN_UINT q, BN_UINT h, BN_UINT l, BN_UINT yh, BN_UINT yl)
251 {
252 BN_UINT rh, rl;
253 MUL_AB(rh, rl, q, yl);
254 /* Compare h|l >= rh|rl. Otherwise, reduce q. */
255 if (rh < h || (rh == h && rl <= l)) {
256 return q;
257 }
258 BN_UINT nq = q - 1;
259 BN_UINT nh = h + yh;
260 /* If carry occurs, no judgment is required. */
261 if (nh < yh) {
262 return nq;
263 }
264 /* rh|rl - yl */
265 if (rl < yl) {
266 rh--;
267 }
268 rl -= yl;
269
270 /* Compare r|l >= rh|rl. Otherwise, reduce q. */
271 if (rh < nh || (rh == nh && rl <= l)) {
272 return nq;
273 }
274 nq--;
275 return nq;
276 }
277 /* Divide core operation */
BinDivCore(BN_UINT * q,uint32_t * qSize,BN_UINT * x,uint32_t xSize,const BN_UINT * y,uint32_t ySize)278 static void BinDivCore(BN_UINT *q, uint32_t *qSize, BN_UINT *x, uint32_t xSize, const BN_UINT *y, uint32_t ySize)
279 {
280 BN_UINT yy = y[ySize - 1]; /* Obtain the most significant bit of the data. */
281 uint32_t i;
282 for (i = xSize; i >= ySize; i--) {
283 BN_UINT qq;
284 if (x[i] == yy) {
285 qq = (BN_UINT)-1;
286 } else {
287 BN_UINT rr;
288 DIV_ND(qq, rr, x[i], x[i - 1], yy);
289 if (ySize > 1) { /* If ySize is 1, do not need to try divide. */
290 /* Obtain the least significant bit data, that is, make subscript - 2. */
291 qq = TryDiv(qq, rr, x[i - 2], yy, y[ySize - 2]);
292 }
293 }
294 if (qq > 0) {
295 /* After the TryDiv is complete, perform the double subtraction. */
296 BN_UINT extend = BinSubMul(&x[i - ySize], y, ySize, qq);
297 extend = (x[i] -= extend);
298 if (extend > 0) {
299 /* reverse, borrowing required */
300 extend = BinAdd(&x[i - ySize], &x[i - ySize], y, ySize);
301 x[i] += extend;
302 qq--;
303 }
304 if (q != NULL && qq != 0) {
305 /* update quotient */
306 q[i - ySize] = qq;
307 *qSize = (*qSize) > (i - ySize + 1) ? (*qSize) : (i - ySize + 1);
308 }
309 }
310 }
311 }
312
313 // The L-shift of the divisor does not exceed the highest BN_UINT.
BnLshiftSimple(BN_UINT * a,uint32_t aSize,uint32_t bits)314 static void BnLshiftSimple(BN_UINT *a, uint32_t aSize, uint32_t bits)
315 {
316 uint32_t rem = BN_UNIT_BITS - bits;
317 BN_UINT nextBits = 0;
318 for (uint32_t i = 0; i < aSize; i++) {
319 BN_UINT n = a[i];
320 a[i] = (n << bits) | nextBits;
321 nextBits = (n >> rem);
322 }
323 return;
324 }
325
326 /**
327 * x / y = q...x, the return value is the updated xSize.
328 * q and asize are both NULL or not NULL. Other input parameters must be valid.
329 * q, x and y cannot be the same pointer, the data in q must be 0.
330 * Ensure that x->room >= xSize + 2, and the extra two spaces need to be cleared. Extra space is used during try divide.
331 * this interface does not ensure that the y is consistent after running.
332 */
BinDiv(BN_UINT * q,uint32_t * qSize,BN_UINT * x,uint32_t xSize,BN_UINT * y,uint32_t ySize)333 uint32_t BinDiv(BN_UINT *q, uint32_t *qSize, BN_UINT *x, uint32_t xSize, BN_UINT *y, uint32_t ySize)
334 {
335 uint32_t shifts = GetZeroBitsUint(y[ySize - 1]);
336 uint32_t xNewSize = xSize;
337 /* Left shift until the maximum displacement of the divisor is full. */
338 if (shifts != 0) {
339 BnLshiftSimple(y, ySize, shifts);
340 xNewSize = BinLshift(x, x, xSize, shifts);
341 }
342 BinDivCore(q, qSize, x, xSize, y, ySize);
343 /* shift compensation */
344 if (shifts != 0) {
345 xNewSize = BinRshift(x, x, xNewSize, shifts);
346 }
347 return BinFixSize(x, xNewSize);
348 }
349 #endif /* HITLS_CRYPTO_BN */
350