Skip to content

Commit

Permalink
pass regex by argv, use new PrivKey format
Browse files Browse the repository at this point in the history
  • Loading branch information
milahu committed Aug 31, 2021
1 parent d166e9a commit ed7ddc4
Showing 1 changed file with 92 additions and 27 deletions.
119 changes: 92 additions & 27 deletions main.go
Original file line number Diff line number Diff line change
@@ -1,96 +1,161 @@
package main

/*
based on
https://github.com/ipfs/go-ipfs-keystore/blob/master/keystore.go
https://github.com/ipfs/go-ipfs/blob/master/core/coreapi/key.go
https://github.com/ipfs/go-ipfs/blob/master/core/node/identity.go
*/

import (
"crypto/rand"
"fmt"
"io/ioutil"
"log"
"os"
"regexp"
"runtime"
"strings"
//"strings"
"encoding/base64"
//"encoding/base32"

"github.com/libp2p/go-libp2p-core/crypto"
"github.com/libp2p/go-libp2p-core/peer"
)

var (
alphabet = regexp.MustCompile("^[123456789abcdefghijklmnopqrstuvwxyz]+$")
numWorkers = runtime.NumCPU()
)

// Key stores PrettyID containing desired substring at Index
type Key struct {
PrettyID string
Index int
Index int
Part string
PrivateKey64 string
}

func main() {
if len(os.Args) != 2 {
fmt.Printf(`
This tool generates IPFS public and private keypair until it finds public key
which contains required substring. Keys are stored in local directory. If you
like one of them, you can move it to ~/.ipfs/keystore/ to use it with IPFS.
This tool can generate IPFS public and private keypairs
and filter the public keys by regex, to find vanity IPFS public keys
Keypairs are printed to stdout and to output.txt
To use a key, edit your ~/.ipfs/config file, which is generated by ipfs init
Identity.PeerID is your public key
Identity.PrivKey is your private key in base64 encoding
Usage:
%s {part}
For fast results suggested length of public key part is 4-5 characters
%s {regex}
For fast results, use a short substring of 4-5 characters
Alphabet of public key:
[1-9a-zA-Z]
Regex samples:
hello$
(?i)hello
(foo|bar)$
Regex basics:
(?i) add this prefix to make the regex case-insensitive
(a|b) a or b
$ end of string
^ start of string. not needed here, the start is mostly constant
Regex docs:
https://duckduckgo.com/?q=golang+regexp
https://yourbasic.org/golang/regexp-cheat-sheet/
https://golangdocs.com/regex-in-golang-regexp-package
`, os.Args[0])
os.Exit(1)
}
part := strings.ToLower(os.Args[1])
if !alphabet.MatchString(part) {
fmt.Println("{part} must match the alphabet:", alphabet.String())
os.Exit(2)

partRegex := regexp.MustCompile(os.Args[1])
// TODO? validate regex with alphabet
//alphabet = regexp.MustCompile("^[123456789abcdefghijklmnopqrstuvwxyz]+$")

outputFile, err := os.OpenFile("output.txt", os.O_APPEND | os.O_CREATE | os.O_WRONLY, 0644)
if err != nil {
log.Println(err)
}
defer outputFile.Close()

runtime.GOMAXPROCS(numWorkers)
keyChan := make(chan Key)
for i := 0; i < numWorkers; i++ {
go func() {
err := generateKey(part, keyChan)
err := generateKey(partRegex, keyChan)
if err != nil {
log.Fatal(err)
}
}()
}
for key := range keyChan {

fmt.Printf(
"%s\u001b[32m%s\u001b[0m%s\n",
// TODO allow to disable color
"%s %s\u001b[32m%s\u001b[0m%s %s\n",
//"%s %s%s%s %s\n",
key.Part,
key.PrettyID[:key.Index],
key.PrettyID[key.Index:len(part)+key.Index],
key.PrettyID[len(part)+key.Index:])
key.PrettyID[key.Index:len(key.Part)+key.Index],
key.PrettyID[len(key.Part)+key.Index:],
key.PrivateKey64,
)

// TODO allow to print json format for ~/.ipfs/config
/*
fmt.Printf(
"%s\n \"Identity\": {\n \"PeerID\": \"%s\",\n \"PrivKey\": \"%s\",\n },\n\n",
key.Part, key.PrettyID, key.PrivateKey64,
)
*/

// TODO allow to disable writing to output.txt
_, err := outputFile.WriteString(
fmt.Sprintf("%s %s %s\n", key.Part, key.PrettyID, key.PrivateKey64),
)
if err != nil {
log.Println(err)
}
}
}

func generateKey(part string, keyChan chan Key) error {
func generateKey(partRegex *regexp.Regexp, keyChan chan Key) error {
for {
privateKey, publicKey, err := crypto.GenerateEd25519Key(rand.Reader)
if err != nil {
return err
}

peerID, err := peer.IDFromPublicKey(publicKey)
if err != nil {
return err
}
prettyID := peerID.Pretty()
lowerID := strings.ToLower(prettyID)
idx := strings.Index(lowerID, part)
if idx == -1 {

if !partRegex.MatchString(prettyID) {
continue
}
privateKeyBytes, err := privateKey.Raw()
if err != nil {
return err
}
err = ioutil.WriteFile(prettyID, privateKeyBytes, 0600)
// TODO print privateKey in base64, as in ~/.ipfs/config .Identity.PrivKey

part := partRegex.FindString(prettyID)
idx := partRegex.FindStringIndex(prettyID)[0]

privateKeyBytes, err := crypto.MarshalPrivateKey(privateKey)
if err != nil {
return err
}

privateKey64 := base64.StdEncoding.EncodeToString(privateKeyBytes)

keyChan <- Key{
PrettyID: prettyID,
Index: idx,
Part: part,
PrivateKey64: privateKey64,
}
}
}

0 comments on commit ed7ddc4

Please sign in to comment.