40deef8e852bd9b96f506b7f630371e58d2cf82d
[xonotic/d0_blind_id.git] / d0_bignum-tommath.c
1 /*
2  * FILE:        d0_bignum-gmp.c
3  * AUTHOR:      Rudolf Polzer - divVerent@xonotic.org
4  * 
5  * Copyright (c) 2010, Rudolf Polzer
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the copyright holder nor the names of contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  * 
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTOR(S) BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  * $Format:commit %H$
33  * $Id$
34  */
35
36 /* NOTE: this file links against libgmp (http://gmplib.org), which is under the
37  * Lesser General Public License 2.1 or later. You may have to abide to its
38  * terms too if you use this file.
39  * To alternatively link to OpenSSL, provide the option --with-openssl to
40  * ./configure.
41  */
42
43 #ifdef WIN32
44 #include <windows.h>
45 #include <wincrypt.h>
46 #endif
47
48 #include "d0_bignum.h"
49
50 #include <tommath.h>
51 #include <string.h>
52 #include <stdlib.h>
53 #include <assert.h>
54
55 struct d0_bignum_s
56 {
57         mp_int z;
58 };
59
60 static d0_bignum_t temp;
61
62 #include <stdio.h>
63
64 #ifdef WIN32
65 HCRYPTPROV hCryptProv;
66 #else
67 static FILE *randf;
68 #endif
69
70 void rand_bytes(unsigned char *buf, size_t n)
71 {
72 #ifdef WIN32
73         CryptGenRandom(hCryptProv, n, (PBYTE) buf);
74 #else
75         if(!randf)
76                 return;
77         fread(buf, 1, n, randf);
78 #endif
79 }
80
81 D0_WARN_UNUSED_RESULT D0_BOOL d0_bignum_INITIALIZE(void)
82 {
83         D0_BOOL ret = 1;
84         unsigned char buf[256];
85         d0_bignum_init(&temp);
86 #ifdef WIN32
87         {
88                 if(CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
89                 {
90                 }
91                 else if(CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_NEWKEYSET))
92                 {
93                 }
94                 else
95                 {
96                         fprintf(stderr, "WARNING: could not initialize random number generator (CryptAcquireContext failed)\n");
97                         ret = 0;
98                         hCryptProv = NULL;
99                 }
100         }
101 #else
102         randf = fopen("/dev/urandom", "rb");
103         if(!randf)
104                 randf = fopen("/dev/random", "rb");
105         if(randf)
106         {
107                 setbuf(randf, NULL);
108         }
109         else
110         {
111                 fprintf(stderr, "WARNING: could not initialize random number generator (no random device found)\n");
112                 ret = 0;
113         }
114 #endif
115
116         return ret;
117 }
118
119 void d0_bignum_SHUTDOWN(void)
120 {
121         d0_bignum_clear(&temp);
122 #ifdef WIN32
123         if(hCryptProv)
124         {
125                 CryptReleaseContext(hCryptProv, 0);
126                 hCryptProv = NULL;
127         }
128 #endif
129 }
130
131 D0_BOOL d0_iobuf_write_bignum(d0_iobuf_t *buf, const d0_bignum_t *bignum)
132 {
133         static unsigned char numbuf[65536];
134         size_t count = 0;
135         numbuf[0] = (mp_iszero(&bignum->z) ? 0 : (bignum->z.sign == MP_ZPOS) ? 1 : 3);
136         if((numbuf[0] & 3) != 0) // nonzero
137         {
138                 count = mp_unsigned_bin_size(&bignum->z);
139                 if(count > sizeof(numbuf) - 1)
140                         return 0;
141                 mp_to_unsigned_bin(&bignum->z, numbuf+1);
142         }
143         return d0_iobuf_write_packet(buf, numbuf, count + 1);
144 }
145
146 d0_bignum_t *d0_iobuf_read_bignum(d0_iobuf_t *buf, d0_bignum_t *bignum)
147 {
148         static unsigned char numbuf[65536];
149         size_t count = sizeof(numbuf);
150         if(!d0_iobuf_read_packet(buf, numbuf, &count))
151                 return NULL;
152         if(count < 1)
153                 return NULL;
154         if(!bignum) bignum = d0_bignum_new(); if(!bignum) return NULL;
155         if(numbuf[0] & 3) // nonzero
156         {
157                 mp_read_unsigned_bin(&bignum->z, numbuf+1, count-1);
158                 if(numbuf[0] & 2) // negative
159                         bignum->z.sign = MP_NEG;
160         }
161         else // zero
162         {
163                 mp_zero(&bignum->z);
164         }
165         return bignum;
166 }
167
168 ssize_t d0_bignum_export_unsigned(const d0_bignum_t *bignum, void *buf, size_t bufsize)
169 {
170         unsigned long count;
171         count = mp_unsigned_bin_size(&bignum->z);
172         if(count > bufsize)
173                 return -1;
174         if(bufsize > count)
175         {
176                 // pad from left (big endian numbers!)
177                 memset(buf, 0, bufsize - count);
178                 buf += bufsize - count;
179         }
180         bufsize = count;
181         mp_to_unsigned_bin_n(&bignum->z, buf, &bufsize);
182         if(bufsize > count)
183         {
184                 // REALLY BAD
185                 // mpz_sizeinbase lied to us
186                 // buffer overflow
187                 // there is no sane way whatsoever to handle this
188                 abort();
189         }
190         if(bufsize < count)
191         {
192                 // BAD
193                 // mpz_sizeinbase lied to us
194                 // move the number
195                 if(count == 0)
196                 {
197                         memset(buf, 0, count);
198                 }
199                 else
200                 {
201                         memmove(buf + count - bufsize, buf, bufsize);
202                         memset(buf, 0, count - bufsize);
203                 }
204         }
205         return bufsize;
206 }
207
208 d0_bignum_t *d0_bignum_import_unsigned(d0_bignum_t *bignum, const void *buf, size_t bufsize)
209 {
210         size_t count;
211         if(!bignum) bignum = d0_bignum_new(); if(!bignum) return NULL;
212         mp_read_unsigned_bin(&bignum->z, buf, bufsize);
213         return bignum;
214 }
215
216 d0_bignum_t *d0_bignum_new(void)
217 {
218         d0_bignum_t *b = d0_malloc(sizeof(d0_bignum_t));
219         mp_init(&b->z);
220         return b;
221 }
222
223 void d0_bignum_free(d0_bignum_t *a)
224 {
225         mp_clear(&a->z);
226         d0_free(a);
227 }
228
229 void d0_bignum_init(d0_bignum_t *b)
230 {
231         mp_init(&b->z);
232 }
233
234 void d0_bignum_clear(d0_bignum_t *a)
235 {
236         mp_clear(&a->z);
237 }
238
239 size_t d0_bignum_size(const d0_bignum_t *r)
240 {
241         return mp_count_bits(&r->z);
242 }
243
244 int d0_bignum_cmp(const d0_bignum_t *a, const d0_bignum_t *b)
245 {
246         return mp_cmp(&a->z, &b->z);
247 }
248
249 static d0_bignum_t *d0_bignum_rand_0_to_limit(d0_bignum_t *r, const d0_bignum_t *limit)
250 {
251         size_t n = d0_bignum_size(limit);
252         size_t b = (n + 7) / 8;
253         unsigned char mask = "\xFF\x7F\x3F\x1F\x0F\x07\x03\x01"[8*b - n];
254         unsigned char numbuf[65536];
255         assert(b <= sizeof(numbuf));
256         for(;;)
257         {
258                 rand_bytes(&numbuf, b);
259                 numbuf[0] &= mask;
260                 r = d0_bignum_import_unsigned(r, numbuf, b);
261                 if(d0_bignum_cmp(r, limit) < 0)
262                         return r;
263         }
264 }
265
266 d0_bignum_t *d0_bignum_rand_range(d0_bignum_t *r, const d0_bignum_t *min, const d0_bignum_t *max)
267 {
268         mp_sub(&max->z, &min->z, &temp.z);
269         r = d0_bignum_rand_0_to_limit(r, &temp);
270         mp_add(&r->z, &min->z, &r->z);
271         return r;
272 }
273
274 d0_bignum_t *d0_bignum_rand_bit_atmost(d0_bignum_t *r, size_t n)
275 {
276         d0_bignum_one(&temp);
277         d0_bignum_shl(&temp, &temp, n);
278         r = d0_bignum_rand_0_to_limit(r, &temp);
279         return r;
280 }
281
282 d0_bignum_t *d0_bignum_rand_bit_exact(d0_bignum_t *r, size_t n)
283 {
284         d0_bignum_one(&temp);
285         d0_bignum_shl(&temp, &temp, n-1);
286         r = d0_bignum_rand_0_to_limit(r, &temp);
287         d0_bignum_add(r, r, &temp);
288         return r;
289 }
290
291 d0_bignum_t *d0_bignum_zero(d0_bignum_t *r)
292 {
293         if(!r) r = d0_bignum_new(); if(!r) return NULL;
294         mp_zero(&r->z);
295         return r;
296 }
297
298 d0_bignum_t *d0_bignum_one(d0_bignum_t *r)
299 {
300         return d0_bignum_int(r, 1);
301 }
302
303 d0_bignum_t *d0_bignum_int(d0_bignum_t *r, int n)
304 {
305         if(!r) r = d0_bignum_new(); if(!r) return NULL;
306         mp_set_int(&r->z, n);
307         return r;
308 }
309
310 d0_bignum_t *d0_bignum_mov(d0_bignum_t *r, const d0_bignum_t *a)
311 {
312         if(r == a)
313                 return r; // trivial
314         if(!r) r = d0_bignum_new(); if(!r) return NULL;
315         mp_copy(&a->z, &r->z);
316         return r;
317 }
318
319 d0_bignum_t *d0_bignum_neg(d0_bignum_t *r, const d0_bignum_t *a)
320 {
321         if(!r) r = d0_bignum_new(); if(!r) return NULL;
322         mp_neg(&a->z, &r->z);
323         return r;
324 }
325
326 d0_bignum_t *d0_bignum_shl(d0_bignum_t *r, const d0_bignum_t *a, ssize_t n)
327 {
328         if(!r) r = d0_bignum_new(); if(!r) return NULL;
329         if(n > 0)
330                 mp_mul_2d(&a->z,  n, &r->z);
331         else if(n < 0)
332                 mp_div_2d(&a->z, -n, &r->z, NULL);
333         else
334                 mp_copy(&a->z, &r->z);
335         return r;
336 }
337
338 d0_bignum_t *d0_bignum_add(d0_bignum_t *r, const d0_bignum_t *a, const d0_bignum_t *b)
339 {
340         if(!r) r = d0_bignum_new(); if(!r) return NULL;
341         mp_add(&a->z, &b->z, &r->z);
342         return r;
343 }
344
345 d0_bignum_t *d0_bignum_sub(d0_bignum_t *r, const d0_bignum_t *a, const d0_bignum_t *b)
346 {
347         if(!r) r = d0_bignum_new(); if(!r) return NULL;
348         mp_sub(&a->z, &b->z, &r->z);
349         return r;
350 }
351
352 d0_bignum_t *d0_bignum_mul(d0_bignum_t *r, const d0_bignum_t *a, const d0_bignum_t *b)
353 {
354         if(!r) r = d0_bignum_new(); if(!r) return NULL;
355         mp_mul(&a->z, &b->z, &r->z);
356         return r;
357 }
358
359 d0_bignum_t *d0_bignum_divmod(d0_bignum_t *q, d0_bignum_t *m, const d0_bignum_t *a, const d0_bignum_t *b)
360 {
361         if(!q && !m)
362                 m = d0_bignum_new();
363         if(q)
364                 mp_div(&a->z, &b->z, &q->z, m ? &m->z : NULL);
365         else
366                 mp_mod(&a->z, &b->z, &m->z);
367         if(m)
368                 return m;
369         else
370                 return q;
371 }
372
373 d0_bignum_t *d0_bignum_mod_add(d0_bignum_t *r, const d0_bignum_t *a, const d0_bignum_t *b, const d0_bignum_t *m)
374 {
375         if(!r) r = d0_bignum_new(); if(!r) return NULL;
376         mp_addmod(&a->z, &b->z, &m->z, &r->z);
377         return r;
378 }
379
380 d0_bignum_t *d0_bignum_mod_sub(d0_bignum_t *r, const d0_bignum_t *a, const d0_bignum_t *b, const d0_bignum_t *m)
381 {
382         if(!r) r = d0_bignum_new(); if(!r) return NULL;
383         mp_submod(&a->z, &b->z, &m->z, &r->z);
384         return r;
385 }
386
387 d0_bignum_t *d0_bignum_mod_mul(d0_bignum_t *r, const d0_bignum_t *a, const d0_bignum_t *b, const d0_bignum_t *m)
388 {
389         if(!r) r = d0_bignum_new(); if(!r) return NULL;
390         mp_mulmod(&a->z, &b->z, &m->z, &r->z);
391         return r;
392 }
393
394 d0_bignum_t *d0_bignum_mod_pow(d0_bignum_t *r, const d0_bignum_t *a, const d0_bignum_t *b, const d0_bignum_t *m)
395 {
396         if(!r) r = d0_bignum_new(); if(!r) return NULL;
397         mp_exptmod(&a->z, &b->z, &m->z, &r->z);
398         return r;
399 }
400
401 D0_BOOL d0_bignum_mod_inv(d0_bignum_t *r, const d0_bignum_t *a, const d0_bignum_t *m)
402 {
403         // here, r MUST be set, as otherwise we cannot return error state!
404         return mp_invmod(&a->z, &m->z, &r->z) == MP_OKAY;
405 }
406
407 int d0_bignum_isprime(d0_bignum_t *r, int param)
408 {
409         int ret = 0;
410         if(param < 1)
411                 param = 1;
412         mp_prime_is_prime(&r->z, param, &ret);
413         return ret;
414 }
415
416 d0_bignum_t *d0_bignum_gcd(d0_bignum_t *r, d0_bignum_t *s, d0_bignum_t *t, const d0_bignum_t *a, const d0_bignum_t *b)
417 {
418         if(!r) r = d0_bignum_new(); if(!r) return NULL;
419         if(s || t)
420                 mp_exteuclid(&a->z, &b->z, s ? &s->z : NULL, t ? &t->z : NULL, &r->z);
421         else
422                 mp_gcd(&a->z, &b->z, &r->z);
423         return r;
424 }
425
426 char *d0_bignum_tostring(const d0_bignum_t *x, unsigned int base)
427 {
428         static char str[65536];
429         mp_toradix_n(&x->z, str, base, sizeof(str));
430         return str;
431 }