From b7c8a0282a29582dd72558816a7893b4e9398fe8 Mon Sep 17 00:00:00 2001 From: mfahriferdiansyah Date: Mon, 2 Dec 2024 20:42:35 +0700 Subject: [PATCH] feat: init --- .gitignore | 2 ++ README.md | 59 ++++++++++++++++++++++++++++++ go.mod | 5 +++ go.sum | 2 ++ main.go | 103 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 171 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 go.mod create mode 100644 go.sum create mode 100644 main.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b58192c --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.txt +*.exe diff --git a/README.md b/README.md new file mode 100644 index 0000000..c11cf55 --- /dev/null +++ b/README.md @@ -0,0 +1,59 @@ +# Solana Wallet Generator + +A high-performance CLI tool to generate Solana wallets with public keys that match a specified prefix. This tool uses Go's concurrency features for fast parallel processing and writes the matched results (public and private keys) to a `result.txt` file. + +## Features +- Generates Solana wallet keypairs (public and private keys). +- Matches public keys against a specified prefix. +- Supports parallel processing with configurable worker threads. +- Saves matched results to a `result.txt` file for later use. + +## Requirements +- [Go (Golang)](https://golang.org/dl/) version 1.19 or later. +- Internet connection to install the necessary dependencies. + +## Installation + +1. Clone the repository: + ``` + git clone https://github.com/your-username/solana-wallet-generator.git + cd solana-wallet-generator + ``` + +2. Install dependencies: + ``` + go mod tidy + ``` + +3. Build the executable: + ``` + go build -o solana-wallet-gen + ``` + +## Usage + +Run the program with the desired options: + +``` +./solana-wallet-gen --prefix [--workers ] [--attempts ] +``` + +### Options +- `--prefix` (required): The prefix the generated public key should start with. +- `--workers` (optional): Number of concurrent workers (default: 4). +- `--attempts` (optional): Maximum number of attempts per worker (default: unlimited). + +### Example +To generate a wallet with a public key starting with `sol`, using 8 workers and up to 1,000,000 attempts per worker: +``` +./solana-wallet-gen --prefix "sol" --workers 8 --attempts 1000000 +``` + +### Output +When a match is found: +1. The public and private keys are printed to the terminal. +2. The matched results are saved in the `result.txt` file in the following format: + ``` + Public Key: solXYZ12345abc... + Private Key: 5TxUHoN123ABCxyz... + ``` diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..7339ecc --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module solana-wallet-gen + +go 1.23.3 + +require github.com/mr-tron/base58 v1.2.0 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..ef4656b --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= +github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= diff --git a/main.go b/main.go new file mode 100644 index 0000000..c3df775 --- /dev/null +++ b/main.go @@ -0,0 +1,103 @@ +package main + +import ( + "crypto/ed25519" + "crypto/rand" + "flag" + "fmt" + "os" + "strings" + "sync" + "time" + + "github.com/mr-tron/base58" +) + +func worker(prefix string, maxAttempts int, result chan<- string, privateKeyChan chan<- string, wg *sync.WaitGroup, id int) { + defer wg.Done() + + for attempts := 0; maxAttempts == 0 || attempts < maxAttempts; attempts++ { + publicKey, privateKey := generateKeypair() + + if strings.HasPrefix(publicKey, prefix) { + result <- publicKey + privateKeyChan <- privateKey + return + } + + if attempts%100000 == 0 && id == 0 { + fmt.Printf("[Worker %d] Attempts: %d\n", id, attempts) + } + } +} + +func generateKeypair() (string, string) { + _, privateKey, err := ed25519.GenerateKey(rand.Reader) + if err != nil { + fmt.Println("Error generating keypair:", err) + os.Exit(1) + } + + publicKey := privateKey.Public().(ed25519.PublicKey) + return base58.Encode(publicKey), base58.Encode(privateKey) +} + +func saveResultToFile(publicKey, privateKey string) { + file, err := os.OpenFile("result.txt", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) + if err != nil { + fmt.Println("Error opening result file:", err) + return + } + defer file.Close() + + _, err = file.WriteString(fmt.Sprintf("Public Key: %s\nPrivate Key: %s\n\n", publicKey, privateKey)) + if err != nil { + fmt.Println("Error writing to result file:", err) + } +} + +func main() { + prefix := flag.String("prefix", "", "The prefix to match (required)") + maxAttempts := flag.Int("attempts", 0, "Maximum number of attempts per worker (0 for unlimited)") + workers := flag.Int("workers", 4, "Number of parallel workers") + flag.Parse() + + if *prefix == "" { + fmt.Println("Error: --prefix is required") + flag.Usage() + os.Exit(1) + } + + fmt.Printf("Searching for wallets starting with: %s\nUsing %d workers...\n", *prefix, *workers) + + result := make(chan string, 1) + privateKeyChan := make(chan string, 1) + + var wg sync.WaitGroup + + start := time.Now() + for i := 0; i < *workers; i++ { + wg.Add(1) + go worker(*prefix, *maxAttempts, result, privateKeyChan, &wg, i) + } + + go func() { + wg.Wait() + close(result) + close(privateKeyChan) + }() + + select { + case publicKey := <-result: + privateKey := <-privateKeyChan + fmt.Printf("Match found!\n") + fmt.Printf("Public Key: %s\n", publicKey) + fmt.Printf("Private Key: %s\n", privateKey) + fmt.Printf("Elapsed Time: %s\n", time.Since(start)) + + saveResultToFile(publicKey, privateKey) + case <-time.After(time.Hour * 24): + fmt.Println("Timeout reached. No match found.") + } +} +