Skip to content

Commit 878d6d9

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

13 files changed

+686
-41
lines changed

bn_mp_pollard_rho.c

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

0 commit comments

Comments
 (0)