[tor-commits] [stem/master] Votes didn't set shared randomness properties

atagar at torproject.org atagar at torproject.org
Thu Jan 5 18:10:20 UTC 2017


commit a3320773183d02faee9bb137faa5e45571d9c5b9
Author: Damian Johnson <atagar at torproject.org>
Date:   Thu Jan 5 10:06:24 2017 -0800

    Votes didn't set shared randomness properties
    
    Tor misdocumented the location of shared randomness properties. They're in the
    authority section rather than the header. As such Stem didn't parse them.
    
    Dropping documentation of the broken header attributes and adding the working
    counterparts to the DirectoryAuthority class.
    
      https://trac.torproject.org/projects/tor/ticket/21102
---
 docs/change_log.rst                               |   1 +
 docs/download.rst                                 |   4 +-
 stem/descriptor/networkstatus.py                  |  68 +++++++----
 test/unit/descriptor/networkstatus/document_v3.py | 141 +++++++++++-----------
 4 files changed, 118 insertions(+), 96 deletions(-)

diff --git a/docs/change_log.rst b/docs/change_log.rst
index 5823a04..5870beb 100644
--- a/docs/change_log.rst
+++ b/docs/change_log.rst
@@ -46,6 +46,7 @@ The following are only available within Stem's `git repository
  * **Descriptors**
 
   * Support for protocol descriptor fields (:spec:`eb4fb3c`)
+  * Shared randomness properties weren't being read in votes (:trac:`21102`)
 
 .. _version_1.5:
 
diff --git a/docs/download.rst b/docs/download.rst
index 46defd4..c853f1d 100644
--- a/docs/download.rst
+++ b/docs/download.rst
@@ -71,9 +71,9 @@ Download
 
        Signed releases and instructions for both Python 2.x and 3.x. You can
        easily install from its `tarball
-       <https://pypi.python.org/packages/ff/74/34d2235cd218356359ee746cf0e1aed1ebbc32151b7a4f000746e29366de/stem-1.5.3.tar.gz>`_
+       <https://pypi.python.org/packages/b3/4e/fc6bb6262fa9ca1b308aa735fc2186586106cef0cb4b4ba80aaaa3c9a071/stem-1.5.4.tar.gz>`_
        (`sig
-       <https://pypi.python.org/packages/ff/74/34d2235cd218356359ee746cf0e1aed1ebbc32151b7a4f000746e29366de/stem-1.5.3.tar.gz.asc>`_),
+       <https://pypi.python.org/packages/b3/4e/fc6bb6262fa9ca1b308aa735fc2186586106cef0cb4b4ba80aaaa3c9a071/stem-1.5.4.tar.gz.asc>`_),
        or with **pip**...
 
        ::
diff --git a/stem/descriptor/networkstatus.py b/stem/descriptor/networkstatus.py
index 464b63c..210975d 100644
--- a/stem/descriptor/networkstatus.py
+++ b/stem/descriptor/networkstatus.py
@@ -805,19 +805,6 @@ class NetworkStatusDocumentV3(NetworkStatusDocument):
   :var datetime published: time when the document was published
   :var dict flag_thresholds: **\*** mapping of internal performance thresholds used while making the vote, values are **ints** or **floats**
 
-  :var bool is_shared_randomness_participate: **\*** **True** if this authority
-    participates in establishing a shared random value, **False** otherwise
-  :var list shared_randomness_commitments: **\*** list of
-    :data:`~stem.descriptor.networkstatus.SharedRandomnessCommitment` entries
-  :var int shared_randomness_previous_reveal_count: number of commitments
-    used to generate the last shared random value
-  :var str shared_randomness_previous_value: base64 encoded last shared random
-    value
-  :var int shared_randomness_current_reveal_count: number of commitments
-    used to generate the current shared random value
-  :var str shared_randomness_current_value: base64 encoded current shared
-    random value
-
   :var dict recommended_client_protocols: recommended protocols for clients
   :var dict recommended_relay_protocols: recommended protocols for relays
   :var dict required_client_protocols: required protocols for clients
@@ -839,6 +826,10 @@ class NetworkStatusDocumentV3(NetworkStatusDocument):
   .. versionchanged:: 1.6.0
      Added the recommended_client_protocols, recommended_relay_protocols,
      required_client_protocols, and required_relay_protocols.
