1 /*
2 * *****************************************************************************
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 *
6 * Copyright (c) 2018-2021 Gavin D. Howard and contributors.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
10 *
11 * * Redistributions of source code must retain the above copyright notice, this
12 * list of conditions and the following disclaimer.
13 *
14 * * Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 *
30 * *****************************************************************************
31 *
32 * The public functions for libbc.
33 *
34 */
35
36 #if BC_ENABLE_LIBRARY
37
38 #include <setjmp.h>
39 #include <string.h>
40 #include <time.h>
41
42 #include <bcl.h>
43
44 #include <library.h>
45 #include <num.h>
46 #include <vm.h>
47
48 static void bcl_num_destruct(void *num);
49
bcl_handleSignal(void)50 void bcl_handleSignal(void) {
51
52 // Signal already in flight, or bc is not executing.
53 if (vm.sig || !vm.running) return;
54
55 vm.sig = 1;
56
57 assert(vm.jmp_bufs.len);
58
59 if (!vm.sig_lock) BC_VM_JMP;
60 }
61
bcl_running(void)62 bool bcl_running(void) {
63 return vm.running != 0;
64 }
65
bcl_init(void)66 BclError bcl_init(void) {
67
68 BclError e = BCL_ERROR_NONE;
69
70 vm.refs += 1;
71
72 if (vm.refs > 1) return e;
73
74 vm.ctxts.v = NULL;
75 vm.jmp_bufs.v = NULL;
76 vm.out.v = NULL;
77
78 vm.abrt = false;
79
80 BC_SIG_LOCK;
81
82 bc_vec_init(&vm.jmp_bufs, sizeof(sigjmp_buf), NULL);
83
84 BC_FUNC_HEADER_INIT(err);
85
86 bc_vm_init();
87
88 bc_vec_init(&vm.ctxts, sizeof(BclContext), NULL);
89 bc_vec_init(&vm.out, sizeof(uchar), NULL);
90
91 srand((unsigned int) time(NULL));
92 bc_rand_init(&vm.rng);
93
94 err:
95 if (BC_ERR(vm.err)) {
96 if (vm.out.v != NULL) bc_vec_free(&vm.out);
97 if (vm.jmp_bufs.v != NULL) bc_vec_free(&vm.jmp_bufs);
98 if (vm.ctxts.v != NULL) bc_vec_free(&vm.ctxts);
99 }
100
101 BC_FUNC_FOOTER_UNLOCK(e);
102
103 assert(!vm.running && !vm.sig && !vm.sig_lock);
104
105 return e;
106 }
107
bcl_pushContext(BclContext ctxt)108 BclError bcl_pushContext(BclContext ctxt) {
109
110 BclError e = BCL_ERROR_NONE;
111
112 BC_FUNC_HEADER_LOCK(err);
113
114 bc_vec_push(&vm.ctxts, &ctxt);
115
116 err:
117 BC_FUNC_FOOTER_UNLOCK(e);
118 return e;
119 }
120
bcl_popContext(void)121 void bcl_popContext(void) {
122 if (vm.ctxts.len) bc_vec_pop(&vm.ctxts);
123 }
124
bcl_context(void)125 BclContext bcl_context(void) {
126 if (!vm.ctxts.len) return NULL;
127 return *((BclContext*) bc_vec_top(&vm.ctxts));
128 }
129
bcl_free(void)130 void bcl_free(void) {
131
132 vm.refs -= 1;
133
134 if (vm.refs) return;
135
136 BC_SIG_LOCK;
137
138 #ifndef NDEBUG
139 bc_rand_free(&vm.rng);
140 bc_vec_free(&vm.out);
141
142 {
143 size_t i;
144
145 for (i = 0; i < vm.ctxts.len; ++i) {
146 BclContext ctxt = *((BclContext*) bc_vec_item(&vm.ctxts, i));
147 bcl_ctxt_free(ctxt);
148 }
149 }
150
151 bc_vec_free(&vm.ctxts);
152 #endif // NDEBUG
153
154 bc_vm_atexit();
155
156 BC_SIG_UNLOCK;
157
158 memset(&vm, 0, sizeof(BcVm));
159
160 assert(!vm.running && !vm.sig && !vm.sig_lock);
161 }
162
bcl_gc(void)163 void bcl_gc(void) {
164 bc_vm_freeTemps();
165 vm.temps.len = 0;
166 }
167
bcl_abortOnFatalError(void)168 bool bcl_abortOnFatalError(void) {
169 return vm.abrt;
170 }
171
bcl_setAbortOnFatalError(bool abrt)172 void bcl_setAbortOnFatalError(bool abrt) {
173 vm.abrt = abrt;
174 }
175
bcl_ctxt_create(void)176 BclContext bcl_ctxt_create(void) {
177
178 BclContext ctxt = NULL;
179
180 BC_FUNC_HEADER_LOCK(err);
181
182 ctxt = bc_vm_malloc(sizeof(BclCtxt));
183
184 bc_vec_init(&ctxt->nums, sizeof(BcNum), bcl_num_destruct);
185 bc_vec_init(&ctxt->free_nums, sizeof(BclNumber), NULL);
186
187 ctxt->scale = 0;
188 ctxt->ibase = 10;
189 ctxt->obase= 10;
190
191 err:
192 if (BC_ERR(vm.err && ctxt != NULL)) {
193 if (ctxt->nums.v != NULL) bc_vec_free(&ctxt->nums);
194 free(ctxt);
195 ctxt = NULL;
196 }
197
198 BC_FUNC_FOOTER_NO_ERR;
199
200 assert(!vm.running && !vm.sig && !vm.sig_lock);
201
202 return ctxt;
203 }
204
bcl_ctxt_free(BclContext ctxt)205 void bcl_ctxt_free(BclContext ctxt) {
206 BC_SIG_LOCK;
207 bc_vec_free(&ctxt->free_nums);
208 bc_vec_free(&ctxt->nums);
209 free(ctxt);
210 BC_SIG_UNLOCK;
211 }
212
bcl_ctxt_freeNums(BclContext ctxt)213 void bcl_ctxt_freeNums(BclContext ctxt) {
214 bc_vec_popAll(&ctxt->nums);
215 bc_vec_popAll(&ctxt->free_nums);
216 }
217
bcl_ctxt_scale(BclContext ctxt)218 size_t bcl_ctxt_scale(BclContext ctxt) {
219 return ctxt->scale;
220 }
221
bcl_ctxt_setScale(BclContext ctxt,size_t scale)222 void bcl_ctxt_setScale(BclContext ctxt, size_t scale) {
223 ctxt->scale = scale;
224 }
225
bcl_ctxt_ibase(BclContext ctxt)226 size_t bcl_ctxt_ibase(BclContext ctxt) {
227 return ctxt->ibase;
228 }
229
bcl_ctxt_setIbase(BclContext ctxt,size_t ibase)230 void bcl_ctxt_setIbase(BclContext ctxt, size_t ibase) {
231 if (ibase < BC_NUM_MIN_BASE) ibase = BC_NUM_MIN_BASE;
232 else if (ibase > BC_NUM_MAX_IBASE) ibase = BC_NUM_MAX_IBASE;
233 ctxt->ibase = ibase;
234 }
235
bcl_ctxt_obase(BclContext ctxt)236 size_t bcl_ctxt_obase(BclContext ctxt) {
237 return ctxt->obase;
238 }
239
bcl_ctxt_setObase(BclContext ctxt,size_t obase)240 void bcl_ctxt_setObase(BclContext ctxt, size_t obase) {
241 ctxt->obase = obase;
242 }
243
bcl_err(BclNumber n)244 BclError bcl_err(BclNumber n) {
245
246 BclContext ctxt;
247
248 BC_CHECK_CTXT_ERR(ctxt);
249
250 if (n.i >= ctxt->nums.len) {
251 if (n.i > 0 - (size_t) BCL_ERROR_NELEMS) return (BclError) (0 - n.i);
252 else return BCL_ERROR_INVALID_NUM;
253 }
254 else return BCL_ERROR_NONE;
255 }
256
bcl_num_insert(BclContext ctxt,BcNum * restrict n)257 static BclNumber bcl_num_insert(BclContext ctxt, BcNum *restrict n) {
258
259 BclNumber idx;
260
261 if (ctxt->free_nums.len) {
262
263 BcNum *ptr;
264
265 idx = *((BclNumber*) bc_vec_top(&ctxt->free_nums));
266
267 bc_vec_pop(&ctxt->free_nums);
268
269 ptr = bc_vec_item(&ctxt->nums, idx.i);
270 memcpy(ptr, n, sizeof(BcNum));
271 }
272 else {
273 idx.i = ctxt->nums.len;
274 bc_vec_push(&ctxt->nums, n);
275 }
276
277 assert(!vm.running && !vm.sig && !vm.sig_lock);
278
279 return idx;
280 }
281
bcl_num_create(void)282 BclNumber bcl_num_create(void) {
283
284 BclError e = BCL_ERROR_NONE;
285 BcNum n;
286 BclNumber idx;
287 BclContext ctxt;
288
289 BC_CHECK_CTXT(ctxt);
290
291 BC_FUNC_HEADER_LOCK(err);
292
293 bc_vec_grow(&ctxt->nums, 1);
294
295 bc_num_init(&n, BC_NUM_DEF_SIZE);
296
297 err:
298 BC_FUNC_FOOTER_UNLOCK(e);
299 BC_MAYBE_SETUP(ctxt, e, n, idx);
300
301 assert(!vm.running && !vm.sig && !vm.sig_lock);
302
303 return idx;
304 }
305
bcl_num_dtor(BclContext ctxt,BclNumber n,BcNum * restrict num)306 static void bcl_num_dtor(BclContext ctxt, BclNumber n, BcNum *restrict num) {
307
308 BC_SIG_ASSERT_LOCKED;
309
310 assert(num != NULL && num->num != NULL);
311
312 bcl_num_destruct(num);
313 bc_vec_push(&ctxt->free_nums, &n);
314 }
315
bcl_num_free(BclNumber n)316 void bcl_num_free(BclNumber n) {
317
318 BcNum *num;
319 BclContext ctxt;
320
321 BC_CHECK_CTXT_ASSERT(ctxt);
322
323 BC_SIG_LOCK;
324
325 assert(n.i < ctxt->nums.len);
326
327 num = BC_NUM(ctxt, n);
328
329 bcl_num_dtor(ctxt, n, num);
330
331 BC_SIG_UNLOCK;
332 }
333
bcl_copy(BclNumber d,BclNumber s)334 BclError bcl_copy(BclNumber d, BclNumber s) {
335
336 BclError e = BCL_ERROR_NONE;
337 BcNum *dest, *src;
338 BclContext ctxt;
339
340 BC_CHECK_CTXT_ERR(ctxt);
341
342 BC_FUNC_HEADER_LOCK(err);
343
344 assert(d.i < ctxt->nums.len && s.i < ctxt->nums.len);
345
346 dest = BC_NUM(ctxt, d);
347 src = BC_NUM(ctxt, s);
348
349 assert(dest != NULL && src != NULL);
350 assert(dest->num != NULL && src->num != NULL);
351
352 bc_num_copy(dest, src);
353
354 err:
355 BC_FUNC_FOOTER_UNLOCK(e);
356
357 assert(!vm.running && !vm.sig && !vm.sig_lock);
358
359 return e;
360 }
361
bcl_dup(BclNumber s)362 BclNumber bcl_dup(BclNumber s) {
363
364 BclError e = BCL_ERROR_NONE;
365 BcNum *src, dest;
366 BclNumber idx;
367 BclContext ctxt;
368
369 BC_CHECK_CTXT(ctxt);
370
371 BC_FUNC_HEADER_LOCK(err);
372
373 bc_vec_grow(&ctxt->nums, 1);
374
375 assert(s.i < ctxt->nums.len);
376
377 src = BC_NUM(ctxt, s);
378
379 assert(src != NULL && src->num != NULL);
380
381 bc_num_clear(&dest);
382
383 bc_num_createCopy(&dest, src);
384
385 err:
386 BC_FUNC_FOOTER_UNLOCK(e);
387 BC_MAYBE_SETUP(ctxt, e, dest, idx);
388
389 assert(!vm.running && !vm.sig && !vm.sig_lock);
390
391 return idx;
392 }
393
bcl_num_destruct(void * num)394 static void bcl_num_destruct(void *num) {
395
396 BcNum *n = (BcNum*) num;
397
398 assert(n != NULL);
399
400 if (n->num == NULL) return;
401
402 bc_num_free(num);
403 bc_num_clear(num);
404 }
405
bcl_num_neg(BclNumber n)406 bool bcl_num_neg(BclNumber n) {
407
408 BcNum *num;
409 BclContext ctxt;
410
411 BC_CHECK_CTXT_ASSERT(ctxt);
412
413 assert(n.i < ctxt->nums.len);
414
415 num = BC_NUM(ctxt, n);
416
417 assert(num != NULL && num->num != NULL);
418
419 return BC_NUM_NEG(num) != 0;
420 }
421
bcl_num_setNeg(BclNumber n,bool neg)422 void bcl_num_setNeg(BclNumber n, bool neg) {
423
424 BcNum *num;
425 BclContext ctxt;
426
427 BC_CHECK_CTXT_ASSERT(ctxt);
428
429 assert(n.i < ctxt->nums.len);
430
431 num = BC_NUM(ctxt, n);
432
433 assert(num != NULL && num->num != NULL);
434
435 num->rdx = BC_NUM_NEG_VAL(num, neg);
436 }
437
bcl_num_scale(BclNumber n)438 size_t bcl_num_scale(BclNumber n) {
439
440 BcNum *num;
441 BclContext ctxt;
442
443 BC_CHECK_CTXT_ASSERT(ctxt);
444
445 assert(n.i < ctxt->nums.len);
446
447 num = BC_NUM(ctxt, n);
448
449 assert(num != NULL && num->num != NULL);
450
451 return bc_num_scale(num);
452 }
453
bcl_num_setScale(BclNumber n,size_t scale)454 BclError bcl_num_setScale(BclNumber n, size_t scale) {
455
456 BclError e = BCL_ERROR_NONE;
457 BcNum *nptr;
458 BclContext ctxt;
459
460 BC_CHECK_CTXT_ERR(ctxt);
461
462 BC_CHECK_NUM_ERR(ctxt, n);
463
464 BC_FUNC_HEADER(err);
465
466 assert(n.i < ctxt->nums.len);
467
468 nptr = BC_NUM(ctxt, n);
469
470 assert(nptr != NULL && nptr->num != NULL);
471
472 if (scale > nptr->scale) bc_num_extend(nptr, scale - nptr->scale);
473 else if (scale < nptr->scale) bc_num_truncate(nptr, nptr->scale - scale);
474
475 err:
476 BC_SIG_MAYLOCK;
477 BC_FUNC_FOOTER(e);
478
479 assert(!vm.running && !vm.sig && !vm.sig_lock);
480
481 return e;
482 }
483
bcl_num_len(BclNumber n)484 size_t bcl_num_len(BclNumber n) {
485
486 BcNum *num;
487 BclContext ctxt;
488
489 BC_CHECK_CTXT_ASSERT(ctxt);
490
491 assert(n.i < ctxt->nums.len);
492
493 num = BC_NUM(ctxt, n);
494
495 assert(num != NULL && num->num != NULL);
496
497 return bc_num_len(num);
498 }
499
bcl_bigdig(BclNumber n,BclBigDig * result)500 BclError bcl_bigdig(BclNumber n, BclBigDig *result) {
501
502 BclError e = BCL_ERROR_NONE;
503 BcNum *num;
504 BclContext ctxt;
505
506 BC_CHECK_CTXT_ERR(ctxt);
507
508 BC_FUNC_HEADER_LOCK(err);
509
510 assert(n.i < ctxt->nums.len);
511 assert(result != NULL);
512
513 num = BC_NUM(ctxt, n);
514
515 assert(num != NULL && num->num != NULL);
516
517 bc_num_bigdig(num, result);
518
519 err:
520 bcl_num_dtor(ctxt, n, num);
521 BC_FUNC_FOOTER_UNLOCK(e);
522
523 assert(!vm.running && !vm.sig && !vm.sig_lock);
524
525 return e;
526 }
527
bcl_bigdig2num(BclBigDig val)528 BclNumber bcl_bigdig2num(BclBigDig val) {
529
530 BclError e = BCL_ERROR_NONE;
531 BcNum n;
532 BclNumber idx;
533 BclContext ctxt;
534
535 BC_CHECK_CTXT(ctxt);
536
537 BC_FUNC_HEADER_LOCK(err);
538
539 bc_vec_grow(&ctxt->nums, 1);
540
541 bc_num_createFromBigdig(&n, val);
542
543 err:
544 BC_FUNC_FOOTER_UNLOCK(e);
545 BC_MAYBE_SETUP(ctxt, e, n, idx);
546
547 assert(!vm.running && !vm.sig && !vm.sig_lock);
548
549 return idx;
550 }
551
bcl_binary(BclNumber a,BclNumber b,const BcNumBinaryOp op,const BcNumBinaryOpReq req)552 static BclNumber bcl_binary(BclNumber a, BclNumber b,
553 const BcNumBinaryOp op,
554 const BcNumBinaryOpReq req)
555 {
556 BclError e = BCL_ERROR_NONE;
557 BcNum *aptr, *bptr;
558 BcNum c;
559 BclNumber idx;
560 BclContext ctxt;
561
562 BC_CHECK_CTXT(ctxt);
563
564 BC_CHECK_NUM(ctxt, a);
565 BC_CHECK_NUM(ctxt, b);
566
567 BC_FUNC_HEADER_LOCK(err);
568
569 bc_vec_grow(&ctxt->nums, 1);
570
571 assert(a.i < ctxt->nums.len && b.i < ctxt->nums.len);
572
573 aptr = BC_NUM(ctxt, a);
574 bptr = BC_NUM(ctxt, b);
575
576 assert(aptr != NULL && bptr != NULL);
577 assert(aptr->num != NULL && bptr->num != NULL);
578
579 bc_num_clear(&c);
580
581 bc_num_init(&c, req(aptr, bptr, ctxt->scale));
582
583 BC_SIG_UNLOCK;
584
585 op(aptr, bptr, &c, ctxt->scale);
586
587 err:
588 BC_SIG_MAYLOCK;
589 bcl_num_dtor(ctxt, a, aptr);
590 if (b.i != a.i) bcl_num_dtor(ctxt, b, bptr);
591 BC_FUNC_FOOTER(e);
592 BC_MAYBE_SETUP(ctxt, e, c, idx);
593
594 assert(!vm.running && !vm.sig && !vm.sig_lock);
595
596 return idx;
597 }
598
bcl_add(BclNumber a,BclNumber b)599 BclNumber bcl_add(BclNumber a, BclNumber b) {
600 return bcl_binary(a, b, bc_num_add, bc_num_addReq);
601 }
602
bcl_sub(BclNumber a,BclNumber b)603 BclNumber bcl_sub(BclNumber a, BclNumber b) {
604 return bcl_binary(a, b, bc_num_sub, bc_num_addReq);
605 }
606
bcl_mul(BclNumber a,BclNumber b)607 BclNumber bcl_mul(BclNumber a, BclNumber b) {
608 return bcl_binary(a, b, bc_num_mul, bc_num_mulReq);
609 }
610
bcl_div(BclNumber a,BclNumber b)611 BclNumber bcl_div(BclNumber a, BclNumber b) {
612 return bcl_binary(a, b, bc_num_div, bc_num_divReq);
613 }
614
bcl_mod(BclNumber a,BclNumber b)615 BclNumber bcl_mod(BclNumber a, BclNumber b) {
616 return bcl_binary(a, b, bc_num_mod, bc_num_divReq);
617 }
618
bcl_pow(BclNumber a,BclNumber b)619 BclNumber bcl_pow(BclNumber a, BclNumber b) {
620 return bcl_binary(a, b, bc_num_pow, bc_num_powReq);
621 }
622
bcl_lshift(BclNumber a,BclNumber b)623 BclNumber bcl_lshift(BclNumber a, BclNumber b) {
624 return bcl_binary(a, b, bc_num_lshift, bc_num_placesReq);
625 }
626
bcl_rshift(BclNumber a,BclNumber b)627 BclNumber bcl_rshift(BclNumber a, BclNumber b) {
628 return bcl_binary(a, b, bc_num_rshift, bc_num_placesReq);
629 }
630
bcl_sqrt(BclNumber a)631 BclNumber bcl_sqrt(BclNumber a) {
632
633 BclError e = BCL_ERROR_NONE;
634 BcNum *aptr;
635 BcNum b;
636 BclNumber idx;
637 BclContext ctxt;
638
639 BC_CHECK_CTXT(ctxt);
640
641 BC_CHECK_NUM(ctxt, a);
642
643 BC_FUNC_HEADER(err);
644
645 bc_vec_grow(&ctxt->nums, 1);
646
647 assert(a.i < ctxt->nums.len);
648
649 aptr = BC_NUM(ctxt, a);
650
651 bc_num_sqrt(aptr, &b, ctxt->scale);
652
653 err:
654 BC_SIG_MAYLOCK;
655 bcl_num_dtor(ctxt, a, aptr);
656 BC_FUNC_FOOTER(e);
657 BC_MAYBE_SETUP(ctxt, e, b, idx);
658
659 assert(!vm.running && !vm.sig && !vm.sig_lock);
660
661 return idx;
662 }
663
bcl_divmod(BclNumber a,BclNumber b,BclNumber * c,BclNumber * d)664 BclError bcl_divmod(BclNumber a, BclNumber b, BclNumber *c, BclNumber *d) {
665
666 BclError e = BCL_ERROR_NONE;
667 size_t req;
668 BcNum *aptr, *bptr;
669 BcNum cnum, dnum;
670 BclContext ctxt;
671
672 BC_CHECK_CTXT_ERR(ctxt);
673
674 BC_CHECK_NUM_ERR(ctxt, a);
675 BC_CHECK_NUM_ERR(ctxt, b);
676
677 BC_FUNC_HEADER_LOCK(err);
678
679 bc_vec_grow(&ctxt->nums, 2);
680
681 assert(c != NULL && d != NULL);
682
683 aptr = BC_NUM(ctxt, a);
684 bptr = BC_NUM(ctxt, b);
685
686 assert(aptr != NULL && bptr != NULL);
687 assert(aptr->num != NULL && bptr->num != NULL);
688
689 bc_num_clear(&cnum);
690 bc_num_clear(&dnum);
691
692 req = bc_num_divReq(aptr, bptr, ctxt->scale);
693
694 bc_num_init(&cnum, req);
695 bc_num_init(&dnum, req);
696
697 BC_SIG_UNLOCK;
698
699 bc_num_divmod(aptr, bptr, &cnum, &dnum, ctxt->scale);
700
701 err:
702 BC_SIG_MAYLOCK;
703
704 bcl_num_dtor(ctxt, a, aptr);
705 if (b.i != a.i) bcl_num_dtor(ctxt, b, bptr);
706
707 if (BC_ERR(vm.err)) {
708 if (cnum.num != NULL) bc_num_free(&cnum);
709 if (dnum.num != NULL) bc_num_free(&dnum);
710 c->i = 0 - (size_t) BCL_ERROR_INVALID_NUM;
711 d->i = c->i;
712 BC_FUNC_FOOTER(e);
713 }
714 else {
715 BC_FUNC_FOOTER(e);
716 *c = bcl_num_insert(ctxt, &cnum);
717 *d = bcl_num_insert(ctxt, &dnum);
718 }
719
720 assert(!vm.running && !vm.sig && !vm.sig_lock);
721
722 return e;
723 }
724
bcl_modexp(BclNumber a,BclNumber b,BclNumber c)725 BclNumber bcl_modexp(BclNumber a, BclNumber b, BclNumber c) {
726
727 BclError e = BCL_ERROR_NONE;
728 size_t req;
729 BcNum *aptr, *bptr, *cptr;
730 BcNum d;
731 BclNumber idx;
732 BclContext ctxt;
733
734 BC_CHECK_CTXT(ctxt);
735
736 BC_CHECK_NUM(ctxt, a);
737 BC_CHECK_NUM(ctxt, b);
738 BC_CHECK_NUM(ctxt, c);
739
740 BC_FUNC_HEADER_LOCK(err);
741
742 bc_vec_grow(&ctxt->nums, 1);
743
744 assert(a.i < ctxt->nums.len && b.i < ctxt->nums.len);
745 assert(c.i < ctxt->nums.len);
746
747 aptr = BC_NUM(ctxt, a);
748 bptr = BC_NUM(ctxt, b);
749 cptr = BC_NUM(ctxt, c);
750
751 assert(aptr != NULL && bptr != NULL && cptr != NULL);
752 assert(aptr->num != NULL && bptr->num != NULL && cptr->num != NULL);
753
754 bc_num_clear(&d);
755
756 req = bc_num_divReq(aptr, cptr, 0);
757
758 bc_num_init(&d, req);
759
760 BC_SIG_UNLOCK;
761
762 bc_num_modexp(aptr, bptr, cptr, &d);
763
764 err:
765 BC_SIG_MAYLOCK;
766
767 bcl_num_dtor(ctxt, a, aptr);
768 if (b.i != a.i) bcl_num_dtor(ctxt, b, bptr);
769 if (c.i != a.i && c.i != b.i) bcl_num_dtor(ctxt, c, cptr);
770
771 BC_FUNC_FOOTER(e);
772 BC_MAYBE_SETUP(ctxt, e, d, idx);
773
774 assert(!vm.running && !vm.sig && !vm.sig_lock);
775
776 return idx;
777 }
778
bcl_cmp(BclNumber a,BclNumber b)779 ssize_t bcl_cmp(BclNumber a, BclNumber b) {
780
781 BcNum *aptr, *bptr;
782 BclContext ctxt;
783
784 BC_CHECK_CTXT_ASSERT(ctxt);
785
786 assert(a.i < ctxt->nums.len && b.i < ctxt->nums.len);
787
788 aptr = BC_NUM(ctxt, a);
789 bptr = BC_NUM(ctxt, b);
790
791 assert(aptr != NULL && bptr != NULL);
792 assert(aptr->num != NULL && bptr->num != NULL);
793
794 return bc_num_cmp(aptr, bptr);
795 }
796
bcl_zero(BclNumber n)797 void bcl_zero(BclNumber n) {
798
799 BcNum *nptr;
800 BclContext ctxt;
801
802 BC_CHECK_CTXT_ASSERT(ctxt);
803
804 assert(n.i < ctxt->nums.len);
805
806 nptr = BC_NUM(ctxt, n);
807
808 assert(nptr != NULL && nptr->num != NULL);
809
810 bc_num_zero(nptr);
811 }
812
bcl_one(BclNumber n)813 void bcl_one(BclNumber n) {
814
815 BcNum *nptr;
816 BclContext ctxt;
817
818 BC_CHECK_CTXT_ASSERT(ctxt);
819
820 assert(n.i < ctxt->nums.len);
821
822 nptr = BC_NUM(ctxt, n);
823
824 assert(nptr != NULL && nptr->num != NULL);
825
826 bc_num_one(nptr);
827 }
828
bcl_parse(const char * restrict val)829 BclNumber bcl_parse(const char *restrict val) {
830
831 BclError e = BCL_ERROR_NONE;
832 BcNum n;
833 BclNumber idx;
834 BclContext ctxt;
835 bool neg;
836
837 BC_CHECK_CTXT(ctxt);
838
839 BC_FUNC_HEADER_LOCK(err);
840
841 bc_vec_grow(&ctxt->nums, 1);
842
843 assert(val != NULL);
844
845 neg = (val[0] == '-');
846
847 if (neg) val += 1;
848
849 if (!bc_num_strValid(val)) {
850 vm.err = BCL_ERROR_PARSE_INVALID_STR;
851 goto err;
852 }
853
854 bc_num_clear(&n);
855
856 bc_num_init(&n, BC_NUM_DEF_SIZE);
857
858 BC_SIG_UNLOCK;
859
860 bc_num_parse(&n, val, (BcBigDig) ctxt->ibase);
861
862 n.rdx = BC_NUM_NEG_VAL_NP(n, neg);
863
864 err:
865 BC_SIG_MAYLOCK;
866 BC_FUNC_FOOTER(e);
867 BC_MAYBE_SETUP(ctxt, e, n, idx);
868
869 assert(!vm.running && !vm.sig && !vm.sig_lock);
870
871 return idx;
872 }
873
bcl_string(BclNumber n)874 char* bcl_string(BclNumber n) {
875
876 BcNum *nptr;
877 char *str = NULL;
878 BclContext ctxt;
879
880 BC_CHECK_CTXT_ASSERT(ctxt);
881
882 if (BC_ERR(n.i >= ctxt->nums.len)) return str;
883
884 BC_FUNC_HEADER(err);
885
886 assert(n.i < ctxt->nums.len);
887
888 nptr = BC_NUM(ctxt, n);
889
890 assert(nptr != NULL && nptr->num != NULL);
891
892 bc_vec_popAll(&vm.out);
893
894 bc_num_print(nptr, (BcBigDig) ctxt->obase, false);
895 bc_vec_pushByte(&vm.out, '\0');
896
897 BC_SIG_LOCK;
898 str = bc_vm_strdup(vm.out.v);
899
900 err:
901 bcl_num_dtor(ctxt, n, nptr);
902
903 BC_FUNC_FOOTER_NO_ERR;
904
905 assert(!vm.running && !vm.sig && !vm.sig_lock);
906
907 return str;
908 }
909
bcl_irand(BclNumber a)910 BclNumber bcl_irand(BclNumber a) {
911
912 BclError e = BCL_ERROR_NONE;
913 BcNum *aptr;
914 BcNum b;
915 BclNumber idx;
916 BclContext ctxt;
917
918 BC_CHECK_CTXT(ctxt);
919
920 BC_CHECK_NUM(ctxt, a);
921
922 BC_FUNC_HEADER_LOCK(err);
923
924 bc_vec_grow(&ctxt->nums, 1);
925
926 assert(a.i < ctxt->nums.len);
927
928 aptr = BC_NUM(ctxt, a);
929
930 assert(aptr != NULL && aptr->num != NULL);
931
932 bc_num_clear(&b);
933
934 bc_num_init(&b, BC_NUM_DEF_SIZE);
935
936 BC_SIG_UNLOCK;
937
938 bc_num_irand(aptr, &b, &vm.rng);
939
940 err:
941 BC_SIG_MAYLOCK;
942 bcl_num_dtor(ctxt, a, aptr);
943 BC_FUNC_FOOTER(e);
944 BC_MAYBE_SETUP(ctxt, e, b, idx);
945
946 assert(!vm.running && !vm.sig && !vm.sig_lock);
947
948 return idx;
949 }
950
bcl_frandHelper(BcNum * restrict b,size_t places)951 static void bcl_frandHelper(BcNum *restrict b, size_t places) {
952
953 BcNum exp, pow, ten;
954 BcDig exp_digs[BC_NUM_BIGDIG_LOG10];
955 BcDig ten_digs[BC_NUM_BIGDIG_LOG10];
956
957 bc_num_setup(&exp, exp_digs, BC_NUM_BIGDIG_LOG10);
958 bc_num_setup(&ten, ten_digs, BC_NUM_BIGDIG_LOG10);
959
960 ten.num[0] = 10;
961 ten.len = 1;
962
963 bc_num_bigdig2num(&exp, (BcBigDig) places);
964
965 bc_num_clear(&pow);
966
967 BC_SIG_LOCK;
968
969 BC_SETJMP_LOCKED(err);
970
971 bc_num_init(&pow, bc_num_powReq(&ten, &exp, 0));
972
973 BC_SIG_UNLOCK;
974
975 bc_num_pow(&ten, &exp, &pow, 0);
976
977 bc_num_irand(&pow, b, &vm.rng);
978
979 bc_num_shiftRight(b, places);
980
981 err:
982 BC_SIG_MAYLOCK;
983 bc_num_free(&pow);
984 BC_LONGJMP_CONT;
985 }
986
bcl_frand(size_t places)987 BclNumber bcl_frand(size_t places) {
988
989 BclError e = BCL_ERROR_NONE;
990 BcNum n;
991 BclNumber idx;
992 BclContext ctxt;
993
994 BC_CHECK_CTXT(ctxt);
995
996 BC_FUNC_HEADER_LOCK(err);
997
998 bc_vec_grow(&ctxt->nums, 1);
999
1000 bc_num_clear(&n);
1001
1002 bc_num_init(&n, BC_NUM_DEF_SIZE);
1003
1004 BC_SIG_UNLOCK;
1005
1006 bcl_frandHelper(&n, places);
1007
1008 err:
1009 BC_SIG_MAYLOCK;
1010 BC_FUNC_FOOTER(e);
1011 BC_MAYBE_SETUP(ctxt, e, n, idx);
1012
1013 assert(!vm.running && !vm.sig && !vm.sig_lock);
1014
1015 return idx;
1016 }
1017
bcl_ifrandHelper(BcNum * restrict a,BcNum * restrict b,size_t places)1018 static void bcl_ifrandHelper(BcNum *restrict a, BcNum *restrict b,
1019 size_t places)
1020 {
1021 BcNum ir, fr;
1022
1023 bc_num_clear(&ir);
1024 bc_num_clear(&fr);
1025
1026 BC_SIG_LOCK;
1027
1028 BC_SETJMP_LOCKED(err);
1029
1030 bc_num_init(&ir, BC_NUM_DEF_SIZE);
1031 bc_num_init(&fr, BC_NUM_DEF_SIZE);
1032
1033 BC_SIG_UNLOCK;
1034
1035 bc_num_irand(a, &ir, &vm.rng);
1036 bcl_frandHelper(&fr, places);
1037
1038 bc_num_add(&ir, &fr, b, 0);
1039
1040 err:
1041 BC_SIG_MAYLOCK;
1042 bc_num_free(&fr);
1043 bc_num_free(&ir);
1044 BC_LONGJMP_CONT;
1045 }
1046
bcl_ifrand(BclNumber a,size_t places)1047 BclNumber bcl_ifrand(BclNumber a, size_t places) {
1048
1049 BclError e = BCL_ERROR_NONE;
1050 BcNum *aptr;
1051 BcNum b;
1052 BclNumber idx;
1053 BclContext ctxt;
1054
1055 BC_CHECK_CTXT(ctxt);
1056
1057 BC_CHECK_NUM(ctxt, a);
1058
1059 BC_FUNC_HEADER_LOCK(err);
1060
1061 bc_vec_grow(&ctxt->nums, 1);
1062
1063 assert(a.i < ctxt->nums.len);
1064
1065 aptr = BC_NUM(ctxt, a);
1066
1067 assert(aptr != NULL && aptr->num != NULL);
1068
1069 bc_num_clear(&b);
1070
1071 bc_num_init(&b, BC_NUM_DEF_SIZE);
1072
1073 BC_SIG_UNLOCK;
1074
1075 bcl_ifrandHelper(aptr, &b, places);
1076
1077 err:
1078 BC_SIG_MAYLOCK;
1079 bcl_num_dtor(ctxt, a, aptr);
1080 BC_FUNC_FOOTER(e);
1081 BC_MAYBE_SETUP(ctxt, e, b, idx);
1082
1083 assert(!vm.running && !vm.sig && !vm.sig_lock);
1084
1085 return idx;
1086 }
1087
bcl_rand_seedWithNum(BclNumber n)1088 BclError bcl_rand_seedWithNum(BclNumber n) {
1089
1090 BclError e = BCL_ERROR_NONE;
1091 BcNum *nptr;
1092 BclContext ctxt;
1093
1094 BC_CHECK_CTXT_ERR(ctxt);
1095
1096 BC_CHECK_NUM_ERR(ctxt, n);
1097
1098 BC_FUNC_HEADER(err);
1099
1100 assert(n.i < ctxt->nums.len);
1101
1102 nptr = BC_NUM(ctxt, n);
1103
1104 assert(nptr != NULL && nptr->num != NULL);
1105
1106 bc_num_rng(nptr, &vm.rng);
1107
1108 err:
1109 BC_SIG_MAYLOCK;
1110 BC_FUNC_FOOTER(e);
1111
1112 assert(!vm.running && !vm.sig && !vm.sig_lock);
1113
1114 return e;
1115 }
1116
bcl_rand_seed(unsigned char seed[BC_SEED_SIZE])1117 BclError bcl_rand_seed(unsigned char seed[BC_SEED_SIZE]) {
1118
1119 BclError e = BCL_ERROR_NONE;
1120 size_t i;
1121 ulong vals[BC_SEED_ULONGS];
1122
1123 BC_FUNC_HEADER(err);
1124
1125 for (i = 0; i < BC_SEED_SIZE; ++i) {
1126 ulong val = ((ulong) seed[i]) << (((ulong) CHAR_BIT) *
1127 (i % sizeof(ulong)));
1128 vals[i / sizeof(long)] |= val;
1129 }
1130
1131 bc_rand_seed(&vm.rng, vals[0], vals[1], vals[2], vals[3]);
1132
1133 err:
1134 BC_SIG_MAYLOCK;
1135 BC_FUNC_FOOTER(e);
1136 return e;
1137 }
1138
bcl_rand_reseed(void)1139 void bcl_rand_reseed(void) {
1140 bc_rand_srand(bc_vec_top(&vm.rng.v));
1141 }
1142
bcl_rand_seed2num(void)1143 BclNumber bcl_rand_seed2num(void) {
1144
1145 BclError e = BCL_ERROR_NONE;
1146 BcNum n;
1147 BclNumber idx;
1148 BclContext ctxt;
1149
1150 BC_CHECK_CTXT(ctxt);
1151
1152 BC_FUNC_HEADER_LOCK(err);
1153
1154 bc_num_clear(&n);
1155
1156 bc_num_init(&n, BC_NUM_DEF_SIZE);
1157
1158 BC_SIG_UNLOCK;
1159
1160 bc_num_createFromRNG(&n, &vm.rng);
1161
1162 err:
1163 BC_SIG_MAYLOCK;
1164 BC_FUNC_FOOTER(e);
1165 BC_MAYBE_SETUP(ctxt, e, n, idx);
1166
1167 assert(!vm.running && !vm.sig && !vm.sig_lock);
1168
1169 return idx;
1170 }
1171
bcl_rand_int(void)1172 BclRandInt bcl_rand_int(void) {
1173 return (BclRandInt) bc_rand_int(&vm.rng);
1174 }
1175
bcl_rand_bounded(BclRandInt bound)1176 BclRandInt bcl_rand_bounded(BclRandInt bound) {
1177 if (bound <= 1) return 0;
1178 return (BclRandInt) bc_rand_bounded(&vm.rng, (BcRand) bound);
1179 }
1180
1181 #endif // BC_ENABLE_LIBRARY
1182