Tor Onion v3 Vanity Address


Saturday 6th January 2018

For 21 days, my Raspberry Pi cluster has been running mkp224o in order to generate a vanity address for my new Tor Onion v3 Hidden Service.

It isn't as good as last time, but I have chosen: jamie3vkiwibfiwucd6vxijskbhpjdyajmzeor4mc4i7yopvpo4p7cyd.onion

So I guess that's... 3 volt Kiwi?

Please note that this Onion v3 Hidden Service will not be available until Onion v3 reaches the stable Tor branch. For now, you can use my test Onion v3 service at 32zzibxmqi2ybxpqyggwwuwz7a3lbvtzoloti7cxoevyvijexvgsfeid.onion, which requires tor-0.3.2.1-alpha (eg: Tor Browser 7.5a5) or newer to access.

Edit 17th Jan 2018 @ 11:00pm: Onion v3 functionaility is now in the stable release of Tor, so my new hidden service is live! The Onion v3 hidden service used for testing is now offline.

Skip to Section:

Tor Onion v3 Vanity Address
┣━━ mkp224o
┣━━ Performance
┣━━ Address Generation Times
┣━━ Filtering Generated Addresses
┣━━ Implementation
┣━━ Other Onion v3 Vanity Address Generation Programs
┣━━ Conclusion
┗━━ References

mkp224o

mkp224o is a vanity address generator for Tor Onion v3 Hidden Services, created by cathugger and available on Github.

The mkp224o repository on cathugger's GitHub account.

Tor Proposal 224 is the proposal for the new Onion v3 specification, so that's what mkp224o was named after.

mkp224o is very easy to install and run. Download and extract the latest version from GitHub, then on Debian-based systems, you can use:

#Install dependencies if required
sudo apt-get install autoconf libsodium-dev

#Build
./autogen
./configure
make

You can run "./mkp224o -h" to view the available options:

js@node0:~/onionv3/mkp224o$ ./mkp224o
Usage: ./mkp224o filter [filter...] [options]
       ./mkp224o -f filterfile [options]
Options:
	-h  - print help
	-f  - instead of specifying filter(s) via commandline, specify filter file which contains filters separated by newlines
	-q  - do not print diagnostic output to stderr
	-x  - do not print onion names
	-o filename  - output onion names to specified file
	-F  - include directory names in onion names output
	-d dirname  - output directory
	-t numthreads  - specify number of threads (default - auto)
	-j numthreads  - same as -t
	-n numkeys  - specify number of keys (default - 0 - unlimited)
	-N numwords  - specify number of words per key (default - 1)
	-z  - use faster key generation method. this is now default
	-Z  - use slower key generation method
	-s  - print statistics each 10 seconds
	-S t  - print statistics every specified amount of seconds
	-T  - do not reset statistics counters when printing

You can then run mkp224o to search for an address. The "-S" argument will make mkp224o output statistics every 5 seconds, and the "-d" argument allows you to specify a directory to store the generated keys.

js@node0:~/onionv3/mkp224o$ ./mkp224o -S 5 -d onions jamie
set workdir: onions/
sorting filters... done.
filters:
	jamie
in total, 1 filter
using 4 threads
>calc/sec:17035.009192, succ/sec:0.000000, rest/sec:39.964831, elapsed:0.100088sec
>calc/sec:22250.236672, succ/sec:0.000000, rest/sec:0.000000, elapsed:5.103855sec
>calc/sec:22272.487630, succ/sec:0.000000, rest/sec:0.000000, elapsed:10.107517sec
>calc/sec:22256.077578, succ/sec:0.000000, rest/sec:0.000000, elapsed:15.111813sec
>calc/sec:22278.089855, succ/sec:0.000000, rest/sec:0.000000, elapsed:20.116102sec
>calc/sec:22253.435622, succ/sec:0.000000, rest/sec:0.000000, elapsed:25.120363sec
>calc/sec:21762.771552, succ/sec:0.000000, rest/sec:0.000000, elapsed:30.142012sec
>calc/sec:22258.870726, succ/sec:0.000000, rest/sec:0.000000, elapsed:35.146309sec
>calc/sec:22282.575137, succ/sec:0.000000, rest/sec:0.000000, elapsed:40.150578sec
>calc/sec:22258.577166, succ/sec:0.000000, rest/sec:0.000000, elapsed:45.154941sec
>calc/sec:22198.079226, succ/sec:0.000000, rest/sec:0.000000, elapsed:50.159383sec
>calc/sec:22253.661568, succ/sec:0.000000, rest/sec:0.000000, elapsed:55.163728sec
>calc/sec:22276.712822, succ/sec:0.000000, rest/sec:0.000000, elapsed:60.168057sec
>calc/sec:22254.261335, succ/sec:0.000000, rest/sec:0.000000, elapsed:65.172357sec
>calc/sec:22277.632325, succ/sec:0.000000, rest/sec:0.000000, elapsed:70.176659sec
>calc/sec:22256.428313, succ/sec:0.000000, rest/sec:0.000000, elapsed:75.180966sec
^Cwaiting for threads to finish... done.

