This is an automated email from the git hooks/post-receive script.
dgoulet pushed a commit to branch main in repository tor.
commit 2de98a7f4ea86c234990747fb566e70fef6aee15 Author: Micah Elizabeth Scott beth@torproject.org AuthorDate: Wed Mar 15 12:31:50 2023 -0700
hs_pow: Represent equix_solution as a byte array
This patch is intended to clarify the points at which we convert between the internal representation of an equix_solution and a portable but opaque byte array representation.
Signed-off-by: Micah Elizabeth Scott beth@torproject.org --- src/feature/hs/hs_cell.c | 8 ++++---- src/feature/hs/hs_pow.c | 43 +++++++++++++++++++++++++++++++++++-------- src/feature/hs/hs_pow.h | 6 ++---- src/test/test_hs_pow.c | 9 ++++----- src/test/test_hs_pow_slow.c | 4 ++-- 5 files changed, 47 insertions(+), 23 deletions(-)
diff --git a/src/feature/hs/hs_cell.c b/src/feature/hs/hs_cell.c index dce360fd91..d3639cb92f 100644 --- a/src/feature/hs/hs_cell.c +++ b/src/feature/hs/hs_cell.c @@ -409,7 +409,7 @@ build_introduce_pow_extension(const hs_pow_solution_t *pow_solution, memcpy(trn_cell_extension_pow_getarray_pow_seed(pow_ext), pow_solution->seed_head, TRUNNEL_POW_SEED_HEAD_LEN); memcpy(trn_cell_extension_pow_getarray_pow_solution(pow_ext), - &pow_solution->equix_solution, TRUNNEL_POW_SOLUTION_LEN); + pow_solution->equix_solution, TRUNNEL_POW_SOLUTION_LEN);
/* Set the field with the encoded PoW extension. */ ret = trn_cell_extension_pow_encoded_len(pow_ext); @@ -830,13 +830,13 @@ handle_introduce2_encrypted_cell_pow_extension(const hs_service_t *service, /* Effort E */ sol.effort = trn_cell_extension_pow_get_pow_effort(pow); /* Seed C */ - memcpy(&sol.seed_head, trn_cell_extension_pow_getconstarray_pow_seed(pow), + memcpy(sol.seed_head, trn_cell_extension_pow_getconstarray_pow_seed(pow), HS_POW_SEED_HEAD_LEN); /* Nonce N */ - memcpy(&sol.nonce, trn_cell_extension_pow_getconstarray_pow_nonce(pow), + memcpy(sol.nonce, trn_cell_extension_pow_getconstarray_pow_nonce(pow), HS_POW_NONCE_LEN); /* Solution S */ - memcpy(&sol.equix_solution, + memcpy(sol.equix_solution, trn_cell_extension_pow_getconstarray_pow_solution(pow), HS_POW_EQX_SOL_LEN);
diff --git a/src/feature/hs/hs_pow.c b/src/feature/hs/hs_pow.c index fef809e369..b5a359940c 100644 --- a/src/feature/hs/hs_pow.c +++ b/src/feature/hs/hs_pow.c @@ -13,11 +13,13 @@ #include "ext/compat_blake2.h" #include "core/or/circuitlist.h" #include "core/or/origin_circuit_st.h" +#include "ext/equix/include/equix.h" #include "feature/hs/hs_cache.h" #include "feature/hs/hs_descriptor.h" #include "feature/hs/hs_client.h" #include "feature/hs/hs_pow.h" #include "lib/crypt_ops/crypto_rand.h" +#include "lib/arch/bytes.h" #include "lib/cc/ctassert.h" #include "core/mainloop/cpuworker.h" #include "lib/evloop/workqueue.h" @@ -126,7 +128,8 @@ build_equix_challenge(const uint8_t *seed, const uint8_t *nonce, /** Helper: Return true iff the given challenge and solution for the given * effort do validate as in: R * E <= UINT32_MAX. */ static bool -validate_equix_challenge(const uint8_t *challenge, const equix_solution *sol, +validate_equix_challenge(const uint8_t *challenge, + const uint8_t *solution_bytes, const uint32_t effort) { /* Fail if R * E > UINT32_MAX. */ @@ -139,7 +142,7 @@ validate_equix_challenge(const uint8_t *challenge, const equix_solution *sol,
/* Construct: blake2b(C || N || E || S) */ blake2b_update(&b2_state, challenge, HS_POW_CHALLENGE_LEN); - blake2b_update(&b2_state, (const uint8_t *) sol, HS_POW_EQX_SOL_LEN); + blake2b_update(&b2_state, solution_bytes, HS_POW_EQX_SOL_LEN); blake2b_final(&b2_state, hash_result, HS_POW_HASH_LEN);
/* Scale to 64 bit so we can avoid 32 bit overflow. */ @@ -148,6 +151,28 @@ validate_equix_challenge(const uint8_t *challenge, const equix_solution *sol, return RE <= UINT32_MAX; }
+/** Helper: Convert equix_solution to a byte array in little-endian order */ +static void +pack_equix_solution(const equix_solution *sol_in, + uint8_t *bytes_out) +{ + for (unsigned i = 0; i < EQUIX_NUM_IDX; i++) { + bytes_out[i*2+0] = (uint8_t)sol_in->idx[i]; + bytes_out[i*2+1] = (uint8_t)(sol_in->idx[i] >> 8); + } +} + +/** Helper: Build an equix_solution from its corresponding byte array. */ +static void +unpack_equix_solution(const uint8_t *bytes_in, + equix_solution *sol_out) +{ + for (unsigned i = 0; i < EQUIX_NUM_IDX; i++) { + sol_out->idx[i] = (uint16_t)bytes_in[i*2+0] | + (uint16_t)bytes_in[i*2+1] << 8; + } +} + /** Solve the EquiX/blake2b PoW scheme using the parameters in pow_params, and * store the solution in pow_solution_out. Returns 0 on success and -1 * otherwise. Called by a client. */ @@ -177,16 +202,17 @@ hs_pow_solve(const hs_pow_desc_params_t *pow_params, goto end; } equix_solution solutions[EQUIX_MAX_SOLS]; + uint8_t sol_bytes[HS_POW_EQX_SOL_LEN];
log_notice(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++) { - const equix_solution *sol = &solutions[i]; + pack_equix_solution(&solutions[i], sol_bytes);
/* Check an Equi-X solution against the effort threshold */ - if (validate_equix_challenge(challenge, sol, effort)) { + 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. */ @@ -195,8 +221,7 @@ hs_pow_solve(const hs_pow_desc_params_t *pow_params, memcpy(pow_solution_out->seed_head, pow_params->seed, sizeof(pow_solution_out->seed_head)); /* Store the solution S */ - memcpy(&pow_solution_out->equix_solution, sol, - sizeof(pow_solution_out->equix_solution)); + memcpy(&pow_solution_out->equix_solution, sol_bytes, sizeof sol_bytes);
/* Indicate success and we are done. */ ret = 0; @@ -267,7 +292,7 @@ hs_pow_verify(const hs_pow_service_state_t *pow_state, challenge = build_equix_challenge(seed, pow_solution->nonce, pow_solution->effort);
- if (!validate_equix_challenge(challenge, &pow_solution->equix_solution, + if (!validate_equix_challenge(challenge, pow_solution->equix_solution, pow_solution->effort)) { log_warn(LD_REND, "Equi-X solution and effort was too large."); goto done; @@ -279,8 +304,10 @@ hs_pow_verify(const hs_pow_service_state_t *pow_state, }
/* Fail if equix_verify(C || N || E, S) != EQUIX_OK */ + equix_solution equix_sol; + unpack_equix_solution(pow_solution->equix_solution, &equix_sol); equix_result result = equix_verify(ctx, challenge, HS_POW_CHALLENGE_LEN, - &pow_solution->equix_solution); + &equix_sol); if (result != EQUIX_OK) { log_warn(LD_REND, "Verification of EquiX solution in PoW failed."); goto done; diff --git a/src/feature/hs/hs_pow.h b/src/feature/hs/hs_pow.h index 3d7018ab30..de4d9df94c 100644 --- a/src/feature/hs/hs_pow.h +++ b/src/feature/hs/hs_pow.h @@ -10,8 +10,6 @@ #ifndef TOR_HS_POW_H #define TOR_HS_POW_H
-#include "ext/equix/include/equix.h" - #include "lib/evloop/compat_libevent.h" #include "lib/evloop/token_bucket.h" #include "lib/smartlist_core/smartlist_core.h" @@ -121,8 +119,8 @@ typedef struct hs_pow_solution_t { /* A prefix of the seed used in this solution, so it can be identified. */ uint8_t seed_head[HS_POW_SEED_HEAD_LEN];
- /* The Equi-X solution used in the solution. */ - equix_solution equix_solution; + /* The Equi-X solution used in this PoW solution. */ + uint8_t equix_solution[HS_POW_EQX_SOL_LEN]; } hs_pow_solution_t;
#ifdef HAVE_MODULE_POW diff --git a/src/test/test_hs_pow.c b/src/test/test_hs_pow.c index edda3cd643..ca470e2b5d 100644 --- a/src/test/test_hs_pow.c +++ b/src/test/test_hs_pow.c @@ -374,12 +374,11 @@ test_hs_pow_vectors(void *arg) tt_int_op(base16_decode((char*)pow_state->seed_previous, HS_POW_SEED_LEN, seed_hex, 2 * HS_POW_SEED_LEN), OP_EQ, HS_POW_SEED_LEN); - tt_int_op(base16_decode((char*)&solution.nonce, sizeof solution.nonce, - nonce_hex, 2 * sizeof solution.nonce), + tt_int_op(base16_decode((char*)solution.nonce, HS_POW_NONCE_LEN, + nonce_hex, 2 * HS_POW_NONCE_LEN), OP_EQ, HS_POW_NONCE_LEN); - tt_int_op(base16_decode((char*)&solution.equix_solution, - sizeof solution.equix_solution, - sol_hex, 2 * sizeof solution.equix_solution), + tt_int_op(base16_decode((char*)solution.equix_solution, HS_POW_EQX_SOL_LEN, + sol_hex, 2 * HS_POW_EQX_SOL_LEN), OP_EQ, HS_POW_EQX_SOL_LEN);
memcpy(solution.seed_head, pow_state->seed_previous, HS_POW_SEED_HEAD_LEN); diff --git a/src/test/test_hs_pow_slow.c b/src/test/test_hs_pow_slow.c index 13d7111e88..690ce0cf78 100644 --- a/src/test/test_hs_pow_slow.c +++ b/src/test/test_hs_pow_slow.c @@ -46,9 +46,9 @@ testing_one_hs_pow_solution(const hs_pow_solution_t *ref_solution, expected = 0; } } else if (variant & 1) { - sol_buffer.nonce[variant % HS_POW_NONCE_LEN]++; + sol_buffer.nonce[variant / 2 % HS_POW_NONCE_LEN]++; } else { - sol_buffer.equix_solution.idx[variant % EQUIX_NUM_IDX]++; + sol_buffer.equix_solution[variant / 2 % HS_POW_EQX_SOL_LEN]++; }
tt_int_op(expected, OP_EQ, hs_pow_verify(s, &sol_buffer));