test.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. /*
  2. Validate ed25519 implementation against the official test vectors from
  3. http://ed25519.cr.yp.to/software.html
  4. */
  5. #include <stdio.h>
  6. #include <string.h>
  7. #include "ed25519.h"
  8. #include "test-ticks.h"
  9. static void
  10. edassert(int check, int round, const char *failreason) {
  11. if (check)
  12. return;
  13. printf("round %d, %s\n", round, failreason);
  14. exit(1);
  15. }
  16. static void
  17. edassert_die(const unsigned char *a, const unsigned char *b, size_t len, int round, const char *failreason) {
  18. size_t i;
  19. if (round > 0)
  20. printf("round %d, %s\n", round, failreason);
  21. else
  22. printf("%s\n", failreason);
  23. printf("want: "); for (i = 0; i < len; i++) printf("%02x,", a[i]); printf("\n");
  24. printf("got : "); for (i = 0; i < len; i++) printf("%02x,", b[i]); printf("\n");
  25. printf("diff: "); for (i = 0; i < len; i++) if (a[i] ^ b[i]) printf("%02x,", a[i] ^ b[i]); else printf(" ,"); printf("\n\n");
  26. exit(1);
  27. }
  28. static void
  29. edassert_equal(const unsigned char *a, const unsigned char *b, size_t len, const char *failreason) {
  30. if (memcmp(a, b, len) == 0)
  31. return;
  32. edassert_die(a, b, len, -1, failreason);
  33. }
  34. static void
  35. edassert_equal_round(const unsigned char *a, const unsigned char *b, size_t len, int round, const char *failreason) {
  36. if (memcmp(a, b, len) == 0)
  37. return;
  38. edassert_die(a, b, len, round, failreason);
  39. }
  40. /* test data */
  41. typedef struct test_data_t {
  42. unsigned char sk[32], pk[32], sig[64];
  43. const char *m;
  44. } test_data;
  45. test_data dataset[] = {
  46. #include "regression.h"
  47. };
  48. /* result of the curve25519 scalarmult ((|255| * basepoint) * basepoint)... 1024 times */
  49. const curved25519_key curved25519_expected = {
  50. 0xac,0xce,0x24,0xb1,0xd4,0xa2,0x36,0x21,
  51. 0x15,0xe2,0x3e,0x84,0x3c,0x23,0x2b,0x5f,
  52. 0x95,0x6c,0xc0,0x7b,0x95,0x82,0xd7,0x93,
  53. 0xd5,0x19,0xb6,0xf1,0xfb,0x96,0xd6,0x04
  54. };
  55. /* from ed25519-donna-batchverify.h */
  56. extern unsigned char batch_point_buffer[3][32];
  57. /* y coordinate of the final point from 'amd64-51-30k' with the same random generator */
  58. static const unsigned char batch_verify_y[32] = {
  59. 0x51,0xe7,0x68,0xe0,0xf7,0xa1,0x88,0x45,
  60. 0xde,0xa1,0xcb,0xd9,0x37,0xd4,0x78,0x53,
  61. 0x1b,0x95,0xdb,0xbe,0x66,0x59,0x29,0x3b,
  62. 0x94,0x51,0x2f,0xbc,0x0d,0x66,0xba,0x3f
  63. };
  64. /*
  65. static const unsigned char batch_verify_y[32] = {
  66. 0x5c,0x63,0x96,0x26,0xca,0xfe,0xfd,0xc4,
  67. 0x2d,0x11,0xa8,0xe4,0xc4,0x46,0x42,0x97,
  68. 0x97,0x92,0xbe,0xe0,0x3c,0xef,0x96,0x01,
  69. 0x50,0xa1,0xcc,0x8f,0x50,0x85,0x76,0x7d
  70. };
  71. Introducing the 128 bit r scalars to the heap _before_ the largest scalar
  72. fits in to 128 bits alters the heap shape and produces a different,
  73. yet still neutral/valid y/z value.
  74. This was the value of introducing the r scalars when the largest scalar fit
  75. in to 135-256 bits. You can produce it with amd64-64-24k / amd64-51-32k
  76. with the random sequence used in the first pass by changing
  77. unsigned long long hlen=((npoints+1)/2)|1;
  78. to
  79. unsigned long long hlen=npoints;
  80. in ge25519_multi_scalarmult.c
  81. ed25519-donna-batchverify.h has been modified to match the
  82. default amd64-64-24k / amd64-51-32k behaviour
  83. */
  84. /* batch test */
  85. #define test_batch_count 64
  86. #define test_batch_rounds 96
  87. typedef enum batch_test_t {
  88. batch_no_errors = 0,
  89. batch_wrong_message = 1,
  90. batch_wrong_pk = 2,
  91. batch_wrong_sig = 3
  92. } batch_test;
  93. static int
  94. test_batch_instance(batch_test type, uint64_t *ticks) {
  95. ed25519_secret_key sks[test_batch_count];
  96. ed25519_public_key pks[test_batch_count];
  97. ed25519_signature sigs[test_batch_count];
  98. unsigned char messages[test_batch_count][128];
  99. size_t message_lengths[test_batch_count];
  100. const unsigned char *message_pointers[test_batch_count];
  101. const unsigned char *pk_pointers[test_batch_count];
  102. const unsigned char *sig_pointers[test_batch_count];
  103. int valid[test_batch_count], ret, validret;
  104. size_t i;
  105. uint64_t t;
  106. /* generate keys */
  107. for (i = 0; i < test_batch_count; i++) {
  108. ed25519_randombytes_unsafe(sks[i], sizeof(sks[i]));
  109. ed25519_publickey(sks[i], pks[i]);
  110. pk_pointers[i] = pks[i];
  111. }
  112. /* generate messages */
  113. ed25519_randombytes_unsafe(messages, sizeof(messages));
  114. for (i = 0; i < test_batch_count; i++) {
  115. message_pointers[i] = messages[i];
  116. message_lengths[i] = (i & 127) + 1;
  117. }
  118. /* sign messages */
  119. for (i = 0; i < test_batch_count; i++) {
  120. ed25519_sign(message_pointers[i], message_lengths[i], sks[i], pks[i], sigs[i]);
  121. sig_pointers[i] = sigs[i];
  122. }
  123. validret = 0;
  124. if (type == batch_wrong_message) {
  125. message_pointers[0] = message_pointers[1];
  126. validret = 1|2;
  127. } else if (type == batch_wrong_pk) {
  128. pk_pointers[0] = pk_pointers[1];
  129. validret = 1|2;
  130. } else if (type == batch_wrong_sig) {
  131. sig_pointers[0] = sig_pointers[1];
  132. validret = 1|2;
  133. }
  134. /* batch verify */
  135. t = get_ticks();
  136. ret = ed25519_sign_open_batch(message_pointers, message_lengths, pk_pointers, sig_pointers, test_batch_count, valid);
  137. *ticks = get_ticks() - t;
  138. edassert_equal((unsigned char *)&validret, (unsigned char *)&ret, sizeof(int), "batch return code");
  139. for (i = 0; i < test_batch_count; i++) {
  140. validret = ((type == batch_no_errors) || (i != 0)) ? 1 : 0;
  141. edassert_equal((unsigned char *)&validret, (unsigned char *)&valid[i], sizeof(int), "individual batch return code");
  142. }
  143. return ret;
  144. }
  145. static void
  146. test_batch(void) {
  147. uint64_t dummy_ticks, ticks[test_batch_rounds], best = maxticks, sum;
  148. size_t i, count;
  149. /* check the first pass for the expected result */
  150. test_batch_instance(batch_no_errors, &dummy_ticks);
  151. edassert_equal(batch_verify_y, batch_point_buffer[1], 32, "failed to generate expected result");
  152. /* make sure ge25519_multi_scalarmult_vartime throws an error on the entire batch with wrong data */
  153. for (i = 0; i < 4; i++) {
  154. test_batch_instance(batch_wrong_message, &dummy_ticks);
  155. test_batch_instance(batch_wrong_pk, &dummy_ticks);
  156. test_batch_instance(batch_wrong_sig, &dummy_ticks);
  157. }
  158. /* speed test */
  159. for (i = 0; i < test_batch_rounds; i++) {
  160. test_batch_instance(batch_no_errors, &ticks[i]);
  161. if (ticks[i] < best)
  162. best = ticks[i];
  163. }
  164. /* take anything within 1% of the best time */
  165. for (i = 0, sum = 0, count = 0; i < test_batch_rounds; i++) {
  166. if (ticks[i] < (best * 1.01)) {
  167. sum += ticks[i];
  168. count++;
  169. }
  170. }
  171. printf("%.0f ticks/verification\n", (double)sum / (count * test_batch_count));
  172. }
  173. static void
  174. test_main(void) {
  175. int i, res;
  176. ed25519_public_key pk;
  177. ed25519_signature sig;
  178. unsigned char forge[1024] = {'x'};
  179. curved25519_key csk[2] = {{255}};
  180. uint64_t ticks, pkticks = maxticks, signticks = maxticks, openticks = maxticks, curvedticks = maxticks;
  181. for (i = 0; i < 1024; i++) {
  182. ed25519_publickey(dataset[i].sk, pk);
  183. edassert_equal_round(dataset[i].pk, pk, sizeof(pk), i, "public key didn't match");
  184. ed25519_sign((unsigned char *)dataset[i].m, i, dataset[i].sk, pk, sig);
  185. edassert_equal_round(dataset[i].sig, sig, sizeof(sig), i, "signature didn't match");
  186. edassert(!ed25519_sign_open((unsigned char *)dataset[i].m, i, pk, sig), i, "failed to open message");
  187. memcpy(forge, dataset[i].m, i);
  188. if (i)
  189. forge[i - 1] += 1;
  190. edassert(ed25519_sign_open(forge, (i) ? i : 1, pk, sig), i, "opened forged message");
  191. }
  192. for (i = 0; i < 1024; i++)
  193. curved25519_scalarmult_basepoint(csk[(i & 1) ^ 1], csk[i & 1]);
  194. edassert_equal(curved25519_expected, csk[0], sizeof(curved25519_key), "curve25519 failed to generate correct value");
  195. for (i = 0; i < 2048; i++) {
  196. timeit(ed25519_publickey(dataset[0].sk, pk), pkticks)
  197. edassert_equal_round(dataset[0].pk, pk, sizeof(pk), i, "public key didn't match");
  198. timeit(ed25519_sign((unsigned char *)dataset[0].m, 0, dataset[0].sk, pk, sig), signticks)
  199. edassert_equal_round(dataset[0].sig, sig, sizeof(sig), i, "signature didn't match");
  200. timeit(res = ed25519_sign_open((unsigned char *)dataset[0].m, 0, pk, sig), openticks)
  201. edassert(!res, 0, "failed to open message");
  202. timeit(curved25519_scalarmult_basepoint(csk[1], csk[0]), curvedticks);
  203. }
  204. printf("%.0f ticks/public key generation\n", (double)pkticks);
  205. printf("%.0f ticks/signature\n", (double)signticks);
  206. printf("%.0f ticks/signature verification\n", (double)openticks);
  207. printf("%.0f ticks/curve25519 basepoint scalarmult\n", (double)curvedticks);
  208. }
  209. int
  210. main(void) {
  211. test_main();
  212. test_batch();
  213. return 0;
  214. }