Coverage Report

Created: 2024-11-21 07:03

/src/libgcrypt/mpi/mpi-mod.c
Line
Count
Source (jump to first uncovered line)
1
/* mpi-mod.c -  Modular reduction
2
 * Copyright (C) 1998, 1999, 2001, 2002, 2003,
3
 *               2007  Free Software Foundation, Inc.
4
 *
5
 * This file is part of Libgcrypt.
6
 *
7
 * Libgcrypt is free software; you can redistribute it and/or modify
8
 * it under the terms of the GNU Lesser General Public License as
9
 * published by the Free Software Foundation; either version 2.1 of
10
 * the License, or (at your option) any later version.
11
 *
12
 * Libgcrypt is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU Lesser General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with this program; if not, see <https://www.gnu.org/licenses/>.
19
 * SPDX-License-Identifier: LGPL-2.1-or-later
20
 */
21
22
23
#include <config.h>
24
#include <stdio.h>
25
#include <stdlib.h>
26
27
#include "mpi-internal.h"
28
#include "longlong.h"
29
#include "g10lib.h"
30
31
32
/* Context used with Barrett reduction.  */
33
struct barrett_ctx_s
34
{
35
  gcry_mpi_t m;   /* The modulus - may not be modified. */
36
  int m_copied;   /* If true, M needs to be released.  */
37
  int k;
38
  gcry_mpi_t y;
39
  gcry_mpi_t r1;  /* Helper MPI. */
40
  gcry_mpi_t r2;  /* Helper MPI. */
41
  gcry_mpi_t r3;  /* Helper MPI allocated on demand. */
42
};
43
44
45
46
void
47
_gcry_mpi_mod (gcry_mpi_t rem, gcry_mpi_t dividend, gcry_mpi_t divisor)
48
3.51M
{
49
3.51M
  _gcry_mpi_fdiv_r (rem, dividend, divisor);
50
3.51M
}
51
52
53
/* This function returns a new context for Barrett based operations on
54
   the modulus M.  This context needs to be released using
55
   _gcry_mpi_barrett_free.  If COPY is true M will be transferred to
56
   the context and the user may change M.  If COPY is false, M may not
57
   be changed until gcry_mpi_barrett_free has been called. */
58
mpi_barrett_t
59
_gcry_mpi_barrett_init (gcry_mpi_t m, int copy)
60
71
{
61
71
  mpi_barrett_t ctx;
62
71
  gcry_mpi_t tmp;
63
64
71
  mpi_normalize (m);
65
71
  ctx = xcalloc (1, sizeof *ctx);
66
67
71
  if (copy)
68
71
    {
69
71
      ctx->m = mpi_copy (m);
70
71
      ctx->m_copied = 1;
71
71
    }
72
0
  else
73
0
    ctx->m = m;
74
75
71
  ctx->k = mpi_get_nlimbs (m);
76
71
  tmp = mpi_alloc (ctx->k + 1);
77
78
  /* Barrett precalculation: y = floor(b^(2k) / m). */
79
71
  mpi_set_ui (tmp, 1);
80
71
  mpi_lshift_limbs (tmp, 2 * ctx->k);
81
71
  mpi_fdiv_q (tmp, tmp, m);
82
83
71
  ctx->y  = tmp;
84
71
  ctx->r1 = mpi_alloc ( 2 * ctx->k + 1 );
85
71
  ctx->r2 = mpi_alloc ( 2 * ctx->k + 1 );
86
87
71
  return ctx;
88
71
}
89
90
void
91
_gcry_mpi_barrett_free (mpi_barrett_t ctx)
92
3.06k
{
93
3.06k
  if (ctx)
94
71
    {
95
71
      mpi_free (ctx->y);
96
71
      mpi_free (ctx->r1);
97
71
      mpi_free (ctx->r2);
98
71
      if (ctx->r3)
99
0
        mpi_free (ctx->r3);
100
71
      if (ctx->m_copied)
101
71
        mpi_free (ctx->m);
102
71
      xfree (ctx);
103
71
    }
104
3.06k
}
105
106
107
/* R = X mod M
108
109
   Using Barrett reduction.  Before using this function
110
   _gcry_mpi_barrett_init must have been called to do the
111
   precalculations.  CTX is the context created by this precalculation
112
   and also conveys M.  If the Barret reduction could no be done a
113
   straightforward reduction method is used.
114
115
   We assume that these conditions are met:
116
   Input:  x =(x_2k-1 ...x_0)_b
117
     m =(m_k-1 ....m_0)_b   with m_k-1 != 0
118
   Output: r = x mod m
119
 */
120
void
121
_gcry_mpi_mod_barrett (gcry_mpi_t r, gcry_mpi_t x, mpi_barrett_t ctx)
122
71
{
123
71
  gcry_mpi_t m = ctx->m;
124
71
  int k = ctx->k;
125
71
  gcry_mpi_t y = ctx->y;
126
71
  gcry_mpi_t r1 = ctx->r1;
127
71
  gcry_mpi_t r2 = ctx->r2;
128
71
  int sign;
129
130
71
  mpi_normalize (x);
131
71
  if (mpi_get_nlimbs (x) > 2*k )
132
24
    {
133
24
      mpi_mod (r, x, m);
134
24
      return;
135
24
    }
136
137
47
  sign = x->sign;
138
47
  x->sign = 0;
139
140
  /* 1. q1 = floor( x / b^k-1)
141
   *    q2 = q1 * y
142
   *    q3 = floor( q2 / b^k+1 )
143
   * Actually, we don't need qx, we can work direct on r2
144
   */
145
47
  mpi_set ( r2, x );
146
47
  mpi_rshift_limbs ( r2, k-1 );
147
47
  mpi_mul ( r2, r2, y );
148
47
  mpi_rshift_limbs ( r2, k+1 );
149
150
  /* 2. r1 = x mod b^k+1
151
   *  r2 = q3 * m mod b^k+1
152
   *  r  = r1 - r2
153
   * 3. if r < 0 then  r = r + b^k+1
154
   */
155
47
  mpi_set ( r1, x );
156
47
  if ( r1->nlimbs > k+1 ) /* Quick modulo operation.  */
157
8
    r1->nlimbs = k+1;
158
47
  mpi_mul ( r2, r2, m );
159
47
  if ( r2->nlimbs > k+1 ) /* Quick modulo operation. */
160
8
    r2->nlimbs = k+1;
161
47
  mpi_sub ( r, r1, r2 );
162
163
47
  if ( mpi_has_sign ( r ) )
164
0
    {
165
0
      if (!ctx->r3)
166
0
        {
167
0
          ctx->r3 = mpi_alloc ( k + 2 );
168
0
          mpi_set_ui (ctx->r3, 1);
169
0
          mpi_lshift_limbs (ctx->r3, k + 1 );
170
0
        }
171
0
      mpi_add ( r, r, ctx->r3 );
172
0
    }
173
174
  /* 4. while r >= m do r = r - m */
175
51
  while ( mpi_cmp( r, m ) >= 0 )
176
4
    mpi_sub ( r, r, m );
177
178
47
  x->sign = sign;
179
47
}
180
181
182
void
183
_gcry_mpi_mul_barrett (gcry_mpi_t w, gcry_mpi_t u, gcry_mpi_t v,
184
                       mpi_barrett_t ctx)
185
41
{
186
41
  mpi_mul (w, u, v);
187
41
  mpi_mod_barrett (w, w, ctx);
188
41
}