Path: blob/main/crypto/libecc/src/examples/basic/nn_miller_rabin.c
34889 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/* We include the NN layer API header */16#include <libecc/libarith.h>1718ATTRIBUTE_WARN_UNUSED_RET int miller_rabin(nn_src_t n, const unsigned int t, int *res);1920/* Miller-Rabin primality test.21* See "Handbook of Applied Cryptography", alorithm 4.24:22*23* Algorithm: Miller-Rabin probabilistic primality test24* MILLER-RABIN(n,t)25* INPUT: an odd integer n ≥ 3 and security parameter t ≥ 1.26* OUTPUT: an answer “prime” or “composite” to the question: “Is n prime?”27* 1. Write n − 1 = 2**s x r such that r is odd.28* 2. For i from 1 to t do the following:29* 2.1 Choose a random integer a, 2 ≤ a ≤ n − 2.30* 2.2 Compute y = a**r mod n using Algorithm 2.143.31* 2.3 If y != 1 and y != n − 1 then do the following:32* j←1.33* While j ≤ s − 1 and y != n − 1 do the following:34* Compute y←y2 mod n.35* If y = 1 then return(“composite”).36* j←j + 1.37* If y != n − 1 then return (“composite”).38* 3. Return(“maybe prime”).39*40* The Miller-Rabin test can give false positives when41* answering "maybe prime", but is always right when answering42* "composite".43*/44int miller_rabin(nn_src_t n, const unsigned int t, int *res)45{46int ret, iszero, cmp, isodd, cmp1, cmp2;47unsigned int i;48bitcnt_t k;49/* Temporary NN variables */50nn s, q, r, d, a, y, j, one, two, tmp;51s.magic = q.magic = r.magic = d.magic = a.magic = y.magic = j.magic = WORD(0);52one.magic = two.magic = tmp.magic = WORD(0);5354ret = nn_check_initialized(n); EG(ret, err);55MUST_HAVE((res != NULL), ret, err);56(*res) = 0;5758/* Initialize our local NN variables */59ret = nn_init(&s, 0); EG(ret, err);60ret = nn_init(&q, 0); EG(ret, err);61ret = nn_init(&r, 0); EG(ret, err);62ret = nn_init(&d, 0); EG(ret, err);63ret = nn_init(&a, 0); EG(ret, err);64ret = nn_init(&y, 0); EG(ret, err);65ret = nn_init(&j, 0); EG(ret, err);66ret = nn_init(&one, 0); EG(ret, err);67ret = nn_init(&two, 0); EG(ret, err);68ret = nn_init(&tmp, 0); EG(ret, err);6970/* Security parameter t must be >= 1 */71MUST_HAVE((t >= 1), ret, err);7273/* one = 1 */74ret = nn_one(&one); EG(ret, err);75/* two = 2 */76ret = nn_set_word_value(&two, WORD(2)); EG(ret, err);7778/* If n = 0, this is not a prime */79ret = nn_iszero(n, &iszero); EG(ret, err);80if (iszero) {81ret = 0;82(*res) = 0;83goto err;84}85/* If n = 1, this is not a prime */86ret = nn_cmp(n, &one, &cmp); EG(ret, err);87if (cmp == 0) {88ret = 0;89(*res) = 0;90goto err;91}92/* If n = 2, this is a prime number */93ret = nn_cmp(n, &two, &cmp); EG(ret, err);94if (cmp == 0) {95ret = 0;96(*res) = 1;97goto err;98}99/* If n = 3, this is a prime number */100ret = nn_copy(&tmp, n); EG(ret, err);101ret = nn_dec(&tmp, &tmp); EG(ret, err);102ret = nn_cmp(&tmp, &two, &cmp); EG(ret, err);103if (cmp == 0) {104ret = 0;105(*res) = 1;106goto err;107}108109/* If n >= 4 is even, this is not a prime */110ret = nn_isodd(n, &isodd); EG(ret, err);111if (!isodd) {112ret = 0;113(*res) = 0;114goto err;115}116117/* n − 1 = 2^s x r, repeatedly try to divide n-1 by 2 */118/* s = 0 and r = n-1 */119ret = nn_zero(&s); EG(ret, err);120ret = nn_copy(&r, n); EG(ret, err);121ret = nn_dec(&r, &r); EG(ret, err);122while (1) {123ret = nn_divrem(&q, &d, &r, &two); EG(ret, err);124ret = nn_inc(&s, &s); EG(ret, err);125ret = nn_copy(&r, &q); EG(ret, err);126/* If r is odd, we have finished our division */127ret = nn_isodd(&r, &isodd); EG(ret, err);128if (isodd) {129break;130}131}132/* 2. For i from 1 to t do the following: */133for (i = 1; i <= t; i++) {134bitcnt_t blen;135/* 2.1 Choose a random integer a, 2 ≤ a ≤ n − 2 */136ret = nn_copy(&tmp, n); EG(ret, err);137ret = nn_dec(&tmp, &tmp); EG(ret, err);138ret = nn_zero(&a); EG(ret, err);139ret = nn_cmp(&a, &two, &cmp); EG(ret, err);140while (cmp < 0) {141ret = nn_get_random_mod(&a, &tmp); EG(ret, err);142ret = nn_cmp(&a, &two, &cmp); EG(ret, err);143}144/* A very loose (and NOT robust) implementation of145* modular exponentiation with square and multiply146* to compute y = a**r (n)147* WARNING: NOT to be used in production code!148*/149ret = nn_one(&y); EG(ret, err);150ret = nn_bitlen(&r, &blen); EG(ret, err);151for (k = 0; k < blen; k++) {152u8 bit;153ret = nn_getbit(&r, k, &bit); EG(ret, err);154if (bit) {155/* Warning: the multiplication is not modular, we156* have to take care of our size here!157*/158MUST_HAVE((NN_MAX_BIT_LEN >=159(WORD_BITS * (y.wlen + a.wlen))), ret, err);160ret = nn_mul(&y, &y, &a); EG(ret, err);161ret = nn_mod(&y, &y, n); EG(ret, err);162}163MUST_HAVE((NN_MAX_BIT_LEN >= (2 * WORD_BITS * a.wlen)), ret, err);164ret = nn_sqr(&a, &a); EG(ret, err);165ret = nn_mod(&a, &a, n); EG(ret, err);166}167/* 2.3 If y != 1 and y != n − 1 then do the following168* Note: tmp still contains n - 1 here.169*/170ret = nn_cmp(&y, &one, &cmp1); EG(ret, err);171ret = nn_cmp(&y, &tmp, &cmp2); EG(ret, err);172if ((cmp1 != 0) && (cmp2 != 0)) {173/* j←1. */174ret = nn_one(&j); EG(ret, err);175/* While j ≤ s − 1 and y != n − 1 do the following: */176ret = nn_cmp(&j, &s, &cmp1); EG(ret, err);177ret = nn_cmp(&y, &tmp, &cmp2); EG(ret, err);178while ((cmp1 < 0) && (cmp2 != 0)) {179/* Compute y←y2 mod n. */180MUST_HAVE((NN_MAX_BIT_LEN >=181(2 * WORD_BITS * y.wlen)), ret, err);182ret = nn_sqr(&y, &y); EG(ret, err);183ret = nn_mod(&y, &y, n); EG(ret, err);184/* If y = 1 then return(“composite”). */185ret = nn_cmp(&y, &one, &cmp); EG(ret, err);186if (cmp == 0) {187ret = 0;188(*res) = 0;189goto err;190}191/* j←j + 1. */192ret = nn_inc(&j, &j); EG(ret, err);193ret = nn_cmp(&j, &s, &cmp1); EG(ret, err);194ret = nn_cmp(&y, &tmp, &cmp2); EG(ret, err);195}196/* If y != n − 1 then return (“composite”). */197ret = nn_cmp(&y, &tmp, &cmp); EG(ret, err);198if (cmp != 0) {199ret = 0;200(*res) = 0;201goto err;202}203}204/* 3. Return(“maybe prime”). */205ret = 0;206(*res) = 1;207}208209err:210nn_uninit(&s);211nn_uninit(&q);212nn_uninit(&r);213nn_uninit(&d);214nn_uninit(&a);215nn_uninit(&y);216nn_uninit(&j);217nn_uninit(&one);218nn_uninit(&two);219nn_uninit(&tmp);220221return ret;222}223224225