xref: /freebsd/contrib/bc/src/library.c (revision a0409676120c1e558d0ade943019934e0f15118d)
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 
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_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 
163 void bcl_gc(void) {
164 	bc_vm_freeTemps();
165 	vm.temps.len = 0;
166 }
167 
168 bool bcl_abortOnFatalError(void) {
169 	return vm.abrt;
170 }
171 
172 void bcl_setAbortOnFatalError(bool abrt) {
173 	vm.abrt = abrt;
174 }
175 
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 
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 
213 void bcl_ctxt_freeNums(BclContext ctxt) {
214 	bc_vec_popAll(&ctxt->nums);
215 	bc_vec_popAll(&ctxt->free_nums);
216 }
217 
218 size_t bcl_ctxt_scale(BclContext ctxt) {
219 	return ctxt->scale;
220 }
221 
222 void bcl_ctxt_setScale(BclContext ctxt, size_t scale) {
223 	ctxt->scale = scale;
224 }
225 
226 size_t bcl_ctxt_ibase(BclContext ctxt) {
227 	return ctxt->ibase;
228 }
229 
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 
236 size_t bcl_ctxt_obase(BclContext ctxt) {
237 	return ctxt->obase;
238 }
239 
240 void bcl_ctxt_setObase(BclContext ctxt, size_t obase) {
241 	ctxt->obase = obase;
242 }
243 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
599 BclNumber bcl_add(BclNumber a, BclNumber b) {
600 	return bcl_binary(a, b, bc_num_add, bc_num_addReq);
601 }
602 
603 BclNumber bcl_sub(BclNumber a, BclNumber b) {
604 	return bcl_binary(a, b, bc_num_sub, bc_num_addReq);
605 }
606 
607 BclNumber bcl_mul(BclNumber a, BclNumber b) {
608 	return bcl_binary(a, b, bc_num_mul, bc_num_mulReq);
609 }
610 
611 BclNumber bcl_div(BclNumber a, BclNumber b) {
612 	return bcl_binary(a, b, bc_num_div, bc_num_divReq);
613 }
614 
615 BclNumber bcl_mod(BclNumber a, BclNumber b) {
616 	return bcl_binary(a, b, bc_num_mod, bc_num_divReq);
617 }
618 
619 BclNumber bcl_pow(BclNumber a, BclNumber b) {
620 	return bcl_binary(a, b, bc_num_pow, bc_num_powReq);
621 }
622 
623 BclNumber bcl_lshift(BclNumber a, BclNumber b) {
624 	return bcl_binary(a, b, bc_num_lshift, bc_num_placesReq);
625 }
626 
627 BclNumber bcl_rshift(BclNumber a, BclNumber b) {
628 	return bcl_binary(a, b, bc_num_rshift, bc_num_placesReq);
629 }
630 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
1139 void bcl_rand_reseed(void) {
1140 	bc_rand_srand(bc_vec_top(&vm.rng.v));
1141 }
1142 
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 
1172 BclRandInt bcl_rand_int(void) {
1173 	return (BclRandInt) bc_rand_int(&vm.rng);
1174 }
1175 
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