25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.
 
 
 
 
 

427 satır
13 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/crypto_255.h>
  14. #include <decaf/crypto_448.h>
  15. #include <decaf/crypto.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. u_int64_t out = 0;
  38. # if (defined(__i386__) || defined(__x86_64__))
  39. __asm__ __volatile__ ("rdtsc" : "=A"(out));
  40. # endif
  41. return out;
  42. }
  43. #endif
  44. static void printSI(double x, const char *unit, const char *spacer = " ") {
  45. const char *small[] = {" ","m","µ","n","p"};
  46. const char *big[] = {" ","k","M","G","T"};
  47. if (x < 1) {
  48. unsigned di=0;
  49. for (di=0; di<sizeof(small)/sizeof(*small)-1 && x && x < 1; di++) {
  50. x *= 1000.0;
  51. }
  52. printf("%6.2f%s%s%s", x, spacer, small[di], unit);
  53. } else {
  54. unsigned di=0;
  55. for (di=0; di<sizeof(big)/sizeof(*big)-1 && x && x >= 1000; di++) {
  56. x /= 1000.0;
  57. }
  58. printf("%6.2f%s%s%s", x, spacer, big[di], unit);
  59. }
  60. }
  61. class Benchmark {
  62. static const int NTESTS = 20, NSAMPLES=50, DISCARD=2;
  63. static double totalCy, totalS;
  64. public:
  65. int i, j, ntests, nsamples;
  66. double begin;
  67. uint64_t tsc_begin;
  68. std::vector<double> times;
  69. std::vector<uint64_t> cycles;
  70. Benchmark(const char *s, double factor = 1) {
  71. printf("%s:", s);
  72. if (strlen(s) < 25) printf("%*s",int(25-strlen(s)),"");
  73. fflush(stdout);
  74. i = j = 0;
  75. ntests = NTESTS * factor;
  76. nsamples = NSAMPLES;
  77. begin = now();
  78. tsc_begin = rdtsc();
  79. times = std::vector<double>(NSAMPLES);
  80. cycles = std::vector<uint64_t>(NSAMPLES);
  81. }
  82. ~Benchmark() {
  83. double tsc = 0;
  84. double t = 0;
  85. std::sort(times.begin(), times.end());
  86. std::sort(cycles.begin(), cycles.end());
  87. for (int k=DISCARD; k<nsamples-DISCARD; k++) {
  88. tsc += cycles[k];
  89. t += times[k];
  90. }
  91. totalCy += tsc;
  92. totalS += t;
  93. t /= ntests*(nsamples-2*DISCARD);
  94. tsc /= ntests*(nsamples-2*DISCARD);
  95. printSI(t,"s");
  96. printf(" ");
  97. printSI(1/t,"/s");
  98. if (tsc) { printf(" "); printSI(tsc, "cy"); }
  99. printf("\n");
  100. }
  101. inline bool iter() {
  102. i++;
  103. if (i >= ntests) {
  104. uint64_t tsc = rdtsc() - tsc_begin;
  105. double t = now() - begin;
  106. begin += t;
  107. tsc_begin += tsc;
  108. assert(j >= 0 && j < nsamples);
  109. cycles[j] = tsc;
  110. times[j] = t;
  111. j++;
  112. i = 0;
  113. }
  114. return j < nsamples;
  115. }
  116. static void calib() {
  117. if (totalS && totalCy) {
  118. const char *s = "Cycle calibration";
  119. printf("%s:", s);
  120. if (strlen(s) < 25) printf("%*s",int(25-strlen(s)),"");
  121. printSI(totalCy / totalS, "Hz");
  122. printf("\n");
  123. }
  124. }
  125. };
  126. double Benchmark::totalCy = 0, Benchmark::totalS = 0;
  127. template<typename Group> struct Benches {
  128. typedef typename Group::Scalar Scalar;
  129. typedef typename Group::Point Point;
  130. typedef typename Group::Precomputed Precomputed;
  131. static void tdh (
  132. SpongeRng &clientRng,
  133. SpongeRng &serverRng,
  134. Scalar x, const Block &gx,
  135. Scalar y, const Block &gy
  136. ) {
  137. /* "TripleDH". A bit of a hack, really: the real TripleDH
  138. * sends gx and gy and certs over the channel, but its goal
  139. * is actually the opposite of STROBE in this case: it doesn't
  140. * hash gx and gy into the session secret (only into the MAC
  141. * and AD) because of IPR concerns.
  142. */
  143. Strobe client("example::tripleDH",Strobe::CLIENT), server("example::tripleDH",Strobe::SERVER);
  144. Scalar xe(clientRng);
  145. SecureBuffer gxe((Precomputed::base() * xe).serialize());
  146. client.send_plaintext(gxe);
  147. server.recv_plaintext(gxe);
  148. Scalar ye(serverRng);
  149. SecureBuffer gye((Precomputed::base() * ye).serialize());
  150. server.send_plaintext(gye);
  151. client.recv_plaintext(gye);
  152. Point pgxe(gxe);
  153. server.dh_key(pgxe*ye);
  154. SecureBuffer tag1 = server.produce_auth();
  155. //SecureBuffer ct = server.encrypt(gy);
  156. server.dh_key(pgxe*y);
  157. SecureBuffer tag2 = server.produce_auth();
  158. Point pgye(gye);
  159. client.dh_key(pgye*xe);
  160. client.verify_auth(tag1);
  161. client.dh_key(Point(gy) * xe);
  162. client.verify_auth(tag2);
  163. // ct = client.encrypt(gx);
  164. client.dh_key(pgye * x);
  165. tag1 = client.produce_auth();
  166. client.respec(STROBE_KEYED_128);
  167. server.dh_key(Point(gx) * ye);
  168. server.verify_auth(tag1);
  169. server.respec(STROBE_KEYED_128);
  170. }
  171. static void fhmqv (
  172. SpongeRng &clientRng,
  173. SpongeRng &serverRng,
  174. Scalar x, const Block &gx,
  175. Scalar y, const Block &gy
  176. ) {
  177. /* Don't use this, it's probably patented */
  178. Strobe client("example::fhmqv",Strobe::CLIENT), server("example::fhmqv",Strobe::SERVER);
  179. Scalar xe(clientRng);
  180. client.send_plaintext(gx);
  181. server.recv_plaintext(gx);
  182. SecureBuffer gxe((Precomputed::base() * xe).serialize());
  183. server.send_plaintext(gxe);
  184. client.recv_plaintext(gxe);
  185. Scalar ye(serverRng);
  186. server.send_plaintext(gy);
  187. client.recv_plaintext(gy);
  188. SecureBuffer gye((Precomputed::base() * ye).serialize());
  189. server.send_plaintext(gye);
  190. Scalar schx(server.prng(Scalar::SER_BYTES));
  191. Scalar schy(server.prng(Scalar::SER_BYTES));
  192. Scalar yec = y + ye*schy;
  193. server.dh_key(Point::double_scalarmul(Point(gx),yec,Point(gxe),yec*schx));
  194. SecureBuffer as = server.produce_auth();
  195. client.recv_plaintext(gye);
  196. Scalar cchx(client.prng(Scalar::SER_BYTES));
  197. Scalar cchy(client.prng(Scalar::SER_BYTES));
  198. Scalar xec = x + xe*schx;
  199. client.dh_key(Point::double_scalarmul(Point(gy),xec,Point(gye),xec*schy));
  200. client.verify_auth(as);
  201. SecureBuffer ac = client.produce_auth();
  202. client.respec(STROBE_KEYED_128);
  203. server.verify_auth(ac);
  204. server.respec(STROBE_KEYED_128);
  205. }
  206. static void spake2ee(
  207. SpongeRng &clientRng,
  208. SpongeRng &serverRng,
  209. const Block &hashed_password,
  210. bool aug
  211. ) {
  212. Strobe client("example::spake2ee",Strobe::CLIENT), server("example::spake2ee",Strobe::SERVER);
  213. Scalar x(clientRng);
  214. SHAKE<256> shake;
  215. shake.update(hashed_password);
  216. SecureBuffer h0 = shake.output(Point::HASH_BYTES);
  217. SecureBuffer h1 = shake.output(Point::HASH_BYTES);
  218. SecureBuffer h2 = shake.output(Scalar::SER_BYTES);
  219. Scalar gs(h2);
  220. Point hc = Point::from_hash(h0);
  221. hc = Point::from_hash(h0); // double-count
  222. Point hs = Point::from_hash(h1);
  223. hs = Point::from_hash(h1); // double-count
  224. SecureBuffer gx((Precomputed::base() * x + hc).serialize());
  225. client.send_plaintext(gx);
  226. server.recv_plaintext(gx);
  227. Scalar y(serverRng);
  228. SecureBuffer gy((Precomputed::base() * y + hs).serialize());
  229. server.send_plaintext(gy);
  230. client.recv_plaintext(gy);
  231. server.dh_key(h1);
  232. server.dh_key((Point(gx) - hc)*y);
  233. if(aug) {
  234. /* This step isn't actually online but whatever, it's fastish */
  235. SecureBuffer serverAug((Precomputed::base() * gs).serialize());
  236. server.dh_key(Point(serverAug)*y);
  237. }
  238. SecureBuffer tag = server.produce_auth();
  239. client.dh_key(h1);
  240. Point pgy(gy); pgy -= hs;
  241. client.dh_key(pgy*x);
  242. if (aug) client.dh_key(pgy * gs);
  243. client.verify_auth(tag);
  244. tag = client.produce_auth();
  245. client.respec(STROBE_KEYED_128);
  246. /* A real protocol would continue with fork etc here... */
  247. server.verify_auth(tag);
  248. server.respec(STROBE_KEYED_128);
  249. }
  250. static void macro() {
  251. printf("\nMacro-benchmarks for %s:\n", Group::name());
  252. printf("Crypto benchmarks:\n");
  253. SpongeRng rng(Block("macro rng seed"));
  254. PrivateKey<Group> s1((NOINIT())), s2(rng);
  255. PublicKey<Group> p1((NOINIT())), p2(s2);
  256. SecureBuffer message = rng.read(5), sig, ss;
  257. for (Benchmark b("Create private key",1); b.iter(); ) {
  258. s1 = PrivateKey<Group>(rng);
  259. SecureBuffer bb = s1.serialize();
  260. }
  261. for (Benchmark b("Sign",1); b.iter(); ) {
  262. sig = s1.sign(message);
  263. }
  264. p1 = s1.pub();
  265. for (Benchmark b("Verify",1); b.iter(); ) {
  266. rng.read(Buffer(message));
  267. try { p1.verify(message, sig); } catch (CryptoException) {}
  268. }
  269. for (Benchmark b("SharedSecret",1); b.iter(); ) {
  270. ss = s1.sharedSecret(p2,32,true);
  271. }
  272. printf("\nProtocol benchmarks:\n");
  273. SpongeRng clientRng(Block("client rng seed"));
  274. SpongeRng serverRng(Block("server rng seed"));
  275. SecureBuffer hashedPassword(Block("hello world"));
  276. for (Benchmark b("Spake2ee c+s",0.1); b.iter(); ) {
  277. spake2ee(clientRng, serverRng, hashedPassword,false);
  278. }
  279. for (Benchmark b("Spake2ee c+s aug",0.1); b.iter(); ) {
  280. spake2ee(clientRng, serverRng, hashedPassword,true);
  281. }
  282. Scalar x(clientRng);
  283. SecureBuffer gx((Precomputed::base() * x).serialize());
  284. Scalar y(serverRng);
  285. SecureBuffer gy((Precomputed::base() * y).serialize());
  286. for (Benchmark b("FHMQV c+s",0.1); b.iter(); ) {
  287. fhmqv(clientRng, serverRng,x,gx,y,gy);
  288. }
  289. for (Benchmark b("TripleDH anon c+s",0.1); b.iter(); ) {
  290. tdh(clientRng, serverRng, x,gx,y,gy);
  291. }
  292. }
  293. static void micro() {
  294. SpongeRng rng(Block("per-curve-benchmarks"));
  295. Precomputed pBase;
  296. Point p,q;
  297. Scalar s(1),t(2);
  298. SecureBuffer ep, ep2(Point::SER_BYTES*2);
  299. printf("\nMicro-benchmarks for %s:\n", Group::name());
  300. for (Benchmark b("Scalar add", 1000); b.iter(); ) { s+=t; }
  301. for (Benchmark b("Scalar times", 100); b.iter(); ) { s*=t; }
  302. for (Benchmark b("Scalar inv", 1); b.iter(); ) { s.inverse(); }
  303. for (Benchmark b("Point add", 100); b.iter(); ) { p += q; }
  304. for (Benchmark b("Point double", 100); b.iter(); ) { p.double_in_place(); }
  305. for (Benchmark b("Point scalarmul"); b.iter(); ) { p * s; }
  306. for (Benchmark b("Point encode"); b.iter(); ) { ep = p.serialize(); }
  307. for (Benchmark b("Point decode"); b.iter(); ) { p = Point(ep); }
  308. for (Benchmark b("Point create/destroy"); b.iter(); ) { Point r; }
  309. for (Benchmark b("Point hash nonuniform"); b.iter(); ) { Point::from_hash(ep); }
  310. for (Benchmark b("Point hash uniform"); b.iter(); ) { Point::from_hash(ep2); }
  311. for (Benchmark b("Point unhash nonuniform"); b.iter(); ) { ignore_result(p.invert_elligator(ep,0)); }
  312. for (Benchmark b("Point unhash uniform"); b.iter(); ) { ignore_result(p.invert_elligator(ep2,0)); }
  313. for (Benchmark b("Point steg"); b.iter(); ) { p.steg_encode(rng); }
  314. for (Benchmark b("Point double scalarmul"); b.iter(); ) { Point::double_scalarmul(p,s,q,t); }
  315. for (Benchmark b("Point dual scalarmul"); b.iter(); ) { p.dual_scalarmul(p,q,s,t); }
  316. for (Benchmark b("Point precmp scalarmul"); b.iter(); ) { pBase * s; }
  317. for (Benchmark b("Point double scalarmul_v"); b.iter(); ) {
  318. s = Scalar(rng);
  319. t = Scalar(rng);
  320. p.non_secret_combo_with_base(s,t);
  321. }
  322. }
  323. }; /* template <typename group> struct Benches */
  324. int main(int argc, char **argv) {
  325. bool micro = false;
  326. if (argc >= 2 && !strcmp(argv[1], "--micro"))
  327. micro = true;
  328. SpongeRng rng(Block("micro-benchmarks"));
  329. if (micro) {
  330. printf("\nMicro-benchmarks:\n");
  331. SHAKE<128> shake1;
  332. SHAKE<256> shake2;
  333. SHA3<512> sha5;
  334. Strobe strobe("example::bench",Strobe::CLIENT);
  335. unsigned char b1024[1024] = {1};
  336. for (Benchmark b("SHAKE128 1kiB", 30); b.iter(); ) { shake1 += Buffer(b1024,1024); }
  337. for (Benchmark b("SHAKE256 1kiB", 30); b.iter(); ) { shake2 += Buffer(b1024,1024); }
  338. for (Benchmark b("SHA3-512 1kiB", 30); b.iter(); ) { sha5 += Buffer(b1024,1024); }
  339. strobe.dh_key(Buffer(b1024,1024));
  340. strobe.respec(STROBE_128);
  341. for (Benchmark b("STROBE128 1kiB", 10); b.iter(); ) {
  342. strobe.encrypt_no_auth(Buffer(b1024,1024),Buffer(b1024,1024));
  343. }
  344. strobe.respec(STROBE_256);
  345. for (Benchmark b("STROBE256 1kiB", 10); b.iter(); ) {
  346. strobe.encrypt_no_auth(Buffer(b1024,1024),Buffer(b1024,1024));
  347. }
  348. strobe.respec(STROBE_KEYED_128);
  349. for (Benchmark b("STROBEk128 1kiB", 10); b.iter(); ) {
  350. strobe.encrypt_no_auth(Buffer(b1024,1024),Buffer(b1024,1024));
  351. }
  352. strobe.respec(STROBE_KEYED_256);
  353. for (Benchmark b("STROBEk256 1kiB", 10); b.iter(); ) {
  354. strobe.encrypt_no_auth(Buffer(b1024,1024),Buffer(b1024,1024));
  355. }
  356. Benches<IsoEd25519>::micro();
  357. Benches<Ed448Goldilocks>::micro();
  358. }
  359. Benches<IsoEd25519>::macro();
  360. Benches<Ed448Goldilocks>::macro();
  361. printf("\n");
  362. Benchmark::calib();
  363. printf("\n");
  364. return 0;
  365. }