+
+  .. versionchanged:: 1.6.0
+     The shared randomness attributes were misdocumented in the tor spec and as
+     such never set. They're now an attribute of **directory_authorities**.
   """
 
   ATTRIBUTES = {
@@ -860,12 +851,6 @@ class NetworkStatusDocumentV3(NetworkStatusDocument):
     'packages': ([], _parse_package_line),
     'known_flags': ([], _parse_header_known_flags_line),
     'flag_thresholds': ({}, _parse_header_flag_thresholds_line),
-    'is_shared_randomness_participate': (False, _parse_shared_rand_participate_line),
-    'shared_randomness_commitments': ([], _parsed_shared_rand_commit),
-    'shared_randomness_previous_reveal_count': (None, _parse_shared_rand_previous_value),
-    'shared_randomness_previous_value': (None, _parse_shared_rand_previous_value),
-    'shared_randomness_current_reveal_count': (None, _parse_shared_rand_current_value),
-    'shared_randomness_current_value': (None, _parse_shared_rand_current_value),
     'recommended_client_protocols': ({}, _parse_recommended_client_protocols_line),
     'recommended_relay_protocols': ({}, _parse_recommended_relay_protocols_line),
     'required_client_protocols': ({}, _parse_required_client_protocols_line),
@@ -891,10 +876,6 @@ class NetworkStatusDocumentV3(NetworkStatusDocument):
     'package': _parse_package_line,
     'known-flags': _parse_header_known_flags_line,
     'flag-thresholds': _parse_header_flag_thresholds_line,
-    'shared-rand-participate': _parse_shared_rand_participate_line,
-    'shared-rand-commit': _parsed_shared_rand_commit,
-    'shared-rand-previous-value': _parse_shared_rand_previous_value,
-    'shared-rand-current-value': _parse_shared_rand_current_value,
     'recommended-client-protocols': _parse_recommended_client_protocols_line,
     'recommended-relay-protocols': _parse_recommended_relay_protocols_line,
     'required-client-protocols': _parse_required_client_protocols_line,
@@ -923,6 +904,17 @@ class NetworkStatusDocumentV3(NetworkStatusDocument):
     super(NetworkStatusDocumentV3, self).__init__(raw_content, lazy_load = not validate)
     document_file = io.BytesIO(raw_content)
 
+    # TODO: Tor misdocumented these as being in the header rather than the
+    # authority section. As such these have never been set but we need the
+    # attributes for stem 1.5 compatability. Drop these in 2.0.
+
+    self.is_shared_randomness_participate = False
+    self.shared_randomness_commitments = []
+    self.shared_randomness_previous_reveal_count = None
+    self.shared_randomness_previous_value = None
+    self.shared_randomness_current_reveal_count = None
+    self.shared_randomness_current_value = None
+
     self._default_params = default_params
     self._header(document_file, validate)
 
@@ -1214,11 +1206,31 @@ class DirectoryAuthority(Descriptor):
   :var stem.descriptor.networkstatus.KeyCertificate key_certificate: **\***
     authority's key certificate
 
+  :var bool is_shared_randomness_participate: **\*** **True** if this authority
+    participates in establishing a shared random value, **False** otherwise
+  :var list shared_randomness_commitments: **\*** list of
+    :data:`~stem.descriptor.networkstatus.SharedRandomnessCommitment` entries
+  :var int shared_randomness_previous_reveal_count: number of commitments
+    used to generate the last shared random value
+  :var str shared_randomness_previous_value: base64 encoded last shared random
+    value
+  :var int shared_randomness_current_reveal_count: number of commitments
+    used to generate the current shared random value
+  :var str shared_randomness_current_value: base64 encoded current shared
+    random value
+
   **\*** mandatory attribute
 
   .. versionchanged:: 1.4.0
      Renamed our 'fingerprint' attribute to 'v3ident' (prior attribute exists
      for backward compatability, but is deprecated).
+
+  .. versionchanged:: 1.6.0
+     Added the is_shared_randomness_participate, shared_randomness_commitments,
+     shared_randomness_previous_reveal_count,
+     shared_randomness_previous_value,
+     shared_randomness_current_reveal_count, and
+     shared_randomness_current_value attributes.
   """
 
   ATTRIBUTES = {
@@ -1232,6 +1244,12 @@ class DirectoryAuthority(Descriptor):
     'contact': (None, _parse_contact_line),
     'vote_digest': (None, _parse_vote_digest_line),
     'legacy_dir_key': (None, _parse_legacy_dir_key_line),
+    'is_shared_randomness_participate': (False, _parse_shared_rand_participate_line),
+    'shared_randomness_commitments': ([], _parsed_shared_rand_commit),
+    'shared_randomness_previous_reveal_count': (None, _parse_shared_rand_previous_value),
+    'shared_randomness_previous_value': (None, _parse_shared_rand_previous_value),
+    'shared_randomness_current_reveal_count': (None, _parse_shared_rand_current_value),
+    'shared_randomness_current_value': (None, _parse_shared_rand_current_value),
   }
 
   PARSER_FOR_LINE = {
@@ -1239,6 +1257,10 @@ class DirectoryAuthority(Descriptor):
     'contact': _parse_contact_line,
     'legacy-dir-key': _parse_legacy_dir_key_line,
     'vote-digest': _parse_vote_digest_line,
+    'shared-rand-participate': _parse_shared_rand_participate_line,
+    'shared-rand-commit': _parsed_shared_rand_commit,
+    'shared-rand-previous-value': _parse_shared_rand_previous_value,
+    'shared-rand-current-value': _parse_shared_rand_current_value,
   }
 
   def __init__(self, raw_content, validate = False, is_vote = False):
