chiark / gitweb /
Merge branch '2.4.x' into 2.5.x
[catacomb] / math / mpcrt.c
CommitLineData
5ee4c893 1/* -*-c-*-
5ee4c893 2 *
3 * Chinese Remainder Theorem computations (Gauss's algorithm)
4 *
5 * (c) 1999 Straylight/Edgeware
6 */
7
45c0fd36 8/*----- Licensing notice --------------------------------------------------*
5ee4c893 9 *
10 * This file is part of Catacomb.
11 *
12 * Catacomb is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Library General Public License as
14 * published by the Free Software Foundation; either version 2 of the
15 * License, or (at your option) any later version.
45c0fd36 16 *
5ee4c893 17 * Catacomb is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Library General Public License for more details.
45c0fd36 21 *
5ee4c893 22 * You should have received a copy of the GNU Library General Public
23 * License along with Catacomb; if not, write to the Free
24 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
25 * MA 02111-1307, USA.
26 */
27
5ee4c893 28/*----- Header files ------------------------------------------------------*/
29
30#include "mp.h"
31#include "mpcrt.h"
5e1601ef 32#include "mpmul.h"
5bda60bd 33#include "mpbarrett.h"
5ee4c893 34
35/*----- Main code ---------------------------------------------------------*/
36
37/* --- @mpcrt_create@ --- *
38 *
39 * Arguments: @mpcrt *c@ = pointer to CRT context
40 * @mpcrt_mod *v@ = pointer to vector of moduli
41 * @size_t k@ = number of moduli
42 * @mp *n@ = product of all moduli (@MP_NEW@ if unknown)
43 *
44 * Returns: ---
45 *
46 * Use: Initializes a context for solving Chinese Remainder Theorem
47 * problems. The vector of moduli can be incomplete. Omitted
48 * items must be left as null pointers. Not all combinations of
49 * missing things can be coped with, even if there is
50 * technically enough information to cope. For example, if @n@
51 * is unspecified, all the @m@ values must be present, even if
52 * there is one modulus with both @m@ and @n@ (from which the
53 * product of all moduli could clearly be calculated).
54 */
55
56void mpcrt_create(mpcrt *c, mpcrt_mod *v, size_t k, mp *n)
57{
5ee4c893 58 size_t i;
59
60 /* --- Simple initialization things --- */
61
62 c->k = k;
63 c->v = v;
64
65 /* --- Work out @n@ if I don't have it already --- */
66
5bda60bd 67 if (n != MP_NEW)
68 n = MP_COPY(n);
69 else {
5e1601ef 70 mpmul mm;
71 mpmul_init(&mm);
5e1601ef 72 for (i = 0; i < k; i++)
73 mpmul_add(&mm, v[i].m);
74 n = mpmul_done(&mm);
5bda60bd 75 }
76
77 /* --- A quick hack if %$k = 2$% --- */
78
79 if (k == 2) {
80
81 /* --- The %$n / n_i$% values are trivial in this case --- */
82
83 if (!v[0].n)
84 v[0].n = MP_COPY(v[1].m);
85 if (!v[1].n)
86 v[1].n = MP_COPY(v[0].m);
87
88 /* --- Now sort out the inverses --- *
89 *
90 * @mp_gcd@ will ensure that the first argument is negative.
91 */
92
93 if (!v[0].ni && !v[1].ni) {
b817bfc6 94 mp *g = MP_NEW;
95 mp_gcd(&g, &v[0].ni, &v[1].ni, v[0].n, v[1].n);
96 assert(MP_EQ(g, MP_ONE));
97 mp_drop(g);
5bda60bd 98 v[0].ni = mp_add(v[0].ni, v[0].ni, v[1].n);
99 } else {
100 int i, j;
101 mp *x;
102
103 if (!v[0].ni)
104 i = 0, j = 1;
105 else
106 i = 1, j = 0;
45c0fd36 107
5bda60bd 108 x = mp_mul(MP_NEW, v[j].n, v[j].ni);
109 x = mp_sub(x, x, MP_ONE);
110 mp_div(&x, 0, x, v[i].n);
111 v[i].ni = x;
5ee4c893 112 }
113 }
114
5bda60bd 115 /* --- Set up the Barrett context --- */
5ee4c893 116
5bda60bd 117 mpbarrett_create(&c->mb, n);
5ee4c893 118
119 /* --- Walk through filling in @n@, @ni@ and @nnir@ --- */
120
121 for (i = 0; i < k; i++) {
122 if (!v[i].n)
123 mp_div(&v[i].n, 0, n, v[i].m);
124 if (!v[i].ni)
b817bfc6 125 v[i].ni = mp_modinv(MP_NEW, v[i].n, v[i].m);
5bda60bd 126 if (!v[i].nni)
127 v[i].nni = mp_mul(MP_NEW, v[i].n, v[i].ni);
5ee4c893 128 }
129
130 /* --- Done --- */
131
5bda60bd 132 mp_drop(n);
5ee4c893 133}
134
135/* --- @mpcrt_destroy@ --- *
136 *
137 * Arguments: @mpcrt *c@ - pointer to CRT context
138 *
139 * Returns: ---
140 *
141 * Use: Destroys a CRT context, releasing all the resources it holds.
142 */
143
144void mpcrt_destroy(mpcrt *c)
145{
146 size_t i;
147
148 for (i = 0; i < c->k; i++) {
149 if (c->v[i].m) mp_drop(c->v[i].m);
150 if (c->v[i].n) mp_drop(c->v[i].n);
151 if (c->v[i].ni) mp_drop(c->v[i].ni);
5bda60bd 152 if (c->v[i].nni) mp_drop(c->v[i].nni);
5ee4c893 153 }
5bda60bd 154 mpbarrett_destroy(&c->mb);
5ee4c893 155}
156
157/* --- @mpcrt_solve@ --- *
158 *
159 * Arguments: @mpcrt *c@ = pointer to CRT context
5bda60bd 160 * @mp *d@ = fake destination
5ee4c893 161 * @mp **v@ = array of residues
162 *
163 * Returns: The unique solution modulo the product of the individual
164 * moduli, which leaves the given residues.
165 *
166 * Use: Constructs a result given its residue modulo an array of
167 * coprime integers. This can be used to improve performance of
168 * RSA encryption or Blum-Blum-Shub generation if the factors
169 * of the modulus are known, since results can be computed mod
170 * each of the individual factors and then combined at the end.
171 * This is rather faster than doing the full-scale modular
172 * exponentiation.
173 */
174
5bda60bd 175mp *mpcrt_solve(mpcrt *c, mp *d, mp **v)
5ee4c893 176{
177 mp *a = MP_ZERO;
178 mp *x = MP_NEW;
179 size_t i;
180
181 for (i = 0; i < c->k; i++) {
5bda60bd 182 x = mp_mul(x, c->v[i].nni, v[i]);
183 x = mpbarrett_reduce(&c->mb, x, x);
5ee4c893 184 a = mp_add(a, a, x);
185 }
186 if (x)
5bda60bd 187 MP_DROP(x);
188 a = mpbarrett_reduce(&c->mb, a, a);
189 if (d != MP_NEW)
190 MP_DROP(d);
5ee4c893 191 return (a);
192}
193
194/*----- Test rig ----------------------------------------------------------*/
195
196#ifdef TEST_RIG
197
198static int verify(size_t n, dstr *v)
199{
200 mpcrt_mod *m = xmalloc(n * sizeof(mpcrt_mod));
201 mp **r = xmalloc(n * sizeof(mp *));
202 mpcrt c;
203 mp *a, *b;
204 size_t i;
205 int ok = 1;
206
207 for (i = 0; i < n; i++) {
208 r[i] = *(mp **)v[2 * i].buf;
209 m[i].m = *(mp **)v[2 * i + 1].buf;
210 m[i].n = 0;
211 m[i].ni = 0;
5bda60bd 212 m[i].nni = 0;
5ee4c893 213 }
214 a = *(mp **)v[2 * n].buf;
215
216 mpcrt_create(&c, m, n, 0);
5bda60bd 217 b = mpcrt_solve(&c, MP_NEW, r);
5ee4c893 218
22bab86c 219 if (!MP_EQ(a, b)) {
5ee4c893 220 fputs("\n*** failed\n", stderr);
221 fputs("n = ", stderr);
5bda60bd 222 mp_writefile(c.mb.m, stderr, 10);
5ee4c893 223 for (i = 0; i < n; i++) {
bb77b1d1 224 fprintf(stderr, "\nr[%lu] = ", (unsigned long)i);
5ee4c893 225 mp_writefile(r[i], stderr, 10);
bb77b1d1 226 fprintf(stderr, "\nm[%lu] = ", (unsigned long)i);
5ee4c893 227 mp_writefile(m[i].m, stderr, 10);
bb77b1d1 228 fprintf(stderr, "\nN[%lu] = ", (unsigned long)i);
5ee4c893 229 mp_writefile(m[i].n, stderr, 10);
bb77b1d1 230 fprintf(stderr, "\nM[%lu] = ", (unsigned long)i);
5ee4c893 231 mp_writefile(m[i].ni, stderr, 10);
232 }
233 fputs("\nresult = ", stderr);
234 mp_writefile(b, stderr, 10);
235 fputs("\nexpect = ", stderr);
236 mp_writefile(a, stderr, 10);
237 fputc('\n', stderr);
238 ok = 0;
239 }
240
5bda60bd 241 for (i = 0; i < n; i++)
242 mp_drop(r[i]);
5ee4c893 243 mp_drop(a);
244 mp_drop(b);
245 mpcrt_destroy(&c);
12ed8a1f 246 xfree(m);
247 xfree(r);
5bda60bd 248 assert(mparena_count(MPARENA_GLOBAL) == 0);
5ee4c893 249 return (ok);
250}
251
252static int crt1(dstr *v) { return verify(1, v); }
253static int crt2(dstr *v) { return verify(2, v); }
254static int crt3(dstr *v) { return verify(3, v); }
255static int crt4(dstr *v) { return verify(4, v); }
256static int crt5(dstr *v) { return verify(5, v); }
257
258static test_chunk tests[] = {
259 { "crt-1", crt1, { &type_mp, &type_mp,
260 &type_mp, 0 } },
261 { "crt-2", crt2, { &type_mp, &type_mp,
262 &type_mp, &type_mp,
263 &type_mp, 0 } },
264 { "crt-3", crt3, { &type_mp, &type_mp,
265 &type_mp, &type_mp,
266 &type_mp, &type_mp,
267 &type_mp, 0 } },
268 { "crt-4", crt4, { &type_mp, &type_mp,
269 &type_mp, &type_mp,
270 &type_mp, &type_mp,
271 &type_mp, &type_mp,
272 &type_mp, 0 } },
273 { "crt-5", crt5, { &type_mp, &type_mp,
274 &type_mp, &type_mp,
275 &type_mp, &type_mp,
276 &type_mp, &type_mp,
277 &type_mp, &type_mp,
278 &type_mp, 0 } },
279 { 0, 0, { 0 } }
280};
281
282int main(int argc, char *argv[])
283{
284 sub_init();
0f00dc4c 285 test_run(argc, argv, tests, SRCDIR "/t/mpcrt");
5ee4c893 286 return (0);
287}
288
289#endif
290
291/*----- That's all, folks -------------------------------------------------*/