aboutsummaryrefslogtreecommitdiff
path: root/src/util/crypto_ecc_dlog.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2015-07-06 14:22:51 +0000
committerChristian Grothoff <christian@grothoff.org>2015-07-06 14:22:51 +0000
commit0f9e6bcd1e511abae16ecc4c86056b0c26d73936 (patch)
tree4ba3af76391ee6c67563316de29b6ad8830cd7f2 /src/util/crypto_ecc_dlog.c
parentf1e619572751f7652db025f66f119d6a0308114b (diff)
downloadgnunet-0f9e6bcd1e511abae16ecc4c86056b0c26d73936.tar.gz
gnunet-0f9e6bcd1e511abae16ecc4c86056b0c26d73936.zip
-fix non-deterministic peerstore sync failure
Diffstat (limited to 'src/util/crypto_ecc_dlog.c')
-rw-r--r--src/util/crypto_ecc_dlog.c231
1 files changed, 220 insertions, 11 deletions
diff --git a/src/util/crypto_ecc_dlog.c b/src/util/crypto_ecc_dlog.c
index 34f3c203d..3a2a91532 100644
--- a/src/util/crypto_ecc_dlog.c
+++ b/src/util/crypto_ecc_dlog.c
@@ -20,11 +20,10 @@
20 20
21/** 21/**
22 * @file util/crypto_ecc_dlog.c 22 * @file util/crypto_ecc_dlog.c
23 * @brief ECC discreate logarithm for small values 23 * @brief ECC addition and discreate logarithm for small values.
24 * Allows us to use ECC for computations as long as the
25 * result is relativey small.
24 * @author Christian Grothoff 26 * @author Christian Grothoff
25 *
26 * TODO:
27 * - support negative factors
28 */ 27 */
29#include "platform.h" 28#include "platform.h"
30#include <gcrypt.h> 29#include <gcrypt.h>
@@ -66,9 +65,27 @@ extract_pk (gcry_mpi_point_t pt,
66 */ 65 */
67struct GNUNET_CRYPTO_EccDlogContext 66struct GNUNET_CRYPTO_EccDlogContext
68{ 67{
68 /**
69 * Maximum absolute value the calculation supports.
70 */
69 unsigned int max; 71 unsigned int max;
72
73 /**
74 * How much memory should we use (relates to the number of entries in the map).
75 */
70 unsigned int mem; 76 unsigned int mem;
77
78 /**
79 * Map mapping points (here "interpreted" as EdDSA public keys) to
80 * a "void * = long" which corresponds to the numeric value of the
81 * point. As NULL is used to represent "unknown", the actual value
82 * represented by the entry in the map is the "long" minus @e max.
83 */
71 struct GNUNET_CONTAINER_MultiPeerMap *map; 84 struct GNUNET_CONTAINER_MultiPeerMap *map;
85
86 /**
87 * Context to use for operations on the elliptic curve.
88 */
72 gcry_ctx_t ctx; 89 gcry_ctx_t ctx;
73 90
74}; 91};
@@ -91,8 +108,10 @@ GNUNET_CRYPTO_ecc_dlog_prepare (unsigned int max,
91 struct GNUNET_PeerIdentity key; 108 struct GNUNET_PeerIdentity key;
92 gcry_mpi_point_t gKi; 109 gcry_mpi_point_t gKi;
93 gcry_mpi_t fact; 110 gcry_mpi_t fact;
111 gcry_mpi_t n;
94 unsigned int i; 112 unsigned int i;
95 113
114 GNUNET_assert (max < INT32_MAX);
96 edc = GNUNET_new (struct GNUNET_CRYPTO_EccDlogContext); 115 edc = GNUNET_new (struct GNUNET_CRYPTO_EccDlogContext);
97 edc->max = max; 116 edc->max = max;
98 edc->mem = mem; 117 edc->mem = mem;
@@ -115,10 +134,25 @@ GNUNET_CRYPTO_ecc_dlog_prepare (unsigned int max,
115 GNUNET_assert (GNUNET_OK == 134 GNUNET_assert (GNUNET_OK ==
116 GNUNET_CONTAINER_multipeermap_put (edc->map, 135 GNUNET_CONTAINER_multipeermap_put (edc->map,
117 &key, 136 &key,
118 (void*) (long) i + 1, 137 (void*) (long) i + max,
138 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
139 }
140 /* negative values */
141 n = gcry_mpi_ec_get_mpi ("n", edc->ctx, 1);
142 for (i=1;i<mem;i++)
143 {
144 gcry_mpi_set_ui (fact, i * K);
145 gcry_mpi_sub (fact, n, fact);
146 gcry_mpi_ec_mul (gKi, fact, g, edc->ctx);
147 extract_pk (gKi, edc->ctx, &key);
148 GNUNET_assert (GNUNET_OK ==
149 GNUNET_CONTAINER_multipeermap_put (edc->map,
150 &key,
151 (void*) (long) max - i,
119 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); 152 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
120 } 153 }
121 gcry_mpi_release (fact); 154 gcry_mpi_release (fact);
155 gcry_mpi_release (n);
122 gcry_mpi_point_release (gKi); 156 gcry_mpi_point_release (gKi);
123 gcry_mpi_point_release (g); 157 gcry_mpi_point_release (g);
124 return edc; 158 return edc;
@@ -132,7 +166,7 @@ GNUNET_CRYPTO_ecc_dlog_prepare (unsigned int max,
132 * @param input point on the curve to factor 166 * @param input point on the curve to factor
133 * @return `edc->max` if dlog failed, otherwise the factor 167 * @return `edc->max` if dlog failed, otherwise the factor
134 */ 168 */
135unsigned int 169int
136GNUNET_CRYPTO_ecc_dlog (struct GNUNET_CRYPTO_EccDlogContext *edc, 170GNUNET_CRYPTO_ecc_dlog (struct GNUNET_CRYPTO_EccDlogContext *edc,
137 gcry_mpi_point_t input) 171 gcry_mpi_point_t input)
138{ 172{
@@ -141,7 +175,7 @@ GNUNET_CRYPTO_ecc_dlog (struct GNUNET_CRYPTO_EccDlogContext *edc,
141 struct GNUNET_PeerIdentity key; 175 struct GNUNET_PeerIdentity key;
142 gcry_mpi_point_t q; 176 gcry_mpi_point_t q;
143 unsigned int i; 177 unsigned int i;
144 unsigned int res; 178 int res;
145 void *retp; 179 void *retp;
146 180
147 g = gcry_mpi_ec_get_point ("g", edc->ctx, 0); 181 g = gcry_mpi_ec_get_point ("g", edc->ctx, 0);
@@ -159,10 +193,10 @@ GNUNET_CRYPTO_ecc_dlog (struct GNUNET_CRYPTO_EccDlogContext *edc,
159 &key); 193 &key);
160 if (NULL != retp) 194 if (NULL != retp)
161 { 195 {
162 res = (((long) retp) - 1) * K - i; 196 res = (((long) retp) - edc->max) * K - i;
163 fprintf (stderr, 197 /* we continue the loop here to make the implementation
164 "Got DLOG %u\n", 198 "constant-time". If we do not care about this, we could just
165 res); 199 'break' here and do fewer operations... */
166 } 200 }
167 if (i == edc->max/edc->mem) 201 if (i == edc->max/edc->mem)
168 break; 202 break;
@@ -180,6 +214,40 @@ GNUNET_CRYPTO_ecc_dlog (struct GNUNET_CRYPTO_EccDlogContext *edc,
180 214
181 215
182/** 216/**
217 * Generate a random value mod n.
218 *
219 * @param edc ECC context
220 * @return random value mod n.
221 */
222gcry_mpi_t
223GNUNET_CRYPTO_ecc_random_mod_n (struct GNUNET_CRYPTO_EccDlogContext *edc)
224{
225 gcry_mpi_t n;
226 unsigned int highbit;
227 gcry_mpi_t r;
228
229 n = gcry_mpi_ec_get_mpi ("n", edc->ctx, 1);
230
231 /* check public key for number of bits, bail out if key is all zeros */
232 highbit = 256; /* Curve25519 */
233 while ( (! gcry_mpi_test_bit (n, highbit)) &&
234 (0 != highbit) )
235 highbit--;
236 GNUNET_assert (0 != highbit);
237 /* generate fact < n (without bias) */
238 GNUNET_assert (NULL != (r = gcry_mpi_new (0)));
239 do {
240 gcry_mpi_randomize (r,
241 highbit + 1,
242 GCRY_STRONG_RANDOM);
243 }
244 while (gcry_mpi_cmp (r, n) >= 0);
245 gcry_mpi_release (n);
246 return r;
247}
248
249
250/**
183 * Release precalculated values. 251 * Release precalculated values.
184 * 252 *
185 * @param edc dlog context 253 * @param edc dlog context
@@ -191,6 +259,147 @@ GNUNET_CRYPTO_ecc_dlog_release (struct GNUNET_CRYPTO_EccDlogContext *edc)
191 GNUNET_CONTAINER_multipeermap_destroy (edc->map); 259 GNUNET_CONTAINER_multipeermap_destroy (edc->map);
192 GNUNET_free (edc); 260 GNUNET_free (edc);
193} 261}
262
263
264/**
265 * Multiply the generator g of the elliptic curve by @a val
266 * to obtain the point on the curve representing @a val.
267 * Afterwards, point addition will correspond to integer
268 * addition. #GNUNET_CRYPTO_ecc_dlog() can be used to
269 * convert a point back to an integer (as long as the
270 * integer is smaller than the MAX of the @a edc context).
271 *
272 * @param edc calculation context for ECC operations
273 * @param val value to encode into a point
274 * @return representation of the value as an ECC point,
275 * must be freed using #GNUNET_CRYPTO_ecc_free()
276 */
277gcry_mpi_point_t
278GNUNET_CRYPTO_ecc_dexp (struct GNUNET_CRYPTO_EccDlogContext *edc,
279 int val)
280{
281 gcry_mpi_t fact;
282 gcry_mpi_t n;
283 gcry_mpi_point_t g;
284 gcry_mpi_point_t r;
285
286 g = gcry_mpi_ec_get_point ("g", edc->ctx, 0);
287 GNUNET_assert (NULL != g);
288 fact = gcry_mpi_new (0);
289 if (val < 0)
290 {
291 n = gcry_mpi_ec_get_mpi ("n", edc->ctx, 1);
292 gcry_mpi_set_ui (fact, - val);
293 gcry_mpi_sub (fact, n, fact);
294 gcry_mpi_release (n);
295 }
296 else
297 {
298 gcry_mpi_set_ui (fact, val);
299 }
300 r = gcry_mpi_point_new (0);
301 gcry_mpi_ec_mul (r, fact, g, edc->ctx);
302 gcry_mpi_release (fact);
303 gcry_mpi_point_release (g);
304 return r;
305}
306
307
308/**
309 * Multiply the generator g of the elliptic curve by @a val
310 * to obtain the point on the curve representing @a val.
311 *
312 * @param edc calculation context for ECC operations
313 * @param val (positive) value to encode into a point
314 * @return representation of the value as an ECC point,
315 * must be freed using #GNUNET_CRYPTO_ecc_free()
316 */
317gcry_mpi_point_t
318GNUNET_CRYPTO_ecc_dexp_mpi (struct GNUNET_CRYPTO_EccDlogContext *edc,
319 gcry_mpi_t val)
320{
321 gcry_mpi_point_t g;
322 gcry_mpi_point_t r;
323
324 g = gcry_mpi_ec_get_point ("g", edc->ctx, 0);
325 GNUNET_assert (NULL != g);
326 r = gcry_mpi_point_new (0);
327 gcry_mpi_ec_mul (r, val, g, edc->ctx);
328 gcry_mpi_point_release (g);
329 return r;
330}
331
332
333/**
334 * Add two points on the elliptic curve.
335 *
336 * @param edc calculation context for ECC operations
337 * @param a some value
338 * @param b some value
339 * @return @a a + @a b, must be freed using #GNUNET_CRYPTO_ecc_free()
340 */
341gcry_mpi_point_t
342GNUNET_CRYPTO_ecc_add (struct GNUNET_CRYPTO_EccDlogContext *edc,
343 gcry_mpi_point_t a,
344 gcry_mpi_point_t b)
345{
346 gcry_mpi_point_t r;
194 347
348 r = gcry_mpi_point_new (0);
349 gcry_mpi_ec_add (r, a, b, edc->ctx);
350 return r;
351}
352
353
354/**
355 * Obtain a random point on the curve and its
356 * additive inverse. Both returned values
357 * must be freed using #GNUNET_CRYPTO_ecc_free().
358 *
359 * @param edc calculation context for ECC operations
360 * @param[out] r set to a random point on the curve
361 * @param[out] r_inv set to the additive inverse of @a r
362 */
363void
364GNUNET_CRYPTO_ecc_rnd (struct GNUNET_CRYPTO_EccDlogContext *edc,
365 gcry_mpi_point_t *r,
366 gcry_mpi_point_t *r_inv)
367{
368 gcry_mpi_t fact;
369 gcry_mpi_t n;
370 gcry_mpi_point_t g;
371
372 fact = GNUNET_CRYPTO_ecc_random_mod_n (edc);
373
374 /* calculate 'r' */
375 g = gcry_mpi_ec_get_point ("g", edc->ctx, 0);
376 GNUNET_assert (NULL != g);
377 *r = gcry_mpi_point_new (0);
378 gcry_mpi_ec_mul (*r, fact, g, edc->ctx);
379
380 /* calculate 'r_inv' */
381 n = gcry_mpi_ec_get_mpi ("n", edc->ctx, 1);
382 gcry_mpi_sub (fact, n, fact); /* fact = n - fact = - fact */
383 *r_inv = gcry_mpi_point_new (0);
384 gcry_mpi_ec_mul (*r_inv, fact, g, edc->ctx);
385
386 gcry_mpi_release (n);
387 gcry_mpi_release (fact);
388 gcry_mpi_point_release (g);
389}
390
391
392/**
393 * Free a point value returned by the API.
394 *
395 * @param p point to free
396 */
397void
398GNUNET_CRYPTO_ecc_free (gcry_mpi_point_t p)
399{
400 gcry_mpi_point_release (p);
401}
402
403
195/* end of crypto_ecc_dlog.c */ 404/* end of crypto_ecc_dlog.c */
196 405