Tor hidden service descriptor fetching


I’m programming a tor implementation, in which I’ve already built-in many things, such as connecting and reading websites via a relay. I’m in the process of implementing hidden service connections, but I don’t understand exactly how it works (used rend-spec-v3). I understood it as follows: I decode the onion address to a public key, checksum and a version then I connect to a directory authority to fetch consensus to get relays with the flag HsDir. In the next steps I have my problems, I use a strange method to turn the public key into a “blinded public key” which I put together from some values and a replica. I then go through all relays with the already mentioned flag twice with replica = 0 and replica = 1. Finally, I use the “blinded public key” with the “/tor/hs/3/” request that I create via a stream (like a normal website request but only that the relay command is “begin dir” - so without an address) with the relay command “data”, but every HsDir responds with “404 - Not found”. That lets me conclude that I could be sending a wrong blinded public key. I would really appreciate if you could help me with that problem.

Thanks in advance.

Yours sincerely,


1 Like

Perhaps you did not find the responsible HSdir correctly. By default, replica is 1 or 2, not 0 or 1.


Thanks for your response.

I’ve changed it but it still couldn’t be found anyways. I guess my calculation of the blinded public might be wrong, but I don’t see the problem in there, I would appreciate if you could help me take a closer look over that. I’ve taken the calculations of rend-spec-v2, I couldn’t find any at rend-spec-v3, they look as following:

(replaced ‘https://’ with ‘https:\’ to bypass link limitations)

/* Pseudo code
[:x] - Ranges: Range from 0 - x
- bytes[:1] → first byte of bytes
- bytes[:4] → bytes from 0 - 4
time() - Current time in milliseconds since the UNIX epoch
sha1(elements…) - SHA-1 hash of any number of elements
base64(x) - Base64-encoded of x
[…] - Documentation / Specification references

replica = value between 1 and 2
currentTime = time() / 1000

publicKey = decoded from onion address

permanentId = sha1(publicKey)[:10]
permanentIdByte = permanentId[:1]

timePeriod = (currentTime + permanentIdByte * 86400 / 256) / 86400

secret = sha1(timePeriod, replica)

descriptorId = sha1(permanentId, secret)

blinded public key = base64(descriptorId)

Yours sincerely,


HI! I don’t think you should have any references to rend-spec-v2.txt here-- that version of onion services is totally obsolete, and not implemented any more. You should only need to look at rend-spec-v3.txt

Something that might help here is the recent implementation for key blinding in rust. They come with test vectors you can copy. I’d suggest that you start by making sure that your low-level key blinding code is right (produces the same results as ours), and then verify it upwards level by level

Hope this helps!

1 Like