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.
 
 
 
 
 

842 lines
28 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/eddsa.hxx>
  14. #include <decaf/shake.hxx>
  15. #include <stdio.h>
  16. using namespace decaf;
  17. static bool passing = true;
  18. static const long NTESTS = 10000;
  19. #include "ristretto_vectors.inc.cxx"
  20. class Test {
  21. public:
  22. bool passing_now;
  23. Test(const char *test) {
  24. passing_now = true;
  25. printf("%s...", test);
  26. if (strlen(test) < 27) printf("%*s",int(27-strlen(test)),"");
  27. fflush(stdout);
  28. }
  29. ~Test() {
  30. if (std::uncaught_exception()) {
  31. fail();
  32. printf(" due to uncaught exception.\n");
  33. }
  34. if (passing_now) printf("[PASS]\n");
  35. }
  36. void fail() {
  37. if (!passing_now) return;
  38. passing_now = passing = false;
  39. printf("[FAIL]\n");
  40. }
  41. };
  42. static uint64_t leint(const SecureBuffer &xx) {
  43. uint64_t out = 0;
  44. for (unsigned int i=0; i<xx.size() && i<sizeof(out); i++) {
  45. out |= uint64_t(xx[i]) << (8*i);
  46. }
  47. return out;
  48. }
  49. template<typename Group> struct Tests {
  50. typedef typename Group::Scalar Scalar;
  51. typedef typename Group::Point Point;
  52. typedef typename Group::DhLadder DhLadder;
  53. typedef typename Group::Precomputed Precomputed;
  54. static void print(const char *name, const Scalar &x) {
  55. unsigned char buffer[Scalar::SER_BYTES];
  56. x.serialize_into(buffer);
  57. printf(" %s = 0x", name);
  58. for (int i=sizeof(buffer)-1; i>=0; i--) {
  59. printf("%02x", buffer[i]);
  60. }
  61. printf("\n");
  62. }
  63. static void hexprint(const char *name, const SecureBuffer &buffer) {
  64. printf(" %s = 0x", name);
  65. for (int i=buffer.size()-1; i>=0; i--) {
  66. printf("%02x", buffer[i]);
  67. }
  68. printf("\n");
  69. }
  70. static void print(const char *name, const Point &x) {
  71. unsigned char buffer[Point::SER_BYTES];
  72. x.serialize_into(buffer);
  73. printf(" %s = 0x", name);
  74. for (int i=Point::SER_BYTES-1; i>=0; i--) {
  75. printf("%02x", buffer[i]);
  76. }
  77. printf("\n");
  78. }
  79. static bool arith_check(
  80. Test &test,
  81. const Scalar &x,
  82. const Scalar &y,
  83. const Scalar &z,
  84. const Scalar &l,
  85. const Scalar &r,
  86. const char *name
  87. ) {
  88. if (l == r) return true;
  89. test.fail();
  90. printf(" %s", name);
  91. print("x", x);
  92. print("y", y);
  93. print("z", z);
  94. print("lhs", l);
  95. print("rhs", r);
  96. return false;
  97. }
  98. static bool point_check(
  99. Test &test,
  100. const Point &p,
  101. const Point &q,
  102. const Point &R,
  103. const Scalar &x,
  104. const Scalar &y,
  105. const Point &l,
  106. const Point &r,
  107. const char *name
  108. ) {
  109. bool good = l==r;
  110. if (!p.validate()) { good = false; printf(" p invalid\n"); }
  111. if (!q.validate()) { good = false; printf(" q invalid\n"); }
  112. if (!r.validate()) { good = false; printf(" r invalid\n"); }
  113. if (!l.validate()) { good = false; printf(" l invalid\n"); }
  114. if (good) return true;
  115. test.fail();
  116. printf(" %s", name);
  117. print("x", x);
  118. print("y", y);
  119. print("p", p);
  120. print("q", q);
  121. print("r", R);
  122. print("lhs", r);
  123. print("rhs", l);
  124. return false;
  125. }
  126. static void test_arithmetic() {
  127. SpongeRng rng(Block("test_arithmetic"),SpongeRng::DETERMINISTIC);
  128. Test test("Arithmetic");
  129. Scalar x(0),y(0),z(0);
  130. arith_check(test,x,y,z,INT_MAX,(decaf_word_t)INT_MAX,"cast from max");
  131. arith_check(test,x,y,z,INT_MIN,-Scalar(1+(decaf_word_t)INT_MAX),"cast from min");
  132. for (int i=0; i<NTESTS*10 && test.passing_now; i++) {
  133. size_t sob = i % (2*Group::Scalar::SER_BYTES);
  134. SecureBuffer xx = rng.read(sob), yy = rng.read(sob), zz = rng.read(sob);
  135. Scalar x(xx);
  136. Scalar y(yy);
  137. Scalar z(zz);
  138. arith_check(test,x,y,z,x+y,y+x,"commute add");
  139. arith_check(test,x,y,z,x,x+0,"ident add");
  140. arith_check(test,x,y,z,x,x-0,"ident sub");
  141. arith_check(test,x,y,z,x+-x,0,"inverse add");
  142. arith_check(test,x,y,z,x-x,0,"inverse sub");
  143. arith_check(test,x,y,z,x-(x+1),-1,"inverse add2");
  144. arith_check(test,x,y,z,x+(y+z),(x+y)+z,"assoc add");
  145. arith_check(test,x,y,z,x*(y+z),x*y + x*z,"distributive mul/add");
  146. arith_check(test,x,y,z,x*(y-z),x*y - x*z,"distributive mul/add");
  147. arith_check(test,x,y,z,x*(y*z),(x*y)*z,"assoc mul");
  148. arith_check(test,x,y,z,x*y,y*x,"commute mul");
  149. arith_check(test,x,y,z,x,x*1,"ident mul");
  150. arith_check(test,x,y,z,0,x*0,"mul by 0");
  151. arith_check(test,x,y,z,-x,x*-1,"mul by -1");
  152. arith_check(test,x,y,z,x+x,x*2,"mul by 2");
  153. arith_check(test,x,y,z,-(x*y),(-x)*y,"neg prop mul");
  154. arith_check(test,x,y,z,x*y,(-x)*(-y),"double neg prop mul");
  155. arith_check(test,x,y,z,-(x+y),(-x)+(-y),"neg prop add");
  156. arith_check(test,x,y,z,x-y,(x)+(-y),"add neg sub");
  157. arith_check(test,x,y,z,(-x)-y,-(x+y),"neg add");
  158. if (sob <= 4) {
  159. uint64_t xi = leint(xx), yi = leint(yy);
  160. arith_check(test,x,y,z,x,xi,"parse consistency");
  161. arith_check(test,x,y,z,x+y,xi+yi,"add consistency");
  162. arith_check(test,x,y,z,x*y,xi*yi,"mul consistency");
  163. }
  164. if (i%20) continue;
  165. if (y!=0) arith_check(test,x,y,z,x*y/y,x,"invert");
  166. try {
  167. y = x/0;
  168. test.fail();
  169. printf(" Inverted zero!");
  170. print("x", x);
  171. print("y", y);
  172. } catch(CryptoException&) {}
  173. }
  174. }
  175. static const Block sqrt_minus_one;
  176. static const Block minus_sqrt_minus_one;
  177. static const Block elli_patho; /* sqrt(1/(u(1-d))) */
  178. static void test_elligator() {
  179. SpongeRng rng(Block("test_elligator"),SpongeRng::DETERMINISTIC);
  180. Test test("Elligator");
  181. const int NHINTS = 1<<Point::INVERT_ELLIGATOR_WHICH_BITS;
  182. SecureBuffer *alts[NHINTS];
  183. bool successes[NHINTS];
  184. SecureBuffer *alts2[NHINTS];
  185. bool successes2[NHINTS];
  186. for (unsigned int i=0; i<NTESTS/10 && (i<10 || test.passing_now); i++) {
  187. size_t len = (i % (2*Point::HASH_BYTES + 3));
  188. SecureBuffer b1(len);
  189. if (i!=Point::HASH_BYTES) rng.read(b1); /* special test case */
  190. /* Pathological cases */
  191. if (i==1) b1[0] = 1;
  192. if (i==2 && sqrt_minus_one.size()) b1 = sqrt_minus_one;
  193. if (i==3 && minus_sqrt_minus_one.size()) b1 = minus_sqrt_minus_one;
  194. if (i==4 && elli_patho.size()) b1 = elli_patho;
  195. len = b1.size();
  196. Point s = Point::from_hash(b1), ss=s;
  197. for (unsigned int j=0; j<(i&3); j++) ss = ss.debugging_torque();
  198. ss = ss.debugging_pscale(rng);
  199. bool good = false;
  200. for (int j=0; j<NHINTS; j++) {
  201. alts[j] = new SecureBuffer(len);
  202. alts2[j] = new SecureBuffer(len);
  203. if (len > Point::HASH_BYTES)
  204. memcpy(&(*alts[j])[Point::HASH_BYTES], &b1[Point::HASH_BYTES], len-Point::HASH_BYTES);
  205. if (len > Point::HASH_BYTES)
  206. memcpy(&(*alts2[j])[Point::HASH_BYTES], &b1[Point::HASH_BYTES], len-Point::HASH_BYTES);
  207. successes[j] = decaf_successful( s.invert_elligator(*alts[j], j));
  208. successes2[j] = decaf_successful(ss.invert_elligator(*alts2[j],j));
  209. if (successes[j] != successes2[j]
  210. || (successes[j] && successes2[j] && *alts[j] != *alts2[j])
  211. ) {
  212. test.fail();
  213. printf(" Unscalable Elligator inversion: i=%d, hint=%d, s=%d,%d\n",i,j,
  214. -int(successes[j]),-int(successes2[j]));
  215. hexprint("x",b1);
  216. hexprint("X",*alts[j]);
  217. hexprint("X",*alts2[j]);
  218. }
  219. if (successes[j]) {
  220. good = good || (b1 == *alts[j]);
  221. for (int k=0; k<j; k++) {
  222. if (successes[k] && *alts[j] == *alts[k]) {
  223. test.fail();
  224. printf(" Duplicate Elligator inversion: i=%d, hints=%d, %d\n",i,j,k);
  225. hexprint("x",b1);
  226. hexprint("X",*alts[j]);
  227. }
  228. }
  229. if (s != Point::from_hash(*alts[j])) {
  230. test.fail();
  231. printf(" Fail Elligator inversion round-trip: i=%d, hint=%d %s\n",i,j,
  232. (s==-Point::from_hash(*alts[j])) ? "[output was -input]": "");
  233. hexprint("x",b1);
  234. hexprint("X",*alts[j]);
  235. }
  236. }
  237. }
  238. if (!good) {
  239. test.fail();
  240. printf(" %s Elligator inversion: i=%d\n",good ? "Passed" : "Failed", i);
  241. hexprint("B", b1);
  242. for (int j=0; j<NHINTS; j++) {
  243. printf(" %d: %s%s", j, successes[j] ? "succ" : "fail\n", (successes[j] && *alts[j] == b1) ? " [x]" : "");
  244. if (successes[j]) {
  245. hexprint("b", *alts[j]);
  246. }
  247. }
  248. printf("\n");
  249. }
  250. for (int j=0; j<NHINTS; j++) {
  251. delete alts[j];
  252. alts[j] = NULL;
  253. delete alts2[j];
  254. alts2[j] = NULL;
  255. }
  256. Point t(rng);
  257. SecureBuffer bsteg = t.steg_encode(rng);
  258. if (bsteg[Point::STEG_BYTES-1] == 0 && bsteg[Point::STEG_BYTES-2] == 0 && bsteg[Point::STEG_BYTES-3] == 0) {
  259. test.fail();
  260. printf(" Steg is nonuniform (probability of false failure = 2^-24)\n");
  261. hexprint(" steg buffer:", bsteg);
  262. }
  263. point_check(test,t,t,t,0,0,t,Point::from_hash(bsteg),"steg round-trip");
  264. FixedArrayBuffer<Point::HASH_BYTES> b3(rng), b4(b3);
  265. t = Point::from_hash(b3);
  266. for (unsigned j=0; j<256; j+=2<<((Group::bits()-1)%8)) {
  267. b4[Point::HASH_BYTES-1] = b3[Point::HASH_BYTES-1] ^ j;
  268. Point u = Point::from_hash(b4);
  269. point_check(test,t,t,t,0,0,t,u,"elligator twiddle high bits");
  270. }
  271. }
  272. }
  273. static void test_ec() {
  274. SpongeRng rng(Block("test_ec"),SpongeRng::DETERMINISTIC);
  275. Test test("EC");
  276. Point id = Point::identity(), base = Point::base();
  277. point_check(test,id,id,id,0,0,Point::from_hash(""),id,"fh0");
  278. unsigned char enc[Point::SER_BYTES] = {0};
  279. if (Group::FIELD_MODULUS_TYPE == 3) {
  280. /* When p == 3 mod 4, the QNR is -1, so u*1^2 = -1 also produces the
  281. * identity.
  282. */
  283. point_check(test,id,id,id,0,0,Point::from_hash("\x01"),id,"fh1");
  284. }
  285. point_check(test,id,id,id,0,0,Point(FixedBlock<sizeof(enc)>(enc)),id,"decode [0]");
  286. try {
  287. enc[0] = 1;
  288. Point f((FixedBlock<sizeof(enc)>(enc)));
  289. test.fail();
  290. printf(" Allowed deserialize of [1]: %d", f==id);
  291. } catch (CryptoException&) {
  292. /* ok */
  293. }
  294. if (sqrt_minus_one.size()) {
  295. try {
  296. Point f(sqrt_minus_one);
  297. test.fail();
  298. printf(" Allowed deserialize of [i]: %d", f==id);
  299. } catch (CryptoException&) {
  300. /* ok */
  301. }
  302. }
  303. if (minus_sqrt_minus_one.size()) {
  304. try {
  305. Point f(minus_sqrt_minus_one);
  306. test.fail();
  307. printf(" Allowed deserialize of [-i]: %d", f==id);
  308. } catch (CryptoException&) {
  309. /* ok */
  310. }
  311. }
  312. for (int i=0; i<NTESTS && test.passing_now; i++) {
  313. Scalar x(rng);
  314. Scalar y(rng);
  315. Point p(rng);
  316. Point q(rng);
  317. Point d1, d2;
  318. SecureBuffer buffer(2*Point::HASH_BYTES);
  319. rng.read(buffer);
  320. Point r = Point::from_hash(buffer);
  321. try {
  322. point_check(test,p,q,r,0,0,p,Point(p.serialize()),"round-trip");
  323. } catch (CryptoException&) {
  324. test.fail();
  325. printf(" Round-trip raised CryptoException!\n");
  326. }
  327. Point pp = p.debugging_torque().debugging_pscale(rng);
  328. if (!memeq(pp.serialize(),p.serialize())) {
  329. test.fail();
  330. printf(" Fail torque seq test\n");
  331. }
  332. if (!memeq((p-pp).serialize(),id.serialize())) {
  333. test.fail();
  334. printf(" Fail torque id test\n");
  335. }
  336. if (!memeq((p-p).serialize(),id.serialize())) {
  337. test.fail();
  338. printf(" Fail id test\n");
  339. }
  340. point_check(test,p,q,r,0,0,p,pp,"torque eq");
  341. point_check(test,p,q,r,0,0,p+q,q+p,"commute add");
  342. point_check(test,p,q,r,0,0,(p-q)+q,p,"correct sub");
  343. point_check(test,p,q,r,0,0,p+(q+r),(p+q)+r,"assoc add");
  344. point_check(test,p,q,r,0,0,p.times_two(),p+p,"dbl add");
  345. if (i%10) continue;
  346. point_check(test,p,q,r,0,0,p.times_two(),p*Scalar(2),"add times two");
  347. point_check(test,p,q,r,x,0,x*(p+q),x*p+x*q,"distr mul");
  348. point_check(test,p,q,r,x,y,(x*y)*p,x*(y*p),"assoc mul");
  349. point_check(test,p,q,r,x,y,x*p+y*q,Point::double_scalarmul(x,p,y,q),"double mul");
  350. p.dual_scalarmul(d1,d2,x,y);
  351. point_check(test,p,q,r,x,y,x*p,d1,"dual mul 1");
  352. point_check(test,p,q,r,x,y,y*p,d2,"dual mul 2");
  353. point_check(test,base,q,r,x,y,x*base+y*q,q.non_secret_combo_with_base(y,x),"ds vt mul");
  354. point_check(test,p,q,r,x,0,Precomputed(p)*x,p*x,"precomp mul");
  355. point_check(test,p,q,r,0,0,r,
  356. Point::from_hash(Buffer(buffer).slice(0,Point::HASH_BYTES))
  357. + Point::from_hash(Buffer(buffer).slice(Point::HASH_BYTES,Point::HASH_BYTES)),
  358. "unih = hash+add"
  359. );
  360. try {
  361. point_check(test,p,q,r,x,0,Point(x.direct_scalarmul(p.serialize())),x*p,"direct mul");
  362. } catch (CryptoException&) {
  363. printf(" Direct mul raised CryptoException!\n");
  364. test.fail();
  365. }
  366. q=p;
  367. for (int j=1; j<Group::REMOVED_COFACTOR; j<<=1) q = q.times_two();
  368. decaf_error_t error = r.decode_like_eddsa_and_mul_by_ratio_noexcept(
  369. p.mul_by_ratio_and_encode_like_eddsa()
  370. );
  371. if (error != DECAF_SUCCESS) {
  372. test.fail();
  373. printf(" Decode like EdDSA failed.");
  374. }
  375. point_check(test,-q,q,r,i,0,q,r,"Encode like EdDSA round-trip");
  376. }
  377. }
  378. static const uint8_t rfc7748_1[DhLadder::PUBLIC_BYTES];
  379. static const uint8_t rfc7748_1000[DhLadder::PUBLIC_BYTES];
  380. static const uint8_t rfc7748_1000000[DhLadder::PUBLIC_BYTES];
  381. static void test_cfrg_crypto() {
  382. Test test("CFRG crypto");
  383. SpongeRng rng(Block("test_cfrg_crypto"),SpongeRng::DETERMINISTIC);
  384. {
  385. FixedArrayBuffer<DhLadder::PUBLIC_BYTES> base, out;
  386. FixedArrayBuffer<DhLadder::PRIVATE_BYTES> s1(rng);
  387. decaf_error_t e = DhLadder::shared_secret_noexcept(out,base,s1);
  388. if (e != DECAF_FAILURE) {
  389. test.fail();
  390. printf(" Multiply by 0 didn't give an error\n");
  391. }
  392. if (!out.contents_equal(base)) {
  393. test.fail();
  394. printf(" Multiply by 0 didn't give 0\n");
  395. }
  396. }
  397. for (int i=0; i<NTESTS && test.passing_now; i++) {
  398. FixedArrayBuffer<DhLadder::PUBLIC_BYTES> base(rng);
  399. FixedArrayBuffer<DhLadder::PRIVATE_BYTES> s1(rng), s2(rng);
  400. SecureBuffer p1 = DhLadder::shared_secret(base,s1);
  401. SecureBuffer p2 = DhLadder::shared_secret(base,s2);
  402. SecureBuffer ss1 = DhLadder::shared_secret(p2,s1);
  403. SecureBuffer ss2 = DhLadder::shared_secret(p1,s2);
  404. if (!memeq(ss1,ss2)) {
  405. test.fail();
  406. printf(" Shared secrets disagree on iteration %d.\n",i);
  407. }
  408. p1 = DhLadder::shared_secret(DhLadder::base_point(),s1);
  409. p2 = DhLadder::derive_public_key(s1);
  410. if (!memeq(p1,p2)) {
  411. test.fail();
  412. printf(" Public keys disagree on iteration %d.\n Ladder public key: ",i);
  413. for (unsigned j=0; j<s1.size(); j++) { printf("%02x",p1[j]); }
  414. printf("\n Derive public key: ");
  415. for (unsigned j=0; j<s1.size(); j++) { printf("%02x",p2[j]); }
  416. printf("\n");
  417. }
  418. }
  419. }
  420. static const bool eddsa_prehashed[];
  421. static const Block eddsa_sk[], eddsa_pk[], eddsa_message[], eddsa_context[], eddsa_sig[];
  422. static const bool eddsa_verify_should_succeed[];
  423. static void test_cfrg_vectors() {
  424. Test test("CFRG test vectors");
  425. SecureBuffer k = DhLadder::base_point();
  426. SecureBuffer u = DhLadder::base_point();
  427. int the_ntests = (NTESTS < 1000000) ? 1000 : 1000000;
  428. /* EdDSA */
  429. for (unsigned int t=0; t<sizeof(eddsa_sk)/sizeof(eddsa_sk[0]); t++) {
  430. if (eddsa_sk[t].size()) {
  431. typename EdDSA<Group>::PrivateKey priv(eddsa_sk[t]);
  432. SecureBuffer eddsa_pk2 = priv.pub().serialize();
  433. if (!memeq(SecureBuffer(eddsa_pk[t]), eddsa_pk2)) {
  434. test.fail();
  435. printf(" EdDSA PK vectors #%d disagree.", t);
  436. printf("\n Correct: ");
  437. for (unsigned i=0; i<eddsa_pk[t].size(); i++) printf("%02x", eddsa_pk[t][i]);
  438. printf("\n Incorrect: ");
  439. for (unsigned i=0; i<eddsa_pk2.size(); i++) printf("%02x", eddsa_pk2[i]);
  440. printf("\n");
  441. }
  442. SecureBuffer sig;
  443. if (eddsa_prehashed[t]) {
  444. typename EdDSA<Group>::PrivateKeyPh priv2(eddsa_sk[t]);
  445. sig = priv2.sign_with_prehash(eddsa_message[t],eddsa_context[t]);
  446. } else {
  447. sig = priv.sign(eddsa_message[t],eddsa_context[t]);
  448. }
  449. if (!memeq(SecureBuffer(eddsa_sig[t]),sig)) {
  450. test.fail();
  451. printf(" EdDSA sig vectors #%d disagree.", t);
  452. printf("\n Correct: ");
  453. for (unsigned i=0; i<eddsa_sig[t].size(); i++) printf("%02x", eddsa_sig[t][i]);
  454. printf("\n Incorrect: ");
  455. for (unsigned i=0; i<sig.size(); i++) printf("%02x", sig[i]);
  456. printf("\n");
  457. }
  458. }
  459. bool verified;
  460. try {
  461. typename EdDSA<Group>::PublicKey pub(eddsa_pk[t]);
  462. if (eddsa_prehashed[t]) {
  463. pub.verify_with_prehash(eddsa_sig[t], eddsa_message[t], eddsa_context[t]);
  464. } else {
  465. pub.verify(eddsa_sig[t], eddsa_message[t], eddsa_context[t]);
  466. }
  467. verified = true;
  468. } catch(CryptoException&) {
  469. verified = false;
  470. }
  471. if (verified != eddsa_verify_should_succeed[t]) {
  472. test.fail();
  473. printf(" EdDSA Verify vector #%d disagree: verify %s but should %s\n",
  474. t, verified ? "passed" : "failed",
  475. eddsa_verify_should_succeed[t] ? "pass" : "fail");
  476. }
  477. }
  478. /* X25519/X448 */
  479. for (int i=0; i<the_ntests && test.passing_now; i++) {
  480. SecureBuffer n = DhLadder::shared_secret(u,k);
  481. u = k; k = n;
  482. if (i==1-1) {
  483. if (!memeq(k,SecureBuffer(FixedBlock<DhLadder::PUBLIC_BYTES>(rfc7748_1)))) {
  484. test.fail();
  485. printf(" Test vectors disagree at 1.");
  486. }
  487. } else if (i==1000-1) {
  488. if (!memeq(k,SecureBuffer(FixedBlock<DhLadder::PUBLIC_BYTES>(rfc7748_1000)))) {
  489. test.fail();
  490. printf(" Test vectors disagree at 1000.");
  491. }
  492. } else if (i==1000000-1) {
  493. if (!memeq(k,SecureBuffer(FixedBlock<DhLadder::PUBLIC_BYTES>(rfc7748_1000000)))) {
  494. test.fail();
  495. printf(" Test vectors disagree at 1000000.");
  496. }
  497. }
  498. }
  499. }
  500. static void test_eddsa() {
  501. Test test("EdDSA");
  502. SpongeRng rng(Block("test_eddsa"),SpongeRng::DETERMINISTIC);
  503. int lg_scalar = Group::bits();
  504. for (int cof = Group::REMOVED_COFACTOR; cof>1; cof>>=1) {
  505. lg_scalar--;
  506. }
  507. typename Group::Scalar more_than_size = 1;
  508. for (int i=0; i<lg_scalar; i++) more_than_size *= 2;
  509. for (int i=0; i<NTESTS && test.passing_now; i++) {
  510. typename EdDSA<Group>::PrivateKey priv(rng);
  511. typename EdDSA<Group>::PublicKey pub(priv);
  512. SecureBuffer message(i);
  513. rng.read(message);
  514. SecureBuffer context(i%256);
  515. rng.read(context);
  516. SecureBuffer sig = priv.sign(message,context);
  517. try {
  518. pub.verify(sig,message,context);
  519. } catch(CryptoException&) {
  520. test.fail();
  521. printf(" Signature validation failed on sig %d\n", i);
  522. }
  523. try {
  524. sig[(i/8) % sig.size()] ^= 1<<(i%8);
  525. pub.verify(sig,message,context);
  526. test.fail();
  527. printf(" Signature validation passed incorrectly on corrupted sig %d\n", i);
  528. } catch(CryptoException&) {}
  529. sig[(i/8) % sig.size()] ^= 1<<(i%8);
  530. try {
  531. const int size = EdDSA<Group>::PublicKey::SER_BYTES;
  532. uint8_t ser[size];
  533. pub.serialize_into(ser);
  534. ser[(i/8) % size] ^= 1<<(i%8);
  535. typename EdDSA<Group>::PublicKey pub2((FixedBlock<size>(ser)));
  536. pub2.verify(sig,message,context);
  537. test.fail();
  538. printf(" Signature validation passed incorrectly on corrupted pubkey %d\n", i);
  539. } catch(CryptoException&) {}
  540. if (message.size() > 0) {
  541. try {
  542. message[(i/8) % message.size()] ^= 1<<(i%8);
  543. pub.verify(sig,message,context);
  544. test.fail();
  545. printf(" Signature validation passed incorrectly on corrupted message %d\n", i);
  546. } catch(CryptoException&) {}
  547. message[(i/8) % message.size()] ^= 1<<(i%8);
  548. }
  549. if (context.size() > 0) {
  550. try {
  551. context[(i/8) % context.size()] ^= 1<<(i%8);
  552. pub.verify(sig,message,context);
  553. test.fail();
  554. printf(" Signature validation passed incorrectly on corrupted message %d\n", i);
  555. } catch(CryptoException&) {}
  556. context[(i/8) % context.size()] ^= 1<<(i%8);
  557. }
  558. // Construct sig which is numerically equal but improper
  559. const int scalarbytes = Group::Scalar::SER_BYTES;
  560. uint8_t *scalarpart = &sig[EdDSA<Group>::PublicKey::SER_BYTES];
  561. typename Group::Scalar sig_r = FixedBlock<scalarbytes>(scalarpart);
  562. memcpy(scalarpart, (-sig_r).serialize().data(), scalarbytes);
  563. try {
  564. pub.verify(sig,message,context);
  565. test.fail();
  566. printf(" Signature validation passed incorrectly on negated sig %d\n", i);
  567. } catch(CryptoException&) {}
  568. sig_r -= more_than_size;
  569. memcpy(scalarpart, sig_r.serialize().data(), scalarbytes);
  570. scalarpart[scalarbytes-1] += 1<<(lg_scalar%8);
  571. try {
  572. pub.verify(sig,message,context);
  573. test.fail();
  574. printf(" Signature validation passed incorrectly on improper sig %d\n", i);
  575. } catch(CryptoException&) {}
  576. /* Test encode_like and torque */
  577. Point p(rng);
  578. SecureBuffer p1 = p.mul_by_ratio_and_encode_like_eddsa();
  579. SecureBuffer p2 = p.debugging_torque().mul_by_ratio_and_encode_like_eddsa();
  580. if (!memeq(p1,p2)) {
  581. test.fail();
  582. printf(" Torque and encode like EdDSA failed\n");
  583. }
  584. SecureBuffer p3 = p.mul_by_ratio_and_encode_like_ladder();
  585. SecureBuffer p4 = p.debugging_torque().mul_by_ratio_and_encode_like_ladder();
  586. if (!memeq(p3,p4)) {
  587. test.fail();
  588. printf(" Torque and encode like ladder failed\n");
  589. }
  590. }
  591. }
  592. /* Thanks Johan Pascal */
  593. static void test_convert_eddsa_to_x() {
  594. Test test("ECDH using EdDSA keys");
  595. SpongeRng rng(Block("test_x_on_eddsa_key"),SpongeRng::DETERMINISTIC);
  596. for (int i=0; i<NTESTS && test.passing_now; i++) {
  597. /* generate 2 pairs of EdDSA keys */
  598. typename EdDSA<Group>::PrivateKey alice_priv(rng);
  599. typename EdDSA<Group>::PublicKey alice_pub(alice_priv);
  600. typename EdDSA<Group>::PrivateKey bob_priv(rng);
  601. typename EdDSA<Group>::PublicKey bob_pub(bob_priv);
  602. /* convert them to ECDH format
  603. * check public key value by computing it from direct conversion and regeneration from converted private)
  604. */
  605. SecureBuffer alice_priv_x = alice_priv.convert_to_x();
  606. SecureBuffer alice_pub_x_conversion = alice_pub.convert_to_x();
  607. SecureBuffer alice_pub_x_generated = DhLadder::derive_public_key(alice_priv_x);
  608. if (!memeq(alice_pub_x_conversion, alice_pub_x_generated)) {
  609. test.fail();
  610. printf(" Ed2X Public key conversion and regeneration from converted private key differs.\n");
  611. }
  612. SecureBuffer bob_priv_x = bob_priv.convert_to_x();
  613. SecureBuffer bob_pub_x_conversion = bob_pub.convert_to_x();
  614. SecureBuffer bob_pub_x_generated = DhLadder::derive_public_key(bob_priv_x);
  615. if (!memeq(bob_pub_x_conversion, bob_pub_x_generated)) {
  616. test.fail();
  617. printf(" Ed2X Public key conversion and regeneration from converted private key differs.\n");
  618. }
  619. /* compute shared secrets and check they match */
  620. SecureBuffer alice_shared = DhLadder::shared_secret(bob_pub_x_conversion, alice_priv_x);
  621. SecureBuffer bob_shared = DhLadder::shared_secret(alice_pub_x_conversion, bob_priv_x);
  622. if (!memeq(alice_shared, bob_shared)) {
  623. test.fail();
  624. printf(" ECDH shared secret mismatch.\n");
  625. }
  626. }
  627. }
  628. static void test_dalek_vectors() {
  629. Test test("Test vectors from Dalek");
  630. Point p = Point::base(), q;
  631. for (unsigned i=0; i<base_multiples<Group>::count; i++) {
  632. if (!decaf_memeq(q.serialize().data(),base_multiples<Group>::values[i],Point::SER_BYTES)) {
  633. test.fail();
  634. printf(" Failed test vector for %d * base point.\n", i);
  635. }
  636. q += p;
  637. }
  638. for (unsigned i=0; i<elligator_examples<Group>::count; i++) {
  639. Point r = Point::from_hash(FixedBlock<Point::HASH_BYTES>(elligator_examples<Group>::inputs[i]));
  640. Point s = Point(FixedBlock<Point::SER_BYTES>(elligator_examples<Group>::outputs[i]));
  641. point_check(test,r,r,r,0,0,r,s,"elligator test vector");
  642. }
  643. }
  644. static void run() {
  645. printf("Testing %s:\n",Group::name());
  646. test_arithmetic();
  647. test_elligator();
  648. test_ec();
  649. test_eddsa();
  650. test_convert_eddsa_to_x();
  651. test_cfrg_crypto();
  652. test_cfrg_vectors();
  653. test_dalek_vectors();
  654. printf("\n");
  655. }
  656. }; /* template<GroupId GROUP> struct Tests */
  657. template<typename T>
  658. static void test_xof() {
  659. /* TODO: more testing of XOFs */
  660. Test test("XOF");
  661. SpongeRng rng(Block("test_xof"),SpongeRng::DETERMINISTIC);
  662. FixedArrayBuffer<1024> a,b,c;
  663. rng.read(c);
  664. T s1, s2;
  665. unsigned i;
  666. for (i=0; i<c.size(); i++) s1.update(c.slice(i,1));
  667. s2.update(c);
  668. for (i=0; i<a.size(); i++) s1.output(a.slice(i,1));
  669. s2.output(b);
  670. if (!a.contents_equal(b)) {
  671. test.fail();
  672. printf(" Buffers aren't equal!\n");
  673. }
  674. }
  675. static void test_rng() {
  676. Test test("RNG");
  677. SpongeRng rng_d1(Block("test_rng"),SpongeRng::DETERMINISTIC);
  678. SpongeRng rng_d2(Block("test_rng"),SpongeRng::DETERMINISTIC);
  679. SpongeRng rng_d3(Block("best_rng"),SpongeRng::DETERMINISTIC);
  680. SpongeRng rng_n1;
  681. SpongeRng rng_n2;
  682. SecureBuffer s1,s2,s3;
  683. for (int i=0; i<5; i++) {
  684. s1 = rng_d1.read(16<<i);
  685. s2 = rng_d2.read(16<<i);
  686. s3 = rng_d3.read(16<<i);
  687. if (s1 != s2) {
  688. test.fail();
  689. printf(" Deterministic RNG didn't match!\n");
  690. }
  691. if (s1 == s3) {
  692. test.fail();
  693. printf(" Deterministic matched with different data!\n");
  694. }
  695. rng_d1.stir("hello");
  696. rng_d2.stir("hello");
  697. rng_d3.stir("hello");
  698. s1 = rng_n1.read(16<<i);
  699. s2 = rng_n2.read(16<<i);
  700. if (s1 == s2) {
  701. test.fail();
  702. printf(" Nondeterministic RNG matched!\n");
  703. }
  704. }
  705. rng_d1.stir("hello");
  706. rng_d2.stir("jello");
  707. s1 = rng_d1.read(16);
  708. s2 = rng_d2.read(16);
  709. if (s1 == s2) {
  710. test.fail();
  711. printf(" Deterministic matched with different data!\n");
  712. }
  713. }
  714. #include "vectors.inc.cxx"
  715. int main(int argc, char **argv) {
  716. (void) argc; (void) argv;
  717. test_rng();
  718. test_xof<SHAKE<128> >();
  719. test_xof<SHAKE<256> >();
  720. printf("\n");
  721. run_for_all_curves<Tests>();
  722. if (passing) printf("Passed all tests.\n");
  723. return passing ? 0 : 1;
  724. }