diff options
Diffstat (limited to 'src/feature/hs')
-rw-r--r-- | src/feature/hs/hs_pow.c | 110 |
1 files changed, 68 insertions, 42 deletions
diff --git a/src/feature/hs/hs_pow.c b/src/feature/hs/hs_pow.c index f75b3cb119..27d09cb0b4 100644 --- a/src/feature/hs/hs_pow.c +++ b/src/feature/hs/hs_pow.c @@ -27,6 +27,7 @@ #include "lib/cc/ctassert.h" #include "core/mainloop/cpuworker.h" #include "lib/evloop/workqueue.h" +#include "lib/time/compat_time.h" /** Replay cache set up */ /** Cache entry for (nonce, seed) replay protection. */ @@ -91,23 +92,6 @@ increment_and_set_nonce(uint8_t *nonce, uint8_t *challenge) memcpy(challenge + HS_POW_NONCE_OFFSET, nonce, HS_POW_NONCE_LEN); } -/* Helper: Allocate an EquiX context, using the much faster compiled - * implementation of hashx if it's available on this architecture. */ -static equix_ctx * -build_equix_ctx(equix_ctx_flags flags) -{ - equix_ctx *ctx = equix_alloc(flags | EQUIX_CTX_COMPILE); - if (ctx == EQUIX_NOTSUPP) { - ctx = equix_alloc(flags); - } - tor_assert_nonfatal(ctx != EQUIX_NOTSUPP); - tor_assert_nonfatal(ctx != NULL); - if (ctx == EQUIX_NOTSUPP) { - ctx = NULL; - } - return ctx; -} - /* Helper: Build EquiX challenge (P || ID || C || N || INT_32(E)) and return * a newly allocated buffer containing it. */ static uint8_t * @@ -214,36 +198,82 @@ hs_pow_solve(const hs_pow_solver_inputs_t *pow_inputs, challenge = build_equix_challenge(&pow_inputs->service_blinded_id, pow_inputs->seed, nonce, effort); - ctx = build_equix_ctx(EQUIX_CTX_SOLVE); + ctx = equix_alloc(EQUIX_CTX_SOLVE | EQUIX_CTX_TRY_COMPILE); if (!ctx) { goto end; } - equix_solution solutions[EQUIX_MAX_SOLS]; - uint8_t sol_bytes[HS_POW_EQX_SOL_LEN]; + uint8_t sol_bytes[HS_POW_EQX_SOL_LEN]; + monotime_t start_time; + monotime_get(&start_time); log_info(LD_REND, "Solving proof of work (effort %u)", effort); + for (;;) { /* Calculate solutions to S = equix_solve(C || N || E), */ - int count = equix_solve(ctx, challenge, HS_POW_CHALLENGE_LEN, solutions); - for (int i = 0; i < count; i++) { - pack_equix_solution(&solutions[i], sol_bytes); - - /* Check an Equi-X solution against the effort threshold */ - if (validate_equix_challenge(challenge, sol_bytes, effort)) { - /* Store the nonce N. */ - memcpy(pow_solution_out->nonce, nonce, HS_POW_NONCE_LEN); - /* Store the effort E. */ - pow_solution_out->effort = effort; - /* We only store the first 4 bytes of the seed C. */ - memcpy(pow_solution_out->seed_head, pow_inputs->seed, + equix_solutions_buffer buffer; + equix_result result; + result = equix_solve(ctx, challenge, HS_POW_CHALLENGE_LEN, &buffer); + switch (result) { + + case EQUIX_OK: + for (unsigned i = 0; i < buffer.count; i++) { + pack_equix_solution(&buffer.sols[i], sol_bytes); + + /* Check an Equi-X solution against the effort threshold */ + if (validate_equix_challenge(challenge, sol_bytes, effort)) { + /* Store the nonce N. */ + memcpy(pow_solution_out->nonce, nonce, HS_POW_NONCE_LEN); + /* Store the effort E. */ + pow_solution_out->effort = effort; + /* We only store the first 4 bytes of the seed C. */ + memcpy(pow_solution_out->seed_head, pow_inputs->seed, sizeof(pow_solution_out->seed_head)); - /* Store the solution S */ - memcpy(&pow_solution_out->equix_solution, sol_bytes, sizeof sol_bytes); + /* Store the solution S */ + memcpy(&pow_solution_out->equix_solution, + sol_bytes, sizeof sol_bytes); + + monotime_t end_time; + monotime_get(&end_time); + int64_t duration_usec = monotime_diff_usec(&start_time, &end_time); + log_info(LD_REND, "Proof of work solution (effort %u) found " + "using %s implementation in %u.%06u seconds", + effort, + (EQUIX_SOLVER_DID_USE_COMPILER & buffer.flags) + ? "compiled" : "interpreted", + (unsigned)(duration_usec / 1000000), + (unsigned)(duration_usec % 1000000)); + + /* Indicate success and we are done. */ + ret = 0; + goto end; + } + } + break; + + case EQUIX_FAIL_CHALLENGE: + /* This happens occasionally due to HashX rejecting some program + * configurations. For our purposes here it's the same as count==0. + * Increment the nonce and try again. */ + break; + + case EQUIX_FAIL_COMPILE: + /* The interpreter is disabled and the compiler failed */ + log_warn(LD_REND, "Proof of work solver failed, " + "compile error with no fallback enabled."); + goto end; - /* Indicate success and we are done. */ - ret = 0; + /* These failures are not applicable to equix_solve, but included for + * completeness and to satisfy exhaustive enum warnings. */ + case EQUIX_FAIL_ORDER: + case EQUIX_FAIL_PARTIAL_SUM: + case EQUIX_FAIL_FINAL_SUM: + /* And these really should not happen, and indicate + * programming errors if they do. */ + case EQUIX_FAIL_NO_SOLVER: + case EQUIX_FAIL_INTERNAL: + default: + tor_assert_nonfatal_unreached(); goto end; - } } /* No solutions for this nonce and/or none that passed the effort @@ -309,7 +339,7 @@ hs_pow_verify(const ed25519_public_key_t *service_blinded_id, goto done; } - ctx = build_equix_ctx(EQUIX_CTX_VERIFY); + ctx = equix_alloc(EQUIX_CTX_VERIFY | EQUIX_CTX_TRY_COMPILE); if (!ctx) { goto done; } @@ -401,11 +431,7 @@ pow_worker_threadfn(void *state_, void *work_) log_warn(LD_REND, "Failed to run the proof of work solver"); tor_free(job->pow_solution_out); job->pow_solution_out = NULL; /* how we signal that we came up empty */ - return WQ_RPL_REPLY; } - - /* we have a winner! */ - log_info(LD_REND, "cpuworker has a proof of work solution"); return WQ_RPL_REPLY; } |