In the example above, I exited mkp224o after 75 seconds using Ctrl+C.

Matching addresses are automatically saved into either the directory where mkp224o is running or the one specified using the "-d" switch.

js@node0:~/onionv3/mkp224o$ ls onions/ | head -n 5
jamie22ezawwi5r3o7lrgsno43jj7vq5en74czuw6wfmjzkhjjryxnid.onion
jamie22jd4c7g7osiio7jnqnsqj4w7dpqmit32easwp2igjge67nktid.onion
jamie233pm4t6zkbkdyiu7yknnqccirtkcwne2h5nc73mykvckg76sqd.onion
jamie23kp7n6xgk3lvy6wnse4cuk4dawfpwl52img7za35tiyex2mvyd.onion
jamie24hjpe7ia2usa6odvoi3s77j4uegeytk7c3syfyve2t33curbyd.onion

js@node0:~/onionv3/mkp224o$ ls jamie22ezawwi5r3o7lrgsno43jj7vq5en74czuw6wfmjzkhjjryxnid.onion/
hostname  hs_ed25519_public_key  hs_ed25519_secret_key

You could also set up a cronjob to run mkp224o at boot in a detached screen session:

@reboot cd /path/to/mkp224o && screen -dmS onionv3 ./mkp224o -S 600 -d onions jamie

You can then check up on mkp224o using "screen -r onionv3". Use Ctrl+A followed by Ctrl+D to detach from a screen session without terminating it.

Performance

Running on a Raspberry Pi 2B, mkp224o achieved a pretty consistent 22,200 calculations per second, with 1 filter running on 4 threads.

The 4 Raspberry Pi Zeros all achieved around 4,180 calculations per second, with 1 filter running on 1 thread.

mkp224o ran 24 hours a day for 21 days. The total number of addresses generated by each device is shown below:

Master (RPi 2B)   : 1014
Node 1 (RPi Zero) : 222
Node 2 (RPi Zero) : 192
Node 3 (RPi Zero) : 212
Node 4 (RPi Zero) : 235

This makes for a total of 1,875 addresses, which is roughly 1 matching address found every 16 minutes and 8 seconds, or 967.68 seconds.

Address Generation Times

In order to get a very rough estimate for the address generation time for each vanity length, I used the total generation time for the 1,875 addresses that I generated over 21 days, and extrapolated that using the total number of possible characters (32, a-z, 2-7) in order to get values for other vanity address lengths.

These values are estimated using combined data from mkp224o running on 1 Raspberry Pi 2B and 4 Raspberry Pi Zeros, simultaneously and 24/7 for 21 days.

