├── .travis.yml ├── BitcoinAddressGenerator ├── base58.sh ├── btemp.sh └── wif_ecsda.rb └── README.md /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | dist: trusty 3 | sudo: required 4 | -------------------------------------------------------------------------------- /BitcoinAddressGenerator/base58.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source ./btemp.sh 3 | keyin=$(echo -n $1) 4 | encodeBase58 $keyin -------------------------------------------------------------------------------- /BitcoinAddressGenerator/btemp.sh: -------------------------------------------------------------------------------- 1 | declare -a base58=( 2 | 1 2 3 4 5 6 7 8 9 3 | A B C D E F G H J K L M N P Q R S T U V W X Y Z 4 | a b c d e f g h i j k m n o p q r s t u v w x y z 5 | ) 6 | unset dcr; for i in {0..57}; do dcr+="${i}s${base58[i]}"; done 7 | declare ec_dc=' 8 | I16i7sb0sa[[_1*lm1-*lm%q]Std0>tlm%Lts#]s%[Smddl%x-lm/rl%xLms#]s~ 9 | 483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8 10 | 79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798 11 | 2 100^d14551231950B75FC4402DA1732FC9BEBF-so1000003D1-ddspsm*+sGi 12 | [_1*l%x]s_[+l%x]s+[*l%x]s*[-l%x]s-[l%xsclmsd1su0sv0sr1st[q]SQ[lc 13 | 0=Qldlcl~xlcsdscsqlrlqlu*-ltlqlv*-lulvstsrsvsulXx]dSXxLXs#LQs#lr 14 | l%x]sI[lpSm[+q]S0d0=0lpl~xsydsxd*3*lal+x2ly*lIx*l%xdsld*2lx*l-xd 15 | lxrl-xlll*xlyl-xrlp*+Lms#L0s#]sD[lpSm[+q]S0[2;AlDxq]Sdd0=0rd0=0d 16 | 2:Alp~1:A0:Ad2:Blp~1:B0:B2;A2;B=d[0q]Sx2;A0;B1;Bl_xrlm*+=x0;A0;B 17 | l-xlIxdsi1;A1;Bl-xl*xdsld*0;Al-x0;Bl-xd0;Arl-xlll*x1;Al-xrlp*+L0 18 | s#Lds#Lxs#Lms#]sA[rs.0r[rl.lAxr]SP[q]sQ[d0! temp` 12 | `hexdump -C temp` 13 | $hash256 = Digest::SHA256.hexdigest File.read "temp" 14 | return $hash256 15 | end 16 | 17 | # Calculate base58 encoding 18 | def base58encode(checksum) 19 | `chmod +x base58.sh` 20 | return `./base58.sh #{checksum}` 21 | end 22 | 23 | # Generate a Private Key 24 | group = ECDSA::Group::Secp256k1 25 | private_key = 1 + SecureRandom.random_number(group.order - 1) 26 | priv_key = '%x' % private_key 27 | 28 | # Assign address prefix : 80 is for mainnet 29 | address_prefix_1 = "80" 30 | 31 | # Get WIF vs Compressed choice 32 | compressed = false 33 | puts "1. WIF 2. Compressed" 34 | type = gets.chomp 35 | if(type == '2') 36 | compression_flag = "01" 37 | compressed = true 38 | end 39 | 40 | # Get private Key with Address Version 41 | priv_key_with_version = address_prefix_1.concat(priv_key) 42 | 43 | # Append the compression flag if compressed format 44 | priv_key_with_compression_flag = compressed ? priv_key_with_version.concat(compression_flag) : priv_key_with_version 45 | 46 | # SHA256 the Key twice 47 | double_hash = SHA256(SHA256(priv_key_with_compression_flag)) 48 | 49 | # Store the first 4 bytes as a checksum 50 | checksum = $hash256[0..7] 51 | 52 | # Include the checksum at the end of the private Key 53 | priv_key_with_checksum = double_hash.concat(checksum) 54 | 55 | # Encode the private key in base58 56 | base58_priv_key = base58encode(priv_key_with_checksum) 57 | 58 | # Display the private key 59 | puts "\nPRIVATE KEY\t\t : #{base58_priv_key}" 60 | 61 | # Generate a Public Key for the Private Key 62 | public_key = group.generator.multiply_by_scalar(private_key) 63 | 64 | # Get the x and y coordinates of the curve. A public key is a point on the curve. 65 | pub_key_x = '%x' % public_key.x 66 | pub_key_y = '%x' % public_key.y 67 | 68 | # Concatenate the x and y coordinates 69 | pub_key = pub_key_x.concat(pub_key_y) 70 | 71 | # Append 0x04 at the beginning 72 | pub_key = "04".concat(pub_key) 73 | 74 | # SHA256 the key 75 | pub_key_hash = SHA256(pub_key) 76 | 77 | # Strip down the length using RipeMD-160 78 | ripe_md160 = Digest::RMD160.hexdigest(pub_key_hash) 79 | 80 | # Define version number - 0x00 indicates Mainnet 81 | version_number = "00" 82 | 83 | # Append version number to the ripeMD-160 hash 84 | public_key_with_version = version_number.concat(ripe_md160) 85 | 86 | # Double SHA256 the key 87 | hash_after_ripe = SHA256(SHA256(public_key_with_version)) 88 | 89 | # store first 4 bytes as checksum 90 | pub_checksum = hash_after_ripe[0..7] 91 | 92 | # Get the 25 byte binary bitcoin address 93 | binary_btc_add = public_key_with_version.concat(pub_checksum) 94 | 95 | # base58 encode the address 96 | final_encode = base58encode(binary_btc_add) 97 | 98 | # Display the Wallet Address 99 | puts "\nWallet Address\t\t : #{final_encode}" 100 | 101 | # Get a QRCode object for the address 102 | qrcode = RQRCode::QRCode.new("#{final_encode}") 103 | 104 | # Store the address as a png 105 | png = qrcode.as_png( 106 | resize_gte_to: false, 107 | resize_exactly_to: false, 108 | fill: 'white', 109 | color: 'black', 110 | size: 240, 111 | border_modules: 4, 112 | module_px_size: 6, 113 | file: nil 114 | ) 115 | 116 | # Store the png file in the current folder 117 | IO.write("Wallet-qrcode.png", png.to_s) 118 | `google-chrome https://blockchain.info/address/#{final_encode}` 119 | `xdg-open Wallet-qrcode.png` 120 | 121 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | [![Codacy Badge](https://api.codacy.com/project/badge/Grade/590046c13de44602b36d561b6868a98c)](https://app.codacy.com/app/llk23r/BitcoinAddressGenerator?utm_source=github.com&utm_medium=referral&utm_content=llk23r/BitcoinAddressGenerator&utm_campaign=badger) 3 | 4 |
Install necessary gems:
5 | 6 | `gem install ecdsa securerandom digest rubygems rqrcode` 7 | 8 |
Run the Script
9 | 10 | `ruby wif_ecsda.rb` 11 | 12 |
Files Description
13 | 14 | ``` 15 | - wif_ecsda.rb : It generates a new Key-pair everytime it executes. Supports WIF and compression bit. Doesn't support BIP32 seed generation. It also shows a QR-Code of the address that can be scanned by any wallet application. It also opens blockchain.info to explore the corresponding address in Google Chrome _(Chrome has to be installed for this to work.)_ 16 | 17 | - base58.sh : It passes the checksum-appended-key to btemp.sh 18 | 19 | - btemp.sh : Generates a valid base58 encoding. 20 | 21 | - Wallet-qrcode.png : QR-Code of the address. 22 | 23 | ``` 24 |
Tests
25 | 26 | ``` 27 | - Able to successfully import the generated private key in Electrum Wallet. 28 | - Mobile application wallets are able to successfully scan the QR code. 29 | - Block Explorer validates the generated block address. 30 | ``` 31 |

CAUTION!

32 | 33 |

34 | 35 | This script generates addresses for the mainnet. Do not use it unless you know how to import a wallet from a private key. This is only for educational purpose and is not the most secure way to handle wallets. Please look into BIP32 implementation https://datatracker.ietf.org/meeting/interim-2017-cfrg-01/materials/slides-interim-2017-cfrg-01-sessa-bip32-ed25519-01.pdf of wallets which are much more secure. 36 | P.S Do not share the private key with anyone. 37 | 38 |

39 | --------------------------------------------------------------------------------