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.
 
 
 
 
 

289 lines
9.0 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 "shake.hxx"
  13. #include "decaf_crypto.h"
  14. #include <stdio.h>
  15. static bool passing = true;
  16. static const long NTESTS = 10000;
  17. class Test {
  18. public:
  19. bool passing_now;
  20. Test(const char *test) {
  21. passing_now = true;
  22. printf("%s...", test);
  23. if (strlen(test) < 27) printf("%*s",int(27-strlen(test)),"");
  24. fflush(stdout);
  25. }
  26. ~Test() {
  27. if (std::uncaught_exception()) {
  28. fail();
  29. printf(" due to uncaught exception.\n");
  30. }
  31. if (passing_now) printf("[PASS]\n");
  32. }
  33. void fail() {
  34. if (!passing_now) return;
  35. passing_now = passing = false;
  36. printf("[FAIL]\n");
  37. }
  38. };
  39. template<typename Group> struct Tests {
  40. typedef typename Group::Scalar Scalar;
  41. typedef typename Group::Point Point;
  42. typedef typename Group::Precomputed Precomputed;
  43. static void print(const char *name, const Scalar &x) {
  44. unsigned char buffer[Scalar::SER_BYTES];
  45. x.encode(buffer);
  46. printf(" %s = 0x", name);
  47. for (int i=sizeof(buffer)-1; i>=0; i--) {
  48. printf("%02x", buffer[i]);
  49. }
  50. printf("\n");
  51. }
  52. static void print(const char *name, const Point &x) {
  53. unsigned char buffer[Point::SER_BYTES];
  54. x.encode(buffer);
  55. printf(" %s = 0x", name);
  56. for (int i=sizeof(buffer)-1; i>=0; i--) {
  57. printf("%02x", buffer[i]);
  58. }
  59. printf("\n");
  60. }
  61. static bool arith_check(
  62. Test &test,
  63. const Scalar &x,
  64. const Scalar &y,
  65. const Scalar &z,
  66. const Scalar &r,
  67. const Scalar &l,
  68. const char *name
  69. ) {
  70. if (l == r) return true;
  71. test.fail();
  72. printf(" %s", name);
  73. print("x", x);
  74. print("y", y);
  75. print("z", z);
  76. print("lhs", r);
  77. print("rhs", l);
  78. return false;
  79. }
  80. static bool point_check(
  81. Test &test,
  82. const Point &p,
  83. const Point &q,
  84. const Point &R,
  85. const Scalar &x,
  86. const Scalar &y,
  87. const Point &l,
  88. const Point &r,
  89. const char *name
  90. ) {
  91. bool good = l==r;
  92. if (!p.validate()) { good = false; printf(" p invalid\n"); }
  93. if (!q.validate()) { good = false; printf(" q invalid\n"); }
  94. if (!r.validate()) { good = false; printf(" r invalid\n"); }
  95. if (!l.validate()) { good = false; printf(" l invalid\n"); }
  96. if (good) return true;
  97. test.fail();
  98. printf(" %s", name);
  99. print("x", x);
  100. print("y", y);
  101. print("p", p);
  102. print("q", q);
  103. print("r", R);
  104. print("lhs", l);
  105. print("rhs", r);
  106. return false;
  107. }
  108. static void test_arithmetic() {
  109. decaf::SpongeRng rng(decaf::Block("test_arithmetic"));
  110. Test test("Arithmetic");
  111. Scalar x(0),y(0),z(0);
  112. arith_check(test,x,y,z,INT_MAX,(decaf_word_t)INT_MAX,"cast from max");
  113. arith_check(test,x,y,z,INT_MIN,-Scalar(1+(decaf_word_t)INT_MAX),"cast from min");
  114. for (int i=0; i<NTESTS*10 && test.passing_now; i++) {
  115. /* TODO: pathological cases */
  116. size_t sob = DECAF_255_SCALAR_BYTES + 8 - (i%16);
  117. Scalar x(rng.read(sob));
  118. Scalar y(rng.read(sob));
  119. Scalar z(rng.read(sob));
  120. arith_check(test,x,y,z,x+y,y+x,"commute add");
  121. arith_check(test,x,y,z,x,x+0,"ident add");
  122. arith_check(test,x,y,z,x,x-0,"ident sub");
  123. arith_check(test,x,y,z,x+(y+z),(x+y)+z,"assoc add");
  124. arith_check(test,x,y,z,x*(y+z),x*y + x*z,"distributive mul/add");
  125. arith_check(test,x,y,z,x*(y-z),x*y - x*z,"distributive mul/add");
  126. arith_check(test,x,y,z,x*(y*z),(x*y)*z,"assoc mul");
  127. arith_check(test,x,y,z,x*y,y*x,"commute mul");
  128. arith_check(test,x,y,z,x,x*1,"ident mul");
  129. arith_check(test,x,y,z,0,x*0,"mul by 0");
  130. arith_check(test,x,y,z,-x,x*-1,"mul by -1");
  131. arith_check(test,x,y,z,x+x,x*2,"mul by 2");
  132. if (i%20) continue;
  133. if (y!=0) arith_check(test,x,y,z,x*y/y,x,"invert");
  134. arith_check(test,x,y,z,x/0,0,"invert0");
  135. }
  136. }
  137. static void test_elligator() {
  138. decaf::SpongeRng rng(decaf::Block("test_elligator"));
  139. Test test("Elligator");
  140. for (int i=0; i<16; i++) {
  141. decaf::SecureBuffer b1(Point::HASH_BYTES);
  142. Point p = Point::identity();
  143. if (i>=8) p.debugging_torque_in_place();
  144. bool succ = p.invert_elligator(b1,i&7);
  145. Point q;
  146. unsigned char hint = q.set_to_hash(b1);
  147. if (succ != ((i&7) != 4) || (q != p) || (succ && (hint != (i&7)))) {
  148. test.fail();
  149. printf("Elligator test: t=%d, h=%d->%d, q%sp, %s %02x%02x\n",
  150. i/8, i&7, hint, (q==p)?"==":"!=",succ ? "SUCC" : "FAIL",
  151. b1[0], b1[1]);
  152. }
  153. }
  154. for (int i=0; i<NTESTS /*&& test.passing_now*/; i++) {
  155. size_t len = (i % (2*Point::HASH_BYTES + 3));
  156. decaf::SecureBuffer b1(len), b2(len);
  157. rng.read(b1);
  158. if (i==1) b1[0] = 1; /* special case test */
  159. if (len > Point::HASH_BYTES)
  160. memcpy(&b2[Point::HASH_BYTES], &b1[Point::HASH_BYTES], len-Point::HASH_BYTES);
  161. Point s;
  162. unsigned char hint = s.set_to_hash(b1);
  163. if (i&1) s.debugging_torque_in_place();
  164. bool succ = s.invert_elligator(b2,hint);
  165. if (!succ || memcmp(b1,b2,len)) {
  166. test.fail();
  167. printf(" Fail elligator inversion i=%d, len=%d (claimed %s, hint=0x%02x)\n",
  168. i, (int)len, succ ? "success" : "failure", hint);
  169. }
  170. // Point t(rng);
  171. //point_check(test,t,t,t,0,0,t,Point::from_hash(t.steg_encode(rng)),"steg round-trip");
  172. }
  173. }
  174. static void test_ec() {
  175. decaf::SpongeRng rng(decaf::Block("test_ec"));
  176. Test test("EC");
  177. Point id = Point::identity(), base = Point::base();
  178. point_check(test,id,id,id,0,0,Point::from_hash(""),id,"fh0");
  179. //point_check(test,id,id,id,0,0,Point::from_hash("\x01"),id,"fh1"); // FIXME
  180. for (int i=0; i<NTESTS && test.passing_now; i++) {
  181. /* TODO: pathological cases */
  182. Scalar x(rng);
  183. Scalar y(rng);
  184. Point p(rng);
  185. Point q(rng);
  186. decaf::SecureBuffer buffer(2*Point::HASH_BYTES);
  187. rng.read(buffer);
  188. Point r = Point::from_hash(buffer);
  189. point_check(test,p,q,r,0,0,p,Point((decaf::SecureBuffer)p),"round-trip");
  190. point_check(test,p,q,r,0,0,p+q,q+p,"commute add");
  191. point_check(test,p,q,r,0,0,(p-q)+q,p,"correct sub");
  192. point_check(test,p,q,r,0,0,p+(q+r),(p+q)+r,"assoc add");
  193. point_check(test,p,q,r,0,0,p.times_two(),p+p,"dbl add");
  194. if (i%10) continue;
  195. point_check(test,p,q,r,x,0,x*(p+q),x*p+x*q,"distr mul");
  196. point_check(test,p,q,r,x,y,(x*y)*p,x*(y*p),"assoc mul");
  197. point_check(test,p,q,r,x,y,x*p+y*q,Point::double_scalarmul(x,p,y,q),"ds mul");
  198. point_check(test,base,q,r,x,y,x*base+y*q,q.non_secret_combo_with_base(y,x),"ds vt mul");
  199. point_check(test,p,q,r,x,0,Precomputed(p)*x,p*x,"precomp mul");
  200. point_check(test,p,q,r,0,0,r,
  201. Point::from_hash(buffer.slice(0,Point::HASH_BYTES))
  202. + Point::from_hash(buffer.slice(Point::HASH_BYTES,Point::HASH_BYTES)),
  203. "unih = hash+add"
  204. );
  205. point_check(test,p,q,r,x,0,Point(x.direct_scalarmul(decaf::SecureBuffer(p))),x*p,"direct mul");
  206. }
  207. }
  208. }; // template<decaf::GroupId GROUP>
  209. static void test_decaf() {
  210. Test test("Sample crypto");
  211. decaf::SpongeRng rng(decaf::Block("test_decaf"));
  212. decaf_255_symmetric_key_t proto1,proto2;
  213. decaf_255_private_key_t s1,s2;
  214. decaf_255_public_key_t p1,p2;
  215. decaf_255_signature_t sig;
  216. unsigned char shared1[1234],shared2[1234];
  217. const char *message = "Hello, world!";
  218. for (int i=0; i<NTESTS && test.passing_now; i++) {
  219. rng.read(decaf::TmpBuffer(proto1,sizeof(proto1)));
  220. rng.read(decaf::TmpBuffer(proto2,sizeof(proto2)));
  221. decaf_255_derive_private_key(s1,proto1);
  222. decaf_255_private_to_public(p1,s1);
  223. decaf_255_derive_private_key(s2,proto2);
  224. decaf_255_private_to_public(p2,s2);
  225. if (!decaf_255_shared_secret (shared1,sizeof(shared1),s1,p2)) {
  226. test.fail(); printf("Fail ss12\n");
  227. }
  228. if (!decaf_255_shared_secret (shared2,sizeof(shared2),s2,p1)) {
  229. test.fail(); printf("Fail ss21\n");
  230. }
  231. if (memcmp(shared1,shared2,sizeof(shared1))) {
  232. test.fail(); printf("Fail ss21 == ss12\n");
  233. }
  234. decaf_255_sign (sig,s1,(const unsigned char *)message,strlen(message));
  235. if (!decaf_255_verify (sig,p1,(const unsigned char *)message,strlen(message))) {
  236. test.fail(); printf("Fail sig ver\n");
  237. }
  238. }
  239. }
  240. int main(int argc, char **argv) {
  241. (void) argc; (void) argv;
  242. Tests<decaf::Ed255>::test_arithmetic();
  243. Tests<decaf::Ed255>::test_elligator();
  244. Tests<decaf::Ed255>::test_ec();
  245. test_decaf();
  246. if (passing) printf("Passed all tests.\n");
  247. return passing ? 0 : 1;
  248. }