diff options
author | Christian Grothoff <christian@grothoff.org> | 2015-07-06 14:22:51 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2015-07-06 14:22:51 +0000 |
commit | 0f9e6bcd1e511abae16ecc4c86056b0c26d73936 (patch) | |
tree | 4ba3af76391ee6c67563316de29b6ad8830cd7f2 /src/util/crypto_ecc_dlog.c | |
parent | f1e619572751f7652db025f66f119d6a0308114b (diff) | |
download | gnunet-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.c | 231 |
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 | */ |
67 | struct GNUNET_CRYPTO_EccDlogContext | 66 | struct 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 | */ |
135 | unsigned int | 169 | int |
136 | GNUNET_CRYPTO_ecc_dlog (struct GNUNET_CRYPTO_EccDlogContext *edc, | 170 | GNUNET_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 | */ | ||
222 | gcry_mpi_t | ||
223 | GNUNET_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 | */ | ||
277 | gcry_mpi_point_t | ||
278 | GNUNET_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 | */ | ||
317 | gcry_mpi_point_t | ||
318 | GNUNET_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 | */ | ||
341 | gcry_mpi_point_t | ||
342 | GNUNET_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 | */ | ||
363 | void | ||
364 | GNUNET_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 | */ | ||
397 | void | ||
398 | GNUNET_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 | ||