bench_decaf.cxx 8.48 KB
Newer Older
Mike Hamburg's avatar
Mike Hamburg committed
1 2 3 4 5 6 7 8 9 10 11
/**
 * @file test_decaf.cxx
 * @author Mike Hamburg
 *
 * @copyright
 *   Copyright (c) 2015 Cryptography Research, Inc.  \n
 *   Released under the MIT License.  See LICENSE.txt for license information.
 *
 * @brief C++ benchmarks, because that's easier.
 */

12 13
#include <decaf.hxx>
#include <decaf/shake.hxx>
14
#include <decaf/sha512.hxx>
15
#include <decaf/spongerng.hxx>
16
#include <decaf/eddsa.hxx>
Mike Hamburg's avatar
Mike Hamburg committed
17 18 19
#include <stdio.h>
#include <assert.h>
#include <stdint.h>
20 21
#include <vector>
#include <algorithm>
Mike Hamburg's avatar
Mike Hamburg committed
22

Mike Hamburg's avatar
Mike Hamburg committed
23 24
using namespace decaf;

mrolinek's avatar
mrolinek committed
25 26 27 28 29
#if defined _MSC_VER  // Turn off attribute code and rename inline
#define __attribute__(x)        // Turn off attribute code
#define __attribute(x)
#define __inline__ __inline  // Use MSVC inline
#endif // MSVC
Mike Hamburg's avatar
Mike Hamburg committed
30 31

static __inline__ void __attribute__((unused)) ignore_result ( int result ) { (void)result; }
mrolinek's avatar
mrolinek committed
32 33 34 35 36 37 38 39 40 41 42
#if defined _MSC_VER  // MSVC does not have gettimeoftheday
#include <chrono>
static double now(void) {
  static const auto beg = std::chrono::high_resolution_clock::now();
  auto end_time = std::chrono::high_resolution_clock::now();
  auto time = end_time - beg;
  double duration = 0.000001 * std::chrono::duration_cast<std::chrono::microseconds>(time).count();
  return duration;
}
#else
#include <sys/time.h>
Mike Hamburg's avatar
Mike Hamburg committed
43 44 45 46 47
static double now(void) {
  struct timeval tv;
  gettimeofday(&tv, NULL);
  return tv.tv_sec + tv.tv_usec/1000000.0;
}
mrolinek's avatar
mrolinek committed
48 49
#endif

Mike Hamburg's avatar
Mike Hamburg committed
50 51 52 53 54 55 56 57 58

// RDTSC from the chacha code
#ifndef __has_builtin
#define __has_builtin(X) 0
#endif
#if defined(__clang__) && __has_builtin(__builtin_readcyclecounter)
#define rdtsc __builtin_readcyclecounter
#else
static inline uint64_t rdtsc(void) {
59 60 61 62 63 64 65 66 67 68
# if defined(__x86_64__)
    uint32_t lobits, hibits;
    __asm__ __volatile__ ("rdtsc" : "=a"(lobits), "=d"(hibits));
    return (lobits | ((uint64_t)(hibits) << 32));
# elif defined(__i386__)
    uint64_t __value;
    __asm__ __volatile__ ("rdtsc" : "=A"(__value));
    return __value;
# else
    return 0;
Mike Hamburg's avatar
Mike Hamburg committed
69 70 71 72
# endif
}
#endif

Mike Hamburg's avatar
Mike Hamburg committed
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
static void printSI(double x, const char *unit, const char *spacer = " ") {
    const char *small[] = {" ","m","µ","n","p"};
    const char *big[] = {" ","k","M","G","T"};
    if (x < 1) {
        unsigned di=0;
        for (di=0; di<sizeof(small)/sizeof(*small)-1 && x && x < 1; di++) { 
            x *= 1000.0;
        }
        printf("%6.2f%s%s%s", x, spacer, small[di], unit);
    } else {
        unsigned di=0;
        for (di=0; di<sizeof(big)/sizeof(*big)-1 && x && x >= 1000; di++) { 
            x /= 1000.0;
        }
        printf("%6.2f%s%s%s", x, spacer, big[di], unit);
    }
}

