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 */ 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 */ 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 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