1*f0865ec9SKyle Evans /*
2*f0865ec9SKyle Evans * Copyright (C) 2017 - This file is part of libecc project
3*f0865ec9SKyle Evans *
4*f0865ec9SKyle Evans * Authors:
5*f0865ec9SKyle Evans * Ryad BENADJILA <ryadbenadjila@gmail.com>
6*f0865ec9SKyle Evans * Arnaud EBALARD <arnaud.ebalard@ssi.gouv.fr>
7*f0865ec9SKyle Evans * Jean-Pierre FLORI <jean-pierre.flori@ssi.gouv.fr>
8*f0865ec9SKyle Evans *
9*f0865ec9SKyle Evans * Contributors:
10*f0865ec9SKyle Evans * Nicolas VIVET <nicolas.vivet@ssi.gouv.fr>
11*f0865ec9SKyle Evans * Karim KHALFALLAH <karim.khalfallah@ssi.gouv.fr>
12*f0865ec9SKyle Evans *
13*f0865ec9SKyle Evans * This software is licensed under a dual BSD and GPL v2 license.
14*f0865ec9SKyle Evans * See LICENSE file at the root folder of the project.
15*f0865ec9SKyle Evans */
16*f0865ec9SKyle Evans /*
17*f0865ec9SKyle Evans * The purpose of this example is to implement Pollard's rho
18*f0865ec9SKyle Evans * algorithm to find non-trivial factors of a composite natural
19*f0865ec9SKyle Evans * number.
20*f0865ec9SKyle Evans * The prime numbers decomposition of the natural number is
21*f0865ec9SKyle Evans * recovered through repeated Pollard's rho. Primality checking
22*f0865ec9SKyle Evans * is performed using a Miller-Rabin test.
23*f0865ec9SKyle Evans *
24*f0865ec9SKyle Evans * WARNING: the code in this example is only here to illustrate
25*f0865ec9SKyle Evans * how to use the NN layer API. This code has not been designed
26*f0865ec9SKyle Evans * for production purposes (e.g. no effort has been made to make
27*f0865ec9SKyle Evans * it constant time).
28*f0865ec9SKyle Evans *
29*f0865ec9SKyle Evans *
30*f0865ec9SKyle Evans */
31*f0865ec9SKyle Evans
32*f0865ec9SKyle Evans /* We include the NN layer API header */
33*f0865ec9SKyle Evans #include <libecc/libarith.h>
34*f0865ec9SKyle Evans
35*f0865ec9SKyle Evans /* Declare our Miller-Rabin test implemented
36*f0865ec9SKyle Evans * in another module.
37*f0865ec9SKyle Evans */
38*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET int miller_rabin(nn_src_t n, const unsigned int t, int *check);
39*f0865ec9SKyle Evans
40*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET int pollard_rho(nn_t d, nn_src_t n, const word_t c);
41*f0865ec9SKyle Evans /* Pollard's rho main function, as described in
42*f0865ec9SKyle Evans * "Handbook of Applied Cryptography".
43*f0865ec9SKyle Evans *
44*f0865ec9SKyle Evans * Pollard's rho:
45*f0865ec9SKyle Evans * ==============
46*f0865ec9SKyle Evans * See "Handbook of Applied Cryptography", alorithm 3.9:
47*f0865ec9SKyle Evans *
48*f0865ec9SKyle Evans * Algorithm Pollard’s rho algorithm for factoring integers
49*f0865ec9SKyle Evans * INPUT: a composite integer n that is not a prime power.
50*f0865ec9SKyle Evans * OUTPUT: a non-trivial factor d of n.
51*f0865ec9SKyle Evans * 1. Set a←2, b←2.
52*f0865ec9SKyle Evans * 2. For i = 1, 2, ... do the following:
53*f0865ec9SKyle Evans * 2.1 Compute a←a^2 + 1 mod n, b←b^2 + 1 mod n, b←b^2 + 1 mod n.
54*f0865ec9SKyle Evans * 2.2 Compute d = gcd(a − b, n).
55*f0865ec9SKyle Evans * 2.3 If 1 < d < n then return(d) and terminate with success.
56*f0865ec9SKyle Evans * 2.4 If d = n then terminate the algorithm with failure (see Note 3.12).
57*f0865ec9SKyle Evans */
pollard_rho(nn_t d,nn_src_t n,const word_t c)58*f0865ec9SKyle Evans int pollard_rho(nn_t d, nn_src_t n, const word_t c)
59*f0865ec9SKyle Evans {
60*f0865ec9SKyle Evans int ret, cmp, cmp1, cmp2;
61*f0865ec9SKyle Evans /* Temporary a and b variables */
62*f0865ec9SKyle Evans nn a, b, tmp, one, c_bignum;
63*f0865ec9SKyle Evans a.magic = b.magic = tmp.magic = one.magic = c_bignum.magic = WORD(0);
64*f0865ec9SKyle Evans
65*f0865ec9SKyle Evans /* Initialize variables */
66*f0865ec9SKyle Evans ret = nn_init(&a, 0); EG(ret, err);
67*f0865ec9SKyle Evans ret = nn_init(&b, 0); EG(ret, err);
68*f0865ec9SKyle Evans ret = nn_init(&tmp, 0); EG(ret, err);
69*f0865ec9SKyle Evans ret = nn_init(&one, 0); EG(ret, err);
70*f0865ec9SKyle Evans ret = nn_init(&c_bignum, 0); EG(ret, err);
71*f0865ec9SKyle Evans ret = nn_init(d, 0); EG(ret, err);
72*f0865ec9SKyle Evans
73*f0865ec9SKyle Evans MUST_HAVE((c > 0), ret, err);
74*f0865ec9SKyle Evans
75*f0865ec9SKyle Evans /* Zeroize the output */
76*f0865ec9SKyle Evans ret = nn_zero(d); EG(ret, err);
77*f0865ec9SKyle Evans ret = nn_one(&one); EG(ret, err);
78*f0865ec9SKyle Evans /* 1. Set a←2, b←2. */
79*f0865ec9SKyle Evans ret = nn_set_word_value(&a, WORD(2)); EG(ret, err);
80*f0865ec9SKyle Evans ret = nn_set_word_value(&b, WORD(2)); EG(ret, err);
81*f0865ec9SKyle Evans ret = nn_set_word_value(&c_bignum, c); EG(ret, err);
82*f0865ec9SKyle Evans
83*f0865ec9SKyle Evans /* For i = 1, 2, . . . do the following: */
84*f0865ec9SKyle Evans while (1) {
85*f0865ec9SKyle Evans int sign;
86*f0865ec9SKyle Evans /* 2.1 Compute a←a^2 + c mod n */
87*f0865ec9SKyle Evans ret = nn_sqr(&a, &a); EG(ret, err);
88*f0865ec9SKyle Evans ret = nn_add(&a, &a, &c_bignum); EG(ret, err);
89*f0865ec9SKyle Evans ret = nn_mod(&a, &a, n); EG(ret, err);
90*f0865ec9SKyle Evans /* 2.1 Compute b←b^2 + c mod n twice in a row */
91*f0865ec9SKyle Evans ret = nn_sqr(&b, &b); EG(ret, err);
92*f0865ec9SKyle Evans ret = nn_add(&b, &b, &c_bignum); EG(ret, err);
93*f0865ec9SKyle Evans ret = nn_mod(&b, &b, n); EG(ret, err);
94*f0865ec9SKyle Evans ret = nn_sqr(&b, &b); EG(ret, err);
95*f0865ec9SKyle Evans ret = nn_add(&b, &b, &c_bignum); EG(ret, err);
96*f0865ec9SKyle Evans ret = nn_mod(&b, &b, n); EG(ret, err);
97*f0865ec9SKyle Evans /* 2.2 Compute d = gcd(a − b, n) */
98*f0865ec9SKyle Evans ret = nn_cmp(&a, &b, &cmp); EG(ret, err);
99*f0865ec9SKyle Evans if (cmp >= 0) {
100*f0865ec9SKyle Evans ret = nn_sub(&tmp, &a, &b); EG(ret, err);
101*f0865ec9SKyle Evans } else {
102*f0865ec9SKyle Evans ret = nn_sub(&tmp, &b, &a); EG(ret, err);
103*f0865ec9SKyle Evans }
104*f0865ec9SKyle Evans ret = nn_gcd(d, &tmp, n, &sign); EG(ret, err);
105*f0865ec9SKyle Evans ret = nn_cmp(d, n, &cmp1); EG(ret, err);
106*f0865ec9SKyle Evans ret = nn_cmp(d, &one, &cmp2); EG(ret, err);
107*f0865ec9SKyle Evans if ((cmp1 < 0) && (cmp2 > 0)) {
108*f0865ec9SKyle Evans ret = 0;
109*f0865ec9SKyle Evans goto err;
110*f0865ec9SKyle Evans }
111*f0865ec9SKyle Evans ret = nn_cmp(d, n, &cmp); EG(ret, err);
112*f0865ec9SKyle Evans if (cmp == 0) {
113*f0865ec9SKyle Evans ret = -1;
114*f0865ec9SKyle Evans goto err;
115*f0865ec9SKyle Evans }
116*f0865ec9SKyle Evans }
117*f0865ec9SKyle Evans err:
118*f0865ec9SKyle Evans /* Uninitialize local variables */
119*f0865ec9SKyle Evans nn_uninit(&a);
120*f0865ec9SKyle Evans nn_uninit(&b);
121*f0865ec9SKyle Evans nn_uninit(&tmp);
122*f0865ec9SKyle Evans nn_uninit(&one);
123*f0865ec9SKyle Evans nn_uninit(&c_bignum);
124*f0865ec9SKyle Evans
125*f0865ec9SKyle Evans return ret;
126*f0865ec9SKyle Evans }
127*f0865ec9SKyle Evans
128*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET int find_divisors(nn_src_t in);
129*f0865ec9SKyle Evans /* Maximum number of divisors we support */
130*f0865ec9SKyle Evans #define MAX_DIVISORS 10
131*f0865ec9SKyle Evans /* Function to find prime divisors of the NN input */
find_divisors(nn_src_t in)132*f0865ec9SKyle Evans int find_divisors(nn_src_t in)
133*f0865ec9SKyle Evans {
134*f0865ec9SKyle Evans int n_divisors_found, i, found, ret, check, cmp;
135*f0865ec9SKyle Evans nn n;
136*f0865ec9SKyle Evans nn divisors[MAX_DIVISORS];
137*f0865ec9SKyle Evans word_t c;
138*f0865ec9SKyle Evans
139*f0865ec9SKyle Evans n.magic = WORD(0);
140*f0865ec9SKyle Evans for(i = 0; i < MAX_DIVISORS; i++){
141*f0865ec9SKyle Evans divisors[i].magic = WORD(0);
142*f0865ec9SKyle Evans }
143*f0865ec9SKyle Evans
144*f0865ec9SKyle Evans ret = nn_check_initialized(in); EG(ret, err);
145*f0865ec9SKyle Evans
146*f0865ec9SKyle Evans ext_printf("=================\n");
147*f0865ec9SKyle Evans nn_print("Finding factors of:", in);
148*f0865ec9SKyle Evans
149*f0865ec9SKyle Evans /* First, check primality of the input */
150*f0865ec9SKyle Evans ret = miller_rabin(in, 10, &check); EG(ret, err);
151*f0865ec9SKyle Evans if (check) {
152*f0865ec9SKyle Evans ext_printf("The number is probably prime, leaving ...\n");
153*f0865ec9SKyle Evans ret = -1;
154*f0865ec9SKyle Evans goto err;
155*f0865ec9SKyle Evans }
156*f0865ec9SKyle Evans ext_printf("The number is composite, performing Pollard's rho\n");
157*f0865ec9SKyle Evans
158*f0865ec9SKyle Evans ret = nn_init(&n, 0); EG(ret, err);
159*f0865ec9SKyle Evans ret = nn_copy(&n, in); EG(ret, err);
160*f0865ec9SKyle Evans for (i = 0; i < MAX_DIVISORS; i++) {
161*f0865ec9SKyle Evans ret = nn_init(&(divisors[i]), 0); EG(ret, err);
162*f0865ec9SKyle Evans }
163*f0865ec9SKyle Evans
164*f0865ec9SKyle Evans n_divisors_found = 0;
165*f0865ec9SKyle Evans c = 0;
166*f0865ec9SKyle Evans while (1) {
167*f0865ec9SKyle Evans c++;
168*f0865ec9SKyle Evans ret = pollard_rho(&(divisors[n_divisors_found]), &n, c);
169*f0865ec9SKyle Evans if (ret) {
170*f0865ec9SKyle Evans continue;
171*f0865ec9SKyle Evans }
172*f0865ec9SKyle Evans found = 0;
173*f0865ec9SKyle Evans for (i = 0; i < n_divisors_found; i++) {
174*f0865ec9SKyle Evans ret = nn_cmp(&(divisors[n_divisors_found]), &(divisors[i]), &cmp); EG(ret, err);
175*f0865ec9SKyle Evans if (cmp == 0) {
176*f0865ec9SKyle Evans found = 1;
177*f0865ec9SKyle Evans }
178*f0865ec9SKyle Evans }
179*f0865ec9SKyle Evans if (found == 0) {
180*f0865ec9SKyle Evans nn q, r;
181*f0865ec9SKyle Evans ret = nn_init(&q, 0); EG(ret, err);
182*f0865ec9SKyle Evans ret = nn_init(&r, 0); EG(ret, err);
183*f0865ec9SKyle Evans ext_printf("Pollard's rho succeded\n");
184*f0865ec9SKyle Evans nn_print("d:", &(divisors[n_divisors_found]));
185*f0865ec9SKyle Evans /*
186*f0865ec9SKyle Evans * Now we can launch the algorithm again on n / d
187*f0865ec9SKyle Evans * to find new divisors. If n / d is prime, we are done!
188*f0865ec9SKyle Evans */
189*f0865ec9SKyle Evans ret = nn_divrem(&q, &r, &n, &(divisors[n_divisors_found])); EG(ret, err);
190*f0865ec9SKyle Evans /*
191*f0865ec9SKyle Evans * Check n / d primality with Miller-Rabin (security
192*f0865ec9SKyle Evans * parameter of 10)
193*f0865ec9SKyle Evans */
194*f0865ec9SKyle Evans ret = miller_rabin(&q, 10, &check); EG(ret, err);
195*f0865ec9SKyle Evans if (check == 1) {
196*f0865ec9SKyle Evans nn_print("Last divisor is prime:", &q);
197*f0865ec9SKyle Evans nn_uninit(&q);
198*f0865ec9SKyle Evans nn_uninit(&r);
199*f0865ec9SKyle Evans break;
200*f0865ec9SKyle Evans }
201*f0865ec9SKyle Evans nn_print("Now performing Pollard's rho on:", &q);
202*f0865ec9SKyle Evans ret = nn_copy(&n, &q); EG(ret, err);
203*f0865ec9SKyle Evans nn_uninit(&q);
204*f0865ec9SKyle Evans nn_uninit(&r);
205*f0865ec9SKyle Evans c = 0;
206*f0865ec9SKyle Evans n_divisors_found++;
207*f0865ec9SKyle Evans if (n_divisors_found == MAX_DIVISORS) {
208*f0865ec9SKyle Evans ext_printf
209*f0865ec9SKyle Evans ("Max divisors reached, leaving ...\n");
210*f0865ec9SKyle Evans break;
211*f0865ec9SKyle Evans }
212*f0865ec9SKyle Evans }
213*f0865ec9SKyle Evans }
214*f0865ec9SKyle Evans ret = 0;
215*f0865ec9SKyle Evans
216*f0865ec9SKyle Evans err:
217*f0865ec9SKyle Evans ext_printf("=================\n");
218*f0865ec9SKyle Evans nn_uninit(&n);
219*f0865ec9SKyle Evans for (i = 0; i < MAX_DIVISORS; i++) {
220*f0865ec9SKyle Evans nn_uninit(&(divisors[i]));
221*f0865ec9SKyle Evans }
222*f0865ec9SKyle Evans return ret;
223*f0865ec9SKyle Evans }
224*f0865ec9SKyle Evans
225*f0865ec9SKyle Evans #ifdef NN_EXAMPLE
main(int argc,char * argv[])226*f0865ec9SKyle Evans int main(int argc, char *argv[])
227*f0865ec9SKyle Evans {
228*f0865ec9SKyle Evans int ret;
229*f0865ec9SKyle Evans
230*f0865ec9SKyle Evans /* Fermat F5 = 2^32 + 1 = 641 x 6700417 */
231*f0865ec9SKyle Evans const unsigned char fermat_F5[] = { 0x01, 0x00, 0x00, 0x00, 0x01 };
232*f0865ec9SKyle Evans /* Fermat F6 = 2^64 + 1 = 274177 x 67280421310721 */
233*f0865ec9SKyle Evans const unsigned char fermat_F6[] =
234*f0865ec9SKyle Evans { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 };
235*f0865ec9SKyle Evans nn n;
236*f0865ec9SKyle Evans n.magic = WORD(0);
237*f0865ec9SKyle Evans
238*f0865ec9SKyle Evans FORCE_USED_VAR(argc);
239*f0865ec9SKyle Evans FORCE_USED_VAR(argv);
240*f0865ec9SKyle Evans
241*f0865ec9SKyle Evans ret = nn_init(&n, 0); EG(ret, err);
242*f0865ec9SKyle Evans /* Execute factorization on F5 */
243*f0865ec9SKyle Evans ret = nn_init_from_buf(&n, fermat_F5, sizeof(fermat_F5)); EG(ret, err);
244*f0865ec9SKyle Evans ret = find_divisors(&n); EG(ret, err);
245*f0865ec9SKyle Evans /* Execute factorization on F6 */
246*f0865ec9SKyle Evans ret = nn_init_from_buf(&n, fermat_F6, sizeof(fermat_F6)); EG(ret, err);
247*f0865ec9SKyle Evans ret = find_divisors(&n); EG(ret, err);
248*f0865ec9SKyle Evans /* Execute factorization on a random 80 bits number */
249*f0865ec9SKyle Evans ret = nn_one(&n); EG(ret, err);
250*f0865ec9SKyle Evans /* Compute 2**80 = 0x1 << 80 */
251*f0865ec9SKyle Evans ret = nn_lshift(&n, &n, 80); EG(ret, err);
252*f0865ec9SKyle Evans ret = nn_get_random_mod(&n, &n); EG(ret, err);
253*f0865ec9SKyle Evans ret = find_divisors(&n); EG(ret, err);
254*f0865ec9SKyle Evans
255*f0865ec9SKyle Evans return 0;
256*f0865ec9SKyle Evans err:
257*f0865ec9SKyle Evans return -1;
258*f0865ec9SKyle Evans }
259*f0865ec9SKyle Evans #endif
260