Vanity Characters : Approximate Generation Time
1  : <1 second
2  : <1 second
3  : 1 second
4  : 30 seconds
5  : 16 minutes
6  : 8.5 hours
7  : 11.5 days
8  : 1 year
9  : 32 years
10 : 1,024 years
11 : 32,768 years
12 : 1 million years
13 : 32 million years
14 : 1 billion years
15 : 32 billion years
16 : 1 trillion years
17 : 32 trillion years
18 : 1 quadrillion years
19 : 32 quadrillion years
20 : 1 quintillion years
21 : 32 quintillion years
22 : 1 sextillion years
23 : 32 sextillion years
24 : 1 septillion years
25 : 32 septillion years
26 : 1 octillion years
27 : 32 octillion years
28 : 1 nonillion years
29 : 32 nonillion years
30 : 1 decillion years
31 : 32 decillion years
32 : 1 undecillion years
33 : 32 undecillion years
34 : 1 duodecillion years
35 : 32 duodecillion years
36 : 1 tredecillion years
37 : 32 tredecillion years
38 : 1 quattuordecillion years
39 : 32 quattuordecillion years
40 : 1 quindecillion years
41 : 32 quindecillion years
42 : 1 sexdecillion years
43 : 32 sexdecillion years
44 : 1 septendecillion years
45 : 32 septendecillion years
46 : 1 octodecillion years
47 : 32 octodecillion years
48 : 1 novemdecillion years
49 : 32 novemdecillion years
50 : 1 vigintillion years
51 : 32 vigintillion years
52 : 10^66 years
53 : 10^69 years
54 : 10^72 years
55 : 10^75 years
56 : 10^78 years (1,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000)

A copy of this is available on my Pastebin if you wish to view it without scrolling: https://pastebin.com/hdB8QU6z

I think that 11 vanity characters is realistically achievable given enough computing power, for example when/if Facebook upgrade their hidden service to Onion v3. The Raspberry Pi cluster that I used is a very low performance device when compared to a dedicated GPU crypto rig.

Filtering Generated Addresses

After I had been running mkp224o for 21 days, I needed to use the cluster for something else so it was time to choose an address. Glancing through the results, there wasn't anything that stood out, so I searched through it with grep for various keywords and acronyms (eg: sec, pgp, php, etc), however there wasn't anything particularly good.

I wanted to search for English words in the output, so I used the /usr/share/dict/british-english file that is included with the package "wbritish" on Debian-based systems.

At first I tried the following, but it turned out to be extremely inefficient and could cause a system crash, so I do not recommend trying this yourself!

#Install wbritish if required
sudo apt-get install wbritish

#Make a copy of the british-english dictionary for searching
cp /usr/share/dict/british-english wordlist.txt

#Remove one character words
grep -v "^[A-Za-z]$" wordlist.txt > wordlist2.txt

#Remove two character words
grep -v "^[A-Za-z][A-Za-z]$" wordlist2.txt > wordlist.txt

#Remove "onion", "Onion", "Jamie", "ion", "Jami", "jam" & "Amie"
egrep -v "(^onion$|^Onion$|^ion$|^Jamie$|^Amie$|^Jami$|^jam$)" wordlist.txt > wordlist2.txt

#Find words from wordlist2.txt in onion-v3-export.txt
This could crash your system, be careful!
grep -iFf wordlist2.txt onion-v3-export.txt

The reason that this technique is so inefficient is that it uses just one instance of grep for the entire search, and grep isn't designed to handle that. I had this running for around 5 minutes and it slowly built up 16 GB RAM usage and started eating into my swap partition, which isn't good! Grep isn't designed for handling this sort of processing, so it's unfair to discount it for this memory-handling behaviour.

The technique that worked well was using a separate instance of grep for each word to search for, instead of trying to search for them all at once. This was a slower searching method, however it uses minimal memory.

I also decided to cut the addresses to search down to just the first 12 characters, as words that aren't at the start of the address aren't of much value in most cases.

cut -c 1-12 onion-v3-export.txt > onion-cut.txt

Then use a simple bash for loop in order to check each of the dictionary words against the address list individually:

for word in `cat wordlist2.txt`; do grep --colour=always -i "$word" onion-cut.txt; done

I set this running on a Raspberry Pi 2B and it took around 5 hours to search 1875 addresses for around 90,000 dictionary words.

The output can be seen below:

