1 | /* mpi-add.c - MPI functions |
2 | * Copyright (C) 1994, 1996, 1998, 2001, 2002, |
3 | * 2003 Free Software Foundation, Inc. |
4 | * |
5 | * This file is part of Libgcrypt. |
6 | * |
7 | * Note: This code is heavily based on the GNU MP Library. |
8 | * Actually it's the same code with only minor changes in the |
9 | * way the data is stored; this is to support the abstraction |
10 | * of an optional secure memory allocation which may be used |
11 | * to avoid revealing of sensitive data due to paging etc. |
12 | */ |
13 | |
14 | #include "mpi-internal.h" |
15 | |
16 | /**************** |
17 | * Add the unsigned integer V to the mpi-integer U and store the |
18 | * result in W. U and V may be the same. |
19 | */ |
20 | void mpi_add_ui(MPI w, MPI u, unsigned long v) |
21 | { |
22 | mpi_ptr_t wp, up; |
23 | mpi_size_t usize, wsize; |
24 | int usign, wsign; |
25 | |
26 | usize = u->nlimbs; |
27 | usign = u->sign; |
28 | wsign = 0; |
29 | |
30 | /* If not space for W (and possible carry), increase space. */ |
31 | wsize = usize + 1; |
32 | if (w->alloced < wsize) |
33 | mpi_resize(a: w, nlimbs: wsize); |
34 | |
35 | /* These must be after realloc (U may be the same as W). */ |
36 | up = u->d; |
37 | wp = w->d; |
38 | |
39 | if (!usize) { /* simple */ |
40 | wp[0] = v; |
41 | wsize = v ? 1:0; |
42 | } else if (!usign) { /* mpi is not negative */ |
43 | mpi_limb_t cy; |
44 | cy = mpihelp_add_1(res_ptr: wp, s1_ptr: up, s1_size: usize, s2_limb: v); |
45 | wp[usize] = cy; |
46 | wsize = usize + cy; |
47 | } else { |
48 | /* The signs are different. Need exact comparison to determine |
49 | * which operand to subtract from which. |
50 | */ |
51 | if (usize == 1 && up[0] < v) { |
52 | wp[0] = v - up[0]; |
53 | wsize = 1; |
54 | } else { |
55 | mpihelp_sub_1(res_ptr: wp, s1_ptr: up, s1_size: usize, s2_limb: v); |
56 | /* Size can decrease with at most one limb. */ |
57 | wsize = usize - (wp[usize-1] == 0); |
58 | wsign = 1; |
59 | } |
60 | } |
61 | |
62 | w->nlimbs = wsize; |
63 | w->sign = wsign; |
64 | } |
65 | |
66 | |
67 | void mpi_add(MPI w, MPI u, MPI v) |
68 | { |
69 | mpi_ptr_t wp, up, vp; |
70 | mpi_size_t usize, vsize, wsize; |
71 | int usign, vsign, wsign; |
72 | |
73 | if (u->nlimbs < v->nlimbs) { /* Swap U and V. */ |
74 | usize = v->nlimbs; |
75 | usign = v->sign; |
76 | vsize = u->nlimbs; |
77 | vsign = u->sign; |
78 | wsize = usize + 1; |
79 | RESIZE_IF_NEEDED(w, wsize); |
80 | /* These must be after realloc (u or v may be the same as w). */ |
81 | up = v->d; |
82 | vp = u->d; |
83 | } else { |
84 | usize = u->nlimbs; |
85 | usign = u->sign; |
86 | vsize = v->nlimbs; |
87 | vsign = v->sign; |
88 | wsize = usize + 1; |
89 | RESIZE_IF_NEEDED(w, wsize); |
90 | /* These must be after realloc (u or v may be the same as w). */ |
91 | up = u->d; |
92 | vp = v->d; |
93 | } |
94 | wp = w->d; |
95 | wsign = 0; |
96 | |
97 | if (!vsize) { /* simple */ |
98 | MPN_COPY(wp, up, usize); |
99 | wsize = usize; |
100 | wsign = usign; |
101 | } else if (usign != vsign) { /* different sign */ |
102 | /* This test is right since USIZE >= VSIZE */ |
103 | if (usize != vsize) { |
104 | mpihelp_sub(res_ptr: wp, s1_ptr: up, s1_size: usize, s2_ptr: vp, s2_size: vsize); |
105 | wsize = usize; |
106 | MPN_NORMALIZE(wp, wsize); |
107 | wsign = usign; |
108 | } else if (mpihelp_cmp(op1_ptr: up, op2_ptr: vp, size: usize) < 0) { |
109 | mpihelp_sub_n(res_ptr: wp, s1_ptr: vp, s2_ptr: up, size: usize); |
110 | wsize = usize; |
111 | MPN_NORMALIZE(wp, wsize); |
112 | if (!usign) |
113 | wsign = 1; |
114 | } else { |
115 | mpihelp_sub_n(res_ptr: wp, s1_ptr: up, s2_ptr: vp, size: usize); |
116 | wsize = usize; |
117 | MPN_NORMALIZE(wp, wsize); |
118 | if (usign) |
119 | wsign = 1; |
120 | } |
121 | } else { /* U and V have same sign. Add them. */ |
122 | mpi_limb_t cy = mpihelp_add(res_ptr: wp, s1_ptr: up, s1_size: usize, s2_ptr: vp, s2_size: vsize); |
123 | wp[usize] = cy; |
124 | wsize = usize + cy; |
125 | if (usign) |
126 | wsign = 1; |
127 | } |
128 | |
129 | w->nlimbs = wsize; |
130 | w->sign = wsign; |
131 | } |
132 | EXPORT_SYMBOL_GPL(mpi_add); |
133 | |
134 | void mpi_sub(MPI w, MPI u, MPI v) |
135 | { |
136 | MPI vv = mpi_copy(a: v); |
137 | vv->sign = !vv->sign; |
138 | mpi_add(w, u, vv); |
139 | mpi_free(a: vv); |
140 | } |
141 | EXPORT_SYMBOL_GPL(mpi_sub); |
142 | |
143 | void mpi_addm(MPI w, MPI u, MPI v, MPI m) |
144 | { |
145 | mpi_add(w, u, v); |
146 | mpi_mod(rem: w, dividend: w, divisor: m); |
147 | } |
148 | EXPORT_SYMBOL_GPL(mpi_addm); |
149 | |
150 | void mpi_subm(MPI w, MPI u, MPI v, MPI m) |
151 | { |
152 | mpi_sub(w, u, v); |
153 | mpi_mod(rem: w, dividend: w, divisor: m); |
154 | } |
155 | EXPORT_SYMBOL_GPL(mpi_subm); |
156 | |