SHOW:
|
|
- or go back to the newest paste.
1 | ####################################Python Bitcoin KeyChain | |
2 | #This program takes an initial private key (seed) and and increment (customincr), and generates a list of keys (wallet). | |
3 | #Then it saves a .txt file holding the list of related keys. | |
4 | #No need for custom libraries, the eliptic equations are built in! | |
5 | #For good security, roll lots of d10 dice to sequence a key somewhere between 2^50 and 2^253. | |
6 | #Then pick an increment, the larger the better, but keep it below 2^150. | |
7 | #This program WILL generate any address, the limits are suggestions, and invalid keys should close program. | |
8 | #Keep those two numbers safe, they can be used to recreate the entire wallet! | |
9 | #Also, this is a ready to use application, to enable prompt for seeds, scroll down and uncomment blocks noted. | |
10 | ##### Lawsky Aug, '14 , some of this code is from other sources, and is free for all purposes. | |
11 | ||
12 | import hashlib, binascii # local imports required for conversions, they are standard with Python | |
13 | #import urllib2 #for blockchain query that is disabled | |
14 | #import json #for blockchain query that is disabled | |
15 | ||
16 | Pcurve = 2**256 - 2**32 - 2**9 - 2**8 - 2**7 - 2**6 - 2**4 -1 # The proven prime | |
17 | N=0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 # Number of points in the field | |
18 | Acurve = 0; Bcurve = 7 # These two defines the elliptic curve. y^2 = x^3 + Acurve * x + Bcurve | |
19 | Gx = 55066263022277343669578718895168534326250603453777594175500187360389116729240 #x coordinate of GPoint | |
20 | Gy = 32670510020758816978083085130507043184471273380659243275938904335757337482424 #y coordinate of GPoint | |
21 | GPoint = (Gx,Gy) # This is our generator point. Trillions of dif ones possible | |
22 | t='123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' # Base58 Charset | |
23 | ||
24 | def Byte2Hex(b): #Convert a byte string to hex number | |
25 | out=""; | |
26 | for x in b: | |
27 | y=hex(ord(x))[2:] | |
28 | if len(y)==1: | |
29 | y="0"+y | |
30 | out+="%2s"%y | |
31 | return out | |
32 | ||
33 | def Hex2Byte(hexStr): # convert hex number into a byte string | |
34 | bytes = [] | |
35 | hexStr = ''.join( hexStr.split(" ") ) | |
36 | for i in range(0, len(hexStr), 2): | |
37 | bytes.append( chr( int (hexStr[i:i+2], 16 ) ) ) | |
38 | return ''.join( bytes ) | |
39 | ||
40 | def Int2Byte(n,b): #Convert a integer to a byte string of length b | |
41 | out="" | |
42 | for i in range(b): | |
43 | (n,m)=divmod(n,256) | |
44 | out=chr(m)+out | |
45 | return out | |
46 | ||
47 | def modinv(a,n=Pcurve): #Extended Euclidean Algorithm/'division' in elliptic curves | |
48 | lm, hm = 1,0 | |
49 | low, high = a%n,n | |
50 | while low > 1: | |
51 | ratio = high/low | |
52 | nm, new = hm-lm*ratio, high-low*ratio | |
53 | lm, low, hm, high = nm, new, lm, low | |
54 | return lm % n | |
55 | ||
56 | def ECadd(a,b): # Not true addition, invented for EC. Could have been called anything. | |
57 | LamAdd = ((b[1]-a[1]) * modinv(b[0]-a[0],Pcurve)) % Pcurve | |
58 | x = (LamAdd*LamAdd-a[0]-b[0]) % Pcurve | |
59 | y = (LamAdd*(a[0]-x)-a[1]) % Pcurve | |
60 | return (x,y) | |
61 | ||
62 | def ECdouble(a): # This is called point doubling, also invented for EC. | |
63 | Lam = ((3*a[0]*a[0]+Acurve) * modinv((2*a[1]),Pcurve)) % Pcurve | |
64 | x = (Lam*Lam-2*a[0]) % Pcurve | |
65 | y = (Lam*(a[0]-x)-a[1]) % Pcurve | |
66 | return (x,y) | |
67 | ||
68 | def EccMultiply(GenPoint,ScalarHex): #Double & add. Not true multiplication | |
69 | if ScalarHex == 0 or ScalarHex >= N: raise Exception("Invalid Scalar/Private Key") | |
70 | ScalarBin = str(bin(ScalarHex))[2:] | |
71 | Q=GenPoint | |
72 | for i in range (1, len(ScalarBin)): # This is invented EC multiplication. | |
73 | Q=ECdouble(Q); # print "DUB", Q[0]; print | |
74 | if ScalarBin[i] == "1": | |
75 | Q=ECadd(Q,GenPoint); # print "ADD", Q[0]; print | |
76 | return (Q) | |
77 | ||
78 | def numtowif(numpriv): #converts numerical private key to WIF | |
79 | step1 = '80'+hex(numpriv)[2:].strip('L').zfill(64) | |
80 | step2 = hashlib.sha256(binascii.unhexlify(step1)).hexdigest() | |
81 | step3 = hashlib.sha256(binascii.unhexlify(step2)).hexdigest() | |
82 | step4 = int(step1 + step3[:8] , 16) | |
83 | return ''.join([t[step4/(58**l)%58] for l in range(100)])[::-1].lstrip('1') | |
84 | ||
85 | def wiftonum(wifpriv): #converts from WIF to numerical private key | |
86 | return sum([t.index(wifpriv[::-1][l])*(58**l) for l in range(len(wifpriv))])/(2**32)%(2**256) | |
87 | ||
88 | def validwif(wifpriv): #validates WIF generated by converting it back and forth | |
89 | return numtowif(wiftonum(wifpriv))==wifpriv | |
90 | ||
91 | def b58encode(v): #Encode a byte string to the Base58 | |
92 | base=len(t) | |
93 | val=0 | |
94 | for c in v: | |
95 | val*=256 | |
96 | val+=ord(c) | |
97 | result="" | |
98 | while val: | |
99 | (val,mod)=divmod(val,base) | |
100 | result=t[mod]+result | |
101 | pad=0 | |
102 | for c in v: | |
103 | if c=="\0": | |
104 | pad+=1 | |
105 | else: | |
106 | break | |
107 | return (t[0]*pad)+result | |
108 | ||
109 | def pubtoaddy(puk): #converts uncompressed public key to public address | |
110 | version=chr(0) | |
111 | h=hashlib.new("SHA256") | |
112 | h.update(puk) | |
113 | s=h.digest() | |
114 | h=hashlib.new("RIPEMD160") | |
115 | h.update(s) | |
116 | kh=version+h.digest() | |
117 | h=hashlib.new("SHA256") | |
118 | h.update(kh) | |
119 | cs=h.digest() | |
120 | h=hashlib.new("SHA256") | |
121 | h.update(cs) | |
122 | cs=h.digest()[:4] | |
123 | adr=b58encode(kh+cs) | |
124 | return adr | |
125 | ||
126 | ###Enable to allow blockchain query: | |
127 | #def GetBCIbalance(query): | |
128 | # url = 'https://blockchain.info/q/addressbalance/' + query | |
129 | # json_obj = urllib2.urlopen(url) | |
130 | # data = json.load(json_obj) | |
131 | # return data | |
132 | ||
133 | def genwallet(): # the main generator | |
134 | totalbalance = 0 | |
135 | walletname = "DEFAULTWALLET.txt" | |
136 | ||
137 | #################Change these############ GENERATOR SEEDS: Initial numerical private key and numerical increment between keys, thus: key chain | |
138 | seedbtc=13787023450987234098623465093474584872345908273452360908908071097932145987679 # default seed = first numerical private key to use in generation | |
139 | customincr = 10873345756478567985678956481319876234879623450 # default increment between private keys | |
140 | ################################################################################################################### | |
141 | customcount = 50 # default address count | |
142 | ||
143 | #######DO NOT MOVE###########Enable the following to have Prompt for custom filename,seed and customincr -- these two numbers are all you need with this scrip to recover all keys, so pick smart. | |
144 | #customseed = input('Enter a seed number between 2^50 and 2^253: ') #Overrides default seed with prompt | |
145 | #seedbtc = customseed | |
146 | #customcount = input('How many wallets, 144 max: ') | |
147 | #if customcount >> 144: | |
148 | # customcount = 144 | |
149 | #customincr = input('Enter an increment number between 2^3 and 2^116: ') | |
150 | #walletname = raw_input('Pick a filename: ') | |
151 | ########DO NOT MOVE##########You can also recover wallets made with this software with just the first two numerical private keys, prk2-prk1=customincr | |
152 | ||
153 | text_file = open(walletname, "w") #creates new file to store all keys, change the name of this file after/during creation to NOT LOSE KEYS!!! | |
154 | multn = 0 #don't change this or you'll have to remember it too!!! this is the multipier that spaces your private keys | |
155 | ||
156 | for looper in range(0,customcount): # for each address | |
157 | balance = 0 | |
158 | privKey = seedbtc+customincr*multn # equals seedbtc on first run, then counts up by customincr. These are your numerical private keys. | |
159 | multn=multn+1 #counter for customincr multiplier | |
160 | hexprkstr= '%x' % privKey #removes 0x and 'L' for printing purposes | |
161 | PublicKey = EccMultiply(GPoint,privKey) #gets public key from Eliptic function | |
162 | WIFKEY = numtowif(privKey) #gets WIF | |
163 | wifvalid = validwif(numtowif(privKey)) #checks if WIF validates by double conversion | |
164 | ucpuk = "04" + "%064x" % PublicKey[0] + "%064x" % PublicKey[1]; #uncompressed public key | |
165 | ||
166 | if PublicKey[1] % 2 == 1: #odd compressed public key | |
167 | cpuk ="03"+str(hex(PublicKey[0])[2:-1]).zfill(64) | |
168 | else: #even compressed public key | |
169 | cpuk ="02"+str(hex(PublicKey[0])[2:-1]).zfill(64) | |
170 | ||
171 | PubAd = pubtoaddy(Hex2Byte(ucpuk)) #gets public address | |
172 | - | #balance = float(GetBCIbalance(PubAd))/100000000; balchen = true #Enable to do api balance check on blockchain.info |
172 | + | #balance = float(GetBCIbalance(PubAd))/100000000; #Enable to do api balance check on blockchain.info |
173 | #totalbalance = totalbalance + balance #tracks total balance for disabled query | |
174 | ||
175 | newhex = hexprkstr | |
176 | for padhexpr in range (0, (64 - len(hexprkstr))): #makes hex private key ready to copy | |
177 | newhex = "0"+ newhex # just padding left side with zeros until 64 characters | |
178 | hexprkstr = newhex | |
179 | ||
180 | print >>text_file | |
181 | print >>text_file,"PublicAddress",looper+1,": ",PubAd#, " ",balance #enable ', " ",balance' to print | |
182 | print >>text_file,"NumericalPrivteKey: " | |
183 | print >>text_file," ",privKey | |
184 | print >>text_file,"HexPrivateKey: " | |
185 | print >>text_file," ",hexprkstr | |
186 | print >>text_file,"WalletImportFormat: " | |
187 | print >>text_file," ",WIFKEY," : Use this to validate" | |
188 | ||
189 | if wifvalid: | |
190 | donothing=0 #does not print if WIF is valid | |
191 | else: | |
192 | print >>text_file," ","WIFValid: ",wifvalid #prints if WIF is invalid | |
193 | ||
194 | print >>text_file,"UncompressedPublicKey: " | |
195 | print >>text_file," ",ucpuk | |
196 | print >>text_file,"CompressedPublicKey: " | |
197 | print >>text_file," ",cpuk | |
198 | ||
199 | print PubAd#, " ",balance #enable ', " ",balance' to print | |
200 | ||
201 | text_file.close() | |
202 | ||
203 | print "File has been created with", multn, "key sets."# + " Total balance of: ", totalbalance #enable ' + " Total balance of: ", totalbalance' to print balance | |
204 | ||
205 | genwallet() # Start Generator | |
206 | ||
207 | ########################################This section enables restart | |
208 | #newwalletstart = "y" | |
209 | #yesido = "y" | |
210 | #while newwalletstart is yesido: | |
211 | # newwalletstart = raw_input('Create another wallet? y, else close:') | |
212 | # if newwalletstart is yesido: | |
213 | # genwallet() | |
214 | ######################################### |