/* rsa.c -- benchmark signing with the RSA algorithm. Copyright 2003 Free Software Foundation, Inc. This file is part of GMPbench. GMPbench is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. GMPbench is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GMPbench. If not, see http://www.gnu.org/licenses/. */ #include #include #include "gmp.h" #include "timing.h" #define RSA_EXP 0x10001 int cputime (void); void rsa_sign (mpz_t, mpz_t, mpz_t, mpz_t, mpz_t, mpz_t, mpz_t, mpz_t); int main (int argc, char *argv[]) { gmp_randstate_t rs; mpz_t p, q, pq, pm1, qm1, phi, e, d, p_i_q, dp, dq, msg[1024], smsg; unsigned long int n, i, niter, t0, ti; double t, f, ops_per_sec; int decimals; if (argc != 2) { fprintf (stderr, "usage: %s n\n", argv[0]); fprintf (stderr, " where n is number of bits in numbers tested\n"); return -1; } if (argc == 2) n = atoi (argv[1]); gmp_randinit_default (rs); mpz_init (p); mpz_init (q); mpz_init (pq); printf ("Generating p, q, d..."); fflush (stdout); #if 0 mpz_urandomb (p, rs, n/2); mpz_setbit (p, n / 2 - 1); mpz_setbit (p, n / 2 - 2); mpz_nextprime (p, p); mpz_urandomb (q, rs, n/2); mpz_setbit (q, n / 2 - 1); mpz_setbit (q, n / 2 - 2); mpz_nextprime (q, q); #else do { mpz_urandomb (p, rs, n/2); mpz_setbit (p, n / 2 - 1); mpz_setbit (p, n / 2 - 2); mpz_setbit (p, 0); mpz_urandomb (q, rs, n/2); mpz_setbit (q, n / 2 - 1); mpz_setbit (q, n / 2 - 2); mpz_setbit (q, 0); mpz_gcd (pq, p, q); } while (mpz_cmp_ui (pq, 1) != 0); #endif mpz_mul (pq, p, q); mpz_init_set_ui (e, RSA_EXP); mpz_init (d); mpz_init (pm1); mpz_init (qm1); mpz_init (phi); mpz_sub_ui (pm1, p, 1); mpz_sub_ui (qm1, q, 1); mpz_mul (phi, pm1, qm1); if (mpz_invert (d, e, phi) == 0) abort (); printf ("done; pq is %d bits\n", (int) mpz_sizeinbase (pq, 2)); printf ("Precomputing CRT constants\n"); mpz_init (p_i_q); if (mpz_invert (p_i_q, p, q) == 0) abort (); mpz_init (dp); mpz_init (dq); mpz_mod (dp, d, pm1); mpz_mod (dq, d, qm1); printf ("Generating random messages\n"); for (i = 0; i < 1024; i++) { mpz_init (msg[i]); mpz_urandomb (msg[i], rs, n); } mpz_init (smsg); printf ("Calibrating CPU speed..."); fflush (stdout); TIME (t, rsa_sign (smsg, msg[0], p, q, pq, p_i_q, dp, dq)); printf ("done\n"); niter = (unsigned long) (1e4 / t); if (niter == 0) niter = 1; printf ("Signing random messages %lu times...", niter); fflush (stdout); t0 = cputime (); for (i = niter; i > 0; i--) { rsa_sign (smsg, msg[i % 1024], p, q, pq, p_i_q, dp, dq); } ti = cputime () - t0; printf ("done!\n"); ops_per_sec = 1000.0 * niter / ti; f = 100.0; for (decimals = 0;; decimals++) { if (ops_per_sec > f) break; f = f * 0.1; } printf ("RESULT: %.*f operations per second\n", decimals, ops_per_sec); return 0; } void rsa_sign (mpz_t smsg, mpz_t msg, mpz_t p, mpz_t q, mpz_t pq, mpz_t p_i_q, mpz_t dp, mpz_t dq) { mpz_t t, o, pr, qr, qr_m_pr; mpz_init (pr); mpz_init (qr); mpz_init (qr_m_pr); mpz_init (t); mpz_init (o); mpz_powm (pr, msg, dp, p); mpz_powm (qr, msg, dq, q); mpz_sub (qr_m_pr, qr, pr); mpz_mul (t, qr_m_pr, p_i_q); mpz_mod (o, t, q); /* slow mod */ mpz_mul (t, o, p); mpz_add (smsg, pr, t); mpz_mod (smsg, smsg, pq); /* fast mod */ mpz_clear (o); mpz_clear (t); mpz_clear (qr_m_pr); mpz_clear (qr); mpz_clear (pr); } /* Return user CPU time measured in milliseconds. */ // #if !defined (__sun) \ // && (defined (USG) || defined (__SVR4) || defined (_UNICOS) \ // || defined (__hpux)) #include int cputime () { return (int) ((double) clock () * 1000 / CLOCKS_PER_SEC); } // #else // #include // #include // #include // int // cputime () // { // struct rusage rus; // getrusage (0, &rus); // return rus.ru_utime.tv_sec * 1000 + rus.ru_utime.tv_usec / 1000; // } // #endif