summaryrefslogtreecommitdiff
path: root/src/libbiguint
diff options
context:
space:
mode:
authorLaurent Bercot <ska-skaware@skarnet.org>2014-09-18 18:55:44 +0000
committerLaurent Bercot <ska-skaware@skarnet.org>2014-09-18 18:55:44 +0000
commit3534b428629be185e096be99e3bd5fdfe32d5544 (patch)
tree210ef3198ed66bc7f7b7bf6a85e4579f455e5a36 /src/libbiguint
downloadskalibs-3534b428629be185e096be99e3bd5fdfe32d5544.tar.xz
initial commit with rc for skalibs-2.0.0.0
Diffstat (limited to 'src/libbiguint')
-rw-r--r--src/libbiguint/bu_addc.c22
-rw-r--r--src/libbiguint/bu_addmod.c11
-rw-r--r--src/libbiguint/bu_cmp.c18
-rw-r--r--src/libbiguint/bu_copy.c21
-rw-r--r--src/libbiguint/bu_copy_internal.c9
-rw-r--r--src/libbiguint/bu_div.c23
-rw-r--r--src/libbiguint/bu_div_internal.c46
-rw-r--r--src/libbiguint/bu_divmod.c32
-rw-r--r--src/libbiguint/bu_divmod_internal.c37
-rw-r--r--src/libbiguint/bu_fmt.c19
-rw-r--r--src/libbiguint/bu_gcd.c33
-rw-r--r--src/libbiguint/bu_invmod.c12
-rw-r--r--src/libbiguint/bu_len.c10
-rw-r--r--src/libbiguint/bu_mod.c10
-rw-r--r--src/libbiguint/bu_mul.c32
-rw-r--r--src/libbiguint/bu_mulmod.c16
-rw-r--r--src/libbiguint/bu_pack.c9
-rw-r--r--src/libbiguint/bu_pack_big.c10
-rw-r--r--src/libbiguint/bu_scan.c18
-rw-r--r--src/libbiguint/bu_scan_internal.c21
-rw-r--r--src/libbiguint/bu_scanlen.c12
-rw-r--r--src/libbiguint/bu_slbc.c17
-rw-r--r--src/libbiguint/bu_srbc.c15
-rw-r--r--src/libbiguint/bu_subc.c22
-rw-r--r--src/libbiguint/bu_submod.c12
-rw-r--r--src/libbiguint/bu_unpack.c9
-rw-r--r--src/libbiguint/bu_unpack_big.c10
-rw-r--r--src/libbiguint/bu_zero.c9
28 files changed, 515 insertions, 0 deletions
diff --git a/src/libbiguint/bu_addc.c b/src/libbiguint/bu_addc.c
new file mode 100644
index 0000000..0a57531
--- /dev/null
+++ b/src/libbiguint/bu_addc.c
@@ -0,0 +1,22 @@
+/* ISC license. */
+
+/* OpenBSD needs that for EOVERFLOW. wtfbsdseriously */
+#define _BSD_SOURCE
+
+#include <errno.h>
+#include <skalibs/uint32.h>
+#include <skalibs/biguint.h>
+
+int bu_addc (uint32 *c, unsigned int cn, uint32 const *a, unsigned int an, uint32 const *b, unsigned int bn, register int carry)
+{
+ register unsigned int i = 0 ;
+ for (; i < cn ; i++)
+ {
+ register uint32 ai = (i < an) ? a[i] : 0 ;
+ register uint32 bi = (i < bn) ? b[i] : 0 ;
+ register uint32 ci = ai + bi + carry ;
+ carry = (carry || bi) && (ci < ai) ;
+ c[i] = ci ;
+ }
+ return carry ? (errno = EOVERFLOW, 0) : 1 ;
+}
diff --git a/src/libbiguint/bu_addmod.c b/src/libbiguint/bu_addmod.c
new file mode 100644
index 0000000..c997897
--- /dev/null
+++ b/src/libbiguint/bu_addmod.c
@@ -0,0 +1,11 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/biguint.h>
+
+int bu_addmod (uint32 *c, unsigned int cn, uint32 const *a, unsigned int an, uint32 const *b, unsigned int bn, uint32 const *m, unsigned int mn)
+{
+ if (!bu_add(c, cn, a, an, b, bn)) return 0 ;
+ if (bu_cmp(c, cn, m, mn) >= 0) bu_sub(c, cn, c, cn, m, mn) ;
+ return 1 ;
+}
diff --git a/src/libbiguint/bu_cmp.c b/src/libbiguint/bu_cmp.c
new file mode 100644
index 0000000..a6bfaeb
--- /dev/null
+++ b/src/libbiguint/bu_cmp.c
@@ -0,0 +1,18 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/biguint.h>
+
+int bu_cmp (register uint32 const *a, register unsigned int an, register uint32 const *b, register unsigned int bn)
+{
+ an = bu_len(a, an) ;
+ bn = bu_len(b, bn) ;
+ if (an < bn) return -1 ;
+ if (an > bn) return 1 ;
+ while (bn--)
+ {
+ if (a[bn] < b[bn]) return -1 ;
+ if (a[bn] > b[bn]) return 1 ;
+ }
+ return 0 ;
+}
diff --git a/src/libbiguint/bu_copy.c b/src/libbiguint/bu_copy.c
new file mode 100644
index 0000000..1358aca
--- /dev/null
+++ b/src/libbiguint/bu_copy.c
@@ -0,0 +1,21 @@
+/* ISC license. */
+
+/* OpenBSD needs that for EOVERFLOW. wtfbsdseriously */
+#define _BSD_SOURCE
+
+#include <errno.h>
+#include <skalibs/uint32.h>
+#include <skalibs/biguint.h>
+
+int bu_copy (uint32 *b, unsigned int bn, uint32 const *a, unsigned int an)
+{
+ register unsigned int alen = bu_len(a, an) ;
+ if (bn < alen)
+ {
+ bu_copy_internal(b, a, bn) ;
+ return (errno = EOVERFLOW, 0) ;
+ }
+ bu_copy_internal(b, a, alen) ;
+ bu_zero(b + alen, bn - alen) ;
+ return 1 ;
+}
diff --git a/src/libbiguint/bu_copy_internal.c b/src/libbiguint/bu_copy_internal.c
new file mode 100644
index 0000000..919929b
--- /dev/null
+++ b/src/libbiguint/bu_copy_internal.c
@@ -0,0 +1,9 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/biguint.h>
+
+void bu_copy_internal (register uint32 *b, register uint32 const *a, register unsigned int n)
+{
+ while (n--) b[n] = a[n] ;
+}
diff --git a/src/libbiguint/bu_div.c b/src/libbiguint/bu_div.c
new file mode 100644
index 0000000..c7718e2
--- /dev/null
+++ b/src/libbiguint/bu_div.c
@@ -0,0 +1,23 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/uint32.h>
+#include <skalibs/biguint.h>
+
+int bu_div (uint32 const *a, unsigned int an, uint32 const *b, unsigned int bn, uint32 *q, unsigned int qn, uint32 *r, unsigned int rn)
+{
+ unsigned int alen = bu_len(a, an) ;
+ unsigned int blen = bu_len(b, bn) ;
+ if (!blen) return (errno = EDOM, 0) ;
+ else
+ {
+ uint32 qq[alen] ;
+ uint32 rr[alen] ;
+ register int qh, rh ;
+ bu_copy_internal(rr, a, alen) ;
+ bu_div_internal(rr, alen, b, blen, qq, alen) ;
+ qh = bu_copy(q, qn, qq, alen) ;
+ rh = bu_copy(r, rn, rr, alen) ;
+ return qh && rh ;
+ }
+}
diff --git a/src/libbiguint/bu_div_internal.c b/src/libbiguint/bu_div_internal.c
new file mode 100644
index 0000000..d1be789
--- /dev/null
+++ b/src/libbiguint/bu_div_internal.c
@@ -0,0 +1,46 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/uint32.h>
+#include <skalibs/biguint.h>
+
+/*
+ q = a/b, a = a mod b. Assumes b != 0 and qn >= alen - blen + 1.
+*/
+
+void bu_div_internal (uint32 *a, unsigned int an, uint32 const *b, unsigned int bn, uint32 *q, unsigned int qn)
+{
+ unsigned int alen = bu_len(a, an) ;
+ unsigned int blen = bu_len(b, bn) ;
+ bu_zero(q, qn) ;
+ if (alen < blen) return ;
+ {
+ uint32 bb[alen + 1] ;
+ unsigned int i = 1 + ((alen - blen) << 5) ;
+ bu_zero(bb, alen - blen) ;
+ bu_copy_internal(bb + alen - blen, b, blen) ;
+ bb[alen] = 0 ;
+
+ while (bu_cmp(a, alen, bb, alen+1) >= 0)
+ {
+ bu_slb(bb + alen - blen, blen + 1) ;
+ i++ ;
+ }
+ while (i && (bu_cmp(a, alen, bb, alen+1) < 0))
+ {
+ bu_srb(bb, alen + 1) ;
+ i-- ;
+ }
+
+ while (i--)
+ {
+ bu_slb(q, alen - blen + 1) ;
+ if (bu_cmp(a, alen, bb, alen) >= 0)
+ {
+ bu_sub(a, alen, a, alen, bb, alen) ;
+ q[0] |= 1 ;
+ }
+ bu_srb(bb, alen) ;
+ }
+ }
+}
diff --git a/src/libbiguint/bu_divmod.c b/src/libbiguint/bu_divmod.c
new file mode 100644
index 0000000..5d5802f
--- /dev/null
+++ b/src/libbiguint/bu_divmod.c
@@ -0,0 +1,32 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/uint32.h>
+#include <skalibs/biguint.h>
+
+/*
+ q = y/x mod m.
+*/
+
+int bu_divmod (uint32 *q, unsigned int qn, uint32 const *y, unsigned int yn, uint32 const *x, unsigned int xn, uint32 const *m, unsigned int mn)
+{
+ unsigned int ylen = bu_len(y, yn) ;
+ unsigned int xlen = bu_len(x, xn) ;
+ unsigned int mlen = bu_len(m, mn) ;
+ unsigned int n = ylen ;
+ if (n < xlen) n = xlen ;
+ if (n < mlen) n = mlen ;
+ if (!n) return (errno = EDOM, 0) ;
+ {
+ uint32 yy[n] ;
+ uint32 xx[n] ;
+ uint32 mm[n] ;
+ bu_gcd(xx, n, x, xlen, m, mlen) ;
+ if ((xx[0] != 1) || (bu_len(xx, n) != 1)) return (errno = EDOM, 0) ;
+ bu_copy_internal(yy, y, ylen) ; bu_zero(yy+ylen, n-ylen) ;
+ bu_copy_internal(xx, x, xlen) ; bu_zero(xx+xlen, n-xlen) ;
+ bu_copy_internal(mm, m, mlen) ; bu_zero(mm+mlen, n-mlen) ;
+ bu_divmod_internal(yy, xx, mm, n) ;
+ return bu_copy(q, qn, yy, n) ;
+ }
+}
diff --git a/src/libbiguint/bu_divmod_internal.c b/src/libbiguint/bu_divmod_internal.c
new file mode 100644
index 0000000..46d3335
--- /dev/null
+++ b/src/libbiguint/bu_divmod_internal.c
@@ -0,0 +1,37 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/biguint.h>
+
+/*
+ u = u/a mod m. a and m must be relatively prime - otherwise, infinite loop.
+ a is not immutable.
+ Original idea: see http://research.sun.com/techrep/2001/abstract-95.html
+*/
+
+void bu_divmod_internal (register uint32 *u, register uint32 *a, register uint32 const *m, unsigned int n)
+{
+ uint32 bb[n] ; register uint32 *b = bb ;
+ uint32 vv[n] ; register uint32 *v = vv ;
+ bu_copy_internal(b, m, n) ;
+ bu_zero(v, n) ;
+
+ /*** XXX: this iterates like mad, should probably be optimized more */
+ for (;;)
+ {
+ while (!(a[0] & 1))
+ {
+ bu_srb(a, n) ;
+ if (u[0] & 1) bu_add(u, n, u, n, m, n) ;
+ bu_srb(u, n) ;
+ }
+ if ((a[0] == 1) && (bu_len(a, n) == 1)) break ;
+ if (bu_cmp(a, n, b, n) < 0)
+ {
+ register uint32 *t = a ; a = b ; b = t ;
+ t = u ; u = v ; v = t ;
+ }
+ bu_add(a, n, a, n, b, n) ;
+ bu_add(u, n, u, n, v, n) ;
+ }
+}
diff --git a/src/libbiguint/bu_fmt.c b/src/libbiguint/bu_fmt.c
new file mode 100644
index 0000000..31fa706
--- /dev/null
+++ b/src/libbiguint/bu_fmt.c
@@ -0,0 +1,19 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/biguint.h>
+
+unsigned int bu_fmt (char *s, uint32 const *x, unsigned int n)
+{
+ unsigned int len = 0 ;
+ while (n--)
+ {
+ char fmt[8] ;
+ unsigned int i = uint32_xfmt(fmt, x[n]) ;
+ byte_copy(s+len, 8-i, "00000000") ;
+ byte_copy(s+len+8-i, i, fmt) ;
+ len += 8 ;
+ }
+ return len ;
+}
diff --git a/src/libbiguint/bu_gcd.c b/src/libbiguint/bu_gcd.c
new file mode 100644
index 0000000..d6c5791
--- /dev/null
+++ b/src/libbiguint/bu_gcd.c
@@ -0,0 +1,33 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/biguint.h>
+
+int bu_gcd (uint32 *r, unsigned int rn, uint32 const *a, unsigned int an, uint32 const *b, unsigned int bn)
+{
+ if (bu_cmp(a, an, b, bn) < 0)
+ {
+ register uint32 const *t = a ;
+ register unsigned int tn = an ;
+ a = b ; an = bn ;
+ b = t ; bn = tn ;
+ }
+ {
+ uint32 trash[an] ;
+ uint32 aa[an] ;
+ uint32 bb[an] ;
+ uint32 *aaa = aa, *bbb = bb ;
+ bu_copy_internal(aa, a, an) ;
+ bu_copy_internal(bb, b, bn) ;
+ bu_zero(bb+bn, an-bn) ;
+
+ while (bu_len(bbb, an))
+ {
+ register uint32 *ttt = aaa ;
+ bu_div_internal(aaa, an, bbb, an, trash, an) ;
+ aaa = bbb ;
+ bbb = ttt ;
+ }
+ return bu_copy(r, rn, aaa, an) ;
+ }
+}
diff --git a/src/libbiguint/bu_invmod.c b/src/libbiguint/bu_invmod.c
new file mode 100644
index 0000000..ff209e7
--- /dev/null
+++ b/src/libbiguint/bu_invmod.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/biguint.h>
+
+/* x^-1 mod m. */
+
+int bu_invmod (uint32 *x, unsigned int xn, uint32 const *m, unsigned int mn)
+{
+ uint32 const one = 1 ;
+ return bu_divmod(x, xn, &one, 1, x, xn, m, mn) ;
+}
diff --git a/src/libbiguint/bu_len.c b/src/libbiguint/bu_len.c
new file mode 100644
index 0000000..0f6ec10
--- /dev/null
+++ b/src/libbiguint/bu_len.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/biguint.h>
+
+unsigned int bu_len (register uint32 const *a, register unsigned int n)
+{
+ while (n--) if (a[n]) return n+1 ;
+ return 0 ;
+}
diff --git a/src/libbiguint/bu_mod.c b/src/libbiguint/bu_mod.c
new file mode 100644
index 0000000..2050320
--- /dev/null
+++ b/src/libbiguint/bu_mod.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/biguint.h>
+
+int bu_mod (uint32 *a, unsigned int an, uint32 const *b, unsigned int bn)
+{
+ uint32 q[an] ;
+ return bu_div(a, an, b, bn, q, an, a, an) ;
+}
diff --git a/src/libbiguint/bu_mul.c b/src/libbiguint/bu_mul.c
new file mode 100644
index 0000000..184d652
--- /dev/null
+++ b/src/libbiguint/bu_mul.c
@@ -0,0 +1,32 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/uint64.h>
+#include <skalibs/biguint.h>
+
+ /* No Karatsuba. Keep it simple, stupid. */
+
+int bu_mul (uint32 *x, unsigned int xn, uint32 const *a, unsigned int an, uint32 const *b, unsigned int bn)
+{
+ unsigned int alen = bu_len(a, an) ;
+ unsigned int blen = bu_len(b, bn) ;
+ uint32 c[alen + blen] ;
+ register unsigned int i = 0 ;
+ bu_zero(c, alen + blen) ;
+ for (; i < alen ; i++)
+ {
+ register uint32 carry = 0 ;
+ register unsigned int j = 0 ;
+ for (; j < blen ; j++)
+ {
+ register uint64 t = a[i] ;
+ t *= b[j] ;
+ t += c[i+j] ;
+ t += carry ;
+ c[i+j] = (uint32)t ;
+ carry = (uint32)(t >> 32) ;
+ }
+ c[i+j] += carry ;
+ }
+ return bu_copy(x, xn, c, alen+blen) ;
+}
diff --git a/src/libbiguint/bu_mulmod.c b/src/libbiguint/bu_mulmod.c
new file mode 100644
index 0000000..18e5a1c
--- /dev/null
+++ b/src/libbiguint/bu_mulmod.c
@@ -0,0 +1,16 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/biguint.h>
+
+ /* Nope, no Montgomery either. */
+
+int bu_mulmod (uint32 *c, unsigned int cn, uint32 const *a, unsigned int an, uint32 const *b, unsigned int bn, uint32 const *m, unsigned int mn)
+{
+ unsigned int alen = bu_len(a, an) ;
+ unsigned int blen = bu_len(b, bn) ;
+ uint32 x[alen+blen] ;
+ if (!bu_mul(x, alen+blen, a, alen, b, blen)) return 0 ;
+ if (!bu_mod(x, alen+blen, m, mn)) return 0 ;
+ return bu_copy(c, cn, x, mn) ;
+}
diff --git a/src/libbiguint/bu_pack.c b/src/libbiguint/bu_pack.c
new file mode 100644
index 0000000..0145b9f
--- /dev/null
+++ b/src/libbiguint/bu_pack.c
@@ -0,0 +1,9 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/biguint.h>
+
+void bu_pack (char *s, uint32 const *a, register unsigned int n)
+{
+ while (n--) uint32_pack(s + (n<<2), a[n]) ;
+}
diff --git a/src/libbiguint/bu_pack_big.c b/src/libbiguint/bu_pack_big.c
new file mode 100644
index 0000000..8340fd7
--- /dev/null
+++ b/src/libbiguint/bu_pack_big.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/biguint.h>
+
+void bu_pack_big (char *s, uint32 const *a, unsigned int n)
+{
+ register unsigned int i = 0 ;
+ for (; i < n ; i++) uint32_pack_big(s + (i<<2), a[n-1-i]) ;
+}
diff --git a/src/libbiguint/bu_scan.c b/src/libbiguint/bu_scan.c
new file mode 100644
index 0000000..a34ed99
--- /dev/null
+++ b/src/libbiguint/bu_scan.c
@@ -0,0 +1,18 @@
+/* ISC license. */
+
+/* OpenBSD needs that for EOVERFLOW. wtfbsdseriously */
+#define _BSD_SOURCE
+
+#include <errno.h>
+#include <skalibs/uint32.h>
+#include <skalibs/bitarray.h>
+#include <skalibs/biguint.h>
+
+int bu_scan (char const *s, unsigned int len, uint32 *x, unsigned int xn, unsigned int zeron)
+{
+ register unsigned int n = bitarray_div8(zeron) ;
+ if (xn < n) return (errno = EOVERFLOW, 0) ;
+ bu_scan_internal(s, len, x) ;
+ bu_zero(x + n, xn - n) ;
+ return 1 ;
+}
diff --git a/src/libbiguint/bu_scan_internal.c b/src/libbiguint/bu_scan_internal.c
new file mode 100644
index 0000000..696880a
--- /dev/null
+++ b/src/libbiguint/bu_scan_internal.c
@@ -0,0 +1,21 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/biguint.h>
+
+void bu_scan_internal (char const *s, unsigned int len, uint32 *x)
+{
+ char fmt[9] = "\0\0\0\0\0\0\0\0" ;
+ unsigned int i = 0 ;
+ if (len & 7)
+ {
+ byte_copy(fmt, len & 7, s) ;
+ uint32_xscan(fmt, x + (len >> 3)) ;
+ }
+ for (; i < (len >> 3) ; i++)
+ {
+ byte_copy(fmt, 8, s + len - 8 - (i << 3)) ;
+ uint32_xscan(fmt, x + i) ;
+ }
+}
diff --git a/src/libbiguint/bu_scanlen.c b/src/libbiguint/bu_scanlen.c
new file mode 100644
index 0000000..88c6aee
--- /dev/null
+++ b/src/libbiguint/bu_scanlen.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+#include <skalibs/fmtscan.h>
+#include <skalibs/biguint.h>
+
+unsigned int bu_scanlen (char const *s, unsigned int *zeron)
+{
+ unsigned int n = ucharn_findlen(s) ;
+ *zeron = n ;
+ while (*s == '0') { s++ ; (*zeron)-- ; }
+ return n ;
+}
diff --git a/src/libbiguint/bu_slbc.c b/src/libbiguint/bu_slbc.c
new file mode 100644
index 0000000..081c599
--- /dev/null
+++ b/src/libbiguint/bu_slbc.c
@@ -0,0 +1,17 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/biguint.h>
+
+int bu_slbc (register uint32 *a, register unsigned int n, register int carry)
+{
+ register unsigned int i = 0 ;
+ carry = !!carry ;
+ for (; i < n ; i++)
+ {
+ register int c = a[i] >> 31 ;
+ a[i] = (a[i] << 1) | carry ;
+ carry = c ;
+ }
+ return carry ;
+}
diff --git a/src/libbiguint/bu_srbc.c b/src/libbiguint/bu_srbc.c
new file mode 100644
index 0000000..87196b1
--- /dev/null
+++ b/src/libbiguint/bu_srbc.c
@@ -0,0 +1,15 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/biguint.h>
+
+int bu_srbc (register uint32 *a, register unsigned int n, register int carry)
+{
+ while (n--)
+ {
+ register int c = a[n] & 1 ;
+ a[n] = (a[n] >> 1) | (carry ? 0x80000000UL : 0) ;
+ carry = c ;
+ }
+ return carry ;
+}
diff --git a/src/libbiguint/bu_subc.c b/src/libbiguint/bu_subc.c
new file mode 100644
index 0000000..c26adca
--- /dev/null
+++ b/src/libbiguint/bu_subc.c
@@ -0,0 +1,22 @@
+/* ISC license. */
+
+/* OpenBSD needs that for EOVERFLOW. wtfbsdseriously */
+#define _BSD_SOURCE
+
+#include <errno.h>
+#include <skalibs/uint32.h>
+#include <skalibs/biguint.h>
+
+int bu_subc (uint32 *c, unsigned int cn, uint32 const *a, unsigned int an, uint32 const *b, unsigned int bn, register int carry)
+{
+ register unsigned int i = 0 ;
+ for (; i < cn ; i++)
+ {
+ register uint32 ai = (i < an) ? a[i] : 0 ;
+ register uint32 bi = (i < bn) ? b[i] : 0 ;
+ register uint32 ci = ai - bi - carry ;
+ carry = (carry || bi) && (ci > ai) ;
+ c[i] = ci ;
+ }
+ return carry ? (errno = EOVERFLOW, 0) : 1 ;
+}
diff --git a/src/libbiguint/bu_submod.c b/src/libbiguint/bu_submod.c
new file mode 100644
index 0000000..f988a50
--- /dev/null
+++ b/src/libbiguint/bu_submod.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/uint32.h>
+#include <skalibs/biguint.h>
+
+int bu_submod (uint32 *c, unsigned int cn, uint32 const *a, unsigned int an, uint32 const *b, unsigned int bn, uint32 const *m, unsigned int mn)
+{
+ if (!bu_sub(c, cn, a, an, b, bn) && bu_add(c, cn, c, cn, m, mn))
+ return (errno = EDOM, 0) ;
+ return (errno = 0, 1) ;
+}
diff --git a/src/libbiguint/bu_unpack.c b/src/libbiguint/bu_unpack.c
new file mode 100644
index 0000000..d4f4130
--- /dev/null
+++ b/src/libbiguint/bu_unpack.c
@@ -0,0 +1,9 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/biguint.h>
+
+void bu_unpack (char const *s, uint32 *a, register unsigned int n)
+{
+ while (n--) uint32_unpack(s + (n<<2), a + n) ;
+}
diff --git a/src/libbiguint/bu_unpack_big.c b/src/libbiguint/bu_unpack_big.c
new file mode 100644
index 0000000..ef79029
--- /dev/null
+++ b/src/libbiguint/bu_unpack_big.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/biguint.h>
+
+void bu_unpack_big (char const *s, uint32 *a, unsigned int n)
+{
+ register unsigned int i = 0 ;
+ for (; i < n ; i++) uint32_unpack_big(s + (i<<2), a + n - 1 - i) ;
+}
diff --git a/src/libbiguint/bu_zero.c b/src/libbiguint/bu_zero.c
new file mode 100644
index 0000000..07efd69
--- /dev/null
+++ b/src/libbiguint/bu_zero.c
@@ -0,0 +1,9 @@
+/* ISC license. */
+
+#include <skalibs/uint32.h>
+#include <skalibs/biguint.h>
+
+void bu_zero (register uint32 *z, register unsigned int n)
+{
+ while (n--) z[n] = 0 ;
+}