|
@@ -17,20 +17,24 @@
|
|
static void dircollator_collate_by_rsa(dircollator_t *dc);
|
|
static void dircollator_collate_by_rsa(dircollator_t *dc);
|
|
static void dircollator_collate_by_ed25519(dircollator_t *dc);
|
|
static void dircollator_collate_by_ed25519(dircollator_t *dc);
|
|
|
|
|
|
|
|
+/** Hashtable entry mapping a pair of digests (actually an ed25519 key and an
|
|
|
|
+ * RSA SHA1 digest) to an array of vote_routerstatus_t. */
|
|
typedef struct ddmap_entry_s {
|
|
typedef struct ddmap_entry_s {
|
|
HT_ENTRY(ddmap_entry_s) node;
|
|
HT_ENTRY(ddmap_entry_s) node;
|
|
uint8_t d[DIGEST_LEN + DIGEST256_LEN];
|
|
uint8_t d[DIGEST_LEN + DIGEST256_LEN];
|
|
|
|
+ /* The nth member of this array corresponds to the vote_routerstatus_t (if
|
|
|
|
+ * any) received for this digest pair from the nth voter. */
|
|
vote_routerstatus_t *vrs_lst[FLEXIBLE_ARRAY_MEMBER];
|
|
vote_routerstatus_t *vrs_lst[FLEXIBLE_ARRAY_MEMBER];
|
|
} ddmap_entry_t;
|
|
} ddmap_entry_t;
|
|
|
|
|
|
-double_digest_map_t *by_both_ids;
|
|
|
|
-
|
|
|
|
|
|
+/** Release all storage held by e. */
|
|
static void
|
|
static void
|
|
ddmap_entry_free(ddmap_entry_t *e)
|
|
ddmap_entry_free(ddmap_entry_t *e)
|
|
{
|
|
{
|
|
tor_free(e);
|
|
tor_free(e);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/** Return a new empty ddmap_entry, with <b>n_votes</b> elements in vrs_list. */
|
|
static ddmap_entry_t *
|
|
static ddmap_entry_t *
|
|
ddmap_entry_new(int n_votes)
|
|
ddmap_entry_new(int n_votes)
|
|
{
|
|
{
|
|
@@ -50,6 +54,8 @@ ddmap_entry_eq(const ddmap_entry_t *a, const ddmap_entry_t *b)
|
|
return fast_memeq(a->d, b->d, sizeof(a->d));
|
|
return fast_memeq(a->d, b->d, sizeof(a->d));
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/** Record the RSA identity of <b>ent</b> as <b>rsa_sha1</b>, and the
|
|
|
|
+ * ed25519 identity as <b>ed25519</b>. */
|
|
static void
|
|
static void
|
|
ddmap_entry_set_digests(ddmap_entry_t *ent,
|
|
ddmap_entry_set_digests(ddmap_entry_t *ent,
|
|
const uint8_t *rsa_sha1,
|
|
const uint8_t *rsa_sha1,
|
|
@@ -63,6 +69,10 @@ HT_PROTOTYPE(double_digest_map, ddmap_entry_s, node, ddmap_entry_hash,
|
|
ddmap_entry_eq);
|
|
ddmap_entry_eq);
|
|
HT_GENERATE2(double_digest_map, ddmap_entry_s, node, ddmap_entry_hash,
|
|
HT_GENERATE2(double_digest_map, ddmap_entry_s, node, ddmap_entry_hash,
|
|
ddmap_entry_eq, 0.6, tor_reallocarray, tor_free_);
|
|
ddmap_entry_eq, 0.6, tor_reallocarray, tor_free_);
|
|
|
|
+
|
|
|
|
+/** Helper: add a single vote_routerstatus_t <b>vrs</b> to the collator
|
|
|
|
+ * <b>dc</b>, indexing it by its RSA key digest, and by the 2-tuple of
|
|
|
|
+ * its RSA key digest and Ed25519 key. */
|
|
static void
|
|
static void
|
|
dircollator_add_routerstatus(dircollator_t *dc,
|
|
dircollator_add_routerstatus(dircollator_t *dc,
|
|
int vote_num,
|
|
int vote_num,
|
|
@@ -71,6 +81,8 @@ dircollator_add_routerstatus(dircollator_t *dc,
|
|
{
|
|
{
|
|
const char *id = vrs->status.identity_digest;
|
|
const char *id = vrs->status.identity_digest;
|
|
|
|
|
|
|
|
+ vrs->ed25519_reflects_consensus = 0;
|
|
|
|
+
|
|
(void) vote;
|
|
(void) vote;
|
|
vote_routerstatus_t **vrs_lst = digestmap_get(dc->by_rsa_sha1, id);
|
|
vote_routerstatus_t **vrs_lst = digestmap_get(dc->by_rsa_sha1, id);
|
|
if (NULL == vrs_lst) {
|
|
if (NULL == vrs_lst) {
|
|
@@ -82,7 +94,7 @@ dircollator_add_routerstatus(dircollator_t *dc,
|
|
|
|
|
|
const uint8_t *ed = vrs->ed25519_id;
|
|
const uint8_t *ed = vrs->ed25519_id;
|
|
|
|
|
|
- if (tor_mem_is_zero((char*)ed, DIGEST256_LEN))
|
|
|
|
|
|
+ if (! vrs->has_ed25519_listing)
|
|
return;
|
|
return;
|
|
|
|
|
|
ddmap_entry_t search, *found;
|
|
ddmap_entry_t search, *found;
|
|
@@ -99,6 +111,8 @@ dircollator_add_routerstatus(dircollator_t *dc,
|
|
vrs_lst[vote_num] = vrs;
|
|
vrs_lst[vote_num] = vrs;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/** Create and return a new dircollator object to use when collating
|
|
|
|
+ * <b>n_votes</b> out of a total of <b>n_authorities</b>. */
|
|
dircollator_t *
|
|
dircollator_t *
|
|
dircollator_new(int n_votes, int n_authorities)
|
|
dircollator_new(int n_votes, int n_authorities)
|
|
{
|
|
{
|
|
@@ -115,6 +129,7 @@ dircollator_new(int n_votes, int n_authorities)
|
|
return dc;
|
|
return dc;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/** Release all storage held by <b>dc</b>. */
|
|
void
|
|
void
|
|
dircollator_free(dircollator_t *dc)
|
|
dircollator_free(dircollator_t *dc)
|
|
{
|
|
{
|
|
@@ -139,6 +154,10 @@ dircollator_free(dircollator_t *dc)
|
|
tor_free(dc);
|
|
tor_free(dc);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/** Add a single vote <b>v</b> to a dircollator <b>dc</b>. This function must
|
|
|
|
+ * be called exactly once for each vote to be used in the consensus. It may
|
|
|
|
+ * only be called before dircollator_collate().
|
|
|
|
+ */
|
|
void
|
|
void
|
|
dircollator_add_vote(dircollator_t *dc, networkstatus_t *v)
|
|
dircollator_add_vote(dircollator_t *dc, networkstatus_t *v)
|
|
{
|
|
{
|
|
@@ -153,13 +172,16 @@ dircollator_add_vote(dircollator_t *dc, networkstatus_t *v)
|
|
} SMARTLIST_FOREACH_END(vrs);
|
|
} SMARTLIST_FOREACH_END(vrs);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/** Sort the entries in <b>dc</b> according to <b>consensus_method</b>, so
|
|
|
|
+ * that the consensus process can iterate over them with
|
|
|
|
+ * dircollator_n_routers() and dircollator_get_votes_for_router(). */
|
|
void
|
|
void
|
|
dircollator_collate(dircollator_t *dc, int consensus_method)
|
|
dircollator_collate(dircollator_t *dc, int consensus_method)
|
|
{
|
|
{
|
|
tor_assert(!dc->is_collated);
|
|
tor_assert(!dc->is_collated);
|
|
dc->all_rsa_sha1_lst = smartlist_new();
|
|
dc->all_rsa_sha1_lst = smartlist_new();
|
|
|
|
|
|
- if (consensus_method < MIN_METHOD_FOR_ED25519_ID_VOTING + 10/*XXX*/)
|
|
|
|
|
|
+ if (consensus_method < MIN_METHOD_FOR_ED25519_ID_VOTING)
|
|
dircollator_collate_by_rsa(dc);
|
|
dircollator_collate_by_rsa(dc);
|
|
else
|
|
else
|
|
dircollator_collate_by_ed25519(dc);
|
|
dircollator_collate_by_ed25519(dc);
|
|
@@ -168,6 +190,15 @@ dircollator_collate(dircollator_t *dc, int consensus_method)
|
|
dc->is_collated = 1;
|
|
dc->is_collated = 1;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * Collation function for RSA-only consensuses: collate the votes for each
|
|
|
|
+ * entry in <b>dc</b> by their RSA keys.
|
|
|
|
+ *
|
|
|
|
+ * The rule is:
|
|
|
|
+ * If an RSA identity key is listed by more than half of the authorities,
|
|
|
|
+ * include that identity, and treat all descriptors with that RSA identity
|
|
|
|
+ * as describing the same router.
|
|
|
|
+ */
|
|
static void
|
|
static void
|
|
dircollator_collate_by_rsa(dircollator_t *dc)
|
|
dircollator_collate_by_rsa(dircollator_t *dc)
|
|
{
|
|
{
|
|
@@ -189,6 +220,20 @@ dircollator_collate_by_rsa(dircollator_t *dc)
|
|
dc->by_collated_rsa_sha1 = dc->by_rsa_sha1;
|
|
dc->by_collated_rsa_sha1 = dc->by_rsa_sha1;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * Collation function for ed25519 consensuses: collate the votes for each
|
|
|
|
+ * entry in <b>dc</b> by ed25519 key and by RSA key.
|
|
|
|
+ *
|
|
|
|
+ * The rule is, approximately:
|
|
|
|
+ * If a <ed,rsa> identity is listed by more than half of authorities,
|
|
|
|
+ * include it. And include all <rsa>-only votes about that node as
|
|
|
|
+ * matching.
|
|
|
|
+ *
|
|
|
|
+ * Otherwise, if an <*,rsa> or <rsa> identity is listed by more than
|
|
|
|
+ * half of the authorities, and no <ed,rsa> pair for the same RSA key
|
|
|
|
+ * has been already been included based on the rule above, include
|
|
|
|
+ * that RSA identity.
|
|
|
|
+ */
|
|
static void
|
|
static void
|
|
dircollator_collate_by_ed25519(dircollator_t *dc)
|
|
dircollator_collate_by_ed25519(dircollator_t *dc)
|
|
{
|
|
{
|
|
@@ -197,6 +242,7 @@ dircollator_collate_by_ed25519(dircollator_t *dc)
|
|
|
|
|
|
ddmap_entry_t **iter;
|
|
ddmap_entry_t **iter;
|
|
|
|
|
|
|
|
+ /* Go over all <ed,rsa> pairs */
|
|
HT_FOREACH(iter, double_digest_map, &dc->by_both_ids) {
|
|
HT_FOREACH(iter, double_digest_map, &dc->by_both_ids) {
|
|
ddmap_entry_t *ent = *iter;
|
|
ddmap_entry_t *ent = *iter;
|
|
int n = 0, i;
|
|
int n = 0, i;
|
|
@@ -205,9 +251,13 @@ dircollator_collate_by_ed25519(dircollator_t *dc)
|
|
++n;
|
|
++n;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /* If not enough authorties listed this exact <ed,rsa> pair,
|
|
|
|
+ * don't include it. */
|
|
if (n <= total_authorities / 2)
|
|
if (n <= total_authorities / 2)
|
|
continue;
|
|
continue;
|
|
|
|
|
|
|
|
+ /* Now consider whether there are any other entries with the same
|
|
|
|
+ * RSA key (but with possibly different or missing ed value). */
|
|
vote_routerstatus_t **vrs_lst2 = digestmap_get(dc->by_rsa_sha1,
|
|
vote_routerstatus_t **vrs_lst2 = digestmap_get(dc->by_rsa_sha1,
|
|
(char*)ent->d);
|
|
(char*)ent->d);
|
|
tor_assert(vrs_lst2);
|
|
tor_assert(vrs_lst2);
|
|
@@ -220,13 +270,17 @@ dircollator_collate_by_ed25519(dircollator_t *dc)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /* Record that we have seen this RSA digest. */
|
|
digestmap_set(rsa_digests, (char*)ent->d, ent->vrs_lst);
|
|
digestmap_set(rsa_digests, (char*)ent->d, ent->vrs_lst);
|
|
smartlist_add(dc->all_rsa_sha1_lst, ent->d);
|
|
smartlist_add(dc->all_rsa_sha1_lst, ent->d);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /* Now look over all entries with an RSA digest, looking for RSA digests
|
|
|
|
+ * we didn't put in yet.
|
|
|
|
+ */
|
|
DIGESTMAP_FOREACH(dc->by_rsa_sha1, k, vote_routerstatus_t **, vrs_lst) {
|
|
DIGESTMAP_FOREACH(dc->by_rsa_sha1, k, vote_routerstatus_t **, vrs_lst) {
|
|
if (digestmap_get(rsa_digests, k) != NULL)
|
|
if (digestmap_get(rsa_digests, k) != NULL)
|
|
- continue;
|
|
|
|
|
|
+ continue; /* We already included this RSA digest */
|
|
|
|
|
|
int n = 0, i;
|
|
int n = 0, i;
|
|
for (i = 0; i < dc->n_votes; ++i) {
|
|
for (i = 0; i < dc->n_votes; ++i) {
|
|
@@ -235,7 +289,7 @@ dircollator_collate_by_ed25519(dircollator_t *dc)
|
|
}
|
|
}
|
|
|
|
|
|
if (n <= total_authorities / 2)
|
|
if (n <= total_authorities / 2)
|
|
- continue;
|
|
|
|
|
|
+ continue; /* Not enough votes */
|
|
|
|
|
|
digestmap_set(rsa_digests, k, vrs_lst);
|
|
digestmap_set(rsa_digests, k, vrs_lst);
|
|
smartlist_add(dc->all_rsa_sha1_lst, (char *)k);
|
|
smartlist_add(dc->all_rsa_sha1_lst, (char *)k);
|
|
@@ -244,15 +298,27 @@ dircollator_collate_by_ed25519(dircollator_t *dc)
|
|
dc->by_collated_rsa_sha1 = rsa_digests;
|
|
dc->by_collated_rsa_sha1 = rsa_digests;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/** Return the total number of collated router entries. This function may
|
|
|
|
+ * only be called after dircollator_collate. */
|
|
int
|
|
int
|
|
dircollator_n_routers(dircollator_t *dc)
|
|
dircollator_n_routers(dircollator_t *dc)
|
|
{
|
|
{
|
|
|
|
+ tor_assert(dc->is_collated);
|
|
return smartlist_len(dc->all_rsa_sha1_lst);
|
|
return smartlist_len(dc->all_rsa_sha1_lst);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/** Return an array of vote_routerstatus_t entries for the <b>idx</b>th router
|
|
|
|
+ * in the collation order. Each array contains n_votes elements, where the
|
|
|
|
+ * nth element of the array is the vote_routerstatus_t from the nth voter for
|
|
|
|
+ * this identity (or NULL if there is no such entry).
|
|
|
|
+ *
|
|
|
|
+ * The maximum value for <b>idx</b> is dircollator_n_routers().
|
|
|
|
+ *
|
|
|
|
+ * This function may only be called after dircollator_collate. */
|
|
vote_routerstatus_t **
|
|
vote_routerstatus_t **
|
|
dircollator_get_votes_for_router(dircollator_t *dc, int idx)
|
|
dircollator_get_votes_for_router(dircollator_t *dc, int idx)
|
|
{
|
|
{
|
|
|
|
+ tor_assert(dc->is_collated);
|
|
tor_assert(idx < smartlist_len(dc->all_rsa_sha1_lst));
|
|
tor_assert(idx < smartlist_len(dc->all_rsa_sha1_lst));
|
|
return digestmap_get(dc->by_collated_rsa_sha1,
|
|
return digestmap_get(dc->by_collated_rsa_sha1,
|
|
smartlist_get(dc->all_rsa_sha1_lst, idx));
|
|
smartlist_get(dc->all_rsa_sha1_lst, idx));
|