Pages:
Author

Topic: VanitySearch (Yet another address prefix finder) - page 15. (Read 32072 times)

hero member
Activity: 1438
Merit: 513
For any of you guys hung up trying to get this to work I've made a simple submission guide/walkthrough for requesting a vanity wallet
Here
I would like to automate this if anyone would be interested in helping i could make it worthwhile
Automating it would entail a quote based on lavishness ,verifying a txid and automatically working it on submission or when txid has 1 confirmation
I have a website too it could be built from/on. Id like to provide 6 digits or less for free with this service.
newbie
Activity: 8
Merit: 0
@Jean_Luc , btw..

yeah I can search all keys in 3 days Smiley

this is with 1.16

Vanitysearch.exe -b -t 0 -gpu -gpuId 0,1 -g 1088,512,1088,512 -r 10000000 -o found_0.txt -i in.txt

[4544125350086.37 Mkey/s][GPU 4544125350086.37 Mkey/s][Total 2^64.00][Prob 0.0%][50% in 7.06916e+21y][Found 0]

544,512,544,512 still shows korrekt MKeys

Huh


Hi Jean_Luc,
I have work your commanding as above, it was found same result as bellow:

VanitySearch16.exe -b -gpu -gpuId 0,1 -g 1088,512,1088,512 -r 10000000 -o results.txt -i addr.txt
VanitySearch v1.16
Search: 17 prefixes (Lookup size 17) [Compressed or Uncompressed]
Start Thu Mar 25 21:43:10 2021
Base Key: Randomly changed every 10000000 Mkeys
Number of CPU thread: 46
GPU: GPU #0 GeForce RTX 3080 (68x0 cores) Grid(1088x512)
GPU: GPU #1 GeForce RTX 3080 (68x0 cores) Grid(1088x512)
[475.99 Mkey/s][GPU 0.00 Mkey/s][Total 2^29.85][Prob 0.0%][50% in 50.6d][Found 0]
Warning, 1710241 items lost
Hint: Search with less prefixes, less threads (-g) or increase maxFound (-m)

Warning, 1713507 items lost
Hint: Search with less prefixes, less threads (-g) or increase maxFound (-m)
[4521395825967.33 Mkey/s][GPU 4521395825916.71 Mkey/s][Total 2^64.00][Prob 100.0%][99% in 00:00:00][Found 0]

I want to ensure you it is real and it was count 2^64.00 per second. Please response.....
newbie
Activity: 6
Merit: 0
Can anybody please post here link for VanBitKraken program?
legendary
Activity: 1568
Merit: 6660
bitcoincleanup.com / bitmixlist.org
I can't understand, is the search for private keys from the list of full addresses (100000+) on the processor and on the video card not the same (despite the speed)? And what is the difference if it is?

I just peeked at the code and it doesn't look like there's any. The GPU code is called from the main loop in CPU so the only things which could possibly be different could be the way it checks points/hashes and how it iterates through them.

I think it is very similar to these btc address generators. But underlying algo is different which is ed25519 in case of onion v3 addresses. How hard is it to port vanitysearch to do onion v3?

The Integer class is abstracted enough to let you make your own curve class and slot it right inside as a parameter, but writing ed25519 arithmetic in assembly will be one hell of a challenge.

... or you could directly use this expression -i input.txt > output.txt this way no extra work has to be done we can directly save it to text file whatever the command line is outputting

I don't like this particular approach. The console is just as slow as file I/O, which you can easily notice if you run any cpu-intensive program with its --verbose switch and notice how the time for the command to complete becomes longer because so much time is being spent printing to the screen.

Redirecting output to a file from a shell doesn't make it any faster, it just "fools" the program into thinking its writing to the console.
newbie
Activity: 20
Merit: 0
~
can somebody implement this please i have millions of private keys so it cannot be converted quickly to addresses with cpu because cpu is not powerful enough can somebody make small modification to the software where it read single hex private key to read those values from file this way we can convert millions of private keys using gpu thanks again for anyone out there who can help.