diff --git a/test/unit/descriptor/networkstatus/document_v3.py b/test/unit/descriptor/networkstatus/document_v3.py
index ef3717a..f34bcc8 100644
--- a/test/unit/descriptor/networkstatus/document_v3.py
+++ b/test/unit/descriptor/networkstatus/document_v3.py
@@ -832,77 +832,6 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
       document = NetworkStatusDocumentV3(content, False)
       self.assertEqual({}, document.flag_thresholds)
 
-  def test_shared_randomness(self):
-    """
-    Parses the shared randomness attributes.
-    """
-
-    COMMITMENT_1 = '1 sha3-256 4CAEC248004A0DC6CE86EBD5F608C9B05500C70C AAAAAFd4/kAaklgYr4ijHZjXXy/B354jQfL31BFhhE46nuOHSPITyw== AAAAAFd4/kCpZeis3yJyr//rz8hXCeeAhHa4k3lAcAiMJd1vEMTPuw=='
-    COMMITMENT_2 = '1 sha3-256 598536A9DD4E6C0F18B4AD4B88C7875A0A29BA31 AAAAAFd4/kC7S920awC5/HF5RfX4fKZtYqjm6qMh9G91AcjZm13DQQ=='
-
-    document = get_network_status_document_v3(OrderedDict([
-      ('vote-status', 'vote'),
-      ('shared-rand-participate', ''),
-      ('shared-rand-commit', '%s\nshared-rand-commit %s' % (COMMITMENT_1, COMMITMENT_2)),
-      ('shared-rand-previous-value', '8 hAQLxyt0U3gu7QR2owixRCbIltcyPrz3B0YBfUshOkE='),
-      ('shared-rand-current-value', '7 KEIfSB7Db+ToasQIzJhbh0CtkeSePHLEehO+ams/RTU='),
-    ]))
-
-    self.assertEqual(True, document.is_shared_randomness_participate)
-    self.assertEqual(8, document.shared_randomness_previous_reveal_count)
-    self.assertEqual('hAQLxyt0U3gu7QR2owixRCbIltcyPrz3B0YBfUshOkE=', document.shared_randomness_previous_value)
-    self.assertEqual(7, document.shared_randomness_current_reveal_count)
-    self.assertEqual('KEIfSB7Db+ToasQIzJhbh0CtkeSePHLEehO+ams/RTU=', document.shared_randomness_current_value)
-
-    self.assertEqual(2, len(document.shared_randomness_commitments))
-
-    first_commitment = document.shared_randomness_commitments[0]
-    self.assertEqual(1, first_commitment.version)
-    self.assertEqual('sha3-256', first_commitment.algorithm)
-    self.assertEqual('4CAEC248004A0DC6CE86EBD5F608C9B05500C70C', first_commitment.identity)
-    self.assertEqual('AAAAAFd4/kAaklgYr4ijHZjXXy/B354jQfL31BFhhE46nuOHSPITyw==', first_commitment.commit)
-    self.assertEqual('AAAAAFd4/kCpZeis3yJyr//rz8hXCeeAhHa4k3lAcAiMJd1vEMTPuw==', first_commitment.reveal)
-
-    second_commitment = document.shared_randomness_commitments[1]
-    self.assertEqual(1, second_commitment.version)
-    self.assertEqual('sha3-256', second_commitment.algorithm)
-    self.assertEqual('598536A9DD4E6C0F18B4AD4B88C7875A0A29BA31', second_commitment.identity)
-    self.assertEqual('AAAAAFd4/kC7S920awC5/HF5RfX4fKZtYqjm6qMh9G91AcjZm13DQQ==', second_commitment.commit)
-    self.assertEqual(None, second_commitment.reveal)
-
-  def test_shared_randomness_malformed(self):
-    """
-    Checks shared randomness with malformed values.
-    """
-
-    test_values = [
-      ({'vote-status': 'vote', 'shared-rand-commit': 'hi sha3-256 598536A9DD4E6C0F18B4AD4B88C7875A0A29BA31 AAAAAFd4/kC7S920awC5/HF5RfX4fKZtYqjm6qMh9G91AcjZm13DQQ=='},
-        "The version on our 'shared-rand-commit' line wasn't an integer: hi sha3-256 598536A9DD4E6C0F18B4AD4B88C7875A0A29BA31 AAAAAFd4/kC7S920awC5/HF5RfX4fKZtYqjm6qMh9G91AcjZm13DQQ=="),
-      ({'vote-status': 'vote', 'shared-rand-commit': 'sha3-256 598536A9DD4E6C0F18B4AD4B88C7875A0A29BA31 AAAAAFd4/kC7S920awC5/HF5RfX4fKZtYqjm6qMh9G91AcjZm13DQQ=='},
-        "'shared-rand-commit' must at least have a 'Version AlgName Identity Commit': sha3-256 598536A9DD4E6C0F18B4AD4B88C7875A0A29BA31 AAAAAFd4/kC7S920awC5/HF5RfX4fKZtYqjm6qMh9G91AcjZm13DQQ=="),
-      ({'vote-status': 'vote', 'shared-rand-current-value': 'hi KEIfSB7Db+ToasQIzJhbh0CtkeSePHLEehO+ams/RTU='},
-        "A network status document's 'shared-rand-current-value' line must be a pair of values, the first an integer but was 'hi KEIfSB7Db+ToasQIzJhbh0CtkeSePHLEehO+ams/RTU='"),
-      ({'vote-status': 'vote', 'shared-rand-current-value': 'KEIfSB7Db+ToasQIzJhbh0CtkeSePHLEehO+ams/RTU='},
-        "A network status document's 'shared-rand-current-value' line must be a pair of values, the first an integer but was 'KEIfSB7Db+ToasQIzJhbh0CtkeSePHLEehO+ams/RTU='"),
-    ]
-
-    for attr, expected_exception in test_values:
-      content = get_network_status_document_v3(attr, content = True)
-
-      try:
-        NetworkStatusDocumentV3(content, True)
-        self.fail("validation should've rejected malformed shared randomness attribute")
-      except ValueError as exc:
-        self.assertEqual(expected_exception, str(exc))
-
-      document = NetworkStatusDocumentV3(content, False)
-
-      self.assertEqual([], document.shared_randomness_commitments)
-      self.assertEqual(None, document.shared_randomness_previous_reveal_count)
-      self.assertEqual(None, document.shared_randomness_previous_value)
-      self.assertEqual(None, document.shared_randomness_current_reveal_count)
-      self.assertEqual(None, document.shared_randomness_current_value)
-
   def test_parameters(self):
     """
     Parses the parameters attributes.
@@ -1258,6 +1187,76 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
           document = NetworkStatusDocumentV3(content, validate = False)
           self.assertEqual((authority1, authority2), document.directory_authorities)
 
+  def test_shared_randomness(self):
+    """
+    Parses the shared randomness attributes.
+    """
+
+    COMMITMENT_1 = '1 sha3-256 4CAEC248004A0DC6CE86EBD5F608C9B05500C70C AAAAAFd4/kAaklgYr4ijHZjXXy/B354jQfL31BFhhE46nuOHSPITyw== AAAAAFd4/kCpZeis3yJyr//rz8hXCeeAhHa4k3lAcAiMJd1vEMTPuw=='
+    COMMITMENT_2 = '1 sha3-256 598536A9DD4E6C0F18B4AD4B88C7875A0A29BA31 AAAAAFd4/kC7S920awC5/HF5RfX4fKZtYqjm6qMh9G91AcjZm13DQQ=='
+
+    authority = get_directory_authority(OrderedDict([
+      ('shared-rand-participate', ''),
+      ('shared-rand-commit', '%s\nshared-rand-commit %s' % (COMMITMENT_1, COMMITMENT_2)),
+      ('shared-rand-previous-value', '8 hAQLxyt0U3gu7QR2owixRCbIltcyPrz3B0YBfUshOkE='),
+      ('shared-rand-current-value', '7 KEIfSB7Db+ToasQIzJhbh0CtkeSePHLEehO+ams/RTU='),
+    ]))
+
+    self.assertEqual(True, authority.is_shared_randomness_participate)
+    self.assertEqual(8, authority.shared_randomness_previous_reveal_count)
+    self.assertEqual('hAQLxyt0U3gu7QR2owixRCbIltcyPrz3B0YBfUshOkE=', authority.shared_randomness_previous_value)
+    self.assertEqual(7, authority.shared_randomness_current_reveal_count)
+    self.assertEqual('KEIfSB7Db+ToasQIzJhbh0CtkeSePHLEehO+ams/RTU=', authority.shared_randomness_current_value)
+
+    self.assertEqual(2, len(authority.shared_randomness_commitments))
+
+    first_commitment = authority.shared_randomness_commitments[0]
+    self.assertEqual(1, first_commitment.version)
+    self.assertEqual('sha3-256', first_commitment.algorithm)
+    self.assertEqual('4CAEC248004A0DC6CE86EBD5F608C9B05500C70C', first_commitment.identity)
+    self.assertEqual('AAAAAFd4/kAaklgYr4ijHZjXXy/B354jQfL31BFhhE46nuOHSPITyw==', first_commitment.commit)
+    self.assertEqual('AAAAAFd4/kCpZeis3yJyr//rz8hXCeeAhHa4k3lAcAiMJd1vEMTPuw==', first_commitment.reveal)
+
+    second_commitment = authority.shared_randomness_commitments[1]
+    self.assertEqual(1, second_commitment.version)
+    self.assertEqual('sha3-256', second_commitment.algorithm)
+    self.assertEqual('598536A9DD4E6C0F18B4AD4B88C7875A0A29BA31', second_commitment.identity)
+    self.assertEqual('AAAAAFd4/kC7S920awC5/HF5RfX4fKZtYqjm6qMh9G91AcjZm13DQQ==', second_commitment.commit)
+    self.assertEqual(None, second_commitment.reveal)
+
+  def test_shared_randomness_malformed(self):
+    """
+    Checks shared randomness with malformed values.
+    """
+
+    test_values = [
+      ({'vote-status': 'vote', 'shared-rand-commit': 'hi sha3-256 598536A9DD4E6C0F18B4AD4B88C7875A0A29BA31 AAAAAFd4/kC7S920awC5/HF5RfX4fKZtYqjm6qMh9G91AcjZm13DQQ=='},
+        "The version on our 'shared-rand-commit' line wasn't an integer: hi sha3-256 598536A9DD4E6C0F18B4AD4B88C7875A0A29BA31 AAAAAFd4/kC7S920awC5/HF5RfX4fKZtYqjm6qMh9G91AcjZm13DQQ=="),
+      ({'vote-status': 'vote', 'shared-rand-commit': 'sha3-256 598536A9DD4E6C0F18B4AD4B88C7875A0A29BA31 AAAAAFd4/kC7S920awC5/HF5RfX4fKZtYqjm6qMh9G91AcjZm13DQQ=='},
+        "'shared-rand-commit' must at least have a 'Version AlgName Identity Commit': sha3-256 598536A9DD4E6C0F18B4AD4B88C7875A0A29BA31 AAAAAFd4/kC7S920awC5/HF5RfX4fKZtYqjm6qMh9G91AcjZm13DQQ=="),
+      ({'vote-status': 'vote', 'shared-rand-current-value': 'hi KEIfSB7Db+ToasQIzJhbh0CtkeSePHLEehO+ams/RTU='},
+        "A network status document's 'shared-rand-current-value' line must be a pair of values, the first an integer but was 'hi KEIfSB7Db+ToasQIzJhbh0CtkeSePHLEehO+ams/RTU='"),
+      ({'vote-status': 'vote', 'shared-rand-current-value': 'KEIfSB7Db+ToasQIzJhbh0CtkeSePHLEehO+ams/RTU='},
+        "A network status document's 'shared-rand-current-value' line must be a pair of values, the first an integer but was 'KEIfSB7Db+ToasQIzJhbh0CtkeSePHLEehO+ams/RTU='"),
+    ]
+
+    for attr, expected_exception in test_values:
+      content = get_directory_authority(attr, content = True)
+
+      try:
+        DirectoryAuthority(content, True)
+        self.fail("validation should've rejected malformed shared randomness attribute")
+      except ValueError as exc:
+        self.assertEqual(expected_exception, str(exc))
+
+      authority = DirectoryAuthority(content, False)
+
+      self.assertEqual([], authority.shared_randomness_commitments)
+      self.assertEqual(None, authority.shared_randomness_previous_reveal_count)
+      self.assertEqual(None, authority.shared_randomness_previous_value)
+      self.assertEqual(None, authority.shared_randomness_current_reveal_count)
+      self.assertEqual(None, authority.shared_randomness_current_value)
+
   def test_with_legacy_directory_authorities(self):
     """
     Includes both normal authorities and those following the '-legacy' format.



More information about the tor-commits mailing list