You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

245 lines
7.9 KiB

  1. /**
  2. * @file test_decaf.cxx
  3. * @author Mike Hamburg
  4. *
  5. * @copyright
  6. * Copyright (c) 2015 Cryptography Research, Inc. \n
  7. * Released under the MIT License. See LICENSE.txt for license information.
  8. *
  9. * @brief C++ benchmarks, because that's easier.
  10. */
  11. #include <decaf.hxx>
  12. #include <decaf/shake.hxx>
  13. #include <decaf/sha512.hxx>
  14. #include <decaf/spongerng.hxx>
  15. #include <decaf/eddsa.hxx>
  16. #include <stdio.h>
  17. #include <sys/time.h>
  18. #include <assert.h>
  19. #include <stdint.h>
  20. #include <vector>
  21. #include <algorithm>
  22. using namespace decaf;
  23. static __inline__ void __attribute__((unused)) ignore_result ( int result ) { (void)result; }
  24. static double now(void) {
  25. struct timeval tv;
  26. gettimeofday(&tv, NULL);
  27. return tv.tv_sec + tv.tv_usec/1000000.0;
  28. }
  29. // RDTSC from the chacha code
  30. #ifndef __has_builtin
  31. #define __has_builtin(X) 0
  32. #endif
  33. #if defined(__clang__) && __has_builtin(__builtin_readcyclecounter)
  34. #define rdtsc __builtin_readcyclecounter
  35. #else
  36. static inline uint64_t rdtsc(void) {
  37. # if defined(__x86_64__)
  38. uint32_t lobits, hibits;
  39. __asm__ __volatile__ ("rdtsc" : "=a"(lobits), "=d"(hibits));
  40. return (lobits | ((uint64_t)(hibits) << 32));
  41. # elif defined(__i386__)
  42. uint64_t __value;
  43. __asm__ __volatile__ ("rdtsc" : "=A"(__value));
  44. return __value;
  45. # else
  46. return 0;
  47. # endif
  48. }
  49. #endif
  50. static void printSI(double x, const char *unit, const char *spacer = " ") {
  51. const char *small[] = {" ","m","ยต","n","p"};
  52. const char *big[] = {" ","k","M","G","T"};
  53. if (x < 1) {
  54. unsigned di=0;
  55. for (di=0; di<sizeof(small)/sizeof(*small)-1 && x && x < 1; di++) {
  56. x *= 1000.0;
  57. }
  58. printf("%6.2f%s%s%s", x, spacer, small[di], unit);
  59. } else {
  60. unsigned di=0;
  61. for (di=0; di<sizeof(big)/sizeof(*big)-1 && x && x >= 1000; di++) {
  62. x /= 1000.0;
  63. }
  64. printf("%6.2f%s%s%s", x, spacer, big[di], unit);
  65. }
  66. }
  67. class Benchmark {
  68. static const int NTESTS = 20, NSAMPLES=50, DISCARD=2;
  69. static double totalCy, totalS;
  70. public:
  71. int i, j, ntests, nsamples;
  72. double begin;
  73. uint64_t tsc_begin;
  74. std::vector<double> times;
  75. std::vector<uint64_t> cycles;
  76. Benchmark(const char *s, double factor = 1) {
  77. printf("%s:", s);
  78. if (strlen(s) < 25) printf("%*s",int(25-strlen(s)),"");
  79. fflush(stdout);
  80. i = j = 0;
  81. ntests = NTESTS * factor;
  82. nsamples = NSAMPLES;
  83. begin = now();
  84. tsc_begin = rdtsc();
  85. times = std::vector<double>(NSAMPLES);
  86. cycles = std::vector<uint64_t>(NSAMPLES);
  87. }
  88. ~Benchmark() {
  89. double tsc = 0;
  90. double t = 0;
  91. std::sort(times.begin(), times.end());
  92. std::sort(cycles.begin(), cycles.end());
  93. for (int k=DISCARD; k<nsamples-DISCARD; k++) {
  94. tsc += cycles[k];
  95. t += times[k];
  96. }
  97. totalCy += tsc;
  98. totalS += t;
  99. t /= ntests*(nsamples-2*DISCARD);
  100. tsc /= ntests*(nsamples-2*DISCARD);
  101. printSI(t,"s");
  102. printf(" ");
  103. printSI(1/t,"/s");
  104. if (tsc) { printf(" "); printSI(tsc, "cy"); }
  105. printf("\n");
  106. }
  107. inline bool iter() {
  108. i++;
  109. if (i >= ntests) {
  110. uint64_t tsc = rdtsc() - tsc_begin;
  111. double t = now() - begin;
  112. begin += t;
  113. tsc_begin += tsc;
  114. assert(j >= 0 && j < nsamples);
  115. cycles[j] = tsc;
  116. times[j] = t;
  117. j++;
  118. i = 0;
  119. }
  120. return j < nsamples;
  121. }
  122. static void calib() {
  123. if (totalS && totalCy) {
  124. const char *s = "Cycle calibration";
  125. printf("%s:", s);
  126. if (strlen(s) < 25) printf("%*s",int(25-strlen(s)),"");
  127. printSI(totalCy / totalS, "Hz");
  128. printf("\n");
  129. }
  130. }
  131. };
  132. double Benchmark::totalCy = 0, Benchmark::totalS = 0;
  133. template<typename Group> struct Benches {
  134. typedef typename Group::Scalar Scalar;
  135. typedef typename Group::Point Point;
  136. typedef typename Group::Precomputed Precomputed;
  137. static void cfrg() {
  138. SpongeRng rng(Block("bench_cfrg_crypto"),SpongeRng::DETERMINISTIC);
  139. FixedArrayBuffer<Group::DhLadder::PUBLIC_BYTES> base(rng);
  140. FixedArrayBuffer<Group::DhLadder::PRIVATE_BYTES> s1(rng);
  141. for (Benchmark b("RFC 7748 keygen"); b.iter(); ) { Group::DhLadder::derive_public_key(s1); }
  142. for (Benchmark b("RFC 7748 shared secret"); b.iter(); ) { Group::DhLadder::shared_secret(base,s1); }
  143. FixedArrayBuffer<EdDSA<Group>::PrivateKey::SER_BYTES> e1(rng);
  144. typename EdDSA<Group>::PublicKey pub((NOINIT()));
  145. typename EdDSA<Group>::PrivateKey priv((NOINIT()));
  146. SecureBuffer sig;
  147. for (Benchmark b("EdDSA keygen"); b.iter(); ) { priv = e1; }
  148. for (Benchmark b("EdDSA sign"); b.iter(); ) { sig = priv.sign(Block(NULL,0)); }
  149. pub = priv;
  150. for (Benchmark b("EdDSA verify"); b.iter(); ) { pub.verify(sig,Block(NULL,0)); }
  151. }
  152. static void macro() {
  153. printf("\nMacro-benchmarks for %s:\n", Group::name());
  154. printf("CFRG crypto benchmarks:\n");
  155. cfrg();
  156. }
  157. static void micro() {
  158. SpongeRng rng(Block("per-curve-benchmarks"),SpongeRng::DETERMINISTIC);
  159. Precomputed pBase;
  160. Point p,q;
  161. Scalar s(1),t(2);
  162. SecureBuffer ep, ep2(Point::SER_BYTES*2);
  163. printf("\nMicro-benchmarks for %s:\n", Group::name());
  164. for (Benchmark b("Scalar add", 1000); b.iter(); ) { s+=t; }
  165. for (Benchmark b("Scalar times", 100); b.iter(); ) { s*=t; }
  166. for (Benchmark b("Scalar inv", 1); b.iter(); ) { s.inverse(); }
  167. for (Benchmark b("Point add", 100); b.iter(); ) { p += q; }
  168. for (Benchmark b("Point double", 100); b.iter(); ) { p.double_in_place(); }
  169. for (Benchmark b("Point scalarmul"); b.iter(); ) { p * s; }
  170. for (Benchmark b("Point encode"); b.iter(); ) { ep = p.serialize(); }
  171. for (Benchmark b("Point decode"); b.iter(); ) { p = Point(ep); }
  172. for (Benchmark b("Point create/destroy"); b.iter(); ) { Point r; }
  173. for (Benchmark b("Point hash nonuniform"); b.iter(); ) { Point::from_hash(ep); }
  174. for (Benchmark b("Point hash uniform"); b.iter(); ) { Point::from_hash(ep2); }
  175. for (Benchmark b("Point unhash nonuniform"); b.iter(); ) { ignore_result(p.invert_elligator(ep,0)); }
  176. for (Benchmark b("Point unhash uniform"); b.iter(); ) { ignore_result(p.invert_elligator(ep2,0)); }
  177. for (Benchmark b("Point steg"); b.iter(); ) { p.steg_encode(rng); }
  178. for (Benchmark b("Point double scalarmul"); b.iter(); ) { Point::double_scalarmul(p,s,q,t); }
  179. for (Benchmark b("Point dual scalarmul"); b.iter(); ) { p.dual_scalarmul(p,q,s,t); }
  180. for (Benchmark b("Point precmp scalarmul"); b.iter(); ) { pBase * s; }
  181. for (Benchmark b("Point double scalarmul_v"); b.iter(); ) {
  182. s = Scalar(rng);
  183. t = Scalar(rng);
  184. p.non_secret_combo_with_base(s,t);
  185. }
  186. }
  187. }; /* template <typename group> struct Benches */
  188. template <typename Group> struct Macro { static void run() { Benches<Group>::macro(); } };
  189. template <typename Group> struct Micro { static void run() { Benches<Group>::micro(); } };
  190. int main(int argc, char **argv) {
  191. bool micro = false;
  192. if (argc >= 2 && !strcmp(argv[1], "--micro"))
  193. micro = true;
  194. SpongeRng rng(Block("micro-benchmarks"),SpongeRng::DETERMINISTIC);
  195. if (micro) {
  196. printf("\nMicro-benchmarks:\n");
  197. SHAKE<128> shake1;
  198. SHAKE<256> shake2;
  199. SHA3<512> sha5;
  200. SHA512 sha2;
  201. unsigned char b1024[1024] = {1};
  202. for (Benchmark b("SHAKE128 1kiB", 30); b.iter(); ) { shake1 += Buffer(b1024,1024); }
  203. for (Benchmark b("SHAKE256 1kiB", 30); b.iter(); ) { shake2 += Buffer(b1024,1024); }
  204. for (Benchmark b("SHA3-512 1kiB", 30); b.iter(); ) { sha5 += Buffer(b1024,1024); }
  205. for (Benchmark b("SHA512 1kiB", 30); b.iter(); ) { sha2 += Buffer(b1024,1024); }
  206. run_for_all_curves<Micro>();
  207. }
  208. run_for_all_curves<Macro>();
  209. printf("\n");
  210. Benchmark::calib();
  211. printf("\n");
  212. return 0;
  213. }