diff options
Diffstat (limited to 'src/rps/rps-test_util.c')
-rw-r--r-- | src/rps/rps-test_util.c | 550 |
1 files changed, 0 insertions, 550 deletions
diff --git a/src/rps/rps-test_util.c b/src/rps/rps-test_util.c deleted file mode 100644 index 8fd82f7b3..000000000 --- a/src/rps/rps-test_util.c +++ /dev/null | |||
@@ -1,550 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file rps/rps-test_util.c | ||
23 | * @brief Some utils facilitating the view into the internals for the sampler | ||
24 | * needed for evaluation | ||
25 | * | ||
26 | * @author Julius Bünger | ||
27 | */ | ||
28 | |||
29 | #include "platform.h" | ||
30 | #include "gnunet_util_lib.h" | ||
31 | #include "rps-test_util.h" | ||
32 | |||
33 | #include <inttypes.h> | ||
34 | |||
35 | #define LOG(kind, ...) GNUNET_log_from (kind, "rps-test_util", __VA_ARGS__) | ||
36 | |||
37 | #define B2B_PAT "%c%c%c%c%c%c%c%c" | ||
38 | #define B2B(byte) \ | ||
39 | (byte & 0x80 ? '1' : '0'), \ | ||
40 | (byte & 0x40 ? '1' : '0'), \ | ||
41 | (byte & 0x20 ? '1' : '0'), \ | ||
42 | (byte & 0x10 ? '1' : '0'), \ | ||
43 | (byte & 0x08 ? '1' : '0'), \ | ||
44 | (byte & 0x04 ? '1' : '0'), \ | ||
45 | (byte & 0x02 ? '1' : '0'), \ | ||
46 | (byte & 0x01 ? '1' : '0') | ||
47 | |||
48 | #ifdef TO_FILE | ||
49 | |||
50 | |||
51 | /** | ||
52 | * @brief buffer for storing the unaligned bits for the next write | ||
53 | */ | ||
54 | static char buf_unaligned; | ||
55 | |||
56 | /** | ||
57 | * @brief number of bits in unaligned buffer | ||
58 | */ | ||
59 | static unsigned num_bits_buf_unaligned; | ||
60 | |||
61 | static struct GNUNET_CONTAINER_MultiHashMap *open_files; | ||
62 | |||
63 | |||
64 | /** | ||
65 | * @brief Get file handle | ||
66 | * | ||
67 | * If necessary, create file handle and store it with the other file handles. | ||
68 | * | ||
69 | * @param name Name of the file | ||
70 | * | ||
71 | * @return File handle | ||
72 | */ | ||
73 | struct GNUNET_DISK_FileHandle * | ||
74 | get_file_handle (const char *name) | ||
75 | { | ||
76 | struct GNUNET_HashCode hash; | ||
77 | struct GNUNET_DISK_FileHandle *fh; | ||
78 | |||
79 | if (NULL == open_files) | ||
80 | { | ||
81 | open_files = GNUNET_CONTAINER_multihashmap_create (16, | ||
82 | GNUNET_NO); | ||
83 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
84 | "Created map of open files.\n"); | ||
85 | } | ||
86 | GNUNET_CRYPTO_hash (name, | ||
87 | strlen (name), | ||
88 | &hash); | ||
89 | if (NULL != (fh = GNUNET_CONTAINER_multihashmap_get (open_files, | ||
90 | &hash))) | ||
91 | return fh; | ||
92 | fh = GNUNET_DISK_file_open (name, | ||
93 | GNUNET_DISK_OPEN_WRITE | ||
94 | | GNUNET_DISK_OPEN_CREATE | ||
95 | | GNUNET_DISK_OPEN_APPEND, | ||
96 | GNUNET_DISK_PERM_USER_READ | ||
97 | | GNUNET_DISK_PERM_USER_WRITE | ||
98 | | GNUNET_DISK_PERM_GROUP_READ); | ||
99 | if (NULL == fh) | ||
100 | { | ||
101 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
102 | "Opening file `%s' failed.\n", | ||
103 | name); | ||
104 | GNUNET_assert (0); | ||
105 | } | ||
106 | GNUNET_assert (GNUNET_YES == | ||
107 | GNUNET_CONTAINER_multihashmap_put (open_files, | ||
108 | &hash, | ||
109 | fh, | ||
110 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | ||
111 | return fh; | ||
112 | } | ||
113 | |||
114 | |||
115 | /** | ||
116 | * @brief Closes the file of the current entry | ||
117 | * | ||
118 | * Implements #GNUNET_CONTAINER_HashMapIterator | ||
119 | * | ||
120 | * @param cls unused | ||
121 | * @param key unused | ||
122 | * @param value the file handle | ||
123 | * | ||
124 | * @return #GNUNET_YES if we should continue to | ||
125 | * iterate, | ||
126 | * #GNUNET_NO if not. | ||
127 | */ | ||
128 | int | ||
129 | close_files_iter (void *cls, | ||
130 | const struct GNUNET_HashCode *key, | ||
131 | void *value) | ||
132 | { | ||
133 | (void) cls; | ||
134 | (void) key; | ||
135 | struct GNUNET_DISK_FileHandle *fh = value; | ||
136 | |||
137 | if (NULL != fh) | ||
138 | { | ||
139 | GNUNET_DISK_file_close (fh); | ||
140 | } | ||
141 | return GNUNET_YES; | ||
142 | } | ||
143 | |||
144 | |||
145 | /** | ||
146 | * @brief Close all files that were opened with #get_file_handle | ||
147 | * | ||
148 | * @return Success of iterating over files | ||
149 | */ | ||
150 | int | ||
151 | close_all_files () | ||
152 | { | ||
153 | int ret; | ||
154 | |||
155 | if (NULL != open_files) | ||
156 | { | ||
157 | ret = GNUNET_CONTAINER_multihashmap_iterate (open_files, | ||
158 | close_files_iter, | ||
159 | NULL); | ||
160 | GNUNET_CONTAINER_multihashmap_destroy (open_files); | ||
161 | open_files = NULL; | ||
162 | return ret; | ||
163 | } | ||
164 | return GNUNET_YES; | ||
165 | } | ||
166 | |||
167 | |||
168 | void | ||
169 | to_file_raw (const char *file_name, const char *buf, size_t size_buf) | ||
170 | { | ||
171 | struct GNUNET_DISK_FileHandle *f; | ||
172 | size_t size_written; | ||
173 | |||
174 | if (NULL == (f = GNUNET_DISK_file_open (file_name, | ||
175 | GNUNET_DISK_OPEN_APPEND | ||
176 | | GNUNET_DISK_OPEN_WRITE | ||
177 | | GNUNET_DISK_OPEN_CREATE, | ||
178 | GNUNET_DISK_PERM_USER_READ | ||
179 | | GNUNET_DISK_PERM_USER_WRITE | ||
180 | | GNUNET_DISK_PERM_GROUP_READ | ||
181 | | GNUNET_DISK_PERM_OTHER_READ))) | ||
182 | { | ||
183 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
184 | "Not able to open file %s\n", | ||
185 | file_name); | ||
186 | return; | ||
187 | } | ||
188 | |||
189 | size_written = GNUNET_DISK_file_write (f, buf, size_buf); | ||
190 | if (size_buf != size_written) | ||
191 | { | ||
192 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
193 | "Unable to write to file! (Size: %llu, size_written: %llu)\n", | ||
194 | (unsigned long long) size_buf, | ||
195 | (unsigned long long) size_written); | ||
196 | |||
197 | if (GNUNET_YES != GNUNET_DISK_file_close (f)) | ||
198 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
199 | "Unable to close file\n"); | ||
200 | |||
201 | return; | ||
202 | } | ||
203 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
204 | "Wrote %llu bytes raw.\n", | ||
205 | (unsigned long long) size_written); | ||
206 | if (GNUNET_YES != GNUNET_DISK_file_close (f)) | ||
207 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
208 | "Unable to close file\n"); | ||
209 | } | ||
210 | |||
211 | |||
212 | void | ||
213 | to_file_raw_unaligned (const char *file_name, | ||
214 | const char *buf, | ||
215 | size_t size_buf, | ||
216 | unsigned bits_needed) | ||
217 | { | ||
218 | // TODO endianness! | ||
219 | GNUNET_assert (size_buf >= (bits_needed / 8)); | ||
220 | // if (0 == num_bits_buf_unaligned) | ||
221 | // { | ||
222 | // if (0 == (bits_needed % 8)) | ||
223 | // { | ||
224 | // to_file_raw (file_name, buf, size_buf); | ||
225 | // return; | ||
226 | // } | ||
227 | // to_file_raw (file_name, buf, size_buf - 1); | ||
228 | // buf_unaligned = buf[size_buf - 1]; | ||
229 | // num_bits_buf_unaligned = bits_needed % 8; | ||
230 | // return; | ||
231 | // } | ||
232 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
233 | "Was asked to write %u bits\n", bits_needed); | ||
234 | |||
235 | char buf_write[size_buf + 1]; | ||
236 | const unsigned bytes_iter = (0 != bits_needed % 8 ? | ||
237 | (bits_needed / 8) + 1 : | ||
238 | bits_needed / 8); | ||
239 | // TODO what if no iteration happens? | ||
240 | unsigned size_buf_write = 0; | ||
241 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
242 | "num_bits_buf_unaligned: %u\n", | ||
243 | num_bits_buf_unaligned); | ||
244 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
245 | "ua args: size_buf: %llu, bits_needed: %u -> iter: %u\n", | ||
246 | (unsigned long long) size_buf, | ||
247 | bits_needed, | ||
248 | bytes_iter); | ||
249 | buf_write[0] = buf_unaligned; | ||
250 | /* Iterate over input bytes */ | ||
251 | for (unsigned i = 0; i < bytes_iter; i++) | ||
252 | { | ||
253 | /* Number of bits needed in this iteration - 8 for all except last iter */ | ||
254 | unsigned num_bits_needed_iter; | ||
255 | /* Mask for bits to actually use */ | ||
256 | unsigned mask_bits_needed_iter; | ||
257 | char byte_input; | ||
258 | /* Number of bits needed to align unaligned byte */ | ||
259 | unsigned num_bits_to_align; | ||
260 | /* Number of bits that are to be moved */ | ||
261 | unsigned num_bits_to_move; | ||
262 | /* Mask for bytes to be moved */ | ||
263 | char mask_input_to_move; | ||
264 | /* Masked bits to be moved */ | ||
265 | char bits_to_move; | ||
266 | /* The amount of bits needed to fit the bits to shift to the nearest spot */ | ||
267 | unsigned distance_shift_bits; | ||
268 | /* Shifted bits on the move */ | ||
269 | char bits_moving; | ||
270 | /* (unaligned) byte being filled with bits */ | ||
271 | char byte_to_fill; | ||
272 | /* mask for needed bits of the input byte that have not been moved */ | ||
273 | char mask_input_leftover; | ||
274 | /* needed bits of the input byte that have not been moved */ | ||
275 | char byte_input_leftover; | ||
276 | unsigned num_bits_leftover; | ||
277 | // unsigned num_bits_discard; | ||
278 | char byte_unaligned_new; | ||
279 | |||
280 | if ((bits_needed - (i * 8)) <= 8) | ||
281 | { | ||
282 | /* last iteration */ | ||
283 | num_bits_needed_iter = bits_needed - (i * 8); | ||
284 | } | ||
285 | else | ||
286 | { | ||
287 | num_bits_needed_iter = 8; | ||
288 | } | ||
289 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
290 | "number of bits needed in this iteration: %u\n", | ||
291 | num_bits_needed_iter); | ||
292 | mask_bits_needed_iter = ((char) 1 << num_bits_needed_iter) - 1; | ||
293 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
294 | "mask needed bits (current iter): "B2B_PAT "\n", | ||
295 | B2B (mask_bits_needed_iter)); | ||
296 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
297 | "Unaligned byte: "B2B_PAT " (%u bits)\n", | ||
298 | B2B (buf_unaligned), | ||
299 | num_bits_buf_unaligned); | ||
300 | byte_input = buf[i]; | ||
301 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
302 | "next whole input byte: "B2B_PAT "\n", | ||
303 | B2B (byte_input)); | ||
304 | byte_input &= mask_bits_needed_iter; | ||
305 | num_bits_to_align = 8 - num_bits_buf_unaligned; | ||
306 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
307 | "input byte, needed bits: "B2B_PAT "\n", | ||
308 | B2B (byte_input)); | ||
309 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
310 | "number of bits needed to align unaligned bit: %u\n", | ||
311 | num_bits_to_align); | ||
312 | num_bits_to_move = GNUNET_MIN (num_bits_to_align, num_bits_needed_iter); | ||
313 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
314 | "number of bits of new byte to move: %u\n", | ||
315 | num_bits_to_move); | ||
316 | mask_input_to_move = ((char) 1 << num_bits_to_move) - 1; | ||
317 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
318 | "mask of bits of new byte to take for moving: "B2B_PAT "\n", | ||
319 | B2B (mask_input_to_move)); | ||
320 | bits_to_move = byte_input & mask_input_to_move; | ||
321 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
322 | "masked bits of new byte to take for moving: "B2B_PAT "\n", | ||
323 | B2B (bits_to_move)); | ||
324 | distance_shift_bits = num_bits_buf_unaligned; | ||
325 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
326 | "distance needed to shift bits to their correct spot: %u\n", | ||
327 | distance_shift_bits); | ||
328 | bits_moving = bits_to_move << distance_shift_bits; | ||
329 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
330 | "shifted, masked bits of new byte being moved: "B2B_PAT "\n", | ||
331 | B2B (bits_moving)); | ||
332 | byte_to_fill = buf_unaligned | bits_moving; | ||
333 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
334 | "byte being filled: "B2B_PAT "\n", | ||
335 | B2B (byte_to_fill)); | ||
336 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
337 | "pending bytes: %u\n", | ||
338 | num_bits_buf_unaligned + num_bits_needed_iter); | ||
339 | if (num_bits_buf_unaligned + num_bits_needed_iter >= 8) | ||
340 | { | ||
341 | /* buf_unaligned was aligned by filling | ||
342 | * -> can be written to storage */ | ||
343 | buf_write[i] = byte_to_fill; | ||
344 | size_buf_write++; | ||
345 | |||
346 | /* store the leftover, unaligned bits in buffer */ | ||
347 | mask_input_leftover = mask_bits_needed_iter & (~mask_input_to_move); | ||
348 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
349 | "mask of leftover bits of new byte: "B2B_PAT "\n", | ||
350 | B2B (mask_input_leftover)); | ||
351 | byte_input_leftover = byte_input & mask_input_leftover; | ||
352 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
353 | "masked, leftover bits of new byte: "B2B_PAT "\n", | ||
354 | B2B (byte_input_leftover)); | ||
355 | num_bits_leftover = num_bits_needed_iter - num_bits_to_move; | ||
356 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
357 | "number of unaligned bits left: %u\n", | ||
358 | num_bits_leftover); | ||
359 | // num_bits_discard = 8 - num_bits_needed_iter; | ||
360 | byte_unaligned_new = byte_input_leftover >> num_bits_to_move; | ||
361 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
362 | "new unaligned byte: "B2B_PAT "\n", | ||
363 | B2B (byte_unaligned_new)); | ||
364 | buf_unaligned = byte_unaligned_new; | ||
365 | num_bits_buf_unaligned = num_bits_leftover % 8; | ||
366 | } | ||
367 | else | ||
368 | { | ||
369 | /* unaligned buffer still unaligned but 'fuller' */ | ||
370 | buf_unaligned = byte_to_fill; | ||
371 | num_bits_buf_unaligned = (num_bits_buf_unaligned + bits_needed) % 8; | ||
372 | } | ||
373 | } | ||
374 | to_file_raw (file_name, buf_write, size_buf_write); | ||
375 | LOG (GNUNET_ERROR_TYPE_DEBUG, "\n"); | ||
376 | } | ||
377 | |||
378 | |||
379 | char * | ||
380 | auth_key_to_string (struct GNUNET_CRYPTO_AuthKey auth_key) | ||
381 | { | ||
382 | int size; | ||
383 | size_t name_buf_size; | ||
384 | char *end; | ||
385 | char *buf; | ||
386 | char *name_buf; | ||
387 | size_t keylen = (sizeof(struct GNUNET_CRYPTO_AuthKey)) * 8; | ||
388 | |||
389 | name_buf_size = 512 * sizeof(char); | ||
390 | name_buf = GNUNET_malloc (name_buf_size); | ||
391 | |||
392 | if (keylen % 5 > 0) | ||
393 | keylen += 5 - keylen % 5; | ||
394 | keylen /= 5; | ||
395 | buf = GNUNET_malloc (keylen + 1); | ||
396 | |||
397 | end = GNUNET_STRINGS_data_to_string (&(auth_key.key), | ||
398 | sizeof(struct GNUNET_CRYPTO_AuthKey), | ||
399 | buf, | ||
400 | keylen); | ||
401 | |||
402 | if (NULL == end) | ||
403 | { | ||
404 | GNUNET_free (buf); | ||
405 | GNUNET_break (0); | ||
406 | } | ||
407 | else | ||
408 | { | ||
409 | *end = '\0'; | ||
410 | } | ||
411 | |||
412 | size = GNUNET_snprintf (name_buf, name_buf_size, "sampler_el-%s", buf); | ||
413 | if (0 > size) | ||
414 | LOG (GNUNET_ERROR_TYPE_WARNING, "Failed to create name_buf\n"); | ||
415 | |||
416 | GNUNET_free (buf); | ||
417 | |||
418 | return name_buf; | ||
419 | } | ||
420 | |||
421 | |||
422 | #endif /* TO_FILE */ | ||
423 | |||
424 | |||
425 | struct GNUNET_CRYPTO_AuthKey | ||
426 | string_to_auth_key (const char *str) | ||
427 | { | ||
428 | struct GNUNET_CRYPTO_AuthKey auth_key; | ||
429 | |||
430 | if (GNUNET_OK != | ||
431 | GNUNET_STRINGS_string_to_data (str, | ||
432 | strlen (str), | ||
433 | &auth_key.key, | ||
434 | sizeof(struct GNUNET_CRYPTO_AuthKey))) | ||
435 | { | ||
436 | LOG (GNUNET_ERROR_TYPE_WARNING, "Failed to convert string to data\n"); | ||
437 | } | ||
438 | |||
439 | return auth_key; | ||
440 | } | ||
441 | |||
442 | |||
443 | /** | ||
444 | * @brief Try to ensure that `/tmp/rps` exists. | ||
445 | * | ||
446 | * @return #GNUNET_YES on success | ||
447 | * #GNUNET_SYSERR on failure | ||
448 | */ | ||
449 | static int | ||
450 | ensure_folder_exist (void) | ||
451 | { | ||
452 | if (GNUNET_OK != | ||
453 | GNUNET_DISK_directory_create ("/tmp/rps")) | ||
454 | { | ||
455 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
456 | "Could not create directory `/tmp/rps'\n"); | ||
457 | return GNUNET_SYSERR; | ||
458 | } | ||
459 | return GNUNET_YES; | ||
460 | } | ||
461 | |||
462 | |||
463 | char * | ||
464 | store_prefix_file_name (const unsigned int index, | ||
465 | const char *prefix) | ||
466 | { | ||
467 | int len_file_name; | ||
468 | int out_size; | ||
469 | char *file_name; | ||
470 | char index_str[64]; | ||
471 | |||
472 | if (GNUNET_SYSERR == ensure_folder_exist ()) | ||
473 | return NULL; | ||
474 | out_size = GNUNET_snprintf (index_str, | ||
475 | 64, | ||
476 | "%u", | ||
477 | index); | ||
478 | if ((64 < out_size) || | ||
479 | (0 > out_size) ) | ||
480 | { | ||
481 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
482 | "Failed to write string to buffer (size: %i, out_size: %i)\n", | ||
483 | 64, | ||
484 | out_size); | ||
485 | } | ||
486 | len_file_name = (strlen (prefix) | ||
487 | + strlen (index_str) | ||
488 | + 11) | ||
489 | * sizeof(char); | ||
490 | file_name = GNUNET_malloc (len_file_name); | ||
491 | out_size = GNUNET_snprintf (file_name, | ||
492 | len_file_name, | ||
493 | "/tmp/rps/%s-%s", | ||
494 | prefix, | ||
495 | index_str); | ||
496 | if ((len_file_name < out_size) || | ||
497 | (0 > out_size) ) | ||
498 | { | ||
499 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
500 | "Failed to write string to buffer (size: %i, out_size: %i)\n", | ||
501 | len_file_name, | ||
502 | out_size); | ||
503 | } | ||
504 | return file_name; | ||
505 | } | ||
506 | |||
507 | |||
508 | /** | ||
509 | * @brief Factorial | ||
510 | * | ||
511 | * @param x Number of which to compute the factorial | ||
512 | * | ||
513 | * @return Factorial of @a x | ||
514 | */ | ||
515 | uint32_t | ||
516 | fac (uint32_t x) | ||
517 | { | ||
518 | if (1 >= x) | ||
519 | { | ||
520 | return x; | ||
521 | } | ||
522 | return x * fac (x - 1); | ||
523 | } | ||
524 | |||
525 | |||
526 | /** | ||
527 | * @brief Binomial coefficient (n choose k) | ||
528 | * | ||
529 | * @param n | ||
530 | * @param k | ||
531 | * | ||
532 | * @return Binomial coefficient of @a n and @a k | ||
533 | */ | ||
534 | uint32_t | ||
535 | binom (uint32_t n, uint32_t k) | ||
536 | { | ||
537 | // GNUNET_assert (n >= k); | ||
538 | if (k > n) | ||
539 | return 0; | ||
540 | /* if (0 > n) return 0; - always false */ | ||
541 | /* if (0 > k) return 0; - always false */ | ||
542 | if (0 == k) | ||
543 | return 1; | ||
544 | return fac (n) | ||
545 | / | ||
546 | fac (k) * fac (n - k); | ||
547 | } | ||
548 | |||
549 | |||
550 | /* end of gnunet-service-rps.c */ | ||