├── .gitignore ├── README.md ├── package.json ├── private-key-generator.js └── public-key-generator ├── Makefile └── ecdsapubkey.c /.gitignore: -------------------------------------------------------------------------------- 1 | .*~ 2 | *~ 3 | node_modules/ 4 | public-key-generator/ecdsapubkey 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Bitcoin 2 of 3 Multisig 2 | ========= 3 | 4 | This is an example walkthrough of using bitcoind RPC commands to generate a 2 5 | of 3 multisignature address. We will: 6 | 7 | - Generate three private keys 8 | - Find the ECDSA public key for each address 9 | - Generate a 2 of 3 multisig address 10 | - Send coins to the multisig address 11 | - Generate a transaction to spend funds out of the multisig address 12 | - Sign the transaction with two of the keys 13 | - Broadcast that transaction on the network 14 | 15 | Prerequisites 16 | -------------- 17 | 18 | - bitcoind (in particular, bitcoin-cli - you don't need a full copy of the blockchain) 19 | - node.js 20 | - c++ 21 | 22 | Installation 23 | -------------- 24 | 25 | ```sh 26 | npm install 27 | cd public-key-generator 28 | make 29 | cd .. 30 | ``` 31 | 32 | Steps 33 | ----- 34 | First we will generate some private keys. It is very important that this 35 | process is as random as possible. I'd suggest a hardware true random number 36 | generator such as the [FST-01](https://www.youtube.com/watch?v=iDuhLQ43tvQ). 37 | 38 | ```sh 39 | node private-key-generator 40 | ``` 41 | 42 | You will get something like this: 43 | 44 | ```sh 45 | Private Key in Hex: f3d03f863d9dd6ed35b9c15739f34d8c8fdd07797cc5cc6f2e610721d06bb816 46 | Private Key in WIF: 5KffUB9YUsvoGjrcn76PjVnC61PcWLzws4QPfrT9RFNd85utCkZ 47 | ``` 48 | Note: WIF stands for Wallet Import Format - a bitcoin specific way of representing 49 | an address which includes a checksum capability. 50 | 51 | You will want to generate a total of three private keys. Here is a second one: 52 | 53 | ```sh 54 | Private Key in Hex: e919e62a30f8ca06b66d7c9c22c176c77646c3db2c06d3ed1db0a9b2cc9f4b58 55 | Private Key in WIF: 5KawqZHB1H6Af12ZhgTBXwQUY1jACgvGMywET7NF5bdYYzCxomY 56 | ``` 57 | 58 | And a last one: 59 | 60 | ```sh 61 | Private Key in Hex: f99974355fbe8865e522643421914acb8f3efc0e3a1a746aa2fe68993e700d4e 62 | Private Key in WIF: 5KiDGG8sfmTNnzKDmm1MteWHV2TQQaUBbaEY3huVLwVz1i6i5be 63 | ``` 64 | 65 | Next you will want to generate a ECDSA public key that corrosponds to each of 66 | the private keys. Let's use the hex value of each private key to find an associated 67 | ECDSA public key: 68 | 69 | ```sh 70 | cd public-key-generator 71 | ./ecdsapubkey f3d03f863d9dd6ed35b9c15739f34d8c8fdd07797cc5cc6f2e610721d06bb816 72 | 04A97B658C114D77DC5F71736AB78FBE408CE632ED1478D7EAA106EEF67C55D58A91C6449DE4858FAF11721E85FE09EC850C6578432EB4BE9A69C76232AC593C3B 73 | ./ecdsapubkey e919e62a30f8ca06b66d7c9c22c176c77646c3db2c06d3ed1db0a9b2cc9f4b58 74 | 04019EF04A316792F0ECBE5AB1718C833C3964DEE3626CFABE19D97745DBCAA5198919081B456E8EEEA5898AFA0E36D5C17AB693A80D728721128ED8C5F38CDBA0 75 | ./ecdsapubkey f99974355fbe8865e522643421914acb8f3efc0e3a1a746aa2fe68993e700d4e 76 | 04A04F29F308160E6F945B33D943304B1B471ED8F9EACEEB5412C04E60A0FAB0376871D9D1108948B67CAFBC703E565A18F8351FB8558FD7C7482D7027EECD687C 77 | ``` 78 | 79 | Now we will create our multisig address given the three hex public keys. The parameter "2" 80 | tells bitcoind to create an address that requires the signature of at least two private keys. 81 | The fact that we are presenting three ECDSA keys as well is what makes it a two of three 82 | address. You can use any number of keys as long as it is equal to or greater than the 83 | "minimum required to sign" parameter. Two of two and three of five are other common 84 | strategies. 85 | 86 | ```sh 87 | bitcoin-cli createmultisig 2 '["04A97B658C114D77DC5F71736AB78FBE408CE632ED1478D7EAA106EEF67C55D58A91C6449DE4858FAF11721E85FE09EC850C6578432EB4BE9A69C76232AC593C3B","04019EF04A316792F0ECBE5AB1718C833C3964DEE3626CFABE19D97745DBCAA5198919081B456E8EEEA5898AFA0E36D5C17AB693A80D728721128ED8C5F38CDBA0","04A04F29F308160E6F945B33D943304B1B471ED8F9EACEEB5412C04E60A0FAB0376871D9D1108948B67CAFBC703E565A18F8351FB8558FD7C7482D7027EECD687C"]' 88 | { 89 | "address" : "38aNB81yPqNp6X2T3rXYZN8Z3C4pSbqEvs", 90 | "redeemScript" : "524104a97b658c114d77dc5f71736ab78fbe408ce632ed1478d7eaa106eef67c55d58a91c6449de4858faf11721e85fe09ec850c6578432eb4be9a69c76232ac593c3b4104019ef04a316792f0ecbe5ab1718c833c3964dee3626cfabe19d97745dbcaa5198919081b456e8eeea5898afa0e36d5c17ab693a80d728721128ed8c5f38cdba04104a04f29f308160e6f945b33d943304b1b471ed8f9eaceeb5412c04e60a0fab0376871d9d1108948b67cafbc703e565a18f8351fb8558fd7c7482d7027eecd687c53ae" 91 | } 92 | ``` 93 | 94 | So in this case, our address is 38aNB81yPqNp6X2T3rXYZN8Z3C4pSbqEvs. Let's send it some coins: 95 | 96 | ```sh 97 | bitcoin-cli sendtoaddress 38aNB81yPqNp6X2T3rXYZN8Z3C4pSbqEvs 0.001 98 | 7e69687c94c57a878cf711a39870383c6fe93b420f26184a21d020d8ace2df83 99 | ``` 100 | 101 | The resulting transaction (transaction number 102 | 7e69687c94c57a878cf711a39870383c6fe93b420f26184a21d020d8ace2df83) is a spend to our new address. 103 | That transaction will show some coin going in and other coin being returned as change. We will 104 | need the vout and the scriptPubKey of the output that we can now spend. Let's take a look: 105 | 106 | ```sh 107 | bitcoin-cli getrawtransaction 7e69687c94c57a878cf711a39870383c6fe93b420f26184a21d020d8ace2df83 1 108 | ... 109 | { 110 | "value" : 0.00100000, 111 | "n" : 1, 112 | "scriptPubKey" : { 113 | "asm" : "OP_HASH160 4b86dfac7f503de1127366815d1d452413282466 OP_EQUAL", 114 | "hex" : "a9144b86dfac7f503de1127366815d1d45241328246687", 115 | "reqSigs" : 1, 116 | "type" : "scripthash", 117 | "addresses" : [ 118 | "38aNB81yPqNp6X2T3rXYZN8Z3C4pSbqEvs" 119 | ] 120 | } 121 | } 122 | ... 123 | ``` 124 | 125 | Let's spend that money out of the address. To do that, we'll create a spend transaction 126 | that spends away 0.0009 BTC leaving the remainder (0.0001 BTC) to cover fees for the 127 | miners. 128 | 129 | ```sh 130 | bitcoin-cli createrawtransaction '[{"txid":"7e69687c94c57a878cf711a39870383c6fe93b420f26184a21d020d8ace2df83","vout":1}]' '{"19ijkHfTosmo6rHtVKte145XPnQQNqVn46":0.0009}' 131 | 010000000183dfe2acd820d0214a18260f423be96f3c387098a311f78c877ac5947c68697e0100000000ffffffff01905f0100000000001976a9145fa5be58f939d6ae79636c2143fa9e7924102c1588ac00000000 132 | ``` 133 | 134 | Note: the JSON here is very picky. For example, it doesn't tollerate things like spaces after 135 | commas and other standard patterns. Also be careful to escape things properly in the shell. 136 | If you get stuck, try copying the example EXACTLY and just replace the transaction id and 137 | multi-sig address. 138 | 139 | Now we have an unsigned raw transaction. It means nothing right now and can safely be sent 140 | through untrusted mediums such as unencrypted email. 141 | 142 | Let's go sign it with one of the private keys. In this case we will use the private key in 143 | Wallet Import Format. (WIF) 144 | 145 | Note: When doing this using the `bitcoin-abc` Bitcoin Cash (BCH / BCC) or `bgold-cli` Bitcoin Gold (BTG) 146 | you will need to also add an `amount` property to each input specifying the amount of each input. 147 | (the original input value without subtracting miner's fees) The JSON will look something like 148 | `..."vout":1,amount:0.001,"scriptPubKey"...`. 149 | 150 | ```sh 151 | bitcoin-cli signrawtransaction '010000000183dfe2acd820d0214a18260f423be96f3c387098a311f78c877ac5947c68697e0100000000ffffffff01905f0100000000001976a9145fa5be58f939d6ae79636c2143fa9e7924102c1588ac00000000' '[{"txid":"7e69687c94c57a878cf711a39870383c6fe93b420f26184a21d020d8ace2df83","vout":1,"scriptPubKey":"a9144b86dfac7f503de1127366815d1d45241328246687","redeemScript":"524104a97b658c114d77dc5f71736ab78fbe408ce632ed1478d7eaa106eef67c55d58a91c6449de4858faf11721e85fe09ec850c6578432eb4be9a69c76232ac593c3b4104019ef04a316792f0ecbe5ab1718c833c3964dee3626cfabe19d97745dbcaa5198919081b456e8eeea5898afa0e36d5c17ab693a80d728721128ed8c5f38cdba04104a04f29f308160e6f945b33d943304b1b471ed8f9eaceeb5412c04e60a0fab0376871d9d1108948b67cafbc703e565a18f8351fb8558fd7c7482d7027eecd687c53ae"}]' '["5KffUB9YUsvoGjrcn76PjVnC61PcWLzws4QPfrT9RFNd85utCkZ"]' 152 | { 153 | "hex" : "010000000183dfe2acd820d0214a18260f423be96f3c387098a311f78c877ac5947c68697e01000000fd150100483045022100acb79a21e7e6cea47a598254e02639f87b5fa9a08c0ec8455503da0a479c19560220724014c241ac64ffc108d4457302644d5d057fbc4f2edbf33a86f24cf0b10447014cc9524104a97b658c114d77dc5f71736ab78fbe408ce632ed1478d7eaa106eef67c55d58a91c6449de4858faf11721e85fe09ec850c6578432eb4be9a69c76232ac593c3b4104019ef04a316792f0ecbe5ab1718c833c3964dee3626cfabe19d97745dbcaa5198919081b456e8eeea5898afa0e36d5c17ab693a80d728721128ed8c5f38cdba04104a04f29f308160e6f945b33d943304b1b471ed8f9eaceeb5412c04e60a0fab0376871d9d1108948b67cafbc703e565a18f8351fb8558fd7c7482d7027eecd687c53aeffffffff01905f0100000000001976a9145fa5be58f939d6ae79636c2143fa9e7924102c1588ac00000000", 154 | "complete" : false 155 | } 156 | ``` 157 | 158 | The resulting transaction in hex format is a bit longer but still marked as incomplete 159 | because we only have one signature on it. Likewise, it can be sent through insecure mediums 160 | such as email because it isn't completely signed. Even if it were, an abuser wouldn't be able 161 | to alter the transaction sending the coin to another address because that would invalidate 162 | the original signature. 163 | 164 | However, I should point out that the transaction isn't encrypted. Let's take a look at it to 165 | demonstrate that. 166 | 167 | ```sh 168 | bitcoin-cli decoderawtransaction '010000000183dfe2acd820d0214a18260f423be96f3c387098a311f78c877ac5947c68697e01000000fd150100483045022100acb79a21e7e6cea47a598254e02639f87b5fa9a08c0ec8455503da0a479c19560220724014c241ac64ffc108d4457302644d5d057fbc4f2edbf33a86f24cf0b10447014cc9524104a97b658c114d77dc5f71736ab78fbe408ce632ed1478d7eaa106eef67c55d58a91c6449de4858faf11721e85fe09ec850c6578432eb4be9a69c76232ac593c3b4104019ef04a316792f0ecbe5ab1718c833c3964dee3626cfabe19d97745dbcaa5198919081b456e8eeea5898afa0e36d5c17ab693a80d728721128ed8c5f38cdba04104a04f29f308160e6f945b33d943304b1b471ed8f9eaceeb5412c04e60a0fab0376871d9d1108948b67cafbc703e565a18f8351fb8558fd7c7482d7027eecd687c53aeffffffff01905f0100000000001976a9145fa5be58f939d6ae79636c2143fa9e7924102c1588ac00000000' 169 | { 170 | "txid" : "3312407d07de68d09eba1c9bee333aa947f46075c6f491eaeda2025c513aa45f", 171 | "version" : 1, 172 | "locktime" : 0, 173 | "vin" : [ 174 | { 175 | "txid" : "7e69687c94c57a878cf711a39870383c6fe93b420f26184a21d020d8ace2df83", 176 | "vout" : 1, 177 | "scriptSig" : { 178 | "asm" : "0 3045022100acb79a21e7e6cea47a598254e02639f87b5fa9a08c0ec8455503da0a479c19560220724014c241ac64ffc108d4457302644d5d057fbc4f2edbf33a86f24cf0b1044701 524104a97b658c114d77dc5f71736ab78fbe408ce632ed1478d7eaa106eef67c55d58a91c6449de4858faf11721e85fe09ec850c6578432eb4be9a69c76232ac593c3b4104019ef04a316792f0ecbe5ab1718c833c3964dee3626cfabe19d97745dbcaa5198919081b456e8eeea5898afa0e36d5c17ab693a80d728721128ed8c5f38cdba04104a04f29f308160e6f945b33d943304b1b471ed8f9eaceeb5412c04e60a0fab0376871d9d1108948b67cafbc703e565a18f8351fb8558fd7c7482d7027eecd687c53ae", 179 | "hex" : "00483045022100acb79a21e7e6cea47a598254e02639f87b5fa9a08c0ec8455503da0a479c19560220724014c241ac64ffc108d4457302644d5d057fbc4f2edbf33a86f24cf0b10447014cc9524104a97b658c114d77dc5f71736ab78fbe408ce632ed1478d7eaa106eef67c55d58a91c6449de4858faf11721e85fe09ec850c6578432eb4be9a69c76232ac593c3b4104019ef04a316792f0ecbe5ab1718c833c3964dee3626cfabe19d97745dbcaa5198919081b456e8eeea5898afa0e36d5c17ab693a80d728721128ed8c5f38cdba04104a04f29f308160e6f945b33d943304b1b471ed8f9eaceeb5412c04e60a0fab0376871d9d1108948b67cafbc703e565a18f8351fb8558fd7c7482d7027eecd687c53ae" 180 | }, 181 | "sequence" : 4294967295 182 | } 183 | ], 184 | "vout" : [ 185 | { 186 | "value" : 0.00090000, 187 | "n" : 0, 188 | "scriptPubKey" : { 189 | "asm" : "OP_DUP OP_HASH160 5fa5be58f939d6ae79636c2143fa9e7924102c15 OP_EQUALVERIFY OP_CHECKSIG", 190 | "hex" : "76a9145fa5be58f939d6ae79636c2143fa9e7924102c1588ac", 191 | "reqSigs" : 1, 192 | "type" : "pubkeyhash", 193 | "addresses" : [ 194 | "19ijkHfTosmo6rHtVKte145XPnQQNqVn46" 195 | ] 196 | } 197 | } 198 | ] 199 | } 200 | ``` 201 | 202 | Sure enough, in the vout section you can see that this is a spend of 0.00090000 BTC to 19ijkHfTosmo6rHtVKte145XPnQQNqVn46. 203 | 204 | Moving on, let's add another signature to this transaction: 205 | 206 | ```sh 207 | bitcoin-cli signrawtransaction '010000000183dfe2acd820d0214a18260f423be96f3c387098a311f78c877ac5947c68697e01000000fd150100483045022100acb79a21e7e6cea47a598254e02639f87b5fa9a08c0ec8455503da0a479c19560220724014c241ac64ffc108d4457302644d5d057fbc4f2edbf33a86f24cf0b10447014cc9524104a97b658c114d77dc5f71736ab78fbe408ce632ed1478d7eaa106eef67c55d58a91c6449de4858faf11721e85fe09ec850c6578432eb4be9a69c76232ac593c3b4104019ef04a316792f0ecbe5ab1718c833c3964dee3626cfabe19d97745dbcaa5198919081b456e8eeea5898afa0e36d5c17ab693a80d728721128ed8c5f38cdba04104a04f29f308160e6f945b33d943304b1b471ed8f9eaceeb5412c04e60a0fab0376871d9d1108948b67cafbc703e565a18f8351fb8558fd7c7482d7027eecd687c53aeffffffff01905f0100000000001976a9145fa5be58f939d6ae79636c2143fa9e7924102c1588ac00000000' '[{"txid":"7e69687c94c57a878cf711a39870383c6fe93b420f26184a21d020d8ace2df83","vout":1,"scriptPubKey":"a9144b86dfac7f503de1127366815d1d45241328246687","redeemScript":"524104a97b658c114d77dc5f71736ab78fbe408ce632ed1478d7eaa106eef67c55d58a91c6449de4858faf11721e85fe09ec850c6578432eb4be9a69c76232ac593c3b4104019ef04a316792f0ecbe5ab1718c833c3964dee3626cfabe19d97745dbcaa5198919081b456e8eeea5898afa0e36d5c17ab693a80d728721128ed8c5f38cdba04104a04f29f308160e6f945b33d943304b1b471ed8f9eaceeb5412c04e60a0fab0376871d9d1108948b67cafbc703e565a18f8351fb8558fd7c7482d7027eecd687c53ae"}]' '["5KiDGG8sfmTNnzKDmm1MteWHV2TQQaUBbaEY3huVLwVz1i6i5be"]' 208 | { 209 | "hex" : "010000000183dfe2acd820d0214a18260f423be96f3c387098a311f78c877ac5947c68697e01000000fd5d0100483045022100acb79a21e7e6cea47a598254e02639f87b5fa9a08c0ec8455503da0a479c19560220724014c241ac64ffc108d4457302644d5d057fbc4f2edbf33a86f24cf0b10447014730440220338862b4a13d67415fdaac35d408bd2a6d86e4c3be03b7abc92ee769b254dbe1022043ba94f304aff774fdb957af078c9b302425976370cc66f42ae05382c84ea5ea014cc9524104a97b658c114d77dc5f71736ab78fbe408ce632ed1478d7eaa106eef67c55d58a91c6449de4858faf11721e85fe09ec850c6578432eb4be9a69c76232ac593c3b4104019ef04a316792f0ecbe5ab1718c833c3964dee3626cfabe19d97745dbcaa5198919081b456e8eeea5898afa0e36d5c17ab693a80d728721128ed8c5f38cdba04104a04f29f308160e6f945b33d943304b1b471ed8f9eaceeb5412c04e60a0fab0376871d9d1108948b67cafbc703e565a18f8351fb8558fd7c7482d7027eecd687c53aeffffffff01905f0100000000001976a9145fa5be58f939d6ae79636c2143fa9e7924102c1588ac00000000", 210 | "complete" : true 211 | } 212 | ``` 213 | 214 | Now our transaction is marked complete. Again, an attacker can't alter the transaction 215 | without invalidating it so it is still in a resonably safe condition. Additionally, if 216 | our private keys were to be kept in distant and secure locations, at no point were our 217 | private keys in the same place at the same time. You can see how this strategy might be 218 | better than simply splitting a private key into multiple peices and combining them later 219 | to spend. 220 | 221 | All that is left is to transmit our signed transaction on the network: 222 | 223 | ```sh 224 | bitcoin-cli sendrawtransaction 010000000183dfe2acd820d0214a18260f423be96f3c387098a311f78c877ac5947c68697e01000000fd5d0100483045022100acb79a21e7e6cea47a598254e02639f87b5fa9a08c0ec8455503da0a479c19560220724014c241ac64ffc108d4457302644d5d057fbc4f2edbf33a86f24cf0b10447014730440220338862b4a13d67415fdaac35d408bd2a6d86e4c3be03b7abc92ee769b254dbe1022043ba94f304aff774fdb957af078c9b302425976370cc66f42ae05382c84ea5ea014cc9524104a97b658c114d77dc5f71736ab78fbe408ce632ed1478d7eaa106eef67c55d58a91c6449de4858faf11721e85fe09ec850c6578432eb4be9a69c76232ac593c3b4104019ef04a316792f0ecbe5ab1718c833c3964dee3626cfabe19d97745dbcaa5198919081b456e8eeea5898afa0e36d5c17ab693a80d728721128ed8c5f38cdba04104a04f29f308160e6f945b33d943304b1b471ed8f9eaceeb5412c04e60a0fab0376871d9d1108948b67cafbc703e565a18f8351fb8558fd7c7482d7027eecd687c53aeffffffff01905f0100000000001976a9145fa5be58f939d6ae79636c2143fa9e7924102c1588ac00000000 225 | 78126ea4aaf1acd232711b1efa3dc15832bd45d89bd5718c1cd15ec57d802497 226 | ``` 227 | 228 | Now we should be able to see our spend transaction populate across the network. Search for 229 | [78126ea4aaf1acd232711b1efa3dc15832bd45d89bd5718c1cd15ec57d802497](https://blockchain.info/tx/78126ea4aaf1acd232711b1efa3dc15832bd45d89bd5718c1cd15ec57d802497) in a block explorer to 230 | verify. 231 | 232 | We have now successfully created a multi-sig bitcoin address, sent funds to it and retrieved 233 | the funds out the other side. (minus a small transaction fee) 234 | 235 | License 236 | ---- 237 | 238 | MIT 239 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bitcoin-2-of-3-multisig", 3 | "version": "0.0.1", 4 | "description": "A bitcoin private key generator.", 5 | "main": "private-key-generator.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [ 10 | "bitcoin", 11 | "private", 12 | "key" 13 | ], 14 | "author": "Anders Brownworth", 15 | "license": "MIT", 16 | "dependencies": { 17 | "bignum": "^0.9.0" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /private-key-generator.js: -------------------------------------------------------------------------------- 1 | var bignum = require('bignum'); 2 | var crypto = require('crypto'); 3 | var util = require('util'); 4 | 5 | var key = getRandomPrivateKey(); 6 | console.log('Private Key in Hex: '+key.toString('hex')); 7 | console.log('Private Key in WIF: '+walletImportFormat(key)); 8 | 9 | function getRandomPrivateKey() { 10 | var buf = new Buffer([0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 11 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 12 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 13 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]); 14 | 15 | // not every random 32 bytes is a valid private key. this is the top 16 | var top = new Buffer([0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 17 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 18 | 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 19 | 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41]); 20 | 21 | while (bignum.fromBuffer(buf) > bignum.fromBuffer(top)) { 22 | try { 23 | buf = crypto.randomBytes(32); 24 | } 25 | catch (ex) { 26 | console.log(ex); 27 | } 28 | } 29 | return(buf); 30 | } 31 | 32 | function walletImportFormat(buf) { 33 | //console.log('add 0x80 in the front for main net'); 34 | var extBuf = new Buffer(buf.length+1); 35 | extBuf[0] = 0x80; 36 | buf.copy(extBuf, 1); 37 | 38 | //console.log('double sha256 the result'); 39 | var digest = sha256(sha256(extBuf)); 40 | 41 | //console.log('add the first 4 bytes of the double sha256 to the end as a checksum') 42 | var chkbuf = new Buffer(extBuf.length+4); 43 | extBuf.copy(chkbuf, 0); 44 | chkbuf[33] = digest[0]; 45 | chkbuf[34] = digest[1]; 46 | chkbuf[35] = digest[2]; 47 | chkbuf[36] = digest[3]; 48 | 49 | //console.log('base58 that'); 50 | return base58Encode(chkbuf); 51 | } 52 | 53 | function sha256(data) { 54 | return new Buffer(crypto.createHash('sha256').update(data).digest('binary'), 'binary'); 55 | } 56 | 57 | function base58Encode(buf) { 58 | var globalBuffer = new Buffer(1024); 59 | var ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'; 60 | var ALPHABET_BUF = new Buffer(ALPHABET, 'ascii'); 61 | var str; 62 | var x = bignum.fromBuffer(buf); 63 | var r; 64 | 65 | if (buf.length < 512) 66 | str = globalBuffer; 67 | else 68 | str = new Buffer(buf.length << 1); 69 | var i = str.length - 1; 70 | while (x.gt(0)) { 71 | r = x.mod(58); 72 | x = x.div(58); 73 | str[i] = ALPHABET_BUF[r.toNumber()]; 74 | i--; 75 | } 76 | 77 | // deal with leading zeros 78 | var j=0; 79 | while (buf[j] == 0) { 80 | str[i] = ALPHABET_BUF[0]; 81 | j++; 82 | i--; 83 | } 84 | 85 | return str.slice(i+1, str.length).toString('ascii'); 86 | } 87 | -------------------------------------------------------------------------------- /public-key-generator/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | gcc -Wall ecdsapubkey.c -o ecdsapubkey -lcrypto 3 | clean: 4 | rm -rf ecdsapubkey 5 | -------------------------------------------------------------------------------- /public-key-generator/ecdsapubkey.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int main(int argc, char *argv[]) { 9 | char prv_hex[64]; 10 | EC_KEY *eckey = NULL; 11 | EC_POINT *pub_key = NULL; 12 | const EC_GROUP *group = NULL; 13 | BIGNUM start; 14 | BIGNUM *res; 15 | BN_CTX *ctx; 16 | 17 | strcpy(prv_hex, argv[1]); 18 | 19 | BN_init(&start); 20 | ctx = BN_CTX_new(); // ctx is an optional buffer to save time from allocating and deallocating memory whenever required 21 | 22 | res = &start; 23 | BN_hex2bn(&res,prv_hex); 24 | 25 | /* 26 | BIO *out=NULL; 27 | out=BIO_new(BIO_s_file()); 28 | if (out == NULL) exit(1); 29 | BIO_set_fp(out,stdout,BIO_NOCLOSE); 30 | BN_print(out,res); 31 | printf("\n"); 32 | */ 33 | 34 | eckey = EC_KEY_new_by_curve_name(NID_secp256k1); 35 | group = EC_KEY_get0_group(eckey); 36 | pub_key = EC_POINT_new(group); 37 | 38 | EC_KEY_set_private_key(eckey, res); 39 | 40 | /* pub_key is a new uninitialized `EC_POINT*`. priv_key res is a `BIGNUM*`. */ 41 | if (!EC_POINT_mul(group, pub_key, res, NULL, NULL, ctx)) 42 | printf("Error at EC_POINT_mul.\n"); 43 | 44 | //assert(EC_POINT_bn2point(group, &res, pub_key, ctx)); // Null here 45 | 46 | EC_KEY_set_public_key(eckey, pub_key); 47 | 48 | char *cc = EC_POINT_point2hex(group, pub_key, 4, ctx); 49 | char *c = cc; 50 | int i; 51 | 52 | for (i=0; i<130; i++) { // 1 byte 0x42, 32 bytes for X coordinate, 32 bytes for Y coordinate 53 | printf("%c", *c++); 54 | } 55 | printf("\n"); 56 | 57 | BN_CTX_free(ctx); 58 | free(cc); 59 | 60 | return 0; 61 | } 62 | --------------------------------------------------------------------------------