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.
 
 
 
 
 

372 lines
11 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 "shake.hxx"
  13. #include "shake.h"
  14. #include "decaf_crypto.h"
  15. #include <stdio.h>
  16. #include <sys/time.h>
  17. #include <assert.h>
  18. #include <stdint.h>
  19. using namespace decaf;
  20. typedef decaf<448>::Scalar Scalar;
  21. typedef decaf<448>::Point Point;
  22. typedef decaf<448>::Precomputed Precomputed;
  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 = 1000;
  63. static double totalCy, totalS;
  64. /* FIXME Tcy if get descheduled */
  65. public:
  66. int i, ntests;
  67. double begin;
  68. uint64_t tsc_begin;
  69. Benchmark(const char *s, double factor = 1) {
  70. printf("%s:", s);
  71. if (strlen(s) < 25) printf("%*s",int(25-strlen(s)),"");
  72. fflush(stdout);
  73. i = 0;
  74. ntests = NTESTS * factor;
  75. begin = now();
  76. tsc_begin = rdtsc();
  77. }
  78. ~Benchmark() {
  79. double tsc = (rdtsc() - tsc_begin) * 1.0;
  80. double t = (now() - begin);
  81. totalCy += tsc;
  82. totalS += t;
  83. t /= ntests;
  84. tsc /= ntests;
  85. printSI(t,"s");
  86. printf(" ");
  87. printSI(1/t,"/s");
  88. if (tsc) { printf(" "); printSI(tsc, "cy"); }
  89. printf("\n");
  90. }
  91. inline bool iter() { return i++ < ntests; }
  92. static void calib() {
  93. if (totalS && totalCy) {
  94. const char *s = "Cycle calibration";
  95. printf("%s:", s);
  96. if (strlen(s) < 25) printf("%*s",int(25-strlen(s)),"");
  97. printSI(totalCy / totalS, "Hz");
  98. printf("\n");
  99. }
  100. }
  101. };
  102. double Benchmark::totalCy = 0, Benchmark::totalS = 0;
  103. static void tdh (
  104. SpongeRng &clientRng,
  105. SpongeRng &serverRng,
  106. Scalar x, const Block &gx,
  107. Scalar y, const Block &gy
  108. ) {
  109. Strobe client(Strobe::CLIENT), server(Strobe::SERVER);
  110. Scalar xe(clientRng);
  111. SecureBuffer gxe = Precomputed::base() * xe;
  112. client.send_plaintext(gxe);
  113. server.recv_plaintext(gxe);
  114. Scalar ye(serverRng);
  115. SecureBuffer gye = Precomputed::base() * ye;
  116. server.send_plaintext(gye);
  117. client.recv_plaintext(gye);
  118. Point pgxe(gxe);
  119. server.key(pgxe*ye);
  120. SecureBuffer tag1 = server.produce_auth();
  121. SecureBuffer ct = server.encrypt(gy);
  122. server.key(pgxe*y);
  123. SecureBuffer tag2 = server.produce_auth();
  124. Point pgye(gye);
  125. client.key(pgye*xe);
  126. client.verify_auth(tag1);
  127. client.key(Point(client.decrypt(ct)) * xe);
  128. client.verify_auth(tag2);
  129. ct = client.encrypt(gx);
  130. client.key(pgye * x);
  131. tag1 = client.produce_auth();
  132. client.respec(STROBE_KEYED_128);
  133. server.key(Point(server.decrypt(ct)) * ye);
  134. server.verify_auth(tag1);
  135. server.respec(STROBE_KEYED_128);
  136. }
  137. static void fhmqv (
  138. SpongeRng &clientRng,
  139. SpongeRng &serverRng,
  140. Scalar x, const Block &gx,
  141. Scalar y, const Block &gy
  142. ) {
  143. /* Don't use this, it's probably patented */
  144. Strobe client(Strobe::CLIENT), server(Strobe::SERVER);
  145. Scalar xe(clientRng);
  146. client.send_plaintext(gx);
  147. server.recv_plaintext(gx);
  148. SecureBuffer gxe = Precomputed::base() * xe;
  149. server.send_plaintext(gxe);
  150. client.recv_plaintext(gxe);
  151. Scalar ye(serverRng);
  152. server.send_plaintext(gy);
  153. client.recv_plaintext(gy);
  154. SecureBuffer gye = Precomputed::base() * ye;
  155. server.send_plaintext(gye);
  156. Scalar schx(server.prng(Scalar::SER_BYTES));
  157. Scalar schy(server.prng(Scalar::SER_BYTES));
  158. Scalar yec = y + ye*schy;
  159. server.key(Point::double_scalarmul(Point(gx),yec,Point(gxe),yec*schx));
  160. SecureBuffer as = server.produce_auth();
  161. client.recv_plaintext(gye);
  162. Scalar cchx(client.prng(Scalar::SER_BYTES));
  163. Scalar cchy(client.prng(Scalar::SER_BYTES));
  164. Scalar xec = x + xe*schx;
  165. client.key(Point::double_scalarmul(Point(gy),xec,Point(gye),xec*schy));
  166. client.verify_auth(as);
  167. SecureBuffer ac = client.produce_auth();
  168. client.respec(STROBE_KEYED_128);
  169. server.verify_auth(ac);
  170. server.respec(STROBE_KEYED_128);
  171. }
  172. static void spake2ee(
  173. SpongeRng &clientRng,
  174. SpongeRng &serverRng,
  175. const Block &hashed_password,
  176. bool aug
  177. ) {
  178. Strobe client(Strobe::CLIENT), server(Strobe::SERVER);
  179. Scalar x(clientRng);
  180. SHAKE<256> shake;
  181. shake.update(hashed_password);
  182. SecureBuffer h0 = shake.output(Point::HASH_BYTES);
  183. SecureBuffer h1 = shake.output(Point::HASH_BYTES);
  184. SecureBuffer h2 = shake.output(Scalar::SER_BYTES);
  185. Scalar gs(h2);
  186. Point hc = Point::from_hash(h0);
  187. hc = Point::from_hash(h0); // double-count
  188. Point hs = Point::from_hash(h1);
  189. hs = Point::from_hash(h1); // double-count
  190. SecureBuffer gx(Precomputed::base() * x + hc);
  191. client.send_plaintext(gx);
  192. server.recv_plaintext(gx);
  193. Scalar y(serverRng);
  194. SecureBuffer gy(Precomputed::base() * y + hs);
  195. server.send_plaintext(gy);
  196. client.recv_plaintext(gy);
  197. server.key(h1);
  198. server.key((Point(gx) - hc)*y);
  199. if(aug) {
  200. /* This step isn't actually online but whatever, it's fastish */
  201. SecureBuffer serverAug(Precomputed::base() * gs);
  202. server.key(Point(serverAug)*y);
  203. }
  204. SecureBuffer tag = server.produce_auth();
  205. client.key(h1);
  206. Point pgy(gy); pgy -= hs;
  207. client.key(pgy*x);
  208. if (aug) client.key(pgy * gs);
  209. client.verify_auth(tag);
  210. tag = client.produce_auth();
  211. client.respec(STROBE_KEYED_128);
  212. /* TODO: fork... */
  213. server.verify_auth(tag);
  214. server.respec(STROBE_KEYED_128);
  215. }
  216. int main(int argc, char **argv) {
  217. bool micro = false;
  218. if (argc >= 2 && !strcmp(argv[1], "--micro"))
  219. micro = true;
  220. decaf_448_public_key_t p1,p2;
  221. decaf_448_private_key_t s1,s2;
  222. decaf_448_symmetric_key_t r1,r2;
  223. decaf_448_signature_t sig1;
  224. unsigned char ss[32];
  225. memset(r1,1,sizeof(r1));
  226. memset(r2,2,sizeof(r2));
  227. unsigned char umessage[] = {1,2,3,4,5};
  228. size_t lmessage = sizeof(umessage);
  229. if (micro) {
  230. Precomputed pBase;
  231. Point p,q;
  232. Scalar s,t;
  233. SecureBuffer ep, ep2(Point::SER_BYTES*2);
  234. printf("\nMicro-benchmarks:\n");
  235. SHAKE<128> shake1;
  236. SHAKE<256> shake2;
  237. SHA3<512> sha5;
  238. Strobe strobe(Strobe::CLIENT);
  239. unsigned char b1024[1024] = {1};
  240. for (Benchmark b("SHAKE128 1kiB", 30); b.iter(); ) { shake1 += TmpBuffer(b1024,1024); }
  241. for (Benchmark b("SHAKE256 1kiB", 30); b.iter(); ) { shake2 += TmpBuffer(b1024,1024); }
  242. for (Benchmark b("SHA3-512 1kiB", 30); b.iter(); ) { sha5 += TmpBuffer(b1024,1024); }
  243. strobe.key(TmpBuffer(b1024,1024));
  244. strobe.respec(STROBE_128);
  245. for (Benchmark b("STROBE128 1kiB", 10); b.iter(); ) {
  246. strobe.encrypt_no_auth(TmpBuffer(b1024,1024),TmpBuffer(b1024,1024),b.i>1);
  247. }
  248. strobe.respec(STROBE_256);
  249. for (Benchmark b("STROBE256 1kiB", 10); b.iter(); ) {
  250. strobe.encrypt_no_auth(TmpBuffer(b1024,1024),TmpBuffer(b1024,1024),b.i>1);
  251. }
  252. strobe.respec(STROBE_KEYED_128);
  253. for (Benchmark b("STROBEk128 1kiB", 10); b.iter(); ) {
  254. strobe.encrypt_no_auth(TmpBuffer(b1024,1024),TmpBuffer(b1024,1024),b.i>1);
  255. }
  256. strobe.respec(STROBE_KEYED_256);
  257. for (Benchmark b("STROBEk256 1kiB", 10); b.iter(); ) {
  258. strobe.encrypt_no_auth(TmpBuffer(b1024,1024),TmpBuffer(b1024,1024),b.i>1);
  259. }
  260. for (Benchmark b("Scalar add", 1000); b.iter(); ) { s+=t; }
  261. for (Benchmark b("Scalar times", 100); b.iter(); ) { s*=t; }
  262. for (Benchmark b("Scalar inv", 1); b.iter(); ) { s.inverse(); }
  263. for (Benchmark b("Point add", 100); b.iter(); ) { p += q; }
  264. for (Benchmark b("Point double", 100); b.iter(); ) { p.double_in_place(); }
  265. for (Benchmark b("Point scalarmul"); b.iter(); ) { p * s; }
  266. for (Benchmark b("Point encode"); b.iter(); ) { ep = SecureBuffer(p); }
  267. for (Benchmark b("Point decode"); b.iter(); ) { p = Point(ep); }
  268. for (Benchmark b("Point create/destroy"); b.iter(); ) { Point r; }
  269. for (Benchmark b("Point hash nonuniform"); b.iter(); ) { Point::from_hash(ep); }
  270. for (Benchmark b("Point hash uniform"); b.iter(); ) { Point::from_hash(ep2); }
  271. for (Benchmark b("Point double scalarmul"); b.iter(); ) { Point::double_scalarmul(p,s,q,t); }
  272. for (Benchmark b("Point precmp scalarmul"); b.iter(); ) { pBase * s; }
  273. /* TODO: scalarmul for verif, etc */
  274. }
  275. printf("\nMacro-benchmarks:\n");
  276. for (Benchmark b("Keygen"); b.iter(); ) {
  277. decaf_448_derive_private_key(s1,r1);
  278. }
  279. decaf_448_private_to_public(p1,s1);
  280. decaf_448_derive_private_key(s2,r2);
  281. decaf_448_private_to_public(p2,s2);
  282. for (Benchmark b("Shared secret"); b.iter(); ) {
  283. decaf_bool_t ret = decaf_448_shared_secret(ss,sizeof(ss),s1,p2);
  284. ignore_result(ret);
  285. assert(ret);
  286. }
  287. for (Benchmark b("Sign"); b.iter(); ) {
  288. decaf_448_sign(sig1,s1,umessage,lmessage);
  289. }
  290. for (Benchmark b("Verify"); b.iter(); ) {
  291. decaf_bool_t ret = decaf_448_verify(sig1,p1,umessage,lmessage);
  292. umessage[0]++;
  293. umessage[1]^=umessage[0];
  294. ignore_result(ret);
  295. }
  296. printf("\nProtocol benchmarks:\n");
  297. SpongeRng clientRng(Block("client rng seed"));
  298. SpongeRng serverRng(Block("server rng seed"));
  299. SecureBuffer hashedPassword("hello world");
  300. for (Benchmark b("Spake2ee c+s",0.1); b.iter(); ) {
  301. spake2ee(clientRng, serverRng, hashedPassword,false);
  302. }
  303. for (Benchmark b("Spake2ee c+s aug",0.1); b.iter(); ) {
  304. spake2ee(clientRng, serverRng, hashedPassword,true);
  305. }
  306. Scalar x(clientRng);
  307. SecureBuffer gx(Precomputed::base() * x);
  308. Scalar y(serverRng);
  309. SecureBuffer gy(Precomputed::base() * y);
  310. for (Benchmark b("FHMQV c+s",0.1); b.iter(); ) {
  311. fhmqv(clientRng, serverRng,x,gx,y,gy);
  312. }
  313. for (Benchmark b("TripleDH anon c+s",0.1); b.iter(); ) {
  314. tdh(clientRng, serverRng, x,gx,y,gy);
  315. }
  316. printf("\n");
  317. Benchmark::calib();
  318. printf("\n");
  319. return 0;
  320. }