Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.
 
 
 
 
 

372 Zeilen
12 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::Precomputed Precomputed;
  45. static void print(const char *name, const Scalar &x) {
  46. unsigned char buffer[Scalar::SER_BYTES];
  47. x.serialize_into(buffer);
  48. printf(" %s = 0x", name);
  49. for (int i=sizeof(buffer)-1; i>=0; i--) {
  50. printf("%02x", buffer[i]);
  51. }
  52. printf("\n");
  53. }
  54. static void hexprint(const char *name, const SecureBuffer &buffer) {
  55. printf(" %s = 0x", name);
  56. for (int i=buffer.size()-1; i>=0; i--) {
  57. printf("%02x", buffer[i]);
  58. }
  59. printf("\n");
  60. }
  61. static void print(const char *name, const Point &x) {
  62. unsigned char buffer[Point::SER_BYTES];
  63. x.serialize_into(buffer);
  64. printf(" %s = 0x", name);
  65. for (int i=Point::SER_BYTES-1; i>=0; i--) {
  66. printf("%02x", buffer[i]);
  67. }
  68. printf("\n");
  69. }
  70. static bool arith_check(
  71. Test &test,
  72. const Scalar &x,
  73. const Scalar &y,
  74. const Scalar &z,
  75. const Scalar &l,
  76. const Scalar &r,
  77. const char *name
  78. ) {
  79. if (l == r) return true;
  80. test.fail();
  81. printf(" %s", name);
  82. print("x", x);
  83. print("y", y);
  84. print("z", z);
  85. print("lhs", l);
  86. print("rhs", r);
  87. return false;
  88. }
  89. static bool point_check(
  90. Test &test,
  91. const Point &p,
  92. const Point &q,
  93. const Point &R,
  94. const Scalar &x,
  95. const Scalar &y,
  96. const Point &l,
  97. const Point &r,
  98. const char *name
  99. ) {
  100. bool good = l==r;
  101. if (!p.validate()) { good = false; printf(" p invalid\n"); }
  102. if (!q.validate()) { good = false; printf(" q invalid\n"); }
  103. if (!r.validate()) { good = false; printf(" r invalid\n"); }
  104. if (!l.validate()) { good = false; printf(" l invalid\n"); }
  105. if (good) return true;
  106. test.fail();
  107. printf(" %s", name);
  108. print("x", x);
  109. print("y", y);
  110. print("p", p);
  111. print("q", q);
  112. print("r", R);
  113. print("lhs", r);
  114. print("rhs", l);
  115. return false;
  116. }
  117. static void test_arithmetic() {
  118. SpongeRng rng(Block("test_arithmetic"));
  119. Test test("Arithmetic");
  120. Scalar x(0),y(0),z(0);
  121. arith_check(test,x,y,z,INT_MAX,(decaf_word_t)INT_MAX,"cast from max");
  122. arith_check(test,x,y,z,INT_MIN,-Scalar(1+(decaf_word_t)INT_MAX),"cast from min");
  123. for (int i=0; i<NTESTS*10 && test.passing_now; i++) {
  124. /* TODO: pathological cases */
  125. size_t sob = DECAF_255_SCALAR_BYTES + 8 - (i%16);
  126. Scalar x(rng.read(sob));
  127. Scalar y(rng.read(sob));
  128. Scalar z(rng.read(sob));
  129. arith_check(test,x,y,z,x+y,y+x,"commute add");
  130. arith_check(test,x,y,z,x,x+0,"ident add");
  131. arith_check(test,x,y,z,x,x-0,"ident sub");
  132. arith_check(test,x,y,z,x+(y+z),(x+y)+z,"assoc add");
  133. arith_check(test,x,y,z,x*(y+z),x*y + x*z,"distributive mul/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)*z,"assoc mul");
  136. arith_check(test,x,y,z,x*y,y*x,"commute mul");
  137. arith_check(test,x,y,z,x,x*1,"ident mul");
  138. arith_check(test,x,y,z,0,x*0,"mul by 0");
  139. arith_check(test,x,y,z,-x,x*-1,"mul by -1");
  140. arith_check(test,x,y,z,x+x,x*2,"mul by 2");
  141. if (i%20) continue;
  142. if (y!=0) arith_check(test,x,y,z,x*y/y,x,"invert");
  143. try {
  144. y = x/0;
  145. test.fail();
  146. printf(" Inverted zero!");
  147. print("x", x);
  148. print("y", y);
  149. } catch(CryptoException) {}
  150. }
  151. }
  152. static void test_elligator() {
  153. SpongeRng rng(Block("test_elligator"));
  154. Test test("Elligator");
  155. const int NHINTS = Group::REMOVED_COFACTOR * 2;
  156. SecureBuffer *alts[NHINTS];
  157. bool successes[NHINTS];
  158. SecureBuffer *alts2[NHINTS];
  159. bool successes2[NHINTS];
  160. for (int i=0; i<NTESTS/10 && (test.passing_now || i < 100); i++) {
  161. size_t len = (i % (2*Point::HASH_BYTES + 3));
  162. SecureBuffer b1(len);
  163. if (i!=Point::HASH_BYTES) rng.read(b1); /* special test case */
  164. if (i==1) b1[0] = 1; /* special case test */
  165. if (len >= Point::HASH_BYTES) b1[Point::HASH_BYTES-1] &= 0x7F; // FIXME MAGIC
  166. Point s = Point::from_hash(b1), ss=s;
  167. for (int j=0; j<(i&3); j++) ss = ss.debugging_torque();
  168. ss = ss.debugging_pscale(rng);
  169. bool good = false;
  170. for (int j=0; j<NHINTS; j++) {
  171. alts[j] = new SecureBuffer(len);
  172. alts2[j] = new SecureBuffer(len);
  173. if (len > Point::HASH_BYTES)
  174. memcpy(&(*alts[j])[Point::HASH_BYTES], &b1[Point::HASH_BYTES], len-Point::HASH_BYTES);
  175. if (len > Point::HASH_BYTES)
  176. memcpy(&(*alts2[j])[Point::HASH_BYTES], &b1[Point::HASH_BYTES], len-Point::HASH_BYTES);
  177. successes[j] = decaf_successful( s.invert_elligator(*alts[j], j));
  178. successes2[j] = decaf_successful(ss.invert_elligator(*alts2[j],j));
  179. if (successes[j] != successes2[j]
  180. || (successes[j] && successes2[j] && *alts[j] != *alts2[j])
  181. ) {
  182. test.fail();
  183. printf(" Unscalable Elligator inversion: i=%d, hint=%d, s=%d,%d\n",i,j,
  184. -int(successes[j]),-int(successes2[j]));
  185. hexprint("x",b1);
  186. hexprint("X",*alts[j]);
  187. hexprint("X",*alts2[j]);
  188. }
  189. if (successes[j]) {
  190. good = good || (b1 == *alts[j]);
  191. for (int k=0; k<j; k++) {
  192. if (successes[k] && *alts[j] == *alts[k]) {
  193. test.fail();
  194. printf(" Duplicate Elligator inversion: i=%d, hints=%d, %d\n",i,j,k);
  195. hexprint("x",b1);
  196. hexprint("X",*alts[j]);
  197. }
  198. }
  199. if (s != Point::from_hash(*alts[j])) {
  200. test.fail();
  201. printf(" Fail Elligator inversion round-trip: i=%d, hint=%d %s\n",i,j,
  202. (s==-Point::from_hash(*alts[j])) ? "[output was -input]": "");
  203. hexprint("x",b1);
  204. hexprint("X",*alts[j]);
  205. }
  206. }
  207. }
  208. if (!good) {
  209. test.fail();
  210. printf(" %s Elligator inversion: i=%d\n",good ? "Passed" : "Failed", i);
  211. hexprint("B", b1);
  212. for (int j=0; j<NHINTS; j++) {
  213. printf(" %d: %s%s", j, successes[j] ? "succ" : "fail\n", (successes[j] && *alts[j] == b1) ? " [x]" : "");
  214. if (successes[j]) {
  215. hexprint("b", *alts[j]);
  216. }
  217. }
  218. printf("\n");
  219. }
  220. for (int j=0; j<NHINTS; j++) {
  221. delete alts[j];
  222. alts[j] = NULL;
  223. delete alts2[j];
  224. alts2[j] = NULL;
  225. }
  226. Point t(rng);
  227. point_check(test,t,t,t,0,0,t,Point::from_hash(t.steg_encode(rng)),"steg round-trip");
  228. }
  229. }
  230. static void test_ec() {
  231. SpongeRng rng(Block("test_ec"));
  232. Test test("EC");
  233. Point id = Point::identity(), base = Point::base();
  234. point_check(test,id,id,id,0,0,Point::from_hash(""),id,"fh0");
  235. if (Group::FIELD_MODULUS_TYPE == 3) {
  236. /* When p == 3 mod 4, the QNR is -1, so u*1^2 = -1 also produces the
  237. * identity.
  238. */
  239. point_check(test,id,id,id,0,0,Point::from_hash("\x01"),id,"fh1");
  240. }
  241. for (int i=0; i<NTESTS && test.passing_now; i++) {
  242. /* TODO: pathological cases */
  243. Scalar x(rng);
  244. Scalar y(rng);
  245. Point p(rng);
  246. Point q(rng);
  247. Point d1, d2;
  248. SecureBuffer buffer(2*Point::HASH_BYTES);
  249. rng.read(buffer);
  250. Point r = Point::from_hash(buffer);
  251. point_check(test,p,q,r,0,0,p,Point(p.serialize()),"round-trip");
  252. Point pp = p.debugging_torque().debugging_pscale(rng);
  253. if (!memeq(pp.serialize(),p.serialize())) {
  254. test.fail();
  255. printf("Fail torque seq test\n");
  256. }
  257. point_check(test,p,q,r,0,0,p,pp,"torque eq");
  258. point_check(test,p,q,r,0,0,p+q,q+p,"commute add");
  259. point_check(test,p,q,r,0,0,(p-q)+q,p,"correct sub");
  260. point_check(test,p,q,r,0,0,p+(q+r),(p+q)+r,"assoc add");
  261. point_check(test,p,q,r,0,0,p.times_two(),p+p,"dbl add");
  262. if (i%10) continue;
  263. point_check(test,p,q,r,x,0,x*(p+q),x*p+x*q,"distr mul");
  264. point_check(test,p,q,r,x,y,(x*y)*p,x*(y*p),"assoc mul");
  265. point_check(test,p,q,r,x,y,x*p+y*q,Point::double_scalarmul(x,p,y,q),"double mul");
  266. p.dual_scalarmul(d1,d2,x,y);
  267. point_check(test,p,q,r,x,y,x*p,d1,"dual mul 1");
  268. point_check(test,p,q,r,x,y,y*p,d2,"dual mul 2");
  269. point_check(test,base,q,r,x,y,x*base+y*q,q.non_secret_combo_with_base(y,x),"ds vt mul");
  270. point_check(test,p,q,r,x,0,Precomputed(p)*x,p*x,"precomp mul");
  271. point_check(test,p,q,r,0,0,r,
  272. Point::from_hash(Buffer(buffer).slice(0,Point::HASH_BYTES))
  273. + Point::from_hash(Buffer(buffer).slice(Point::HASH_BYTES,Point::HASH_BYTES)),
  274. "unih = hash+add"
  275. );
  276. point_check(test,p,q,r,x,0,Point(x.direct_scalarmul(p.serialize())),x*p,"direct mul");
  277. }
  278. }
  279. static void test_crypto() {
  280. Test test("Sample crypto");
  281. SpongeRng rng(Block("test_decaf_crypto"));
  282. for (int i=0; i<NTESTS && test.passing_now; i++) {
  283. PrivateKey<Group> priv1(rng), priv2(rng);
  284. PublicKey<Group> pub1(priv1), pub2(priv2);
  285. SecureBuffer message = rng.read(i);
  286. SecureBuffer sig(priv1.sign(message));
  287. pub1.verify(message, sig);
  288. SecureBuffer s1(priv1.sharedSecret(pub2,32,true));
  289. SecureBuffer s2(priv2.sharedSecret(pub1,32,false));
  290. if (memcmp(s1.data(),s2.data(),s1.size())) {
  291. test.fail();
  292. printf(" Shared secrets disagree.");
  293. }
  294. }
  295. }
  296. }; /* template<GroupId GROUP> */
  297. int main(int argc, char **argv) {
  298. (void) argc; (void) argv;
  299. printf("Testing %s:\n",IsoEd25519::name());
  300. Tests<IsoEd25519>::test_arithmetic();
  301. Tests<IsoEd25519>::test_elligator();
  302. Tests<IsoEd25519>::test_ec();
  303. Tests<IsoEd25519>::test_crypto();
  304. printf("\n");
  305. printf("Testing %s:\n", Ed448Goldilocks::name());
  306. Tests<Ed448Goldilocks>::test_arithmetic();
  307. Tests<Ed448Goldilocks>::test_elligator();
  308. Tests<Ed448Goldilocks>::test_ec();
  309. Tests<Ed448Goldilocks>::test_crypto();
  310. if (passing) printf("Passed all tests.\n");
  311. return passing ? 0 : 1;
  312. }