How exactly many millions are we talking about? Because GPUs cannot do disk I/O, so only the actual conversion of hex to WIF can be accelerated with CUDA. The reads and writes still have to be done on CPU, and then all that has to be copied to the GPU memory and then back again, because CUDA cannot read memory in RAM (unless you use their new feature called Unified Memory but honestly I don't know how fast that is), so what I'm trying to tell you is it might be better implementing this on CPU using multiple threads and the AVX instruction set and that should the job. The CPU can already do much more complicated address generation at millions of keys per second anyway.

Because none have made it as you said the conversation is possible with gpu and at the time of saving you can use cpu i think the program already does it can convert millions keys per second and cpu can save it in a minute this way is better then all the way to cpu or you could directly use this expression -i input.txt > output.txt this way no extra work has to be done we can directly save it to text file whatever the command line is outputting
newbie
Activity: 18
Merit: 1
Can anyone build GPU vanity search for Onion V3 addresses?

There is cpu version: https://github.com/cathugger/mkp224o
And GPU version for v2 address which are old format: https://github.com/lachesis/scallion

I think it is very similar to these btc address generators. But underlying algo is different which is ed25519 in case of onion v3 addresses. How hard is it to port vanitysearch to do onion v3?
newbie
Activity: 12
Merit: 0
I can't understand, is the search for private keys from the list of full addresses (100000+) on the processor and on the video card not the same (despite the speed)? And what is the difference if it is?
legendary
Activity: 1568
Merit: 6660
bitcoincleanup.com / bitmixlist.org
~
can somebody implement this please i have millions of private keys so it cannot be converted quickly to addresses with cpu because cpu is not powerful enough can somebody make small modification to the software where it read single hex private key to read those values from file this way we can convert millions of private keys using gpu thanks again for anyone out there who can help.

How exactly many millions are we talking about? Because GPUs cannot do disk I/O, so only the actual conversion of hex to WIF can be accelerated with CUDA. The reads and writes still have to be done on CPU, and then all that has to be copied to the GPU memory and then back again, because CUDA cannot read memory in RAM (unless you use their new feature called Unified Memory but honestly I don't know how fast that is), so what I'm trying to tell you is it might be better implementing this on CPU using multiple threads and the AVX instruction set and that should the job. The CPU can already do much more complicated address generation at millions of keys per second anyway.
newbie
Activity: 8
Merit: 0
Quote
c++ coders please help me how to modify this to work on 64 bit rand not 256 bit rand. c++ really hard to me to understand
To key.Rand(64). This is going to change the starting key to be a 64-bit random int, same for all subsequent keys.
dude above suggest me to comment code blocks related endo and sym i tryed but got compile error then some tests again got key error .
Are you just trying to randomly generate only 64 bit keys to look for #64 of challenge/puzzle?
yes
Something like this:

Code:
VanBitKracken
RandomMode
Range Start=8000000000000000
  Range End=FFFFFFFFFFFFFFFF
Searching For: 16jY7qLJnxb7CHZyqBP8qca9d51gAjyXQN [Compressed]
Started Mon Mar 15 10:56:51 2021
CPU threads used: 0
GPU: GPU #4 GeForce RTX 2070 SUPER (40x64 cores) Grid(1024x512)
GPU: GPU #0 GeForce RTX 3070 (46x128 cores) Grid(1024x512)
GPU: GPU #5 GeForce RTX 2070 (36x64 cores) Grid(1024x512)
GPU: GPU #2 GeForce RTX 3070 (46x128 cores) Grid(1024x512)
GPU: GPU #1 GeForce RTX 3070 (46x128 cores) Grid(1024x512)
GPU: GPU #3 GeForce RTX 3070 (46x128 cores) Grid(1024x512)
Key 0: F8F7AB14B549D963
Key 1: E27A8E10F7B88360
Key 2: ABFE11261BBD4690
Key 3: F422548A1F4B2DAE
Key 0: FA88129A5AB50074
Key 1: B0341A673B1314D4
Key 2: C6719553AAD5A8C6
Key 3: D09C89B9E74DF9EE
Key 0: E9CC7B8BB752F5CB
Key 1: A7B789B6A94D60AD
Key 2: A741098EFA53130A
Key 3: 97FB2DB875755EA6
Key 0: F399AEDCE1F72EA8
Key 1: D24BDBDE76E19FAC
Key 2: 8F9A7FC4F8591C25
Key 3: CACFECB3F9230C7F
Key 0: F25D378E2916D696
Key 1: ED7EA9A718B61017
Key 2: FCDDD610A70AF071
Key 3: 893CF7F570EFB585
Key 0: D84FE1221CFDC77A
Key 1: D8445FE43B6D871E
Key 2: 8C323D909C23163C
Key 3: 867C5E6DA5D981D9
Key 524285: AA670B193E7CAA36
Key 524285: C6D15B55CC2DCA5A
Key 524286: C7901B0332FE38A9
Key 524286: EA11A526D7135C77
Key 524287: C5F35D538D961196
Key 524287: 8DA14E252E6DC1E7
Key 524285: D3FBF43E6888E2C0
Key 524286: F8F40F51C3388D6C
Key 524287: FB86E889D499BE6A
Key 524285: 8C639A3EEBBB486D
Key 524286: AFF06C39E04CF30D
Key 524287: D9A7EEE1CC93F155
Key 524285: CF060C3C274DB24A
Key 524286: C4349EEDE915A9A0
Key 524287: A57D8D77096307E4
Key 524285: B15B02DFB42CD315
Key 524286: A4F20EA9DABE20BB
[11419.89 Mkey/s][GPU 11419.89 Mkey/s][Private Keys Checked = 2^35.81] [00:00:07 Run Time ]  [Expected Run Time 34.7357y][Found 0]



version VanBitKracken? it's available?


Dear Sir,
Could you please share to us VanBitKracken software; I am looking for your valuable response.

Regards,
GSCIServices
newbie
Activity: 2
Merit: 0
Quote
c++ coders please help me how to modify this to work on 64 bit rand not 256 bit rand. c++ really hard to me to understand
To key.Rand(64). This is going to change the starting key to be a 64-bit random int, same for all subsequent keys.
dude above suggest me to comment code blocks related endo and sym i tryed but got compile error then some tests again got key error .
Are you just trying to randomly generate only 64 bit keys to look for #64 of challenge/puzzle?
yes
Something like this:

Code:
VanBitKracken
RandomMode
Range Start=8000000000000000
  Range End=FFFFFFFFFFFFFFFF
Searching For: 16jY7qLJnxb7CHZyqBP8qca9d51gAjyXQN [Compressed]
Started Mon Mar 15 10:56:51 2021
CPU threads used: 0
GPU: GPU #4 GeForce RTX 2070 SUPER (40x64 cores) Grid(1024x512)
GPU: GPU #0 GeForce RTX 3070 (46x128 cores) Grid(1024x512)
GPU: GPU #5 GeForce RTX 2070 (36x64 cores) Grid(1024x512)
GPU: GPU #2 GeForce RTX 3070 (46x128 cores) Grid(1024x512)
GPU: GPU #1 GeForce RTX 3070 (46x128 cores) Grid(1024x512)
GPU: GPU #3 GeForce RTX 3070 (46x128 cores) Grid(1024x512)
Key 0: F8F7AB14B549D963
Key 1: E27A8E10F7B88360
Key 2: ABFE11261BBD4690
Key 3: F422548A1F4B2DAE
Key 0: FA88129A5AB50074
Key 1: B0341A673B1314D4
Key 2: C6719553AAD5A8C6
Key 3: D09C89B9E74DF9EE
Key 0: E9CC7B8BB752F5CB
Key 1: A7B789B6A94D60AD
Key 2: A741098EFA53130A
Key 3: 97FB2DB875755EA6
Key 0: F399AEDCE1F72EA8
Key 1: D24BDBDE76E19FAC
Key 2: 8F9A7FC4F8591C25
Key 3: CACFECB3F9230C7F
Key 0: F25D378E2916D696
Key 1: ED7EA9A718B61017
Key 2: FCDDD610A70AF071
Key 3: 893CF7F570EFB585
Key 0: D84FE1221CFDC77A
Key 1: D8445FE43B6D871E
Key 2: 8C323D909C23163C
Key 3: 867C5E6DA5D981D9
Key 524285: AA670B193E7CAA36
Key 524285: C6D15B55CC2DCA5A
Key 524286: C7901B0332FE38A9
Key 524286: EA11A526D7135C77
Key 524287: C5F35D538D961196
Key 524287: 8DA14E252E6DC1E7
Key 524285: D3FBF43E6888E2C0
Key 524286: F8F40F51C3388D6C
Key 524287: FB86E889D499BE6A
Key 524285: 8C639A3EEBBB486D
Key 524286: AFF06C39E04CF30D
Key 524287: D9A7EEE1CC93F155
Key 524285: CF060C3C274DB24A
Key 524286: C4349EEDE915A9A0
Key 524287: A57D8D77096307E4
Key 524285: B15B02DFB42CD315
Key 524286: A4F20EA9DABE20BB
[11419.89 Mkey/s][GPU 11419.89 Mkey/s][Private Keys Checked = 2^35.81] [00:00:07 Run Time ]  [Expected Run Time 34.7357y][Found 0]



version VanBitKracken? it's available?
newbie
Activity: 20
Merit: 0
the -cp option at the moment does not convert private key hex to uncompressed address format i am sure this is not a bug also for convenience can you update -><

-cp option update:

add read from input file for -cp option where it can read bunch of private key in hex format from text file instead of single computation to leverage gpu horse power for converting pre computed private keys and converting to compressed and uncompressed address format there is no tool out there does this using gpu i am pretty most people want their pre computed private keys to be converted as a side benefit.

can somebody implement this please i have millions of private keys so it cannot be converted quickly to addresses with cpu because cpu is not powerful enough can somebody make small modification to the software where it read single hex private key to read those values from file this way we can convert millions of private keys using gpu thanks again for anyone out there who can help.
full member
Activity: 1162
Merit: 237
Shooters Shoot...
Quote
c++ coders please help me how to modify this to work on 64 bit rand not 256 bit rand. c++ really hard to me to understand
To key.Rand(64). This is going to change the starting key to be a 64-bit random int, same for all subsequent keys.
dude above suggest me to comment code blocks related endo and sym i tryed but got compile error then some tests again got key error .
Are you just trying to randomly generate only 64 bit keys to look for #64 of challenge/puzzle?
yes
Something like this:

Code:
VanBitKracken
RandomMode
Range Start=8000000000000000
  Range End=FFFFFFFFFFFFFFFF
Searching For: 16jY7qLJnxb7CHZyqBP8qca9d51gAjyXQN [Compressed]
Started Mon Mar 15 10:56:51 2021
CPU threads used: 0
GPU: GPU #4 GeForce RTX 2070 SUPER (40x64 cores) Grid(1024x512)
GPU: GPU #0 GeForce RTX 3070 (46x128 cores) Grid(1024x512)
GPU: GPU #5 GeForce RTX 2070 (36x64 cores) Grid(1024x512)
GPU: GPU #2 GeForce RTX 3070 (46x128 cores) Grid(1024x512)
GPU: GPU #1 GeForce RTX 3070 (46x128 cores) Grid(1024x512)
GPU: GPU #3 GeForce RTX 3070 (46x128 cores) Grid(1024x512)
Key 0: F8F7AB14B549D963
Key 1: E27A8E10F7B88360
Key 2: ABFE11261BBD4690
Key 3: F422548A1F4B2DAE
Key 0: FA88129A5AB50074
Key 1: B0341A673B1314D4
Key 2: C6719553AAD5A8C6
Key 3: D09C89B9E74DF9EE
Key 0: E9CC7B8BB752F5CB
Key 1: A7B789B6A94D60AD
Key 2: A741098EFA53130A
Key 3: 97FB2DB875755EA6
Key 0: F399AEDCE1F72EA8
Key 1: D24BDBDE76E19FAC
Key 2: 8F9A7FC4F8591C25
Key 3: CACFECB3F9230C7F
Key 0: F25D378E2916D696
Key 1: ED7EA9A718B61017
Key 2: FCDDD610A70AF071
Key 3: 893CF7F570EFB585
Key 0: D84FE1221CFDC77A
Key 1: D8445FE43B6D871E
Key 2: 8C323D909C23163C
Key 3: 867C5E6DA5D981D9
Key 524285: AA670B193E7CAA36
Key 524285: C6D15B55CC2DCA5A
Key 524286: C7901B0332FE38A9
Key 524286: EA11A526D7135C77
Key 524287: C5F35D538D961196
Key 524287: 8DA14E252E6DC1E7
Key 524285: D3FBF43E6888E2C0
Key 524286: F8F40F51C3388D6C
Key 524287: FB86E889D499BE6A
Key 524285: 8C639A3EEBBB486D
Key 524286: AFF06C39E04CF30D
Key 524287: D9A7EEE1CC93F155
Key 524285: CF060C3C274DB24A
Key 524286: C4349EEDE915A9A0
Key 524287: A57D8D77096307E4
Key 524285: B15B02DFB42CD315
Key 524286: A4F20EA9DABE20BB
[11419.89 Mkey/s][GPU 11419.89 Mkey/s][Private Keys Checked = 2^35.81] [00:00:07 Run Time ]  [Expected Run Time 34.7357y][Found 0]
newbie
Activity: 15
Merit: 0
Quote
c++ coders please help me how to modify this to work on 64 bit rand not 256 bit rand. c++ really hard to me to understand

To key.Rand(64). This is going to change the starting key to be a 64-bit random int, same for all subsequent keys.

thank you. but i already did that i am using gpu so changed keys.Rand(256);" to "keys.Rand(64);" on VanitySearch::getGPUStartingKeys but when i run VanitySearch.exe -t 0 -r 1 -gpu -o info.txt 1Lx  only some keys 64 bit .

dude above suggest me to comment code blocks related endo and sym i tryed but got compile error then some tests again got key error .
Are you just trying to randomly generate only 64 bit keys to look for #64 of challenge/puzzle?
yes
full member
Activity: 1162
Merit: 237
Shooters Shoot...
Quote
c++ coders please help me how to modify this to work on 64 bit rand not 256 bit rand. c++ really hard to me to understand

To key.Rand(64). This is going to change the starting key to be a 64-bit random int, same for all subsequent keys.

thank you. but i already did that i am using gpu so changed keys.Rand(256);" to "keys.Rand(64);" on VanitySearch::getGPUStartingKeys but when i run VanitySearch.exe -t 0 -r 1 -gpu -o info.txt 1Lx  only some keys 64 bit .

dude above suggest me to comment code blocks related endo and sym i tryed but got compile error then some tests again got key error .
Are you just trying to randomly generate only 64 bit keys to look for #64 of challenge/puzzle?
newbie
Activity: 15
Merit: 0
Quote
c++ coders please help me how to modify this to work on 64 bit rand not 256 bit rand. c++ really hard to me to understand

In Kangaroo.cpp try changing this line:

Code:
void VanitySearch::getCPUStartingKey(int thId,Int& key,Point& startP) {

  if (rekey > 0) {
    key.Rand(256); <--- this line
...

To key.Rand(64). This is going to change the starting key to be a 64-bit random int, same for all subsequent keys.

thank you. but i already did that i am using gpu so changed keys.Rand(256);" to "keys.Rand(64);" on VanitySearch::getGPUStartingKeys but when i run VanitySearch.exe -t 0 -r 1 -gpu -o info.txt 1Lx  only some keys 64 bit .

dude above suggest me to comment code blocks related endo and sym i tryed but got compile error then some tests again got key error .
legendary
Activity: 1568
Merit: 6660
bitcoincleanup.com / bitmixlist.org
Quote
c++ coders please help me how to modify this to work on 64 bit rand not 256 bit rand. c++ really hard to me to understand

In Kangaroo.cpp try changing this line:

Code:
void VanitySearch::getCPUStartingKey(int thId,Int& key,Point& startP) {

  if (rekey > 0) {
    key.Rand(256); <--- this line
...

To key.Rand(64). This is going to change the starting key to be a 64-bit random int, same for all subsequent keys.
full member
Activity: 1162
Merit: 237
Shooters Shoot...
hi i want to generate 64 bit not full 256 now i change "keys.Rand(256);" to "keys.Rand(64);" on VanitySearch::getGPUStartingKeys but only some keys are  64 bit what i am missing i am new on c++
most of keys found will be outside of 64 bit due to the endo and symm. Basically the program takes in inputted key, say 64 bit, but then checks it and 5 other keys related to that 64 bit key. So you would have to comment out those sections if you want all keys in the 64 bit range.
can you help me which code section need i comment

c++ coders please help me how to modify this to work on 64 bit rand not 256 bit rand. c++ really hard to me to understand
You will also have to modify the Main.cpp (at the minimum)
newbie
Activity: 15
Merit: 0
hi i want to generate 64 bit not full 256 now i change "keys.Rand(256);" to "keys.Rand(64);" on VanitySearch::getGPUStartingKeys but only some keys are  64 bit what i am missing i am new on c++
most of keys found will be outside of 64 bit due to the endo and symm. Basically the program takes in inputted key, say 64 bit, but then checks it and 5 other keys related to that 64 bit key. So you would have to comment out those sections if you want all keys in the 64 bit range.
can you help me which code section need i comment
Code:
/*
 * This file is part of the VanitySearch distribution (https://github.com/JeanLucPons/VanitySearch).
 * Copyright (c) 2019 Jean Luc PONS.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, version 3.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see .
*/

#include "Vanity.h"
#include "Base58.h"
#include "Bech32.h"
#include "hash/sha256.h"
#include "hash/sha512.h"
#include "IntGroup.h"
#include "Timer.h"
#include "hash/ripemd160.h"
#include
#include
#include
#ifndef WIN64
#include
#endif

using namespace std;

Point Gn[CPU_GRP_SIZE / 2];
Point _2Gn;

// ----------------------------------------------------------------------------

VanitySearch::VanitySearch(Secp256K1 *secp, vector &inputPrefixes,string seed,int searchMode,
                           bool useGpu, bool stop, string outputFile, bool useSSE, uint32_t maxFound,
                           uint64_t rekey, Point &startPubKey) {

  this->secp = secp;
  this->searchMode = searchMode;
  this->useGpu = useGpu;
  this->stopWhenFound = stop;
  this->outputFile = outputFile;
  this->useSSE = useSSE;
  this->nbGPUThread = 0;
  this->maxFound = maxFound;
  this->rekey = rekey;
  this->searchType = -1;
  this->startPubKey = startPubKey;
  this->startPubKeySpecified = !startPubKey.isZero();

  lastRekey = 0;
  prefixes.clear();

  // Create a 65536 items lookup table
  PREFIX_TABLE_ITEM t;
  t.found = true;
  t.items = NULL;
  for(int i=0;i<65536;i++)
    prefixes.push_back(t);

  // Insert prefixes
  bool loadingProgress = (inputPrefixes.size()>1000);
  if(loadingProgress)
    printf("[Building lookup16   0.0%%]\r");

  nbPrefix = 0;
  onlyFull = true;
  for (int i = 0; i < (int)inputPrefixes.size(); i++) {
    PREFIX_ITEM it;
    if (initPrefix(inputPrefixes[i], &it)) {
      std::vector *items;
      items = prefixes[it.sPrefix].items;
      if (items == NULL) {
        prefixes[it.sPrefix].items = new vector();
        prefixes[it.sPrefix].found = false;
        items = prefixes[it.sPrefix].items;
        usedPrefix.push_back(it.sPrefix);
      }
      items->push_back(it);
      onlyFull &= it.isFull;
      nbPrefix++;
    }
    if(loadingProgress && i%1000==0)
      printf("[Building lookup16 %5.1f%%]\r",(((double)i)/(double)(inputPrefixes.size()-1)) * 100.0);
  }

  if (loadingProgress)
    printf("\n");

  //dumpPrefixes();

  if (nbPrefix == 0) {
    printf("VanitySearch: nothing to search !\n");
    exit(1);
  }

  // Second level lookup
  uint32_t unique_sPrefix = 0;
  uint32_t minI = 0xFFFFFFFF;
  uint32_t maxI = 0;
  for (int i = 0; i < prefixes.size(); i++) {
    std::vector *items;
    items = prefixes[i].items;
    if (items) {
      LPREFIX lit;
      lit.sPrefix = i;
      for (int j = 0; j < items->size(); j++)
        lit.lPrefixes.push_back((*items)[j].lPrefix);
      sort(lit.lPrefixes.begin(), lit.lPrefixes.end());
      usedPrefixL.push_back(lit);
      if( (uint32_t)lit.lPrefixes.size()>maxI ) maxI = (uint32_t)lit.lPrefixes.size();
      if( (uint32_t)lit.lPrefixes.size()      unique_sPrefix++;
    }
    if (loadingProgress)
      printf("[Building lookup32 %.1f%%]\r", ((double)i*100.0) / (double)prefixes.size());
  }

  if (loadingProgress)
    printf("\n");

  _difficulty = getDiffuclty();
  string seachInfo = string(searchModes[searchMode]) + (startPubKeySpecified?" With Public Key":"");
  if (nbPrefix == 1) {
    prefix_t p0 = usedPrefix[0];
    printf("Difficulty: %.0f\n", _difficulty);
    printf("Search: %s [%s]\n", (*prefixes[p0].items)[0].prefix, seachInfo.c_str());
  } else {
    if (onlyFull) {
      printf("Search: %d addresses (Lookup size %d,[%d,%d]) [%s]\n", nbPrefix, unique_sPrefix, minI, maxI, seachInfo.c_str());
    } else {
      printf("Search: %d prefixes (Lookup size %d) [%s]\n", nbPrefix, unique_sPrefix, seachInfo.c_str());
    }
  }

  // Compute Generator table G[n] = (n+1)*G

  Point g = secp->G;
  Gn[0] = g;
  g = secp->DoubleDirect(g);
  Gn[1] = g;
  for (int i = 2; i < CPU_GRP_SIZE/2; i++) {
    g = secp->AddDirect(g,secp->G);
    Gn[i] = g;
  }
  // _2Gn = CPU_GRP_SIZE*G
  _2Gn = secp->DoubleDirect(Gn[CPU_GRP_SIZE/2-1]);

  // Constant for endomorphism
  // if a is a nth primitive root of unity, a^-1 is also a nth primitive root.
  // beta^3 = 1 mod p implies also beta^2 = beta^-1 mop (by multiplying both side by beta^-1)
  // (beta^3 = 1 mod p),  beta2 = beta^-1 = beta^2
  // (lambda^3 = 1 mod n), lamba2 = lamba^-1 = lamba^2
  beta.SetBase16("7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee");
  lambda.SetBase16("5363ad4cc05c30e0a5261c028812645a122e22ea20816678df02967c1b23bd72");
  beta2.SetBase16("851695d49a83f8ef919bb86153cbcb16630fb68aed0a766a3ec693d68e6afa40");
  lambda2.SetBase16("ac9c52b33fa3cf1f5ad9e3fd77ed9ba4a880b9fc8ec739c2e0cfc810b51283ce");

  // Seed
  if (seed.length() == 0) {
    // Default seed
    seed = to_string(Timer::getSeedFromTimer());
  }

  // Protect seed against "seed search attack" using pbkdf2_hmac_sha512
  string salt = "VanitySearch";
  unsigned char hseed[64];
  pbkdf2_hmac_sha512(hseed, 64, (const uint8_t *)seed.c_str(), seed.length(),
    (const uint8_t *)salt.c_str(), salt.length(),
    2048);
  startKey.SetInt32(0);
  sha256(hseed, 64, (unsigned char *)startKey.bits64);

  char *ctimeBuff;
  time_t now = time(NULL);
  ctimeBuff = ctime(&now);
  printf("Start %s", ctimeBuff);
  
  startKey.Rand(64);
  
  if (rekey > 0) {
    printf("Base Key: Randomly changed every %.0f Mkeys\n",(double)rekey);
    printf("Base Key: %s\n", startKey.GetBase16().c_str());
  } else {
    printf("Base Key: %s\n", startKey.GetBase16().c_str());
  }

}

// ----------------------------------------------------------------------------

bool VanitySearch::isSingularPrefix(std::string pref) {

  // check is the given prefix contains only 1
  bool only1 = true;
  int i=0;
  while (only1 && i < (int)pref.length()) {
    only1 = pref.data()[i] == '1';
    i++;
  }
  return only1;

}

// ----------------------------------------------------------------------------
bool VanitySearch::initPrefix(std::string &prefix,PREFIX_ITEM *it) {

  std::vector result;
  string dummy1 = prefix;
  int nbDigit = 0;
  bool wrong = false;

  if (prefix.length() < 2) {
    printf("Ignoring prefix \"%s\" (too short)\n",prefix.c_str());
    return false;
  }

  int aType = -1;
  

  switch (prefix.data()[0]) {
  case '1':
    aType = P2PKH;
    break;
  case '3':
    aType = P2SH;
    break;
  case 'b':
  case 'B':
    std::transform(prefix.begin(), prefix.end(), prefix.begin(), ::tolower);
    if(strncmp(prefix.c_str(), "bc1q", 4) == 0)
      aType = BECH32;
    break;
  }

  if (aType==-1) {
    printf("Ignoring prefix \"%s\" (must start with 1 or 3 or bc1q)\n", prefix.c_str());
    return false;
  }

  if (searchType == -1) searchType = aType;
  if (aType != searchType) {
    printf("Ignoring prefix \"%s\" (P2PKH, P2SH or BECH32 allowed at once)\n", prefix.c_str());
    return false;
  }

  if (aType == BECH32) {

    // BECH32
    uint8_t witprog[40];
    size_t witprog_len;
    int witver;
    const char* hrp = "bc";

    int ret = segwit_addr_decode(&witver, witprog, &witprog_len, hrp, prefix.c_str());

    // Try to attack a full address ?
    if (ret && witprog_len==20) {

      // mamma mia !
      it->difficulty = pow(2, 160);
      it->isFull = true;
      memcpy(it->hash160, witprog, 20);
      it->sPrefix = *(prefix_t *)(it->hash160);
      it->lPrefix = *(prefixl_t *)(it->hash160);
      it->prefix = (char *)prefix.c_str();
      it->prefixLength = (int)prefix.length();
      it->found = false;
      return true;

    }

    if (prefix.length() < 5) {
      printf("Ignoring prefix \"%s\" (too short, length<5 )\n", prefix.c_str());
      return false;
    }

    if (prefix.length() >= 36) {
      printf("Ignoring prefix \"%s\" (too long, length>36 )\n", prefix.c_str());
      return false;
    }

    uint8_t data[64];
    memset(data,0,64);
    size_t data_length;
    if(!bech32_decode_nocheck(data,&data_length,prefix.c_str()+4)) {
      printf("Ignoring prefix \"%s\" (Only \"023456789acdefghjklmnpqrstuvwxyz\" allowed)\n", prefix.c_str());
      return false;
    }

    // Difficulty
    it->sPrefix = *(prefix_t *)data;
    it->difficulty = pow(2, 5*(prefix.length()-4));
    it->isFull = false;
    it->lPrefix = 0;
    it->prefix = (char *)prefix.c_str();
    it->prefixLength = (int)prefix.length();
    it->found = false;

    return true;

  } else {

    // P2PKH/P2SH

    wrong = !DecodeBase58(prefix, result);

    if (wrong) {
      printf("Ignoring prefix \"%s\" (0, I, O and l not allowed)\n", prefix.c_str());
      return false;
    }

    // Try to attack a full address ?
    if (result.size() > 21) {

      // mamma mia !
      //if (!secp.CheckPudAddress(prefix)) {
      //  printf("Warning, \"%s\" (address checksum may never match)\n", prefix.c_str());
      //}
      it->difficulty = pow(2, 160);
      it->isFull = true;
      memcpy(it->hash160, result.data() + 1, 20);
      it->sPrefix = *(prefix_t *)(it->hash160);
      it->lPrefix = *(prefixl_t *)(it->hash160);
      it->prefix = (char *)prefix.c_str();
      it->prefixLength = (int)prefix.length();
      it->found = false;
      return true;

    }

    // Prefix containing only '1'
    if (isSingularPrefix(prefix)) {

      if (prefix.length() > 21) {
        printf("Ignoring prefix \"%s\" (Too much 1)\n", prefix.c_str());
        return false;
      }

      // Difficulty
      it->difficulty = pow(256, prefix.length() - 1);
      it->isFull = false;
      it->sPrefix = 0;
      it->lPrefix = 0;
      it->prefix = (char *)prefix.c_str();
      it->prefixLength = (int)prefix.length();
      it->found = false;
      return true;

    }

    // Search for highest hash160 16bit prefix (most probable)

    while (result.size() < 25) {
      DecodeBase58(dummy1, result);
      if (result.size() < 25) {
        dummy1.append("1");
        nbDigit++;
      }
    }

    if (searchType == P2SH) {
      if (result.data()[0] != 5) {
        printf("Ignoring prefix \"%s\" (Unreachable, 31h1 to 3R2c only)\n", prefix.c_str());
        return false;
      }
    }

    if (result.size() != 25) {
      printf("Ignoring prefix \"%s\" (Invalid size)\n", prefix.c_str());
      return false;
    }

    //printf("VanitySearch: Found prefix %s\n",GetHex(result).c_str() );
    it->sPrefix = *(prefix_t *)(result.data() + 1);

    dummy1.append("1");
    DecodeBase58(dummy1, result);

    if (result.size() == 25) {
      //printf("VanitySearch: Found prefix %s\n", GetHex(result).c_str());
      it->sPrefix = *(prefix_t *)(result.data() + 1);
      nbDigit++;
    }

    // Difficulty
    it->difficulty = pow(2, 192) / pow(58, nbDigit);
    it->isFull = false;
    it->lPrefix = 0;
    it->prefix = (char *)prefix.c_str();
    it->prefixLength = (int)prefix.length();
    it->found = false;

    return true;

  }
}

// ----------------------------------------------------------------------------

void VanitySearch::dumpPrefixes() {

  for (int i = 0; i < 0xFFFF; i++) {
    if (prefixes[i].items) {
      printf("%04X\n", i);
      std::vector *items = prefixes[i].items;
      for (int j = 0; j < (*items).size(); j++) {
        printf("  %d\n", (*items)[j].sPrefix);
        printf("  %g\n", (*items)[j].difficulty);
        printf("  %s\n", (*items)[j].prefix);
      }
    }
  }

}

// ----------------------------------------------------------------------------

double VanitySearch::getDiffuclty() {

  double min = pow(2,160);

  if (onlyFull)
    return min;

  for (int i = 0; i < (int)usedPrefix.size(); i++) {
    int p = usedPrefix[i];
    std::vector& items = *prefixes[p].items;
    for (int j = 0; j < items.size(); j++) {
      if (!items[j].found) {
        if(items[j].difficulty          min = items[j].difficulty;
      }
    }
  }

  return min;

}

double log1(double x) {
  // Use taylor series to approximate log(1-x)
  return -x - (x*x)/2.0 - (x*x*x)/3.0 - (x*x*x*x)/4.0;
}

string VanitySearch::GetExpectedTime(double keyRate,double keyCount) {

  char tmp[128];
  string ret;

  double P = 1.0/ _difficulty;
  // pow(1-P,keyCount) is the probality of failure after keyCount tries
  double cP = 1.0 - pow(1-P,keyCount);

  sprintf(tmp,"[P %.2f%%]",cP*100.0);
  ret = string(tmp);
  
  double desiredP = 0.5;
  while(desiredP    desiredP += 0.1;
  if(desiredP>=0.99) desiredP = 0.99;
  double k = log(1.0-desiredP)/log(1.0-P);
  if (isinf(k)) {
    // Try taylor
    k = log(1.0 - desiredP)/log1(P);
  }
  double dTime = (k-keyCount)/keyRate; // Time to perform k tries

  if(dTime<0) dTime = 0;

  double nbDay  = dTime / 86400.0;
  if (nbDay >= 1) {

    double nbYear = nbDay/365.0;
    if (nbYear > 1) {
      if(nbYear<5)
        sprintf(tmp, "[%.2f%% in %.1fy]", desiredP*100.0, nbYear);
      else
        sprintf(tmp, "[%.2f%% in %gy]", desiredP*100.0, nbYear);
    } else {
      sprintf(tmp, "[%.2f%% in %.1fd]", desiredP*100.0, nbDay);
    }

  } else {

    int iTime = (int)dTime;
    int nbHour = (int)((iTime % 86400) / 3600);
    int nbMin = (int)(((iTime % 86400) % 3600) / 60);
    int nbSec = (int)(iTime % 60);

    sprintf(tmp, "[%.2f%% in %02d:%02d:%02d]", desiredP*100.0, nbHour, nbMin, nbSec);

  }

  return ret + string(tmp);

}

// ----------------------------------------------------------------------------

void VanitySearch::output(string addr,string pAddr,string pAddrHex) {

#ifdef WIN64
   WaitForSingleObject(ghMutex,INFINITE);
#else
  pthread_mutex_lock(&ghMutex);
#endif
  
  FILE *f = stdout;
  bool needToClose = false;

  if (outputFile.length() > 0) {
    f = fopen(outputFile.c_str(), "a");
    if (f == NULL) {
      printf("Cannot open %s for writing\n", outputFile.c_str());
      f = stdout;
    } else {
      needToClose = true;
    }
  }

  fprintf(f, "\nPub Addr: %s\n", addr.c_str());

  if (startPubKeySpecified) {

    fprintf(f, "PartialPriv: %s\n", pAddr.c_str());

  } else {

    switch (searchType) {
    case P2PKH:
      fprintf(f, "Priv (WIF): p2pkh:%s\n", pAddr.c_str());
      break;
    case P2SH:
      fprintf(f, "Priv (WIF): p2wpkh-p2sh:%s\n", pAddr.c_str());
      break;
    case BECH32:
      fprintf(f, "Priv (WIF): p2wpkh:%s\n", pAddr.c_str());
      break;
    }
    fprintf(f, "Priv (HEX): 0x%s\n", pAddrHex.c_str());

  }

  if(needToClose)
    fclose(f);

#ifdef WIN64
  ReleaseMutex(ghMutex);
#else
  pthread_mutex_unlock(&ghMutex);
#endif

}

// ----------------------------------------------------------------------------

void VanitySearch::updateFound() {

  // Check if all prefixes has been found
  // Needed only if stopWhenFound is asked
  if (stopWhenFound) {

    bool allFound = true;
    for (int i = 0; i < usedPrefix.size(); i++) {
      bool iFound = true;
      if (!prefixes[usedPrefix[i]].found) {
        std::vector& items = *prefixes[usedPrefix[i]].items;
        for (int j = 0; j < items.size(); j++)
          iFound &= items[j].found;
        prefixes[usedPrefix[i]].found = iFound;
      }
      allFound &= iFound;
    }
    endOfSearch = allFound;

    // Update difficulty to the next most probable item
    _difficulty = getDiffuclty();

  }

}

// ----------------------------------------------------------------------------

bool VanitySearch::checkPrivKey(string addr, Int &key, int32_t incr, int endomorphism, bool mode) {

  Int k(&key);
  Point sp = startPubKey;

  if (incr < 0) {
    k.Add((uint64_t)(-incr));
    k.Neg();
    k.Add(&secp->order);
    if (startPubKeySpecified) sp.y.ModNeg();
  } else {
    k.Add((uint64_t)incr);
  }

  // Endomorphisms
  switch (endomorphism) {
  case 1:
    k.ModMulK1order(&lambda);
    if(startPubKeySpecified) sp.x.ModMulK1(&beta);
    break;
  case 2:
    k.ModMulK1order(&lambda2);
    if (startPubKeySpecified) sp.x.ModMulK1(&beta2);
    break;
  }

  // Check addresses
  Point p = secp->ComputePublicKey(&k);
  if (startPubKeySpecified) p = secp->AddDirect(p, sp);

  string chkAddr = secp->GetAddress(searchType, mode, p);
  if (chkAddr != addr) {

    //Key may be the opposite one (negative zero or compressed key)
    k.Neg();
    k.Add(&secp->order);
    p = secp->ComputePublicKey(&k);
    if (startPubKeySpecified) {
      sp.y.ModNeg();
      p = secp->AddDirect(p, sp);
    }
    string chkAddr = secp->GetAddress(searchType, mode, p);
    if (chkAddr != addr) {
      printf("\nWarning, wrong private key generated !\n");
      printf("  Addr :%s\n", addr.c_str());
      printf("  Check:%s\n", chkAddr.c_str());
      printf("  Endo:%d incr:%d comp:%d\n", endomorphism, incr, mode);
      return false;
    }

  }

  output(addr, secp->GetPrivAddress(mode ,k), k.GetBase16());

  return true;

}

void VanitySearch::checkAddr(int prefIdx, uint8_t *hash160, Int &key, int32_t incr, int endomorphism, bool mode) {

  vector& items = *prefixes[prefIdx].items;
  
  if (onlyFull) {
 
// Full addresses
    for (int i = 0; i < items.size(); i++) {

      if(stopWhenFound && items[i].found)
        continue;

      if (ripemd160_comp_hash(items[i].hash160, hash160) ) {

        // Found it !
        // You believe it ?
        if (checkPrivKey(secp->GetAddress(searchType,mode,hash160), key, incr, endomorphism, mode)) {
          // Mark it as found
          items[i].found = true;
          nbFoundKey++;
          updateFound();
        }
        
      }

    }
    
  } else {
 
    char a[64];
 
    string addr = secp->GetAddress(searchType, mode, hash160);

    for (int i = 0; i < items.size(); i++) {

      if(stopWhenFound && items[i].found)
        continue;
        
      strncpy(a, addr.c_str(),items[i].prefixLength);
      a[items[i].prefixLength] = 0;
        
      if (strcmp(items[i].prefix, a) == 0) {

        // Found it !
        if (checkPrivKey(addr, key, incr, endomorphism, mode)) {
          // Mark it as found
          items[i].found = true;
          nbFoundKey++;
          updateFound();
        }

      }

    }

  }
  
}

// ----------------------------------------------------------------------------

#ifdef WIN64
DWORD WINAPI _FindKey(LPVOID lpParam) {
#else
void *_FindKey(void *lpParam) {
#endif
  TH_PARAM *p = (TH_PARAM *)lpParam;
  p->obj->FindKeyCPU(p);
  return 0;
}

#ifdef WIN64
DWORD WINAPI _FindKeyGPU(LPVOID lpParam) {
#else
void *_FindKeyGPU(void *lpParam) {
#endif
  TH_PARAM *p = (TH_PARAM *)lpParam;
  p->obj->FindKeyGPU(p);
  return 0;
}

// ----------------------------------------------------------------------------

void VanitySearch::checkAddresses(bool compressed, Int key, int i, Point p1) {

  unsigned char h0[20];
  Point pte1[1];
  Point pte2[1];

  // Point
  secp->GetHash160(searchType,compressed, p1, h0);
  prefix_t pr0 = *(prefix_t *)h0;
  if (prefixes[pr0].items)
    checkAddr(pr0, h0, key, i, 0, compressed);

  // Endomorphism #1
  pte1[0].x.ModMulK1(&p1.x, &beta);
  pte1[0].y.Set(&p1.y);

  secp->GetHash160(searchType, compressed, pte1[0], h0);

  pr0 = *(prefix_t *)h0;
  if (prefixes[pr0].items)
    checkAddr(pr0, h0, key, i, 1, compressed);

  // Endomorphism #2
  pte2[0].x.ModMulK1(&p1.x, &beta2);
  pte2[0].y.Set(&p1.y);

  secp->GetHash160(searchType, compressed, pte2[0], h0);

  pr0 = *(prefix_t *)h0;
  if (prefixes[pr0].items)
    checkAddr(pr0, h0, key, i, 2, compressed);

  // Curve symetrie
  // if (x,y) = k*G, then (x, -y) is -k*G
  p1.y.ModNeg();
  secp->GetHash160(searchType, compressed, p1, h0);
  pr0 = *(prefix_t *)h0;
  if (prefixes[pr0].items)
    checkAddr(pr0, h0, key, -i, 0, compressed);

  // Endomorphism #1
  pte1[0].y.ModNeg();

  secp->GetHash160(searchType, compressed, pte1[0], h0);

  pr0 = *(prefix_t *)h0;
  if (prefixes[pr0].items)
    checkAddr(pr0, h0, key, -i, 1, compressed);

  // Endomorphism #2
  pte2[0].y.ModNeg();

  secp->GetHash160(searchType, compressed, pte2[0], h0);

  pr0 = *(prefix_t *)h0;
  if (prefixes[pr0].items)
    checkAddr(pr0, h0, key, -i, 2, compressed);

}

// ----------------------------------------------------------------------------

void VanitySearch::checkAddressesSSE(bool compressed,Int key, int i, Point p1, Point p2, Point p3, Point p4) {

  unsigned char h0[20];
  unsigned char h1[20];
  unsigned char h2[20];
  unsigned char h3[20];
  Point pte1[4];
  Point pte2[4];

  // Point -------------------------------------------------------------------------
  secp->GetHash160(searchType, compressed, p1, p2, p3, p4, h0, h1, h2, h3);

  prefix_t pr0 = *(prefix_t *)h0;
  prefix_t pr1 = *(prefix_t *)h1;
  prefix_t pr2 = *(prefix_t *)h2;
  prefix_t pr3 = *(prefix_t *)h3;

  if (prefixes[pr0].items)
    checkAddr(pr0, h0, key, i, 0, compressed);
  if (prefixes[pr1].items)
    checkAddr(pr1, h1, key, i + 1, 0, compressed);
  if (prefixes[pr2].items)
    checkAddr(pr2, h2, key, i + 2, 0, compressed);
  if (prefixes[pr3].items)
    checkAddr(pr3, h3, key, i + 3, 0, compressed);

  // Endomorphism #1
  // if (x, y) = k * G, then (beta*x, y) = lambda*k*G
  pte1[0].x.ModMulK1(&p1.x, &beta);
  pte1[0].y.Set(&p1.y);
  pte1[1].x.ModMulK1(&p2.x, &beta);
  pte1[1].y.Set(&p2.y);
  pte1[2].x.ModMulK1(&p3.x, &beta);
  pte1[2].y.Set(&p3.y);
  pte1[3].x.ModMulK1(&p4.x, &beta);
  pte1[3].y.Set(&p4.y);

  secp->GetHash160(searchType, compressed, pte1[0], pte1[1], pte1[2], pte1[3], h0, h1, h2, h3);

  pr0 = *(prefix_t *)h0;
  pr1 = *(prefix_t *)h1;
  pr2 = *(prefix_t *)h2;
  pr3 = *(prefix_t *)h3;

  if (prefixes[pr0].items)
    checkAddr(pr0, h0, key, i, 1, compressed);
  if (prefixes[pr1].items)
    checkAddr(pr1, h1, key, (i + 1), 1, compressed);
  if (prefixes[pr2].items)
    checkAddr(pr2, h2, key, (i + 2), 1, compressed);
  if (prefixes[pr3].items)
    checkAddr(pr3, h3, key, (i + 3), 1, compressed);

  // Endomorphism #2
  // if (x, y) = k * G, then (beta2*x, y) = lambda2*k*G
  pte2[0].x.ModMulK1(&p1.x, &beta2);
  pte2[0].y.Set(&p1.y);
  pte2[1].x.ModMulK1(&p2.x, &beta2);
  pte2[1].y.Set(&p2.y);
  pte2[2].x.ModMulK1(&p3.x, &beta2);
  pte2[2].y.Set(&p3.y);
  pte2[3].x.ModMulK1(&p4.x, &beta2);
  pte2[3].y.Set(&p4.y);

  secp->GetHash160(searchType, compressed, pte2[0], pte2[1], pte2[2], pte2[3], h0, h1, h2, h3);

  pr0 = *(prefix_t *)h0;
  pr1 = *(prefix_t *)h1;
  pr2 = *(prefix_t *)h2;
  pr3 = *(prefix_t *)h3;

  if (prefixes[pr0].items)
    checkAddr(pr0, h0, key, i, 2, compressed);
  if (prefixes[pr1].items)
    checkAddr(pr1, h1, key, (i + 1), 2, compressed);
  if (prefixes[pr2].items)
    checkAddr(pr2, h2, key, (i + 2), 2, compressed);
  if (prefixes[pr3].items)
    checkAddr(pr3, h3, key, (i + 3), 2, compressed);

  // Curve symetrie -------------------------------------------------------------------------
  // if (x,y) = k*G, then (x, -y) is -k*G

  p1.y.ModNeg();
  p2.y.ModNeg();
  p3.y.ModNeg();
  p4.y.ModNeg();

  secp->GetHash160(searchType, compressed, p1, p2, p3, p4, h0, h1, h2, h3);

  pr0 = *(prefix_t *)h0;
  pr1 = *(prefix_t *)h1;
  pr2 = *(prefix_t *)h2;
  pr3 = *(prefix_t *)h3;

  if (prefixes[pr0].items)
    checkAddr(pr0, h0, key, -i, 0, compressed);
  if (prefixes[pr1].items)
    checkAddr(pr1, h1, key, -(i + 1), 0, compressed);
  if (prefixes[pr2].items)
    checkAddr(pr2, h2, key, -(i + 2), 0, compressed);
  if (prefixes[pr3].items)
    checkAddr(pr3, h3, key, -(i + 3), 0, compressed);

  // Endomorphism #1
  // if (x, y) = k * G, then (beta*x, y) = lambda*k*G
  pte1[0].y.ModNeg();
  pte1[1].y.ModNeg();
  pte1[2].y.ModNeg();
  pte1[3].y.ModNeg();


  secp->GetHash160(searchType, compressed, pte1[0], pte1[1], pte1[2], pte1[3], h0, h1, h2, h3);

  pr0 = *(prefix_t *)h0;
  pr1 = *(prefix_t *)h1;
  pr2 = *(prefix_t *)h2;
  pr3 = *(prefix_t *)h3;

  if (prefixes[pr0].items)
    checkAddr(pr0, h0, key, -i, 1, compressed);
  if (prefixes[pr1].items)
    checkAddr(pr1, h1, key, -(i + 1), 1, compressed);
  if (prefixes[pr2].items)
    checkAddr(pr2, h2, key, -(i + 2), 1, compressed);
  if (prefixes[pr3].items)
    checkAddr(pr3, h3, key, -(i + 3), 1, compressed);

  // Endomorphism #2
  // if (x, y) = k * G, then (beta2*x, y) = lambda2*k*G
  pte2[0].y.ModNeg();
  pte2[1].y.ModNeg();
  pte2[2].y.ModNeg();
  pte2[3].y.ModNeg();

  secp->GetHash160(searchType, compressed, pte2[0], pte2[1], pte2[2], pte2[3], h0, h1, h2, h3);

  pr0 = *(prefix_t *)h0;
  pr1 = *(prefix_t *)h1;
  pr2 = *(prefix_t *)h2;
  pr3 = *(prefix_t *)h3;

  if (prefixes[pr0].items)
    checkAddr(pr0, h0, key, -i, 2, compressed);
  if (prefixes[pr1].items)
    checkAddr(pr1, h1, key, -(i + 1), 2, compressed);
  if (prefixes[pr2].items)
    checkAddr(pr2, h2, key, -(i + 2), 2, compressed);
  if (prefixes[pr3].items)
    checkAddr(pr3, h3, key, -(i + 3), 2, compressed);

}

// ----------------------------------------------------------------------------
void VanitySearch::getCPUStartingKey(int thId,Int& key,Point& startP) {

  if (rekey > 0) {
    key.Rand(256);
  } else {
    key.Set(&startKey);
    Int off((int64_t)thId);
    off.ShiftL(64);
    key.Add(&off);
  }
  Int km(&key);
  
  km.Add((uint64_t)CPU_GRP_SIZE / 2);
  startP = secp->ComputePublicKey(&km);
  
  if(startPubKeySpecified)
   startP = secp->AddDirect(startP,startPubKey);

}

void VanitySearch::FindKeyCPU(TH_PARAM *ph) {

  // Global init
  int thId = ph->threadId;
  counters[thId] = 0;

  // CPU Thread
  IntGroup *grp = new IntGroup(CPU_GRP_SIZE/2+1);

  // Group Init
  Int  key;
  Point startP;
  getCPUStartingKey(thId,key,startP);

  Int dx[CPU_GRP_SIZE/2+1];
  Point pts[CPU_GRP_SIZE];

  Int dy;
  Int dyn;
  Int _s;
  Int _p;
  Point pp;
  Point pn;
  grp->Set(dx);

  ph->hasStarted = true;
  ph->rekeyRequest = false;

  while (!endOfSearch) {

    if (ph->rekeyRequest) {
      getCPUStartingKey(thId, key, startP);
      ph->rekeyRequest = false;
    }

    // Fill group
    int i;
    int hLength = (CPU_GRP_SIZE / 2 - 1);

    for (i = 0; i < hLength; i++) {
      dx[i].ModSub(&Gn[i].x, &startP.x);
    }
    dx[i].ModSub(&Gn[i].x, &startP.x);  // For the first point
    dx[i+1].ModSub(&_2Gn.x, &startP.x); // For the next center point

    // Grouped ModInv
    grp->ModInv();

    // We use the fact that P + i*G and P - i*G has the same deltax, so the same inverse
    // We compute key in the positive and negative way from the center of the group

    // center point
    pts[CPU_GRP_SIZE/2] = startP;

    for (i = 0; i
      pp = startP;
      pn = startP;

      // P = startP + i*G
      dy.ModSub(&Gn[i].y,&pp.y);

      _s.ModMulK1(&dy, &dx[i]);       // s = (p2.y-p1.y)*inverse(p2.x-p1.x);
      _p.ModSquareK1(&_s);            // _p = pow2(s)

      pp.x.ModNeg();
      pp.x.ModAdd(&_p);
      pp.x.ModSub(&Gn[i].x);           // rx = pow2(s) - p1.x - p2.x;

      pp.y.ModSub(&Gn[i].x, &pp.x);
      pp.y.ModMulK1(&_s);
      pp.y.ModSub(&Gn[i].y);           // ry = - p2.y - s*(ret.x-p2.x);  

      // P = startP - i*G  , if (x,y) = i*G then (x,-y) = -i*G
      dyn.Set(&Gn[i].y);
      dyn.ModNeg();
      dyn.ModSub(&pn.y);

      _s.ModMulK1(&dyn, &dx[i]);      // s = (p2.y-p1.y)*inverse(p2.x-p1.x);
      _p.ModSquareK1(&_s);            // _p = pow2(s)

      pn.x.ModNeg();
      pn.x.ModAdd(&_p);
      pn.x.ModSub(&Gn[i].x);          // rx = pow2(s) - p1.x - p2.x;

      pn.y.ModSub(&Gn[i].x, &pn.x);
      pn.y.ModMulK1(&_s);
      pn.y.ModAdd(&Gn[i].y);          // ry = - p2.y - s*(ret.x-p2.x);  

      pts[CPU_GRP_SIZE/2 + (i+1)] = pp;
      pts[CPU_GRP_SIZE/2 - (i+1)] = pn;

    }

    // First point (startP - (GRP_SZIE/2)*G)
    pn = startP;
    dyn.Set(&Gn[i].y);
    dyn.ModNeg();
    dyn.ModSub(&pn.y);

    _s.ModMulK1(&dyn, &dx[i]);
    _p.ModSquareK1(&_s);

    pn.x.ModNeg();
    pn.x.ModAdd(&_p);
    pn.x.ModSub(&Gn[i].x);

    pn.y.ModSub(&Gn[i].x, &pn.x);
    pn.y.ModMulK1(&_s);
    pn.y.ModAdd(&Gn[i].y);

    pts[0] = pn;

    // Next start point (startP + GRP_SIZE*G)
    pp = startP;
    dy.ModSub(&_2Gn.y, &pp.y);

    _s.ModMulK1(&dy, &dx[i+1]);
    _p.ModSquareK1(&_s);

    pp.x.ModNeg();
    pp.x.ModAdd(&_p);
    pp.x.ModSub(&_2Gn.x);

    pp.y.ModSub(&_2Gn.x, &pp.x);
    pp.y.ModMulK1(&_s);
    pp.y.ModSub(&_2Gn.y);
    startP = pp;

#if 0
    // Check
    {
      bool wrong = false;
      Point p0 = secp.ComputePublicKey(&key);
      for (int i = 0; i < CPU_GRP_SIZE; i++) {
        if (!p0.equals(pts[i])) {
          wrong = true;
          printf("[%d] wrong point\n",i);
        }
        p0 = secp.NextKey(p0);
      }
      if(wrong) exit(0);
    }
#endif

    // Check addresses
    if (useSSE) {

      for (int i = 0; i < CPU_GRP_SIZE && !endOfSearch; i += 4) {

        switch (searchMode) {
          case SEARCH_COMPRESSED:
            checkAddressesSSE(true, key, i, pts[i], pts[i + 1], pts[i + 2], pts[i + 3]);
            break;
          case SEARCH_UNCOMPRESSED:
            checkAddressesSSE(false, key, i, pts[i], pts[i + 1], pts[i + 2], pts[i + 3]);
            break;
          case SEARCH_BOTH:
            checkAddressesSSE(true, key, i, pts[i], pts[i + 1], pts[i + 2], pts[i + 3]);
            checkAddressesSSE(false, key, i, pts[i], pts[i + 1], pts[i + 2], pts[i + 3]);
            break;
        }

      }

    } else {

      for (int i = 0; i < CPU_GRP_SIZE && !endOfSearch; i ++) {

        switch (searchMode) {
        case SEARCH_COMPRESSED:
          checkAddresses(true, key, i, pts[i]);
          break;
        case SEARCH_UNCOMPRESSED:
          checkAddresses(false, key, i, pts[i]);
          break;
        case SEARCH_BOTH:
          checkAddresses(true, key, i, pts[i]);
          checkAddresses(false, key, i, pts[i]);
          break;
        }

      }

    }

    key.Add((uint64_t)CPU_GRP_SIZE);
    counters[thId]+= 6*CPU_GRP_SIZE; // Point + endo #1 + endo #2 + Symetric point + endo #1 + endo #2

  }

  ph->isRunning = false;

}

// ----------------------------------------------------------------------------

void VanitySearch::getGPUStartingKeys(int thId, int groupSize, int nbThread, Int *keys, Point *p) {

  for (int i = 0; i < nbThread; i++) {
    if (rekey > 0) {
      keys[i].Rand(64);
    } else {
      keys[i].Set(&startKey);
      Int offT((uint64_t)i);
      offT.ShiftL(80);
      Int offG((uint64_t)thId);
      offG.ShiftL(112);
      keys[i].Add(&offT);
      keys[i].Add(&offG);
    }
    Int k(keys + i);
    // Starting key is at the middle of the group
    k.Add((uint64_t)(groupSize / 2));
    p[i] = secp->ComputePublicKey(&k);
    if (startPubKeySpecified)
      p[i] = secp->AddDirect(p[i], startPubKey);
  }

}

void VanitySearch::FindKeyGPU(TH_PARAM *ph) {

  bool ok = true;

#ifdef WITHGPU

  // Global init
  int thId = ph->threadId;
  GPUEngine g(ph->gridSize, ph->gpuId, maxFound, (rekey!=0));
  int nbThread = g.GetNbThread();
  Point *p = new Point[nbThread];
  Int *keys = new Int[nbThread];
  vector found;

  printf("GPU: %s\n",g.deviceName.c_str());

  counters[thId] = 0;

  getGPUStartingKeys(thId, g.GetGroupSize(), nbThread, keys, p);

  g.SetSearchMode(searchMode);
  g.SetSearchType(searchType);
  if (onlyFull) {
    g.SetPrefix(usedPrefixL,nbPrefix);
  } else {
    g.SetPrefix(usedPrefix);
  }

  getGPUStartingKeys(thId, g.GetGroupSize(), nbThread, keys, p);
  ok = g.SetKeys(p);
  ph->rekeyRequest = false;

  ph->hasStarted = true;

  // GPU Thread
  while (ok && !endOfSearch) {

    if (ph->rekeyRequest) {
      getGPUStartingKeys(thId, g.GetGroupSize(), nbThread, keys, p);
      ok = g.SetKeys(p);
      ph->rekeyRequest = false;
    }

    // Call kernel
    ok = g.Launch(found);

    for(int i=0;i<(int)found.size() && !endOfSearch;i++) {

      ITEM it = found[i];
      checkAddr(*(prefix_t *)(it.hash), it.hash, keys[it.thId], it.incr, it.endo, it.mode);
 
    }

    if (ok) {
      for (int i = 0; i < nbThread; i++) {
        keys[i].Add((uint64_t)STEP_SIZE);
      }
      counters[thId] += 6 * STEP_SIZE * nbThread; // Point +  endo1 + endo2 + symetrics
    }

  }

  delete[] keys;
  delete[] p;

#else
  ph->hasStarted = true;
  printf("GPU code not compiled, use -DWITHGPU when compiling.\n");
#endif

  ph->isRunning = false;

}

// ----------------------------------------------------------------------------

bool VanitySearch::isAlive(TH_PARAM *p) {

  bool isAlive = true;
  int total = nbCPUThread + nbGPUThread;
  for(int i=0;i    isAlive = isAlive && p[i].isRunning;

  return isAlive;

}

// ----------------------------------------------------------------------------

bool VanitySearch::hasStarted(TH_PARAM *p) {

  bool hasStarted = true;
  int total = nbCPUThread + nbGPUThread;
  for (int i = 0; i < total; i++)
    hasStarted = hasStarted && p[i].hasStarted;

  return hasStarted;

}

// ----------------------------------------------------------------------------

void VanitySearch::rekeyRequest(TH_PARAM *p) {

  bool hasStarted = true;
  int total = nbCPUThread + nbGPUThread;
  for (int i = 0; i < total; i++)
  p[i].rekeyRequest = true;

}

// ----------------------------------------------------------------------------

uint64_t VanitySearch::getGPUCount() {

  uint64_t count = 0;
  for(int i=0;i    count += counters[0x80L+i];
  return count;

}

uint64_t VanitySearch::getCPUCount() {

  uint64_t count = 0;
  for(int i=0;i    count += counters[i];
  return count;

}

// ----------------------------------------------------------------------------

void VanitySearch::Search(int nbThread,std::vector gpuId,std::vector gridSize) {

  double t0;
  double t1;
  endOfSearch = false;
  nbCPUThread = nbThread;
  nbGPUThread = (useGpu?(int)gpuId.size():0);
  nbFoundKey = 0;

  memset(counters,0,sizeof(counters));

  printf("Number of CPU thread: %d\n", nbCPUThread);

  TH_PARAM *params = (TH_PARAM *)malloc((nbCPUThread + nbGPUThread) * sizeof(TH_PARAM));
  memset(params,0,(nbCPUThread + nbGPUThread) * sizeof(TH_PARAM));

  // Launch CPU threads
  for (int i = 0; i < nbCPUThread; i++) {
    params[i].obj = this;
    params[i].threadId = i;
    params[i].isRunning = true;

#ifdef WIN64
    DWORD thread_id;
    CreateThread(NULL, 0, _FindKey, (void*)(params+i), 0, &thread_id);
    ghMutex = CreateMutex(NULL, FALSE, NULL);
#else
    pthread_t thread_id;
    pthread_create(&thread_id, NULL, &_FindKey, (void*)(params+i));  
    ghMutex = PTHREAD_MUTEX_INITIALIZER;
#endif
  }

  // Launch GPU threads
  for (int i = 0; i < nbGPUThread; i++) {
    params[nbCPUThread+i].obj = this;
    params[nbCPUThread+i].threadId = 0x80L+i;
    params[nbCPUThread+i].isRunning = true;
    params[nbCPUThread+i].gpuId = gpuId[i];
    params[nbCPUThread+i].gridSize = gridSize[i];
#ifdef WIN64
    DWORD thread_id;
    CreateThread(NULL, 0, _FindKeyGPU, (void*)(params+(nbCPUThread+i)), 0, &thread_id);
#else
    pthread_t thread_id;
    pthread_create(&thread_id, NULL, &_FindKeyGPU, (void*)(params+(nbCPUThread+i)));  
#endif
  }

#ifndef WIN64
  setvbuf(stdout, NULL, _IONBF, 0);
#endif

  uint64_t lastCount = 0;
  uint64_t gpuCount = 0;
  uint64_t lastGPUCount = 0;

  // Key rate smoothing filter
  #define FILTER_SIZE 8
  double lastkeyRate[FILTER_SIZE];
  double lastGpukeyRate[FILTER_SIZE];
  uint32_t filterPos = 0;

  double keyRate = 0.0;
  double gpuKeyRate = 0.0;

  memset(lastkeyRate,0,sizeof(lastkeyRate));
  memset(lastGpukeyRate,0,sizeof(lastkeyRate));

  // Wait that all threads have started
  while (!hasStarted(params)) {
    Timer::SleepMillis(500);
  }

  t0 = Timer::get_tick();
  startTime = t0;

  while (isAlive(params)) {

    int delay = 2000;
    while (isAlive(params) && delay>0) {
      Timer::SleepMillis(500);
      delay -= 500;
    }

    gpuCount = getGPUCount();
    uint64_t count = getCPUCount() + gpuCount;

    t1 = Timer::get_tick();
    keyRate = (double)(count - lastCount) / (t1 - t0);
    gpuKeyRate = (double)(gpuCount - lastGPUCount) / (t1 - t0);
    lastkeyRate[filterPos%FILTER_SIZE] = keyRate;
    lastGpukeyRate[filterPos%FILTER_SIZE] = gpuKeyRate;
    filterPos++;

    // KeyRate smoothing
    double avgKeyRate = 0.0;
    double avgGpuKeyRate = 0.0;
    uint32_t nbSample;
    for (nbSample = 0; (nbSample < FILTER_SIZE) && (nbSample < filterPos); nbSample++) {
      avgKeyRate += lastkeyRate[nbSample];
      avgGpuKeyRate += lastGpukeyRate[nbSample];
    }
    avgKeyRate /= (double)(nbSample);
    avgGpuKeyRate /= (double)(nbSample);

    if (isAlive(params)) {
      printf("%.3f MK/s (GPU %.3f MK/s) (2^%.2f) %s[%d]  \r",
        avgKeyRate / 1000000.0, avgGpuKeyRate / 1000000.0,
          log2((double)count), GetExpectedTime(avgKeyRate, (double)count).c_str(),nbFoundKey);
    }

    if (rekey > 0) {
      if ((count - lastRekey) > (1000000 * rekey)) {
        // Rekey request
        rekeyRequest(params);
        lastRekey = count;
      }
    }

    lastCount = count;
    lastGPUCount = gpuCount;
    t0 = t1;

  }

  free(params);

}

// ----------------------------------------------------------------------------

string VanitySearch::GetHex(vector &buffer) {

  string ret;

  char tmp[128];
  for (int i = 0; i < (int)buffer.size(); i++) {
    sprintf(tmp,"%02X",buffer[i]);
    ret.append(tmp);
  }

  return ret;

}


c++ coders please help me how to modify this to work on 64 bit rand not 256 bit rand. c++ really hard to me to understand
full member
Activity: 1162
Merit: 237
Shooters Shoot...
hi i want to generate 64 bit not full 256 now i change "keys.Rand(256);" to "keys.Rand(64);" on VanitySearch::getGPUStartingKeys but only some keys are  64 bit what i am missing i am new on c++
most of keys found will be outside of 64 bit due to the endo and symm. Basically the program takes in inputted key, say 64 bit, but then checks it and 5 other keys related to that 64 bit key. So you would have to comment out those sections if you want all keys in the 64 bit range.
newbie
Activity: 15
Merit: 0
hi i want to generate 64 bit not full 256 now i change "keys.Rand(256);" to "keys.Rand(64);" on VanitySearch::getGPUStartingKeys but only some keys are  64 bit what i am missing i am new on c++
Pages:
Jump to: