Skip to content

This tool searches for a WireGuard Curve25519 keypair with a base64-encoded public key that has a specified prefix

License

Notifications You must be signed in to change notification settings

AlexanderYastrebov/wireguard-vanity-key

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

65 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

wireguard-vanity-key

This tool searches for a WireGuard Curve25519 keypair with a base64-encoded public key that has a specified prefix.

Compared to similar tools, it uses the fastest search algorithm ๐Ÿš€

Example

Install the tool locally and run:

$ go install github.com/AlexanderYastrebov/wireguard-vanity-key@latest
$ wireguard-vanity-key -prefix=2025
private                                      public                                       attempts   duration   attempts/s
WHakaGFouuy2AxMmOdSTf2L2KWsI6a3s+gvAOKuKtH0= 2025sb38RUVI+GJg5Uk2RRPuJfhZyg4uSxfV2WDn1g8= 47423039   2s         19926032

$ # verify
$ echo WHakaGFouuy2AxMmOdSTf2L2KWsI6a3s+gvAOKuKtH0= | wg pubkey
2025sb38RUVI+GJg5Uk2RRPuJfhZyg4uSxfV2WDn1g8=

or run the tool from the source repository:

$ go run . -prefix=2025

or use the Docker image:

$ docker pull ghcr.io/alexanderyastrebov/wireguard-vanity-key:latest
$ docker run  ghcr.io/alexanderyastrebov/wireguard-vanity-key:latest -prefix=2025

Performance

The tool checks ~29'000'000 keys per second on a test machine:

$ go run . -prefix=GoodLuckWithThisPrefix -timeout=20s
private                                      public                                       attempts   duration   attempts/s
-                                            GoodLuckWithThisPrefix...                    583920640  20s        29194831

In practice, it finds a 4-character prefix in a second and a 5-character prefix in a minute:

$ while go run . -prefix=AYAYA ; do : ; done
private                                      public                                       attempts   duration   attempts/s
OM9WvIxO90NRnHpMLBYbKCwRxj1KcwWVfo5EO1vftls= AYAYAgcnXbdsMwLB+nR0kkWDpIkMr+3thhfGnBEvTmM= 515859548  23s        22328225
private                                      public                                       attempts   duration   attempts/s
eEbiqUhcUrH6Uj1p7cycgTOspY6fMxxImSNNr1YvaEg= AYAYA4yow92Ks1wnbQeceKEWIYHhaRyezomUz9SQJic= 350598404  19s        18060407
private                                      public                                       attempts   duration   attempts/s
OOkjEu4elrWJ4MD+OxB2kvUcKdyo482E3G3Y/tLBsmI= AYAYAW4yGEUVT/IkX3T6ZZTnz3yPS1lPxiRe0yhOCCs= 260273230  14s        17972036
private                                      public                                       attempts   duration   attempts/s
+BWkcGvbkXFxNgxIrAYyJoMF1R6R3eguv5NyMsdlaEA= AYAYAQEsY0gagwZ5lGLRQYfxQ+5rl83LOPmaASvASFQ= 1094012149 56s        19446702
private                                      public                                       attempts   duration   attempts/s
aG7Rakjbn1kpc2HN7fUz1u/ZrTcYziXg7OJq2EcMWFU= AYAYAe9QZdXn36CrkOK8aoD8h92mbEHCQt1QdTBARjY= 1088287697 56s        19483959

Each additional character increases search time by a factor of 64.

Blind search

The tool supports blind search, i.e., when the worker does not know the private key. See demo-blind.sh.

Kubernetes

You can run the tool in a distributed manner in Kubernetes cluster using the demo-k8s.yaml manifest to search for a vanity key without exposing the private key:

$ # Generate secure starting key pair
$ wg genkey | tee /dev/stderr | wg pubkey
YI5+UcKmyLdeRDqU8l3k53wrUZO9Mw23NpvB8tDtvWU=
startkQgqI9Gv1IX7eNa2qeFhpYBRDwpz40JIAAYOSk=

$ # Edit demo-k8s.yaml to configure prefix, starting public key, parallelism, and resource limits ๐Ÿ’ธ

$ # Create search job
$ kubectl apply -f demo-k8s.yaml
job.batch/wvk created

$ # Check job
$ kubectl get job wvk
NAME   STATUS    COMPLETIONS   DURATION   AGE
wvk    Running   0/10          2m53s      2m53s