Mike Hamburg's avatar
Mike Hamburg committed
91
class Benchmark {
92
    static const int NTESTS = 20, NSAMPLES=50, DISCARD=2;
Mike Hamburg's avatar
Mike Hamburg committed
93
    static double totalCy, totalS;
Mike Hamburg's avatar
Mike Hamburg committed
94
public:
95
    int i, j, ntests, nsamples;
Mike Hamburg's avatar
Mike Hamburg committed
96 97
    double begin;
    uint64_t tsc_begin;
98 99
    std::vector<double> times;
    std::vector<uint64_t> cycles;
Mike Hamburg's avatar
Mike Hamburg committed
100 101 102 103
    Benchmark(const char *s, double factor = 1) {
        printf("%s:", s);
        if (strlen(s) < 25) printf("%*s",int(25-strlen(s)),"");
        fflush(stdout);
104
        i = j = 0;
Mike Hamburg's avatar
Mike Hamburg committed
105
        ntests = NTESTS * factor;
106
        nsamples = NSAMPLES;
Mike Hamburg's avatar
Mike Hamburg committed
107 108
        begin = now();
        tsc_begin = rdtsc();
109 110
        times = std::vector<double>(NSAMPLES);
        cycles = std::vector<uint64_t>(NSAMPLES);
Mike Hamburg's avatar
Mike Hamburg committed
111 112
    }
    ~Benchmark() {
113 114 115 116 117 118 119 120 121 122
        double tsc = 0;
        double t = 0;
        
        std::sort(times.begin(), times.end());
        std::sort(cycles.begin(), cycles.end());
        
        for (int k=DISCARD; k<nsamples-DISCARD; k++) {
            tsc += cycles[k];
            t += times[k];
        }
Mike Hamburg's avatar
Mike Hamburg committed
123 124 125 126
        
        totalCy += tsc;
        totalS += t;
        
127 128
        t /= ntests*(nsamples-2*DISCARD);
        tsc /= ntests*(nsamples-2*DISCARD);
Mike Hamburg's avatar
Mike Hamburg committed
129 130 131 132 133
        
        printSI(t,"s");
        printf("    ");
        printSI(1/t,"/s");
        if (tsc) { printf("    "); printSI(tsc, "cy"); }
Mike Hamburg's avatar
Mike Hamburg committed
134 135
        printf("\n");
    }
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
    inline bool iter() {
        i++;
        if (i >= ntests) {
            uint64_t tsc = rdtsc() - tsc_begin;
            double t = now() - begin;
            begin += t;
            tsc_begin += tsc;
            assert(j >= 0 && j < nsamples);
            cycles[j] = tsc;
            times[j] = t;
            
            j++;
            i = 0;
        }
        return j < nsamples;
    }
Mike Hamburg's avatar
Mike Hamburg committed
152 153 154 155 156 157 158 159 160
    static void calib() {
        if (totalS && totalCy) {
            const char *s = "Cycle calibration";
            printf("%s:", s);
            if (strlen(s) < 25) printf("%*s",int(25-strlen(s)),"");
            printSI(totalCy / totalS, "Hz");
            printf("\n");
        }
    }
Mike Hamburg's avatar
Mike Hamburg committed
161 162
};

Mike Hamburg's avatar
Mike Hamburg committed
163 164
double Benchmark::totalCy = 0, Benchmark::totalS = 0;

165 166 167 168 169 170 171

