diff options
Diffstat (limited to 'src/libbiguint')
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 ; +} |