jamieiabe7a4
jamie6r6zala
jamiearkjlxm
jamiecq7kaug
jamiefzubmwi
jamieshbikol
jamieyvh7chi
jamielwsclem
jamied4coltx
jamied4coltx
jamieigdelcr
jamie35cjdoe
jamieolrdowa
jamieastrwc5
jamiecojx25o
jamieli4bdva
jamieli5eiua
jamieliozi7k
jamiemmelinl
jamiengdpoqe
jamiengzlpbx
jamiem7erinn
jamie6wesqby
jamiedesqkt7
jamiesf7besq
jamiehuetnao
jamieva5stck
jamievaa3tz7
jamievai4mxi
jamievavnyxz
jamievawy4s3
jamieve3ay5l
jamievegkrdr
jamievendyi3
jamieveut4pl
jamieus7fdry
jamieklfoxy6
jamieoygeov7
jamiess73geo
jamieh3qgodd
jamieigodyok
jamieogodx2p
jamiegusqcma
jamieygusgz2
jamierguy22t
jamieylguysw
jamiehaysabt
jamieochay7v
jamiehaysabt
jamie4mianru
jamiezayfian
jamiezce5ida
jamie52vinae
jamieiincyvq
jamieaiveslc
jamieza5jayl
jamie5joec2a
jamiejon7tqe
jamiepjondzx
jamiejovebbc
jamie4kentlb
jamie4kentlb
jamiekongx4v
jamie3leegvc
jamieruezlen
jamieg7xrleo
jamiemiaaleo
jamiejjj5les
jamiewles7cq
jamieflewzbs
jamiemmelinl
jamieltdwsfu
jamieqpltdvr
jamieqwmciwy
jamierfnmhzf
jamie7kmarhc
jamienmaycho
jamiemmelinl
jamiez72melu
jamie4mianru
jamiemiaaleo
jamienoem2kg
jamiemynohox
jamiealoctkj
jamiei6rkono
jamieoslok3j
jamiecqommgv
jamiex5iqomc
jamiefrcayod
jamieircaxtn
jamiesraybwe
jamiesamxrep
jamiepysaptu
jamiesamxrep
jamie4dssgtt
jamieoossols
jamiellhsuex
jamie3osunkf
jamiefwsuzyt
jamiekftwax2
jamietwau3l2
jamiecgtadb2
jamieoftaogv
jamiented7pn
jamieiup3tex
jamietexsrhi
jamieenbmvic
jamiee45wisj
jamie5zenznc
jamie7zoeb5u
jamie63uado4
jamiekadz6r3
jamie7yailju
jamieel2iail
jamieb3c6aim
jamiekaime7x
jamierair7zf
jamiefoalemu
jamiekoale5v
jamiemiaaleo
jamieou5wale
jamievwuiall
jamiepysaptu
jamiearkjlxm
jamiekawlt2h
jamiepbagzbw
jamieqkr3ban
jamie3fbetfj
jamieybogdzn
jamie3dmbooj
jamiet4bugok
jamiebunquil
jamieqfburu7
jamie2yvbut2
jamiegcap4bx
jamiecarxx2z
jamieyvh7chi
jamieclapvft
jamiepcodwwz
jamied4coltx
jamie3icoo5o
jamieqcrudor
jamieztmdabf
jamie4debrkh
jamiedewp2l4
jamiedigjmx5
jamie2fidip4
jamies4fdipl
jamie35cjdoe
jamiexiidogt
jamieus7fdry
jamief3adubg
jamielhidubk
jamiehxduet6
jamiehxduet6
jamiearkjlxm
jamiearxrrxz
jamieastrwc5
jamieatksy64
jamiebbazgwr
jamiebbe4onn
jamiebbk4civ
jamiebblfkwp
jamiebboqkaq
jamiejovebbc
jamieel2iail
jamieelc6o6e
jamieelvm27e
jamiegg4cmuc
jamieggmw7r4
jamieggqukg4
jamieggr35m5
jamieggx5omp
jamieke6czqs
jamielfccgrt
jamielfh3f6h
jamielfzwd2l
jamie4zelkks
jamielk2btz3
jamielklik6v
jamiell45bdv
jamiellhsuex
jamieems2vzv
jamiems3bz5b
jamiemsavbsj
jamiemslb7wv
jamiemsty6yk
jamiefoalemu
jamiemub2jhx
jamiemukqyol
jamienddpbfp
jamiepend5mx
jamievendyi3
jamieeonwydp
jamiera2wgtx
jamiera4jhrl
jamierac2xhr
jamierair7zf
jamiere4xdh5
jamiereiwyin
jamieremhidk
jamiereza4ph
jamierezh3pg
jamierguy22t
jamierr2jah7
jamievferrat
jamietap7o7p
jamieve3ay5l
jamievegkrdr
jamievendyi3
jamieveut4pl
jamievendyi3
jamiewe5ihs6
jamiexamjhrr
jamieyeik2sq
jamieyek5q45
jamiewhafaxb
jamievferrat
jamiefig7jeu
jamieflewzbs
jamiebqfflud
jamiefoalemu
jamiewmcfob4
jamiefoe7puf
jamiefogksuv
jamienpfopab
jamieklfoxy6
jamieklfoxy6
jamiezsfuntu
jamiecxgel4m
jamiegq3sgem
jamieufiugob
jamieh3qgodd
jamieigodyok
jamieogodx2p
jamiedgraphf
jamieegunxiy
jamierguy22t
jamieylguysw
jamieylguysw
jamie4hat4o7
jamieprwhawx
jamiehaysabt
jamieochay7v
jamiehaysabt
jamiefhazyvn
jamielhidubk
jamieremhidk
jamienrjdhip
jamiensqihot
jamiepjdhotn
jamiehuetnao
jamieal2hugy
jamieifsuoia
jamiem7erinn
jamieijxjawp
jamieza5jayl
jamiemkhz2zm
jamie4kentlb
jamie5ikidcw
jamieigwkin4
jamie3vkiwib
jamieclapvft
jamienlazyb4
jamieleduvsh
jamie3leegvc
jamieeaqlibc
jamieasl3lit
jamiejlivevk
jamie5ibllow
jamieqcwlowg
jamiehmadnlg
jamie7kmarhc
jamiepdmasxf
jamie44mawsj
jamie44mawsj
jamienmaycho
jamien3qp5cw
jamien42romd
jamien4khbab
jamien56czjy
jamien6iiq47
jamien6vzoon
jamien766udo
jamien7evqfh
jamien7hxhqq
jamien7rrxmx
jamiena25tw3
jamiena2m4ad
jamienb5srqt
jamiencevt24
jamienddpbfp
jamieneoqsde
jamienfcnozu
jamienfrzm5t
jamienfulha7
jamiengdpoqe
jamiengzlpbx
jamieni4wpem
jamienigx3xw
jamieniox2od
jamienje2ohv
jamienjsyflg
jamienkdtpy7
jamienkvdjty
jamienlazyb4
jamienlwvpxl
jamienm27ex6
jamienmafk4n
jamienmaycho
jamienntzth2
jamienoem2kg
jamienoyixsl
jamienp7rstj
jamienpfopab
jamienptccfs
jamienrhpwj3
jamienrjdhip
jamiensf3icf
jamiensfldni
jamiensndk5t
jamiensogx5u
jamiensqihot
jamiented7pn
jamienup4blr
jamienwulrkn
jamienwwuixd
jamienx6zpgq
jamienxcz23c
jamienxdmjtp
jamienyjmqc6
jamienyrheg6
jamienz2zsnp
jamienz6du67
jamienzbapkd
jamienzhu36p
jamienzv45tc
jamiensf3icf
jamiensfldni
jamiensndk5t
jamiensogx5u
jamiensqihot
jamiegdtmixa
jamieymommno
jamie7nixgpq
jamiee4notf2
jamieod2nubq
jamie6zuodd5
jamieh3qgodd
jamieoftaogv
jamiemynohox
jamielrpnopt
jamiesoptrhw
jamiegpadbjk
jamiekwbpadx
jamie7pawj52
jamiebtpawpi
jamieb6paygd
jamiepend5mx
jamieypepj3i
jamie2mvpitg
jamieplyw6bm
jamiepodl6ka
jamiepbzupol
jamie6vdpotq
jamieprytdwt
jamiedgraphf
jamiewp2jrap
jamievferrat
jamiesraybwe
jamiesamxrep
jamiejribrux
jamieugwlroe
jamiezu4mrow
jamiej4truew
jamieruezlen
jamiepysaptu
jamiesaysnbd
jamiesaysnbd
jamiewqs7sex
jamie2zzysly
jamieeslyftw
jamieoossols
jamieoossols
jamiesoptrhw
jamiebcspyd2
jamiemsty6yk
jamiellhsuex
jamiesumk3iw
jamie3osunkf
jamie3osunkf
jamiecgtadb2
jamietap7o7p
jamiey4lvtea
jamieqryitie
jamiewtitd5q
jamietop4unx
jamiej4truew
jamie5xtryfc
jamieagtubqw
jamieitunyoy
jamievendyi3
jamie6jjvia2
jamieou5wale
jamiegwas2k5
jamiekftwax2
jamiel6nwen3
jamiewigoswr
jamieoqpwowi
jamieyapnyqg
jamieod6yawh
jamien6vzoon

