|
|
|
@ -132,6 +132,8 @@ information required to access the internet via that exit address.
|
|
|
|
|
|
|
|
|
|
router contact (RC)
|
|
|
|
|
|
|
|
|
|
router's full identity
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
a: [ one, or, many, AI, here ... ],
|
|
|
|
|
k: "<32 bytes public signing/encryption identity key>",
|
|
|
|
@ -143,6 +145,16 @@ router contact (RC)
|
|
|
|
|
|
|
|
|
|
service info (SI)
|
|
|
|
|
|
|
|
|
|
public information blob for a hidden service
|
|
|
|
|
|
|
|
|
|
n is the claimed fqdn of the service
|
|
|
|
|
s is the long term public signing key
|
|
|
|
|
v is the protocol version
|
|
|
|
|
x is a nounce value for generating vanity addresses that can be omitted
|
|
|
|
|
|
|
|
|
|
if x is included it MUST be less than or equal to 16 bytes, any larger and it is
|
|
|
|
|
considered invalid.
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
n: "<optional claimed name>",
|
|
|
|
|
s: "<32 bytes public signing key>",
|
|
|
|
@ -152,10 +164,20 @@ service info (SI)
|
|
|
|
|
|
|
|
|
|
service address (SA)
|
|
|
|
|
|
|
|
|
|
H(BE(SI))
|
|
|
|
|
the "network address" of a hidden service, which is computed as the blake2b
|
|
|
|
|
256 bit hash of the public infomration blob.
|
|
|
|
|
|
|
|
|
|
HS(BE(SI))
|
|
|
|
|
|
|
|
|
|
introducer (I)
|
|
|
|
|
|
|
|
|
|
a descriptor annoucing a path to a hidden service
|
|
|
|
|
|
|
|
|
|
i is the rc.k value of the router to contact
|
|
|
|
|
p is the path id on the router that is owned by the service
|
|
|
|
|
v is the protocol version
|
|
|
|
|
x is the timestamp seconds since epoch that this introducer expires at
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
i: "<32 bytes public key of router>",
|
|
|
|
|
p: path_id_uint64,
|
|
|
|
@ -165,8 +187,16 @@ introducer (I)
|
|
|
|
|
|
|
|
|
|
introducer set (IS)
|
|
|
|
|
|
|
|
|
|
a signed set of introducers for a hidden service
|
|
|
|
|
a is the service info
|
|
|
|
|
e is the ephemeral public encryption key
|
|
|
|
|
i is the list of introducers that this service is advertising with
|
|
|
|
|
v is the protocol version
|
|
|
|
|
z is the signature of the entire IS where z is set to zero signed by the hidden
|
|
|
|
|
service's signing key.
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
a: "<64 bytes SA>",
|
|
|
|
|
a: SI,
|
|
|
|
|
e: "<1218 bytes ntru public encryption key>",
|
|
|
|
|
i: [ I, I, I, ... ],
|
|
|
|
|
v: 0,
|
|
|
|
@ -570,26 +600,74 @@ DHT messages
|
|
|
|
|
|
|
|
|
|
find introduction message (FIM)
|
|
|
|
|
|
|
|
|
|
recursively find an IS
|
|
|
|
|
recursively find an IS.
|
|
|
|
|
|
|
|
|
|
variant 1, by SA
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
A: "F",
|
|
|
|
|
R: r5n_counter,
|
|
|
|
|
S: "<64 bytes dht key>",
|
|
|
|
|
S: "<32 bytes SA>",
|
|
|
|
|
T: transaction_id_uint64,
|
|
|
|
|
V: 0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if R is non-zero and less or equal to than 5, decrement the value and forward
|
|
|
|
|
request to random peer unconditionally. The transaction will persist until
|
|
|
|
|
replied to by a GIM or 60 seconds, whichever is reached first.
|
|
|
|
|
variant 2, by claimed name
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
A: "F",
|
|
|
|
|
N: "service.name.tld",
|
|
|
|
|
R: r5n_counter,
|
|
|
|
|
T: transaction_id_uin64,
|
|
|
|
|
V: 0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Transactions will persist until replied to by a GIM or 60 seconds, whichever
|
|
|
|
|
is reached first.
|
|
|
|
|
|
|
|
|
|
If the timeout is reached before a GIM or the forwarding of the request fails:
|
|
|
|
|
|
|
|
|
|
* close transaction
|
|
|
|
|
* close linked transactions
|
|
|
|
|
|
|
|
|
|
if R is non-zero and less or equal to than 5:
|
|
|
|
|
|
|
|
|
|
* decrement R by 1
|
|
|
|
|
* open a transaction with id T for sender's RC.k
|
|
|
|
|
* pick random dht capable router, F
|
|
|
|
|
* generate new transaction id, U
|
|
|
|
|
* open a transaction with id U for F.k
|
|
|
|
|
* link transaction U to transaction T
|
|
|
|
|
* send FIM with transaction id U to F
|
|
|
|
|
|
|
|
|
|
if R is greater than 5 or less than 0:
|
|
|
|
|
|
|
|
|
|
if R is greater than 5, immediately reply with a GIM with an X value as an empty
|
|
|
|
|
list, terminating the transaction.
|
|
|
|
|
* increment shitlist value of sender's RC.k by 1
|
|
|
|
|
* if the shitlist value for sender's RC.k is less than 10 reply with a GIM with
|
|
|
|
|
an X
|
|
|
|
|
* if the shitlist value for sender's RC.k is equal to or greater than 10 drop
|
|
|
|
|
the message
|
|
|
|
|
|
|
|
|
|
if R is zero, if we have 1 or more IS at position S in dht keyspace reply with a
|
|
|
|
|
GIM holding the IS who contains the introducer with the highest expiration
|
|
|
|
|
timestamp.
|
|
|
|
|
if R is zero and we have 1 or more IS at position S in dht keyspace:
|
|
|
|
|
|
|
|
|
|
* reply with a GIM holding the IS who contains the introducer with the highest
|
|
|
|
|
expiration timestamp
|
|
|
|
|
|
|
|
|
|
if R is zero and we do not have any IS at position S in dht keyspace:
|
|
|
|
|
|
|
|
|
|
* find a router who's RC.k is closest to S, N
|
|
|
|
|
|
|
|
|
|
if N is our router:
|
|
|
|
|
|
|
|
|
|
* reply with a GIM with an empty X value
|
|
|
|
|
|
|
|
|
|
if N is not our router:
|
|
|
|
|
|
|
|
|
|
* open transaction with id T for sender's RC.k
|
|
|
|
|
* generate new transaction id, U
|
|
|
|
|
* open transaction with id U for N.k
|
|
|
|
|
* link transaction U to transaction T
|
|
|
|
|
* forward request to N using transaction id U
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
got introduction message (GIM)
|
|
|
|
@ -601,6 +679,16 @@ got introduction message (GIM)
|
|
|
|
|
X: [ IS, IS, IS, ... ]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if we have a transaction with id T:
|
|
|
|
|
|
|
|
|
|
* forward the GIM to all linked transactions
|
|
|
|
|
* terminate transaction T
|
|
|
|
|
|
|
|
|
|
when a linked transaction gets a GIM:
|
|
|
|
|
|
|
|
|
|
* set T to the current transaction id
|
|
|
|
|
* foward the GIM to the requester of T
|
|
|
|
|
|
|
|
|
|
publish introduction message (PIM)
|
|
|
|
|
|
|
|
|
|
publish one or many IM into the dht at once.
|
|
|
|
@ -617,22 +705,99 @@ R is currently set to 3 +/- 2 by the sender.
|
|
|
|
|
{
|
|
|
|
|
A: "P",
|
|
|
|
|
R: r5n_counter,
|
|
|
|
|
T: transaction_id_uint64,
|
|
|
|
|
V: 0,
|
|
|
|
|
X: [ IS, IS, IS, ... ]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
acknoleged introduction message (AIM)
|
|
|
|
|
The following steps happen in order:
|
|
|
|
|
|
|
|
|
|
acknolege the publishing of a previous PIM, X contains the backoff values in ms
|
|
|
|
|
for the previously provided IS, if backoff is 0 the operation was successfull
|
|
|
|
|
first stage: reduction
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
A: "A",
|
|
|
|
|
T: transaction_id_uint64,
|
|
|
|
|
V: 0,
|
|
|
|
|
X: [ 0, 0, backoff, ...]
|
|
|
|
|
}
|
|
|
|
|
if X's length is divisble by 2:
|
|
|
|
|
|
|
|
|
|
* split X in half as J and K
|
|
|
|
|
* generate 2 new PIM with the same values as the parent with empty X
|
|
|
|
|
* put J and K into the new PIM's X values
|
|
|
|
|
* associate the 2 new PIM with the current PIM batch
|
|
|
|
|
|
|
|
|
|
if X's length is not divisible by 2 and greater than 1:
|
|
|
|
|
|
|
|
|
|
* pop off an IS from X as A
|
|
|
|
|
* generate a new PIM with the same values as the parent with an X value of A
|
|
|
|
|
* associate the new PIM with the current PIM batch
|
|
|
|
|
* associate the old PIM having A removed from X with the current PIM batch
|
|
|
|
|
|
|
|
|
|
if X's length is 1:
|
|
|
|
|
|
|
|
|
|
* associate the PIM with the current PIM batch
|
|
|
|
|
|
|
|
|
|
any other cases for X are ignored.
|
|
|
|
|
|
|
|
|
|
for each PIM in the current batch:
|
|
|
|
|
|
|
|
|
|
if R is greater than 0:
|
|
|
|
|
|
|
|
|
|
* decrement R by 1
|
|
|
|
|
* queue the PIM for shuffle (second stage)
|
|
|
|
|
|
|
|
|
|
if R is 0:
|
|
|
|
|
|
|
|
|
|
* queue the PIM for distribution (third stage)
|
|
|
|
|
|
|
|
|
|
if R is less than 0:
|
|
|
|
|
|
|
|
|
|
* drop the message entirely
|
|
|
|
|
|
|
|
|
|
second stage: shuffle
|
|
|
|
|
|
|
|
|
|
* The dht node waits until we have collected 10 or more PIM or for 5 seconds,
|
|
|
|
|
which ever comes first.
|
|
|
|
|
* shuffle the list of IS randomly
|
|
|
|
|
* re-combine the IS into new PIMs
|
|
|
|
|
* queue each newly shuffled PIM for distribution (third stage)
|
|
|
|
|
|
|
|
|
|
if we collected 10 or more PIM:
|
|
|
|
|
|
|
|
|
|
* X holds 5 IS at most
|
|
|
|
|
|
|
|
|
|
if we collected less than 10 but more than 1 PIM:
|
|
|
|
|
|
|
|
|
|
* X holds 2 IS at most
|
|
|
|
|
|
|
|
|
|
if we only collected 1 PIM:
|
|
|
|
|
|
|
|
|
|
* the single PIM is unmodified
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
third stage: distribution
|
|
|
|
|
|
|
|
|
|
if R is less than 0:
|
|
|
|
|
|
|
|
|
|
* drop message and terminate current transaction, this should never happen but
|
|
|
|
|
this case is left here in the event of implementation bugs.
|
|
|
|
|
|
|
|
|
|
if R is greater than 0:
|
|
|
|
|
|
|
|
|
|
* pick a random dht capable router, N
|
|
|
|
|
* forward the PIM to N
|
|
|
|
|
|
|
|
|
|
if R is equal to 0:
|
|
|
|
|
|
|
|
|
|
for each IS in X as A:
|
|
|
|
|
|
|
|
|
|
* find the router closest to the SA in A, N
|
|
|
|
|
|
|
|
|
|
if N is our router:
|
|
|
|
|
|
|
|
|
|
* create dht positon S from SA in A
|
|
|
|
|
* store A for lookup at S
|
|
|
|
|
|
|
|
|
|
if N is not our router:
|
|
|
|
|
|
|
|
|
|
* send a PIM with X value containing just A to N
|
|
|
|
|
|
|
|
|
|
In the future post random walk keyspace batching may be done here.
|
|
|
|
|
As of version 0, none is done.
|
|
|
|
|
|
|
|
|
|
find router contact message (FRCM)
|
|
|
|
|
|
|
|
|
@ -645,6 +810,29 @@ find a router by long term RC.k public key
|
|
|
|
|
V: 0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
find RC who's RC.k is closest to K:
|
|
|
|
|
|
|
|
|
|
if A.k is equal to K:
|
|
|
|
|
|
|
|
|
|
* reply with a GRCM with an R value of just A
|
|
|
|
|
|
|
|
|
|
if A.k is not equal to K and we are closesr to A.k than anyone we know:
|
|
|
|
|
|
|
|
|
|
* reply with a GRCM with an empty R value
|
|
|
|
|
|
|
|
|
|
find a pending transaction id for K, P
|
|
|
|
|
|
|
|
|
|
if P exists:
|
|
|
|
|
|
|
|
|
|
* link transaction T to P
|
|
|
|
|
|
|
|
|
|
if P does not exist:
|
|
|
|
|
|
|
|
|
|
* generate a new transaction id, U
|
|
|
|
|
* start transaction U for A.k
|
|
|
|
|
* link transaction U to transaction T
|
|
|
|
|
* send FRCM to A.k requesting K
|
|
|
|
|
|
|
|
|
|
got router contact message (GRCM)
|
|
|
|
|
|
|
|
|
|
R is a list containing a single RC if found or is an empty list if not found
|
|
|
|
@ -656,3 +844,12 @@ sent in reply to FRCM only
|
|
|
|
|
T: transaction_id_uint64,
|
|
|
|
|
V: 0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
* send a GRCM with R to requesters in all linked transactions
|
|
|
|
|
* terminate transaction with id T
|
|
|
|
|
|
|
|
|
|
notes:
|
|
|
|
|
|
|
|
|
|
if we get a GRCM with empty R on one Tx and then one with a filled R on another
|
|
|
|
|
with the same K, the request is terminated by the first message as not found.
|
|
|
|
|
A backtrack case is needed.
|
|
|
|
|