|
@@ -12,18 +12,23 @@ import nacl.hash
|
|
|
import nacl.bindings
|
|
|
import hashlib
|
|
|
|
|
|
+from collections import namedtuple
|
|
|
+
|
|
|
import network
|
|
|
import dirauth
|
|
|
|
|
|
+VRFOutput = namedtuple('VRFOutput', 'output proof')
|
|
|
+
|
|
|
class VRF():
|
|
|
- def __init__(self, private_key):
|
|
|
+ def __init__(self, private_key, relaypicker):
|
|
|
self.private_key = private_key
|
|
|
+ self.relaypicker = relaypicker
|
|
|
|
|
|
def get_output(self, vrf_input):
|
|
|
- output = random.choice(str(vrf_input))
|
|
|
+ output = self.relaypicker.pick_weighted_relay_index()
|
|
|
m = hashlib.sha256()
|
|
|
m.update(str(output).encode())
|
|
|
- m.digest()
|
|
|
+ return VRFOutput(output, m.digest())
|
|
|
|
|
|
class RelayNetMsg(network.NetMsg):
|
|
|
"""The subclass of NetMsg for messages between relays and either
|
|
@@ -199,8 +204,11 @@ class SinglePassCreatedCircuitCell(RelayCell):
|
|
|
"""The message for responding to circuit creation in Single-Pass Walking
|
|
|
Onions."""
|
|
|
|
|
|
- def __init__(self, ntor_reply):
|
|
|
+ def __init__(self, ntor_reply, snip, vrf_output, ttl):
|
|
|
self.ntor_reply = ntor_reply
|
|
|
+ self.snip = snip
|
|
|
+ self.vrf_output = vrf_output
|
|
|
+ self.ttl = ttl
|
|
|
|
|
|
|
|
|
class EncryptedCell(RelayCell):
|
|
@@ -521,22 +529,24 @@ class SinglePassCreatedRelayHandler:
|
|
|
"""Handle a SinglePassCreatedCircuitCell received by a _relay_ that
|
|
|
recently received a SinglePassCreateCircuitMsg from this relay."""
|
|
|
|
|
|
- def __init__(self, ntorreply, next_snip, vrf_output):
|
|
|
+ def __init__(self, ntorreply, next_snip, vrf_output, ttl):
|
|
|
+ self.ntorreply = ntorreply
|
|
|
self.next_snip = next_snip
|
|
|
self.vrf_output = vrf_output
|
|
|
- self.ntorreply = ntorreply
|
|
|
+ self.ttl = ttl
|
|
|
|
|
|
def received_cell(self, circhandler, cell):
|
|
|
logging.debug("Handle a SinglePassCreatedCircuitCell received by a relay")
|
|
|
# Remove ourselves from handling a second
|
|
|
# SinglePassCreatedCircuitCell on this circuit
|
|
|
circhandler.replace_celltype_handler(SinglePassCreatedCircuitCell, None)
|
|
|
- logging.debug("WARNING: Unimplemented! have not yet implemented encrypting the reply directly to the client.")
|
|
|
+ logging.debug("Sending SinglePassCreatedCell")
|
|
|
|
|
|
# Just forward a SinglePassCreatedCircuitCell back towards the
|
|
|
# client
|
|
|
circhandler.adjacent_circuit_handler.send_cell(
|
|
|
- SinglePassCreatedCircuitCell(cell.ntor_reply, self.next_snip))
|
|
|
+ SinglePassCreatedCircuitCell(cell.ntor_reply, self.next_snip,
|
|
|
+ self.vrf_output, self.ttl))
|
|
|
|
|
|
|
|
|
class CircuitHandler:
|
|
@@ -928,9 +938,10 @@ class RelayChannelManager(ChannelManager):
|
|
|
deckey = nacl.hash.sha256(secret + b'upstream')
|
|
|
circhandler.add_crypt_layer(enckey, deckey)
|
|
|
|
|
|
- # Send the ntor reply
|
|
|
+ # Send the ntor reply, but no need to send the snip for the next
|
|
|
+ # relay or vrf proof, as this is the last relay in the circuit.
|
|
|
self.send_msg(CircuitCellMsg(msg.circid,
|
|
|
- SinglePassCreatedCircuitCell(reply)), peeraddr)
|
|
|
+ SinglePassCreatedCircuitCell(reply, None, None, 0)), peeraddr)
|
|
|
|
|
|
elif isinstance(msg, SinglePassCreateCircuitMsg) and msg.ttl > 0:
|
|
|
# A new circuit has arrived
|
|
@@ -960,18 +971,16 @@ class RelayChannelManager(ChannelManager):
|
|
|
logging.debug("RelayChannelManager: Unimplemented! need to translate idx into endive index")
|
|
|
logging.debug("RelayChannelManager: Unimplemented! need to pick the next relay using the shared secret between the client and the relay.")
|
|
|
|
|
|
- # TODO temporary
|
|
|
- next_hop = None
|
|
|
- # make sure the next hop is not the same as ourselves or as the
|
|
|
- # relay that we just received the create message from.
|
|
|
+ # simpulate the VRF output for now
|
|
|
+ vrf_output = VRF(self.onionkey,
|
|
|
+ self.relaypicker).get_output(idx_as_hex)
|
|
|
+
|
|
|
+ next_hop = self.relaypicker.pick_relay_by_uniform_index(vrf_output.output)
|
|
|
+ logging.debug("WARNING: Unimplemented! Need to validate next hop is not null or ourselves, if it is, we should send a CLOSE cell.")
|
|
|
while next_hop == None or next_hop.snipdict["idkey"] == self.idpubkey or next_hop.snipdict["addr"] == peeraddr:
|
|
|
- logging.debug("WARNING: Unimplemented! Need to validate next hop is not null or ourselves, if it is, we should send a CLOSE cell.")
|
|
|
idx = self.relaypicker.pick_weighted_relay_index()
|
|
|
next_hop = self.relaypicker.pick_relay_by_uniform_index(idx)
|
|
|
|
|
|
- # simpulate the VRF output for now
|
|
|
- vrf_output = VRF(self.onionkey).get_output(idx)
|
|
|
-
|
|
|
# Allocate a new circuit id to the requested next hop
|
|
|
channelmgr = circhandler.channel.channelmgr
|
|
|
nexthopchannel = channelmgr.get_channel_to(next_hop.snipdict["addr"])
|
|
@@ -985,7 +994,8 @@ class RelayChannelManager(ChannelManager):
|
|
|
# circuit has been created
|
|
|
newcirchandler.replace_celltype_handler(
|
|
|
SinglePassCreatedCircuitCell,
|
|
|
- SinglePassCreatedRelayHandler(ntorreply, next_hop, vrf_output))
|
|
|
+ SinglePassCreatedRelayHandler(ntorreply, next_hop,
|
|
|
+ vrf_output, msg.ttl))
|
|
|
|
|
|
# Send the next create message to the next hop
|
|
|
nexthopchannel.send_msg(SinglePassCreateCircuitMsg(newcircid,
|