Skip to content

Commit ee72d6c

Browse files
committed
addition of function mp_pollard_rho
1 parent 2033fb9 commit ee72d6c

13 files changed

+675
-41
lines changed

bn_mp_pollard_rho.c

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
#include "tommath_private.h"
2+
#ifdef BN_MP_POLLARD_RHO_C
3+
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
4+
/* SPDX-License-Identifier: Unlicense */
5+
6+
7+
/* Find one factor of a positive integer using the Pollard-Rho algorithm */
8+
9+
/* a small helper to keep the code readable */
10+
static int s_square_mod_add(const mp_int *y, const mp_int *c, const mp_int *n, mp_int *r)
11+
{
12+
int e = MP_OKAY;
13+
if ((e = mp_sqrmod(y, n, r)) != MP_OKAY) {
14+
return e;
15+
}
16+
if ((e = mp_add(r, c, r)) != MP_OKAY) {
17+
return e;
18+
}
19+
if ((e = mp_mod(r, n, r)) != MP_OKAY) {
20+
return e;
21+
}
22+
return e;
23+
}
24+
/*
25+
This implementation uses Richard P. Brent's refinements as described in
26+
http://wwwmaths.anu.edu.au/~brent/pd/rpb051i.pdf section 7.
27+
28+
Good enough for factors up to ~40 bits.
29+
30+
Does not check anything about the input, just if it is one or even.
31+
32+
Minimum preparation before use:
33+
- check if "n" is a (pseudo) prime
34+
- check if "n" is a square
35+
36+
Recommended preparation:
37+
- check if "n" is (pseudo) prime. LibTomMath uses BPSW wich is tested
38+
up to 2^64 (~10^19).
39+
- check if "n" is a power (n = a^b where "a" can be a power, too,
40+
so check recursively)
41+
- check if "n" is a prime power (n = p^b with "p" prime)
42+
- trial division up to the architecture dependent limit. If you
43+
are using mp_next_small_prime() you can try the first 6542
44+
primes, even with MP_8BIT. Output "n_t"
45+
- check if "n_t" is (pseudo) prime. LibTomMath uses BPSW wich is tested
46+
up to 2^64 (~10^19).
47+
- check if "n_t" is a power (n = a^b where "a" can be a power, too,
48+
so check recursively)
49+
- check if "n_t" is a prime power (n = p^b with "p" prime)
50+
51+
*/
52+
int mp_pollard_rho(const mp_int *n, mp_int *factor)
53+
{
54+
mp_int x, y, ys, c, tmp;
55+
mp_int d, q;
56+
/*
57+
{j,r} might get problematic if sizeof(long) <= sizeof(short),
58+
15 bit might not be enough.
59+
*/
60+
long i, j, m, r;
61+
int e = MP_OKAY, ilog2, ilog2_rand, digits;
62+
63+
if (IS_UNITY(n)) {
64+
if ((e = mp_copy(n, factor)) != MP_OKAY) {
65+
return e;
66+
}
67+
return MP_OKAY;
68+
}
69+
if (IS_EVEN(n)) {
70+
mp_set(factor, 2uL);
71+
return MP_OKAY;
72+
}
73+
74+
if ((e = mp_init_multi(&x, &y, &ys, &c, &d, &q, &tmp, NULL)) != MP_OKAY) {
75+
return e;
76+
}
77+
ilog2 = mp_count_bits(n);
78+
digits = n->used;
79+
80+
if ((e = mp_rand(&y, digits)) != MP_OKAY) {
81+
goto LTM_END;
82+
}
83+
ilog2_rand = mp_count_bits(&y);
84+
if (ilog2_rand >= ilog2) {
85+
if ((e = mp_div_2d(&y, ilog2_rand - (ilog2 + 1), &y,NULL)) != MP_OKAY) {
86+
goto LTM_END;
87+
}
88+
}
89+
90+
if ((e = mp_copy(&y, &ys)) != MP_OKAY) {
91+
goto LTM_END;
92+
}
93+
94+
/* 0 < c < (n-2) */
95+
if ((e = mp_rand(&c, digits)) != MP_OKAY) {
96+
goto LTM_END;
97+
}
98+
ilog2_rand = mp_count_bits(&c);
99+
if (ilog2_rand >= ilog2) {
100+
if ((e = mp_div_2d(&c, ilog2_rand - (ilog2 + 1), &c,NULL)) != MP_OKAY) {
101+
goto LTM_END;
102+
}
103+
}
104+
if (mp_cmp_d(&c,3uL) != MP_LT) {
105+
if ((e = mp_sub_d(&c, 2uL, &c)) != MP_OKAY) {
106+
goto LTM_END;
107+
}
108+
}
109+
110+
m = 1000L;
111+
r = 1;
112+
mp_set(&d, 1uL);
113+
mp_set(&q, 1uL);
114+
115+
do {
116+
if ((e = mp_copy(&y, &x)) != MP_OKAY) {
117+
goto LTM_END;
118+
}
119+
for (i = 1; i <= r; i++) {
120+
if ((e = s_square_mod_add(&y, &c, n, &y)) != MP_OKAY) {
121+
goto LTM_END;
122+
}
123+
}
124+
j = 0;
125+
do {
126+
mp_copy(&y, &ys);
127+
for (i = 1; i <= MIN(m, r - j); i++) {
128+
if ((e = s_square_mod_add(&y, &c, n, &y)) != MP_OKAY) {
129+
goto LTM_END;
130+
}
131+
if ((e = mp_sub(&x, &y, &tmp)) != MP_OKAY) {
132+
goto LTM_END;
133+
}
134+
tmp.sign = MP_ZPOS;
135+
if ((e = mp_mulmod(&q, &tmp, n, &q)) != MP_OKAY) {
136+
goto LTM_END;
137+
}
138+
}
139+
if ((e = mp_gcd(&q, n, &d)) != MP_OKAY) {
140+
goto LTM_END;
141+
}
142+
/* TODO: check for overflow */
143+
j += m;
144+
} while ((j < r) && IS_UNITY(&d));
145+
/* TODO: check for overflow */
146+
r *= 2;
147+
} while (IS_UNITY(&d));
148+
if (mp_cmp(n, &d) == MP_EQ) {
149+
do {
150+
if ((e = s_square_mod_add(&ys, &c, n, &ys)) != MP_OKAY) {
151+
goto LTM_END;
152+
}
153+
if ((e = mp_sub(&x, &ys, &tmp)) != MP_OKAY) {
154+
goto LTM_END;
155+
}
156+
tmp.sign = MP_ZPOS;
157+
if ((e = mp_gcd(&tmp, n, &d)) != MP_OKAY) {
158+
goto LTM_END;
159+
}
160+
} while (IS_UNITY(&d));
161+
}
162+
LTM_END:
163+
mp_exch(&d, factor);
164+
mp_clear_multi(&x, &y, &ys, &c, &d, &q, &tmp, NULL);
165+
return e;
166+
}
167+
#endif

0 commit comments

Comments
 (0)