Line data Source code
1 : /* mpi-add.c - MPI functions
2 : * Copyright (C) 1994, 1996, 1998, 2001, 2002, 2003 Free Software Foundation, Inc.
3 : *
4 : * This file is part of Libgcrypt.
5 : *
6 : * Libgcrypt is free software; you can redistribute it and/or modify
7 : * it under the terms of the GNU Lesser General Public License as
8 : * published by the Free Software Foundation; either version 2.1 of
9 : * the License, or (at your option) any later version.
10 : *
11 : * Libgcrypt is distributed in the hope that it will be useful,
12 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : * GNU Lesser General Public License for more details.
15 : *
16 : * You should have received a copy of the GNU Lesser General Public
17 : * License along with this program; if not, write to the Free Software
18 : * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19 : *
20 : * Note: This code is heavily based on the GNU MP Library.
21 : * Actually it's the same code with only minor changes in the
22 : * way the data is stored; this is to support the abstraction
23 : * of an optional secure memory allocation which may be used
24 : * to avoid revealing of sensitive data due to paging etc.
25 : */
26 :
27 : #include <config.h>
28 : #include <stdio.h>
29 : #include <stdlib.h>
30 :
31 : #include "mpi-internal.h"
32 :
33 :
34 : /****************
35 : * Add the unsigned integer V to the mpi-integer U and store the
36 : * result in W. U and V may be the same.
37 : */
38 : void
39 42376 : _gcry_mpi_add_ui (gcry_mpi_t w, gcry_mpi_t u, unsigned long v )
40 : {
41 : mpi_ptr_t wp, up;
42 : mpi_size_t usize, wsize;
43 : int usign, wsign;
44 :
45 42376 : usize = u->nlimbs;
46 42376 : usign = u->sign;
47 42376 : wsign = 0;
48 :
49 : /* If not space for W (and possible carry), increase space. */
50 42376 : wsize = usize + 1;
51 42376 : if( w->alloced < wsize )
52 710 : mpi_resize(w, wsize);
53 :
54 : /* These must be after realloc (U may be the same as W). */
55 42376 : up = u->d;
56 42376 : wp = w->d;
57 :
58 42376 : if( !usize ) { /* simple */
59 0 : wp[0] = v;
60 0 : wsize = v? 1:0;
61 : }
62 42376 : else if( !usign ) { /* mpi is not negative */
63 : mpi_limb_t cy;
64 42375 : cy = _gcry_mpih_add_1(wp, up, usize, v);
65 42375 : wp[usize] = cy;
66 42375 : wsize = usize + cy;
67 : }
68 : else { /* The signs are different. Need exact comparison to determine
69 : * which operand to subtract from which. */
70 1 : if( usize == 1 && up[0] < v ) {
71 0 : wp[0] = v - up[0];
72 0 : wsize = 1;
73 : }
74 : else {
75 1 : _gcry_mpih_sub_1(wp, up, usize, v);
76 : /* Size can decrease with at most one limb. */
77 1 : wsize = usize - (wp[usize-1]==0);
78 1 : wsign = 1;
79 : }
80 : }
81 :
82 42376 : w->nlimbs = wsize;
83 42376 : w->sign = wsign;
84 42376 : }
85 :
86 :
87 : void
88 36029218 : _gcry_mpi_add(gcry_mpi_t w, gcry_mpi_t u, gcry_mpi_t v)
89 : {
90 : mpi_ptr_t wp, up, vp;
91 : mpi_size_t usize, vsize, wsize;
92 : int usign, vsign, wsign;
93 :
94 36029218 : if( u->nlimbs < v->nlimbs ) { /* Swap U and V. */
95 1057952 : usize = v->nlimbs;
96 1057952 : usign = v->sign;
97 1057952 : vsize = u->nlimbs;
98 1057952 : vsign = u->sign;
99 1057952 : wsize = usize + 1;
100 1057952 : RESIZE_IF_NEEDED(w, wsize);
101 : /* These must be after realloc (u or v may be the same as w). */
102 1057952 : up = v->d;
103 1057952 : vp = u->d;
104 : }
105 : else {
106 34971266 : usize = u->nlimbs;
107 34971266 : usign = u->sign;
108 34971266 : vsize = v->nlimbs;
109 34971266 : vsign = v->sign;
110 34971266 : wsize = usize + 1;
111 34971266 : RESIZE_IF_NEEDED(w, wsize);
112 : /* These must be after realloc (u or v may be the same as w). */
113 34971266 : up = u->d;
114 34971266 : vp = v->d;
115 : }
116 36029218 : wp = w->d;
117 36029218 : wsign = 0;
118 :
119 36029218 : if( !vsize ) { /* simple */
120 76866 : MPN_COPY(wp, up, usize );
121 76866 : wsize = usize;
122 76866 : wsign = usign;
123 : }
124 35952352 : else if( usign != vsign ) { /* different sign */
125 : /* This test is right since USIZE >= VSIZE */
126 25496855 : if( usize != vsize ) {
127 1043073 : _gcry_mpih_sub(wp, up, usize, vp, vsize);
128 1043073 : wsize = usize;
129 1043073 : MPN_NORMALIZE(wp, wsize);
130 1043073 : wsign = usign;
131 : }
132 24453782 : else if( _gcry_mpih_cmp(up, vp, usize) < 0 ) {
133 14205122 : _gcry_mpih_sub_n(wp, vp, up, usize);
134 14205122 : wsize = usize;
135 14205122 : MPN_NORMALIZE(wp, wsize);
136 14205122 : if( !usign )
137 7617445 : wsign = 1;
138 : }
139 : else {
140 10248660 : _gcry_mpih_sub_n(wp, up, vp, usize);
141 10248660 : wsize = usize;
142 10248660 : MPN_NORMALIZE(wp, wsize);
143 10248660 : if( usign )
144 25464 : wsign = 1;
145 : }
146 : }
147 : else { /* U and V have same sign. Add them. */
148 10455497 : mpi_limb_t cy = _gcry_mpih_add(wp, up, usize, vp, vsize);
149 10455497 : wp[usize] = cy;
150 10455497 : wsize = usize + cy;
151 10455497 : if( usign )
152 25574 : wsign = 1;
153 : }
154 :
155 36029218 : w->nlimbs = wsize;
156 36029218 : w->sign = wsign;
157 36029218 : }
158 :
159 :
160 : /****************
161 : * Subtract the unsigned integer V from the mpi-integer U and store the
162 : * result in W.
163 : */
164 : void
165 16020 : _gcry_mpi_sub_ui(gcry_mpi_t w, gcry_mpi_t u, unsigned long v )
166 : {
167 : mpi_ptr_t wp, up;
168 : mpi_size_t usize, wsize;
169 : int usign, wsign;
170 :
171 16020 : usize = u->nlimbs;
172 16020 : usign = u->sign;
173 16020 : wsign = 0;
174 :
175 : /* If not space for W (and possible carry), increase space. */
176 16020 : wsize = usize + 1;
177 16020 : if( w->alloced < wsize )
178 4570 : mpi_resize(w, wsize);
179 :
180 : /* These must be after realloc (U may be the same as W). */
181 16020 : up = u->d;
182 16020 : wp = w->d;
183 :
184 16020 : if( !usize ) { /* simple */
185 1 : wp[0] = v;
186 1 : wsize = v? 1:0;
187 1 : wsign = 1;
188 : }
189 16019 : else if( usign ) { /* mpi and v are negative */
190 : mpi_limb_t cy;
191 0 : cy = _gcry_mpih_add_1(wp, up, usize, v);
192 0 : wp[usize] = cy;
193 0 : wsize = usize + cy;
194 : }
195 : else { /* The signs are different. Need exact comparison to determine
196 : * which operand to subtract from which. */
197 16019 : if( usize == 1 && up[0] < v ) {
198 0 : wp[0] = v - up[0];
199 0 : wsize = 1;
200 0 : wsign = 1;
201 : }
202 : else {
203 16019 : _gcry_mpih_sub_1(wp, up, usize, v);
204 : /* Size can decrease with at most one limb. */
205 16019 : wsize = usize - (wp[usize-1]==0);
206 : }
207 : }
208 :
209 16020 : w->nlimbs = wsize;
210 16020 : w->sign = wsign;
211 16020 : }
212 :
213 : void
214 18658313 : _gcry_mpi_sub(gcry_mpi_t w, gcry_mpi_t u, gcry_mpi_t v)
215 : {
216 18658313 : gcry_mpi_t vv = mpi_copy (v);
217 18658313 : vv->sign = ! vv->sign;
218 18658313 : mpi_add (w, u, vv);
219 18658313 : mpi_free (vv);
220 18658313 : }
221 :
222 :
223 : void
224 1191 : _gcry_mpi_addm( gcry_mpi_t w, gcry_mpi_t u, gcry_mpi_t v, gcry_mpi_t m)
225 : {
226 1191 : mpi_add (w, u, v);
227 1191 : mpi_mod (w, w, m);
228 1191 : }
229 :
230 : void
231 46 : _gcry_mpi_subm( gcry_mpi_t w, gcry_mpi_t u, gcry_mpi_t v, gcry_mpi_t m)
232 : {
233 46 : mpi_sub (w, u, v);
234 46 : mpi_mod (w, w, m);
235 46 : }
|