1 /*
2  * Argon2 reference source code package - reference C implementations
3  *
4  * Copyright 2015
5  * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
6  *
7  * You may use this work under the terms of a Creative Commons CC0 1.0
8  * License/Waiver or the Apache Public License 2.0, at your option. The terms of
9  * these licenses can be found at:
10  *
11  * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
12  * - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * You should have received a copy of both of these licenses along with this
15  * software. If not, they may be obtained at the above URLs.
16  */
17 
18 #include <stdio.h>
19 #include <stdint.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <time.h>
23 #ifdef _MSC_VER
24 #include <intrin.h>
25 #endif
26 
27 #include "argon2.h"
28 
rdtsc(void)29 static uint64_t rdtsc(void) {
30 #ifdef _MSC_VER
31     return __rdtsc();
32 #else
33 #if defined(__amd64__) || defined(__x86_64__)
34     uint64_t rax, rdx;
35     __asm__ __volatile__("rdtsc" : "=a"(rax), "=d"(rdx) : :);
36     return (rdx << 32) | rax;
37 #elif defined(__i386__) || defined(__i386) || defined(__X86__)
38     uint64_t rax;
39     __asm__ __volatile__("rdtsc" : "=A"(rax) : :);
40     return rax;
41 #else
42 #error "Not implemented!"
43 #endif
44 #endif
45 }
46 
47 /*
48  * Benchmarks Argon2 with salt length 16, password length 16, t_cost 3,
49    and different m_cost and threads
50  */
benchmark()51 static void benchmark() {
52 #define BENCH_OUTLEN 16
53 #define BENCH_INLEN 16
54     const uint32_t inlen = BENCH_INLEN;
55     const unsigned outlen = BENCH_OUTLEN;
56     unsigned char out[BENCH_OUTLEN];
57     unsigned char pwd_array[BENCH_INLEN];
58     unsigned char salt_array[BENCH_INLEN];
59 #undef BENCH_INLEN
60 #undef BENCH_OUTLEN
61 
62     uint32_t t_cost = 3;
63     uint32_t m_cost;
64     uint32_t thread_test[4] = {1, 2, 4,  8};
65     argon2_type types[3] = {Argon2_i, Argon2_d, Argon2_id};
66 
67     memset(pwd_array, 0, inlen);
68     memset(salt_array, 1, inlen);
69 
70     for (m_cost = (uint32_t)1 << 10; m_cost <= (uint32_t)1 << 22; m_cost *= 2) {
71         unsigned i;
72         for (i = 0; i < 4; ++i) {
73             double run_time = 0;
74             uint32_t thread_n = thread_test[i];
75 
76             unsigned j;
77             for (j = 0; j < 3; ++j) {
78                 clock_t start_time, stop_time;
79                 uint64_t start_cycles, stop_cycles;
80                 uint64_t delta;
81                 double mcycles;
82 
83                 argon2_type type = types[j];
84                 start_time = clock();
85                 start_cycles = rdtsc();
86 
87                 argon2_hash(t_cost, m_cost, thread_n, pwd_array, inlen,
88                             salt_array, inlen, out, outlen, NULL, 0, type,
89                             ARGON2_VERSION_NUMBER);
90 
91                 stop_cycles = rdtsc();
92                 stop_time = clock();
93 
94                 delta = (stop_cycles - start_cycles) / (m_cost);
95                 mcycles = (double)(stop_cycles - start_cycles) / (1UL << 20);
96                 run_time += ((double)stop_time - start_time) / (CLOCKS_PER_SEC);
97 
98                 printf("%s %d iterations  %d MiB %d threads:  %2.2f cpb %2.2f "
99                        "Mcycles \n", argon2_type2string(type, 1), t_cost,
100                        m_cost >> 10, thread_n, (float)delta / 1024, mcycles);
101             }
102 
103             printf("%2.4f seconds\n\n", run_time);
104         }
105     }
106 }
107 
main()108 int main() {
109     benchmark();
110     return ARGON2_OK;
111 }
112