The previous tracking code model was a major headache. The codes were visible to all members of a circuit, they (potentially) leaked information about the topology of the network, and required that members of the circuit perform multiple decryption attempts for each packet they received. Luckily, there’s a nice alternative which has been staring us in the face the whole time. The tracker can wrap each part of the tracking code in layer after layer of public key encryption. In other words, after generating the tracking code “0:3:2″ the Tracker uses an encryption function E_peer(c), where c is the concatenation of the next tracking code digit and the encryption function corresponding to the next peer. If the tracking code “0:3:2″ is to pass a message m from peer “a” to peer “d” through the circuit “a -0-> b -3-> c -2-> d” then the expanded encryption function is:
E_a(0 . E_b(3 . E_c(2 . E_d(m))))
Each peer removes a layer of encryption and passes the message along. This is essentially the way in which Onion Routing networks, such as Tor, protect their routing information.









You’re still leaking information about the path length since the path string monotonically decreases in length. If you naïvely concatenate a pad, a participant can still infer the remaining length of the path.
Instead, I suggest that each participant attach a pseudo-random pad to the message before retransmission. When any recipient other than the last decrypts the message, the pad text will be indistinguishable from ciphertext intended for a subsequent recipient. The terminal recipient will be able to distinguish the original message from the pad text by means of some delimiter string.
Thanks for the suggestion bh, although I didn’t detail it in the post, we are using a padding scheme very similar to what you described. The encryption function E_peer generates an AES session key and uses that to bulk encrypt the rest of the tracking code. Each layer therefore looks something like this:
{Session Key}[checksum, length, data, padding]
|————————-160 bytes——————————-|
where {} means that the data is encrypted with the peers RSA public key and [] means that it’s encrypted with the AES session key. The [] section is padded so that its length modulo 32 is 0. The completed tracking code is padded out to a predefined size (most likely 1024 bytes), so that, after reading their part of the message, each peer can repad the message with random data to that length.