diff --git a/bn_mp_factors_add.c b/bn_mp_factors_add.c
new file mode 100644
index 000000000..2dd5c5f82
--- /dev/null
+++ b/bn_mp_factors_add.c
@@ -0,0 +1,30 @@
+#include "tommath_private.h"
+#ifdef BN_MP_FACTORS_ADD_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* Add one element (mp_int) to a factor-array (an array of mp_int's) */
+int mp_factors_add(const mp_int *a, mp_factors *f)
+{
+ int new_size = f->alloc;
+ mp_int *tmp;
+ mp_int t;
+ if (f->alloc <= f->length) {
+ new_size += LTM_TRIAL_GROWTH;
+ tmp = (mp_int *) XREALLOC(f->factors, sizeof(*tmp) * f->alloc,
+ sizeof(*tmp) * (size_t)(new_size));
+ if (tmp == NULL) {
+ return MP_MEM;
+ }
+ f->factors = tmp;
+ f->alloc = new_size;
+ }
+ mp_init(&t);
+ mp_copy(a,&t);
+ f->factors[f->length] = t;
+ f->length++;
+ return MP_OKAY;
+}
+
+#endif
+
diff --git a/bn_mp_factors_clear.c b/bn_mp_factors_clear.c
new file mode 100644
index 000000000..c68c00a89
--- /dev/null
+++ b/bn_mp_factors_clear.c
@@ -0,0 +1,22 @@
+#include "tommath_private.h"
+#ifdef BN_MP_FACTORS_CLEAR_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* Clear and free factor-array (an array of mp_int's) */
+void mp_factors_clear(mp_factors *f)
+{
+ int i;
+ if (f->factors != NULL) {
+ for (i = 0; i < f->length; i++) {
+ mp_clear(&f->factors[i]);
+ }
+ XFREE(f->factors, sizeof(mp_int) * f->alloc);
+ f->factors = NULL;
+ f->alloc = 0;
+ f->length = 0;
+ }
+}
+
+#endif
+
diff --git a/bn_mp_factors_compress.c b/bn_mp_factors_compress.c
new file mode 100644
index 000000000..c0f99ca45
--- /dev/null
+++ b/bn_mp_factors_compress.c
@@ -0,0 +1,68 @@
+#include "tommath_private.h"
+#ifdef BN_MP_FACTORS_COMPRESS_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+
+/* Change (sorted) factors array into format prime,prime-count,...,prime,prime-count */
+int mp_factors_compress(mp_factors *f, int sorted, mp_factors *g)
+{
+ int i, e = MP_OKAY;
+ mp_int count;
+ mp_factors in, out, t;
+
+ if ((e = mp_init(&count)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+ if ((e = mp_factors_init(&out)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+
+ if ((e = mp_factors_init(&in)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+ for (i = 0; i < f->length; i++) {
+ if ((e = mp_factors_add(&(f->factors[i]), &in)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+ }
+ if (sorted == MP_NO) {
+ mp_factors_sort(&in);
+ }
+
+ for (i = 1; i < in.length; i++) {
+ if ((e = mp_incr(&count)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+ if (mp_cmp(&(in.factors[i-1]), &(in.factors[i])) != MP_EQ) {
+ if ((e = mp_factors_add(&(in.factors[i-1]), &out)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+ if ((e = mp_factors_add(&count, &out)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+ mp_zero(&count);
+ }
+ }
+ /* and the last one, too */
+ if ((e = mp_incr(&count)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+ if ((e = mp_factors_add(&(in.factors[i-1]), &out)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+ if ((e = mp_factors_add(&count, &out)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+
+ t = *g;
+ *g = out;
+ out = t;
+
+LTM_ERR:
+ mp_factors_clear(&in);
+ mp_clear(&count);
+ mp_factors_clear(&out);
+ return e;
+}
+#endif
diff --git a/bn_mp_factors_init.c b/bn_mp_factors_init.c
new file mode 100644
index 000000000..f180d586d
--- /dev/null
+++ b/bn_mp_factors_init.c
@@ -0,0 +1,19 @@
+#include "tommath_private.h"
+#ifdef BN_MP_FACTORS_INIT_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* Init factor-array (an array of mp_int's) */
+int mp_factors_init(mp_factors *f)
+{
+ f->factors = (mp_int *) XCALLOC((size_t)(LTM_TRIAL_GROWTH), sizeof(mp_int));
+ if ((f->factors) == NULL) {
+ return MP_MEM;
+ }
+ f->alloc = LTM_TRIAL_GROWTH;
+ f->length = 0;
+ return MP_OKAY;
+}
+
+#endif
+
diff --git a/bn_mp_factors_print.c b/bn_mp_factors_print.c
new file mode 100644
index 000000000..ec711e05f
--- /dev/null
+++ b/bn_mp_factors_print.c
@@ -0,0 +1,32 @@
+#include "tommath_private.h"
+#ifdef BN_MP_FACTORS_PRINT_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* Print the elememts of a factor-array (an array of mp_int's) */
+int mp_factors_print(const mp_factors *f, int base, char delimiter, FILE *stream)
+{
+ int i, e = MP_OKAY;
+ int d;
+ if (delimiter != 0) {
+ d = (int)delimiter;
+ } else {
+ d = ',';
+ }
+ if (f->factors != NULL) {
+ for (i = 0; i < f->length; i++) {
+ if ((e = mp_fwrite(&(f->factors[i]),base, stream)) != MP_OKAY) {
+ return e;
+ }
+ if (i < ((f->length)-1)) {
+ if (fputc(d, stream) == EOF) {
+ return MP_VAL;
+ }
+ }
+ }
+ }
+ return e;
+}
+
+#endif
+
diff --git a/bn_mp_factors_product.c b/bn_mp_factors_product.c
new file mode 100644
index 000000000..8cfb4ee3a
--- /dev/null
+++ b/bn_mp_factors_product.c
@@ -0,0 +1,63 @@
+#include "tommath_private.h"
+#ifdef BN_MP_FACTORS_PRODUCT_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* Compute the product of the elements of "factors" */
+static int s_product_lowlevel(const mp_factors *factors, int start, int n, mp_int *result)
+{
+ int i, first_half, second_half;
+ mp_int tmp;
+ int e = MP_OKAY;
+
+ if (n == 0) {
+ mp_set(result, 1uL);
+ return MP_OKAY;
+ }
+ /* Do the rest linearily. Faster for primorials at least, but YMMV */
+ if (n <= 64) {
+ mp_set_long(result,1uL);
+ for (i = 0; i < n; i++) {
+ if ((e = mp_mul(result, &(factors->factors[i+start]), result)) != MP_OKAY) {
+ return e;
+ }
+ }
+ return MP_OKAY;
+ }
+
+ first_half = n / 2;
+ second_half = n - first_half;
+ if ((e = s_product_lowlevel(factors, start, second_half, result)) != MP_OKAY) {
+ return e;
+ }
+ if ((e = mp_init(&tmp)) != MP_OKAY) {
+ return e;
+ }
+ if ((e = s_product_lowlevel(factors, start+second_half, first_half, &tmp)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+ if ((e = mp_mul(result, &tmp, result)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+
+LTM_ERR:
+ mp_clear(&tmp);
+ return e;
+}
+
+int mp_factors_product(const mp_factors *factors, mp_int *p)
+{
+ int e, r;
+ r = factors->length;
+ if (r == 0) {
+ return MP_VAL;
+ }
+ if (r == 1) {
+ return mp_copy(&(factors->factors[0]), p);
+ }
+ if ((e = s_product_lowlevel(factors, 0, r, p)) != MP_OKAY) {
+ return e;
+ }
+ return MP_OKAY;
+}
+#endif
diff --git a/bn_mp_factors_sort.c b/bn_mp_factors_sort.c
new file mode 100644
index 000000000..fb4a6511b
--- /dev/null
+++ b/bn_mp_factors_sort.c
@@ -0,0 +1,27 @@
+#include "tommath_private.h"
+#ifdef BN_MP_FACTORS_SORT_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* Sort factor-array (an array of mp_int's) */
+/* TODO: Sorts inline. Work on copy instead? */
+void mp_factors_sort(mp_factors *f)
+{
+ int i, idx;
+ mp_int tmp;
+
+ /*
+ It will be almost always be already sorted and even if it is unsorted
+ it will just show a bushy tail. So insertion sort it is.
+ */
+ for (i = 1 ; i < f->length; i++) {
+ idx = i;
+ while ((idx > 0) && (mp_cmp(&(f->factors[idx-1]),&(f->factors[idx])) == MP_GT)) {
+ mp_exch(&(f->factors[idx]), &tmp);
+ mp_exch(&(f->factors[idx-1]), &(f->factors[idx]));
+ mp_exch(&tmp, &(f->factors[idx-1]));
+ idx--;
+ }
+ }
+}
+#endif
diff --git a/bn_mp_factors_zero.c b/bn_mp_factors_zero.c
new file mode 100644
index 000000000..784e0ebd5
--- /dev/null
+++ b/bn_mp_factors_zero.c
@@ -0,0 +1,33 @@
+#include "tommath_private.h"
+#ifdef BN_MP_FACTORS_ZERO_C
+/* LibTomMath, multiple-precision integer library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* Zero the elements of a factor-array (an array of mp_int's) and realloc to default
+ size in that order */
+int mp_factors_zero(mp_factors *f)
+{
+ int i, e = MP_OKAY;
+ mp_int *tmp;
+
+ if (f->factors != NULL) {
+ for (i = 0; i < f->length; i++) {
+ mp_clear(&(f->factors[i]));
+ }
+ }
+
+ tmp = (mp_int *) XREALLOC(f->factors, sizeof(*tmp) * f->alloc,
+ sizeof(*tmp) * LTM_TRIAL_GROWTH);
+ if (tmp == NULL) {
+ return MP_MEM;
+ }
+
+ f->factors = tmp;
+ f->alloc = LTM_TRIAL_GROWTH;
+ f->length = 0;
+
+ return e;
+}
+
+#endif
+
diff --git a/callgraph.txt b/callgraph.txt
index eeeea1383..42e672814 100644
--- a/callgraph.txt
+++ b/callgraph.txt
@@ -2496,6 +2496,226 @@ BN_MP_EXTEUCLID_C
| +--->BN_MP_CLEAR_C
+BN_MP_FACTORS_ADD_C
++--->BN_MP_INIT_C
++--->BN_MP_COPY_C
+| +--->BN_MP_GROW_C
+
+
+BN_MP_FACTORS_CLEAR_C
++--->BN_MP_CLEAR_C
+
+
+BN_MP_FACTORS_COMPRESS_C
++--->BN_MP_INIT_C
++--->BN_MP_FACTORS_INIT_C
++--->BN_MP_FACTORS_ADD_C
+| +--->BN_MP_COPY_C
+| | +--->BN_MP_GROW_C
++--->BN_MP_FACTORS_SORT_C
+| +--->BN_MP_CMP_C
+| | +--->BN_MP_CMP_MAG_C
+| +--->BN_MP_EXCH_C
++--->BN_MP_INCR_C
+| +--->BN_MP_SET_C
+| | +--->BN_MP_ZERO_C
+| +--->BN_MP_DECR_C
+| | +--->BN_MP_ZERO_C
+| | +--->BN_MP_SUB_D_C
+| | | +--->BN_MP_GROW_C
+| | | +--->BN_MP_ADD_D_C
+| | | | +--->BN_MP_CLAMP_C
+| | | +--->BN_MP_CLAMP_C
+| +--->BN_MP_ADD_D_C
+| | +--->BN_MP_GROW_C
+| | +--->BN_MP_SUB_D_C
+| | | +--->BN_MP_CLAMP_C
+| | +--->BN_MP_CLAMP_C
++--->BN_MP_CMP_C
+| +--->BN_MP_CMP_MAG_C
++--->BN_MP_ZERO_C
++--->BN_MP_FACTORS_CLEAR_C
+| +--->BN_MP_CLEAR_C
++--->BN_MP_CLEAR_C
+
+
+BN_MP_FACTORS_INIT_C
+
+
+BN_MP_FACTORS_PRINT_C
++--->BN_MP_FWRITE_C
+| +--->BN_MP_RADIX_SIZE_C
+| | +--->BN_MP_COUNT_BITS_C
+| | +--->BN_MP_INIT_COPY_C
+| | | +--->BN_MP_INIT_SIZE_C
+| | | +--->BN_MP_COPY_C
+| | | | +--->BN_MP_GROW_C
+| | | +--->BN_MP_CLEAR_C
+| | +--->BN_MP_DIV_D_C
+| | | +--->BN_MP_COPY_C
+| | | | +--->BN_MP_GROW_C
+| | | +--->BN_MP_DIV_2D_C
+| | | | +--->BN_MP_ZERO_C
+| | | | +--->BN_MP_MOD_2D_C
+| | | | | +--->BN_MP_CLAMP_C
+| | | | +--->BN_MP_RSHD_C
+| | | | +--->BN_MP_CLAMP_C
+| | | +--->BN_MP_DIV_3_C
+| | | | +--->BN_MP_INIT_SIZE_C
+| | | | +--->BN_MP_CLAMP_C
+| | | | +--->BN_MP_EXCH_C
+| | | | +--->BN_MP_CLEAR_C
+| | | +--->BN_MP_INIT_SIZE_C
+| | | +--->BN_MP_CLAMP_C
+| | | +--->BN_MP_EXCH_C
+| | | +--->BN_MP_CLEAR_C
+| | +--->BN_MP_CLEAR_C
+| +--->BN_MP_TORADIX_C
+| | +--->BN_MP_INIT_COPY_C
+| | | +--->BN_MP_INIT_SIZE_C
+| | | +--->BN_MP_COPY_C
+| | | | +--->BN_MP_GROW_C
+| | | +--->BN_MP_CLEAR_C
+| | +--->BN_MP_DIV_D_C
+| | | +--->BN_MP_COPY_C
+| | | | +--->BN_MP_GROW_C
+| | | +--->BN_MP_DIV_2D_C
+| | | | +--->BN_MP_ZERO_C
+| | | | +--->BN_MP_MOD_2D_C
+| | | | | +--->BN_MP_CLAMP_C
+| | | | +--->BN_MP_RSHD_C
+| | | | +--->BN_MP_CLAMP_C
+| | | +--->BN_MP_DIV_3_C
+| | | | +--->BN_MP_INIT_SIZE_C
+| | | | +--->BN_MP_CLAMP_C
+| | | | +--->BN_MP_EXCH_C
+| | | | +--->BN_MP_CLEAR_C
+| | | +--->BN_MP_INIT_SIZE_C
+| | | +--->BN_MP_CLAMP_C
+| | | +--->BN_MP_EXCH_C
+| | | +--->BN_MP_CLEAR_C
+| | +--->BN_MP_CLEAR_C
+
+
+BN_MP_FACTORS_PRODUCT_C
++--->BN_MP_SET_C
+| +--->BN_MP_ZERO_C
++--->BN_MP_SET_LONG_C
++--->BN_MP_MUL_C
+| +--->BN_FAST_S_MP_MUL_DIGS_C
+| | +--->BN_MP_GROW_C
+| | +--->BN_MP_CLAMP_C
+| +--->BN_MP_BALANCE_MUL_C
+| | +--->BN_MP_INIT_SIZE_C
+| | | +--->BN_MP_INIT_C
+| | +--->BN_MP_INIT_MULTI_C
+| | | +--->BN_MP_INIT_C
+| | | +--->BN_MP_CLEAR_C
+| | +--->BN_MP_CLEAR_C
+| | +--->BN_MP_LSHD_C
+| | | +--->BN_MP_GROW_C
+| | | +--->BN_MP_RSHD_C
+| | | | +--->BN_MP_ZERO_C
+| | +--->BN_MP_ADD_C
+| | | +--->BN_S_MP_ADD_C
+| | | | +--->BN_MP_GROW_C
+| | | | +--->BN_MP_CLAMP_C
+| | | +--->BN_MP_CMP_MAG_C
+| | | +--->BN_S_MP_SUB_C
+| | | | +--->BN_MP_GROW_C
+| | | | +--->BN_MP_CLAMP_C
+| | +--->BN_MP_EXCH_C
+| | +--->BN_MP_CLEAR_MULTI_C
+| +--->BN_MP_TOOM_MUL_C
+| | +--->BN_MP_INIT_MULTI_C
+| | | +--->BN_MP_INIT_C
+| | | +--->BN_MP_CLEAR_C
+| | +--->BN_MP_MOD_2D_C
+| | | +--->BN_MP_ZERO_C
+| | | +--->BN_MP_COPY_C
+| | | | +--->BN_MP_GROW_C
+| | | +--->BN_MP_CLAMP_C
+| | +--->BN_MP_COPY_C
+| | | +--->BN_MP_GROW_C
+| | +--->BN_MP_RSHD_C
+| | | +--->BN_MP_ZERO_C
+| | +--->BN_MP_MUL_2_C
+| | | +--->BN_MP_GROW_C
+| | +--->BN_MP_ADD_C
+| | | +--->BN_S_MP_ADD_C
+| | | | +--->BN_MP_GROW_C
+| | | | +--->BN_MP_CLAMP_C
+| | | +--->BN_MP_CMP_MAG_C
+| | | +--->BN_S_MP_SUB_C
+| | | | +--->BN_MP_GROW_C
+| | | | +--->BN_MP_CLAMP_C
+| | +--->BN_MP_SUB_C
+| | | +--->BN_S_MP_ADD_C
+| | | | +--->BN_MP_GROW_C
+| | | | +--->BN_MP_CLAMP_C
+| | | +--->BN_MP_CMP_MAG_C
+| | | +--->BN_S_MP_SUB_C
+| | | | +--->BN_MP_GROW_C
+| | | | +--->BN_MP_CLAMP_C
+| | +--->BN_MP_DIV_2_C
+| | | +--->BN_MP_GROW_C
+| | | +--->BN_MP_CLAMP_C
+| | +--->BN_MP_MUL_2D_C
+| | | +--->BN_MP_GROW_C
+| | | +--->BN_MP_LSHD_C
+| | | +--->BN_MP_CLAMP_C
+| | +--->BN_MP_MUL_D_C
+| | | +--->BN_MP_GROW_C
+| | | +--->BN_MP_CLAMP_C
+| | +--->BN_MP_DIV_3_C
+| | | +--->BN_MP_INIT_SIZE_C
+| | | | +--->BN_MP_INIT_C
+| | | +--->BN_MP_CLAMP_C
+| | | +--->BN_MP_EXCH_C
+| | | +--->BN_MP_CLEAR_C
+| | +--->BN_MP_LSHD_C
+| | | +--->BN_MP_GROW_C
+| | +--->BN_MP_CLEAR_MULTI_C
+| | | +--->BN_MP_CLEAR_C
+| +--->BN_MP_KARATSUBA_MUL_C
+| | +--->BN_MP_INIT_SIZE_C
+| | | +--->BN_MP_INIT_C
+| | +--->BN_MP_CLAMP_C
+| | +--->BN_S_MP_ADD_C
+| | | +--->BN_MP_GROW_C
+| | +--->BN_MP_ADD_C
+| | | +--->BN_MP_CMP_MAG_C
+| | | +--->BN_S_MP_SUB_C
+| | | | +--->BN_MP_GROW_C
+| | +--->BN_S_MP_SUB_C
+| | | +--->BN_MP_GROW_C
+| | +--->BN_MP_LSHD_C
+| | | +--->BN_MP_GROW_C
+| | | +--->BN_MP_RSHD_C
+| | | | +--->BN_MP_ZERO_C
+| | +--->BN_MP_CLEAR_C
+| +--->BN_S_MP_MUL_DIGS_C
+| | +--->BN_MP_INIT_SIZE_C
+| | | +--->BN_MP_INIT_C
+| | +--->BN_MP_CLAMP_C
+| | +--->BN_MP_EXCH_C
+| | +--->BN_MP_CLEAR_C
++--->BN_MP_INIT_C
++--->BN_MP_CLEAR_C
++--->BN_MP_COPY_C
+| +--->BN_MP_GROW_C
+
+
+BN_MP_FACTORS_SORT_C
++--->BN_MP_CMP_C
+| +--->BN_MP_CMP_MAG_C
++--->BN_MP_EXCH_C
+
+
+BN_MP_FACTORS_ZERO_C
++--->BN_MP_CLEAR_C
+
+
BN_MP_FREAD_C
+--->BN_MP_ZERO_C
+--->BN_MP_MUL_D_C
diff --git a/demo/test.c b/demo/test.c
index 3c61ff512..609030b7c 100644
--- a/demo/test.c
+++ b/demo/test.c
@@ -1643,6 +1643,172 @@ static int test_mp_balance_mul(void)
return EXIT_FAILURE;
}
+static int test_mp_factors_sort(void)
+{
+ int e, i, j, k;
+ mp_factors factors;
+ mp_int t, primorial;
+ const char *p_29 = "6469693230";
+ const mp_digit tests[9][10] = {
+ {2, 3, 5, 7, 11, 13, 17, 19, 23, 29},
+ {29, 23, 19, 17, 13, 11, 7, 5, 3, 2},
+ {19, 2, 29, 3, 23, 17, 5, 11, 13, 7},
+ {23, 2, 11, 5, 7, 19, 17, 3, 13, 29},
+ {3, 2, 5, 7, 11, 13, 17, 19, 23, 29},
+ {2, 3, 5, 7, 11, 13, 17, 19, 29, 23},
+ {2, 2, 2, 2, 2, 2, 2, 2, 2, 23},
+ {23, 2, 2, 2, 2, 2, 2, 2, 2, 2},
+ {2, 2, 2, 2, 2, 23, 2, 2, 2, 2},
+ };
+ unsigned long p_2_23 = 11776uL;
+
+ if ((e = mp_factors_init(&factors)) != MP_OKAY) {
+ return e;
+ }
+ if ((e = mp_init_multi(&t, &primorial, NULL)) != MP_OKAY) {
+ mp_factors_clear(&factors);
+ return e;
+ }
+ if ((e = mp_read_radix(&primorial, p_29, 10)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+
+ for (i = 0; i < 6; i++) {
+ mp_factors_zero(&factors);
+ for (j = 0; j < 10; j++) {
+ mp_set(&t,tests[i][j]);
+ if ((e = mp_factors_add(&t, &factors)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+ }
+ mp_factors_sort(&factors);
+ if ((e = mp_factors_product(&factors, &t)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+ if (mp_cmp(&t, &primorial) != MP_EQ) {
+ goto LTM_ERR;
+ }
+ for (k = 0; k < (factors.length - 1); k++) {
+ if (mp_cmp(&(factors.factors[k]), &(factors.factors[k+1])) == MP_GT) {
+ goto LTM_ERR;
+ }
+ }
+ }
+
+ if ((e = mp_set_long(&primorial, p_2_23)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+
+ for (i = 6; i < 9; i++) {
+ mp_factors_zero(&factors);
+ for (j = 0; j < 10; j++) {
+ mp_set(&t,tests[i][j]);
+ if ((e = mp_factors_add(&t, &factors)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+ }
+ mp_factors_sort(&factors);
+ if ((e = mp_factors_product(&factors, &t)) != MP_OKAY) {
+ goto LTM_ERR;
+ }
+ if (mp_cmp(&t, &primorial) != MP_EQ) {
+ goto LTM_ERR;
+ }
+ for (k = 0; k < (factors.length - 1); k++) {
+ if (mp_cmp(&(factors.factors[k]), &(factors.factors[k+1])) == MP_GT) {
+ goto LTM_ERR;
+ }
+ }
+ }
+
+ mp_clear_multi(&t, &primorial, NULL);
+ mp_factors_clear(&factors);
+ return EXIT_SUCCESS;
+LTM_ERR:
+ mp_clear_multi(&t, &primorial, NULL);
+ mp_factors_clear(&factors);
+ return EXIT_FAILURE;
+}
+
+static int test_mp_factors_product(void)
+{
+ int e;
+ int i, j;
+ mp_factors factors;
+ mp_int t, primorial;
+ const char *p_29 = "6469693230";
+#ifndef MP_8BIT
+ const char *p_1000 =
+ "lWyCCT0aF3uOiLv+kFrAb/EkIbfXTJx+MMPOxI1Dl8aLBCvFRKN/CUTUHwyDdk1sdC8rdjKRFGTd3wE46/iQibo1eoA6l7QW3H2PpQPNb46iK1m2/2Rmhr+Cmxu8eB+KHZoXa7H8pEXdIfufN0hWvfw7o2Sph35IoxakyRoz0nCZiPXLlt4tVsMNHljt+hK67sycluoiFhWR+iCJhtFqX1I21PJok/eNSkr2QM";
+#endif
+ const mp_digit tests_a[3][10] = {
+ {2, 3, 5, 7, 11, 13, 17, 19, 23, 29},
+ {29, 23, 19, 17, 13, 11, 7, 5, 3, 2},
+ {29, 23, 19, 17, 0, 11, 7, 5, 3, 2}
+ };
+
+ if ((e = mp_factors_init(&factors)) != MP_OKAY) {
+ return e;
+ }
+ if ((e = mp_init_multi(&t, &primorial, NULL)) != MP_OKAY) {
+ mp_factors_clear(&factors);
+ return e;
+ }
+
+ /* zero length */
+ if ((e = mp_factors_product(&factors, &t)) == MP_OKAY) {
+ goto LTM_ERR;
+ }
+ /* zero in array */
+ mp_factors_zero(&factors);
+ for (j = 0; j < 10; j++) {
+ mp_set(&t,tests_a[2][j]);
+ mp_factors_add(&t, &factors);
+ }
+ mp_factors_product(&factors, &t);
+ if (mp_cmp_d(&t, 0uL) != MP_EQ) {
+ goto LTM_ERR;
+ }
+
+ mp_read_radix(&primorial, p_29, 10);
+
+ for (i = 0; i < 2; i++) {
+ mp_factors_zero(&factors);
+ for (j = 0; j < 10; j++) {
+ mp_set(&t,tests_a[i][j]);
+ mp_factors_add(&t, &factors);
+ }
+ mp_factors_product(&factors, &t);
+ if (mp_cmp(&t, &primorial) != MP_EQ) {
+ puts("AAA");
+ goto LTM_ERR;
+ }
+ }
+
+ /* not enough primes < 127 to trigger the binary-splitting */
+#ifndef MP_8BIT
+ mp_factors_zero(&factors);
+ for (i = 0; i < 168; i++) {
+ mp_set(&t, ltm_prime_tab[i]);
+ mp_factors_add(&t, &factors);
+ }
+ mp_factors_product(&factors, &t);
+ mp_read_radix(&primorial, p_1000, 64);
+ if (mp_cmp(&t, &primorial) != MP_EQ) {
+ goto LTM_ERR;
+ }
+#endif
+
+ mp_clear_multi(&t, &primorial, NULL);
+ mp_factors_clear(&factors);
+ return EXIT_SUCCESS;
+LTM_ERR:
+ mp_clear_multi(&t, &primorial, NULL);
+ mp_factors_clear(&factors);
+ return EXIT_FAILURE;
+}
+
+
int unit_tests(void)
{
static const struct {
@@ -1678,7 +1844,9 @@ int unit_tests(void)
T(mp_tc_xor),
T(mp_incr),
T(mp_decr),
- T(mp_balance_mul)
+ T(mp_balance_mul),
+ T(mp_factors_sort),
+ T(mp_factors_product)
#undef T
};
unsigned long i;
diff --git a/doc/bn.tex b/doc/bn.tex
index c83b2e399..8b86ab2b0 100644
--- a/doc/bn.tex
+++ b/doc/bn.tex
@@ -2116,6 +2116,57 @@ \subsection{To ASCII}
int mp_fwrite(const mp_int *a, int radix, FILE *stream);
\end{alltt}
+\chapter{Factorizing}
+\subsection{Managing Lists of Factors}
+The data structure used for the list of factors is a simple array, packed into a \texttt{struct} to surround it with some useful information like the number of elements (\texttt{length}) and the amount of memory allocated (\texttt{alloc}), also counted as a number of elements.
+\begin{alltt}
+typedef struct {
+ int length, alloc;
+ mp_int *factors;
+} mp_factors;
+\end{alltt}
+The macro \texttt{LTM\_TRIAL\_GROWTH} holds the amount of memory, measured in numbers of elements, by which \texttt{realloc} will increase the memory available to the list \texttt{factors}. It is defined in \texttt{tommath.h} and the default value is $64$.
+
+A couple of functions are available to make the use of it a bit more comfortable.
+
+\begin{description}
+\item
+\index{mp\_factors\_init}
+\verb!int mp_factors_init(mp_factors *f);!\\
+Initialize the factor list by allocating a certain amount of memory and setting \texttt{length = 0} and \texttt{alloc} to the amount of memory pre-allocated. The exact amount is defined at compile time by the macro \texttt{LTM\_TRIAL\_GROWTH} in \texttt{tommath.h}.
+\item
+\index{mp\_factors\_clear}
+\verb!void mp_factors_clear(mp_factors *f);!\\
+This function free's all memory used.
+\item
+\index{mp\_factors\_zero}
+\verb!int mp_factors_zero(mp_factors *f);!\\
+Remove the elements of the factor list and allocate (fresh) memory of default size in that order.
+\item
+\index{mp\_factors\_add}
+\verb!int mp_factors_add(const mp_int *a, mp_factors *f);!\\
+Add a factor of type \texttt{mp\_int} to the list.
+\item
+\index{mp\_factors\_sort}
+\verb!int mp_factors_sort(mp_factors *f);!\\
+The factors in the list are not necessarily in increasing order. This functions changes that. It does it with the insert-sort algorithm, a good choice for the task it has been written for (the list is most likely already ordered) but not for many other tasks involving large lists in random order.
+\item
+\index{mp\_factors\_print}
+\texttt{int mp\_factors\_print(mp\_factors *f, int base, char delimiter,\\
+\hphantom{int mp\_factors\_print(} FILE *stream);}\\
+Prints the element of the list in base \texttt{base} to \texttt{stream} with the delimiter \texttt{delimiter}. The default delimiter is a comma (ASCII \texttt{0x2c}).
+\item
+\index{mp\_factors\_product}
+\verb!int mp_factors_product(const mp_factors *factors, mp_int *p);!\\
+Multiplies all elements of the list. It does not recognize sparse lists, every zero in the list gets multiplied, too. It does multiply the list with a binary-splitting algorithm which assumes a highly or better fully sorted list to work optimally.
+\item
+\index{mp\_factors\_compress}
+\verb!int mp_factors_compress(const mp_factors *f, int sorted, mp_factors *g)!\\
+Change (sorted) factors array into format ``prime, prime-count, \textellipsis, prime, prime-count''. The type of prime-count is therefore a bigint, too, which makes it useful for low \texttt{MP\_xBIT}.
+\end{description}
+
+
+
\subsection{From ASCII}
\index{mp\_read\_radix}
diff --git a/libtommath_VS2008.vcproj b/libtommath_VS2008.vcproj
index 69bce8769..6a1da0897 100644
--- a/libtommath_VS2008.vcproj
+++ b/libtommath_VS2008.vcproj
@@ -468,6 +468,38 @@
RelativePath="bn_mp_exteuclid.c"
>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/makefile b/makefile
index 4ca43ecad..fdf1aadc9 100644
--- a/makefile
+++ b/makefile
@@ -32,14 +32,16 @@ bn_mp_addmod.o bn_mp_and.o bn_mp_balance_mul.o bn_mp_clamp.o bn_mp_clear.o bn_mp
bn_mp_cmp_d.o bn_mp_cmp_mag.o bn_mp_cnt_lsb.o bn_mp_complement.o bn_mp_copy.o bn_mp_count_bits.o \
bn_mp_decr.o bn_mp_div.o bn_mp_div_2.o bn_mp_div_2d.o bn_mp_div_3.o bn_mp_div_d.o bn_mp_dr_is_modulus.o \
bn_mp_dr_reduce.o bn_mp_dr_setup.o bn_mp_exch.o bn_mp_export.o bn_mp_expt_d.o bn_mp_expt_d_ex.o \
-bn_mp_exptmod.o bn_mp_exptmod_fast.o bn_mp_exteuclid.o bn_mp_fread.o bn_mp_fwrite.o bn_mp_gcd.o \
-bn_mp_get_bit.o bn_mp_get_double.o bn_mp_get_int.o bn_mp_get_long.o bn_mp_get_long_long.o bn_mp_grow.o \
-bn_mp_import.o bn_mp_incr.o bn_mp_init.o bn_mp_init_copy.o bn_mp_init_multi.o bn_mp_init_set.o \
-bn_mp_init_set_int.o bn_mp_init_size.o bn_mp_invmod.o bn_mp_invmod_slow.o bn_mp_is_square.o \
-bn_mp_iseven.o bn_mp_isodd.o bn_mp_jacobi.o bn_mp_karatsuba_mul.o bn_mp_karatsuba_sqr.o bn_mp_kronecker.o \
-bn_mp_lcm.o bn_mp_lshd.o bn_mp_mod.o bn_mp_mod_2d.o bn_mp_mod_d.o bn_mp_montgomery_calc_normalization.o \
-bn_mp_montgomery_reduce.o bn_mp_montgomery_setup.o bn_mp_mul.o bn_mp_mul_2.o bn_mp_mul_2d.o bn_mp_mul_d.o \
-bn_mp_mulmod.o bn_mp_n_root.o bn_mp_n_root_ex.o bn_mp_neg.o bn_mp_or.o bn_mp_prime_fermat.o \
+bn_mp_exptmod.o bn_mp_exptmod_fast.o bn_mp_exteuclid.o bn_mp_factors_add.o bn_mp_factors_clear.o \
+bn_mp_factors_compress.o bn_mp_factors_init.o bn_mp_factors_print.o bn_mp_factors_product.o \
+bn_mp_factors_sort.o bn_mp_factors_zero.o bn_mp_fread.o bn_mp_fwrite.o bn_mp_gcd.o bn_mp_get_bit.o \
+bn_mp_get_double.o bn_mp_get_int.o bn_mp_get_long.o bn_mp_get_long_long.o bn_mp_grow.o bn_mp_import.o \
+bn_mp_incr.o bn_mp_init.o bn_mp_init_copy.o bn_mp_init_multi.o bn_mp_init_set.o bn_mp_init_set_int.o \
+bn_mp_init_size.o bn_mp_invmod.o bn_mp_invmod_slow.o bn_mp_is_square.o bn_mp_iseven.o bn_mp_isodd.o \
+bn_mp_jacobi.o bn_mp_karatsuba_mul.o bn_mp_karatsuba_sqr.o bn_mp_kronecker.o bn_mp_lcm.o bn_mp_lshd.o \
+bn_mp_mod.o bn_mp_mod_2d.o bn_mp_mod_d.o bn_mp_montgomery_calc_normalization.o bn_mp_montgomery_reduce.o \
+bn_mp_montgomery_setup.o bn_mp_mul.o bn_mp_mul_2.o bn_mp_mul_2d.o bn_mp_mul_d.o bn_mp_mulmod.o \
+bn_mp_n_root.o bn_mp_n_root_ex.o bn_mp_neg.o bn_mp_or.o bn_mp_prime_fermat.o \
bn_mp_prime_frobenius_underwood.o bn_mp_prime_is_divisible.o bn_mp_prime_is_prime.o \
bn_mp_prime_miller_rabin.o bn_mp_prime_next_prime.o bn_mp_prime_rabin_miller_trials.o \
bn_mp_prime_random_ex.o bn_mp_prime_strong_lucas_selfridge.o bn_mp_radix_size.o bn_mp_radix_smap.o \
diff --git a/makefile.mingw b/makefile.mingw
index bb2552d95..cf23c6313 100644
--- a/makefile.mingw
+++ b/makefile.mingw
@@ -35,14 +35,16 @@ bn_mp_addmod.o bn_mp_and.o bn_mp_balance_mul.o bn_mp_clamp.o bn_mp_clear.o bn_mp
bn_mp_cmp_d.o bn_mp_cmp_mag.o bn_mp_cnt_lsb.o bn_mp_complement.o bn_mp_copy.o bn_mp_count_bits.o \
bn_mp_decr.o bn_mp_div.o bn_mp_div_2.o bn_mp_div_2d.o bn_mp_div_3.o bn_mp_div_d.o bn_mp_dr_is_modulus.o \
bn_mp_dr_reduce.o bn_mp_dr_setup.o bn_mp_exch.o bn_mp_export.o bn_mp_expt_d.o bn_mp_expt_d_ex.o \
-bn_mp_exptmod.o bn_mp_exptmod_fast.o bn_mp_exteuclid.o bn_mp_fread.o bn_mp_fwrite.o bn_mp_gcd.o \
-bn_mp_get_bit.o bn_mp_get_double.o bn_mp_get_int.o bn_mp_get_long.o bn_mp_get_long_long.o bn_mp_grow.o \
-bn_mp_import.o bn_mp_incr.o bn_mp_init.o bn_mp_init_copy.o bn_mp_init_multi.o bn_mp_init_set.o \
-bn_mp_init_set_int.o bn_mp_init_size.o bn_mp_invmod.o bn_mp_invmod_slow.o bn_mp_is_square.o \
-bn_mp_iseven.o bn_mp_isodd.o bn_mp_jacobi.o bn_mp_karatsuba_mul.o bn_mp_karatsuba_sqr.o bn_mp_kronecker.o \
-bn_mp_lcm.o bn_mp_lshd.o bn_mp_mod.o bn_mp_mod_2d.o bn_mp_mod_d.o bn_mp_montgomery_calc_normalization.o \
-bn_mp_montgomery_reduce.o bn_mp_montgomery_setup.o bn_mp_mul.o bn_mp_mul_2.o bn_mp_mul_2d.o bn_mp_mul_d.o \
-bn_mp_mulmod.o bn_mp_n_root.o bn_mp_n_root_ex.o bn_mp_neg.o bn_mp_or.o bn_mp_prime_fermat.o \
+bn_mp_exptmod.o bn_mp_exptmod_fast.o bn_mp_exteuclid.o bn_mp_factors_add.o bn_mp_factors_clear.o \
+bn_mp_factors_compress.o bn_mp_factors_init.o bn_mp_factors_print.o bn_mp_factors_product.o \
+bn_mp_factors_sort.o bn_mp_factors_zero.o bn_mp_fread.o bn_mp_fwrite.o bn_mp_gcd.o bn_mp_get_bit.o \
+bn_mp_get_double.o bn_mp_get_int.o bn_mp_get_long.o bn_mp_get_long_long.o bn_mp_grow.o bn_mp_import.o \
+bn_mp_incr.o bn_mp_init.o bn_mp_init_copy.o bn_mp_init_multi.o bn_mp_init_set.o bn_mp_init_set_int.o \
+bn_mp_init_size.o bn_mp_invmod.o bn_mp_invmod_slow.o bn_mp_is_square.o bn_mp_iseven.o bn_mp_isodd.o \
+bn_mp_jacobi.o bn_mp_karatsuba_mul.o bn_mp_karatsuba_sqr.o bn_mp_kronecker.o bn_mp_lcm.o bn_mp_lshd.o \
+bn_mp_mod.o bn_mp_mod_2d.o bn_mp_mod_d.o bn_mp_montgomery_calc_normalization.o bn_mp_montgomery_reduce.o \
+bn_mp_montgomery_setup.o bn_mp_mul.o bn_mp_mul_2.o bn_mp_mul_2d.o bn_mp_mul_d.o bn_mp_mulmod.o \
+bn_mp_n_root.o bn_mp_n_root_ex.o bn_mp_neg.o bn_mp_or.o bn_mp_prime_fermat.o \
bn_mp_prime_frobenius_underwood.o bn_mp_prime_is_divisible.o bn_mp_prime_is_prime.o \
bn_mp_prime_miller_rabin.o bn_mp_prime_next_prime.o bn_mp_prime_rabin_miller_trials.o \
bn_mp_prime_random_ex.o bn_mp_prime_strong_lucas_selfridge.o bn_mp_radix_size.o bn_mp_radix_smap.o \
diff --git a/makefile.msvc b/makefile.msvc
index 43f1c6d44..a7bb967d0 100644
--- a/makefile.msvc
+++ b/makefile.msvc
@@ -27,14 +27,16 @@ bn_mp_addmod.obj bn_mp_and.obj bn_mp_balance_mul.obj bn_mp_clamp.obj bn_mp_clear
bn_mp_cmp_d.obj bn_mp_cmp_mag.obj bn_mp_cnt_lsb.obj bn_mp_complement.obj bn_mp_copy.obj bn_mp_count_bits.obj \
bn_mp_decr.obj bn_mp_div.obj bn_mp_div_2.obj bn_mp_div_2d.obj bn_mp_div_3.obj bn_mp_div_d.obj bn_mp_dr_is_modulus.obj \
bn_mp_dr_reduce.obj bn_mp_dr_setup.obj bn_mp_exch.obj bn_mp_export.obj bn_mp_expt_d.obj bn_mp_expt_d_ex.obj \
-bn_mp_exptmod.obj bn_mp_exptmod_fast.obj bn_mp_exteuclid.obj bn_mp_fread.obj bn_mp_fwrite.obj bn_mp_gcd.obj \
-bn_mp_get_bit.obj bn_mp_get_double.obj bn_mp_get_int.obj bn_mp_get_long.obj bn_mp_get_long_long.obj bn_mp_grow.obj \
-bn_mp_import.obj bn_mp_incr.obj bn_mp_init.obj bn_mp_init_copy.obj bn_mp_init_multi.obj bn_mp_init_set.obj \
-bn_mp_init_set_int.obj bn_mp_init_size.obj bn_mp_invmod.obj bn_mp_invmod_slow.obj bn_mp_is_square.obj \
-bn_mp_iseven.obj bn_mp_isodd.obj bn_mp_jacobi.obj bn_mp_karatsuba_mul.obj bn_mp_karatsuba_sqr.obj bn_mp_kronecker.obj \
-bn_mp_lcm.obj bn_mp_lshd.obj bn_mp_mod.obj bn_mp_mod_2d.obj bn_mp_mod_d.obj bn_mp_montgomery_calc_normalization.obj \
-bn_mp_montgomery_reduce.obj bn_mp_montgomery_setup.obj bn_mp_mul.obj bn_mp_mul_2.obj bn_mp_mul_2d.obj bn_mp_mul_d.obj \
-bn_mp_mulmod.obj bn_mp_n_root.obj bn_mp_n_root_ex.obj bn_mp_neg.obj bn_mp_or.obj bn_mp_prime_fermat.obj \
+bn_mp_exptmod.obj bn_mp_exptmod_fast.obj bn_mp_exteuclid.obj bn_mp_factors_add.obj bn_mp_factors_clear.obj \
+bn_mp_factors_compress.obj bn_mp_factors_init.obj bn_mp_factors_print.obj bn_mp_factors_product.obj \
+bn_mp_factors_sort.obj bn_mp_factors_zero.obj bn_mp_fread.obj bn_mp_fwrite.obj bn_mp_gcd.obj bn_mp_get_bit.obj \
+bn_mp_get_double.obj bn_mp_get_int.obj bn_mp_get_long.obj bn_mp_get_long_long.obj bn_mp_grow.obj bn_mp_import.obj \
+bn_mp_incr.obj bn_mp_init.obj bn_mp_init_copy.obj bn_mp_init_multi.obj bn_mp_init_set.obj bn_mp_init_set_int.obj \
+bn_mp_init_size.obj bn_mp_invmod.obj bn_mp_invmod_slow.obj bn_mp_is_square.obj bn_mp_iseven.obj bn_mp_isodd.obj \
+bn_mp_jacobi.obj bn_mp_karatsuba_mul.obj bn_mp_karatsuba_sqr.obj bn_mp_kronecker.obj bn_mp_lcm.obj bn_mp_lshd.obj \
+bn_mp_mod.obj bn_mp_mod_2d.obj bn_mp_mod_d.obj bn_mp_montgomery_calc_normalization.obj bn_mp_montgomery_reduce.obj \
+bn_mp_montgomery_setup.obj bn_mp_mul.obj bn_mp_mul_2.obj bn_mp_mul_2d.obj bn_mp_mul_d.obj bn_mp_mulmod.obj \
+bn_mp_n_root.obj bn_mp_n_root_ex.obj bn_mp_neg.obj bn_mp_or.obj bn_mp_prime_fermat.obj \
bn_mp_prime_frobenius_underwood.obj bn_mp_prime_is_divisible.obj bn_mp_prime_is_prime.obj \
bn_mp_prime_miller_rabin.obj bn_mp_prime_next_prime.obj bn_mp_prime_rabin_miller_trials.obj \
bn_mp_prime_random_ex.obj bn_mp_prime_strong_lucas_selfridge.obj bn_mp_radix_size.obj bn_mp_radix_smap.obj \
diff --git a/makefile.shared b/makefile.shared
index 012cd5bff..533aefa61 100644
--- a/makefile.shared
+++ b/makefile.shared
@@ -29,14 +29,16 @@ bn_mp_addmod.o bn_mp_and.o bn_mp_balance_mul.o bn_mp_clamp.o bn_mp_clear.o bn_mp
bn_mp_cmp_d.o bn_mp_cmp_mag.o bn_mp_cnt_lsb.o bn_mp_complement.o bn_mp_copy.o bn_mp_count_bits.o \
bn_mp_decr.o bn_mp_div.o bn_mp_div_2.o bn_mp_div_2d.o bn_mp_div_3.o bn_mp_div_d.o bn_mp_dr_is_modulus.o \
bn_mp_dr_reduce.o bn_mp_dr_setup.o bn_mp_exch.o bn_mp_export.o bn_mp_expt_d.o bn_mp_expt_d_ex.o \
-bn_mp_exptmod.o bn_mp_exptmod_fast.o bn_mp_exteuclid.o bn_mp_fread.o bn_mp_fwrite.o bn_mp_gcd.o \
-bn_mp_get_bit.o bn_mp_get_double.o bn_mp_get_int.o bn_mp_get_long.o bn_mp_get_long_long.o bn_mp_grow.o \
-bn_mp_import.o bn_mp_incr.o bn_mp_init.o bn_mp_init_copy.o bn_mp_init_multi.o bn_mp_init_set.o \
-bn_mp_init_set_int.o bn_mp_init_size.o bn_mp_invmod.o bn_mp_invmod_slow.o bn_mp_is_square.o \
-bn_mp_iseven.o bn_mp_isodd.o bn_mp_jacobi.o bn_mp_karatsuba_mul.o bn_mp_karatsuba_sqr.o bn_mp_kronecker.o \
-bn_mp_lcm.o bn_mp_lshd.o bn_mp_mod.o bn_mp_mod_2d.o bn_mp_mod_d.o bn_mp_montgomery_calc_normalization.o \
-bn_mp_montgomery_reduce.o bn_mp_montgomery_setup.o bn_mp_mul.o bn_mp_mul_2.o bn_mp_mul_2d.o bn_mp_mul_d.o \
-bn_mp_mulmod.o bn_mp_n_root.o bn_mp_n_root_ex.o bn_mp_neg.o bn_mp_or.o bn_mp_prime_fermat.o \
+bn_mp_exptmod.o bn_mp_exptmod_fast.o bn_mp_exteuclid.o bn_mp_factors_add.o bn_mp_factors_clear.o \
+bn_mp_factors_compress.o bn_mp_factors_init.o bn_mp_factors_print.o bn_mp_factors_product.o \
+bn_mp_factors_sort.o bn_mp_factors_zero.o bn_mp_fread.o bn_mp_fwrite.o bn_mp_gcd.o bn_mp_get_bit.o \
+bn_mp_get_double.o bn_mp_get_int.o bn_mp_get_long.o bn_mp_get_long_long.o bn_mp_grow.o bn_mp_import.o \
+bn_mp_incr.o bn_mp_init.o bn_mp_init_copy.o bn_mp_init_multi.o bn_mp_init_set.o bn_mp_init_set_int.o \
+bn_mp_init_size.o bn_mp_invmod.o bn_mp_invmod_slow.o bn_mp_is_square.o bn_mp_iseven.o bn_mp_isodd.o \
+bn_mp_jacobi.o bn_mp_karatsuba_mul.o bn_mp_karatsuba_sqr.o bn_mp_kronecker.o bn_mp_lcm.o bn_mp_lshd.o \
+bn_mp_mod.o bn_mp_mod_2d.o bn_mp_mod_d.o bn_mp_montgomery_calc_normalization.o bn_mp_montgomery_reduce.o \
+bn_mp_montgomery_setup.o bn_mp_mul.o bn_mp_mul_2.o bn_mp_mul_2d.o bn_mp_mul_d.o bn_mp_mulmod.o \
+bn_mp_n_root.o bn_mp_n_root_ex.o bn_mp_neg.o bn_mp_or.o bn_mp_prime_fermat.o \
bn_mp_prime_frobenius_underwood.o bn_mp_prime_is_divisible.o bn_mp_prime_is_prime.o \
bn_mp_prime_miller_rabin.o bn_mp_prime_next_prime.o bn_mp_prime_rabin_miller_trials.o \
bn_mp_prime_random_ex.o bn_mp_prime_strong_lucas_selfridge.o bn_mp_radix_size.o bn_mp_radix_smap.o \
diff --git a/makefile.unix b/makefile.unix
index 856e18cee..bb428eec2 100644
--- a/makefile.unix
+++ b/makefile.unix
@@ -36,14 +36,16 @@ bn_mp_addmod.o bn_mp_and.o bn_mp_balance_mul.o bn_mp_clamp.o bn_mp_clear.o bn_mp
bn_mp_cmp_d.o bn_mp_cmp_mag.o bn_mp_cnt_lsb.o bn_mp_complement.o bn_mp_copy.o bn_mp_count_bits.o \
bn_mp_decr.o bn_mp_div.o bn_mp_div_2.o bn_mp_div_2d.o bn_mp_div_3.o bn_mp_div_d.o bn_mp_dr_is_modulus.o \
bn_mp_dr_reduce.o bn_mp_dr_setup.o bn_mp_exch.o bn_mp_export.o bn_mp_expt_d.o bn_mp_expt_d_ex.o \
-bn_mp_exptmod.o bn_mp_exptmod_fast.o bn_mp_exteuclid.o bn_mp_fread.o bn_mp_fwrite.o bn_mp_gcd.o \
-bn_mp_get_bit.o bn_mp_get_double.o bn_mp_get_int.o bn_mp_get_long.o bn_mp_get_long_long.o bn_mp_grow.o \
-bn_mp_import.o bn_mp_incr.o bn_mp_init.o bn_mp_init_copy.o bn_mp_init_multi.o bn_mp_init_set.o \
-bn_mp_init_set_int.o bn_mp_init_size.o bn_mp_invmod.o bn_mp_invmod_slow.o bn_mp_is_square.o \
-bn_mp_iseven.o bn_mp_isodd.o bn_mp_jacobi.o bn_mp_karatsuba_mul.o bn_mp_karatsuba_sqr.o bn_mp_kronecker.o \
-bn_mp_lcm.o bn_mp_lshd.o bn_mp_mod.o bn_mp_mod_2d.o bn_mp_mod_d.o bn_mp_montgomery_calc_normalization.o \
-bn_mp_montgomery_reduce.o bn_mp_montgomery_setup.o bn_mp_mul.o bn_mp_mul_2.o bn_mp_mul_2d.o bn_mp_mul_d.o \
-bn_mp_mulmod.o bn_mp_n_root.o bn_mp_n_root_ex.o bn_mp_neg.o bn_mp_or.o bn_mp_prime_fermat.o \
+bn_mp_exptmod.o bn_mp_exptmod_fast.o bn_mp_exteuclid.o bn_mp_factors_add.o bn_mp_factors_clear.o \
+bn_mp_factors_compress.o bn_mp_factors_init.o bn_mp_factors_print.o bn_mp_factors_product.o \
+bn_mp_factors_sort.o bn_mp_factors_zero.o bn_mp_fread.o bn_mp_fwrite.o bn_mp_gcd.o bn_mp_get_bit.o \
+bn_mp_get_double.o bn_mp_get_int.o bn_mp_get_long.o bn_mp_get_long_long.o bn_mp_grow.o bn_mp_import.o \
+bn_mp_incr.o bn_mp_init.o bn_mp_init_copy.o bn_mp_init_multi.o bn_mp_init_set.o bn_mp_init_set_int.o \
+bn_mp_init_size.o bn_mp_invmod.o bn_mp_invmod_slow.o bn_mp_is_square.o bn_mp_iseven.o bn_mp_isodd.o \
+bn_mp_jacobi.o bn_mp_karatsuba_mul.o bn_mp_karatsuba_sqr.o bn_mp_kronecker.o bn_mp_lcm.o bn_mp_lshd.o \
+bn_mp_mod.o bn_mp_mod_2d.o bn_mp_mod_d.o bn_mp_montgomery_calc_normalization.o bn_mp_montgomery_reduce.o \
+bn_mp_montgomery_setup.o bn_mp_mul.o bn_mp_mul_2.o bn_mp_mul_2d.o bn_mp_mul_d.o bn_mp_mulmod.o \
+bn_mp_n_root.o bn_mp_n_root_ex.o bn_mp_neg.o bn_mp_or.o bn_mp_prime_fermat.o \
bn_mp_prime_frobenius_underwood.o bn_mp_prime_is_divisible.o bn_mp_prime_is_prime.o \
bn_mp_prime_miller_rabin.o bn_mp_prime_next_prime.o bn_mp_prime_rabin_miller_trials.o \
bn_mp_prime_random_ex.o bn_mp_prime_strong_lucas_selfridge.o bn_mp_radix_size.o bn_mp_radix_smap.o \
diff --git a/tommath.h b/tommath.h
index 41c9ec0b2..b4e01856d 100644
--- a/tommath.h
+++ b/tommath.h
@@ -567,6 +567,48 @@ int mp_prime_next_prime(mp_int *a, int t, int bbs_style);
*/
int mp_prime_random_ex(mp_int *a, int t, int size, int flags, ltm_prime_callback cb, void *dat);
+/*
+ Simple data structure to hold some mp_int's.
+ Is used in LTM to hold the factors from factoring, about
+ 100 or so max (large primorials of powers notwithstanding),
+ always with linear r/w access.
+ */
+typedef struct {
+ int length, alloc;
+ mp_int *factors;
+} mp_factors;
+
+#ifndef LTM_TRIAL_GROWTH
+#define LTM_TRIAL_GROWTH 64
+#endif
+
+/* Init factor-array (an array of mp_int's) */
+int mp_factors_init(mp_factors *f);
+
+/* Clear and free factor-array (an array of mp_int's) */
+void mp_factors_clear(mp_factors *f);
+
+/* Zero the elements of a factor-array (an array of mp_int's) and realloc to def
+ size in that order */
+int mp_factors_zero(mp_factors *f);
+
+/* Add one element (mp_int) to a factor-array (an array of mp_int's) */
+int mp_factors_add(const mp_int *a, mp_factors *f);
+
+/* Sort factor-array (an array of mp_int's) */
+void mp_factors_sort(mp_factors *f);
+
+/* Factor integer. Good for up to about 35-40 bit large factors */
+int mp_factor(const mp_int *z, mp_factors *factors);
+
+/* Compute the product of the elements of "factors" */
+int mp_factors_product(const mp_factors *factors, mp_int *p);
+
+/* Change (sorted) factors array into format prime,prime-count,...,prime,prime-count */
+int mp_factors_compress(mp_factors *f, int sorted, mp_factors *g);
+
+
+
/* ---> radix conversion <--- */
int mp_count_bits(const mp_int *a);
@@ -588,6 +630,8 @@ int mp_radix_size(const mp_int *a, int radix, int *size);
#ifndef LTM_NO_FILE
int mp_fread(mp_int *a, int radix, FILE *stream);
int mp_fwrite(const mp_int *a, int radix, FILE *stream);
+/* Print the elememts of a factor-array (an array of mp_int's) */
+int mp_factors_print(const mp_factors *f, int base, char delimiter, FILE *stream);
#endif
#define mp_read_raw(mp, str, len) mp_read_signed_bin((mp), (str), (len))
diff --git a/tommath_class.h b/tommath_class.h
index 56a6cf239..df8fec78b 100644
--- a/tommath_class.h
+++ b/tommath_class.h
@@ -49,6 +49,14 @@
# define BN_MP_EXPTMOD_C
# define BN_MP_EXPTMOD_FAST_C
# define BN_MP_EXTEUCLID_C
+# define BN_MP_FACTORS_ADD_C
+# define BN_MP_FACTORS_CLEAR_C
+# define BN_MP_FACTORS_COMPRESS_C
+# define BN_MP_FACTORS_INIT_C
+# define BN_MP_FACTORS_PRINT_C
+# define BN_MP_FACTORS_PRODUCT_C
+# define BN_MP_FACTORS_SORT_C
+# define BN_MP_FACTORS_ZERO_C
# define BN_MP_FREAD_C
# define BN_MP_FWRITE_C
# define BN_MP_GCD_C
@@ -421,6 +429,58 @@
# define BN_MP_CLEAR_MULTI_C
#endif
+#if defined(BN_MP_FACTORS_ADD_C)
+# define BN_MP_FACTORS_C
+# define BN_MP_INIT_C
+# define BN_MP_COPY_C
+#endif
+
+#if defined(BN_MP_FACTORS_CLEAR_C)
+# define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_FACTORS_COMPRESS_C)
+# define BN_MP_INIT_C
+# define BN_MP_FACTORS_INIT_C
+# define BN_MP_FACTORS_ADD_C
+# define BN_MP_FACTORS_SORT_C
+# define BN_MP_INCR_C
+# define BN_MP_CMP_C
+# define BN_MP_ZERO_C
+# define BN_MP_FACTORS_CLEAR_C
+# define BN_MP_CLEAR_C
+#endif
+
+#if defined(BN_MP_FACTORS_INIT_C)
+# define BN_MP_FACTORS_C
+#endif
+
+#if defined(BN_MP_FACTORS_PRINT_C)
+# define BN_MP_FACTORS_C
+# define BN_MP_FWRITE_C
+#endif
+
+#if defined(BN_MP_FACTORS_PRODUCT_C)
+# define BN_MP_FACTORS_C
+# define BN_MP_SET_C
+# define BN_MP_SET_LONG_C
+# define BN_MP_MUL_C
+# define BN_MP_INIT_C
+# define BN_MP_CLEAR_C
+# define BN_MP_COPY_C
+#endif
+
+#if defined(BN_MP_FACTORS_SORT_C)
+# define BN_MP_FACTORS_C
+# define BN_MP_CMP_C
+# define BN_MP_EXCH_C
+#endif
+
+#if defined(BN_MP_FACTORS_ZERO_C)
+# define BN_MP_FACTORS_C
+# define BN_MP_CLEAR_C
+#endif
+
#if defined(BN_MP_FREAD_C)
# define BN_MP_ZERO_C
# define BN_MP_S_RMAP_REVERSE_SZ_C