aboutsummaryrefslogtreecommitdiff
path: root/src/feature/hs/hs_pow.h
blob: 587cae61551b92706e8dc2df822ec2ad82c9a857 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
/* Copyright (c) 2019-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */

/**
 * \file hs_pow.h
 * \brief Header file containing PoW denial of service defenses for the HS
 *        subsystem for all versions.
 **/

#ifndef TOR_HS_POW_H
#define TOR_HS_POW_H

typedef unsigned __int128 uint128_t;

#include "ext/equix/include/equix.h"

#include "lib/evloop/compat_libevent.h"
#include "lib/smartlist_core/smartlist_core.h"

#define HS_POW_SUGGESTED_EFFORT_DEFAULT 20 // HRPR TODO 5000
/* Service updates the suggested effort every HS_UPDATE_PERIOD seconds. */
#define HS_UPDATE_PERIOD 300 // HRPR TODO Should be consensus

/** Length of random nonce (N) used in the PoW scheme. */
#define HS_POW_NONCE_LEN 16
/** Length of an E-quiX solution (S) in bytes. */
#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 random seed used in the PoW scheme. */
#define HS_POW_SEED_LEN 32
/** Length of an effort value */
#define HS_POW_EFFORT_LEN sizeof(uint32_t)
/** Length of a PoW challenge. Construction as per prop327 is:
 *    (C || N || INT_32(E))
 */
#define HS_POW_CHALLENGE_LEN \
  (HS_POW_SEED_LEN + HS_POW_NONCE_LEN + HS_POW_EFFORT_LEN)

/** Type of PoW in the descriptor. */
typedef enum {
  HS_POW_DESC_V1 = 1,
} hs_pow_desc_type_t;

/** Proof-of-Work parameters for DoS defense located in a descriptor. */
typedef struct hs_pow_desc_params_t {
  /** Type of PoW system being used. */
  hs_pow_desc_type_t type;

  /** Random 32-byte seed used as input the the PoW hash function. Decoded? */
  uint8_t seed[HS_POW_SEED_LEN];

  /** Specifies effort value that clients should aim for when contacting the
   * service. */
  uint32_t suggested_effort;

  /** Timestamp after which the above seed expires. */
  time_t expiration_time;
} hs_pow_desc_params_t;

/** State and parameters of PoW defenses, stored in the service state. */
typedef struct hs_pow_service_state_t {
  /* If PoW defenses are enabled this is a priority queue containing acceptable
   * requests that are awaiting rendezvous circuits to built, where priority is
   * based on the amount of effort that was exerted in the PoW. */
  smartlist_t *rend_request_pqueue;

  /* HRPR TODO Is this cursed? Including compat_libevent for this. feb 24 */
  /* When PoW defenses are enabled, this event pops rendezvous requests from
   * the service's priority queue; higher effort is higher priority. */
  mainloop_event_t *pop_pqueue_ev;

  /* The current seed being used in the PoW defenses. */
  uint8_t seed_current[HS_POW_SEED_LEN];

  /* The previous seed that was used in the PoW defenses. We accept solutions
   * for both the current and previous seed.  */
  uint8_t seed_previous[HS_POW_SEED_LEN];

  /* The time at which the current seed expires and rotates for a new one. */
  time_t expiration_time;

  /* The minimum effort required for a valid solution. */
  uint32_t min_effort;

  /* The suggested effort that clients should use in order for their request to
   * be serviced in a timely manner. */
  uint32_t suggested_effort;

  /* The maximum effort of a request we've had to trim, this update period */
  uint32_t max_trimmed_effort;

  /* The following values are used when calculating and updating the suggested
   * effort every HS_UPDATE_PERIOD seconds. */

  /* Number of intro requests the service handled since last update. */
  uint32_t rend_handled;
  /* The next time at which to update the suggested effort. */
  time_t next_effort_update;
  /* Sum of effort of all valid requests received since the last update. */
  uint64_t total_effort;
  /* Did we have elements waiting in the queue during this period? */
  bool had_queue;
} hs_pow_service_state_t;

/* Struct to store a solution to the PoW challenge. */
typedef struct hs_pow_solution_t {
  /** HRPR TODO are we best off storing this as a byte array, as trunnel doesnt
   * support uint128 (?) */
  /* The 16 byte nonce used in the solution. */
  uint128_t nonce;

  /* The effort used in the solution. */
  uint32_t effort;

  /* The first four bytes of the seed used in the solution. */
  uint32_t seed_head;

  /* The Equi-X solution used in the solution. */
  equix_solution equix_solution;
} hs_pow_solution_t;

/* API */
int hs_pow_solve(const hs_pow_desc_params_t *pow_params,
                 hs_pow_solution_t *pow_solution_out);

int hs_pow_verify(const hs_pow_service_state_t *pow_state,
                  const hs_pow_solution_t *pow_solution);

void hs_pow_remove_seed_from_cache(uint32_t seed);
void hs_pow_free_service_state(hs_pow_service_state_t *state);

int pow_queue_work(uint32_t intro_circ_identifier,
                   uint32_t rend_circ_identifier,
                   const hs_pow_desc_params_t *pow_params);

#endif /* !defined(TOR_HS_POW_H) */