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.
 
 
 
 
 

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