hs_pow: Modify challenge format, include blinded HS id

This is a protocol breaking change that implements nickm's
changes to prop 327 to add an algorithm personalization string
and blinded HS id to the EquiX challenge string for our onion
service client puzzle.

This corresponds with the spec changes in torspec!130,
and it fixes a proposed vulnerability documented in
ticket tor#40789.

Clients and services prior to this patch will no longer
be compatible with the proposed "v1" proof-of-work protocol.

Signed-off-by: Micah Elizabeth Scott <beth@torproject.org>
This commit is contained in:
Micah Elizabeth Scott 2023-05-08 23:58:30 -07:00
parent 138fd57072
commit e643a70879
10 changed files with 187 additions and 74 deletions

View File

@ -799,6 +799,7 @@ hs_cell_parse_intro_established(const uint8_t *payload, size_t payload_len)
* including if PoW couldn't be verified. */
static int
handle_introduce2_encrypted_cell_pow_extension(const hs_service_t *service,
const hs_service_intro_point_t *ip,
const trn_extension_field_t *field,
hs_cell_introduce2_data_t *data)
{
@ -807,6 +808,7 @@ handle_introduce2_encrypted_cell_pow_extension(const hs_service_t *service,
hs_pow_solution_t sol;
tor_assert(field);
tor_assert(ip);
if (!service->state.pow_state) {
log_info(LD_REND, "Unsolicited PoW solution in INTRODUCE2 request.");
@ -840,7 +842,7 @@ handle_introduce2_encrypted_cell_pow_extension(const hs_service_t *service,
trn_cell_extension_pow_getconstarray_pow_solution(pow),
HS_POW_EQX_SOL_LEN);
if (hs_pow_verify(service->state.pow_state, &sol)) {
if (hs_pow_verify(&ip->blinded_id, service->state.pow_state, &sol)) {
log_info(LD_REND, "PoW INTRODUCE2 request failed to verify.");
goto end;
}
@ -930,6 +932,7 @@ get_introduce2_keys_and_verify_mac(hs_cell_introduce2_data_t *data,
* includes a PoW that doesn't verify). */
static int
parse_introduce_cell_extension(const hs_service_t *service,
const hs_service_intro_point_t *ip,
hs_cell_introduce2_data_t *data,
const trn_extension_field_t *field)
{
@ -948,7 +951,7 @@ parse_introduce_cell_extension(const hs_service_t *service,
break;
case TRUNNEL_EXT_TYPE_POW:
/* PoW request. If successful, the effort is put in the data. */
if (handle_introduce2_encrypted_cell_pow_extension(service,
if (handle_introduce2_encrypted_cell_pow_extension(service, ip,
field, data) < 0) {
log_fn(LOG_PROTOCOL_WARN, LD_REND, "Invalid PoW cell extension.");
ret = -1;
@ -969,7 +972,8 @@ parse_introduce_cell_extension(const hs_service_t *service,
ssize_t
hs_cell_parse_introduce2(hs_cell_introduce2_data_t *data,
const origin_circuit_t *circ,
const hs_service_t *service)
const hs_service_t *service,
const hs_service_intro_point_t *ip)
{
int ret = -1;
time_t elapsed;
@ -1102,7 +1106,7 @@ hs_cell_parse_introduce2(hs_cell_introduce2_data_t *data,
/* The number of extensions should match the number of fields. */
break;
}
if (parse_introduce_cell_extension(service, data, field) < 0) {
if (parse_introduce_cell_extension(service, ip, data, field) < 0) {
goto done;
}
}

View File

@ -122,7 +122,8 @@ ssize_t hs_cell_parse_intro_established(const uint8_t *payload,
size_t payload_len);
ssize_t hs_cell_parse_introduce2(hs_cell_introduce2_data_t *data,
const origin_circuit_t *circ,
const hs_service_t *service);
const hs_service_t *service,
const hs_service_intro_point_t *ip);
int hs_cell_parse_introduce_ack(const uint8_t *payload, size_t payload_len);
int hs_cell_parse_rendezvous2(const uint8_t *payload, size_t payload_len,
uint8_t *handshake_info,

View File

@ -1333,7 +1333,7 @@ hs_circ_handle_introduce2(const hs_service_t *service,
goto done;
}
if (hs_cell_parse_introduce2(&data, circ, service) < 0) {
if (hs_cell_parse_introduce2(&data, circ, service, ip) < 0) {
hs_metrics_reject_intro_req(service, HS_METRICS_ERR_INTRO_REQ_INTRODUCE2);
goto done;
}

View File

@ -752,6 +752,8 @@ consider_sending_introduce1(origin_circuit_t *intro_circ,
hs_pow_solver_inputs_t pow_inputs = {
.effort = desc->encrypted_data.pow_params->suggested_effort
};
ed25519_pubkey_copy(&pow_inputs.service_blinded_id,
&desc->plaintext_data.blinded_pubkey);
memcpy(pow_inputs.seed, desc->encrypted_data.pow_params->seed,
sizeof pow_inputs.seed);
log_debug(LD_REND, "PoW params present in descriptor, suggested_effort=%u",

View File

@ -9,6 +9,8 @@
#include <stdio.h>
#include "core/or/or.h"
#include "app/config/config.h"
#include "ext/ht.h"
#include "ext/compat_blake2.h"
#include "core/or/circuitlist.h"
@ -20,6 +22,7 @@
#include "feature/hs/hs_client.h"
#include "feature/hs/hs_pow.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "lib/crypt_ops/crypto_format.h"
#include "lib/arch/bytes.h"
#include "lib/cc/ctassert.h"
#include "core/mainloop/cpuworker.h"
@ -85,7 +88,7 @@ increment_and_set_nonce(uint8_t *nonce, uint8_t *challenge)
break;
}
}
memcpy(challenge + HS_POW_SEED_LEN, nonce, HS_POW_NONCE_LEN);
memcpy(challenge + HS_POW_NONCE_OFFSET, nonce, HS_POW_NONCE_LEN);
}
/* Helper: Allocate an EquiX context, using the much faster compiled
@ -105,18 +108,32 @@ build_equix_ctx(equix_ctx_flags flags)
return ctx;
}
/* Helper: Build EquiX challenge (C || N || INT_32(E)) and return a newly
* allocated buffer containing it. */
/* Helper: Build EquiX challenge (P || ID || C || N || INT_32(E)) and return
* a newly allocated buffer containing it. */
static uint8_t *
build_equix_challenge(const uint8_t *seed, const uint8_t *nonce,
build_equix_challenge(const ed25519_public_key_t *blinded_id,
const uint8_t *seed, const uint8_t *nonce,
const uint32_t effort)
{
/* Build EquiX challenge (C || N || INT_32(E)). */
size_t offset = 0;
uint8_t *challenge = tor_malloc_zero(HS_POW_CHALLENGE_LEN);
memcpy(challenge, seed, HS_POW_SEED_LEN);
CTASSERT(HS_POW_ID_LEN == sizeof *blinded_id);
tor_assert_nonfatal(!ed25519_public_key_is_zero(blinded_id));
log_debug(LD_REND,
"Constructing EquiX challenge with "
"blinded service id %s, effort: %d",
safe_str_client(ed25519_fmt(blinded_id)),
effort);
memcpy(challenge + offset, HS_POW_PSTRING, HS_POW_PSTRING_LEN);
offset += HS_POW_PSTRING_LEN;
memcpy(challenge + offset, blinded_id, HS_POW_ID_LEN);
offset += HS_POW_ID_LEN;
memcpy(challenge + offset, seed, HS_POW_SEED_LEN);
offset += HS_POW_SEED_LEN;
tor_assert(HS_POW_NONCE_OFFSET == offset);
memcpy(challenge + offset, nonce, HS_POW_NONCE_LEN);
offset += HS_POW_NONCE_LEN;
set_uint32(challenge + offset, tor_htonl(effort));
@ -193,8 +210,9 @@ hs_pow_solve(const hs_pow_solver_inputs_t *pow_inputs,
/* Generate a random nonce N. */
crypto_rand((char *)nonce, sizeof nonce);
/* Build EquiX challenge (C || N || INT_32(E)). */
challenge = build_equix_challenge(pow_inputs->seed, nonce, effort);
/* Build EquiX challenge string */
challenge = build_equix_challenge(&pow_inputs->service_blinded_id,
pow_inputs->seed, nonce, effort);
ctx = build_equix_ctx(EQUIX_CTX_SOLVE);
if (!ctx) {
@ -243,7 +261,8 @@ hs_pow_solve(const hs_pow_solver_inputs_t *pow_inputs,
* parameters found in pow_state. Returns 0 on success and -1 otherwise. Called
* by the service. */
int
hs_pow_verify(const hs_pow_service_state_t *pow_state,
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)
{
int ret = -1;
@ -254,6 +273,8 @@ hs_pow_verify(const hs_pow_service_state_t *pow_state,
tor_assert(pow_state);
tor_assert(pow_solution);
tor_assert(service_blinded_id);
tor_assert_nonfatal(!ed25519_public_key_is_zero(service_blinded_id));
/* Find a valid seed C that starts with the seed head. Fail if no such seed
* exists. */
@ -278,13 +299,13 @@ hs_pow_verify(const hs_pow_service_state_t *pow_state,
goto done;
}
/* Build the challenge with the param we have. */
challenge = build_equix_challenge(seed, pow_solution->nonce,
pow_solution->effort);
/* Build the challenge with the params we have. */
challenge = build_equix_challenge(service_blinded_id, seed,
pow_solution->nonce, pow_solution->effort);
if (!validate_equix_challenge(challenge, pow_solution->equix_solution,
pow_solution->effort)) {
log_warn(LD_REND, "Equi-X solution and effort was too large.");
log_warn(LD_REND, "Verification of challenge effort in PoW failed.");
goto done;
}
@ -293,7 +314,7 @@ hs_pow_verify(const hs_pow_service_state_t *pow_state,
goto done;
}
/* Fail if equix_verify(C || N || E, S) != EQUIX_OK */
/* Fail if equix_verify() != 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,
@ -482,6 +503,8 @@ hs_pow_queue_work(uint32_t intro_circ_identifier,
tor_assert(in_main_thread());
tor_assert(rend_circ_cookie);
tor_assert(pow_inputs);
tor_assert_nonfatal(
!ed25519_public_key_is_zero(&pow_inputs->service_blinded_id));
pow_worker_job_t *job = tor_malloc_zero(sizeof(*job));
job->intro_circ_identifier = intro_circ_identifier;

View File

@ -13,6 +13,7 @@
#include "lib/evloop/compat_libevent.h"
#include "lib/evloop/token_bucket.h"
#include "lib/smartlist_core/smartlist_core.h"
#include "lib/crypt_ops/crypto_ed25519.h"
/* Service updates the suggested effort every HS_UPDATE_PERIOD seconds.
* This parameter controls how often we can change hs descriptor data to
@ -30,17 +31,27 @@
#define HS_POW_EQX_SOL_LEN 16
/** Length of blake2b hash result (R) used in the PoW scheme. */
#define HS_POW_HASH_LEN 4
/** Length of algorithm personalization string (P) used in the PoW scheme */
#define HS_POW_PSTRING_LEN 16
/** Algorithm personalization string (P) */
#define HS_POW_PSTRING "Tor hs intro v1\0"
/** Length of the blinded public ID for the onion service (ID) */
#define HS_POW_ID_LEN 32
/** Length of random seed used in the PoW scheme. */
#define HS_POW_SEED_LEN 32
/** Length of seed identification heading in the PoW scheme. */
#define HS_POW_SEED_HEAD_LEN 4
/** Length of an effort value */
#define HS_POW_EFFORT_LEN sizeof(uint32_t)
/** Offset of the nonce value within the challenge string */
#define HS_POW_NONCE_OFFSET \
(HS_POW_PSTRING_LEN + HS_POW_ID_LEN + HS_POW_SEED_LEN)
/** Length of a PoW challenge. Construction as per prop327 is:
* (C || N || INT_32(E))
* (P || ID || C || N || INT_32(E))
*/
#define HS_POW_CHALLENGE_LEN \
(HS_POW_SEED_LEN + HS_POW_NONCE_LEN + HS_POW_EFFORT_LEN)
(HS_POW_PSTRING_LEN + HS_POW_ID_LEN + \
HS_POW_SEED_LEN + HS_POW_NONCE_LEN + HS_POW_EFFORT_LEN)
/** Type of PoW in the descriptor. */
typedef enum {
@ -68,7 +79,8 @@ typedef struct hs_pow_desc_params_t {
typedef struct hs_pow_solver_inputs_t {
/** Seed value from a current descriptor */
uint8_t seed[HS_POW_SEED_LEN];
/** Blinded public ID for the onion service this puzzle is bound to */
ed25519_public_key_t service_blinded_id;
/** Effort chosen by the client. May be higher or ower than
* suggested_effort in the descriptor. */
uint32_t effort;
@ -152,7 +164,8 @@ typedef struct hs_pow_solution_t {
int hs_pow_solve(const hs_pow_solver_inputs_t *pow_inputs,
hs_pow_solution_t *pow_solution_out);
int hs_pow_verify(const hs_pow_service_state_t *pow_state,
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);
void hs_pow_remove_seed_from_cache(const uint8_t *seed_head);
@ -175,9 +188,11 @@ hs_pow_solve(const hs_pow_solver_inputs_t *pow_inputs,
}
static inline int
hs_pow_verify(const hs_pow_service_state_t *pow_state,
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)
{
(void)service_blinded_id;
(void)pow_state;
(void)pow_solution;
return -1;

View File

@ -2304,6 +2304,14 @@ pick_needed_intro_points(hs_service_t *service,
safe_str_client(service->onion_address));
goto done;
}
/* Save a copy of the specific version of the blinded ID that we
* use to reach this intro point. Needed to validate proof-of-work
* solutions that are bound to this specific service. */
tor_assert(desc->desc);
ed25519_pubkey_copy(&ip->blinded_id,
&desc->desc->plaintext_data.blinded_pubkey);
/* Valid intro point object, add it to the descriptor current map. */
service_intro_point_add(desc->intro_points.map, ip);
}

View File

@ -62,6 +62,10 @@ typedef struct hs_service_intro_point_t {
/** Encryption keypair for the "ntor" type. */
curve25519_keypair_t enc_key_kp;
/** Blinded public ID for this service, from this intro point's
* active time period. */
ed25519_public_key_t blinded_id;
/** Legacy key if that intro point doesn't support v3. This should be used if
* the base object legacy flag is set. */
crypto_pk_t *legacy_key;

View File

@ -264,6 +264,7 @@ test_hs_pow_vectors(void *arg)
uint32_t validated_effort;
int expected_retval;
const char *seed_hex;
const char *service_blinded_id_hex;
const char *nonce_hex;
const char *sol_hex;
const char *encoded_hex;
@ -272,6 +273,7 @@ test_hs_pow_vectors(void *arg)
/* All zero, expect invalid */
1, 0, -1,
"0000000000000000000000000000000000000000000000000000000000000000",
"1111111111111111111111111111111111111111111111111111111111111111",
"00000000000000000000000000000000", "00000000000000000000000000000000",
"01"
"00000000000000000000000000000000"
@ -282,67 +284,74 @@ test_hs_pow_vectors(void *arg)
/* Valid zero-effort solution */
0, 0, 0,
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"55555555555555555555555555555555", "fd57d7676238c0ad1d5473aa2d0cbff5",
"1111111111111111111111111111111111111111111111111111111111111111",
"55555555555555555555555555555555", "4312f87ceab844c78e1c793a913812d7",
"01"
"55555555555555555555555555555555"
"00000000" "aaaaaaaa"
"fd57d7676238c0ad1d5473aa2d0cbff5"
"4312f87ceab844c78e1c793a913812d7"
},
{
/* Valid high-effort solution */
1000000, 1000000, 0,
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"16505855555555555555555555555555", "bf2c2d345e5773b5c32ec5596244bdbc",
"1111111111111111111111111111111111111111111111111111111111111111",
"59217255555555555555555555555555", "0f3db97b9cac20c1771680a1a34848d3",
"01"
"16505855555555555555555555555555"
"59217255555555555555555555555555"
"000f4240" "aaaaaaaa"
"bf2c2d345e5773b5c32ec5596244bdbc"
"0f3db97b9cac20c1771680a1a34848d3"
},
{
/* Reject replays */
1000000, 0, -1,
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"16505855555555555555555555555555", "bf2c2d345e5773b5c32ec5596244bdbc",
"1111111111111111111111111111111111111111111111111111111111111111",
"59217255555555555555555555555555", "0f3db97b9cac20c1771680a1a34848d3",
"01"
"16505855555555555555555555555555"
"59217255555555555555555555555555"
"000f4240" "aaaaaaaa"
"bf2c2d345e5773b5c32ec5596244bdbc"
"0f3db97b9cac20c1771680a1a34848d3"
},
{
/* The claimed effort must exactly match what's in the challenge */
99999, 0, -1,
"86fb0acf4932cda44dbb451282f415479462dd10cb97ff5e7e8e2a53c3767a7f",
"cdd49fdbc34326d9d2f18ed277469c63", "7f153437c58620d3ea4717746093dde6",
"bfd298428562e530c52bdb36d81a0e293ef4a0e94d787f0f8c0c611f4f9e78ed",
"2eff9fdbc34326d9d2f18ed277469c63", "400cb091139f86b352119f6e131802d6",
"01"
"cdd49fdbc34326d9d2f18ed277469c63"
"2eff9fdbc34326d9d2f18ed277469c63"
"0001869f" "86fb0acf"
"7f153437c58620d3ea4717746093dde6"
"400cb091139f86b352119f6e131802d6"
},
{
/* Otherwise good solution but with a corrupted nonce */
100000, 0, -1,
"86fb0acf4932cda44dbb451282f415479462dd10cb97ff5e7e8e2a53c3767a7f",
"cdd49fdbc34326d9d2f18ed270469c63", "7f153437c58620d3ea4717746093dde6",
"bfd298428562e530c52bdb36d81a0e293ef4a0e94d787f0f8c0c611f4f9e78ed",
"2eff9fdbc34326d9a2f18ed277469c63", "400cb091139f86b352119f6e131802d6",
"01"
"cdd49fdbc34326d9d2f18ed270469c63"
"2eff9fdbc34326d9a2f18ed277469c63"
"000186a0" "86fb0acf"
"7f153437c58620d3ea4717746093dde6"
"400cb091139f86b352119f6e131802d6"
},
{
/* Corrected version of above */
100000, 100000, 0,
"86fb0acf4932cda44dbb451282f415479462dd10cb97ff5e7e8e2a53c3767a7f",
"cdd49fdbc34326d9d2f18ed277469c63", "7f153437c58620d3ea4717746093dde6",
"bfd298428562e530c52bdb36d81a0e293ef4a0e94d787f0f8c0c611f4f9e78ed",
"2eff9fdbc34326d9d2f18ed277469c63", "400cb091139f86b352119f6e131802d6",
"01"
"cdd49fdbc34326d9d2f18ed277469c63"
"2eff9fdbc34326d9d2f18ed277469c63"
"000186a0" "86fb0acf"
"7f153437c58620d3ea4717746093dde6"
"400cb091139f86b352119f6e131802d6"
}
};
testing_hs_pow_service_t *tsvc = testing_hs_pow_service_new();
hs_pow_service_state_t *pow_state = tor_malloc_zero(sizeof *pow_state);
tsvc->service.state.pow_state = pow_state;
tsvc->service.desc_current = service_descriptor_new();
pow_state->rend_request_pqueue = smartlist_new();
char *mem_op_hex_tmp = NULL;
@ -353,6 +362,7 @@ test_hs_pow_vectors(void *arg)
const unsigned num_vectors = sizeof vectors / sizeof vectors[0];
for (unsigned vec_i = 0; vec_i < num_vectors; vec_i++) {
const int expected_retval = vectors[vec_i].expected_retval;
const char *service_blinded_id_hex = vectors[vec_i].service_blinded_id_hex;
const char *seed_hex = vectors[vec_i].seed_hex;
const char *nonce_hex = vectors[vec_i].nonce_hex;
const char *sol_hex = vectors[vec_i].sol_hex;
@ -368,10 +378,19 @@ test_hs_pow_vectors(void *arg)
};
int retval;
tt_int_op(strlen(service_blinded_id_hex), OP_EQ, 2 * HS_POW_ID_LEN);
tt_int_op(strlen(seed_hex), OP_EQ, 2 * HS_POW_SEED_LEN);
tt_int_op(strlen(nonce_hex), OP_EQ, 2 * sizeof solution.nonce);
tt_int_op(strlen(sol_hex), OP_EQ, 2 * sizeof solution.equix_solution);
tt_assert(tsvc->service.desc_current);
ed25519_public_key_t *desc_blinded_pubkey =
&tsvc->service.desc_current->desc->plaintext_data.blinded_pubkey;
tt_int_op(base16_decode((char*)desc_blinded_pubkey->pubkey,
HS_POW_ID_LEN, service_blinded_id_hex,
2 * HS_POW_ID_LEN),
OP_EQ, HS_POW_ID_LEN);
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);
@ -382,6 +401,7 @@ test_hs_pow_vectors(void *arg)
sol_hex, 2 * HS_POW_EQX_SOL_LEN),
OP_EQ, HS_POW_EQX_SOL_LEN);
ed25519_pubkey_copy(&tsvc->service_ip->blinded_id, desc_blinded_pubkey);
memcpy(solution.seed_head, pow_state->seed_previous, HS_POW_SEED_HEAD_LEN);
/* Try to encode 'solution' into a relay cell */
@ -468,6 +488,7 @@ test_hs_pow_vectors(void *arg)
tor_free(decrypted);
trn_cell_introduce1_free(cell);
trn_cell_introduce_encrypted_free(enc_cell);
service_descriptor_free(tsvc->service.desc_current);
testing_hs_pow_service_free(tsvc);
hs_pow_remove_seed_from_cache(NULL);
}

View File

@ -21,6 +21,7 @@
static int
testing_one_hs_pow_solution(const hs_pow_solution_t *ref_solution,
const ed25519_public_key_t *service_blinded_id,
const uint8_t *seed)
{
int retval = -1;
@ -52,7 +53,8 @@ testing_one_hs_pow_solution(const hs_pow_solution_t *ref_solution,
sol_buffer.equix_solution[variant / 2 % HS_POW_EQX_SOL_LEN]++;
}
tt_int_op(expected, OP_EQ, hs_pow_verify(s, &sol_buffer));
tt_int_op(expected, OP_EQ,
hs_pow_verify(service_blinded_id, s, &sol_buffer));
}
}
@ -77,109 +79,136 @@ test_hs_pow_vectors(void *arg)
uint32_t effort;
const char *solve_rng_hex;
const char *seed_hex;
const char *service_blinded_id_hex;
const char *nonce_hex;
const char *sol_hex;
} vectors[] = {
{
0, "55555555555555555555555555555555",
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"55555555555555555555555555555555", "fd57d7676238c0ad1d5473aa2d0cbff5"
"1111111111111111111111111111111111111111111111111111111111111111",
"55555555555555555555555555555555", "4312f87ceab844c78e1c793a913812d7"
},
{
1, "55555555555555555555555555555555",
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"55555555555555555555555555555555", "703d8bc75492e8f90d836dd21bde61fc"
"1111111111111111111111111111111111111111111111111111111111111111",
"55555555555555555555555555555555", "84355542ab2b3f79532ef055144ac5ab"
},
{
1, "55555555555555555555555555555555",
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"1111111111111111111111111111111111111111111111111111111111111110",
"55555555555555555555555555555555", "115e4b70da858792fc205030b8c83af9"
},
{
2, "55555555555555555555555555555555",
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"56555555555555555555555555555555", "c2374478d35040b53e4eb9aa9f16e9ec"
"1111111111111111111111111111111111111111111111111111111111111111",
"55555555555555555555555555555555", "4600a93a535ed76dc746c99942ab7de2"
},
{
10, "55555555555555555555555555555555",
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"5c555555555555555555555555555555", "b167af85e25a0c961928eff53672c1f8"
"1111111111111111111111111111111111111111111111111111111111111111",
"56555555555555555555555555555555", "128bbda5df2929c3be086de2aad34aed"
},
{
10, "ffffffffffffffffffffffffffffffff",
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"02000000000000000000000000000000", "954e4464715842d391712bb3b2289ff8"
"1111111111111111111111111111111111111111111111111111111111111111",
"01000000000000000000000000000000", "203af985537fadb23f3ed5873b4c81ce"
},
{
1337, "7fffffffffffffffffffffffffffffff",
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"eaffffffffffffffffffffffffffffff", "dbab3eb9045f85f8162c482d43f7d6fc"
"4111111111111111111111111111111111111111111111111111111111111111",
"01000000000000000000000000000000", "31c377cb72796ed80ae77df6ac1d6bfd"
},
{
31337, "00410000000000000000000000000000",
31337, "34a20000000000000000000000000000",
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"23410000000000000000000000000000", "545ddd60e33bfa73ec75aada68608ee8"
"1111111111111111111111111111111111111111111111111111111111111111",
"36a20000000000000000000000000000", "ca6899b91113aaf7536f28db42526bff"
},
{
100, "6b555555555555555555555555555555",
100, "55555555555555555555555555555555",
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"6b555555555555555555555555555555", "7e14e98fed2f35a1b293b39d56b260e9"
"1111111111111111111111111111111111111111111111111111111111111111",
"56555555555555555555555555555555", "3a4122a240bd7abfc922ab3cbb9479ed"
},
{
1000, "0e565555555555555555555555555555",
1000, "d3555555555555555555555555555555",
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"0e565555555555555555555555555555", "514963616e0b986afb1414afa88b85ff"
"1111111111111111111111111111111111111111111111111111111111111111",
"d4555555555555555555555555555555", "338cc08f57697ce8ac2e4b453057d6e9"
},
{
10000, "80835555555555555555555555555555",
10000, "c5715555555555555555555555555555",
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"89835555555555555555555555555555", "7a5164905f8aaec152126258a2462ae6"
"1111111111111111111111111111111111111111111111111111111111111111",
"c8715555555555555555555555555555", "9f2d3d4ed831ac96ad34c25fb59ff3e2"
},
{
100000, "fd995655555555555555555555555555",
100000, "418d5655555555555555555555555555",
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"fd995655555555555555555555555555", "8b27f2664340bc88dd5335821a68f5ff"
"1111111111111111111111111111111111111111111111111111111111111111",
"428d5655555555555555555555555555", "9863f3acd2d15adfd244a7ca61d4c6ff"
},
{
1000000, "15505855555555555555555555555555",
1000000, "58217255555555555555555555555555",
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"16505855555555555555555555555555", "bf2c2d345e5773b5c32ec5596244bdbc"
"1111111111111111111111111111111111111111111111111111111111111111",
"59217255555555555555555555555555", "0f3db97b9cac20c1771680a1a34848d3"
},
{
1, "d0aec1669384bfe5ed39cd724d6c7954",
"c52be1f8a5e6cc3b8fb71cfdbe272cbc91d4d035400f2f94fb0d0074794e0a07",
"d0aec1669384bfe5ed39cd724d6c7954", "9e062190e23b34a80562818b14cf4ae5"
"bfd298428562e530c52bdb36d81a0e293ef4a0e94d787f0f8c0c611f4f9e78ed",
"d1aec1669384bfe5ed39cd724d6c7954", "462606e5f8c2f3f844127b8bfdd6b4ff"
},
{
1, "b4d0e611e6935750fcf9406aae131f62",
"86fb0acf4932cda44dbb451282f415479462dd10cb97ff5e7e8e2a53c3767a7f",
"b4d0e611e6935750fcf9406aae131f62", "a01cf4457a016488df4fa45f0864b6fb"
"bfd298428562e530c52bdb36d81a0e293ef4a0e94d787f0f8c0c611f4f9e78ed",
"b4d0e611e6935750fcf9406aae131f62", "9f3fbd50b1a83fb63284bde44318c0fd"
},
{
1, "b4d0e611e6935750fcf9406aae131f62",
"9dfbd06d86fed8e12de3ab214e1a63ea61f46253fe08346a20378da70c4a327d",
"b5d0e611e6935750fcf9406aae131f62", "5944a260423392780f10b25b7e2502d3"
"bec632eb76123956f99a06d394fcbee8f135b8ed01f2e90aabe404cb0346744a",
"b4d0e611e6935750fcf9406aae131f62", "161baa7490356292d020065fdbe55ffc"
},
{
1, "40559fdbc34326d9d2f18ed277469c63",
"86fb0acf4932cda44dbb451282f415479462dd10cb97ff5e7e8e2a53c3767a7f",
"40559fdbc34326d9d2f18ed277469c63", "31139564ca5262a4f82b9385b2832fce"
"bfd298428562e530c52bdb36d81a0e293ef4a0e94d787f0f8c0c611f4f9e78ed",
"40559fdbc34326d9d2f18ed277469c63", "fa649c6a2c5c0bb6a3511b9ea4b448d1"
},
{
10000, "70559fdbc34326d9d2f18ed277469c63",
10000, "34569fdbc34326d9d2f18ed277469c63",
"86fb0acf4932cda44dbb451282f415479462dd10cb97ff5e7e8e2a53c3767a7f",
"72559fdbc34326d9d2f18ed277469c63", "262c6c82025c53b69b0bf255606ca3e2"
"bfd298428562e530c52bdb36d81a0e293ef4a0e94d787f0f8c0c611f4f9e78ed",
"36569fdbc34326d9d2f18ed277469c63", "2802951e623c74adc443ab93e99633ee"
},
{
100000, "c0d49fdbc34326d9d2f18ed277469c63",
100000, "2cff9fdbc34326d9d2f18ed277469c63",
"86fb0acf4932cda44dbb451282f415479462dd10cb97ff5e7e8e2a53c3767a7f",
"cdd49fdbc34326d9d2f18ed277469c63", "7f153437c58620d3ea4717746093dde6"
"bfd298428562e530c52bdb36d81a0e293ef4a0e94d787f0f8c0c611f4f9e78ed",
"2eff9fdbc34326d9d2f18ed277469c63", "400cb091139f86b352119f6e131802d6"
},
{
1000000, "40fdb1dbc34326d9d2f18ed277469c63",
1000000, "5243b3dbc34326d9d2f18ed277469c63",
"86fb0acf4932cda44dbb451282f415479462dd10cb97ff5e7e8e2a53c3767a7f",
"4cfdb1dbc34326d9d2f18ed277469c63", "b31bbb45340e17a14c2156c0b66780e7"
"bfd298428562e530c52bdb36d81a0e293ef4a0e94d787f0f8c0c611f4f9e78ed",
"5543b3dbc34326d9d2f18ed277469c63", "b47c718b56315e9697173a6bac1feaa4"
},
};
const unsigned num_vectors = sizeof vectors / sizeof vectors[0];
for (unsigned vec_i = 0; vec_i < num_vectors; vec_i++) {
const char *seed_hex = vectors[vec_i].seed_hex;
const char *service_blinded_id_hex = vectors[vec_i].service_blinded_id_hex;
const char *solve_rng_hex = vectors[vec_i].solve_rng_hex;
const char *nonce_hex = vectors[vec_i].nonce_hex;
const char *sol_hex = vectors[vec_i].sol_hex;
@ -191,11 +220,16 @@ test_hs_pow_vectors(void *arg)
.effort = vectors[vec_i].effort,
};
tt_int_op(strlen(service_blinded_id_hex), OP_EQ, 2 * HS_POW_ID_LEN);
tt_int_op(strlen(seed_hex), OP_EQ, 2 * sizeof input.seed);
tt_int_op(strlen(solve_rng_hex), OP_EQ, 2 * sizeof rng_bytes);
tt_int_op(strlen(nonce_hex), OP_EQ, 2 * sizeof solution.nonce);
tt_int_op(strlen(sol_hex), OP_EQ, 2 * sizeof solution.equix_solution);
tt_int_op(base16_decode((char*)input.service_blinded_id.pubkey,
HS_POW_ID_LEN, service_blinded_id_hex,
2 * HS_POW_ID_LEN),
OP_EQ, HS_POW_ID_LEN);
tt_int_op(base16_decode((char*)input.seed, HS_POW_SEED_LEN,
seed_hex, 2 * HS_POW_SEED_LEN),
OP_EQ, HS_POW_SEED_LEN);
@ -223,7 +257,8 @@ test_hs_pow_vectors(void *arg)
tt_mem_op(&solution.equix_solution, OP_EQ, &output.equix_solution,
sizeof output.equix_solution);
tt_int_op(testing_one_hs_pow_solution(&output, input.seed), OP_EQ, 0);
tt_int_op(testing_one_hs_pow_solution(&output, &input.service_blinded_id,
input.seed), OP_EQ, 0);
}
done: