Skip to content

Commit

Permalink
Multicore fixes, allow nil pattern, update README.
Browse files Browse the repository at this point in the history
Also fix version String().
  • Loading branch information
chappjc committed Aug 24, 2016
1 parent 33d1e7c commit ae88455
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 39 deletions.
75 changes: 74 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ dcrvanity

dcrvanity is an address and keypair generator for [decred](https://decred.org/).

It takes one or two regex patterns that are matched against the address.
It takes one or two regex patterns that are matched against the address. The
patterns may be unrelated, but in the case where one pattern implies a match on
the other, a switch can be given to speed up the search.

## Requirements

Expand All @@ -27,4 +29,75 @@ Generate a Decred private and public key matching pattern(s).
-regtest Generate a regtest key instead of mainnet
-pattern1 Primary pattern. dcrvanity will exit if this matches an address.
-pattern2 Secondary pattern. dcrvanity will NOT exit, just report, an address match.
-pat1implies2 A match on pattern1 implies a match on pattern2.
-N Number of goroutines to launch (essentially the number of cores to use).
```

The pattern should not include any of `0OIl`.

## Important First Character Restrictions

Many character may not appear in the first digit following "Ds" in an encoded
Decred address. Notably, this includes the potentially confusing characters
`0OIl`, which are present nowhere in an address. Most capital letters should
also not be used as the first letter in the input pattern. However, the
following characters should be possible in the first position after the Ds
prefix: `[a-npQ-Z]` (lowercase a to p, excluding o, and uppercae Q to Z).

Before beginning a potentially long search, test the leading character alone.
Please read more about [base58 address
encoding](https://en.bitcoin.it/wiki/Base58Check_encoding) for more information
about what characters are acceptable.

## Examples

Use 1 core, by default, to search for an address starting with "Dsdcr":

$ dcrvanity.exe -pattern1 dcr
Primary pattern: ^Dsdcr
30325
Woohoo!
Addr: Dsdcr4zcCVvataLzb5w5m6WdnbrM543EV3N
Private key (WIF-encoded): PmQeeekBXGjiPg4SBvHiZsym2zrM8NeTSUgDFjneFaGknaS5NjkER

Use 2 cores (`-N 2`) to search for an address with "goDCR" following the "Ds"
prefix:

$ dcrvanity.exe -pattern1 goDCR -N 2

Ultimately search for "fred". Report any case-insensitive match of "fred", but
don't stop searching. Specify that matching the primary pattern implies a match
on secondary (`-pat1implies2`).

$ dcrvanity.exe -pattern1 "fred" -pattern2 "f(?i)red" -pat1implies2
Primary pattern: ^Dsfred
Secondary pattern: ^Ds(?i)fred
808101
Addr: DsfrEdQDGFf6uYbjmkT2D1cDYoW6m9BD7ga
Pubkey compressed: 0375b0b472bddb49265131b72094e287ec2694d502310df5af1589ca7eef3b715f
Private key (WIF-encoded): PmQejCoacLSiLes4aj6vnNgRhtwjkKTDtBMkix3qDKrS8CEFhLcyD
1898882
Woohoo!
Addr: Dsfrediud1mTy9MuRHE5XNH4HJg9xhJ5Rts
Private key (WIF-encoded): PmQeHrMcmcRQBPqzBiSAnxzmQkj6sP3MdbCQZzeba8gyrwEmM3W4s
WIF struct: PmQeHrMcmcRQBPqzBiSAnxzmQkj6sP3MdbCQZzeba8gyrwEmM3W4s

First it found an address with "frEd" after Ds, then it found "fred" and
stopped searching.

Use 3 cores. Ultimately search for "decred", "d3cred", "DECRED", or "D3CRED".
Secondary pattern (report, but don't stop), implied by pattern1, is a
case-insensitive version of the primary pattern. Both patterns may be found
anywhere in the address because of the leading `.*`.

$ dcrvanity.exe -pattern1 ".*(d[e3]cred|D[E3]CRED)" -pattern2 ".*(?i)d[e3]cred" -N 3
Primary pattern: ^Ds.*(d[e3]cred|D[E3]CRED)
Secondary pattern: ^Ds.*(?i)d[e3]cred
4382354
Addr: Dsg6y9PwYkNj8VUQbLWVcy6qpBtZBDecred
Private key (WIF-encoded): Pm---------------------------------------------------

After 4382354 iterations, it found the address
Dsg6y9PwYkNj8VUQbLWVcy6qpBtZB**Decred**. The corresponding private key is
shown WIF-encoded, as this is the format required by `importprivkey`. I have
redacted the private key for this address since I rather like it.
75 changes: 40 additions & 35 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ func searchKeyPair(regexPrimary, regexSecondary *regexp.Regexp,

ticker := time.NewTicker(time.Millisecond * 200 * time.Duration(1+math.Ceil((float64(*nCores)-1)/1.5)))

searchloop:
for i := int64(0); ; i++ {
select {
case <-ticker.C:
Expand Down Expand Up @@ -139,40 +140,41 @@ func searchKeyPair(regexPrimary, regexSecondary *regexp.Regexp,
addr = addr0
fmt.Printf("Woohoo!\n")
atomic.AddInt64(&searchIterator, i)
break
break searchloop
}
}
} else {
// primary match does not imply secondary, so check both separately
if regexSecondary != nil && regexSecondary.MatchString(addr0.EncodeAddress()) {
ii := atomic.LoadInt64(&searchIterator) + i
fmt.Printf("\r%d\n%s\n", ii, addr0.EncodeAddress())
fmt.Printf("%x\n", pub.SerializeCompressed())
fmt.Printf("\r%d\nAddr: %s\n", ii, addr0.EncodeAddress())
fmt.Printf("Pubkey compressed: %x\n", pub.SerializeCompressed())

privX := secp256k1.PrivateKey{
PublicKey: key0.PublicKey,
D: key0.D,
}
privWifX := NewWIF(privX)
fmt.Printf("%s\n", privWifX.String())
fmt.Printf("Private key (WIF-encoded): %s\n", privWifX.String())
fmt.Println("Private key (secp256k1): ", privX)
}

// Primary does not require printing here since it will be displayed
// in main(). Get the keys and break.
if regexPrimary != nil && regexPrimary.MatchString(addr0.EncodeAddress()) {
ii := atomic.AddInt64(&searchIterator, i)
fmt.Printf("Woohoo!\n")
fmt.Printf("\r%d\n%s\n", ii, addr0.EncodeAddress())
fmt.Printf("%x\n", pub.SerializeCompressed())
atomic.AddInt64(&searchIterator, i)
fmt.Printf("\nWoohoo!\n")
key = key0
addr = addr0

privX := secp256k1.PrivateKey{
PublicKey: key0.PublicKey,
D: key0.D,
}
privWifX := NewWIF(privX)
fmt.Printf("%s\n", privWifX.String())
// privX := secp256k1.PrivateKey{
// PublicKey: key0.PublicKey,
// D: key0.D,
// }
//privWifX := NewWIF(privX)
//fmt.Printf("%s\n", privWifX.String())

break
break searchloop
}
}
}
Expand Down Expand Up @@ -234,6 +236,8 @@ func main() {

inclusive := *pat1implies2

fmt.Printf(appName+" version %s\n", ver.String())

var err error

if *getHelp {
Expand Down Expand Up @@ -263,10 +267,10 @@ func main() {
fmt.Printf("Failed to compile regexp %v: %v", pat, err)
return
}
fmt.Println("Primary pattern: ", regexPrimary.String())
} else {
fmt.Println("nil primary pattern. The program will never quit.")
}
fmt.Println("Primary pattern: ", regexPrimary.String())

// Secondary (report, but no exit) pattern
var regexSecondary *regexp.Regexp
Expand All @@ -278,26 +282,40 @@ func main() {
fmt.Printf("Failed to compile regexp %v: %v", pat, err)
return
}
fmt.Println("Secondary pattern: ", regexSecondary.String())
} else if inclusive {
fmt.Println("nil secondary pattern and inclusive is true. No addresses will be checked.")
return
}
fmt.Println("Secondary pattern: ", regexSecondary.String())

// Launch goroutines
N := int(*nCores)

// Wait for key search results or the quit signal
searchResultChan := make(chan keySearchResult)
searchResult := keySearchResult{}
go func() {
select {
case searchResult = <-searchResultChan:
close(quit)
case <-quit:
}
}()

goroutineloop:
for i := 0; i < N; i++ {
// Stagger the launches so the display is not quite so jumpy
time.Sleep(time.Duration(125*(N-1)) * time.Millisecond)
time.Sleep(time.Duration(100*(N-1)) * time.Millisecond)
select {
case <-quit:
fmt.Println("quit signaled. Not launching more goroutines.")
break goroutineloop
default:
}
wg.Add(1)
go keySearcher(regexPrimary, regexSecondary, inclusive, searchResultChan)
}

searchResult := keySearchResult{}

// Only accept a single CTRL+C
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
Expand All @@ -312,27 +330,14 @@ func main() {
return
}()

select {
case searchResult = <-searchResultChan:
close(quit)
case <-quit:
}

// Allow each goroutine to receive the quit signal and finish up
wg.Wait()

// Single keypair generation/search
// priv, addr, err := searchKeyPair(*pattern1, *pattern2, true)
// if err != nil {
// fmt.Printf("Error generating key pair: %v\n", err.Error())
// return
// }

if searchResult.priv != nil {
fmt.Printf("Addr: %s\n", searchResult.addr.EncodeAddress())
fmt.Println("Private key (secp256k1): ", searchResult.priv)
privWif := NewWIF(*searchResult.priv)
fmt.Printf("Private key (WIF-encoded): %s\nWIF struct: %v\n",
privWif.String(), privWif)
fmt.Println("Private key (WIF-encoded): ", privWif)
}

return
Expand Down
6 changes: 3 additions & 3 deletions version.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ var ver = version{
Major: 0,
Minor: 1,
Patch: 0,
Label: "alpha"}
Label: "beta"}

// CommitHash may be set on the build command line:
// go build -ldflags "-X main.CommitHash=`git rev-parse HEAD`"
Expand All @@ -21,9 +21,9 @@ const appName string = "dcrvanity"

func (v *version) String() string {
if v.Label != "" {
return fmt.Sprintf("%d.%d.%d-%s \"%s\"",
return fmt.Sprintf("%d.%d.%d-%s",
v.Major, v.Minor, v.Patch, v.Label)
}
return fmt.Sprintf("%d.%d.%d \"%s\"",
return fmt.Sprintf("%d.%d.%d",
v.Major, v.Minor, v.Patch)
}

0 comments on commit ae88455

Please sign in to comment.