1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
|
include private/config
type
mp_digit* = distinct uint32
mp_word* = distinct uint64
const
MP_LT* = -1
MP_EQ* = 0
MP_GT* = 1
MP_ZPOS* = 0
MP_NEG* = 1
MP_OKAY* = 0
MP_MEM* = -2
MP_VAL* = -3
MP_RANGE* = MP_VAL
MP_YES* = 1
MP_NO* = 0
## Primality generation flags
const
LTM_PRIME_BBS* = 0x00000001
LTM_PRIME_SAFE* = 0x00000002
LTM_PRIME_2MSB_ON* = 0x00000008
## you'll have to tune these...
var
KARATSUBA_MUL_CUTOFF* {.importc: "KARATSUBA_MUL_CUTOFF".}: cint
KARATSUBA_SQR_CUTOFF* {.importc: "KARATSUBA_SQR_CUTOFF".}: cint
TOOM_MUL_CUTOFF* {.importc: "TOOM_MUL_CUTOFF".}: cint
TOOM_SQR_CUTOFF* {.importc: "TOOM_SQR_CUTOFF".}: cint
type
mp_int* {.importc: "mp_int", header: "tommath.h", bycopy.} = object
used* {.importc: "used".}: cint
alloc* {.importc: "alloc".}: cint
sign* {.importc: "sign".}: cint
dp* {.importc: "dp".}: ptr mp_digit
## callback for mp_prime_random, should fill dst with random bytes and return how many read [upto len]
type
ltm_prime_callback* = proc (dst: ptr cuchar; len: cint; dat: pointer): cint
template USED*(m: untyped): untyped =
((m).used)
template DIGIT*(m, k: untyped): untyped =
((m).dp[(k)])
template SIGN*(m: untyped): untyped =
((m).sign)
## error code to char* string
proc mp_error_to_string*(code: cint): cstring {.importc: "mp_error_to_string".}
## ---> init and deinit bignum functions <---
## init a bignum
proc mp_init*(a: ptr mp_int): cint {.importc: "mp_init".}
## free a bignum
proc mp_clear*(a: ptr mp_int) {.importc: "mp_clear".}
## init a null terminated series of arguments
proc mp_init_multi*(mp: ptr mp_int): cint {.varargs, importc: "mp_init_multi".}
## clear a null terminated series of arguments
proc mp_clear_multi*(mp: ptr mp_int) {.varargs, importc: "mp_clear_multi".}
## exchange two ints
proc mp_exch*(a: ptr mp_int; b: ptr mp_int) {.importc: "mp_exch".}
## shrink ram required for a bignum
proc mp_shrink*(a: ptr mp_int): cint {.importc: "mp_shrink".}
## grow an int to a given size
proc mp_grow*(a: ptr mp_int; size: cint): cint {.importc: "mp_grow".}
## init to a given number of digits
proc mp_init_size*(a: ptr mp_int; size: cint): cint {.importc: "mp_init_size".}
## ---> Basic Manipulations <---
template mp_iszero*(a: untyped): untyped =
(if ((a).used == 0): MP_YES else: MP_NO)
template mp_iseven*(a: untyped): untyped =
(if (((a).used > 0) and (((a).dp[0] and 1) == 0)): MP_YES else: MP_NO)
template mp_isodd*(a: untyped): untyped =
(if (((a).used > 0) and (((a).dp[0] and 1) == 1)): MP_YES else: MP_NO)
template mp_isneg*(a: untyped): untyped =
(if ((a).sign != MP_ZPOS): MP_YES else: MP_NO)
## set to zero
proc mp_zero*(a: ptr mp_int) {.importc: "mp_zero".}
## set to a digit
proc mp_set*(a: ptr mp_int; b: mp_digit) {.importc: "mp_set".}
## set a 32-bit const
proc mp_set_int*(a: ptr mp_int; b: culong): cint {.importc: "mp_set_int".}
## set a platform dependent unsigned long value
proc mp_set_long*(a: ptr mp_int; b: culong): cint {.importc: "mp_set_long".}
## set a platform dependent unsigned long long value
proc mp_set_long_long*(a: ptr mp_int; b: culonglong): cint {.
importc: "mp_set_long_long".}
## get a 32-bit value
proc mp_get_int*(a: ptr mp_int): culong {.importc: "mp_get_int".}
## get a platform dependent unsigned long value
proc mp_get_long*(a: ptr mp_int): culong {.importc: "mp_get_long".}
## get a platform dependent unsigned long long value
proc mp_get_long_long*(a: ptr mp_int): culonglong {.importc: "mp_get_long_long".}
## initialize and set a digit
proc mp_init_set*(a: ptr mp_int; b: mp_digit): cint {.importc: "mp_init_set".}
## initialize and set 32-bit value
proc mp_init_set_int*(a: ptr mp_int; b: culong): cint {.importc: "mp_init_set_int".}
## copy, b = a
proc mp_copy*(a: ptr mp_int; b: ptr mp_int): cint {.importc: "mp_copy".}
## inits and copies, a = b
proc mp_init_copy*(a: ptr mp_int; b: ptr mp_int): cint {.importc: "mp_init_copy".}
## trim unused digits
proc mp_clamp*(a: ptr mp_int) {.importc: "mp_clamp".}
## import binary data
proc mp_import*(rop: ptr mp_int; count: csize; order: cint; size: csize; endian: cint;
nails: csize; op: pointer): cint {.importc: "mp_import".}
## export binary data
proc mp_export*(rop: pointer; countp: ptr csize; order: cint; size: csize; endian: cint;
nails: csize; op: ptr mp_int): cint {.importc: "mp_export".}
## ---> digit manipulation <---
## right shift by "b" digits
proc mp_rshd*(a: ptr mp_int; b: cint) {.importc: "mp_rshd".}
## left shift by "b" digits
proc mp_lshd*(a: ptr mp_int; b: cint): cint {.importc: "mp_lshd".}
## c = a / 2**b, implemented as c = a >> b
proc mp_div_2d*(a: ptr mp_int; b: cint; c: ptr mp_int; d: ptr mp_int): cint {.
importc: "mp_div_2d".}
## b = a/2
proc mp_div_2*(a: ptr mp_int; b: ptr mp_int): cint {.importc: "mp_div_2".}
## c = a * 2**b, implemented as c = a << b
proc mp_mul_2d*(a: ptr mp_int; b: cint; c: ptr mp_int): cint {.importc: "mp_mul_2d".}
## b = a*2
proc mp_mul_2*(a: ptr mp_int; b: ptr mp_int): cint {.importc: "mp_mul_2".}
## c = a mod 2**b
proc mp_mod_2d*(a: ptr mp_int; b: cint; c: ptr mp_int): cint {.importc: "mp_mod_2d".}
## computes a = 2**b
proc mp_2expt*(a: ptr mp_int; b: cint): cint {.importc: "mp_2expt".}
## Counts the number of lsbs which are zero before the first zero bit
proc mp_cnt_lsb*(a: ptr mp_int): cint {.importc: "mp_cnt_lsb".}
## I Love Earth!
## makes a pseudo-random int of a given size
proc mp_rand*(a: ptr mp_int; digits: cint): cint {.importc: "mp_rand".}
## ---> binary operations <---
## c = a XOR b
proc mp_xor*(a: ptr mp_int; b: ptr mp_int; c: ptr mp_int): cint {.importc: "mp_xor".}
## c = a OR b
proc mp_or*(a: ptr mp_int; b: ptr mp_int; c: ptr mp_int): cint {.importc: "mp_or".}
## c = a AND b
proc mp_and*(a: ptr mp_int; b: ptr mp_int; c: ptr mp_int): cint {.importc: "mp_and".}
## ---> Basic arithmetic <---
## b = -a
proc mp_neg*(a: ptr mp_int; b: ptr mp_int): cint {.importc: "mp_neg".}
## b = |a|
proc mp_abs*(a: ptr mp_int; b: ptr mp_int): cint {.importc: "mp_abs".}
## compare a to b
proc mp_cmp*(a: ptr mp_int; b: ptr mp_int): cint {.importc: "mp_cmp".}
## compare |a| to |b|
proc mp_cmp_mag*(a: ptr mp_int; b: ptr mp_int): cint {.importc: "mp_cmp_mag".}
## c = a + b
proc mp_add*(a: ptr mp_int; b: ptr mp_int; c: ptr mp_int): cint {.importc: "mp_add".}
## c = a - b
proc mp_sub*(a: ptr mp_int; b: ptr mp_int; c: ptr mp_int): cint {.importc: "mp_sub".}
## c = a * b
proc mp_mul*(a: ptr mp_int; b: ptr mp_int; c: ptr mp_int): cint {.importc: "mp_mul".}
## b = a*a
proc mp_sqr*(a: ptr mp_int; b: ptr mp_int): cint {.importc: "mp_sqr".}
## a/b => cb + d == a
proc mp_div*(a: ptr mp_int; b: ptr mp_int; c: ptr mp_int; d: ptr mp_int): cint {.
importc: "mp_div".}
## c = a mod b, 0 <= c < b
proc mp_mod*(a: ptr mp_int; b: ptr mp_int; c: ptr mp_int): cint {.importc: "mp_mod".}
## ---> single digit functions <---
## compare against a single digit
proc mp_cmp_d*(a: ptr mp_int; b: mp_digit): cint {.importc: "mp_cmp_d".}
## c = a + b
proc mp_add_d*(a: ptr mp_int; b: mp_digit; c: ptr mp_int): cint {.importc: "mp_add_d".}
## c = a - b
proc mp_sub_d*(a: ptr mp_int; b: mp_digit; c: ptr mp_int): cint {.importc: "mp_sub_d".}
## c = a * b
proc mp_mul_d*(a: ptr mp_int; b: mp_digit; c: ptr mp_int): cint {.importc: "mp_mul_d".}
## a/b => cb + d == a
proc mp_div_d*(a: ptr mp_int; b: mp_digit; c: ptr mp_int; d: ptr mp_digit): cint {.
importc: "mp_div_d".}
## a/3 => 3c + d == a
proc mp_div_3*(a: ptr mp_int; c: ptr mp_int; d: ptr mp_digit): cint {.importc: "mp_div_3".}
## c = a**b
proc mp_expt_d*(a: ptr mp_int; b: mp_digit; c: ptr mp_int): cint {.importc: "mp_expt_d".}
proc mp_expt_d_ex*(a: ptr mp_int; b: mp_digit; c: ptr mp_int; fast: cint): cint {.
importc: "mp_expt_d_ex".}
## c = a mod b, 0 <= c < b
proc mp_mod_d*(a: ptr mp_int; b: mp_digit; c: ptr mp_digit): cint {.importc: "mp_mod_d".}
## ---> number theory <---
## d = a + b (mod c)
proc mp_addmod*(a: ptr mp_int; b: ptr mp_int; c: ptr mp_int; d: ptr mp_int): cint {.
importc: "mp_addmod".}
## d = a - b (mod c)
proc mp_submod*(a: ptr mp_int; b: ptr mp_int; c: ptr mp_int; d: ptr mp_int): cint {.
importc: "mp_submod".}
## d = a * b (mod c)
proc mp_mulmod*(a: ptr mp_int; b: ptr mp_int; c: ptr mp_int; d: ptr mp_int): cint {.
importc: "mp_mulmod".}
## c = a * a (mod b)
proc mp_sqrmod*(a: ptr mp_int; b: ptr mp_int; c: ptr mp_int): cint {.importc: "mp_sqrmod".}
## c = 1/a (mod b)
proc mp_invmod*(a: ptr mp_int; b: ptr mp_int; c: ptr mp_int): cint {.importc: "mp_invmod".}
## c = (a, b)
proc mp_gcd*(a: ptr mp_int; b: ptr mp_int; c: ptr mp_int): cint {.importc: "mp_gcd".}
## produces value such that U1*a + U2*b = U3
proc mp_exteuclid*(a: ptr mp_int; b: ptr mp_int; U1: ptr mp_int; U2: ptr mp_int;
U3: ptr mp_int): cint {.importc: "mp_exteuclid".}
## c = [a, b] or (a*b)/(a, b)
proc mp_lcm*(a: ptr mp_int; b: ptr mp_int; c: ptr mp_int): cint {.importc: "mp_lcm".}
## finds one of the b'th root of a, such that |c|**b <= |a|
##
## returns error if a < 0 and b is even
##
proc mp_n_root*(a: ptr mp_int; b: mp_digit; c: ptr mp_int): cint {.importc: "mp_n_root".}
proc mp_n_root_ex*(a: ptr mp_int; b: mp_digit; c: ptr mp_int; fast: cint): cint {.
importc: "mp_n_root_ex".}
## special sqrt algo
proc mp_sqrt*(arg: ptr mp_int; ret: ptr mp_int): cint {.importc: "mp_sqrt".}
## special sqrt (mod prime)
proc mp_sqrtmod_prime*(arg: ptr mp_int; prime: ptr mp_int; ret: ptr mp_int): cint {.
importc: "mp_sqrtmod_prime".}
## is number a square?
proc mp_is_square*(arg: ptr mp_int; ret: ptr cint): cint {.importc: "mp_is_square".}
## computes the jacobi c = (a | n) (or Legendre if b is prime)
proc mp_jacobi*(a: ptr mp_int; n: ptr mp_int; c: ptr cint): cint {.importc: "mp_jacobi".}
## used to setup the Barrett reduction for a given modulus b
proc mp_reduce_setup*(a: ptr mp_int; b: ptr mp_int): cint {.importc: "mp_reduce_setup".}
## Barrett Reduction, computes a (mod b) with a precomputed value c
##
## Assumes that 0 < a <= b*b, note if 0 > a > -(b*b) then you can merely
## compute the reduction as -1 * mp_reduce(mp_abs(a)) [pseudo code].
##
proc mp_reduce*(a: ptr mp_int; b: ptr mp_int; c: ptr mp_int): cint {.importc: "mp_reduce".}
## setups the montgomery reduction
proc mp_montgomery_setup*(a: ptr mp_int; mp: ptr mp_digit): cint {.
importc: "mp_montgomery_setup".}
## computes a = B**n mod b without division or multiplication useful for
## normalizing numbers in a Montgomery system.
##
proc mp_montgomery_calc_normalization*(a: ptr mp_int; b: ptr mp_int): cint {.
importc: "mp_montgomery_calc_normalization".}
## computes x/R == x (mod N) via Montgomery Reduction
proc mp_montgomery_reduce*(a: ptr mp_int; m: ptr mp_int; mp: mp_digit): cint {.
importc: "mp_montgomery_reduce".}
## returns 1 if a is a valid DR modulus
proc mp_dr_is_modulus*(a: ptr mp_int): cint {.importc: "mp_dr_is_modulus".}
## sets the value of "d" required for mp_dr_reduce
proc mp_dr_setup*(a: ptr mp_int; d: ptr mp_digit) {.importc: "mp_dr_setup".}
## reduces a modulo b using the Diminished Radix method
proc mp_dr_reduce*(a: ptr mp_int; b: ptr mp_int; mp: mp_digit): cint {.
importc: "mp_dr_reduce".}
## returns true if a can be reduced with mp_reduce_2k
proc mp_reduce_is_2k*(a: ptr mp_int): cint {.importc: "mp_reduce_is_2k".}
## determines k value for 2k reduction
proc mp_reduce_2k_setup*(a: ptr mp_int; d: ptr mp_digit): cint {.
importc: "mp_reduce_2k_setup".}
## reduces a modulo b where b is of the form 2**p - k [0 <= a]
proc mp_reduce_2k*(a: ptr mp_int; n: ptr mp_int; d: mp_digit): cint {.
importc: "mp_reduce_2k".}
## returns true if a can be reduced with mp_reduce_2k_l
proc mp_reduce_is_2k_l*(a: ptr mp_int): cint {.importc: "mp_reduce_is_2k_l".}
## determines k value for 2k reduction
proc mp_reduce_2k_setup_l*(a: ptr mp_int; d: ptr mp_int): cint {.
importc: "mp_reduce_2k_setup_l".}
## reduces a modulo b where b is of the form 2**p - k [0 <= a]
proc mp_reduce_2k_l*(a: ptr mp_int; n: ptr mp_int; d: ptr mp_int): cint {.
importc: "mp_reduce_2k_l".}
## d = a**b (mod c)
proc mp_exptmod*(a: ptr mp_int; b: ptr mp_int; c: ptr mp_int; d: ptr mp_int): cint {.
importc: "mp_exptmod".}
## ---> Primes <---
## number of primes
const
PRIME_SIZE* = 256
## table of first PRIME_SIZE primes
var ltm_prime_tab* {.importc: "ltm_prime_tab".}: array[PRIME_SIZE,
mp_digit]
## result=1 if a is divisible by one of the first PRIME_SIZE primes
proc mp_prime_is_divisible*(a: ptr mp_int; result: ptr cint): cint {.
importc: "mp_prime_is_divisible".}
## performs one Fermat test of "a" using base "b".
## Sets result to 0 if composite or 1 if probable prime
##
proc mp_prime_fermat*(a: ptr mp_int; b: ptr mp_int; result: ptr cint): cint {.
importc: "mp_prime_fermat".}
## performs one Miller-Rabin test of "a" using base "b".
## Sets result to 0 if composite or 1 if probable prime
##
proc mp_prime_miller_rabin*(a: ptr mp_int; b: ptr mp_int; result: ptr cint): cint {.
importc: "mp_prime_miller_rabin".}
## This gives [for a given bit size] the number of trials required
## such that Miller-Rabin gives a prob of failure lower than 2^-96
##
proc mp_prime_rabin_miller_trials*(size: cint): cint {.
importc: "mp_prime_rabin_miller_trials".}
## performs t rounds of Miller-Rabin on "a" using the first
## t prime bases. Also performs an initial sieve of trial
## division. Determines if "a" is prime with probability
## of error no more than (1/4)**t.
##
## Sets result to 1 if probably prime, 0 otherwise
##
proc mp_prime_is_prime*(a: ptr mp_int; t: cint; result: ptr cint): cint {.
importc: "mp_prime_is_prime".}
## finds the next prime after the number "a" using "t" trials
## of Miller-Rabin.
##
## bbs_style = 1 means the prime must be congruent to 3 mod 4
##
proc mp_prime_next_prime*(a: ptr mp_int; t: cint; bbs_style: cint): cint {.
importc: "mp_prime_next_prime".}
## makes a truly random prime of a given size (bytes),
## call with bbs = 1 if you want it to be congruent to 3 mod 4
##
## You have to supply a callback which fills in a buffer with random bytes. "dat" is a parameter you can
## have passed to the callback (e.g. a state or something). This function doesn't use "dat" itself
## so it can be NULL
##
## The prime generated will be larger than 2^(8*size).
##
template mp_prime_random*(a, t, size, bbs, cb, dat: untyped): untyped =
mp_prime_random_ex(a, t, ((size) * 8) + 1, if (bbs == 1): LTM_PRIME_BBS else: 0, cb, dat)
## makes a truly random prime of a given size (bits),
##
## Flags are as follows:
##
## LTM_PRIME_BBS - make prime congruent to 3 mod 4
## LTM_PRIME_SAFE - make sure (p-1)/2 is prime as well (implies LTM_PRIME_BBS)
## LTM_PRIME_2MSB_ON - make the 2nd highest bit one
##
## You have to supply a callback which fills in a buffer with random bytes. "dat" is a parameter you can
## have passed to the callback (e.g. a state or something). This function doesn't use "dat" itself
## so it can be NULL
##
##
proc mp_prime_random_ex*(a: ptr mp_int; t: cint; size: cint; flags: cint;
cb: ltm_prime_callback; dat: pointer): cint {.
importc: "mp_prime_random_ex".}
## ---> radix conversion <---
proc mp_count_bits*(a: ptr mp_int): cint {.importc: "mp_count_bits".}
proc mp_unsigned_bin_size*(a: ptr mp_int): cint {.importc: "mp_unsigned_bin_size".}
proc mp_read_unsigned_bin*(a: ptr mp_int; b: ptr cuchar; c: cint): cint {.
importc: "mp_read_unsigned_bin".}
proc mp_to_unsigned_bin*(a: ptr mp_int; b: ptr cuchar): cint {.
importc: "mp_to_unsigned_bin".}
proc mp_to_unsigned_bin_n*(a: ptr mp_int; b: ptr cuchar; outlen: ptr culong): cint {.
importc: "mp_to_unsigned_bin_n".}
proc mp_signed_bin_size*(a: ptr mp_int): cint {.importc: "mp_signed_bin_size".}
proc mp_read_signed_bin*(a: ptr mp_int; b: ptr cuchar; c: cint): cint {.
importc: "mp_read_signed_bin".}
proc mp_to_signed_bin*(a: ptr mp_int; b: ptr cuchar): cint {.
importc: "mp_to_signed_bin".}
proc mp_to_signed_bin_n*(a: ptr mp_int; b: ptr cuchar; outlen: ptr culong): cint {.
importc: "mp_to_signed_bin_n".}
proc mp_read_radix*(a: ptr mp_int; str: cstring; radix: cint): cint {.
importc: "mp_read_radix".}
proc mp_toradix*(a: ptr mp_int; str: cstring; radix: cint): cint {.importc: "mp_toradix".}
proc mp_toradix_n*(a: ptr mp_int; str: cstring; radix: cint; maxlen: cint): cint {.
importc: "mp_toradix_n".}
proc mp_radix_size*(a: ptr mp_int; radix: cint; size: ptr cint): cint {.
importc: "mp_radix_size".}
proc mp_fread*(a: ptr mp_int; radix: cint; stream: ptr FILE): cint {.
importc: "mp_fread".}
proc mp_fwrite*(a: ptr mp_int; radix: cint; stream: ptr FILE): cint {.
importc: "mp_fwrite".}
template mp_read_raw*(mp, str, len: untyped): untyped =
mp_read_signed_bin((mp), (str), (len))
template mp_raw_size*(mp: untyped): untyped =
mp_signed_bin_size(mp)
template mp_toraw*(mp, str: untyped): untyped =
mp_to_signed_bin((mp), (str))
template mp_read_mag*(mp, str, len: untyped): untyped =
mp_read_unsigned_bin((mp), (str), (len))
template mp_mag_size*(mp: untyped): untyped =
mp_unsigned_bin_size(mp)
template mp_tomag*(mp, str: untyped): untyped =
mp_to_unsigned_bin((mp), (str))
template mp_tobinary*(M, S: untyped): untyped =
mp_toradix((M), (S), 2)
template mp_tooctal*(M, S: untyped): untyped =
mp_toradix((M), (S), 8)
template mp_todecimal*(M, S: untyped): untyped =
mp_toradix((M), (S), 10)
template mp_tohex*(M, S: untyped): untyped =
mp_toradix((M), (S), 16)
|