• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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