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