Coverage Report

Created: 2026-06-07 07:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/relic/src/bn/relic_bn_mod.c
Line
Count
Source
1
/*
2
 * RELIC is an Efficient LIbrary for Cryptography
3
 * Copyright (c) 2009 RELIC Authors
4
 *
5
 * This file is part of RELIC. RELIC is legal property of its developers,
6
 * whose names are not listed here. Please refer to the COPYRIGHT file
7
 * for contact information.
8
 *
9
 * RELIC is free software; you can redistribute it and/or modify it under the
10
 * terms of the version 2.1 (or later) of the GNU Lesser General Public License
11
 * as published by the Free Software Foundation; or version 2.0 of the Apache
12
 * License as published by the Apache Software Foundation. See the LICENSE files
13
 * for more details.
14
 *
15
 * RELIC is distributed in the hope that it will be useful, but WITHOUT ANY
16
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
17
 * A PARTICULAR PURPOSE. See the LICENSE files for more details.
18
 *
19
 * You should have received a copy of the GNU Lesser General Public or the
20
 * Apache License along with RELIC. If not, see <https://www.gnu.org/licenses/>
21
 * or <https://www.apache.org/licenses/>.
22
 */
23
24
/**
25
 * @file
26
 *
27
 * Implementation of the multiple precision integer modular reduction
28
 * functions.
29
 *
30
 * @ingroup bn
31
 */
