Tor  0.4.7.0-alpha-dev
circuitpadding_machines.c
Go to the documentation of this file.
1 /* Copyright (c) 2019 The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
3 
4 /**
5  * \file circuitpadding_machines.c
6  * \brief Circuit padding state machines
7  *
8  * Introduce circuit padding machines that will be used by Tor circuits, as
9  * specified by proposal 302 "Hiding onion service clients using padding".
10  *
11  * Right now this file introduces two machines that aim to hide the client-side
12  * of onion service circuits against naive classifiers like the ones from the
13  * "Circuit Fingerprinting Attacks: Passive Deanonymization of Tor Hidden
14  * Services" paper from USENIX. By naive classifiers we mean classifiers that
15  * use basic features like "circuit construction circuits" and "incoming and
16  * outgoing cell counts" and "duration of activity".
17  *
18  * In particular, these machines aim to be lightweight and protect against
19  * these basic classifiers. They don't aim to protect against more advanced
20  * attacks that use deep learning or even correlate various circuit
21  * construction events together. Machines that fool such advanced classifiers
22  * are also possible, but they can't be so lightweight and might require more
23  * WTF-PAD features. So for now we opt for the following two machines:
24  *
25  * Client-side introduction circuit hiding machine:
26  *
27  * This machine hides client-side introduction circuits by making their
28  * circuit construction sequence look like normal general circuits that
29  * download directory information. Furthermore, the circuits are kept open
30  * until all the padding has been sent, since intro circuits are usually
31  * very short lived and this act as a distinguisher. For more info see
32  * circpad_machine_client_hide_intro_circuits() and the sec.
33  *
34  * Client-side rendezvous circuit hiding machine:
35  *
36  * This machine hides client-side rendezvous circuits by making their
37  * circuit construction sequence look like normal general circuits. For more
38  * details see circpad_machine_client_hide_rend_circuits() and the spec.
39  *
40  * TODO: These are simple machines that carefully manipulate the cells of the
41  * initial circuit setup procedure to make them look like general
42  * circuits. In the future, more states can be baked into their state machine
43  * to do more advanced obfuscation.
44  **/
45 
46 #define CIRCUITPADDING_MACHINES_PRIVATE
47 
48 #include "core/or/or.h"
50 
52 
53 #include "core/or/circuitlist.h"
54 
56 #include "core/or/circuitpadding.h"
57 
58 /** Create a client-side padding machine that aims to hide IP circuits. In
59  * particular, it keeps intro circuits alive until a bunch of fake traffic has
60  * been pushed through.
61  */
62 void
64 {
65  circpad_machine_spec_t *client_machine
66  = tor_malloc_zero(sizeof(circpad_machine_spec_t));
67 
68  client_machine->name = "client_ip_circ";
69 
70  client_machine->conditions.apply_state_mask = CIRCPAD_CIRC_OPENED;
71  client_machine->target_hopnum = 2;
72 
73  /* This is a client machine */
74  client_machine->is_origin_side = 1;
75 
76  /* We only want to pad introduction circuits, and we want to start padding
77  * only after the INTRODUCE1 cell has been sent, so set the purposes
78  * appropriately.
79  *
80  * In particular we want introduction circuits to blend as much as possible
81  * with general circuits. Most general circuits have the following initial
82  * relay cell sequence (outgoing cells marked in [brackets]):
83  *
84  * [EXTEND2] -> EXTENDED2 -> [EXTEND2] -> EXTENDED2 -> [BEGIN] -> CONNECTED
85  * -> [DATA] -> [DATA] -> DATA -> DATA...(inbound data cells continue)
86  *
87  * Whereas normal introduction circuits usually look like:
88  *
89  * [EXTEND2] -> EXTENDED2 -> [EXTEND2] -> EXTENDED2 -> [EXTEND2] -> EXTENDED2
90  * -> [INTRO1] -> INTRODUCE_ACK
91  *
92  * This means that up to the sixth cell (first line of each sequence above),
93  * both general and intro circuits have identical cell sequences. After that
94  * we want to mimic the second line sequence of
95  * -> [DATA] -> [DATA] -> DATA -> DATA...(inbound data cells continue)
96  *
97  * We achieve this by starting padding INTRODUCE1 has been sent. With padding
98  * negotiation cells, in the common case of the second line looks like:
99  * -> [INTRO1] -> [PADDING_NEGOTIATE] -> PADDING_NEGOTIATED -> INTRO_ACK
100  *
101  * Then, the middle node will send between INTRO_MACHINE_MINIMUM_PADDING and
102  * INTRO_MACHINE_MAXIMUM_PADDING cells, to match the "...(inbound data cells
103  * continue)" portion of the trace (aka the rest of an HTTPS response body).
104  */
105 
106  /* Start the machine on fresh intro circs. */
107  client_machine->conditions.apply_purpose_mask =
109 
110  /* If the client purpose changes back to CIRCUIT_PURPOSE_C_INTRODUCING,
111  * or transitions to CIRCUIT_PURPOSE_C_INTRODUCE_ACKED, keep the machine
112  * alive, but do not launch new machines for these purposes. Also
113  * keep the machine around if it is in the CIRCUIT_PADDING purpose
114  * (but do not try to take over other machines in that purpose). */
115  client_machine->conditions.keep_purpose_mask =
118 
119  /* Keep the circuit alive even after the introduction has been finished,
120  * otherwise the short-term lifetime of the circuit will blow our cover */
121  client_machine->manage_circ_lifetime = 1;
122 
123  /* Set padding machine limits to help guard against excessive padding */
124  client_machine->allowed_padding_count = INTRO_MACHINE_MAXIMUM_PADDING;
125  client_machine->max_padding_percent = 1;
126 
127  /* Two states: START, OBFUSCATE_CIRC_SETUP (and END) */
128  circpad_machine_states_init(client_machine, 2);
129 
130  /* For the origin-side machine, we transition to OBFUSCATE_CIRC_SETUP after
131  * sending PADDING_NEGOTIATE, and we stay there (without sending any padding)
132  * until we receive a STOP from the other side. */
133  client_machine->states[CIRCPAD_STATE_START].
134  next_state[CIRCPAD_EVENT_NONPADDING_SENT] =
135  CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP;
136 
137  /* origin-side machine has no event reactions while in
138  * CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP, so no more state transitions here. */
139 
140  /* The client side should never send padding, so it does not need
141  * to specify token removal, or a histogram definition or state lengths.
142  * That is all controlled by the middle node. */
143 
144  /* Register the machine */
145  client_machine->machine_num = smartlist_len(machines_sl);
146  circpad_register_padding_machine(client_machine, machines_sl);
147 
148  log_info(LD_CIRC,
149  "Registered client intro point hiding padding machine (%u)",
150  client_machine->machine_num);
151 }
152 
153 /** Create a relay-side padding machine that aims to hide IP circuits. See
154  * comments on the function above for more details on the workings of the
155  * machine. */
156 void
158 {
159  circpad_machine_spec_t *relay_machine
160  = tor_malloc_zero(sizeof(circpad_machine_spec_t));
161 
162  relay_machine->name = "relay_ip_circ";
163 
164  relay_machine->conditions.apply_state_mask = CIRCPAD_CIRC_OPENED;
165 
166  /* This is a relay-side machine */
167  relay_machine->is_origin_side = 0;
168 
169  /* We want to negotiate END from this side after all our padding is done, so
170  * that the origin-side machine goes into END state, and eventually closes
171  * the circuit. */
172  relay_machine->should_negotiate_end = 1;
173 
174  /* Set padding machine limits to help guard against excessive padding */
175  relay_machine->allowed_padding_count = INTRO_MACHINE_MAXIMUM_PADDING;
176  relay_machine->max_padding_percent = 1;
177 
178  /* Two states: START, OBFUSCATE_CIRC_SETUP (and END) */
179  circpad_machine_states_init(relay_machine, 2);
180 
181  /* For the relay-side machine, we want to transition
182  * START -> OBFUSCATE_CIRC_SETUP upon first non-padding
183  * cell sent (PADDING_NEGOTIATED in this case). */
184  relay_machine->states[CIRCPAD_STATE_START].
185  next_state[CIRCPAD_EVENT_NONPADDING_SENT] =
186  CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP;
187 
188  /* For the relay-side, we want to transition from OBFUSCATE_CIRC_SETUP to END
189  * state when the length finishes. */
190  relay_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP].
191  next_state[CIRCPAD_EVENT_LENGTH_COUNT] = CIRCPAD_STATE_END;
192 
193  /* Now let's define the OBF -> OBF transitions that maintain our padding
194  * flow:
195  *
196  * For the relay-side machine, we want to keep on sending padding bytes even
197  * when nothing else happens on this circuit. */
198  relay_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP].
199  next_state[CIRCPAD_EVENT_PADDING_SENT] =
200  CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP;
201  /* For the relay-side machine, we need this transition so that we re-enter
202  the state, after PADDING_NEGOTIATED is sent. Otherwise, the remove token
203  function will disable the timer, and nothing will restart it since there
204  is no other motion on an intro circuit. */
205  relay_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP].
206  next_state[CIRCPAD_EVENT_NONPADDING_SENT] =
207  CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP;
208 
209  /* Token removal strategy for OBFUSCATE_CIRC_SETUP state: Don't
210  * remove any tokens.
211  *
212  * We rely on the state length sampling and not token removal, to avoid
213  * the mallocs required to copy the histograms for token removal,
214  * and to avoid monotime calls needed to determine histogram
215  * bins for token removal. */
216  relay_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP].
217  token_removal = CIRCPAD_TOKEN_REMOVAL_NONE;
218 
219  /* Figure out the length of the OBFUSCATE_CIRC_SETUP state so that it's
220  * randomized. The relay side will send between INTRO_MACHINE_MINIMUM_PADDING
221  * and INTRO_MACHINE_MAXIMUM_PADDING padding cells towards the client. */
222  relay_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP].
223  length_dist.type = CIRCPAD_DIST_UNIFORM;
224  relay_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP].
225  length_dist.param1 = INTRO_MACHINE_MINIMUM_PADDING;
226  relay_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP].
227  length_dist.param2 = INTRO_MACHINE_MAXIMUM_PADDING;
228 
229  /* Configure histogram */
230  relay_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP].
231  histogram_len = 2;
232 
233  /* For the relay-side machine we want to batch padding instantly to pretend
234  * its an incoming directory download. So set the histogram edges tight:
235  * (1, 10ms, infinity). */
236  relay_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP].
237  histogram_edges[0] = 1000;
238  relay_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP].
239  histogram_edges[1] = 10000;
240 
241  /* We put all our tokens in bin 0, which means we want 100% probability
242  * for choosing a inter-packet delay of between 1000 and 10000 microseconds
243  * (1 to 10ms). Since we only have 1 bin, it doesn't matter how many tokens
244  * there are, 1000 out of 1000 is 100% */
245  relay_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP].
246  histogram[0] = 1000;
247 
248  /* just one bin, so setup the total tokens */
249  relay_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP].
250  histogram_total_tokens =
251  relay_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP].histogram[0];
252 
253  /* Register the machine */
254  relay_machine->machine_num = smartlist_len(machines_sl);
255  circpad_register_padding_machine(relay_machine, machines_sl);
256 
257  log_info(LD_CIRC,
258  "Registered relay intro circuit hiding padding machine (%u)",
259  relay_machine->machine_num);
260 }
261 
262 /************************** Rendezvous-circuit machine ***********************/
263 
264 /** Create a client-side padding machine that aims to hide rendezvous
265  * circuits.*/
266 void
268 {
269  circpad_machine_spec_t *client_machine
270  = tor_malloc_zero(sizeof(circpad_machine_spec_t));
271 
272  client_machine->name = "client_rp_circ";
273 
274  /* Only pad after the circuit has been built and pad to the middle */
275  client_machine->conditions.apply_state_mask = CIRCPAD_CIRC_OPENED;
276  client_machine->target_hopnum = 2;
277 
278  /* This is a client machine */
279  client_machine->is_origin_side = 1;
280 
281  /* We only want to pad rendezvous circuits, and we want to start padding only
282  * after the rendezvous circuit has been established.
283  *
284  * Following a similar argument as for intro circuits, we are aiming for
285  * padded rendezvous circuits to blend in with the initial cell sequence of
286  * general circuits which usually look like this:
287  *
288  * [EXTEND2] -> EXTENDED2 -> [EXTEND2] -> EXTENDED2 -> [BEGIN] -> CONNECTED
289  * -> [DATA] -> [DATA] -> DATA -> DATA...(incoming cells continue)
290  *
291  * Whereas normal rendezvous circuits usually look like:
292  *
293  * [EXTEND2] -> EXTENDED2 -> [EXTEND2] -> EXTENDED2 -> [EST_REND] -> REND_EST
294  * -> REND2 -> [BEGIN]
295  *
296  * This means that up to the sixth cell (in the first line), both general and
297  * rend circuits have identical cell sequences.
298  *
299  * After that we want to mimic a [DATA] -> [DATA] -> DATA -> DATA sequence.
300  *
301  * With padding negotiation right after the REND_ESTABLISHED, the sequence
302  * becomes:
303  *
304  * [EXTEND2] -> EXTENDED2 -> [EXTEND2] -> EXTENDED2 -> [EST_REND] -> REND_EST
305  * -> [PADDING_NEGOTIATE] -> [DROP] -> PADDING_NEGOTIATED -> DROP...
306  *
307  * After which normal application DATA cells continue on the circuit.
308  *
309  * Hence this way we make rendezvous circuits look like general circuits up
310  * till the end of the circuit setup. */
311  client_machine->conditions.apply_purpose_mask =
315 
316  /* Set padding machine limits to help guard against excessive padding */
317  client_machine->allowed_padding_count = 1;
318  client_machine->max_padding_percent = 1;
319 
320  /* Two states: START, OBFUSCATE_CIRC_SETUP (and END) */
321  circpad_machine_states_init(client_machine, 2);
322 
323  /* START -> OBFUSCATE_CIRC_SETUP transition upon sending the first
324  * non-padding cell (which is PADDING_NEGOTIATE) */
325  client_machine->states[CIRCPAD_STATE_START].
326  next_state[CIRCPAD_EVENT_NONPADDING_SENT] =
327  CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP;
328 
329  /* OBFUSCATE_CIRC_SETUP -> END transition when we send our first
330  * padding packet and/or hit the state length (the state length is 1). */
331  client_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP].
332  next_state[CIRCPAD_EVENT_PADDING_RECV] = CIRCPAD_STATE_END;
333  client_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP].
334  next_state[CIRCPAD_EVENT_LENGTH_COUNT] = CIRCPAD_STATE_END;
335 
336  /* Don't use a token removal strategy since we don't want to use monotime
337  * functions and we want to avoid mallocing histogram copies. We want
338  * this machine to be light. */
339  client_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP].
340  token_removal = CIRCPAD_TOKEN_REMOVAL_NONE;
341 
342  /* Instead, to control the volume of padding (we just want to send a single
343  * padding cell) we will use a static state length. We just want one token,
344  * since we want to make the following pattern:
345  * [PADDING_NEGOTIATE] -> [DROP] -> PADDING_NEGOTIATED -> DROP */
346  client_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP].
347  length_dist.type = CIRCPAD_DIST_UNIFORM;
348  client_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP].
349  length_dist.param1 = 1;
350  client_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP].
351  length_dist.param2 = 2; // rand(1,2) is always 1
352 
353  /* Histogram is: (0 msecs, 1 msec, infinity). We want this to be fast so
354  * that we send our outgoing [DROP] before the PADDING_NEGOTIATED comes
355  * back from the relay side. */
356  client_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP].
357  histogram_len = 2;
358  client_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP].
359  histogram_edges[0] = 0;
360  client_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP].
361  histogram_edges[1] = 1000;
362 
363  /* We want a 100% probability of choosing an inter-packet delay of
364  * between 0 and 1ms. Since we don't use token removal,
365  * the number of tokens does not matter. (And also, state_length
366  * governs how many packets we send). */
367  client_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP].
368  histogram[0] = 1;
369  client_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP].
370  histogram_total_tokens = 1;
371 
372  /* Register the machine */
373  client_machine->machine_num = smartlist_len(machines_sl);
374  circpad_register_padding_machine(client_machine, machines_sl);
375 
376  log_info(LD_CIRC,
377  "Registered client rendezvous circuit hiding padding machine (%u)",
378  client_machine->machine_num);
379 }
380 
381 /** Create a relay-side padding machine that aims to hide IP circuits.
382  *
383  * This is meant to follow the client-side machine.
384  */
385 void
387 {
388  circpad_machine_spec_t *relay_machine
389  = tor_malloc_zero(sizeof(circpad_machine_spec_t));
390 
391  relay_machine->name = "relay_rp_circ";
392 
393  /* Only pad after the circuit has been built and pad to the middle */
394  relay_machine->conditions.min_hops = 2;
395  relay_machine->conditions.apply_state_mask = CIRCPAD_CIRC_OPENED;
396 
397  /* This is a relay-side machine */
398  relay_machine->is_origin_side = 0;
399 
400  /* Set padding machine limits to help guard against excessive padding */
401  relay_machine->allowed_padding_count = 1;
402  relay_machine->max_padding_percent = 1;
403 
404  /* Two states: START, OBFUSCATE_CIRC_SETUP (and END) */
405  circpad_machine_states_init(relay_machine, 2);
406 
407  /* START -> OBFUSCATE_CIRC_SETUP transition upon sending the first
408  * non-padding cell (which is PADDING_NEGOTIATED) */
409  relay_machine->states[CIRCPAD_STATE_START].
410  next_state[CIRCPAD_EVENT_NONPADDING_SENT] =
411  CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP;
412 
413  /* OBFUSCATE_CIRC_SETUP -> END transition when we send our first
414  * padding packet and/or hit the state length (the state length is 1). */
415  relay_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP].
416  next_state[CIRCPAD_EVENT_PADDING_SENT] = CIRCPAD_STATE_END;
417  relay_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP].
418  next_state[CIRCPAD_EVENT_LENGTH_COUNT] = CIRCPAD_STATE_END;
419 
420  /* Don't use a token removal strategy since we don't want to use monotime
421  * functions and we want to avoid mallocing histogram copies. We want
422  * this machine to be light. */
423  relay_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP].
424  token_removal = CIRCPAD_TOKEN_REMOVAL_NONE;
425 
426  /* Instead, to control the volume of padding (we just want to send a single
427  * padding cell) we will use a static state length. We just want one token,
428  * since we want to make the following pattern:
429  * [PADDING_NEGOTIATE] -> [DROP] -> PADDING_NEGOTIATED -> DROP */
430  relay_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP].
431  length_dist.type = CIRCPAD_DIST_UNIFORM;
432  relay_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP].
433  length_dist.param1 = 1;
434  relay_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP].
435  length_dist.param2 = 2; // rand(1,2) is always 1
436 
437  /* Histogram is: (0 msecs, 1 msec, infinity). We want this to be fast so
438  * that the outgoing DROP cell is sent immediately after the
439  * PADDING_NEGOTIATED. */
440  relay_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP].
441  histogram_len = 2;
442  relay_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP].
443  histogram_edges[0] = 0;
444  relay_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP].
445  histogram_edges[1] = 1000;
446 
447  /* We want a 100% probability of choosing an inter-packet delay of
448  * between 0 and 1ms. Since we don't use token removal,
449  * the number of tokens does not matter. (And also, state_length
450  * governs how many packets we send). */
451  relay_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP].
452  histogram[0] = 1;
453  relay_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP].
454  histogram_total_tokens = 1;
455 
456  /* Register the machine */
457  relay_machine->machine_num = smartlist_len(machines_sl);
458  circpad_register_padding_machine(relay_machine, machines_sl);
459 
460  log_info(LD_CIRC,
461  "Registered relay rendezvous circuit hiding padding machine (%u)",
462  relay_machine->machine_num);
463 }
Header file for circuitlist.c.
#define CIRCUIT_PURPOSE_C_REND_JOINED
Definition: circuitlist.h:88
#define CIRCUIT_PURPOSE_C_CIRCUIT_PADDING
Definition: circuitlist.h:95
#define CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED
Definition: circuitlist.h:86
#define CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT
Definition: circuitlist.h:76
#define CIRCUIT_PURPOSE_C_REND_READY
Definition: circuitlist.h:83
#define CIRCUIT_PURPOSE_C_INTRODUCE_ACKED
Definition: circuitlist.h:79
void circpad_machine_states_init(circpad_machine_spec_t *machine, circpad_statenum_t num_states)
circpad_purpose_mask_t circpad_circ_purpose_to_mask(uint8_t circ_purpose)
Header file for circuitpadding.c.
#define CIRCPAD_STATE_START
#define CIRCPAD_STATE_END
@ CIRCPAD_TOKEN_REMOVAL_NONE
void circpad_machine_client_hide_rend_circuits(smartlist_t *machines_sl)
void circpad_machine_client_hide_intro_circuits(smartlist_t *machines_sl)
void circpad_machine_relay_hide_intro_circuits(smartlist_t *machines_sl)
void circpad_machine_relay_hide_rend_circuits(smartlist_t *machines_sl)
Header file for circuitpadding_machines.c.
Common functions for using (pseudo-)random number generators.
#define LD_CIRC
Definition: log.h:82
Header file for networkstatus.c.
Master header file for Tor-specific functionality.
circpad_purpose_mask_t apply_purpose_mask
circpad_purpose_mask_t keep_purpose_mask
circpad_circuit_state_t apply_state_mask
circpad_machine_num_t machine_num
circpad_state_t * states
circpad_machine_conditions_t conditions
circpad_hist_token_t histogram[CIRCPAD_MAX_HISTOGRAM_LEN]