vanity25519

package module
v0.0.0-...-ee4ba17 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 12, 2025 License: BSD-3-Clause Imports: 9 Imported by: 3

README

vanity25519 Go Reference

This package implements an efficient curve25519 vanity key generator.

This package provides functions to generate vanity curve25519 key pair with a specific pattern in its public key. It uses an optimized search algorithm that generates candidate public keys by adding offsets to the start public key, avoiding the need to perform full scalar multiplication for each candidate.

The algorithm has amortized cost (3.5M + 3A) per candidate key, where M is field multiplication and A is field addition.

For comparison, brute-force key pair generator requires 2561 field multiplications using double-and-add or 743 field multiplications using Twisted Edwards curve per candidate key.

See example_test.go for usage.

Tools

Documentation

Overview

Package vanity25519 implements an efficient curve25519 vanity key generator.

This package provides functions to generate vanity curve25519 key pair with a specific pattern in its public key. It uses an optimized search algorithm that generates candidate public keys by adding offsets to the start public key, avoiding the need to perform full scalar multiplication for each candidate.

The algorithm has amortized cost (3.5M + 3A) per candidate key, where M is field multiplication and A is field addition.

For comparison, brute-force key pair generator requires 2561 field multiplications using square-and-multiply or 743 field multiplications using Twisted Edwards curve per candidate key.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Add

func Add(startPrivateKey []byte, offset *big.Int) ([]byte, error)

Add returns curve25519 private key obtained by adding offset found by Search function to the start private key.

func HasPrefixBits

func HasPrefixBits(prefix []byte, bits int) func(input []byte) bool

HasPrefixBits returns a function that checks if the input has the specified prefix bits.

func Search(ctx context.Context, startPublicKey []byte, startOffset *big.Int, batchSize int, accept func(candidatePublicKey []byte) bool, yield func(publicKey []byte, offset *big.Int)) uint64

Search generates candidate curve25519 public keys by adding batches of incrementing offsets to the start public key. Once matching candidate is found the corresponding private key can be obtained from its offset using Add function.

Parameters:

  • startPublicKey: the start curve25519 public key to generate candidates from
  • startOffset: the initial offset to start generating candidates from
  • batchSize: number of candidates to generate per batch, must be positive and even
  • accept: function that evaluates each candidate public key (hence it must be fast) and retruns true to accept the key
  • yield: function called for each accepted candidate public key and its offset from the start key

Performance: amortized (3.5M + 3A) per candidate key, where M is field multiplication and A is field addition.

The search continues until context is done and returns number of generated candidates. The function panics if batchSize is not positive and even, or if startPublicKey is not a valid curve25519 public key.

Example (Parallel)
package main

import (
	"context"
	"crypto/ecdh"
	"crypto/rand"
	"encoding/base64"
	"fmt"
	"math/big"
	"os"
	"runtime"
	"sync"
	"sync/atomic"

	"github.com/AlexanderYastrebov/vanity25519"
)

func main() {
	startKey, _ := ecdh.X25519().GenerateKey(rand.Reader)
	startPublicKey := startKey.PublicKey().Bytes()

	prefix, _ := base64.StdEncoding.DecodeString("AY/" + "x") // pad to 4 characters to decode properly
	testPrefix := vanity25519.HasPrefixBits(prefix, 3*6)      // search for 3-character prefix, i.e. 18 bits

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	var attempts atomic.Uint64
	var found atomic.Pointer[big.Int]

	var wg sync.WaitGroup
	for range runtime.NumCPU() {
		wg.Add(1)
		go func() {
			defer wg.Done()

			skip, _ := rand.Int(rand.Reader, new(big.Int).SetUint64(1<<64-1))
			n := vanity25519.Search(ctx, startPublicKey, skip, 4096, testPrefix, func(_ []byte, offset *big.Int) {
				if found.CompareAndSwap(nil, offset) {
					cancel()
				}
			})
			attempts.Add(n)
		}()
	}
	wg.Wait()

	vkb, _ := vanity25519.Add(startKey.Bytes(), found.Load())
	vk, _ := ecdh.X25519().NewPrivateKey(vkb)

	vpk := base64.StdEncoding.EncodeToString(vk.PublicKey().Bytes())

	fmt.Fprintf(os.Stderr, "Found %s after %d attempts\n", vpk, attempts.Load())

	fmt.Printf("Found key: %s...\n", vpk[:3])
}
Output:

Found key: AY/...

Types

This section is empty.

Directories

Path Synopsis
Package field implements fast arithmetic modulo 2^255-19.
Package field implements fast arithmetic modulo 2^255-19.
internal

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL