Coverage Report

Created: 2024-11-21 07:03

/src/libgcrypt/mpi/mpi-add.c
Line
Count
Source (jump to first uncovered line)
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, see <https://www.gnu.org/licenses/>.
18
 * SPDX-License-Identifier: LGPL-2.1-or-later
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
_gcry_mpi_add_ui (gcry_mpi_t w, gcry_mpi_t u, unsigned long v )
40
9
{
41
9
    mpi_ptr_t wp, up;
42
9
    mpi_size_t usize, wsize;
43
9
    int usign, wsign;
44
45
9
    usize = u->nlimbs;
46
9
    usign = u->sign;
47
9
    wsign = 0;
48
49
    /* If not space for W (and possible carry), increase space.  */
50
9
    wsize = usize + 1;
51
9
    if( w->alloced < wsize )
52
8
  mpi_resize(w, wsize);
53
54
    /* These must be after realloc (U may be the same as W).  */
55
9
    up = u->d;
56
9
    wp = w->d;
57
58
9
    if( !usize ) {  /* simple */
59
1
  wp[0] = v;
60
1
  wsize = v? 1:0;
61
1
    }
62
8
    else if( !usign ) {  /* mpi is not negative */
63
8
  mpi_limb_t cy;
64
8
  cy = _gcry_mpih_add_1(wp, up, usize, v);
65
8
  wp[usize] = cy;
66
8
  wsize = usize + cy;
67
8
    }
68
0
    else {  /* The signs are different.  Need exact comparison to determine
69
       * which operand to subtract from which.  */
70
0
  if( usize == 1 && up[0] < v ) {
71
0
      wp[0] = v - up[0];
72
0
      wsize = 1;
73
0
  }
74
0
  else {
75
0
      _gcry_mpih_sub_1(wp, up, usize, v);
76
      /* Size can decrease with at most one limb. */
77
0
      wsize = usize - (wp[usize-1]==0);
78
0
      wsign = 1;
79
0
  }
80
0
    }
81
82
9
    w->nlimbs = wsize;
83
9
    w->sign   = wsign;
84
9
}
85
86
87
static void
88
_gcry_mpi_add_inv_sign(gcry_mpi_t w, gcry_mpi_t u, gcry_mpi_t v, int inv_v_sign)
89
11.2M
{
90
11.2M
    mpi_ptr_t wp, up, vp;
91
11.2M
    mpi_size_t usize, vsize, wsize;
92
11.2M
    int usign, vsign, wsign;
93
94
11.2M
    if( u->nlimbs < v->nlimbs ) { /* Swap U and V. */
95
6.84k
  usize = v->nlimbs;
96
6.84k
  usign = v->sign ^ inv_v_sign;
97
6.84k
  vsize = u->nlimbs;
98
6.84k
  vsign = u->sign;
99
6.84k
  wsize = usize + 1;
100
6.84k
  RESIZE_IF_NEEDED(w, wsize);
101
  /* These must be after realloc (u or v may be the same as w).  */
102
6.84k
  up    = v->d;
103
6.84k
  vp    = u->d;
104
6.84k
    }
105
11.2M
    else {
106
11.2M
  usize = u->nlimbs;
107
11.2M
  usign = u->sign;
108
11.2M
  vsize = v->nlimbs;
109
11.2M
  vsign = v->sign ^ inv_v_sign;
110
11.2M
  wsize = usize + 1;
111
11.2M
  RESIZE_IF_NEEDED(w, wsize);
112
  /* These must be after realloc (u or v may be the same as w).  */
113
11.2M
  up    = u->d;
114
11.2M
  vp    = v->d;
115
11.2M
    }
116
11.2M
    wp = w->d;
117
11.2M
    wsign = 0;
118
119
11.2M
    if( !vsize ) {  /* simple */
120
211k
  MPN_COPY(wp, up, usize );
121
211k
  wsize = usize;
122
211k
  wsign = usign;
123
211k
    }
124
11.0M
    else if( usign != vsign ) { /* different sign */
125
  /* This test is right since USIZE >= VSIZE */
126
9.28M
  if( usize != vsize ) {
127
8.91k
      _gcry_mpih_sub(wp, up, usize, vp, vsize);
128
8.91k
      wsize = usize;
129
8.91k
      MPN_NORMALIZE(wp, wsize);
130
8.91k
      wsign = usign;
131
8.91k
  }
132
9.27M
  else if( _gcry_mpih_cmp(up, vp, usize) < 0 ) {
133
6.18M
      _gcry_mpih_sub_n(wp, vp, up, usize);
134
6.18M
      wsize = usize;
135
6.18M
      MPN_NORMALIZE(wp, wsize);
136
6.18M
      if( !usign )
137
3.09M
    wsign = 1;
138
6.18M
  }
139
3.09M
  else {
140
3.09M
      _gcry_mpih_sub_n(wp, up, vp, usize);
141
3.09M
      wsize = usize;
142
3.09M
      MPN_NORMALIZE(wp, wsize);
143
3.09M
      if( usign )
144
0
    wsign = 1;
145
3.09M
  }
146
9.28M
    }
147
1.74M
    else { /* U and V have same sign. Add them. */
148
1.74M
  mpi_limb_t cy = _gcry_mpih_add(wp, up, usize, vp, vsize);
149
1.74M
  wp[usize] = cy;
150
1.74M
  wsize = usize + cy;
151
1.74M
  if( usign )
152
0
      wsign = 1;
153
1.74M
    }
154
155
11.2M
    w->nlimbs = wsize;
156
11.2M
    w->sign = wsign;
157
11.2M
}
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
_gcry_mpi_sub_ui(gcry_mpi_t w, gcry_mpi_t u, unsigned long v )
166
1.92k
{
167
1.92k
    mpi_ptr_t wp, up;
168
1.92k
    mpi_size_t usize, wsize;
169
1.92k
    int usign, wsign;
170
171
1.92k
    usize = u->nlimbs;
172
1.92k
    usign = u->sign;
173
1.92k
    wsign = 0;
174
175
    /* If not space for W (and possible carry), increase space.  */
176
1.92k
    wsize = usize + 1;
177
1.92k
    if( w->alloced < wsize )
178
1.92k
  mpi_resize(w, wsize);
179
180
    /* These must be after realloc (U may be the same as W).  */
181
1.92k
    up = u->d;
182
1.92k
    wp = w->d;
183
184
1.92k
    if( !usize ) {  /* simple */
185
0
  wp[0] = v;
186
0
  wsize = v? 1:0;
187
0
  wsign = 1;
188
0
    }
189
1.92k
    else if( usign ) { /* mpi and v are negative */
190
0
  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
0
  wsign = 1;
195
0
    }
196
1.92k
    else {  /* The signs are different.  Need exact comparison to determine
197
       * which operand to subtract from which.  */
198
1.92k
  if( usize == 1 && up[0] < v ) {
199
0
      wp[0] = v - up[0];
200
0
      wsize = 1;
201
0
      wsign = 1;
202
0
  }
203
1.92k
  else {
204
1.92k
      _gcry_mpih_sub_1(wp, up, usize, v);
205
      /* Size can decrease with at most one limb. */
206
1.92k
      wsize = usize - (wp[usize-1]==0);
207
1.92k
  }
208
1.92k
    }
209
210
1.92k
    w->nlimbs = wsize;
211
1.92k
    w->sign   = wsign;
212
1.92k
}
213
214
void
215
_gcry_mpi_add(gcry_mpi_t w, gcry_mpi_t u, gcry_mpi_t v)
216
5.05M
{
217
5.05M
  _gcry_mpi_add_inv_sign (w, u, v, 0);
218
5.05M
}
219
220
void
221
_gcry_mpi_sub(gcry_mpi_t w, gcry_mpi_t u, gcry_mpi_t v)
222
6.19M
{
223
6.19M
  _gcry_mpi_add_inv_sign (w, u, v, 1);
224
6.19M
}
225
226
227
void
228
_gcry_mpi_addm( gcry_mpi_t w, gcry_mpi_t u, gcry_mpi_t v, gcry_mpi_t m)
229
405
{
230
405
  gcry_mpi_t temp_m = NULL;
231
232
405
  if (w == m)
233
11
    {
234
11
      temp_m = mpi_copy (m);
235
11
      m = temp_m;
236
11
    }
237
238
405
  mpi_add (w, u, v);
239
405
  mpi_mod (w, w, m);
240
241
405
  if (temp_m)
242
11
    mpi_free(temp_m);
243
405
}
244
245
void
246
_gcry_mpi_subm( gcry_mpi_t w, gcry_mpi_t u, gcry_mpi_t v, gcry_mpi_t m)
247
122
{
248
122
  gcry_mpi_t temp_m = NULL;
249
250
122
  if (w == m)
251
18
    {
252
18
      temp_m = mpi_copy (m);
253
18
      m = temp_m;
254
18
    }
255
256
122
  mpi_sub (w, u, v);
257
122
  mpi_mod (w, w, m);
258
259
122
  if (temp_m)
260
18
    mpi_free(temp_m);
261
122
}