aboutsummaryrefslogtreecommitdiff
path: root/v_windows/v/thirdparty/bignum
diff options
context:
space:
mode:
Diffstat (limited to 'v_windows/v/thirdparty/bignum')
-rw-r--r--v_windows/v/thirdparty/bignum/README.md2
-rw-r--r--v_windows/v/thirdparty/bignum/bn.c664
-rw-r--r--v_windows/v/thirdparty/bignum/bn.h123
3 files changed, 789 insertions, 0 deletions
diff --git a/v_windows/v/thirdparty/bignum/README.md b/v_windows/v/thirdparty/bignum/README.md
new file mode 100644
index 0000000..04eb555
--- /dev/null
+++ b/v_windows/v/thirdparty/bignum/README.md
@@ -0,0 +1,2 @@
+This folder contains bn.h and bn.c files
+from https://github.com/kokke/tiny-bignum-c
diff --git a/v_windows/v/thirdparty/bignum/bn.c b/v_windows/v/thirdparty/bignum/bn.c
new file mode 100644
index 0000000..7ec0895
--- /dev/null
+++ b/v_windows/v/thirdparty/bignum/bn.c
@@ -0,0 +1,664 @@
+/*
+
+Big number library - arithmetic on multiple-precision unsigned integers.
+
+This library is an implementation of arithmetic on arbitrarily large integers.
+
+The difference between this and other implementations, is that the data structure
+has optimal memory utilization (i.e. a 1024 bit integer takes up 128 bytes RAM),
+and all memory is allocated statically: no dynamic allocation for better or worse.
+
+Primary goals are correctness, clarity of code and clean, portable implementation.
+Secondary goal is a memory footprint small enough to make it suitable for use in
+embedded applications.
+
+
+The current state is correct functionality and adequate performance.
+There may well be room for performance-optimizations and improvements.
+
+*/
+
+#include <stdio.h>
+#include <stdbool.h>
+#include <assert.h>
+#include "bn.h"
+
+
+
+/* Functions for shifting number in-place. */
+static void _lshift_one_bit(struct bn* a);
+static void _rshift_one_bit(struct bn* a);
+static void _lshift_word(struct bn* a, int nwords);
+static void _rshift_word(struct bn* a, int nwords);
+
+
+
+/* Public / Exported functions. */
+void bignum_init(struct bn* n)
+{
+ require(n, "n is null");
+
+ int i;
+ for (i = 0; i < BN_ARRAY_SIZE; ++i)
+ {
+ n->array[i] = 0;
+ }
+}
+
+
+void bignum_from_int(struct bn* n, DTYPE_TMP i)
+{
+ require(n, "n is null");
+
+ bignum_init(n);
+
+ /* Endianness issue if machine is not little-endian? */
+#ifdef WORD_SIZE
+ #if (WORD_SIZE == 1)
+ n->array[0] = (i & 0x000000ff);
+ n->array[1] = (i & 0x0000ff00) >> 8;
+ n->array[2] = (i & 0x00ff0000) >> 16;
+ n->array[3] = (i & 0xff000000) >> 24;
+ #elif (WORD_SIZE == 2)
+ n->array[0] = (i & 0x0000ffff);
+ n->array[1] = (i & 0xffff0000) >> 16;
+ #elif (WORD_SIZE == 4)
+ n->array[0] = i;
+ DTYPE_TMP num_32 = 32;
+ DTYPE_TMP tmp = i >> num_32; /* bit-shift with U64 operands to force 64-bit results */
+ n->array[1] = tmp;
+ #endif
+#endif
+}
+
+
+int bignum_to_int(struct bn* n)
+{
+ require(n, "n is null");
+
+ int ret = 0;
+
+ /* Endianness issue if machine is not little-endian? */
+#if (WORD_SIZE == 1)
+ ret += n->array[0];
+ ret += n->array[1] << 8;
+ ret += n->array[2] << 16;
+ ret += n->array[3] << 24;
+#elif (WORD_SIZE == 2)
+ ret += n->array[0];
+ ret += n->array[1] << 16;
+#elif (WORD_SIZE == 4)
+ ret += n->array[0];
+#endif
+
+ return ret;
+}
+
+
+void bignum_from_string(struct bn* n, char* str, int nbytes)
+{
+ require(n, "n is null");
+ require(str, "str is null");
+ require(nbytes > 0, "nbytes must be positive");
+ require((nbytes & 1) == 0, "string format must be in hex -> equal number of bytes");
+
+ bignum_init(n);
+
+ DTYPE tmp; /* DTYPE is defined in bn.h - uint{8,16,32,64}_t */
+ int i = nbytes - (2 * WORD_SIZE); /* index into string */
+ int j = 0; /* index into array */
+
+ /* reading last hex-byte "MSB" from string first -> big endian */
+ /* MSB ~= most significant byte / block ? :) */
+ while (i >= 0)
+ {
+ tmp = 0;
+ sscanf(&str[i], SSCANF_FORMAT_STR, &tmp);
+ n->array[j] = tmp;
+ i -= (2 * WORD_SIZE); /* step WORD_SIZE hex-byte(s) back in the string. */
+ j += 1; /* step one element forward in the array. */
+ }
+}
+
+
+void bignum_to_string(struct bn* n, char* str, int nbytes)
+{
+ require(n, "n is null");
+ require(str, "str is null");
+ require(nbytes > 0, "nbytes must be positive");
+ require((nbytes & 1) == 0, "string format must be in hex -> equal number of bytes");
+
+ int j = BN_ARRAY_SIZE - 1; /* index into array - reading "MSB" first -> big-endian */
+ int i = 0; /* index into string representation. */
+
+ /* reading last array-element "MSB" first -> big endian */
+ while ((j >= 0) && (nbytes > (i + 1)))
+ {
+ sprintf(&str[i], SPRINTF_FORMAT_STR, n->array[j]);
+ i += (2 * WORD_SIZE); /* step WORD_SIZE hex-byte(s) forward in the string. */
+ j -= 1; /* step one element back in the array. */
+ }
+
+ /* Count leading zeros: */
+ j = 0;
+ while (str[j] == '0')
+ {
+ j += 1;
+ }
+
+ /* Move string j places ahead, effectively skipping leading zeros */
+ for (i = 0; i < (nbytes - j); ++i)
+ {
+ str[i] = str[i + j];
+ }
+
+ /* Zero-terminate string */
+ str[i] = 0;
+}
+
+
+void bignum_dec(struct bn* n)
+{
+ require(n, "n is null");
+
+ DTYPE tmp; /* copy of n */
+ DTYPE res;
+
+ int i;
+ for (i = 0; i < BN_ARRAY_SIZE; ++i)
+ {
+ tmp = n->array[i];
+ res = tmp - 1;
+ n->array[i] = res;
+
+ if (!(res > tmp))
+ {
+ break;
+ }
+ }
+}
+
+
+void bignum_inc(struct bn* n)
+{
+ require(n, "n is null");
+
+ DTYPE res;
+ DTYPE_TMP tmp; /* copy of n */
+
+ int i;
+ for (i = 0; i < BN_ARRAY_SIZE; ++i)
+ {
+ tmp = n->array[i];
+ res = tmp + 1;
+ n->array[i] = res;
+
+ if (res > tmp)
+ {
+ break;
+ }
+ }
+}
+
+
+void bignum_add(struct bn* a, struct bn* b, struct bn* c)
+{
+ require(a, "a is null");
+ require(b, "b is null");
+ require(c, "c is null");
+
+ DTYPE_TMP tmp;
+ int carry = 0;
+ int i;
+ for (i = 0; i < BN_ARRAY_SIZE; ++i)
+ {
+ tmp = (DTYPE_TMP)a->array[i] + b->array[i] + carry;
+ carry = (tmp > MAX_VAL);
+ c->array[i] = (tmp & MAX_VAL);
+ }
+}
+
+
+void bignum_sub(struct bn* a, struct bn* b, struct bn* c)
+{
+ require(a, "a is null");
+ require(b, "b is null");
+ require(c, "c is null");
+
+ DTYPE_TMP res;
+ DTYPE_TMP tmp1;
+ DTYPE_TMP tmp2;
+ int borrow = 0;
+ int i;
+ for (i = 0; i < BN_ARRAY_SIZE; ++i)
+ {
+ tmp1 = (DTYPE_TMP)a->array[i] + (MAX_VAL + 1); /* + number_base */
+ tmp2 = (DTYPE_TMP)b->array[i] + borrow;;
+ res = (tmp1 - tmp2);
+ c->array[i] = (DTYPE)(res & MAX_VAL); /* "modulo number_base" == "% (number_base - 1)" if number_base is 2^N */
+ borrow = (res <= MAX_VAL);
+ }
+}
+
+
+void bignum_mul(struct bn* a, struct bn* b, struct bn* c)
+{
+ require(a, "a is null");
+ require(b, "b is null");
+ require(c, "c is null");
+
+ struct bn row;
+ struct bn tmp;
+ int i, j;
+
+ bignum_init(c);
+
+ for (i = 0; i < BN_ARRAY_SIZE; ++i)
+ {
+ bignum_init(&row);
+
+ for (j = 0; j < BN_ARRAY_SIZE; ++j)
+ {
+ if (i + j < BN_ARRAY_SIZE)
+ {
+ bignum_init(&tmp);
+ DTYPE_TMP intermediate = ((DTYPE_TMP)a->array[i] * (DTYPE_TMP)b->array[j]);
+ bignum_from_int(&tmp, intermediate);
+ _lshift_word(&tmp, i + j);
+ bignum_add(&tmp, &row, &row);
+ }
+ }
+ bignum_add(c, &row, c);
+ }
+}
+
+
+void bignum_div(struct bn* a, struct bn* b, struct bn* c)
+{
+ require(a, "a is null");
+ require(b, "b is null");
+ require(c, "c is null");
+
+ struct bn current;
+ struct bn denom;
+ struct bn tmp;
+
+ bignum_from_int(&current, 1); // int current = 1;
+ bignum_assign(&denom, b); // denom = b
+ bignum_assign(&tmp, a); // tmp = a
+
+ const DTYPE_TMP half_max = 1 + (DTYPE_TMP)(MAX_VAL / 2);
+ bool overflow = false;
+ while (bignum_cmp(&denom, a) != LARGER) // while (denom <= a) {
+ {
+ if (denom.array[BN_ARRAY_SIZE - 1] >= half_max)
+ {
+ overflow = true;
+ break;
+ }
+ _lshift_one_bit(&current); // current <<= 1;
+ _lshift_one_bit(&denom); // denom <<= 1;
+ }
+ if (!overflow)
+ {
+ _rshift_one_bit(&denom); // denom >>= 1;
+ _rshift_one_bit(&current); // current >>= 1;
+ }
+ bignum_init(c); // int answer = 0;
+
+ while (!bignum_is_zero(&current)) // while (current != 0)
+ {
+ if (bignum_cmp(&tmp, &denom) != SMALLER) // if (dividend >= denom)
+ {
+ bignum_sub(&tmp, &denom, &tmp); // dividend -= denom;
+ bignum_or(c, &current, c); // answer |= current;
+ }
+ _rshift_one_bit(&current); // current >>= 1;
+ _rshift_one_bit(&denom); // denom >>= 1;
+ } // return answer;
+}
+
+
+void bignum_lshift(struct bn* a, struct bn* b, int nbits)
+{
+ require(a, "a is null");
+ require(b, "b is null");
+ require(nbits >= 0, "no negative shifts");
+
+ bignum_assign(b, a);
+ /* Handle shift in multiples of word-size */
+ const int nbits_pr_word = (WORD_SIZE * 8);
+ int nwords = nbits / nbits_pr_word;
+ if (nwords != 0)
+ {
+ _lshift_word(b, nwords);
+ nbits -= (nwords * nbits_pr_word);
+ }
+
+ if (nbits != 0)
+ {
+ int i;
+ for (i = (BN_ARRAY_SIZE - 1); i > 0; --i)
+ {
+ b->array[i] = (b->array[i] << nbits) | (b->array[i - 1] >> ((8 * WORD_SIZE) - nbits));
+ }
+ b->array[i] <<= nbits;
+ }
+}
+
+
+void bignum_rshift(struct bn* a, struct bn* b, int nbits)
+{
+ require(a, "a is null");
+ require(b, "b is null");
+ require(nbits >= 0, "no negative shifts");
+
+ bignum_assign(b, a);
+ /* Handle shift in multiples of word-size */
+ const int nbits_pr_word = (WORD_SIZE * 8);
+ int nwords = nbits / nbits_pr_word;
+ if (nwords != 0)
+ {
+ _rshift_word(b, nwords);
+ nbits -= (nwords * nbits_pr_word);
+ }
+
+ if (nbits != 0)
+ {
+ int i;
+ for (i = 0; i < (BN_ARRAY_SIZE - 1); ++i)
+ {
+ b->array[i] = (b->array[i] >> nbits) | (b->array[i + 1] << ((8 * WORD_SIZE) - nbits));
+ }
+ b->array[i] >>= nbits;
+ }
+
+}
+
+
+void bignum_mod(struct bn* a, struct bn* b, struct bn* c)
+{
+ /*
+ Take divmod and throw away div part
+ */
+ require(a, "a is null");
+ require(b, "b is null");
+ require(c, "c is null");
+
+ struct bn tmp;
+
+ bignum_divmod(a,b,&tmp,c);
+}
+
+void bignum_divmod(struct bn* a, struct bn* b, struct bn* c, struct bn* d)
+{
+ /*
+ Puts a%b in d
+ and a/b in c
+
+ mod(a,b) = a - ((a / b) * b)
+
+ example:
+ mod(8, 3) = 8 - ((8 / 3) * 3) = 2
+ */
+ require(a, "a is null");
+ require(b, "b is null");
+ require(c, "c is null");
+
+ struct bn tmp;
+
+ /* c = (a / b) */
+ bignum_div(a, b, c);
+
+ /* tmp = (c * b) */
+ bignum_mul(c, b, &tmp);
+
+ /* c = a - tmp */
+ bignum_sub(a, &tmp, d);
+}
+
+
+void bignum_and(struct bn* a, struct bn* b, struct bn* c)
+{
+ require(a, "a is null");
+ require(b, "b is null");
+ require(c, "c is null");
+
+ int i;
+ for (i = 0; i < BN_ARRAY_SIZE; ++i)
+ {
+ c->array[i] = (a->array[i] & b->array[i]);
+ }
+}
+
+
+void bignum_or(struct bn* a, struct bn* b, struct bn* c)
+{
+ require(a, "a is null");
+ require(b, "b is null");
+ require(c, "c is null");
+
+ int i;
+ for (i = 0; i < BN_ARRAY_SIZE; ++i)
+ {
+ c->array[i] = (a->array[i] | b->array[i]);
+ }
+}
+
+
+void bignum_xor(struct bn* a, struct bn* b, struct bn* c)
+{
+ require(a, "a is null");
+ require(b, "b is null");
+ require(c, "c is null");
+
+ int i;
+ for (i = 0; i < BN_ARRAY_SIZE; ++i)
+ {
+ c->array[i] = (a->array[i] ^ b->array[i]);
+ }
+}
+
+
+int bignum_cmp(struct bn* a, struct bn* b)
+{
+ require(a, "a is null");
+ require(b, "b is null");
+
+ int i = BN_ARRAY_SIZE;
+ do
+ {
+ i -= 1; /* Decrement first, to start with last array element */
+ if (a->array[i] > b->array[i])
+ {
+ return LARGER;
+ }
+ else if (a->array[i] < b->array[i])
+ {
+ return SMALLER;
+ }
+ }
+ while (i != 0);
+
+ return EQUAL;
+}
+
+
+int bignum_is_zero(struct bn* n)
+{
+ require(n, "n is null");
+
+ int i;
+ for (i = 0; i < BN_ARRAY_SIZE; ++i)
+ {
+ if (n->array[i])
+ {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+
+void bignum_pow(struct bn* a, struct bn* b, struct bn* c)
+{
+ require(a, "a is null");
+ require(b, "b is null");
+ require(c, "c is null");
+
+ struct bn tmp;
+
+ bignum_init(c);
+
+ if (bignum_cmp(b, c) == EQUAL)
+ {
+ /* Return 1 when exponent is 0 -- n^0 = 1 */
+ bignum_inc(c);
+ }
+ else
+ {
+ struct bn bcopy;
+ bignum_assign(&bcopy, b);
+
+ /* Copy a -> tmp */
+ bignum_assign(&tmp, a);
+
+ bignum_dec(&bcopy);
+
+ /* Begin summing products: */
+ while (!bignum_is_zero(&bcopy))
+ {
+
+ /* c = tmp * tmp */
+ bignum_mul(&tmp, a, c);
+ /* Decrement b by one */
+ bignum_dec(&bcopy);
+
+ bignum_assign(&tmp, c);
+ }
+
+ /* c = tmp */
+ bignum_assign(c, &tmp);
+ }
+}
+
+void bignum_isqrt(struct bn *a, struct bn* b)
+{
+ require(a, "a is null");
+ require(b, "b is null");
+
+ struct bn low, high, mid, tmp;
+
+ bignum_init(&low);
+ bignum_assign(&high, a);
+ bignum_rshift(&high, &mid, 1);
+ bignum_inc(&mid);
+
+ while (bignum_cmp(&high, &low) > 0)
+ {
+ bignum_mul(&mid, &mid, &tmp);
+ if (bignum_cmp(&tmp, a) > 0)
+ {
+ bignum_assign(&high, &mid);
+ bignum_dec(&high);
+ }
+ else
+ {
+ bignum_assign(&low, &mid);
+ }
+ bignum_sub(&high,&low,&mid);
+ _rshift_one_bit(&mid);
+ bignum_add(&low,&mid,&mid);
+ bignum_inc(&mid);
+ }
+ bignum_assign(b,&low);
+}
+
+
+void bignum_assign(struct bn* dst, struct bn* src)
+{
+ require(dst, "dst is null");
+ require(src, "src is null");
+
+ int i;
+ for (i = 0; i < BN_ARRAY_SIZE; ++i)
+ {
+ dst->array[i] = src->array[i];
+ }
+}
+
+
+/* Private / Static functions. */
+static void _rshift_word(struct bn* a, int nwords)
+{
+ /* Naive method: */
+ require(a, "a is null");
+ require(nwords >= 0, "no negative shifts");
+
+ int i;
+ if (nwords >= BN_ARRAY_SIZE)
+ {
+ for (i = 0; i < BN_ARRAY_SIZE; ++i)
+ {
+ a->array[i] = 0;
+ }
+ return;
+ }
+
+ for (i = 0; i < BN_ARRAY_SIZE - nwords; ++i)
+ {
+ a->array[i] = a->array[i + nwords];
+ }
+ for (; i < BN_ARRAY_SIZE; ++i)
+ {
+ a->array[i] = 0;
+ }
+}
+
+
+static void _lshift_word(struct bn* a, int nwords)
+{
+ require(a, "a is null");
+ require(nwords >= 0, "no negative shifts");
+
+ int i;
+ /* Shift whole words */
+ for (i = (BN_ARRAY_SIZE - 1); i >= nwords; --i)
+ {
+ a->array[i] = a->array[i - nwords];
+ }
+ /* Zero pad shifted words. */
+ for (; i >= 0; --i)
+ {
+ a->array[i] = 0;
+ }
+}
+
+
+static void _lshift_one_bit(struct bn* a)
+{
+ require(a, "a is null");
+
+ int i;
+ for (i = (BN_ARRAY_SIZE - 1); i > 0; --i)
+ {
+ a->array[i] = (a->array[i] << 1) | (a->array[i - 1] >> ((8 * WORD_SIZE) - 1));
+ }
+ a->array[0] <<= 1;
+}
+
+
+static void _rshift_one_bit(struct bn* a)
+{
+ require(a, "a is null");
+
+ int i;
+ for (i = 0; i < (BN_ARRAY_SIZE - 1); ++i)
+ {
+ a->array[i] = (a->array[i] >> 1) | (a->array[i + 1] << ((8 * WORD_SIZE) - 1));
+ }
+ a->array[BN_ARRAY_SIZE - 1] >>= 1;
+}
+
+
diff --git a/v_windows/v/thirdparty/bignum/bn.h b/v_windows/v/thirdparty/bignum/bn.h
new file mode 100644
index 0000000..f82676f
--- /dev/null
+++ b/v_windows/v/thirdparty/bignum/bn.h
@@ -0,0 +1,123 @@
+#ifndef __BIGNUM_H__
+#define __BIGNUM_H__
+/*
+
+Big number library - arithmetic on multiple-precision unsigned integers.
+
+This library is an implementation of arithmetic on arbitrarily large integers.
+
+The difference between this and other implementations, is that the data structure
+has optimal memory utilization (i.e. a 1024 bit integer takes up 128 bytes RAM),
+and all memory is allocated statically: no dynamic allocation for better or worse.
+
+Primary goals are correctness, clarity of code and clean, portable implementation.
+Secondary goal is a memory footprint small enough to make it suitable for use in
+embedded applications.
+
+
+The current state is correct functionality and adequate performance.
+There may well be room for performance-optimizations and improvements.
+
+*/
+
+#include <stdint.h>
+#include <assert.h>
+
+
+/* This macro defines the word size in bytes of the array that constitues the big-number data structure. */
+#ifndef WORD_SIZE
+ #define WORD_SIZE 4
+#endif
+
+/* Size of big-numbers in bytes */
+#define BN_ARRAY_SIZE (128 / WORD_SIZE)
+
+
+/* Here comes the compile-time specialization for how large the underlying array size should be. */
+/* The choices are 1, 2 and 4 bytes in size with uint32, uint64 for WORD_SIZE==4, as temporary. */
+#ifndef WORD_SIZE
+ #error Must define WORD_SIZE to be 1, 2, 4
+#elif (WORD_SIZE == 1)
+ /* Data type of array in structure */
+ #define DTYPE uint8_t
+ /* bitmask for getting MSB */
+ #define DTYPE_MSB ((DTYPE_TMP)(0x80))
+ /* Data-type larger than DTYPE, for holding intermediate results of calculations */
+ #define DTYPE_TMP uint32_t
+ /* sprintf format string */
+ #define SPRINTF_FORMAT_STR "%.02x"
+ #define SSCANF_FORMAT_STR "%2hhx"
+ /* Max value of integer type */
+ #define MAX_VAL ((DTYPE_TMP)0xFF)
+#elif (WORD_SIZE == 2)
+ #define DTYPE uint16_t
+ #define DTYPE_TMP uint32_t
+ #define DTYPE_MSB ((DTYPE_TMP)(0x8000))
+ #define SPRINTF_FORMAT_STR "%.04x"
+ #define SSCANF_FORMAT_STR "%4hx"
+ #define MAX_VAL ((DTYPE_TMP)0xFFFF)
+#elif (WORD_SIZE == 4)
+ #define DTYPE uint32_t
+ #define DTYPE_TMP uint64_t
+ #define DTYPE_MSB ((DTYPE_TMP)(0x80000000))
+ #define SPRINTF_FORMAT_STR "%.08x"
+ #define SSCANF_FORMAT_STR "%8x"
+ #define MAX_VAL ((DTYPE_TMP)0xFFFFFFFF)
+#endif
+#ifndef DTYPE
+ #error DTYPE must be defined to uint8_t, uint16_t uint32_t or whatever
+#endif
+
+
+/* Custom assert macro - easy to disable */
+#define require(p, msg) assert(p && #msg)
+
+
+/* Data-holding structure: array of DTYPEs */
+struct bn
+{
+ DTYPE array[BN_ARRAY_SIZE];
+};
+
+
+
+/* Tokens returned by bignum_cmp() for value comparison */
+enum { SMALLER = -1, EQUAL = 0, LARGER = 1 };
+
+
+
+/* Initialization functions: */
+void bignum_init(struct bn* n);
+void bignum_from_int(struct bn* n, DTYPE_TMP i);
+int bignum_to_int(struct bn* n);
+void bignum_from_string(struct bn* n, char* str, int nbytes);
+void bignum_to_string(struct bn* n, char* str, int maxsize);
+
+/* Basic arithmetic operations: */
+void bignum_add(struct bn* a, struct bn* b, struct bn* c); /* c = a + b */
+void bignum_sub(struct bn* a, struct bn* b, struct bn* c); /* c = a - b */
+void bignum_mul(struct bn* a, struct bn* b, struct bn* c); /* c = a * b */
+void bignum_div(struct bn* a, struct bn* b, struct bn* c); /* c = a / b */
+void bignum_mod(struct bn* a, struct bn* b, struct bn* c); /* c = a % b */
+void bignum_divmod(struct bn* a, struct bn* b, struct bn* c, struct bn* d); /* c = a/b, d = a%b */
+
+/* Bitwise operations: */
+void bignum_and(struct bn* a, struct bn* b, struct bn* c); /* c = a & b */
+void bignum_or(struct bn* a, struct bn* b, struct bn* c); /* c = a | b */
+void bignum_xor(struct bn* a, struct bn* b, struct bn* c); /* c = a ^ b */
+void bignum_lshift(struct bn* a, struct bn* b, int nbits); /* b = a << nbits */
+void bignum_rshift(struct bn* a, struct bn* b, int nbits); /* b = a >> nbits */
+
+/* Special operators and comparison */
+int bignum_cmp(struct bn* a, struct bn* b); /* Compare: returns LARGER, EQUAL or SMALLER */
+int bignum_is_zero(struct bn* n); /* For comparison with zero */
+void bignum_inc(struct bn* n); /* Increment: add one to n */
+void bignum_dec(struct bn* n); /* Decrement: subtract one from n */
+void bignum_pow(struct bn* a, struct bn* b, struct bn* c); /* Calculate a^b -- e.g. 2^10 => 1024 */
+void bignum_isqrt(struct bn* a, struct bn* b); /* Integer square root -- e.g. isqrt(5) => 2*/
+void bignum_assign(struct bn* dst, struct bn* src); /* Copy src into dst -- dst := src */
+
+
+#endif /* #ifndef __BIGNUM_H__ */
+
+