$ # Check pods
$ kubectl get pods --selector=batch.kubernetes.io/job-name=wvk
NAME         READY   STATUS    RESTARTS   AGE
wvk-0-8tdz5  1/1     Running   0          3m8s
wvk-1-pmnkn  1/1     Running   0          3m8s
wvk-2-2ls7m  1/1     Running   0          3m8s
wvk-3-rd7gx  1/1     Running   0          3m8s
wvk-4-jqksz  1/1     Running   0          3m8s
wvk-5-vj6gd  1/1     Running   0          3m8s
wvk-6-vhgmc  1/1     Running   0          3m8s
wvk-7-drr98  1/1     Running   0          3m8s
wvk-8-tmb6c  1/1     Running   0          3m8s
wvk-9-gxlp2  1/1     Running   0          3m8s

$ # Check resource usage
$ kubectl top pods --selector=batch.kubernetes.io/job-name=wvk

$ # Wait for the job to complete
$ kubectl wait --for=condition=complete job/wvk --timeout=1h
job.batch/wvk condition met

$ # Job is complete
$ kubectl get job wvk
NAME   STATUS     COMPLETIONS   DURATION   AGE
wvk    Complete   1/999999      34m        37m

$ # Get found offset from the logs
$ kubectl logs jobs/wvk
7538451707115552752

$ # Generate new private vanity key by offsetting the starting private key
$ echo YI5+UcKmyLdeRDqU8l3k53wrUZO9Mw23NpvB8tDtvWU= | wireguard-vanity-key add --offset=7538451707115552752 --prefix=wvk+k8s
4I4EWan32HJbRDqU8l3k53wrUZO9Mw23NpvB8tDtvWU=

$ # Get the vanity public key
$ echo 4I4EWan32HJbRDqU8l3k53wrUZO9Mw23NpvB8tDtvWU= | wg pubkey
wvk+k8shgsJcW5EKet2AkViKc7a/0Ud8/EDOy91aCQg=

$ # Delete the job
$ kubectl delete job wvk
job.batch "wvk" deleted

Similar tools

The fastest search algorithm

A WireGuard key pair consists of a 256-bit random private key and a public key derived by scalar multiplication on Curve25519 involving arithmetic operations (additions, multiplications) in a finite field.

The performance of any brute-force key search algorithm ultimately depends on the number of finite field multiplications per candidate key - the most expensive field operation.

All available WireGuard vanity key search tools use the straightforward approach: multiply the base point by a random candidate private key and check the resulting public key:

public_key = private_key ร— base_point

For the WireGuard key format, this basic algorithm requires 2561 field multiplications (using square-and-multiply) or 743 field multiplications (using Twisted Edwards curve) per candidate key.

This tool uses only 5 (five) field multiplications per candidate key and other optimizations, which makes it the fastest ๐Ÿš€

โž• Point increment approach

Inspired by wireguard-vanity-address "faster algorithm", instead of doing full scalar multiplication for each candidate, this tool applies a point increment technique that reduces the number of multiplications:

public_key0 = private_key0 ร— base_point
public_key1 = (private_key0 + const_offset) ร— base_point
            = private_key0 ร— base_point + const_offset ร— base_point
            = public_key0 + const_offset ร— base_point
            = public_key0 + const_point_offset

i.e., the candidate public key is obtained by point addition instead of base point multiplication, which requires fewer field multiplications (275 vs. 743 or ~60% faster). See initial commit.

๐Ÿงฎ Batch field inversion

Getting the public key in WireGuard format (Montgomery form) requires a field inversion, which uses 265 field multiplications. This tool uses the Montgomery trick to implement batch inversion, so for a batch of N candidates, only 1 (one) inversion is needed, resulting in a huge speedup. See #3.

๐Ÿชž Affine coordinates and offset symmetry

The algorithm uses affine coordinates and exploits symmetries in precomputed point offsets, saving even more field multiplications. See #10, #12, and #14.

โšก Fast base64 prefix check

Other tools encode the full public key to base64 and compare the prefix. This tool decodes the base64 prefix and compares it to public key bytes directly. See #5.

๐Ÿ† High-performance C implementation

For raw speed, the C worker (wvk) uses awslabs/s2n-bignum - a highly optimized field arithmetic library written in assembly. The worker supports prefix lengths up to 10 base64 characters, so the prefix check becomes a single masked integer comparison. These two optimizations make wvk ~2 times faster than the Go implementation. See #15.

About

This tool searches for a WireGuard Curve25519 keypair with a base64-encoded public key that has a specified prefix

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors 3

  •  
  •  
  •