crypto_ecc_dlog.c 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 2012, 2013, 2015 GNUnet e.V.
  4. GNUnet is free software: you can redistribute it and/or modify it
  5. under the terms of the GNU Affero General Public License as published
  6. by the Free Software Foundation, either version 3 of the License,
  7. or (at your option) any later version.
  8. GNUnet is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Affero General Public License for more details.
  12. You should have received a copy of the GNU Affero General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. SPDX-License-Identifier: AGPL3.0-or-later
  15. */
  16. /**
  17. * @file util/crypto_ecc_dlog.c
  18. * @brief ECC addition and discreate logarithm for small values.
  19. * Allows us to use ECC for computations as long as the
  20. * result is relativey small.
  21. * @author Christian Grothoff
  22. */
  23. #include "platform.h"
  24. #include <gcrypt.h>
  25. #include "gnunet_crypto_lib.h"
  26. #include "gnunet_container_lib.h"
  27. /**
  28. * Internal structure used to cache pre-calculated values for DLOG calculation.
  29. */
  30. struct GNUNET_CRYPTO_EccDlogContext
  31. {
  32. /**
  33. * Maximum absolute value the calculation supports.
  34. */
  35. unsigned int max;
  36. /**
  37. * How much memory should we use (relates to the number of entries in the map).
  38. */
  39. unsigned int mem;
  40. /**
  41. * Map mapping points (here "interpreted" as EdDSA public keys) to
  42. * a "void * = long" which corresponds to the numeric value of the
  43. * point. As NULL is used to represent "unknown", the actual value
  44. * represented by the entry in the map is the "long" minus @e max.
  45. */
  46. struct GNUNET_CONTAINER_MultiPeerMap *map;
  47. /**
  48. * Context to use for operations on the elliptic curve.
  49. */
  50. gcry_ctx_t ctx;
  51. };
  52. struct GNUNET_CRYPTO_EccDlogContext *
  53. GNUNET_CRYPTO_ecc_dlog_prepare (unsigned int max,
  54. unsigned int mem)
  55. {
  56. struct GNUNET_CRYPTO_EccDlogContext *edc;
  57. int K = ((max + (mem - 1)) / mem);
  58. GNUNET_assert (max < INT32_MAX);
  59. edc = GNUNET_new (struct GNUNET_CRYPTO_EccDlogContext);
  60. edc->max = max;
  61. edc->mem = mem;
  62. edc->map = GNUNET_CONTAINER_multipeermap_create (mem * 2,
  63. GNUNET_NO);
  64. for (int i = -(int) mem; i <= (int) mem; i++)
  65. {
  66. struct GNUNET_CRYPTO_EccScalar Ki;
  67. struct GNUNET_PeerIdentity key;
  68. GNUNET_CRYPTO_ecc_scalar_from_int (K * i,
  69. &Ki);
  70. if (0 == i) /* libsodium does not like to multiply with zero */
  71. GNUNET_assert (
  72. 0 ==
  73. crypto_core_ed25519_sub ((unsigned char *) &key,
  74. (unsigned char *) &key,
  75. (unsigned char *) &key));
  76. else
  77. GNUNET_assert (
  78. 0 ==
  79. crypto_scalarmult_ed25519_base_noclamp ((unsigned char*) &key,
  80. Ki.v));
  81. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  82. "K*i: %d (mem=%u, i=%d) => %s\n",
  83. K * i,
  84. mem,
  85. i,
  86. GNUNET_i2s (&key));
  87. GNUNET_assert (GNUNET_OK ==
  88. GNUNET_CONTAINER_multipeermap_put (edc->map,
  89. &key,
  90. (void *) (long) i + max,
  91. GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
  92. }
  93. return edc;
  94. }
  95. int
  96. GNUNET_CRYPTO_ecc_dlog (struct GNUNET_CRYPTO_EccDlogContext *edc,
  97. const struct GNUNET_CRYPTO_EccPoint *input)
  98. {
  99. unsigned int K = ((edc->max + (edc->mem - 1)) / edc->mem);
  100. int res;
  101. struct GNUNET_CRYPTO_EccPoint g;
  102. struct GNUNET_CRYPTO_EccPoint q;
  103. struct GNUNET_CRYPTO_EccPoint nq;
  104. {
  105. struct GNUNET_CRYPTO_EccScalar fact;
  106. memset (&fact,
  107. 0,
  108. sizeof (fact));
  109. sodium_increment (fact.v,
  110. sizeof (fact.v));
  111. GNUNET_assert (0 ==
  112. crypto_scalarmult_ed25519_base_noclamp (g.v,
  113. fact.v));
  114. }
  115. /* make compiler happy: initialize q and nq, technically not needed! */
  116. memset (&q,
  117. 0,
  118. sizeof (q));
  119. memset (&nq,
  120. 0,
  121. sizeof (nq));
  122. res = INT_MAX;
  123. for (unsigned int i = 0; i <= edc->max / edc->mem; i++)
  124. {
  125. struct GNUNET_PeerIdentity key;
  126. void *retp;
  127. GNUNET_assert (sizeof (key) == crypto_scalarmult_BYTES);
  128. if (0 == i)
  129. {
  130. memcpy (&key,
  131. input,
  132. sizeof (key));
  133. }
  134. else
  135. {
  136. memcpy (&key,
  137. &q,
  138. sizeof (key));
  139. }
  140. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  141. "Trying offset i=%u): %s\n",
  142. i,
  143. GNUNET_i2s (&key));
  144. retp = GNUNET_CONTAINER_multipeermap_get (edc->map,
  145. &key);
  146. if (NULL != retp)
  147. {
  148. res = (((long) retp) - edc->max) * K - i;
  149. /* we continue the loop here to make the implementation
  150. "constant-time". If we do not care about this, we could just
  151. 'break' here and do fewer operations... */
  152. }
  153. if (i == edc->max / edc->mem)
  154. break;
  155. /* q = q + g */
  156. if (0 == i)
  157. {
  158. GNUNET_assert (0 ==
  159. crypto_core_ed25519_add (q.v,
  160. input->v,
  161. g.v));
  162. }
  163. else
  164. {
  165. GNUNET_assert (0 ==
  166. crypto_core_ed25519_add (q.v,
  167. q.v,
  168. g.v));
  169. }
  170. }
  171. return res;
  172. }
  173. void
  174. GNUNET_CRYPTO_ecc_random_mod_n (struct GNUNET_CRYPTO_EccScalar *r)
  175. {
  176. crypto_core_ed25519_scalar_random (r->v);
  177. }
  178. void
  179. GNUNET_CRYPTO_ecc_dlog_release (struct GNUNET_CRYPTO_EccDlogContext *edc)
  180. {
  181. GNUNET_CONTAINER_multipeermap_destroy (edc->map);
  182. GNUNET_free (edc);
  183. }
  184. void
  185. GNUNET_CRYPTO_ecc_dexp (int val,
  186. struct GNUNET_CRYPTO_EccPoint *r)
  187. {
  188. struct GNUNET_CRYPTO_EccScalar fact;
  189. GNUNET_CRYPTO_ecc_scalar_from_int (val,
  190. &fact);
  191. crypto_scalarmult_ed25519_base_noclamp (r->v,
  192. fact.v);
  193. }
  194. enum GNUNET_GenericReturnValue
  195. GNUNET_CRYPTO_ecc_dexp_mpi (const struct GNUNET_CRYPTO_EccScalar *val,
  196. struct GNUNET_CRYPTO_EccPoint *r)
  197. {
  198. if (0 ==
  199. crypto_scalarmult_ed25519_base_noclamp (r->v,
  200. val->v))
  201. return GNUNET_OK;
  202. return GNUNET_SYSERR;
  203. }
  204. enum GNUNET_GenericReturnValue
  205. GNUNET_CRYPTO_ecc_add (const struct GNUNET_CRYPTO_EccPoint *a,
  206. const struct GNUNET_CRYPTO_EccPoint *b,
  207. struct GNUNET_CRYPTO_EccPoint *r)
  208. {
  209. if (0 ==
  210. crypto_core_ed25519_add (r->v,
  211. a->v,
  212. b->v))
  213. return GNUNET_OK;
  214. return GNUNET_SYSERR;
  215. }
  216. enum GNUNET_GenericReturnValue
  217. GNUNET_CRYPTO_ecc_pmul_mpi (const struct GNUNET_CRYPTO_EccPoint *p,
  218. const struct GNUNET_CRYPTO_EccScalar *val,
  219. struct GNUNET_CRYPTO_EccPoint *r)
  220. {
  221. if (0 ==
  222. crypto_scalarmult_ed25519_noclamp (r->v,
  223. val->v,
  224. p->v))
  225. return GNUNET_OK;
  226. return GNUNET_SYSERR;
  227. }
  228. enum GNUNET_GenericReturnValue
  229. GNUNET_CRYPTO_ecc_rnd (struct GNUNET_CRYPTO_EccPoint *r,
  230. struct GNUNET_CRYPTO_EccPoint *r_inv)
  231. {
  232. struct GNUNET_CRYPTO_EccScalar s;
  233. unsigned char inv_s[crypto_scalarmult_ed25519_SCALARBYTES];
  234. GNUNET_CRYPTO_ecc_random_mod_n (&s);
  235. if (0 !=
  236. crypto_scalarmult_ed25519_base_noclamp (r->v,
  237. s.v))
  238. return GNUNET_SYSERR;
  239. crypto_core_ed25519_scalar_negate (inv_s,
  240. s.v);
  241. if (0 !=
  242. crypto_scalarmult_ed25519_base_noclamp (r_inv->v,
  243. inv_s))
  244. return GNUNET_SYSERR;
  245. return GNUNET_OK;
  246. }
  247. void
  248. GNUNET_CRYPTO_ecc_rnd_mpi (struct GNUNET_CRYPTO_EccScalar *r,
  249. struct GNUNET_CRYPTO_EccScalar *r_neg)
  250. {
  251. GNUNET_CRYPTO_ecc_random_mod_n (r);
  252. crypto_core_ed25519_scalar_negate (r_neg->v,
  253. r->v);
  254. }
  255. void
  256. GNUNET_CRYPTO_ecc_scalar_from_int (int64_t val,
  257. struct GNUNET_CRYPTO_EccScalar *r)
  258. {
  259. unsigned char fact[crypto_scalarmult_ed25519_SCALARBYTES];
  260. uint64_t valBe;
  261. GNUNET_assert (sizeof (*r) == sizeof (fact));
  262. if (val < 0)
  263. {
  264. if (INT64_MIN == val)
  265. valBe = GNUNET_htonll ((uint64_t) INT64_MAX);
  266. else
  267. valBe = GNUNET_htonll ((uint64_t) (-val));
  268. }
  269. else
  270. {
  271. valBe = GNUNET_htonll ((uint64_t) val);
  272. }
  273. memset (fact,
  274. 0,
  275. sizeof (fact));
  276. for (unsigned int i = 0; i < sizeof (val); i++)
  277. fact[i] = ((unsigned char*) &valBe)[sizeof (val) - 1 - i];
  278. if (val < 0)
  279. {
  280. if (INT64_MIN == val)
  281. /* See above: fact is one too small, increment now that we can */
  282. sodium_increment (fact,
  283. sizeof (fact));
  284. crypto_core_ed25519_scalar_negate (r->v,
  285. fact);
  286. }
  287. else
  288. {
  289. memcpy (r,
  290. fact,
  291. sizeof (fact));
  292. }
  293. }
  294. /* end of crypto_ecc_dlog.c */