Tor 0.4.9.0-alpha-dev
hs_pow.c
Go to the documentation of this file.
1/* Copyright (c) 2017-2020, The Tor Project, Inc. */
2/* See LICENSE for licensing information */
3
4/**
5 * \file hs_pow.c
6 * \brief Contains code to handle proof-of-work computations
7 * when a hidden service is defending against DoS attacks.
8 **/
9
10#include <stdio.h>
11
12#include "core/or/or.h"
13#include "app/config/config.h"
14#include "ext/ht.h"
15#include "ext/compat_blake2.h"
16#include "core/or/circuitlist.h"
18#include "ext/equix/include/equix.h"
19#include "feature/hs/hs_cache.h"
23#include "feature/hs/hs_pow.h"
26#include "lib/arch/bytes.h"
27#include "lib/cc/ctassert.h"
31
32/** Replay cache set up */
33/** Cache entry for (nonce, seed) replay protection. */
34typedef struct nonce_cache_entry_t {
35 HT_ENTRY(nonce_cache_entry_t) node;
36 struct {
37 uint8_t nonce[HS_POW_NONCE_LEN];
38 uint8_t seed_head[HS_POW_SEED_HEAD_LEN];
39 } bytes;
41
42/** Return true if the two (nonce, seed) replay cache entries are the same */
43static inline int
45 const struct nonce_cache_entry_t *entry2)
46{
47 return fast_memeq(&entry1->bytes, &entry2->bytes, sizeof entry1->bytes);
48}
49
50/** Hash function to hash the (nonce, seed) tuple entry. */
51static inline unsigned
53{
54 return (unsigned)siphash24g(&ent->bytes, sizeof ent->bytes);
55}
56
57static HT_HEAD(nonce_cache_table_ht, nonce_cache_entry_t)
58 nonce_cache_table = HT_INITIALIZER();
59
60HT_PROTOTYPE(nonce_cache_table_ht, nonce_cache_entry_t, node,
62
63HT_GENERATE2(nonce_cache_table_ht, nonce_cache_entry_t, node,
66
67/** This is a callback used to check replay cache entries against a provided
68 * seed head, or NULL to operate on the entire cache. Matching entries return
69 * 1 and their internal cache entry is freed, non-matching entries return 0. */
70static int
71nonce_cache_entry_match_seed_and_free(nonce_cache_entry_t *ent, void *data)
72{
73 if (data == NULL ||
74 fast_memeq(ent->bytes.seed_head, data, HS_POW_SEED_HEAD_LEN)) {
75 tor_free(ent);
76 return 1;
77 }
78 return 0;
79}
80
81/** Helper: Increment a given nonce and set it in the challenge at the right
82 * offset. Use by the solve function. */
83static inline void
84increment_and_set_nonce(uint8_t *nonce, uint8_t *challenge)
85{
86 for (unsigned i = 0; i < HS_POW_NONCE_LEN; i++) {
87 uint8_t prev = nonce[i];
88 if (++nonce[i] > prev) {
89 break;
90 }
91 }
92 memcpy(challenge + HS_POW_NONCE_OFFSET, nonce, HS_POW_NONCE_LEN);
93}
94
95/* Helper: Build EquiX challenge (P || ID || C || N || INT_32(E)) and return
96 * a newly allocated buffer containing it. */
97static uint8_t *
98build_equix_challenge(const ed25519_public_key_t *blinded_id,
99 const uint8_t *seed, const uint8_t *nonce,
100 const uint32_t effort)
101{
102 size_t offset = 0;
103 uint8_t *challenge = tor_malloc_zero(HS_POW_CHALLENGE_LEN);
104
105 CTASSERT(HS_POW_ID_LEN == sizeof *blinded_id);
106 tor_assert_nonfatal(!ed25519_public_key_is_zero(blinded_id));
107
108 log_debug(LD_REND,
109 "Constructing EquiX challenge with "
110 "blinded service id %s, effort: %d",
111 safe_str_client(ed25519_fmt(blinded_id)),
112 effort);
113
114 memcpy(challenge + offset, HS_POW_PSTRING, HS_POW_PSTRING_LEN);
115 offset += HS_POW_PSTRING_LEN;
116 memcpy(challenge + offset, blinded_id, HS_POW_ID_LEN);
117 offset += HS_POW_ID_LEN;
118 memcpy(challenge + offset, seed, HS_POW_SEED_LEN);
119 offset += HS_POW_SEED_LEN;
121 memcpy(challenge + offset, nonce, HS_POW_NONCE_LEN);
122 offset += HS_POW_NONCE_LEN;
123 set_uint32(challenge + offset, tor_htonl(effort));
124 offset += HS_POW_EFFORT_LEN;
126
127 return challenge;
128}
129
130/** Helper: Return true iff the given challenge and solution for the given
131 * effort do validate as in: R * E <= UINT32_MAX. */
132static bool
133validate_equix_challenge(const uint8_t *challenge,
134 const uint8_t *solution_bytes,
135 const uint32_t effort)
136{
137 /* Fail if R * E > UINT32_MAX. */
138 uint8_t hash_result[HS_POW_HASH_LEN];
139 blake2b_state b2_state;
140
141 if (BUG(blake2b_init(&b2_state, HS_POW_HASH_LEN) < 0)) {
142 return false;
143 }
144
145 /* Construct: blake2b(C || N || E || S) */
146 blake2b_update(&b2_state, challenge, HS_POW_CHALLENGE_LEN);
147 blake2b_update(&b2_state, solution_bytes, HS_POW_EQX_SOL_LEN);
148 blake2b_final(&b2_state, hash_result, HS_POW_HASH_LEN);
149
150 /* Scale to 64 bit so we can avoid 32 bit overflow. */
151 uint64_t RE = tor_htonl(get_uint32(hash_result)) * (uint64_t) effort;
152
153 return RE <= UINT32_MAX;
154}
155
156/** Helper: Convert equix_solution to a byte array in little-endian order */
157static void
159 uint8_t *bytes_out)
160{
161 for (unsigned i = 0; i < EQUIX_NUM_IDX; i++) {
162 bytes_out[i*2+0] = (uint8_t)sol_in->idx[i];
163 bytes_out[i*2+1] = (uint8_t)(sol_in->idx[i] >> 8);
164 }
165}
166
167/** Helper: Build an equix_solution from its corresponding byte array. */
168static void
169unpack_equix_solution(const uint8_t *bytes_in,
170 equix_solution *sol_out)
171{
172 for (unsigned i = 0; i < EQUIX_NUM_IDX; i++) {
173 sol_out->idx[i] = (uint16_t)bytes_in[i*2+0] |
174 (uint16_t)bytes_in[i*2+1] << 8;
175 }
176}
177
178/** Helper: Map the CompiledProofOfWorkHash configuration option to its
179 * corresponding equix_ctx_flags bit. */
180static equix_ctx_flags
181hs_pow_equix_option_flags(int CompiledProofOfWorkHash)
182{
183 if (CompiledProofOfWorkHash == 0) {
184 return 0;
185 } else if (CompiledProofOfWorkHash == 1) {
186 return EQUIX_CTX_MUST_COMPILE;
187 } else {
188 tor_assert_nonfatal(CompiledProofOfWorkHash == -1);
189 return EQUIX_CTX_TRY_COMPILE;
190 }
191}
192
193/** Solve the EquiX/blake2b PoW scheme using the parameters in pow_params, and
194 * store the solution in pow_solution_out. Returns 0 on success and -1
195 * otherwise. Called by a client, from a cpuworker thread. */
196int
198 hs_pow_solution_t *pow_solution_out)
199{
200 int ret = -1;
201 uint8_t nonce[HS_POW_NONCE_LEN];
202 uint8_t *challenge = NULL;
203 equix_ctx *ctx = NULL;
204
205 tor_assert(pow_inputs);
206 tor_assert(pow_solution_out);
207 const uint32_t effort = pow_inputs->effort;
208
209 /* Generate a random nonce N. */
210 crypto_rand((char *)nonce, sizeof nonce);
211
212 /* Build EquiX challenge string */
213 challenge = build_equix_challenge(&pow_inputs->service_blinded_id,
214 pow_inputs->seed, nonce, effort);
215
216 /* This runs on a cpuworker, let's not access global get_options().
217 * Instead, the particular options we need are captured in pow_inputs. */
218 ctx = equix_alloc(EQUIX_CTX_SOLVE |
220 if (!ctx) {
221 goto end;
222 }
223
224 uint8_t sol_bytes[HS_POW_EQX_SOL_LEN];
225 monotime_t start_time;
226 monotime_get(&start_time);
227 log_info(LD_REND, "Solving proof of work (effort %u)", effort);
228
229 for (;;) {
230 /* Calculate solutions to S = equix_solve(C || N || E), */
232 equix_result result;
233 result = equix_solve(ctx, challenge, HS_POW_CHALLENGE_LEN, &buffer);
234 switch (result) {
235
236 case EQUIX_OK:
237 for (unsigned i = 0; i < buffer.count; i++) {
238 pack_equix_solution(&buffer.sols[i], sol_bytes);
239
240 /* Check an Equi-X solution against the effort threshold */
241 if (validate_equix_challenge(challenge, sol_bytes, effort)) {
242 /* Store the nonce N. */
243 memcpy(pow_solution_out->nonce, nonce, HS_POW_NONCE_LEN);
244 /* Store the effort E. */
245 pow_solution_out->effort = effort;
246 /* We only store the first 4 bytes of the seed C. */
247 memcpy(pow_solution_out->seed_head, pow_inputs->seed,
248 sizeof(pow_solution_out->seed_head));
249 /* Store the solution S */
250 memcpy(&pow_solution_out->equix_solution,
251 sol_bytes, sizeof sol_bytes);
252
253 monotime_t end_time;
254 monotime_get(&end_time);
255 int64_t duration_usec = monotime_diff_usec(&start_time, &end_time);
256 log_info(LD_REND, "Proof of work solution (effort %u) found "
257 "using %s implementation in %u.%06u seconds",
258 effort,
259 (EQUIX_SOLVER_DID_USE_COMPILER & buffer.flags)
260 ? "compiled" : "interpreted",
261 (unsigned)(duration_usec / 1000000),
262 (unsigned)(duration_usec % 1000000));
263
264 /* Indicate success and we are done. */
265 ret = 0;
266 goto end;
267 }
268 }
269 break;
270
271 case EQUIX_FAIL_CHALLENGE:
272 /* This happens occasionally due to HashX rejecting some program
273 * configurations. For our purposes here it's the same as count==0.
274 * Increment the nonce and try again. */
275 break;
276
277 case EQUIX_FAIL_COMPILE:
278 /* The interpreter is disabled and the compiler failed */
279 log_warn(LD_REND, "Proof of work solver failed, "
280 "compile error with no fallback enabled.");
281 goto end;
282
283 /* These failures are not applicable to equix_solve, but included for
284 * completeness and to satisfy exhaustive enum warnings. */
285 case EQUIX_FAIL_ORDER:
286 case EQUIX_FAIL_PARTIAL_SUM:
287 case EQUIX_FAIL_FINAL_SUM:
288 /* And these really should not happen, and indicate
289 * programming errors if they do. */
290 case EQUIX_FAIL_NO_SOLVER:
291 case EQUIX_FAIL_INTERNAL:
292 default:
294 goto end;
295 }
296
297 /* No solutions for this nonce and/or none that passed the effort
298 * threshold, increment and try again. */
299 increment_and_set_nonce(nonce, challenge);
300 }
301
302 end:
303 tor_free(challenge);
304 equix_free(ctx);
305 return ret;
306}
307
308/** Verify the solution in pow_solution using the service's current PoW
309 * parameters found in pow_state. Returns 0 on success and -1 otherwise. Called
310 * by the service. */
311int
312hs_pow_verify(const ed25519_public_key_t *service_blinded_id,
313 const hs_pow_service_state_t *pow_state,
314 const hs_pow_solution_t *pow_solution)
315{
316 int ret = -1;
317 uint8_t *challenge = NULL;
318 nonce_cache_entry_t search, *entry = NULL;
319 equix_ctx *ctx = NULL;
320 const uint8_t *seed = NULL;
321
322 tor_assert(pow_state);
323 tor_assert(pow_solution);
324 tor_assert(service_blinded_id);
325 tor_assert_nonfatal(!ed25519_public_key_is_zero(service_blinded_id));
326
327 /* Find a valid seed C that starts with the seed head. Fail if no such seed
328 * exists. */
329 if (fast_memeq(pow_state->seed_current, pow_solution->seed_head,
331 seed = pow_state->seed_current;
332 } else if (fast_memeq(pow_state->seed_previous, pow_solution->seed_head,
334 seed = pow_state->seed_previous;
335 } else {
336 log_warn(LD_REND, "Seed head didn't match either seed.");
337 goto done;
338 }
339
340 /* Fail if N = POW_NONCE is present in the replay cache. */
341 memcpy(search.bytes.nonce, pow_solution->nonce, HS_POW_NONCE_LEN);
342 memcpy(search.bytes.seed_head, pow_solution->seed_head,
344 entry = HT_FIND(nonce_cache_table_ht, &nonce_cache_table, &search);
345 if (entry) {
346 log_warn(LD_REND, "Found (nonce, seed) tuple in the replay cache.");
347 goto done;
348 }
349
350 /* Build the challenge with the params we have. */
351 challenge = build_equix_challenge(service_blinded_id, seed,
352 pow_solution->nonce, pow_solution->effort);
353
354 if (!validate_equix_challenge(challenge, pow_solution->equix_solution,
355 pow_solution->effort)) {
356 log_warn(LD_REND, "Verification of challenge effort in PoW failed.");
357 goto done;
358 }
359
360 ctx = equix_alloc(EQUIX_CTX_VERIFY |
361 hs_pow_equix_option_flags(get_options()->CompiledProofOfWorkHash));
362 if (!ctx) {
363 goto done;
364 }
365
366 /* Fail if equix_verify() != EQUIX_OK */
367 equix_solution equix_sol;
368 unpack_equix_solution(pow_solution->equix_solution, &equix_sol);
369 equix_result result = equix_verify(ctx, challenge, HS_POW_CHALLENGE_LEN,
370 &equix_sol);
371 if (result != EQUIX_OK) {
372 log_warn(LD_REND, "Verification of EquiX solution in PoW failed.");
373 goto done;
374 }
375
376 /* PoW verified successfully. */
377 ret = 0;
378
379 /* Add the (nonce, seed) tuple to the replay cache. */
380 entry = tor_malloc_zero(sizeof(nonce_cache_entry_t));
381 memcpy(entry->bytes.nonce, pow_solution->nonce, HS_POW_NONCE_LEN);
382 memcpy(entry->bytes.seed_head, pow_solution->seed_head,
384 HT_INSERT(nonce_cache_table_ht, &nonce_cache_table, entry);
385
386 done:
387 tor_free(challenge);
388 equix_free(ctx);
389 return ret;
390}
391
392/** Remove entries from the (nonce, seed) replay cache which are for the seed
393 * beginning with seed_head. If seed_head is NULL, remove all cache entries. */
394void
395hs_pow_remove_seed_from_cache(const uint8_t *seed_head)
396{
397 /* If nonce_cache_entry_has_seed returns 1, the entry is removed. */
398 HT_FOREACH_FN(nonce_cache_table_ht, &nonce_cache_table,
399 nonce_cache_entry_match_seed_and_free, (void*)seed_head);
400}
401
402/** Free a given PoW service state. */
403void
405{
406 if (state == NULL) {
407 return;
408 }
409 rend_pqueue_clear(state);
410 tor_assert(smartlist_len(state->rend_request_pqueue) == 0);
411 smartlist_free(state->rend_request_pqueue);
412 mainloop_event_free(state->pop_pqueue_ev);
413 tor_free(state);
414}
415
416/* =====
417 Thread workers
418 =====*/
419
420/**
421 * An object passed to a worker thread that will try to solve the pow.
422 */
423typedef struct pow_worker_job_t {
424
425 /** Inputs for the PoW solver (seed, chosen effort) */
427
428 /** State: we'll look these up to figure out how to proceed after. */
430 uint8_t rend_circ_cookie[HS_REND_COOKIE_LEN];
431
432 /** Output: The worker thread will malloc and write its answer here,
433 * or set it to NULL if it produced no useful answer. */
435
437
438/**
439 * Worker function. This function runs inside a worker thread and receives
440 * a pow_worker_job_t as its input.
441 */
443pow_worker_threadfn(void *state_, void *work_)
444{
445 (void)state_;
446 pow_worker_job_t *job = work_;
447 job->pow_solution_out = tor_malloc_zero(sizeof(hs_pow_solution_t));
448
449 if (hs_pow_solve(&job->pow_inputs, job->pow_solution_out)) {
451 job->pow_solution_out = NULL; /* how we signal that we came up empty */
452 }
453 return WQ_RPL_REPLY;
454}
455
456/**
457 * Helper: release all storage held in <b>job</b>.
458 */
459static void
461{
462 if (!job)
463 return;
465 tor_free(job);
466}
467
468/**
469 * Worker function: This function runs in the main thread, and receives
470 * a pow_worker_job_t that the worker thread has already processed.
471 */
472static void
474{
476 tor_assert(work_);
477
478 pow_worker_job_t *job = work_;
479
480 /* Look up the circuits that we're going to use this pow in.
481 * There's room for improvement here. We already had a fast mapping to
482 * rend circuits from some kind of identifier that we can keep in a
483 * pow_worker_job_t, but we don't have that index for intro circs at this
484 * time. If the linear search in circuit_get_by_global_id() is ever a
485 * noticeable bottleneck we should add another map.
486 */
487 origin_circuit_t *intro_circ =
489 origin_circuit_t *rend_circ =
491
492 /* try to re-create desc and ip */
493 const ed25519_public_key_t *service_identity_pk = NULL;
494 const hs_descriptor_t *desc = NULL;
495 const hs_desc_intro_point_t *ip = NULL;
496 if (intro_circ)
497 service_identity_pk = &intro_circ->hs_ident->identity_pk;
498 if (service_identity_pk)
499 desc = hs_cache_lookup_as_client(service_identity_pk);
500 if (desc)
501 ip = find_desc_intro_point_by_ident(intro_circ->hs_ident, desc);
502
503 if (intro_circ && rend_circ && service_identity_pk && desc && ip &&
504 job->pow_solution_out) {
505
506 /* successful pow solve, and circs still here */
507 log_info(LD_REND, "Got a PoW solution we like! Shipping it!");
508
509 /* Set flag to reflect that the HS we are attempting to rendezvous has PoW
510 * defenses enabled, and as such we will need to be more lenient with
511 * timing out while waiting for the service-side circuit to be built. */
512 rend_circ->hs_with_pow_circ = 1;
513
514 /* Remember the PoW effort we chose, for client-side rend circuits. */
515 rend_circ->hs_pow_effort = job->pow_inputs.effort;
516
517 // and then send that intro cell
518 if (send_introduce1(intro_circ, rend_circ,
519 desc, job->pow_solution_out, ip) < 0) {
520 /* if it failed, mark the intro point as ready to start over */
521 intro_circ->hs_currently_solving_pow = 0;
522 }
523
524 } else {
525 if (!job->pow_solution_out) {
526 log_warn(LD_REND, "PoW cpuworker returned with no solution");
527 } else {
528 log_info(LD_REND, "PoW solution completed but we can "
529 "no longer locate its circuit");
530 }
531 if (intro_circ) {
532 intro_circ->hs_currently_solving_pow = 0;
533 }
534 }
535
537}
538
539/**
540 * Queue the job of solving the pow in a worker thread.
541 */
542int
543hs_pow_queue_work(uint32_t intro_circ_identifier,
544 const uint8_t *rend_circ_cookie,
545 const hs_pow_solver_inputs_t *pow_inputs)
546{
548 tor_assert(rend_circ_cookie);
549 tor_assert(pow_inputs);
550 tor_assert_nonfatal(
552
553 pow_worker_job_t *job = tor_malloc_zero(sizeof(*job));
554 job->intro_circ_identifier = intro_circ_identifier;
555 memcpy(&job->rend_circ_cookie, rend_circ_cookie,
556 sizeof job->rend_circ_cookie);
557 memcpy(&job->pow_inputs, pow_inputs, sizeof job->pow_inputs);
558
559 workqueue_entry_t *work;
560 work = cpuworker_queue_work(WQ_PRI_LOW,
563 job);
564 if (!work) {
566 return -1;
567 }
568 return 0;
569}
Inline functions for reading and writing multibyte values from the middle of strings,...
static uint32_t tor_htonl(uint32_t a)
Definition: bytes.h:163
static void set_uint32(void *cp, uint32_t v)
Definition: bytes.h:87
static uint32_t get_uint32(const void *cp)
Definition: bytes.h:54
origin_circuit_t * circuit_get_by_global_id(uint32_t id)
Definition: circuitlist.c:1453
Header file for circuitlist.c.
Compatibility adapter providing blake2b using ext/equix/hashx.
int in_main_thread(void)
int64_t monotime_diff_usec(const monotime_t *start, const monotime_t *end)
Definition: compat_time.c:776
Functions and types for monotonic times.
void monotime_get(monotime_t *out)
const or_options_t * get_options(void)
Definition: config.c:944
Header file for config.c.
workqueue_entry_t * cpuworker_queue_work(workqueue_priority_t priority, workqueue_reply_t(*fn)(void *, void *), void(*reply_fn)(void *), void *arg)
Definition: cpuworker.c:567
Header file for cpuworker.c.
int ed25519_public_key_is_zero(const ed25519_public_key_t *pubkey)
const char * ed25519_fmt(const ed25519_public_key_t *pkey)
Header for crypto_format.c.
void crypto_rand(char *to, size_t n)
Definition: crypto_rand.c:479
Common functions for using (pseudo-)random number generators.
Compile-time assertions: CTASSERT(expression).
#define fast_memeq(a, b, c)
Definition: di_ops.h:35
CTASSERT(NUMBER_SECOND_GUARDS< 20)
const hs_descriptor_t * hs_cache_lookup_as_client(const ed25519_public_key_t *key)
Definition: hs_cache.c:845
Header file for hs_cache.c.
void rend_pqueue_clear(hs_pow_service_state_t *pow_state)
Definition: hs_circuit.c:748
HT_PROTOTYPE(hs_circuitmap_ht, circuit_t, hs_circuitmap_node, hs_circuit_hash_token, hs_circuits_have_same_token)
origin_circuit_t * hs_circuitmap_get_established_rend_circ_client_side(const uint8_t *cookie)
Header file for hs_circuitmap.c.
const hs_desc_intro_point_t * find_desc_intro_point_by_ident(const hs_ident_circuit_t *ident, const hs_descriptor_t *desc)
Definition: hs_client.c:545
int send_introduce1(origin_circuit_t *intro_circ, origin_circuit_t *rend_circ, const hs_descriptor_t *desc, hs_pow_solution_t *pow_solution, const hs_desc_intro_point_t *ip)
Definition: hs_client.c:609
Header file containing client data for the HS subsystem.
Header file for hs_descriptor.c.
#define HS_REND_COOKIE_LEN
Definition: hs_ident.h:30
static unsigned nonce_cache_entry_hash_(const struct nonce_cache_entry_t *ent)
Definition: hs_pow.c:52
int hs_pow_verify(const ed25519_public_key_t *service_blinded_id, const hs_pow_service_state_t *pow_state, const hs_pow_solution_t *pow_solution)
Definition: hs_pow.c:312
static bool validate_equix_challenge(const uint8_t *challenge, const uint8_t *solution_bytes, const uint32_t effort)
Definition: hs_pow.c:133
static void pack_equix_solution(const equix_solution *sol_in, uint8_t *bytes_out)
Definition: hs_pow.c:158
static equix_ctx_flags hs_pow_equix_option_flags(int CompiledProofOfWorkHash)
Definition: hs_pow.c:181
static void pow_worker_replyfn(void *work_)
Definition: hs_pow.c:473
static void unpack_equix_solution(const uint8_t *bytes_in, equix_solution *sol_out)
Definition: hs_pow.c:169
int hs_pow_solve(const hs_pow_solver_inputs_t *pow_inputs, hs_pow_solution_t *pow_solution_out)
Definition: hs_pow.c:197
static void increment_and_set_nonce(uint8_t *nonce, uint8_t *challenge)
Definition: hs_pow.c:84
int hs_pow_queue_work(uint32_t intro_circ_identifier, const uint8_t *rend_circ_cookie, const hs_pow_solver_inputs_t *pow_inputs)
Definition: hs_pow.c:543
static int nonce_cache_entries_eq_(const struct nonce_cache_entry_t *entry1, const struct nonce_cache_entry_t *entry2)
Definition: hs_pow.c:44
static void pow_worker_job_free(pow_worker_job_t *job)
Definition: hs_pow.c:460
static workqueue_reply_t pow_worker_threadfn(void *state_, void *work_)
Definition: hs_pow.c:443
void hs_pow_remove_seed_from_cache(const uint8_t *seed_head)
Definition: hs_pow.c:395
void hs_pow_free_service_state(hs_pow_service_state_t *state)
Definition: hs_pow.c:404
Header file containing PoW denial of service defenses for the HS subsystem for all versions.
#define HS_POW_EQX_SOL_LEN
Definition: hs_pow.h:31
#define HS_POW_PSTRING
Definition: hs_pow.h:37
#define HS_POW_NONCE_OFFSET
Definition: hs_pow.h:47
#define HS_POW_EFFORT_LEN
Definition: hs_pow.h:45
#define HS_POW_CHALLENGE_LEN
Definition: hs_pow.h:52
#define HS_POW_SEED_LEN
Definition: hs_pow.h:41
#define HS_POW_HASH_LEN
Definition: hs_pow.h:33
#define HS_POW_NONCE_LEN
Definition: hs_pow.h:29
#define HS_POW_SEED_HEAD_LEN
Definition: hs_pow.h:43
#define HS_POW_ID_LEN
Definition: hs_pow.h:39
#define HS_POW_PSTRING_LEN
Definition: hs_pow.h:35
typedef HT_HEAD(hs_service_ht, hs_service_t) hs_service_ht
#define LD_REND
Definition: log.h:84
void * tor_reallocarray_(void *ptr, size_t sz1, size_t sz2)
Definition: malloc.c:146
void tor_free_(void *mem)
Definition: malloc.c:227
#define tor_free(p)
Definition: malloc.h:56
Master header file for Tor-specific functionality.
Origin circuit structure.
ed25519_public_key_t identity_pk
Definition: hs_ident.h:45
uint8_t seed[HS_POW_SEED_LEN]
Definition: hs_pow.h:81
ed25519_public_key_t service_blinded_id
Definition: hs_pow.h:83
int CompiledProofOfWorkHash
Definition: hs_pow.h:88
Definition: hs_pow.c:34
struct hs_ident_circuit_t * hs_ident
unsigned int hs_currently_solving_pow
unsigned int hs_with_pow_circ
hs_pow_solver_inputs_t pow_inputs
Definition: hs_pow.c:426
uint32_t intro_circ_identifier
Definition: hs_pow.c:429
hs_pow_solution_t * pow_solution_out
Definition: hs_pow.c:434
Definition: workqueue.c:98
#define tor_assert_nonfatal_unreached()
Definition: util_bug.h:177
#define tor_assert(expr)
Definition: util_bug.h:103
Header for workqueue.c.
workqueue_reply_t
Definition: workqueue.h:24