Here [1] is a related trick in the old Unix to run either `foo`, `/bin/foo` or `/usr/bin/foo` (apparently before `PATH` convention existed):
char string[10000];
strp = string;
for (i=0; i<9; i++)
*strp++ = "/usr/bin/"[i];
p = *argv++;
while(*strp++ = *p++);
// string == "/usr/bin/foo"
execv(string+9, args); // foo (execv returns only in case of error, i.e. when foo does not exist)
execv(string+4, args); // /bin/foo
execv(string, args); // /usr/bin/foo
While it's cool, something about vanity keys in general stroke me the wrong way. I feel like in principle you should never use a very short part of a public key for ocular identification, and it attempts to solve something that should be solved outside of wireguard, i.e. the "friendly naming" of public keys.
Be careful with vanity address generators. A cryptocurrency market maker once lost around $160,000,000 in a vanity Ethereum address because the generator they used was only seeded with 32 bits of entropy.
// hashItem computes the slot an item hashes to, given a total number of slots.
func hashItem(item string, nslots uint64) uint64 {
digest := md5.Sum([]byte(item))
digestHigh := binary.BigEndian.Uint64(digest[8:16])
digestLow := binary.BigEndian.Uint64(digest[:8])
return (digestHigh | digestLow) % nslots
}
Should be using XOR: (digestHigh ^ digestLow) % nslots
Prefix check is a fast operation compared to candidate key generation so checking several prefixes adds a small overhead compared to checking just one.
Wildcard support has low value for the use case in my opinion, compare:
In short: I got obsessed by making it as fast as possible and read a ton of elliptic curve cryptography papers.
It was a journey that started from reading WireGuard kernel sources,
then I was thinking about deriving IPv6 address from peer key,
left a random comment on a dated gist https://gist.github.com/artizirk/c91e4f8c237dec07e3ad1b286f1...
from which I learned about vanity key concept.
I've implemented first version of https://github.com/AlexanderYastrebov/wireguard-vanity-key and then continuously profiled it to improve performance.
From profiling I saw that field inversion and multiplication are the main operations.
I realized I need to reduce unnecessary computation to make it faster and for that I need to understand the underlying math which is actually quite simple.
I read RFCs for Curve25519 and papers from D. J. Bernstein who invented it.