On a side note, in order to generate HTML output of the ANSI-encoded terminal emulator colours, you can use the "aha" command:

for word in `cat wordlist4.txt`; do grep --colour=always -i "$word" onion-cut.txt; done | aha

...which will convert the input into HTML with inline colour styling and the following header:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<!-- This file was created with the aha Ansi HTML Adapter. https://github.com/theZiz/aha -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="application/xml+xhtml; charset=UTF-8" />
<title>stdin</title>
</head>
<body>
...

I then edited out the inline styling and used my CSS file instead in order to be compliant with my Content-Security-Policy.

A significantly better way of filtering the vanity addresses would have been putting them all into a database and querying it, as database software is highly optimised for handling this sort of computation.

I was really hoping to get a ^jamieweb address to go along with my Onion v2 service jamiewebgbelqfno.onion, however with Onion v3 and mkp224o, my estimates show that would take around a year. With Onion v2 and Shallot, that would (and did) take around 25 days.

Honourable Mentions:

jamie4debrkhllykiyiztbpg6fokecmzhxvj4buig5qss5m4wasn5yyd.onion - Debian?
jamiedgraphfwrf2mfhc4iprjjpgzapiqikjxz4yseodq2bvnqcicoad.onion - Fast Graph Database?
jamiedigjmx56qpxfwht6pniy2jibt6lpled4juja3wmyuk7bfeaczad.onion - DNS Lookup Utility?
jamieoslok3jxyg223xdm2fftsdd33cio2p5hozkipj27wcygomy4yid.onion - Capital of Norway?
jamietap7o7pux6fxpnxrbqvto6dypr3tx3befc7bpon6gn5m4tsftqd.onion - Network Tap?

