Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 
 
 

491 строка
16 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++ tests, because that's easier.
  10. */
  11. #include <decaf.hxx>
  12. #include <decaf/spongerng.hxx>
  13. #include <decaf/crypto.h>
  14. #include <decaf/crypto.hxx>
  15. #include <stdio.h>
  16. using namespace decaf;
  17. static bool passing = true;
  18. static const long NTESTS = 10000;
  19. class Test {
  20. public:
  21. bool passing_now;
  22. Test(const char *test) {
  23. passing_now = true;
  24. printf("%s...", test);
  25. if (strlen(test) < 27) printf("%*s",int(27-strlen(test)),"");
  26. fflush(stdout);
  27. }
  28. ~Test() {
  29. if (std::uncaught_exception()) {
  30. fail();
  31. printf(" due to uncaught exception.\n");
  32. }
  33. if (passing_now) printf("[PASS]\n");
  34. }
  35. void fail() {
  36. if (!passing_now) return;
  37. passing_now = passing = false;
  38. printf("[FAIL]\n");
  39. }
  40. };
  41. template<typename Group> struct Tests {
  42. typedef typename Group::Scalar Scalar;
  43. typedef typename Group::Point Point;
  44. typedef typename Group::DhLadder DhLadder;
  45. typedef typename Group::Precomputed Precomputed;
  46. static void print(const char *name, const Scalar &x) {
  47. unsigned char buffer[Scalar::SER_BYTES];
  48. x.serialize_into(buffer);
  49. printf(" %s = 0x", name);
  50. for (int i=sizeof(buffer)-1; i>=0; i--) {
  51. printf("%02x", buffer[i]);
  52. }
  53. printf("\n");
  54. }
  55. static void hexprint(const char *name, const SecureBuffer &buffer) {
  56. printf(" %s = 0x", name);
  57. for (int i=buffer.size()-1; i>=0; i--) {
  58. printf("%02x", buffer[i]);
  59. }
  60. printf("\n");
  61. }
  62. static void print(const char *name, const Point &x) {
  63. unsigned char buffer[Point::SER_BYTES];
  64. x.serialize_into(buffer);
  65. printf(" %s = 0x", name);
  66. for (int i=Point::SER_BYTES-1; i>=0; i--) {
  67. printf("%02x", buffer[i]);
  68. }
  69. printf("\n");
  70. }
  71. static bool arith_check(
  72. Test &test,
  73. const Scalar &x,
  74. const Scalar &y,
  75. const Scalar &z,
  76. const Scalar &l,
  77. const Scalar &r,
  78. const char *name
  79. ) {
  80. if (l == r) return true;
  81. test.fail();
  82. printf(" %s", name);
  83. print("x", x);
  84. print("y", y);
  85. print("z", z);
  86. print("lhs", l);
  87. print("rhs", r);
  88. return false;
  89. }
  90. static bool point_check(
  91. Test &test,
  92. const Point &p,
  93. const Point &q,
  94. const Point &R,
  95. const Scalar &x,
  96. const Scalar &y,
  97. const Point &l,
  98. const Point &r,
  99. const char *name
  100. ) {
  101. bool good = l==r;
  102. if (!p.validate()) { good = false; printf(" p invalid\n"); }
  103. if (!q.validate()) { good = false; printf(" q invalid\n"); }
  104. if (!r.validate()) { good = false; printf(" r invalid\n"); }
  105. if (!l.validate()) { good = false; printf(" l invalid\n"); }
  106. if (good) return true;
  107. test.fail();
  108. printf(" %s", name);
  109. print("x", x);
  110. print("y", y);
  111. print("p", p);
  112. print("q", q);
  113. print("r", R);
  114. print("lhs", r);
  115. print("rhs", l);
  116. return false;
  117. }
  118. static void test_arithmetic() {
  119. SpongeRng rng(Block("test_arithmetic"),SpongeRng::DETERMINISTIC);
  120. Test test("Arithmetic");
  121. Scalar x(0),y(0),z(0);
  122. arith_check(test,x,y,z,INT_MAX,(decaf_word_t)INT_MAX,"cast from max");
  123. arith_check(test,x,y,z,INT_MIN,-Scalar(1+(decaf_word_t)INT_MAX),"cast from min");
  124. for (int i=0; i<NTESTS*10 && test.passing_now; i++) {
  125. /* TODO: pathological cases */
  126. size_t sob = DECAF_255_SCALAR_BYTES + 8 - (i%16);
  127. Scalar x(rng.read(sob));
  128. Scalar y(rng.read(sob));
  129. Scalar z(rng.read(sob));
  130. arith_check(test,x,y,z,x+y,y+x,"commute add");
  131. arith_check(test,x,y,z,x,x+0,"ident add");
  132. arith_check(test,x,y,z,x,x-0,"ident sub");
  133. arith_check(test,x,y,z,x+(y+z),(x+y)+z,"assoc add");
  134. arith_check(test,x,y,z,x*(y+z),x*y + x*z,"distributive mul/add");
  135. arith_check(test,x,y,z,x*(y-z),x*y - x*z,"distributive mul/add");
  136. arith_check(test,x,y,z,x*(y*z),(x*y)*z,"assoc mul");
  137. arith_check(test,x,y,z,x*y,y*x,"commute mul");
  138. arith_check(test,x,y,z,x,x*1,"ident mul");
  139. arith_check(test,x,y,z,0,x*0,"mul by 0");
  140. arith_check(test,x,y,z,-x,x*-1,"mul by -1");
  141. arith_check(test,x,y,z,x+x,x*2,"mul by 2");
  142. if (i%20) continue;
  143. if (y!=0) arith_check(test,x,y,z,x*y/y,x,"invert");
  144. try {
  145. y = x/0;
  146. test.fail();
  147. printf(" Inverted zero!");
  148. print("x", x);
  149. print("y", y);
  150. } catch(CryptoException) {}
  151. }
  152. }
  153. static void test_elligator() {
  154. SpongeRng rng(Block("test_elligator"),SpongeRng::DETERMINISTIC);
  155. Test test("Elligator");
  156. const int NHINTS = Group::REMOVED_COFACTOR * 2;
  157. SecureBuffer *alts[NHINTS];
  158. bool successes[NHINTS];
  159. SecureBuffer *alts2[NHINTS];
  160. bool successes2[NHINTS];
  161. for (int i=0; i<NTESTS/10 && (test.passing_now || i < 100); i++) {
  162. size_t len = (i % (2*Point::HASH_BYTES + 3));
  163. SecureBuffer b1(len);
  164. if (i!=Point::HASH_BYTES) rng.read(b1); /* special test case */
  165. if (i==1) b1[0] = 1; /* special case test */
  166. if (len >= Point::HASH_BYTES) b1[Point::HASH_BYTES-1] &= 0x7F; // FIXME MAGIC
  167. Point s = Point::from_hash(b1), ss=s;
  168. for (int j=0; j<(i&3); j++) ss = ss.debugging_torque();
  169. ss = ss.debugging_pscale(rng);
  170. bool good = false;
  171. for (int j=0; j<NHINTS; j++) {
  172. alts[j] = new SecureBuffer(len);
  173. alts2[j] = new SecureBuffer(len);
  174. if (len > Point::HASH_BYTES)
  175. memcpy(&(*alts[j])[Point::HASH_BYTES], &b1[Point::HASH_BYTES], len-Point::HASH_BYTES);
  176. if (len > Point::HASH_BYTES)
  177. memcpy(&(*alts2[j])[Point::HASH_BYTES], &b1[Point::HASH_BYTES], len-Point::HASH_BYTES);
  178. successes[j] = decaf_successful( s.invert_elligator(*alts[j], j));
  179. successes2[j] = decaf_successful(ss.invert_elligator(*alts2[j],j));
  180. if (successes[j] != successes2[j]
  181. || (successes[j] && successes2[j] && *alts[j] != *alts2[j])
  182. ) {
  183. test.fail();
  184. printf(" Unscalable Elligator inversion: i=%d, hint=%d, s=%d,%d\n",i,j,
  185. -int(successes[j]),-int(successes2[j]));
  186. hexprint("x",b1);
  187. hexprint("X",*alts[j]);
  188. hexprint("X",*alts2[j]);
  189. }
  190. if (successes[j]) {
  191. good = good || (b1 == *alts[j]);
  192. for (int k=0; k<j; k++) {
  193. if (successes[k] && *alts[j] == *alts[k]) {
  194. test.fail();
  195. printf(" Duplicate Elligator inversion: i=%d, hints=%d, %d\n",i,j,k);
  196. hexprint("x",b1);
  197. hexprint("X",*alts[j]);
  198. }
  199. }
  200. if (s != Point::from_hash(*alts[j])) {
  201. test.fail();
  202. printf(" Fail Elligator inversion round-trip: i=%d, hint=%d %s\n",i,j,
  203. (s==-Point::from_hash(*alts[j])) ? "[output was -input]": "");
  204. hexprint("x",b1);
  205. hexprint("X",*alts[j]);
  206. }
  207. }
  208. }
  209. if (!good) {
  210. test.fail();
  211. printf(" %s Elligator inversion: i=%d\n",good ? "Passed" : "Failed", i);
  212. hexprint("B", b1);
  213. for (int j=0; j<NHINTS; j++) {
  214. printf(" %d: %s%s", j, successes[j] ? "succ" : "fail\n", (successes[j] && *alts[j] == b1) ? " [x]" : "");
  215. if (successes[j]) {
  216. hexprint("b", *alts[j]);
  217. }
  218. }
  219. printf("\n");
  220. }
  221. for (int j=0; j<NHINTS; j++) {
  222. delete alts[j];
  223. alts[j] = NULL;
  224. delete alts2[j];
  225. alts2[j] = NULL;
  226. }
  227. Point t(rng);
  228. point_check(test,t,t,t,0,0,t,Point::from_hash(t.steg_encode(rng)),"steg round-trip");
  229. }
  230. }
  231. static void test_ec() {
  232. SpongeRng rng(Block("test_ec"),SpongeRng::DETERMINISTIC);
  233. Test test("EC");
  234. Point id = Point::identity(), base = Point::base();
  235. point_check(test,id,id,id,0,0,Point::from_hash(""),id,"fh0");
  236. if (Group::FIELD_MODULUS_TYPE == 3) {
  237. /* When p == 3 mod 4, the QNR is -1, so u*1^2 = -1 also produces the
  238. * identity.
  239. */
  240. point_check(test,id,id,id,0,0,Point::from_hash("\x01"),id,"fh1");
  241. }
  242. for (int i=0; i<NTESTS && test.passing_now; i++) {
  243. /* TODO: pathological cases */
  244. Scalar x(rng);
  245. Scalar y(rng);
  246. Point p(rng);
  247. Point q(rng);
  248. Point d1, d2;
  249. SecureBuffer buffer(2*Point::HASH_BYTES);
  250. rng.read(buffer);
  251. Point r = Point::from_hash(buffer);
  252. point_check(test,p,q,r,0,0,p,Point(p.serialize()),"round-trip");
  253. Point pp = p.debugging_torque().debugging_pscale(rng);
  254. if (!memeq(pp.serialize(),p.serialize())) {
  255. test.fail();
  256. printf("Fail torque seq test\n");
  257. }
  258. point_check(test,p,q,r,0,0,p,pp,"torque eq");
  259. point_check(test,p,q,r,0,0,p+q,q+p,"commute add");
  260. point_check(test,p,q,r,0,0,(p-q)+q,p,"correct sub");
  261. point_check(test,p,q,r,0,0,p+(q+r),(p+q)+r,"assoc add");
  262. point_check(test,p,q,r,0,0,p.times_two(),p+p,"dbl add");
  263. if (i%10) continue;
  264. point_check(test,p,q,r,x,0,x*(p+q),x*p+x*q,"distr mul");
  265. point_check(test,p,q,r,x,y,(x*y)*p,x*(y*p),"assoc mul");
  266. point_check(test,p,q,r,x,y,x*p+y*q,Point::double_scalarmul(x,p,y,q),"double mul");
  267. p.dual_scalarmul(d1,d2,x,y);
  268. point_check(test,p,q,r,x,y,x*p,d1,"dual mul 1");
  269. point_check(test,p,q,r,x,y,y*p,d2,"dual mul 2");
  270. point_check(test,base,q,r,x,y,x*base+y*q,q.non_secret_combo_with_base(y,x),"ds vt mul");
  271. point_check(test,p,q,r,x,0,Precomputed(p)*x,p*x,"precomp mul");
  272. point_check(test,p,q,r,0,0,r,
  273. Point::from_hash(Buffer(buffer).slice(0,Point::HASH_BYTES))
  274. + Point::from_hash(Buffer(buffer).slice(Point::HASH_BYTES,Point::HASH_BYTES)),
  275. "unih = hash+add"
  276. );
  277. point_check(test,p,q,r,x,0,Point(x.direct_scalarmul(p.serialize())),x*p,"direct mul");
  278. }
  279. }
  280. static void test_crypto() {
  281. Test test("Sample crypto");
  282. SpongeRng rng(Block("test_decaf_crypto"),SpongeRng::DETERMINISTIC);
  283. for (int i=0; i<NTESTS && test.passing_now; i++) {
  284. try {
  285. PrivateKey<Group> priv1(rng), priv2(rng);
  286. PublicKey<Group> pub1(priv1), pub2(priv2);
  287. SecureBuffer message = rng.read(i);
  288. SecureBuffer sig(priv1.sign(message));
  289. pub1.verify(message, sig);
  290. SecureBuffer s1(priv1.sharedSecret(pub2,32,true));
  291. SecureBuffer s2(priv2.sharedSecret(pub1,32,false));
  292. if (!memeq(s1,s2)) {
  293. test.fail();
  294. printf(" Shared secrets disagree on iteration %d.\n",i);
  295. }
  296. } catch (CryptoException) {
  297. test.fail();
  298. printf(" Threw CryptoException.\n");
  299. }
  300. }
  301. }
  302. static const uint8_t rfc7748_1[DhLadder::PUBLIC_BYTES];
  303. static const uint8_t rfc7748_1000[DhLadder::PUBLIC_BYTES];
  304. static const uint8_t rfc7748_1000000[DhLadder::PUBLIC_BYTES];
  305. static void test_cfrg_crypto() {
  306. Test test("CFRG crypto");
  307. SpongeRng rng(Block("test_cfrg_crypto"),SpongeRng::DETERMINISTIC);
  308. for (int i=0; i<NTESTS && test.passing_now; i++) {
  309. FixedArrayBuffer<DhLadder::PUBLIC_BYTES> base(rng);
  310. FixedArrayBuffer<DhLadder::PRIVATE_BYTES> s1(rng), s2(rng);
  311. SecureBuffer p1 = DhLadder::shared_secret(base,s1);
  312. SecureBuffer p2 = DhLadder::shared_secret(base,s2);
  313. SecureBuffer ss1 = DhLadder::shared_secret(p2,s1);
  314. SecureBuffer ss2 = DhLadder::shared_secret(p1,s2);
  315. if (!memeq(ss1,ss2)) {
  316. test.fail();
  317. printf(" Shared secrets disagree on iteration %d.\n",i);
  318. }
  319. if (!memeq(
  320. DhLadder::shared_secret(DhLadder::base_point(),s1),
  321. DhLadder::generate_key(s1)
  322. )) {
  323. test.fail();
  324. printf(" Generated keys disagree on iteration %d.\n",i);
  325. }
  326. }
  327. }
  328. static void test_cfrg_vectors() {
  329. Test test("CFRG test vectors");
  330. SecureBuffer k = DhLadder::base_point();
  331. SecureBuffer u = DhLadder::base_point();
  332. int the_ntests = (NTESTS < 1000000) ? 1000 : 1000000;
  333. for (int i=0; i<the_ntests && test.passing_now; i++) {
  334. SecureBuffer n = DhLadder::shared_secret(u,k);
  335. u = k; k = n;
  336. if (i==1-1) {
  337. if (!memeq(k,SecureBuffer(FixedBlock<DhLadder::PUBLIC_BYTES>(rfc7748_1)))) {
  338. test.fail();
  339. printf(" Test vectors disagree at 1.");
  340. }
  341. } else if (i==1000-1) {
  342. if (!memeq(k,SecureBuffer(FixedBlock<DhLadder::PUBLIC_BYTES>(rfc7748_1000)))) {
  343. test.fail();
  344. printf(" Test vectors disagree at 1000.");
  345. }
  346. } else if (i==1000000-1) {
  347. if (!memeq(k,SecureBuffer(FixedBlock<DhLadder::PUBLIC_BYTES>(rfc7748_1000000)))) {
  348. test.fail();
  349. printf(" Test vectors disagree at 1000000.");
  350. }
  351. }
  352. }
  353. }
  354. }; /* template<GroupId GROUP> struct Tests */
  355. template<> const uint8_t Tests<IsoEd25519>::rfc7748_1[32] = {
  356. 0x42,0x2c,0x8e,0x7a,0x62,0x27,0xd7,0xbc,
  357. 0xa1,0x35,0x0b,0x3e,0x2b,0xb7,0x27,0x9f,
  358. 0x78,0x97,0xb8,0x7b,0xb6,0x85,0x4b,0x78,
  359. 0x3c,0x60,0xe8,0x03,0x11,0xae,0x30,0x79
  360. };
  361. template<> const uint8_t Tests<IsoEd25519>::rfc7748_1000[32] = {
  362. 0x68,0x4c,0xf5,0x9b,0xa8,0x33,0x09,0x55,
  363. 0x28,0x00,0xef,0x56,0x6f,0x2f,0x4d,0x3c,
  364. 0x1c,0x38,0x87,0xc4,0x93,0x60,0xe3,0x87,
  365. 0x5f,0x2e,0xb9,0x4d,0x99,0x53,0x2c,0x51
  366. };
  367. template<> const uint8_t Tests<IsoEd25519>::rfc7748_1000000[32] = {
  368. 0x7c,0x39,0x11,0xe0,0xab,0x25,0x86,0xfd,
  369. 0x86,0x44,0x97,0x29,0x7e,0x57,0x5e,0x6f,
  370. 0x3b,0xc6,0x01,0xc0,0x88,0x3c,0x30,0xdf,
  371. 0x5f,0x4d,0xd2,0xd2,0x4f,0x66,0x54,0x24
  372. };
  373. template<> const uint8_t Tests<Ed448Goldilocks>::rfc7748_1[56] = {
  374. 0x3f,0x48,0x2c,0x8a,0x9f,0x19,0xb0,0x1e,
  375. 0x6c,0x46,0xee,0x97,0x11,0xd9,0xdc,0x14,
  376. 0xfd,0x4b,0xf6,0x7a,0xf3,0x07,0x65,0xc2,
  377. 0xae,0x2b,0x84,0x6a,0x4d,0x23,0xa8,0xcd,
  378. 0x0d,0xb8,0x97,0x08,0x62,0x39,0x49,0x2c,
  379. 0xaf,0x35,0x0b,0x51,0xf8,0x33,0x86,0x8b,
  380. 0x9b,0xc2,0xb3,0xbc,0xa9,0xcf,0x41,0x13
  381. };
  382. template<> const uint8_t Tests<Ed448Goldilocks>::rfc7748_1000[56] = {
  383. 0xaa,0x3b,0x47,0x49,0xd5,0x5b,0x9d,0xaf,
  384. 0x1e,0x5b,0x00,0x28,0x88,0x26,0xc4,0x67,
  385. 0x27,0x4c,0xe3,0xeb,0xbd,0xd5,0xc1,0x7b,
  386. 0x97,0x5e,0x09,0xd4,0xaf,0x6c,0x67,0xcf,
  387. 0x10,0xd0,0x87,0x20,0x2d,0xb8,0x82,0x86,
  388. 0xe2,0xb7,0x9f,0xce,0xea,0x3e,0xc3,0x53,
  389. 0xef,0x54,0xfa,0xa2,0x6e,0x21,0x9f,0x38
  390. };
  391. template<> const uint8_t Tests<Ed448Goldilocks>::rfc7748_1000000[56] = {
  392. 0x07,0x7f,0x45,0x36,0x81,0xca,0xca,0x36,
  393. 0x93,0x19,0x84,0x20,0xbb,0xe5,0x15,0xca,
  394. 0xe0,0x00,0x24,0x72,0x51,0x9b,0x3e,0x67,
  395. 0x66,0x1a,0x7e,0x89,0xca,0xb9,0x46,0x95,
  396. 0xc8,0xf4,0xbc,0xd6,0x6e,0x61,0xb9,0xb9,
  397. 0xc9,0x46,0xda,0x8d,0x52,0x4d,0xe3,0xd6,
  398. 0x9b,0xd9,0xd9,0xd6,0x6b,0x99,0x7e,0x37
  399. };
  400. int main(int argc, char **argv) {
  401. (void) argc; (void) argv;
  402. printf("Testing %s:\n",IsoEd25519::name());
  403. Tests<IsoEd25519>::test_arithmetic();
  404. Tests<IsoEd25519>::test_elligator();
  405. Tests<IsoEd25519>::test_ec();
  406. Tests<IsoEd25519>::test_cfrg_crypto();
  407. Tests<IsoEd25519>::test_cfrg_vectors();
  408. Tests<IsoEd25519>::test_crypto();
  409. printf("\n");
  410. printf("Testing %s:\n", Ed448Goldilocks::name());
  411. Tests<Ed448Goldilocks>::test_arithmetic();
  412. Tests<Ed448Goldilocks>::test_elligator();
  413. Tests<Ed448Goldilocks>::test_ec();
  414. Tests<Ed448Goldilocks>::test_cfrg_crypto();
  415. Tests<Ed448Goldilocks>::test_cfrg_vectors();
  416. Tests<Ed448Goldilocks>::test_crypto();
  417. if (passing) printf("Passed all tests.\n");
  418. return passing ? 0 : 1;
  419. }