Revert "Revert "and added files""
[bcm963xx.git] / userapps / opensource / sshd / libtommath / bn_radix.c
1 /* LibTomMath, multiple-precision integer library -- Tom St Denis
2  *
3  * LibTomMath is library that provides for multiple-precision
4  * integer arithmetic as well as number theoretic functionality.
5  *
6  * The library is designed directly after the MPI library by
7  * Michael Fromberger but has been written from scratch with
8  * additional optimizations in place.
9  *
10  * The library is free for all purposes without any express
11  * guarantee it works.
12  *
13  * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org
14  */
15 #include <tommath.h>
16
17 /* chars used in radix conversions */
18 static const char *s_rmap = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/";
19
20 /* read a string [ASCII] in a given radix */
21 int
22 mp_read_radix (mp_int * a, char *str, int radix)
23 {
24   int     y, res, neg;
25   char    ch;
26
27   if (radix < 2 || radix > 64) {
28     return MP_VAL;
29   }
30
31   if (*str == '-') {
32     ++str;
33     neg = MP_NEG;
34   } else {
35     neg = MP_ZPOS;
36   }
37
38   mp_zero (a);
39   while (*str) {
40     ch = (char) ((radix < 36) ? toupper (*str) : *str);
41     for (y = 0; y < 64; y++) {
42       if (ch == s_rmap[y]) {
43     break;
44       }
45     }
46
47     if (y < radix) {
48       if ((res = mp_mul_d (a, (mp_digit) radix, a)) != MP_OKAY) {
49     return res;
50       }
51       if ((res = mp_add_d (a, (mp_digit) y, a)) != MP_OKAY) {
52     return res;
53       }
54     } else {
55       break;
56     }
57     ++str;
58   }
59   if (mp_iszero(a) != 1) {
60      a->sign = neg;
61   }
62   return MP_OKAY;
63 }
64
65 /* stores a bignum as a ASCII string in a given radix (2..64) */
66 int
67 mp_toradix (mp_int * a, char *str, int radix)
68 {
69   int     res, digs;
70   mp_int  t;
71   mp_digit d;
72   char   *_s = str;
73
74   if (radix < 2 || radix > 64) {
75     return MP_VAL;
76   }
77   
78   /* quick out if its zero */
79   if (mp_iszero(a) == 1) {
80      *str++ = '0';
81      *str = '\0';
82      return MP_OKAY;
83   }
84   
85
86   if ((res = mp_init_copy (&t, a)) != MP_OKAY) {
87     return res;
88   }
89
90   if (t.sign == MP_NEG) {
91     ++_s;
92     *str++ = '-';
93     t.sign = MP_ZPOS;
94   }
95
96   digs = 0;
97   while (mp_iszero (&t) == 0) {
98     if ((res = mp_div_d (&t, (mp_digit) radix, &t, &d)) != MP_OKAY) {
99       mp_clear (&t);
100       return res;
101     }
102     *str++ = s_rmap[d];
103     ++digs;
104   }
105   bn_reverse ((unsigned char *)_s, digs);
106   *str++ = '\0';
107   mp_clear (&t);
108   return MP_OKAY;
109 }
110
111 /* returns size of ASCII reprensentation */
112 int
113 mp_radix_size (mp_int * a, int radix)
114 {
115   int     res, digs;
116   mp_int  t;
117   mp_digit d;
118
119   /* special case for binary */
120   if (radix == 2) {
121     return mp_count_bits (a) + (a->sign == MP_NEG ? 1 : 0) + 1;
122   }
123
124   if (radix < 2 || radix > 64) {
125     return 0;
126   }
127
128   if ((res = mp_init_copy (&t, a)) != MP_OKAY) {
129     return 0;
130   }
131
132   digs = 0;
133   if (t.sign == MP_NEG) {
134     ++digs;
135     t.sign = MP_ZPOS;
136   }
137
138   while (mp_iszero (&t) == 0) {
139     if ((res = mp_div_d (&t, (mp_digit) radix, &t, &d)) != MP_OKAY) {
140       mp_clear (&t);
141       return 0;
142     }
143     ++digs;
144   }
145   mp_clear (&t);
146   return digs + 1;
147 }
148
149 /* read a bigint from a file stream in ASCII */
150 int mp_fread(mp_int *a, int radix, FILE *stream)
151 {
152    int err, ch, neg, y;
153    
154    /* clear a */
155    mp_zero(a);
156    
157    /* if first digit is - then set negative */
158    ch = fgetc(stream);
159    if (ch == '-') {
160       neg = MP_NEG;
161       ch = fgetc(stream);
162    } else {
163       neg = MP_ZPOS;
164    }
165    
166    for (;;) {
167       /* find y in the radix map */
168       for (y = 0; y < radix; y++) {
169           if (s_rmap[y] == ch) {
170              break;
171           }
172       }
173       if (y == radix) {
174          break;
175       }
176       
177       /* shift up and add */
178       if ((err = mp_mul_d(a, radix, a)) != MP_OKAY) {
179          return err;
180       }
181       if ((err = mp_add_d(a, y, a)) != MP_OKAY) {
182          return err;
183       }
184       
185       ch = fgetc(stream);
186    }
187    if (mp_cmp_d(a, 0) != MP_EQ) {
188       a->sign = neg;
189    }
190    
191    return MP_OKAY;
192 }
193
194 int mp_fwrite(mp_int *a, int radix, FILE *stream)
195 {
196    char *buf;
197    int err, len, x;
198    
199    len = mp_radix_size(a, radix);
200    if (len == 0) {
201       return MP_VAL;
202    }
203    
204    buf = malloc(len);
205    if (buf == NULL) {
206       return MP_MEM;
207    }
208    
209    if ((err = mp_toradix(a, buf, radix)) != MP_OKAY) {
210       free(buf);
211       return err;
212    }
213    
214    for (x = 0; x < len; x++) {
215        if (fputc(buf[x], stream) == EOF) {
216           free(buf);
217           return MP_VAL;
218        }
219    }
220    
221    free(buf);
222    return MP_OKAY;
223 }
224