The full list of generated addresses is available on my Pastebin: https://pastebin.com/eiFYaCHG

Implementation

As of writing this, Onion v3 support is only available alpha versions of Tor, however a Tor build with Onion v3 functionality is currently at the second release candidate, so it should be reaching the stable branch very soon.

For as long as Tor Onion v3 functionality remains in alpha only, I will be keeping the current hidden service address (http://32zzibxmqi2ybxpqyggwwuwz7a3lbvtzoloti7cxoevyvijexvgsfeid.onion) as well as running the Tor alpha instance on a separate, isolated server.

When Onion v3 hits Tor stable, I will move it across to a main server as well as start using the jamie3vkiwi vanity address. I will also continue hosting my Onion v2 hidden service for as long as it is safe to do so.

Luckily it is very easy to host multiple hidden services using the same Tor instance. In your torrc, just add multiple hidden service configurations:

HiddenServiceDir /desired/path/to/v3/hidden/service/config
HiddenServiceVersion 3
HiddenServicePort <localport> <server>

HiddenServiceDir /desired/path/to/v2/hidden/service/config
HiddenServiceVersion 2
HiddenServicePort <localport> <server>

Other Onion v3 Vanity Address Generation Programs

In addition to mkp224o by cathugger (which is what I used), there are also other Onion v3 vanity address generation programs out there:

I personally tried out oniongen-go and oniongen-c in addition to mkp224o.

If I have missed any, please let me know.

Conclusion

To conclude, I think that mkp224o is fantastic software that worked stably for prolonged amounts of time on low-end hardware. If you want to generate a vanity address for your own Onion v3 service, definitely check out mkp224o.

I am definitely not as happy with my Onion v3 vanity address as I am with my Onion v2 vanity address, however due to the enormously increased cryptographic security of Onion v3, vanity address generation takes slightly longer. This is not a problem for me though, since security is always more important that vanity, especially with software like Tor.

References