32
33
#include "relic_core.h"
34
#include "relic_bn_low.h"
35
36
/*============================================================================*/
37
/* Public definitions                                                         */
38
/*============================================================================*/
39
40
9.72k
void bn_mod_2b(bn_t c, const bn_t a, int b) {
41
9.72k
  int i, first, d;
42
43
9.72k
  if (b <= 0) {
44
0
    bn_zero(c);
45
0
    return;
46
0
  }
47
48
9.72k
  if (b >= (int)(a->used * RLC_DIG)) {
49
56
    bn_copy(c, a);
50
56
    return;
51
56
  }
52
53
9.66k
  bn_copy(c, a);
54
55
9.66k
  RLC_RIP(b, d, b);
56
57
9.66k
  first = (d) + (b == 0 ? 0 : 1);
58
175k
  for (i = first; i < c->used; i++) {
59
165k
    c->dp[i] = 0;
60
165k
  }
61
62
9.66k
  c->dp[d] &= RLC_MASK(b);
63
64
9.66k
  bn_trim(c);
65
9.66k
}
66
67
19.2k
void bn_mod_dig(dig_t *c, const bn_t a, dig_t b) {
68
19.2k
  bn_div_rem_dig(NULL, c, a, b);
69
19.2k
}
70
71
482k
void bn_mod_basic(bn_t c, const bn_t a, const bn_t m) {
72
482k
  bn_div_rem(NULL, c, a, m);
73
482k
}
74
75
#if BN_MOD == BARRT || !defined(STRIP)
76
77
67
void bn_mod_pre_barrt(bn_t u, const bn_t m) {
78
67
  if (bn_is_zero(m) || bn_sign(m) != RLC_POS) {
79
8
    RLC_THROW(ERR_NO_VALID);
80
8
    return;
81
8
  }
82
83
59
  bn_set_2b(u, m->used * 2 * RLC_DIG);
84
59
  bn_div(u, u, m);
85
59
}
86
87
46
void bn_mod_barrt(bn_t c, const bn_t a, const bn_t m, const bn_t u) {
88
46
  bn_t q, t;
89
46
  int mu, neg;
90
91
46
  bn_null(q);
92
46
  bn_null(t);
93
94
46
  if (bn_is_zero(m) || bn_sign(m) != RLC_POS) {
95
0
    RLC_THROW(ERR_NO_VALID);
96
0
    return;
97
0
  }
98
99
46
  if (bn_cmp_abs(a, m) == RLC_LT) {
100
8
    bn_copy(c, a);
101
8
    return;
102
8
  }
103
104
38
  if (a->used > 2 * m->used) {
105
7
    bn_mod(c, a, m);
106
7
    return;
107
7
  }
108
109
31
  RLC_TRY {
110
31
    bn_new(q);
111
31
    bn_new(t);
112
31
    bn_zero(t);
113
114
31
    neg = (bn_sign(a) == RLC_NEG);
115
31
    bn_abs(c, a);
116
117
31
    bn_rsh(q, c, (m->used - 1) * RLC_DIG);
118
119
31
    if (m->used > ((dig_t)1) << (RLC_DIG - 1)) {
120
0
      bn_mul(t, q, u);
121
31
    } else {
122
31
      bn_grow(t, q->used + u->used);
123
31
      t->used = q->used + u->used;
124
31
      mu = u->used - q->used;
125
31
      if (q->used > u->used) {
126
0
        bn_muld_low(t->dp, q->dp, q->used, u->dp, u->used, mu, t->used);
127
31
      } else {
128
31
        mu = (mu > u->used - q->used ? mu - (u->used - q->used) : 0);
129
31
        bn_muld_low(t->dp, u->dp, u->used, q->dp, q->used, mu, t->used);
130
31
      }
131
31
      bn_trim(t);
132
31
    }
133
134
31
    bn_rsh(q, t, (m->used + 1) * RLC_DIG);
135
136
31
    if (q->used > m->used) {
137
3
      bn_muld_low(t->dp, q->dp, q->used, m->dp, m->used, 0, q->used + 1);
138
28
    } else {
139
28
      bn_muld_low(t->dp, m->dp, m->used, q->dp, q->used, 0, m->used + 1);
140
28
    }
141
31
    t->used = m->used + 1;
142
31
    bn_trim(t);
143
144
31
    bn_mod_2b(q, t, RLC_DIG * (m->used + 1));
145
31
    bn_mod_2b(t, c, RLC_DIG * (m->used + 1));
146
31
    bn_sub(t, t, q);
147
148
31
    if (bn_sign(t) == RLC_NEG) {
149
10
      bn_set_dig(q, (dig_t)1);
150
10
      bn_lsh(q, q, (m->used + 1) * RLC_DIG);
151
10
      bn_add(t, t, q);
152
10
    }
153
154
40
    while (bn_cmp(t, m) != RLC_LT) {
155
9
      bn_sub(t, t, m);
156
9
    }
157
158
31
    bn_copy(c, t);
159
31
    if (neg) {
160
0
      bn_sub(c, m, c);
161
0
    }
162
31
  }
163
62
  RLC_CATCH_ANY {
164
0
    RLC_THROW(ERR_CAUGHT);
165
0
  }
166
62
  RLC_FINALLY {
167
31
    bn_free(q);
168
31
    bn_free(t);
169
31
  }
170
31
}
171
172
#endif /* BN_MOD == BARRT || !defined(STRIP) */
173
174
#if BN_MOD == MONTY || (defined(WITH_FP) && FP_RDC == MONTY) || !defined(STRIP)
175
176
12.0k
void bn_mod_pre_monty(bn_t u, const bn_t m) {
177
12.0k
  dig_t x, b = m->dp[0];
178
179
12.0k
  if (bn_is_even(m) || bn_sign(m) != RLC_POS) {
180
270
    RLC_THROW(ERR_NO_VALID);
181
270
    return;
182
270
  }
183
184
11.7k
  x = (((b + 2) & 4) << 1) + b;       /* here x*a==1 mod 2**4 */
185
11.7k
  x *= (dig_t)2 - b * x;            /* here x*a==1 mod 2**8 */
186
11.7k
#if WSIZE > 8
187
11.7k
  x *= (dig_t)2 - b * x;            /* here x*a==1 mod 2**16 */
188
11.7k
#endif
189
11.7k
#if WSIZE > 16
190
11.7k
  x *= (dig_t)2 - b * x;            /* here x*a==1 mod 2**32 */
191
11.7k
#endif
192
11.7k
#if WSIZE > 32
193
11.7k
  x *= (dig_t)2 - b * x;            /* here x*a==1 mod 2**64 */
194
11.7k
#endif
195
  /* u = -1/m0 (mod 2^RLC_DIG) */
196
11.7k
  bn_set_dig(u, -x);
197
11.7k
}
198
199
6.96k
void bn_mod_monty_conv(bn_t c, const bn_t a, const bn_t m) {
200
6.96k
  if (bn_is_even(m) || bn_sign(m) != RLC_POS) {
201
24
    RLC_THROW(ERR_NO_VALID);
202
24
    return;
203
24
  }
204
205
6.96k
  bn_mod(c, a, m);
206
6.93k
  bn_lsh(c, c, m->used * RLC_DIG);
207
6.93k
  bn_mod(c, c, m);
208
6.93k
}
209
210
3.46k
void bn_mod_monty_back(bn_t c, const bn_t a, const bn_t m) {
211
3.46k
  bn_t u;
212
213
3.46k
  bn_null(u);
214
215
3.46k
  if (bn_is_even(m) || bn_sign(m) != RLC_POS) {
216
0
    RLC_THROW(ERR_NO_VALID);
217
0
    return;
218
0
  }
219
220
3.46k
  RLC_TRY {
221
3.46k
    bn_new(u);
222
3.46k
    bn_mod_pre_monty(u, m);
223
3.46k
    bn_mod_monty(c, a, m, u);
224
6.92k
  } RLC_CATCH_ANY {
225
0
    RLC_THROW(ERR_CAUGHT);
226
6.92k
  } RLC_FINALLY {
227
3.46k
    bn_free(u);
228
3.46k
  }
229
3.46k
}
230
231
#if BN_MUL == BASIC || !defined(STRIP)
232
233
49
void bn_mod_monty_basic(bn_t c, const bn_t a, const bn_t m, const bn_t u) {
234
49
  int digits, i;
235
49
  dig_t r, u0, *tmp;
236
49
  bn_t t;
237
238
49
  if (bn_is_even(m) || bn_sign(m) != RLC_POS) {
239
0
    RLC_THROW(ERR_NO_VALID);
240
0
    return;
241
0
  }
242
243
49
  bn_null(t);
244
49
  digits = 2 * m->used;
245
246
49
  RLC_TRY {
247
49
    bn_new_size(t, digits);
248
49
    bn_zero(t);
249
49
    bn_copy(t, a);
250
251
49
    u0 = u->dp[0];
252
49
    tmp = t->dp;
253
254
950
    for (i = 0; i < m->used; i++, tmp++) {
255
901
      r = (dig_t)(*tmp * u0);
256
901
      *tmp = bn_mula_low(tmp, m->dp, r, m->used);
257
901
    }
258
49
    if (bn_addn_low(t->dp, t->dp, tmp, m->used)) {
259
0
      bn_subn_low(t->dp, t->dp, m->dp, m->used);
260
0
    }
261
49
    t->used = m->used;
262
49
    bn_trim(t);
263
264
49
    if (bn_cmp_abs(t, m) != RLC_LT) {
265
0
      bn_sub(t, t, m);
266
0
    }
267
268
49
    bn_copy(c, t);
269
49
  }
270
98
  RLC_CATCH_ANY {
271
0
    RLC_THROW(ERR_CAUGHT);
272
0
  }
273
98
  RLC_FINALLY {
274
49
    bn_free(t);
275
49
  }
276
49
}
277
278
#endif /* BN_MUL == BASIC || !defined(STRIP) */
279
280
#if BN_MUL == COMBA || !defined(STRIP)
281
282
1.23M
void bn_mod_monty_comba(bn_t c, const bn_t a, const bn_t m, const bn_t u) {
283
1.23M
  int digits;
284
1.23M
  bn_t t;
285
286
1.23M
  if (bn_is_even(m) || bn_sign(m) != RLC_POS) {
287
0
    RLC_THROW(ERR_NO_VALID);
288
0
    return;
289
0
  }
290
291
1.23M
  bn_null(t);
292
1.23M
  digits = 2 * m->used;
293
294
1.23M
  RLC_TRY {
295
1.23M
    bn_new_size(t, digits);
296
1.23M
    bn_zero(t);
297
298
1.23M
    bn_modn_low(t->dp, a->dp, a->used, m->dp, m->used, u->dp[0]);
299
1.23M
    t->used = m->used;
300
301
1.23M
    bn_trim(t);
302
1.23M
    if (bn_cmp_abs(t, m) != RLC_LT) {
303
7.17k
      bn_sub(t, t, m);
304
7.17k
    }
305
1.23M
    bn_copy(c, t);
306
1.23M
  }
307
2.47M
  RLC_CATCH_ANY {
308
0
    RLC_THROW(ERR_CAUGHT);
309
0
  }
310
2.47M
  RLC_FINALLY {
311
1.23M
    bn_free(t);
312
1.23M
  }
313
1.23M
}
314
315
#endif /* BN_MUL == COMBA || !defined(STRIP) */
316
317
#endif /* BN_MOD == MONTY || (WITH_FP && FP_RDC == MONTY) || !defined(STRIP) */
318
319
#if BN_MOD == PMERS || !defined(STRIP)
320
321
64
void bn_mod_pre_pmers(bn_t u, const bn_t m) {
322
64
  if (bn_is_zero(m) || bn_sign(m) != RLC_POS) {
323
11
    RLC_THROW(ERR_NO_VALID);
324
11
    return;
325
11
  }
326
327
53
  bn_set_2b(u, bn_bits(m));
328
53
  bn_sub(u, u, m);
329
53
}
330
331
52
void bn_mod_pmers(bn_t c, const bn_t a, const bn_t m, const bn_t u) {
332
52
  bn_t q, t;
333
52
  int neg = 0, bits = bn_bits(m);
334
335
52
  if (bn_is_zero(m) || bn_sign(m) != RLC_POS) {
336
0
    RLC_THROW(ERR_NO_VALID);
337
0
    return;
338
0
  }
339
340
52
  bn_null(q);
341
52
  bn_null(t);
342
343
52
  RLC_TRY {
344
    /* Implement algorithm 10.25 from HEHC. */
345
346
52
    bn_new(q);
347
52
    bn_new(t);
348
349
52
    bn_copy(c, a);
350
52
    if (bn_sign(c) == RLC_NEG) {
351
0
      neg = 1;
352
0
      bn_sub(c, m, c);
353
0
    }
354
355
52
    bn_rsh(q, c, bits);
356
52
    bn_mod_2b(c, c, bits);
357
358
9.66k
    while (bits > 0 && !bn_is_zero(q)) {
359
9.60k
      if (u -> used == 1) {
360
888
        bn_mul_dig(t, q, u->dp[0]);
361
8.72k
      } else {
362
8.72k
        bn_mul(t, q, u);
363
8.72k
      }
364
9.60k
      bn_rsh(q, t, bits);
365
9.60k
      bn_mod_2b(t, t, bits);
366
367
9.60k
      bn_add(c, c, t);
368
9.60k
    }
369
7.23k
    while (bits > 0 && bn_cmp_abs(c, m) != RLC_LT) {
370
7.18k
      bn_sub(c, c, m);
371
7.18k
    }
372
373
52
    if (neg) {
374
0
      bn_sub(c, m, c);
375
0
    }
376
52
  }
377
104
  RLC_CATCH_ANY {
378
0
    RLC_THROW(ERR_CAUGHT);
379
0
  }
380
104
  RLC_FINALLY {
381
52
    bn_free(t);
382
    bn_free(q);
383
52
  }
384
52
}
385
386
#endif /* BN_MOD == PMERS || !defined(STRIP) */