template<typename Group> struct Benches {

typedef typename Group::Scalar Scalar;
typedef typename Group::Point Point;
typedef typename Group::Precomputed Precomputed;

172 173 174 175
static void cfrg() {
    SpongeRng rng(Block("bench_cfrg_crypto"),SpongeRng::DETERMINISTIC);
    FixedArrayBuffer<Group::DhLadder::PUBLIC_BYTES> base(rng);
    FixedArrayBuffer<Group::DhLadder::PRIVATE_BYTES> s1(rng);
176
    for (Benchmark b("RFC 7748 keygen"); b.iter(); ) { Group::DhLadder::derive_public_key(s1); }
177
    for (Benchmark b("RFC 7748 shared secret"); b.iter(); ) { Group::DhLadder::shared_secret(base,s1); }
Michael Hamburg's avatar
Michael Hamburg committed
178

179 180 181 182 183 184 185 186
    FixedArrayBuffer<EdDSA<Group>::PrivateKey::SER_BYTES> e1(rng);
    typename EdDSA<Group>::PublicKey pub((NOINIT()));
    typename EdDSA<Group>::PrivateKey priv((NOINIT()));
    SecureBuffer sig;
    for (Benchmark b("EdDSA keygen"); b.iter(); ) { priv = e1; }
    for (Benchmark b("EdDSA sign"); b.iter(); ) { sig = priv.sign(Block(NULL,0)); }
    pub = priv;
    for (Benchmark b("EdDSA verify"); b.iter(); ) { pub.verify(sig,Block(NULL,0)); }
187 188
}

189 190
static void macro() {
    printf("\nMacro-benchmarks for %s:\n", Group::name());
191 192
    printf("CFRG crypto benchmarks:\n");
    cfrg();
193 194 195
}

static void micro() {
196
    SpongeRng rng(Block("per-curve-benchmarks"),SpongeRng::DETERMINISTIC);
197 198
    Precomputed pBase;
    Point p,q;
199
    Scalar s(1),t(2);
200 201 202 203 204 205 206 207 208
    SecureBuffer ep, ep2(Point::SER_BYTES*2);
    
    printf("\nMicro-benchmarks for %s:\n", Group::name());
    for (Benchmark b("Scalar add", 1000); b.iter(); ) { s+=t; }
    for (Benchmark b("Scalar times", 100); b.iter(); ) { s*=t; }
    for (Benchmark b("Scalar inv", 1); b.iter(); ) { s.inverse(); }
    for (Benchmark b("Point add", 100); b.iter(); ) { p += q; }
    for (Benchmark b("Point double", 100); b.iter(); ) { p.double_in_place(); }
    for (Benchmark b("Point scalarmul"); b.iter(); ) { p * s; }
Michael Hamburg's avatar
Michael Hamburg committed
209
    for (Benchmark b("Point encode"); b.iter(); ) { ep = p.serialize(); }
210 211 212 213 214 215 216 217
    for (Benchmark b("Point decode"); b.iter(); ) { p = Point(ep); }
    for (Benchmark b("Point create/destroy"); b.iter(); ) { Point r; }
    for (Benchmark b("Point hash nonuniform"); b.iter(); ) { Point::from_hash(ep); }
    for (Benchmark b("Point hash uniform"); b.iter(); ) { Point::from_hash(ep2); }
    for (Benchmark b("Point unhash nonuniform"); b.iter(); ) { ignore_result(p.invert_elligator(ep,0)); }
    for (Benchmark b("Point unhash uniform"); b.iter(); ) { ignore_result(p.invert_elligator(ep2,0)); }
    for (Benchmark b("Point steg"); b.iter(); ) { p.steg_encode(rng); }
    for (Benchmark b("Point double scalarmul"); b.iter(); ) { Point::double_scalarmul(p,s,q,t); }
218
    for (Benchmark b("Point dual scalarmul"); b.iter(); ) { p.dual_scalarmul(p,q,s,t); }
219
    for (Benchmark b("Point precmp scalarmul"); b.iter(); ) { pBase * s; }
Michael Hamburg's avatar
Michael Hamburg committed
220
    for (Benchmark b("Point double scalarmul_v"); b.iter(); ) {
Michael Hamburg's avatar
Michael Hamburg committed
221
        s = Scalar(rng);
Michael Hamburg's avatar
Michael Hamburg committed
222 223 224
        t = Scalar(rng);
        p.non_secret_combo_with_base(s,t);
    }
225 226 227 228
}

}; /* template <typename group> struct Benches */

229 230 231
template <typename Group> struct Macro { static void run() { Benches<Group>::macro(); } };
template <typename Group> struct Micro { static void run() { Benches<Group>::micro(); } };

Mike Hamburg's avatar
Mike Hamburg committed
232
int main(int argc, char **argv) {
Michael Hamburg's avatar
Michael Hamburg committed
233
    
Mike Hamburg's avatar
Mike Hamburg committed
234 235 236
    bool micro = false;
    if (argc >= 2 && !strcmp(argv[1], "--micro"))
        micro = true;
237

238
    SpongeRng rng(Block("micro-benchmarks"),SpongeRng::DETERMINISTIC);
Mike Hamburg's avatar
Mike Hamburg committed
239
    if (micro) {
Mike Hamburg's avatar
Mike Hamburg committed
240
        printf("\nMicro-benchmarks:\n");
Mike Hamburg's avatar
Mike Hamburg committed
241 242 243
        SHAKE<128> shake1;
        SHAKE<256> shake2;
        SHA3<512> sha5;
244
        SHA512 sha2;
Mike Hamburg's avatar
Mike Hamburg committed
245
        unsigned char b1024[1024] = {1};
246 247 248
        for (Benchmark b("SHAKE128 1kiB", 30); b.iter(); ) { shake1 += Buffer(b1024,1024); }
        for (Benchmark b("SHAKE256 1kiB", 30); b.iter(); ) { shake2 += Buffer(b1024,1024); }
        for (Benchmark b("SHA3-512 1kiB", 30); b.iter(); ) { sha5 += Buffer(b1024,1024); }
249
        for (Benchmark b("SHA512 1kiB", 30); b.iter(); ) { sha2 += Buffer(b1024,1024); }
Michael Hamburg's avatar
Michael Hamburg committed
250
        
251
        run_for_all_curves<Micro>();
Mike Hamburg's avatar
Mike Hamburg committed
252
    }
253 254
    
    run_for_all_curves<Macro>();
Mike Hamburg's avatar
Mike Hamburg committed
255
    
Mike Hamburg's avatar
Mike Hamburg committed
256 257
    printf("\n");
    Benchmark::calib();
Mike Hamburg's avatar
Mike Hamburg committed
258 259 260 261
    printf("\n");
    
    return 0;
}