1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* mpi-sub-ui.c - Subtract an unsigned integer from an MPI. |
3 | * |
4 | * Copyright 1991, 1993, 1994, 1996, 1999-2002, 2004, 2012, 2013, 2015 |
5 | * Free Software Foundation, Inc. |
6 | * |
7 | * This file was based on the GNU MP Library source file: |
8 | * https://gmplib.org/repo/gmp-6.2/file/510b83519d1c/mpz/aors_ui.h |
9 | * |
10 | * The GNU MP Library is free software; you can redistribute it and/or modify |
11 | * it under the terms of either: |
12 | * |
13 | * * the GNU Lesser General Public License as published by the Free |
14 | * Software Foundation; either version 3 of the License, or (at your |
15 | * option) any later version. |
16 | * |
17 | * or |
18 | * |
19 | * * the GNU General Public License as published by the Free Software |
20 | * Foundation; either version 2 of the License, or (at your option) any |
21 | * later version. |
22 | * |
23 | * or both in parallel, as here. |
24 | * |
25 | * The GNU MP Library is distributed in the hope that it will be useful, but |
26 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
27 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
28 | * for more details. |
29 | * |
30 | * You should have received copies of the GNU General Public License and the |
31 | * GNU Lesser General Public License along with the GNU MP Library. If not, |
32 | * see https://www.gnu.org/licenses/. |
33 | */ |
34 | |
35 | #include "mpi-internal.h" |
36 | |
37 | int mpi_sub_ui(MPI w, MPI u, unsigned long vval) |
38 | { |
39 | if (u->nlimbs == 0) { |
40 | if (mpi_resize(a: w, nlimbs: 1) < 0) |
41 | return -ENOMEM; |
42 | w->d[0] = vval; |
43 | w->nlimbs = (vval != 0); |
44 | w->sign = (vval != 0); |
45 | return 0; |
46 | } |
47 | |
48 | /* If not space for W (and possible carry), increase space. */ |
49 | if (mpi_resize(a: w, nlimbs: u->nlimbs + 1)) |
50 | return -ENOMEM; |
51 | |
52 | if (u->sign) { |
53 | mpi_limb_t cy; |
54 | |
55 | cy = mpihelp_add_1(res_ptr: w->d, s1_ptr: u->d, s1_size: u->nlimbs, s2_limb: (mpi_limb_t) vval); |
56 | w->d[u->nlimbs] = cy; |
57 | w->nlimbs = u->nlimbs + cy; |
58 | w->sign = 1; |
59 | } else { |
60 | /* The signs are different. Need exact comparison to determine |
61 | * which operand to subtract from which. |
62 | */ |
63 | if (u->nlimbs == 1 && u->d[0] < vval) { |
64 | w->d[0] = vval - u->d[0]; |
65 | w->nlimbs = 1; |
66 | w->sign = 1; |
67 | } else { |
68 | mpihelp_sub_1(res_ptr: w->d, s1_ptr: u->d, s1_size: u->nlimbs, s2_limb: (mpi_limb_t) vval); |
69 | /* Size can decrease with at most one limb. */ |
70 | w->nlimbs = (u->nlimbs - (w->d[u->nlimbs - 1] == 0)); |
71 | w->sign = 0; |
72 | } |
73 | } |
74 | |
75 | mpi_normalize(a: w); |
76 | return 0; |
77 | } |
78 | EXPORT_SYMBOL_GPL(mpi_sub_ui); |
79 | |