fix const warnings
[xonotic/d0_blind_id.git] / d0_bignum-tommath.c
1 /*
2  * FILE:        d0_bignum-tommath.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 #ifdef WIN32
37 #include <windows.h>
38 #include <wincrypt.h>
39 #endif
40
41 #include "d0_bignum.h"
42
43 #include <tommath.h>
44 #include <string.h>
45 #include <stdlib.h>
46 #include <assert.h>
47
48 struct d0_bignum_s
49 {
50         mp_int z;
51 };
52
53 static d0_bignum_t temp;
54
55 #include <stdio.h>
56
57 #ifdef WIN32
58 HCRYPTPROV hCryptProv;
59 #else
60 static FILE *randf;
61 #endif
62
63 void rand_bytes(unsigned char *buf, size_t n)
64 {
65 #ifdef WIN32
66         CryptGenRandom(hCryptProv, n, (PBYTE) buf);
67 #else
68         if(!randf)
69                 return;
70         fread(buf, 1, n, randf);
71 #endif
72 }
73
74 D0_WARN_UNUSED_RESULT D0_BOOL d0_bignum_INITIALIZE(void)
75 {
76         D0_BOOL ret = 1;
77         unsigned char buf[256];
78         d0_bignum_init(&temp);
79 #ifdef WIN32
80         {
81                 if(CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
82                 {
83                 }
84                 else if(CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_NEWKEYSET))
85                 {
86                 }
87                 else
88                 {
89                         fprintf(stderr, "WARNING: could not initialize random number generator (CryptAcquireContext failed)\n");
90                         ret = 0;
91                         hCryptProv = NULL;
92                 }
93         }
94 #else
95         randf = fopen("/dev/urandom", "rb");
96         if(!randf)
97                 randf = fopen("/dev/random", "rb");
98         if(randf)
99         {
100                 setbuf(randf, NULL);
101         }
102         else
103         {
104                 fprintf(stderr, "WARNING: could not initialize random number generator (no random device found)\n");
105                 ret = 0;
106         }
107 #endif
108
109         return ret;
110 }
111
112 void d0_bignum_SHUTDOWN(void)
113 {
114         d0_bignum_clear(&temp);
115 #ifdef WIN32
116         if(hCryptProv)
117         {
118                 CryptReleaseContext(hCryptProv, 0);
119                 hCryptProv = NULL;
120         }
121 #endif
122 }
123
124 D0_BOOL d0_iobuf_write_bignum(d0_iobuf_t *buf, const d0_bignum_t *bignum)
125 {
126         static unsigned char numbuf[65536];
127         size_t count = 0;
128         numbuf[0] = (mp_iszero(&bignum->z) ? 0 : (bignum->z.sign == MP_ZPOS) ? 1 : 3);
129         if((numbuf[0] & 3) != 0) // nonzero
130         {
131                 count = mp_unsigned_bin_size((mp_int *) &bignum->z);
132                 if(count > sizeof(numbuf) - 1)
133                         return 0;
134                 mp_to_unsigned_bin((mp_int *) &bignum->z, numbuf+1);
135         }
136         return d0_iobuf_write_packet(buf, numbuf, count + 1);
137 }
138
139 d0_bignum_t *d0_iobuf_read_bignum(d0_iobuf_t *buf, d0_bignum_t *bignum)
140 {
141         static unsigned char numbuf[65536];
142         size_t count = sizeof(numbuf);
143         if(!d0_iobuf_read_packet(buf, numbuf, &count))
144                 return NULL;
145         if(count < 1)
146                 return NULL;
147         if(!bignum) bignum = d0_bignum_new(); if(!bignum) return NULL;
148         if(numbuf[0] & 3) // nonzero
149         {
150                 mp_read_unsigned_bin(&bignum->z, numbuf+1, count-1);
151                 if(numbuf[0] & 2) // negative
152                         bignum->z.sign = MP_NEG;
153         }
154         else // zero
155         {
156                 mp_zero(&bignum->z);
157         }
158         return bignum;
159 }
160
161 ssize_t d0_bignum_export_unsigned(const d0_bignum_t *bignum, void *buf, size_t bufsize)
162 {
163         unsigned long bufsize_;
164         unsigned long count;
165         count = mp_unsigned_bin_size((mp_int *) &bignum->z);
166         if(count > bufsize)
167                 return -1;
168         if(bufsize > count)
169         {
170                 // pad from left (big endian numbers!)
171                 memset(buf, 0, bufsize - count);
172                 buf += bufsize - count;
173         }
174         bufsize_ = count;
175         mp_to_unsigned_bin_n((mp_int *) &bignum->z, buf, &bufsize_);
176         bufsize = bufsize_;
177         if(bufsize > count)
178         {
179                 // REALLY BAD
180                 // mpz_sizeinbase lied to us
181                 // buffer overflow
182                 // there is no sane way whatsoever to handle this
183                 abort();
184         }
185         if(bufsize < count)
186         {
187                 // BAD
188                 // mpz_sizeinbase lied to us
189                 // move the number
190                 if(count == 0)
191                 {
192                         memset(buf, 0, count);
193                 }
194                 else
195                 {
196                         memmove(buf + count - bufsize, buf, bufsize);
197                         memset(buf, 0, count - bufsize);
198                 }
199         }
200         return bufsize;
201 }
202
203 d0_bignum_t *d0_bignum_import_unsigned(d0_bignum_t *bignum, const void *buf, size_t bufsize)
204 {
205         size_t count;
206         if(!bignum) bignum = d0_bignum_new(); if(!bignum) return NULL;
207         mp_read_unsigned_bin(&bignum->z, buf, bufsize);
208         return bignum;
209 }
210
211 d0_bignum_t *d0_bignum_new(void)
212 {
213         d0_bignum_t *b = d0_malloc(sizeof(d0_bignum_t));
214         mp_init(&b->z);
215         return b;
216 }
217
218 void d0_bignum_free(d0_bignum_t *a)
219 {
220         mp_clear(&a->z);
221         d0_free(a);
222 }
223
224 void d0_bignum_init(d0_bignum_t *b)
225 {
226         mp_init(&b->z);
227 }
228
229 void d0_bignum_clear(d0_bignum_t *a)
230 {
231         mp_clear(&a->z);
232 }
233
234 size_t d0_bignum_size(const d0_bignum_t *r)
235 {
236         return mp_count_bits((mp_int *) &r->z);
237 }
238
239 int d0_bignum_cmp(const d0_bignum_t *a, const d0_bignum_t *b)
240 {
241         return mp_cmp((mp_int *) &a->z, (mp_int *) &b->z);
242 }
243
244 static d0_bignum_t *d0_bignum_rand_0_to_limit(d0_bignum_t *r, const d0_bignum_t *limit)
245 {
246         size_t n = d0_bignum_size(limit);
247         size_t b = (n + 7) / 8;
248         unsigned char mask = "\xFF\x7F\x3F\x1F\x0F\x07\x03\x01"[8*b - n];
249         unsigned char numbuf[65536];
250         assert(b <= sizeof(numbuf));
251         for(;;)
252         {
253                 rand_bytes(numbuf, b);
254                 numbuf[0] &= mask;
255                 r = d0_bignum_import_unsigned(r, numbuf, b);
256                 if(d0_bignum_cmp(r, limit) < 0)
257                         return r;
258         }
259 }
260
261 d0_bignum_t *d0_bignum_rand_range(d0_bignum_t *r, const d0_bignum_t *min, const d0_bignum_t *max)
262 {
263         mp_sub((mp_int *) &max->z, (mp_int *) &min->z, &temp.z);
264         r = d0_bignum_rand_0_to_limit(r, &temp);
265         mp_add((mp_int *) &r->z, (mp_int *) &min->z, &r->z);
266         return r;
267 }
268
269 d0_bignum_t *d0_bignum_rand_bit_atmost(d0_bignum_t *r, size_t n)
270 {
271         if(!d0_bignum_one(&temp))
272                 return NULL;
273         if(!d0_bignum_shl(&temp, &temp, n))
274                 return NULL;
275         r = d0_bignum_rand_0_to_limit(r, &temp);
276         return r;
277 }
278
279 d0_bignum_t *d0_bignum_rand_bit_exact(d0_bignum_t *r, size_t n)
280 {
281         if(!d0_bignum_one(&temp))
282                 return NULL;
283         if(!d0_bignum_shl(&temp, &temp, n-1))
284                 return NULL;
285         r = d0_bignum_rand_0_to_limit(r, &temp);
286         if(!d0_bignum_add(r, r, &temp))
287                 return NULL;
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((mp_int *) &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((mp_int *) &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((mp_int *) &a->z,  n, &r->z);
331         else if(n < 0)
332                 mp_div_2d((mp_int *) &a->z, -n, &r->z, NULL);
333         else
334                 mp_copy((mp_int *) &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((mp_int *) &a->z, (mp_int *) &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((mp_int *) &a->z, (mp_int *) &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((mp_int *) &a->z, (mp_int *) &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((mp_int *) &a->z, (mp_int *) &b->z, &q->z, m ? &m->z : NULL);
365         else
366                 mp_mod((mp_int *) &a->z, (mp_int *) &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((mp_int *) &a->z, (mp_int *) &b->z, (mp_int *) &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((mp_int *) &a->z, (mp_int *) &b->z, (mp_int *) &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((mp_int *) &a->z, (mp_int *) &b->z, (mp_int *) &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((mp_int *) &a->z, (mp_int *) &b->z, (mp_int *) &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((mp_int *) &a->z, (mp_int *) &m->z, &r->z) == MP_OKAY;
405 }
406
407 int d0_bignum_isprime(const d0_bignum_t *r, int param)
408 {
409         int ret = 0;
410         if(param < 1)
411                 param = 1;
412         mp_prime_is_prime((mp_int *) &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((mp_int *) &a->z, (mp_int *) &b->z, s ? &s->z : NULL, t ? &t->z : NULL, &r->z);
421         else
422                 mp_gcd((mp_int *) &a->z, (mp_int *) &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((mp_int *) &x->z, str, base, sizeof(str));
430         return str;
431 }