Path: blob/main/crypto/libecc/src/examples/basic/nn_pollard_rho.c
34907 views
/*1* Copyright (C) 2017 - This file is part of libecc project2*3* Authors:4* Ryad BENADJILA <[email protected]>5* Arnaud EBALARD <[email protected]>6* Jean-Pierre FLORI <[email protected]>7*8* Contributors:9* Nicolas VIVET <[email protected]>10* Karim KHALFALLAH <[email protected]>11*12* This software is licensed under a dual BSD and GPL v2 license.13* See LICENSE file at the root folder of the project.14*/15/*16* The purpose of this example is to implement Pollard's rho17* algorithm to find non-trivial factors of a composite natural18* number.19* The prime numbers decomposition of the natural number is20* recovered through repeated Pollard's rho. Primality checking21* is performed using a Miller-Rabin test.22*23* WARNING: the code in this example is only here to illustrate24* how to use the NN layer API. This code has not been designed25* for production purposes (e.g. no effort has been made to make26* it constant time).27*28*29*/3031/* We include the NN layer API header */32#include <libecc/libarith.h>3334/* Declare our Miller-Rabin test implemented35* in another module.36*/37ATTRIBUTE_WARN_UNUSED_RET int miller_rabin(nn_src_t n, const unsigned int t, int *check);3839ATTRIBUTE_WARN_UNUSED_RET int pollard_rho(nn_t d, nn_src_t n, const word_t c);40/* Pollard's rho main function, as described in41* "Handbook of Applied Cryptography".42*43* Pollard's rho:44* ==============45* See "Handbook of Applied Cryptography", alorithm 3.9:46*47* Algorithm Pollard’s rho algorithm for factoring integers48* INPUT: a composite integer n that is not a prime power.49* OUTPUT: a non-trivial factor d of n.50* 1. Set a←2, b←2.51* 2. For i = 1, 2, ... do the following:52* 2.1 Compute a←a^2 + 1 mod n, b←b^2 + 1 mod n, b←b^2 + 1 mod n.53* 2.2 Compute d = gcd(a − b, n).54* 2.3 If 1 < d < n then return(d) and terminate with success.55* 2.4 If d = n then terminate the algorithm with failure (see Note 3.12).56*/57int pollard_rho(nn_t d, nn_src_t n, const word_t c)58{59int ret, cmp, cmp1, cmp2;60/* Temporary a and b variables */61nn a, b, tmp, one, c_bignum;62a.magic = b.magic = tmp.magic = one.magic = c_bignum.magic = WORD(0);6364/* Initialize variables */65ret = nn_init(&a, 0); EG(ret, err);66ret = nn_init(&b, 0); EG(ret, err);67ret = nn_init(&tmp, 0); EG(ret, err);68ret = nn_init(&one, 0); EG(ret, err);69ret = nn_init(&c_bignum, 0); EG(ret, err);70ret = nn_init(d, 0); EG(ret, err);7172MUST_HAVE((c > 0), ret, err);7374/* Zeroize the output */75ret = nn_zero(d); EG(ret, err);76ret = nn_one(&one); EG(ret, err);77/* 1. Set a←2, b←2. */78ret = nn_set_word_value(&a, WORD(2)); EG(ret, err);79ret = nn_set_word_value(&b, WORD(2)); EG(ret, err);80ret = nn_set_word_value(&c_bignum, c); EG(ret, err);8182/* For i = 1, 2, . . . do the following: */83while (1) {84int sign;85/* 2.1 Compute a←a^2 + c mod n */86ret = nn_sqr(&a, &a); EG(ret, err);87ret = nn_add(&a, &a, &c_bignum); EG(ret, err);88ret = nn_mod(&a, &a, n); EG(ret, err);89/* 2.1 Compute b←b^2 + c mod n twice in a row */90ret = nn_sqr(&b, &b); EG(ret, err);91ret = nn_add(&b, &b, &c_bignum); EG(ret, err);92ret = nn_mod(&b, &b, n); EG(ret, err);93ret = nn_sqr(&b, &b); EG(ret, err);94ret = nn_add(&b, &b, &c_bignum); EG(ret, err);95ret = nn_mod(&b, &b, n); EG(ret, err);96/* 2.2 Compute d = gcd(a − b, n) */97ret = nn_cmp(&a, &b, &cmp); EG(ret, err);98if (cmp >= 0) {99ret = nn_sub(&tmp, &a, &b); EG(ret, err);100} else {101ret = nn_sub(&tmp, &b, &a); EG(ret, err);102}103ret = nn_gcd(d, &tmp, n, &sign); EG(ret, err);104ret = nn_cmp(d, n, &cmp1); EG(ret, err);105ret = nn_cmp(d, &one, &cmp2); EG(ret, err);106if ((cmp1 < 0) && (cmp2 > 0)) {107ret = 0;108goto err;109}110ret = nn_cmp(d, n, &cmp); EG(ret, err);111if (cmp == 0) {112ret = -1;113goto err;114}115}116err:117/* Uninitialize local variables */118nn_uninit(&a);119nn_uninit(&b);120nn_uninit(&tmp);121nn_uninit(&one);122nn_uninit(&c_bignum);123124return ret;125}126127ATTRIBUTE_WARN_UNUSED_RET int find_divisors(nn_src_t in);128/* Maximum number of divisors we support */129#define MAX_DIVISORS 10130/* Function to find prime divisors of the NN input */131int find_divisors(nn_src_t in)132{133int n_divisors_found, i, found, ret, check, cmp;134nn n;135nn divisors[MAX_DIVISORS];136word_t c;137138n.magic = WORD(0);139for(i = 0; i < MAX_DIVISORS; i++){140divisors[i].magic = WORD(0);141}142143ret = nn_check_initialized(in); EG(ret, err);144145ext_printf("=================\n");146nn_print("Finding factors of:", in);147148/* First, check primality of the input */149ret = miller_rabin(in, 10, &check); EG(ret, err);150if (check) {151ext_printf("The number is probably prime, leaving ...\n");152ret = -1;153goto err;154}155ext_printf("The number is composite, performing Pollard's rho\n");156157ret = nn_init(&n, 0); EG(ret, err);158ret = nn_copy(&n, in); EG(ret, err);159for (i = 0; i < MAX_DIVISORS; i++) {160ret = nn_init(&(divisors[i]), 0); EG(ret, err);161}162163n_divisors_found = 0;164c = 0;165while (1) {166c++;167ret = pollard_rho(&(divisors[n_divisors_found]), &n, c);168if (ret) {169continue;170}171found = 0;172for (i = 0; i < n_divisors_found; i++) {173ret = nn_cmp(&(divisors[n_divisors_found]), &(divisors[i]), &cmp); EG(ret, err);174if (cmp == 0) {175found = 1;176}177}178if (found == 0) {179nn q, r;180ret = nn_init(&q, 0); EG(ret, err);181ret = nn_init(&r, 0); EG(ret, err);182ext_printf("Pollard's rho succeded\n");183nn_print("d:", &(divisors[n_divisors_found]));184/*185* Now we can launch the algorithm again on n / d186* to find new divisors. If n / d is prime, we are done!187*/188ret = nn_divrem(&q, &r, &n, &(divisors[n_divisors_found])); EG(ret, err);189/*190* Check n / d primality with Miller-Rabin (security191* parameter of 10)192*/193ret = miller_rabin(&q, 10, &check); EG(ret, err);194if (check == 1) {195nn_print("Last divisor is prime:", &q);196nn_uninit(&q);197nn_uninit(&r);198break;199}200nn_print("Now performing Pollard's rho on:", &q);201ret = nn_copy(&n, &q); EG(ret, err);202nn_uninit(&q);203nn_uninit(&r);204c = 0;205n_divisors_found++;206if (n_divisors_found == MAX_DIVISORS) {207ext_printf208("Max divisors reached, leaving ...\n");209break;210}211}212}213ret = 0;214215err:216ext_printf("=================\n");217nn_uninit(&n);218for (i = 0; i < MAX_DIVISORS; i++) {219nn_uninit(&(divisors[i]));220}221return ret;222}223224#ifdef NN_EXAMPLE225int main(int argc, char *argv[])226{227int ret;228229/* Fermat F5 = 2^32 + 1 = 641 x 6700417 */230const unsigned char fermat_F5[] = { 0x01, 0x00, 0x00, 0x00, 0x01 };231/* Fermat F6 = 2^64 + 1 = 274177 x 67280421310721 */232const unsigned char fermat_F6[] =233{ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 };234nn n;235n.magic = WORD(0);236237FORCE_USED_VAR(argc);238FORCE_USED_VAR(argv);239240ret = nn_init(&n, 0); EG(ret, err);241/* Execute factorization on F5 */242ret = nn_init_from_buf(&n, fermat_F5, sizeof(fermat_F5)); EG(ret, err);243ret = find_divisors(&n); EG(ret, err);244/* Execute factorization on F6 */245ret = nn_init_from_buf(&n, fermat_F6, sizeof(fermat_F6)); EG(ret, err);246ret = find_divisors(&n); EG(ret, err);247/* Execute factorization on a random 80 bits number */248ret = nn_one(&n); EG(ret, err);249/* Compute 2**80 = 0x1 << 80 */250ret = nn_lshift(&n, &n, 80); EG(ret, err);251ret = nn_get_random_mod(&n, &n); EG(ret, err);252ret = find_divisors(&n); EG(ret, err);253254return 0;255err:256return -1;257}258#endif259260261