diff --git a/README.md b/README.md
index abd8463..c51062c 100644
--- a/README.md
+++ b/README.md
@@ -72,6 +72,7 @@ Similar test for compressed WIF (target _Kzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
For other of examples please see the file /docs/examples.txt.
+Program supports legacy addresses (1...), native Segwit/bench32 P2WPKH (bc1...) and P2WPKH-P2SH addresses (3...).
Build
-----
diff --git a/WifSolverCuda/Makefile b/WifSolverCuda/Makefile
index bea181d..e1c1c7d 100644
--- a/WifSolverCuda/Makefile
+++ b/WifSolverCuda/Makefile
@@ -21,6 +21,7 @@ all:
$(CXX) $(CXXFLAGS) -o $(OBJDIR)/sha256_sse.o -c lib/hash/sha256_sse.cpp
gcc -O3 -c lib/base58.c -o $(OBJDIR)/base58.o
$(CXX) -O3 -c lib/util.cpp -o $(OBJDIR)/util.o
+ $(CXX) -O3 -c lib/Bech32.cpp -o $(OBJDIR)/Bech32.o
$(CXX) $(CXXFLAGS) -c lib/Int.cpp -o $(OBJDIR)/Int.o
$(CXX) $(CXXFLAGS) -c lib/Point.cpp -o $(OBJDIR)/Point.o
$(CXX) $(CXXFLAGS) -c lib/SECP256K1.cpp -o $(OBJDIR)/SECP256K1.o
@@ -32,7 +33,7 @@ all:
$(NVCC) --ptxas-options=-v -maxrregcount=0 --compile --compiler-options -fPIC -ccbin $(CXXCUDA) -m64 -O2 -I$(CUDA)/include -gencode=arch=compute_$(COMPUTE_CAP),code=sm_$(COMPUTE_CAP) -o $(OBJDIR)/main.o -c main.cu
@echo Making WifSolver...
- $(CXX) $(OBJDIR)/ripemd160.o $(OBJDIR)/ripemd160_sse.o $(OBJDIR)/sha256cpp.o $(OBJDIR)/sha256_sse.o $(OBJDIR)/base58.o $(OBJDIR)/util.o $(OBJDIR)/Int.o $(OBJDIR)/Point.o $(OBJDIR)/SECP256K1.o $(OBJDIR)/IntGroup.o $(OBJDIR)/IntMod.o $(OBJDIR)/sha256.o $(OBJDIR)/Worker1.o $(OBJDIR)/main.o $(LFLAGS) -o wifSolver
+ $(CXX) $(OBJDIR)/ripemd160.o $(OBJDIR)/ripemd160_sse.o $(OBJDIR)/sha256cpp.o $(OBJDIR)/sha256_sse.o $(OBJDIR)/base58.o $(OBJDIR)/util.o $(OBJDIR)/Bech32.o $(OBJDIR)/Int.o $(OBJDIR)/Point.o $(OBJDIR)/SECP256K1.o $(OBJDIR)/IntGroup.o $(OBJDIR)/IntMod.o $(OBJDIR)/sha256.o $(OBJDIR)/Worker1.o $(OBJDIR)/main.o $(LFLAGS) -o wifSolver
clean:
@echo Cleaning...
diff --git a/WifSolverCuda/WifSolverCuda.vcxproj b/WifSolverCuda/WifSolverCuda.vcxproj
index 88d534f..44bab91 100644
--- a/WifSolverCuda/WifSolverCuda.vcxproj
+++ b/WifSolverCuda/WifSolverCuda.vcxproj
@@ -85,6 +85,7 @@
+
@@ -97,6 +98,7 @@
+
diff --git a/WifSolverCuda/WifSolverCuda.vcxproj.filters b/WifSolverCuda/WifSolverCuda.vcxproj.filters
index 9b57eea..7189558 100644
--- a/WifSolverCuda/WifSolverCuda.vcxproj.filters
+++ b/WifSolverCuda/WifSolverCuda.vcxproj.filters
@@ -24,6 +24,7 @@
+
@@ -37,5 +38,6 @@
+
\ No newline at end of file
diff --git a/WifSolverCuda/lib/Bech32.cpp b/WifSolverCuda/lib/Bech32.cpp
new file mode 100644
index 0000000..4ff5102
--- /dev/null
+++ b/WifSolverCuda/lib/Bech32.cpp
@@ -0,0 +1,227 @@
+/* Copyright (c) 2017 Pieter Wuille
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include
+#include
+#include
+#include
+
+#include "Bech32.h"
+
+uint32_t bech32_polymod_step(uint32_t pre) {
+ uint8_t b = pre >> 25;
+ return ((pre & 0x1FFFFFF) << 5) ^
+ (-((b >> 0) & 1) & 0x3b6a57b2UL) ^
+ (-((b >> 1) & 1) & 0x26508e6dUL) ^
+ (-((b >> 2) & 1) & 0x1ea119faUL) ^
+ (-((b >> 3) & 1) & 0x3d4233ddUL) ^
+ (-((b >> 4) & 1) & 0x2a1462b3UL);
+}
+
+static const char* charset = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
+
+static const int8_t charset_rev[128] = {
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 15, -1, 10, 17, 21, 20, 26, 30, 7, 5, -1, -1, -1, -1, -1, -1,
+ -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1,
+ 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1,
+ -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1,
+ 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1
+};
+
+int bech32_encode(char *output, const char *hrp, const uint8_t *data, size_t data_len) {
+ uint32_t chk = 1;
+ size_t i = 0;
+ while (hrp[i] != 0) {
+ int ch = hrp[i];
+ if (ch < 33 || ch > 126) {
+ return 0;
+ }
+
+ if (ch >= 'A' && ch <= 'Z') return 0;
+ chk = bech32_polymod_step(chk) ^ (ch >> 5);
+ ++i;
+ }
+ if (i + 7 + data_len > 90) return 0;
+ chk = bech32_polymod_step(chk);
+ while (*hrp != 0) {
+ chk = bech32_polymod_step(chk) ^ (*hrp & 0x1f);
+ *(output++) = *(hrp++);
+ }
+ *(output++) = '1';
+ for (i = 0; i < data_len; ++i) {
+ if (*data >> 5) return 0;
+ chk = bech32_polymod_step(chk) ^ (*data);
+ *(output++) = charset[*(data++)];
+ }
+ for (i = 0; i < 6; ++i) {
+ chk = bech32_polymod_step(chk);
+ }
+ chk ^= 1;
+ for (i = 0; i < 6; ++i) {
+ *(output++) = charset[(chk >> ((5 - i) * 5)) & 0x1f];
+ }
+ *output = 0;
+ return 1;
+}
+
+int bech32_decode_nocheck(uint8_t *data, size_t *data_len, const char *input) {
+
+ uint8_t acc=0;
+ uint8_t acc_len=8;
+ size_t out_len=0;
+
+ size_t input_len = strlen(input);
+ for (int i = 0; i < input_len; i++) {
+
+ if(input[i]&0x80)
+ return false;
+
+ int8_t c = charset_rev[tolower(input[i])];
+ if(c<0)
+ return false;
+
+ if (acc_len >= 5) {
+ acc |= c << (acc_len - 5);
+ acc_len -= 5;
+ } else {
+ int shift = 5 - acc_len;
+ data[out_len++] = acc | (c >> shift);
+ acc_len = 8-shift;
+ acc = c << acc_len;
+ }
+
+ }
+
+ data[out_len++] = acc;
+ *data_len = out_len;
+
+ return true;
+
+}
+
+int bech32_decode(char* hrp, uint8_t *data, size_t *data_len, const char *input) {
+ uint32_t chk = 1;
+ size_t i;
+ size_t input_len = strlen(input);
+ size_t hrp_len;
+ int have_lower = 0, have_upper = 0;
+ if (input_len < 8 || input_len > 90) {
+ return 0;
+ }
+ *data_len = 0;
+ while (*data_len < input_len && input[(input_len - 1) - *data_len] != '1') {
+ ++(*data_len);
+ }
+ hrp_len = input_len - (1 + *data_len);
+ if (1 + *data_len >= input_len || *data_len < 6) {
+ return 0;
+ }
+ *(data_len) -= 6;
+ for (i = 0; i < hrp_len; ++i) {
+ int ch = input[i];
+ if (ch < 33 || ch > 126) {
+ return 0;
+ }
+ if (ch >= 'a' && ch <= 'z') {
+ have_lower = 1;
+ } else if (ch >= 'A' && ch <= 'Z') {
+ have_upper = 1;
+ ch = (ch - 'A') + 'a';
+ }
+ hrp[i] = ch;
+ chk = bech32_polymod_step(chk) ^ (ch >> 5);
+ }
+ hrp[i] = 0;
+ chk = bech32_polymod_step(chk);
+ for (i = 0; i < hrp_len; ++i) {
+ chk = bech32_polymod_step(chk) ^ (input[i] & 0x1f);
+ }
+ ++i;
+ while (i < input_len) {
+ int v = (input[i] & 0x80) ? -1 : charset_rev[(int)input[i]];
+ if (input[i] >= 'a' && input[i] <= 'z') have_lower = 1;
+ if (input[i] >= 'A' && input[i] <= 'Z') have_upper = 1;
+ if (v == -1) {
+ return 0;
+ }
+ chk = bech32_polymod_step(chk) ^ v;
+ if (i + 6 < input_len) {
+ data[i - (1 + hrp_len)] = v;
+ }
+ ++i;
+ }
+ if (have_lower && have_upper) {
+ return 0;
+ }
+ return chk == 1;
+}
+
+static int convert_bits(uint8_t* out, size_t* outlen, int outbits, const uint8_t* in, size_t inlen, int inbits, int pad) {
+ uint32_t val = 0;
+ int bits = 0;
+ uint32_t maxv = (((uint32_t)1) << outbits) - 1;
+ while (inlen--) {
+ val = (val << inbits) | *(in++);
+ bits += inbits;
+ while (bits >= outbits) {
+ bits -= outbits;
+ out[(*outlen)++] = (val >> bits) & maxv;
+ }
+ }
+ if (pad) {
+ if (bits) {
+ out[(*outlen)++] = (val << (outbits - bits)) & maxv;
+ }
+ } else if (((val << (outbits - bits)) & maxv) || bits >= inbits) {
+ return 0;
+ }
+ return 1;
+}
+
+int segwit_addr_encode(char *output, const char *hrp, int witver, const uint8_t *witprog, size_t witprog_len) {
+ uint8_t data[65];
+ size_t datalen = 0;
+ if (witver > 16) return 0;
+ if (witver == 0 && witprog_len != 20 && witprog_len != 32) return 0;
+ if (witprog_len < 2 || witprog_len > 40) return 0;
+ data[0] = witver;
+ convert_bits(data + 1, &datalen, 5, witprog, witprog_len, 8, 1);
+ ++datalen;
+ return bech32_encode(output, hrp, data, datalen);
+}
+
+int segwit_addr_decode(int* witver, uint8_t* witdata, size_t* witdata_len, const char* hrp, const char* addr) {
+ uint8_t data[84];
+ char hrp_actual[84];
+ size_t data_len;
+ if (!bech32_decode(hrp_actual, data, &data_len, addr)) return 0;
+ if (data_len == 0 || data_len > 65) return 0;
+ if (strncmp(hrp, hrp_actual, 84) != 0) return 0;
+ if (data[0] > 16) return 0;
+ *witdata_len = 0;
+ if (!convert_bits(witdata, witdata_len, 8, data + 1, data_len - 1, 5, 0)) return 0;
+ if (*witdata_len < 2 || *witdata_len > 40) return 0;
+ if (data[0] == 0 && *witdata_len != 20 && *witdata_len != 32) return 0;
+ *witver = data[0];
+ return 1;
+}
diff --git a/WifSolverCuda/lib/Bech32.h b/WifSolverCuda/lib/Bech32.h
new file mode 100644
index 0000000..03800ee
--- /dev/null
+++ b/WifSolverCuda/lib/Bech32.h
@@ -0,0 +1,103 @@
+/* Copyright (c) 2017 Pieter Wuille
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef _SEGWIT_ADDR_H_
+#define _SEGWIT_ADDR_H_ 1
+
+#include
+
+ /** Encode a SegWit address
+ *
+ * Out: output: Pointer to a buffer of size 73 + strlen(hrp) that will be
+ * updated to contain the null-terminated address.
+ * In: hrp: Pointer to the null-terminated human readable part to use
+ * (chain/network specific).
+ * ver: Version of the witness program (between 0 and 16 inclusive).
+ * prog: Data bytes for the witness program (between 2 and 40 bytes).
+ * prog_len: Number of data bytes in prog.
+ * Returns 1 if successful.
+ */
+int segwit_addr_encode(
+ char *output,
+ const char *hrp,
+ int ver,
+ const uint8_t *prog,
+ size_t prog_len
+);
+
+/** Decode a SegWit address
+ *
+ * Out: ver: Pointer to an int that will be updated to contain the witness
+ * program version (between 0 and 16 inclusive).
+ * prog: Pointer to a buffer of size 40 that will be updated to
+ * contain the witness program bytes.
+ * prog_len: Pointer to a size_t that will be updated to contain the length
+ * of bytes in prog.
+ * hrp: Pointer to the null-terminated human readable part that is
+ * expected (chain/network specific).
+ * addr: Pointer to the null-terminated address.
+ * Returns 1 if successful.
+ */
+int segwit_addr_decode(
+ int* ver,
+ uint8_t* prog,
+ size_t* prog_len,
+ const char* hrp,
+ const char* addr
+);
+
+/** Encode a Bech32 string
+ *
+ * Out: output: Pointer to a buffer of size strlen(hrp) + data_len + 8 that
+ * will be updated to contain the null-terminated Bech32 string.
+ * In: hrp : Pointer to the null-terminated human readable part.
+ * data : Pointer to an array of 5-bit values.
+ * data_len: Length of the data array.
+ * Returns 1 if successful.
+ */
+int bech32_encode(
+ char *output,
+ const char *hrp,
+ const uint8_t *data,
+ size_t data_len
+);
+
+/** Decode a Bech32 string
+ *
+ * Out: hrp: Pointer to a buffer of size strlen(input) - 6. Will be
+ * updated to contain the null-terminated human readable part.
+ * data: Pointer to a buffer of size strlen(input) - 8 that will
+ * hold the encoded 5-bit data values.
+ * data_len: Pointer to a size_t that will be updated to be the number
+ * of entries in data.
+ * In: input: Pointer to a null-terminated Bech32 string.
+ * Returns 1 if succesful.
+ */
+int bech32_decode(
+ char *hrp,
+ uint8_t *data,
+ size_t *data_len,
+ const char *input
+);
+
+int bech32_decode_nocheck(uint8_t *data, size_t *data_len, const char *input);
+
+#endif
diff --git a/WifSolverCuda/main.cu b/WifSolverCuda/main.cu
index cee299b..2c6fde1 100644
--- a/WifSolverCuda/main.cu
+++ b/WifSolverCuda/main.cu
@@ -13,6 +13,7 @@
#include "lib/Int.h"
#include "lib/Math.cuh"
#include "lib/util.h"
+#include "lib/Bech32.h"
#include "Worker.cuh"
#include "lib/SECP256k1.h"
@@ -70,6 +71,7 @@ bool isRestore = false;
bool showDevices = false;
bool p2sh = false;
+bool bech32 = false;
bool isVerbose = false;
@@ -78,7 +80,7 @@ Secp256K1* secp;
int main(int argc, char** argv)
{
- printf("WifSolver 0.5.2\n\n");
+ printf("WifSolver 0.5.3\n\n");
printf("Use parameter '-h' for help and list of available parameters\n\n");
if (argc <=1 || readArgs(argc, argv)) {
@@ -564,20 +566,31 @@ void printSpeed(double speed) {
void processCandidate(Int &toTest) {
FILE* keys;
- char rmdhash[21], address[50], wif[53];
+ char rmdhash[21], address[128], wif[53];
+
unsigned char* buff = new unsigned char[dataLen];
for (int i = 0, d=dataLen-1; i < dataLen; i++, d--) {
buff[i] = toTest.GetByte(d);
}
toTest.SetBase16((char*)toTest.GetBase16().substr(2, 64).c_str());
- Point publickey = secp->ComputePublicKey(&toTest);
- if (p2sh) {
- secp->GetHash160(P2SH, true, publickey, (unsigned char*)rmdhash);
+ Point publickey = secp->ComputePublicKey(&toTest);
+ if (bech32){
+ char output[128];
+ uint8_t h160[20];
+ secp->GetHash160(BECH32, true, publickey, h160);
+ segwit_addr_encode(output, "bc", 0, h160, 20);
+ string addressBech32 = std::string(output);
+ strcpy(address, addressBech32.c_str());
}
else {
- secp->GetHash160(P2PKH, COMPRESSED, publickey, (unsigned char*)rmdhash);
- }
- addressToBase58(rmdhash, address, p2sh);
+ if (p2sh) {
+ secp->GetHash160(P2SH, true, publickey, (unsigned char*)rmdhash);
+ }
+ else {
+ secp->GetHash160(P2PKH, COMPRESSED, publickey, (unsigned char*)rmdhash);
+ }
+ addressToBase58(rmdhash, address, p2sh);
+ }
if (!TARGET_ADDRESS.empty()) {
if (TARGET_ADDRESS == address) {
RESULT = true;
@@ -818,6 +831,10 @@ bool readArgs(int argc, char** argv) {
if (argv[a][0] == '3') {
p2sh = true;
COMPRESSED = true;
+ }else
+ if (argv[a][0] == 'b') {
+ bech32 = true;
+ COMPRESSED = true;
}
}
else if (strcmp(argv[a], "-checksum") == 0) {
diff --git a/docs/examples.txt b/docs/examples.txt
index c91befa..80f0142 100644
--- a/docs/examples.txt
+++ b/docs/examples.txt
@@ -43,3 +43,20 @@ L5K111111KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJsczi8wg
80 f16ba6edac7d556f83fd0b3493826eb06069439fe836b001ddcaaa326d92d785 01 4d463f37
-c -rangeStart 80f16ba6edac7d556f83fd0b3493826eb06069439fe836b001ddcaaa326d92d785014d463f37 -stride edbafda67ca37188cf28263571f03b9716879e4acc9c514ab67280000000000 -checksum 4d463f37 -a 1M9JqAMbCBwtvNLedwNG4TjiPsxATJrvxq
+
+===============================================================================
+bc1qkqjj2ack2psdn0nqm4ea2xzug4hdmq3gc9cjt6
+35qaE5aJERKLGzFYwFUCovtQV8b9GVAuvH
+Kwyw8dQGwjZtguw5vGexmFqPK66uoSPukcEd4DJJLLkJbb4Nwjc6 4e6903fb
+80 16c00715c6976cb6d1d87d2514942724b7595d2d5a997f9e42046e391d973f68 01 4e6903fb
+===============================================================================
+Kwyw8dQGwjZtguw5vGexmFqPK66uoSPukcE_____LLkJbb4Nwjc6
+ ^ 58^12 = 4e900abb53e6b71000
+Kwyw8dQGwjZtguw5vGexmFqPK66uoSPukcE11111LLkJbb4Nwjc6
+8016c00715c6976cb6d1d87d2514942724b7595d2d5a997f9e3a8dcaf5461c4a2118f8aed3fb
+Kwyw8dQGwjZtguw5vGexmFqPK66uoSPukcEzzzzzLLkJbb4Nwjc6
+8016c00715c6976cb6d1d87d2514942724b7595d2d5a997f9e468f507dba430bac941ab1c3fb
+
+-c -rangeStart 8016c00715c6976cb6d1d87d2514942724b7595d2d5a997f9e3a8dcaf5461c4a2118f8aed3fb -stride 4e900abb53e6b71000 -rangeEnd 8016c00715c6976cb6d1d87d2514942724b7595d2d5a997f9e468f507dba430bac941ab1c3fb -a bc1qkqjj2ack2psdn0nqm4ea2xzug4hdmq3gc9cjt6
+
+-c -rangeStart 8016c00715c6976cb6d1d87d2514942724b7595d2d5a997f9e3a8dcaf5461c4a2118f8aed3fb -stride 4e900abb53e6b71000 -rangeEnd 8016c00715c6976cb6d1d87d2514942724b7595d2d5a997f9e468f507dba430bac941ab1c3fb -a 35qaE5aJERKLGzFYwFUCovtQV8b9GVAuvH