crypto-lite 0.2.3 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.md CHANGED
@@ -1,501 +1,1023 @@
1
- # crypto-lite - Cryptographic Secure Hash Functions and Public Key Signature Algorithms Made Easy
2
-
3
-
4
-
5
- * home :: [github.com/rubycoco/blockchain](https://github.com/rubycoco/blockchain)
6
- * bugs :: [github.com/rubycoco/blockchain/issues](https://github.com/rubycoco/blockchain/issues)
7
- * gem :: [rubygems.org/gems/crypto-lite](https://rubygems.org/gems/crypto-lite)
8
- * rdoc :: [rubydoc.info/gems/crypto-lite](http://rubydoc.info/gems/crypto-lite)
9
-
10
-
11
- ## Usage
12
-
13
- ### Secure Hashing / Hash Functions
14
-
15
- **SHA256 - Secure Hash Algorithm (SHA) 256-Bit (32 Bytes)**
16
-
17
-
18
- ``` ruby
19
- require 'crypto' ## or use require 'crypto-lite'
20
-
21
- ## try abc
22
- sha256( "abc" ) #=> "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
23
- sha256( "abc".b ) #=> "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
24
- sha256( "\x61\x62\x63" ) #=> "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
25
- sha256( 0x616263 ) #=> "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
26
-
27
- sha256( hex: '616263' ) #=> "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
28
- sha256( hex: '0x616263' ) #=> "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
29
- sha256( hex: '0X616263' ) #=> "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
30
-
31
- # "auto-magic" hex string to binary string conversion heuristic
32
- sha256( '0x616263' ) #=> "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
33
- sha256( '0X616263' ) #=> "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
34
- ```
35
-
36
-
37
- Bonus Back Stage Tip: How does SHA256 work?
38
-
39
- Try this [amazing animation of the SHA256 hash function in your very own terminal](https://github.com/in3rsha/sha256-animation) by Greg Walker.
40
-
41
-
42
-
43
- Onwards with more sha256 examples:
44
-
45
- ``` ruby
46
- ## try a
47
- sha256( "a" ) #=> "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb"
48
- sha256( "\x61" ) #=> "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb"
49
- sha256( 0b01100001 ) #=> "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb"
50
- sha256( 0x61 ) #=> "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb"
51
-
52
- sha256( hex: '61' ) #=> "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb"
53
- sha256( hex: '0x61' ) #=> "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb"
54
-
55
- # "auto-magic" hex string to binary string conversion heuristic
56
- sha256( '0x61' ) #=> "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb"
57
-
58
-
59
- ## try some more
60
- sha256( "Hello, Cryptos!" ) #=> "33eedea60b0662c66c289ceba71863a864cf84b00e10002ca1069bf58f9362d5"
61
- ```
62
-
63
-
64
- **SHA3-256 - Secure Hashing Algorthim (SHA) 3, 256-Bit (32 Bytes)**
65
-
66
- ``` ruby
67
- sha3_256( "Hello, Cryptos!" ) #=> "7dddf4bc9b86352b67e8823e5010ddbd2a90a854469e2517992ca7ca89e5bd58"
68
- ```
69
-
70
- Note: Yes, SHA256 vs SHA3-256 / SHA-2 vs SHA-3 the hashing functions are
71
- different (although the 256-bit hash size output is the same).
72
- The sha256 hashing function is part of the Secure Hash Algorithm (SHA) 2 family / standards first published in 2001.
73
- The sha3_256 is part of the (newer) Secure Hash Algorithm (SHA) 3 family / standards first published in 2015
74
- (and uses the Keccak cryptographic primitive "under the hood").
75
-
76
-
77
-
78
- **Keccak 256-Bit**
79
-
80
- ``` ruby
81
- keccak256( "Hello, Cryptos!" ) #=> "2cf14baa817e931f5cc2dcb63c889619d6b7ae0794fc2223ebadf8e672c776f5"
82
- ```
83
-
84
-
85
- #### Aside - Keccak vs SHA3 / Original vs Official
86
-
87
- In 2004 the U.S. National Institute of Standards and Technology (NIST)
88
- changed the padding to `SHA3-256(M) = KECCAK [512] (M || 01, 256)`.
89
- This is different from the padding proposed by the Keccak team in
90
- the original Keccak SHA-3 submission version 3 (the final, winning version).
91
- The difference is the additional `'01'` bits appended to the message.
92
-
93
- To help avoid confusion the "submitted original version 3" SHA-3 Keccak
94
- hashing is now called "Keccak"
95
- and the finalized NIST SHA-3 standard "SHA3".
96
-
97
- Tip: If you don't know what variant of the hash function you have -
98
- original or official? - check your hash:
99
-
100
- For keccak 256-bit:
101
-
102
- ``` ruby
103
- keccak256( '' ) #=> "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"
104
- ```
105
-
106
- For sha3 256-bit:
107
-
108
- ``` ruby
109
- sha3_256( '' ) #=> "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a"
110
- ```
111
-
112
-
113
-
114
- **RMD / RIPE-MD - RACE¹ Integrity Primitives Evaluation Message Digest 160-Bit**
115
-
116
- ¹: Research and development in Advanced Communications technologies in Europe
117
-
118
-
119
- ``` ruby
120
- rmd160( "Hello, Cryptos!" ) #=>"4d65f7b740bbade4097e1348e15d2a7d52ac5f53"
121
- # or use the alias / alternate name
122
- ripemd160( "Hello, Cryptos!" ) #=>"4d65f7b740bbade4097e1348e15d2a7d52ac5f53"
123
- ```
124
-
125
-
126
- #### Aside - Hex String `"0x616263"` vs Binary String `"\x61\x62\x63" == "abc"`
127
-
128
- Note: All hash functions operate on binary strings ("byte arrays")
129
- and NOT hex strings.
130
-
131
- Note: For hex strings the `0x` or `0X` prefix is optional.
132
- Examples of hex strings:
133
-
134
- ``` ruby
135
- # hex string binary string ("byte array")
136
- "61" "\x61" == "a"
137
- "0x61" "\x61" == "a"
138
-
139
- "616263" "\x61\x62\x63" == "abc"
140
- "0x616263" "\x61\x62\x63" == "abc"
141
- "0X616263" "\x61\x62\x63" == "abc"
142
-
143
- # or 160-bit hex string (hash)
144
- "93ce48570b55c42c2af816aeaba06cfee1224fae"
145
- "0x93ce48570b55c42c2af816aeaba06cfee1224fae"
146
-
147
- # or 256-bit hex string (hash)
148
- "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
149
- "0xba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
150
- ```
151
-
152
- You can use `[str].pack( 'H*' )`
153
- to convert a hex string into a binary string.
154
- Note: The standard `Array#pack` conversion
155
- will NOT "auto-magically" cut-off the `0x` or `0X` prefix.
156
-
157
-
158
- If you know you have a hex string use the `hex:` keyword to pass
159
- in the arg(ument)
160
- to the hash function and that will "automagically"
161
- handle the hex-to-bin conversion for you. Example:
162
-
163
- ``` ruby
164
- sha256( hex: '61' ) #=> "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb"
165
- sha256( hex: '0x61' ) #=> "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb"
166
-
167
- sha256( hex: '616263' ) #=> "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
168
- sha256( hex: '0x616263' ) #=> "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
169
- sha256( hex: '0X616263' ) #=> "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
170
- ```
171
-
172
- What about the built-in "auto-magic" hex-to-bin conversion / heuristic?
173
-
174
- Yes, if your passed in string starts with the
175
- the `0x` or `0X` prefix the string gets "auto-magically" converted
176
- to binary. Or if your passed in string is all hexadecimal characters,
177
- that is, `0-9` and `a-f` and has a minimum length of ten characters.
178
- Example:
179
-
180
-
181
- ``` ruby
182
- # "auto-magic" hex string to binary string conversion heuristic
183
-
184
- sha256( '0x616263' ) #=> "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
185
- sha256( '0X616263' ) #=> "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
186
-
187
- # or without 0x or 0X BUT with minimum heuristic length
188
- hash160( '02b4632d08485ff1df2db55b9dafd23347d1c47a457072a1e87be26896549a8737' )
189
- #=> "93ce48570b55c42c2af816aeaba06cfee1224fae"
190
-
191
- hash256( '6fe6b145a3908a4d6616b13c1109717add8672c900' )
192
- #=> "02335f08b8fe4ddad263a50b7a33c5d38ea1cbd8fd2056a1320a3ddece541711"
193
-
194
- # and so on
195
- ```
196
-
197
-
198
- #### Hash Function Helpers
199
-
200
- **HASH160 - RMD160(SHA256(X))**
201
-
202
- All-in-one "best-of-both-worlds" helper - first hash with sha256 and than hash with rmd160. Why? Get the higher security of sha256 and the smaller size of rmd160.
203
-
204
-
205
- ``` ruby
206
- hash160( '02b9d1cc0b793b03b9f64d022e9c67d5f32670b03f636abf0b3147b34123d13990' )
207
- #=> "e6b145a3908a4d6616b13c1109717add8672c900"
208
-
209
- hash160( '02b4632d08485ff1df2db55b9dafd23347d1c47a457072a1e87be26896549a8737' )
210
- #=> "93ce48570b55c42c2af816aeaba06cfee1224fae"
211
- ```
212
-
213
-
214
- **HASH256 - SHA256(SHA256(X))**
215
-
216
- All-in-one double sha256 hash helper, that is, first hash with sha256 and than hash with sha256 again. Why? Arguably higher security.
217
-
218
- > SHA256(SHA256(X)) was proposed by Ferguson and Schneier in their excellent book "Practical Cryptography"
219
- > (later updated by Ferguson, Schneier, and Kohno and renamed "Cryptography Engineering") as a way to make SHA256 invulnerable
220
- > to "length-extension" attack. They called it "SHA256D".
221
-
222
-
223
- ``` ruby
224
- hash256( '6fe6b145a3908a4d6616b13c1109717add8672c900' )
225
- #=> "02335f08b8fe4ddad263a50b7a33c5d38ea1cbd8fd2056a1320a3ddece541711"
226
- ```
227
-
228
- #### Base58 Encoding / Decoding Helpers
229
-
230
- **BASE58**
231
-
232
- Base58 encoding / decoding with leading zero bytes (in hex or binary strings) getting encoded from `00` to `1` and back:
233
-
234
- ``` ruby
235
- base58( "516b6fcd0f" ) #=> "ABnLTmg"
236
- base58( "00000000000000000000123456789abcdef0" ) #=> "111111111143c9JGph3DZ"
237
- # or with optional 0x or 0X prefix
238
- base58( "0x516b6fcd0f" ) #=> "ABnLTmg"
239
- base58( "0x00000000000000000000123456789abcdef0" ) #=> "111111111143c9JGph3DZ"
240
-
241
- unbase58( "ABnLTmg" ) #=> "516b6fcd0f"
242
- unbase58( "111111111143c9JGph3DZ" ) #=> "00000000000000000000123456789abcdef0"
243
- ```
244
-
245
-
246
- **BASE58CHECK - BASE58(X || SHA256(SHA256(X))[:4])**
247
-
248
- Base58 encoding with an extra 4-byte secure hash checksum.
249
-
250
- ``` ruby
251
- base58check( "516b6fcd0f" ) #=> "237LSrY9NUUas"
252
- base58check( "00f54a5851e9372b87810a8e60cdd2e7cfd80b6e31" ) #=> "1PMycacnJaSqwwJqjawXBErnLsZ7RkXUAs"
253
-
254
- unbase58check( "237LSrY9NUUas" ) #=> "516b6fcd0f"
255
- unbase58check( "1PMycacnJaSqwwJqjawXBErnLsZ7RkXUAs" ) #=> "00f54a5851e9372b87810a8e60cdd2e7cfd80b6e31"
256
- ```
257
-
258
-
259
-
260
- ### Public Key Signature Algorithms
261
-
262
- **RSA - Rivest, Shamir and Adleman**
263
-
264
-
265
-
266
- ``` ruby
267
- alice_key, alice_pub = RSA.generate_keys
268
-
269
- alice_key
270
- #=> "-----BEGIN RSA PRIVATE KEY-----
271
- # MIIEpAIBAAKCAQEAzLpmAQ+MbUTHU1XxzEaQXqiOvk0Vu/skztaMWz+UoGYWU6eW
272
- # cr7zVt/Y0SYqzD8LkYireX22FxNNFfhgu3/uC5yTl+dri6PD6NDAmrG+1cyE8kZZ
273
- # MGq91wQEemZPuesjTgKEvwZbknjodIKOAP35QycMr4PuWICSrCjhJLrClI7jInTZ
274
- # LOLtD5w5U7/xLOJAIfuhjUA4wrFCLJGPe7214KWgDCLmsan4/GVUloUKa6KAHJiH
275
- # q4tNxNdSrbOlluZbKQl8REhXOCIb5bEX2KnbQT0nPgKkuOlXgZ7jeyOIk0FG1RGa
276
- # FvcGu8LieMgT39WltcHJLblNkDr9YDRGiNiThQIDAQABAoIBAQCE/FPEPqBeXj4I
277
- # MRzHL9MZ2e4XSaVjnYjUXuN/ZnaaFpZMMuF0mfshpHiHq35DfHR8TcXtPi6pIJ2D
278
- # NvtG8JvlqQjqtKXUaEWbFvb1xZ4L7TUy12WaIMw+PlrWU11YjJg7VUF7gJq9M5L0
279
- # E9ZAaLmg2F3SKSYLEUG1WTyeij5ZFqouNjZxD2xo5U5Agy2UVm2D9aUm/n4g8Wnr
280
- # HybadhD6V9+BsZ2e9Q6CamHRah9Hs4nDPnycPFXpbs32wx9nvACPMg5+/Fqxr/ZK
281
- # cPM4syVBW0lNhpTzhHkPvimAgwgqJYvAj/o9nQnq5i1XyVyXp3uKVnld3FCddf9i
282
- # ovQMPmVlAoGBAPHtUKRehy8df/Zw6oGz0WcZCTjEwZ9DEb5rFN9Pr2IyvOhmZ3UJ
283
- # JNx9WmiiGB44dbnafMtr2Ya7u4OAM6e190BbcJKTnpWqVlsXw/wyQqIgJb3AtFu4
284
- # 91mqsDepOWsfs1IjTgmR1OM29WXjGoPHtV9E6//uVmVsciEvkCtcRfGDAoGBANij
285
- # IbZ3mL1rr8uRT/czPLkZ3KPLsJhPriuc6yyOq+tqQ6d3u/1DjKxoeYa7Jbyj7Dwl
286
- # 2wHQf9vRz3Kb2Mw+hPcHGDO9aBWxvZXjxxrVk6g1Ei0mvIP0k8ZbnlReK3cr5ktl
287
- # aY/ZWDDVPpY4aqkcOIbAAi95jPlpb2LsntijxoBXAoGABPJRP8sfAHud7jAI23YN
288
- # xgnhAmQjgVohtr8Bwj8i2uMmsanGW8JAGrIFczY9QADvh0lMW+xsmjCkeN/aLoet
289
- # 8obsGlMiXvUIpvwpabKtYhs+Kk8SYP27MP4odDrljacsR3WpVtDAhZTOF7M5C5C9
290
- # yKDkImuBILnC66LJU9mjJHkCgYEAntDxDSCeQ/dnOBh+hB323UgdXaMdAnwflm+C
291
- # ZPbvCDWuBV6c3W2g+l/Y/7HBV4rgy7OA29KreU5WA5JHHGyU87gqwPuRC55y+yiy
292
- # NXTvu7e0bI9iUmaB00AlUXp76PCw8wMUoVVX9uzN5jjT0MgUlIy8zWsRs2LdOqt3
293
- # RCDEjB8CgYAO6ZptzyJ4FS7ucjKfjig5WMOiKMcIUtTG9qedHmE2Z6vt3g0SQWaD
294
- # zJJacSoRHAdRK61vOlg4k+9/9LjffDrk9uT555BDbYqKWlmST7JMfvO7EpaIMYUu
295
- # CN7+3Rx9gSLyScqtAYiT/LgYgL1Vc6/e0XHaVjA85kPvUDKb785oFg==
296
- # -----END RSA PRIVATE KEY-----"
297
-
298
- alice_pub
299
- #=> "-----BEGIN PUBLIC KEY-----
300
- # MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzLpmAQ+MbUTHU1XxzEaQ
301
- # XqiOvk0Vu/skztaMWz+UoGYWU6eWcr7zVt/Y0SYqzD8LkYireX22FxNNFfhgu3/u
302
- # C5yTl+dri6PD6NDAmrG+1cyE8kZZMGq91wQEemZPuesjTgKEvwZbknjodIKOAP35
303
- # QycMr4PuWICSrCjhJLrClI7jInTZLOLtD5w5U7/xLOJAIfuhjUA4wrFCLJGPe721
304
- # 4KWgDCLmsan4/GVUloUKa6KAHJiHq4tNxNdSrbOlluZbKQl8REhXOCIb5bEX2Knb
305
- # QT0nPgKkuOlXgZ7jeyOIk0FG1RGaFvcGu8LieMgT39WltcHJLblNkDr9YDRGiNiT
306
- # hQIDAQAB
307
- # -----END PUBLIC KEY-----"
308
-
309
- bob_key, bob_pub = RSA.generate_keys
310
-
311
- bob_key
312
- #=> "-----BEGIN RSA PRIVATE KEY-----
313
- # MIIEpAIBAAKCAQEAzADannvKlfVkZmKA4EDIxTW0HiJzjD6Auh8wLi02+iz2BScz
314
- # fECA65Zv+KHfc1B9AWMqGeBIwFE49NrsnXiZwZR3DqcFS8WbnVqpntvhwzlEARna
315
- # RWmZ2XjloD7fxILbXtWfMFNjwSfaK0bpArLkrt9d8eni+JI42+ptIWs/bVynACqm
316
- # DqOTjoEgajuHVpxHtskPNQrsjxzP+umsUWkbE0iaO7oN1pcgZIR4VRr0bz/3Juif
317
- # WmiCgwbDZo1WolfveoCacVsfAB1iesxeWnrGIJUjq8Mqsu9mQz1dg6RF4ElwNJ57
318
- # G3T3nlW+qpVBZDU2sHFqUFxbGmWPdRUn1yn4KwIDAQABAoIBAQCOCwotz4P/Zh3C
319
- # LFQP0Qv6RKplURejTuHStmSVwmXFTAkBDYqLuV4Kq3TLaepsIF7p2GI4IjKFtggy
320
- # dTzLaG2mm/lJ+oF1gOIZbkcslW1cwULYgWe5bQ3ynntEWIL2ESctoRB2VZnfpCAE
321
- # ghs8BdO071I6Xt/qs+VjOpdB7ar8OYhFc1vhwiI03FKbjuScH0CQOETIeLCqK5tC
322
- # qPnjMTYdaTp/NgcZujsOeOBgbARLzGtCaESbmXHO6mPDkEED5uqZzsNBtdCZIGMF
323
- # ApJkZbF6xSRizQhwwRlak1jCkAk2VCYpKPMiop1+cbjs3jU3RyP94RHc/yKo2Rzm
324
- # HCl35XYBAoGBAPJDMV9W2scRsMlLw9In3ZzWtammcouE0oXEgizK61Cg/5C5E06a
325
- # 5anrfwF5bURBANKBqTSHV0u71C2fHs1KO+B+EHzQ4DKsXldCSv2PR/0A6lmF9AIL
326
- # DFfup/mU55plbqCnjJe2BOUrOmurSd5MbWtShRdGri/LBqF58BFgT+U1AoGBANeS
327
- # RZDsCWelZPGN8Wxp9zxhu1AClNO9S7ITjZOQTYlghCVKAkS1wvB/6TIjaw8DyREs
328
- # f6WvtkzQA/vZc4mXE+YM/calL8ee3wVEJJzlGBfuh8mQhxtiLa5PTl7Icv/R8DGV
329
- # 9hU9GkJgWdi/+Plpqdcv79OWVMTB7igmoN8PAPPfAoGAKqatwI04AygYKbhPB2bB
330
- # W2Vpoi6NqAaAUdCg4mXvO8i8daw/u+0FVf8B4y6PkB6pmGX/diIFum2dE1MaRyY0
331
- # mHdZS8AyWHmEOnSPY0igceiBWbV9mgZ769c2d3hBtir5aQtWczc2cWpE5MPJQ3vN
332
- # H8HtcIWfEQb7ad5f548/QakCgYEAwFDjNRYOkePQ+Vrbjg+/HKRH+mpDId9Xv4eI
333
- # H6R2N9/eJHIxMeFCB1Ll1PAaG6wR3ftn6YWnykEtvKpTU+VvQCZI5MYLqTgH2Ofh
334
- # DgOoCfmoNF922SwuerqPvSlwxt8hPOt/PZVkbuEMZr1lPgVRGwPOHmKYP2yPrkw/
335
- # 6p+1BtsCgYABmMLgWhXVD19XxNHm8XpGnPWTEjqAYrw6I5yDUwNhB0n4129qaC+x
336
- # MWrdslKBmQh1r1U5QoSSL0CY4Ef5qN02uZl15FN1kYQzZA6kJi+MoBsjzrZCvzsc
337
- # Bbahpg363PyHC75zgvazvOr4tK3mzaRi5RNTMgivTVu4FyhkRdJ5wQ==
338
- # -----END RSA PRIVATE KEY-----"
339
-
340
- bob_pub
341
- #=> "-----BEGIN PUBLIC KEY-----
342
- # MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzADannvKlfVkZmKA4EDI
343
- # xTW0HiJzjD6Auh8wLi02+iz2BSczfECA65Zv+KHfc1B9AWMqGeBIwFE49NrsnXiZ
344
- # wZR3DqcFS8WbnVqpntvhwzlEARnaRWmZ2XjloD7fxILbXtWfMFNjwSfaK0bpArLk
345
- # rt9d8eni+JI42+ptIWs/bVynACqmDqOTjoEgajuHVpxHtskPNQrsjxzP+umsUWkb
346
- # E0iaO7oN1pcgZIR4VRr0bz/3JuifWmiCgwbDZo1WolfveoCacVsfAB1iesxeWnrG
347
- # IJUjq8Mqsu9mQz1dg6RF4ElwNJ57G3T3nlW+qpVBZDU2sHFqUFxbGmWPdRUn1yn4
348
- # KwIDAQAB
349
- # -----END PUBLIC KEY-----"
350
-
351
-
352
- tx = "from: alice, to: bob, $21"
353
- tx_hash = sha256( tx )
354
- #=> "426a472a6c69bf68354391b7822393bea3952cde9df8949ad7a0f5f405b2fcb5"
355
-
356
- tx_signature = RSA.sign( tx_hash, alice_key )
357
- #=> "xfhzC6tzXYmA5rFAFybJ9KeWnTcTnC0Plt7cSHky6ZSdBZRKz/sfFcpyIN7w
358
- # jWrdPwEREA3nwNu/HSpiGRBFr+lu/YgWGNp6HLGPeL7uHGAfmWPyU5WRzGzf
359
- # iEs5B6kdJ3S8LSbP0hkOD8AOgZLPeU5rzA4+/Ymt8e/UOVwwka6Gj13yoBua
360
- # mSdsVuQfgh2VpySejCz4ykYlMSHK8Kx8QFt+QbyI5QZUy2dFh6HlcnHR+G9A
361
- # RMRZ1vAuQhYqtDSsxwRcZCSFsc6uctAvsgFinhqy6ls5VpcXfuKwZhKAw3Di
362
- # E2MYUnT7+i38Mq26iWzgmDbpOrVCO5tjlSiHY1731A=="
363
-
364
- RSA.valid_signature?( tx_hash, tx_signature, alice_pub )
365
- #=> true
366
-
367
- tx = "from: alice, to: bob, $22"
368
- tx_hash = sha256( tx )
369
- #=> "e899604bb4c95d2f1a7cfe561ad65941769e2064bdbbcaa79eb64ce0a2832380"
370
-
371
- RSA.valid_signature?( tx_hash, tx_signature, alice_pub )
372
- #=> false
373
- ```
374
-
375
-
376
- and some more.
377
-
378
-
379
-
380
-
381
-
382
- ## Examples
383
-
384
- ### Generate the Bitcoin (Base58) Address from the (Elliptic Curve) Public Key
385
-
386
- Let's follow the steps from [How to create Bitcoin Address](https://en.bitcoin.it/wiki/Technical_background_of_version_1_Bitcoin_addresses#How_to_create_Bitcoin_Address):
387
-
388
- ``` ruby
389
- # Lets start with the public key ("raw" hex string encoded)
390
- pk = "0250863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b2352"
391
-
392
- # 1. Perform SHA-256 hashing on the public key
393
- step1 = sha256( pk )
394
- #=> "0b7c28c9b7290c98d7438e70b3d3f7c848fbd7d1dc194ff83f4f7cc9b1378e98"
395
-
396
- # 2. Perform RIPEMD-160 hashing on the result of SHA-256
397
- step2 = ripemd160( step1 )
398
- #=> "f54a5851e9372b87810a8e60cdd2e7cfd80b6e31"
399
-
400
- # 3. Add version byte in front of RIPEMD-160 hash (0x00 for Main Network)
401
- step3 = "00" + step2
402
- #=> "00f54a5851e9372b87810a8e60cdd2e7cfd80b6e31"
403
-
404
- # 4. Perform SHA-256 hash on the extended RIPEMD-160 result
405
- step4 = sha256( step3 )
406
- #=> "ad3c854da227c7e99c4abfad4ea41d71311160df2e415e713318c70d67c6b41c"
407
-
408
- # 5. Perform SHA-256 hash on the result of the previous SHA-256 hash
409
- step5 = sha256( step4 )
410
- #=> "c7f18fe8fcbed6396741e58ad259b5cb16b7fd7f041904147ba1dcffabf747fd"
411
-
412
- # 6. Take the first 4 bytes of the second SHA-256 hash. This is the address checksum
413
- step6 = step5[0..7] # note: 4 bytes in hex string are 8 digits/chars
414
- #=> "c7f18fe8"
415
-
416
- # 7. Add the 4 checksum bytes from step 6 at the end of
417
- # extended RIPEMD-160 hash from step 3.
418
- # This is the 25-byte binary Bitcoin Address.
419
- step7 = step3 + step6
420
- #=> "00f54a5851e9372b87810a8e60cdd2e7cfd80b6e31c7f18fe8"
421
-
422
- # 8. Convert the result from a byte string into a base58 string using Base58 encoding.
423
- # This is the most commonly used Bitcoin Address format.
424
- addr = base58( step7 )
425
- #=> "1PMycacnJaSqwwJqjawXBErnLsZ7RkXUAs"
426
- ```
427
-
428
- Or let's try again with the shortcut helpers:
429
-
430
- - `HASH160 - RMD160(SHA256(X))`
431
- - `BASE58CHECK - BASE58(X || SHA256(SHA256(X))[:4])`
432
-
433
- ``` ruby
434
- # Lets start with the public key ("raw" hex string encoded)
435
- pk = "0250863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b2352"
436
-
437
- # 1. Perform HASH-160 hashing on the public key
438
- # a) Perform SHA-256 hashing on the public key
439
- # b) Perform RIPEMD-160 hashing on the result of SHA-256
440
- step1 = hash160( pk )
441
- #=> "f54a5851e9372b87810a8e60cdd2e7cfd80b6e31"
442
-
443
- # 2. Add version byte in front of RIPEMD-160 hash (0x00 for Main Network)
444
- step2 = "00" + step1
445
- #=> "00f54a5851e9372b87810a8e60cdd2e7cfd80b6e31"
446
-
447
- # 3. Encode with BASE58CHECK
448
- # a) Perform SHA-256 hash on the extended RIPEMD-160 result
449
- # b) Perform SHA-256 hash on the result of the previous SHA-256 hash
450
- # c) Take the first 4 bytes of the second SHA-256 hash. This is the address checksum
451
- # d) Add the 4 checksum bytes at the end of
452
- # extended RIPEMD-160 hash from step 2.
453
- # This is the 25-byte binary Bitcoin Address.
454
- # e) Convert the result from a byte string into a base58 string
455
- # using Base58 encoding.
456
- # This is the most commonly used Bitcoin Address format.
457
- addr = base58check( step2 )
458
- #=> "1PMycacnJaSqwwJqjawXBErnLsZ7RkXUAs"
459
- ```
460
-
461
-
462
- References
463
-
464
- - [How to create Bitcoin Address](https://en.bitcoin.it/wiki/Technical_background_of_version_1_Bitcoin_addresses#How_to_create_Bitcoin_Address)
465
- - [Ruby Quiz #15 - Generate the Bitcoin (Base58) Address from the (Elliptic Curve) Public Key](https://github.com/planetruby/quiz/tree/master/015)
466
-
467
- Bonus: Bitcon Tip - How to Buy Bitcoin (The CO₂-Friendly Way)
468
-
469
- > 1. Take one $50 bill, five $10 bills, or ten $5 bills (I wouldn't recommend change - stay with paper money).
470
- > 2. Go to the bathroom.
471
- > 3. Lift the lid of the loo.
472
- > 4. Throw money in.
473
- > 5. Flush down water.
474
- >
475
- > Congrats! You just purchased $50 worth of Bitcoin - without fucking the planet!
476
- >
477
- > -- Trolly McTrollface, Bitcon Greater Fool Court Jester
478
-
479
- Read more [Crypto Quotes »](https://github.com/openblockchains/crypto-quotes)
480
-
481
-
482
-
483
-
484
- ## Install
485
-
486
- Just install the gem:
487
-
488
- $ gem install crypto-lite
489
-
490
-
491
- ## License
492
-
493
- The scripts are dedicated to the public domain.
494
- Use it as you please with no restrictions whatsoever.
495
-
496
-
497
- ## Questions? Comments?
498
-
499
- Send them along to the [wwwmake forum](http://groups.google.com/group/wwwmake).
500
- Thanks!
501
-
1
+ # crypto-lite - Cryptographic Secure Hash Functions and Public Key Signature Algorithms Made Easy
2
+
3
+
4
+
5
+ * home :: [github.com/rubycocos/blockchain](https://github.com/rubycocos/blockchain)
6
+ * bugs :: [github.com/rubycocos/blockchain/issues](https://github.com/rubycocos/blockchain/issues)
7
+ * gem :: [rubygems.org/gems/crypto-lite](https://rubygems.org/gems/crypto-lite)
8
+ * rdoc :: [rubydoc.info/gems/crypto-lite](http://rubydoc.info/gems/crypto-lite)
9
+
10
+
11
+ ## Usage
12
+
13
+ ### Secure Hashing / Hash Functions
14
+
15
+ **SHA256 - Secure Hash Algorithm (SHA) 256-Bit (32 Bytes)**
16
+
17
+
18
+ ``` ruby
19
+ require 'crypto' ## or use require 'crypto-lite'
20
+
21
+ ## try abc
22
+ sha256( "abc" ) #=> "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
23
+ sha256( "abc".b ) #=> "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
24
+ sha256( "\x61\x62\x63" ) #=> "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
25
+ sha256( 0x616263 ) #=> "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
26
+
27
+ sha256( hex: '616263' ) #=> "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
28
+ sha256( hex: '0x616263' ) #=> "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
29
+ sha256( hex: '0X616263' ) #=> "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
30
+
31
+ # "auto-magic" hex string to binary string conversion heuristic
32
+ sha256( '0x616263' ) #=> "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
33
+ sha256( '0X616263' ) #=> "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
34
+ ```
35
+
36
+
37
+ Bonus Back Stage Tip: How does SHA256 work?
38
+
39
+ Try this [amazing animation of the SHA256 hash function in your very own terminal](https://github.com/in3rsha/sha256-animation) by Greg Walker.
40
+
41
+ More of a code golfer? See [½ Kilo of SHA256](https://idiosyncratic-ruby.com/51-half-kilo-of-sha256.html) by Jan Lelis - yes, the SHA256 algorithm coded (from scratch) in 500 bytes of ruby.
42
+
43
+
44
+ Onwards with more sha256 examples:
45
+
46
+ ``` ruby
47
+ ## try a
48
+ sha256( "a" ) #=> "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb"
49
+ sha256( "\x61" ) #=> "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb"
50
+ sha256( 0b01100001 ) #=> "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb"
51
+ sha256( 0x61 ) #=> "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb"
52
+
53
+ sha256( hex: '61' ) #=> "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb"
54
+ sha256( hex: '0x61' ) #=> "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb"
55
+
56
+ # "auto-magic" hex string to binary string conversion heuristic
57
+ sha256( '0x61' ) #=> "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb"
58
+
59
+
60
+ ## try some more
61
+ sha256( "Hello, Cryptos!" ) #=> "33eedea60b0662c66c289ceba71863a864cf84b00e10002ca1069bf58f9362d5"
62
+ ```
63
+
64
+
65
+ **SHA3-256 - Secure Hashing Algorthim (SHA) 3, 256-Bit (32 Bytes)**
66
+
67
+ ``` ruby
68
+ sha3_256( "Hello, Cryptos!" ) #=> "7dddf4bc9b86352b67e8823e5010ddbd2a90a854469e2517992ca7ca89e5bd58"
69
+ ```
70
+
71
+ Note: Yes, SHA256 vs SHA3-256 / SHA-2 vs SHA-3 the hashing functions are
72
+ different (although the 256-bit hash size output is the same).
73
+ The sha256 hashing function is part of the Secure Hash Algorithm (SHA) 2 family / standards first published in 2001.
74
+ The sha3_256 is part of the (newer) Secure Hash Algorithm (SHA) 3 family / standards first published in 2015
75
+ (and uses the Keccak cryptographic primitive "under the hood").
76
+
77
+
78
+
79
+ **Keccak 256-Bit**
80
+
81
+ ``` ruby
82
+ keccak256( "Hello, Cryptos!" ) #=> "2cf14baa817e931f5cc2dcb63c889619d6b7ae0794fc2223ebadf8e672c776f5"
83
+ ```
84
+
85
+
86
+ #### Aside - Keccak vs SHA3 / Original vs Official
87
+
88
+ In 2004 the U.S. National Institute of Standards and Technology (NIST)
89
+ changed the padding to `SHA3-256(M) = KECCAK [512] (M || 01, 256)`.
90
+ This is different from the padding proposed by the Keccak team in
91
+ the original Keccak SHA-3 submission version 3 (the final, winning version).
92
+ The difference is the additional `'01'` bits appended to the message.
93
+
94
+ To help avoid confusion the "submitted original version 3" SHA-3 Keccak
95
+ hashing is now called "Keccak"
96
+ and the finalized NIST SHA-3 standard "SHA3".
97
+
98
+ Tip: If you don't know what variant of the hash function you have -
99
+ original or official? - check your hash:
100
+
101
+ For keccak 256-bit:
102
+
103
+ ``` ruby
104
+ keccak256( '' ) #=> "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"
105
+ ```
106
+
107
+ For sha3 256-bit:
108
+
109
+ ``` ruby
110
+ sha3_256( '' ) #=> "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a"
111
+ ```
112
+
113
+
114
+
115
+ **RMD / RIPE-MD - RACE¹ Integrity Primitives Evaluation Message Digest 160-Bit**
116
+
117
+ ¹: Research and development in Advanced Communications technologies in Europe
118
+
119
+
120
+ ``` ruby
121
+ rmd160( "Hello, Cryptos!" ) #=>"4d65f7b740bbade4097e1348e15d2a7d52ac5f53"
122
+ # or use the alias / alternate name
123
+ ripemd160( "Hello, Cryptos!" ) #=>"4d65f7b740bbade4097e1348e15d2a7d52ac5f53"
124
+ ```
125
+
126
+
127
+ #### Aside - Hex String `"0x616263"` vs Binary String `"\x61\x62\x63" == "abc"`
128
+
129
+ Note: All hash functions operate on binary strings ("byte arrays")
130
+ and NOT hex strings.
131
+
132
+ Note: For hex strings the `0x` or `0X` prefix is optional.
133
+ Examples of hex strings:
134
+
135
+ ``` ruby
136
+ # hex string binary string ("byte array")
137
+ "61" "\x61" == "a"
138
+ "0x61" "\x61" == "a"
139
+
140
+ "616263" "\x61\x62\x63" == "abc"
141
+ "0x616263" "\x61\x62\x63" == "abc"
142
+ "0X616263" "\x61\x62\x63" == "abc"
143
+
144
+ # or 160-bit hex string (hash)
145
+ "93ce48570b55c42c2af816aeaba06cfee1224fae"
146
+ "0x93ce48570b55c42c2af816aeaba06cfee1224fae"
147
+
148
+ # or 256-bit hex string (hash)
149
+ "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
150
+ "0xba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
151
+ ```
152
+
153
+ You can use `[str].pack( 'H*' )`
154
+ to convert a hex string into a binary string.
155
+ Note: The standard `Array#pack` conversion
156
+ will NOT "auto-magically" cut-off the `0x` or `0X` prefix.
157
+
158
+
159
+ If you know you have a hex string use the `hex:` keyword to pass
160
+ in the arg(ument)
161
+ to the hash function and that will "automagically"
162
+ handle the hex-to-bin conversion for you. Example:
163
+
164
+ ``` ruby
165
+ sha256( hex: '61' ) #=> "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb"
166
+ sha256( hex: '0x61' ) #=> "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb"
167
+
168
+ sha256( hex: '616263' ) #=> "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
169
+ sha256( hex: '0x616263' ) #=> "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
170
+ sha256( hex: '0X616263' ) #=> "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
171
+ ```
172
+
173
+ What about the built-in "auto-magic" hex-to-bin conversion / heuristic?
174
+
175
+ Yes, if your passed in string starts with the
176
+ the `0x` or `0X` prefix the string gets "auto-magically" converted
177
+ to binary. Or if your passed in string is all hexadecimal characters,
178
+ that is, `0-9` and `a-f` and has a minimum length of ten characters.
179
+ Example:
180
+
181
+
182
+ ``` ruby
183
+ # "auto-magic" hex string to binary string conversion heuristic
184
+
185
+ sha256( '0x616263' ) #=> "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
186
+ sha256( '0X616263' ) #=> "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
187
+
188
+ # or without 0x or 0X BUT with minimum heuristic length
189
+ hash160( '02b4632d08485ff1df2db55b9dafd23347d1c47a457072a1e87be26896549a8737' )
190
+ #=> "93ce48570b55c42c2af816aeaba06cfee1224fae"
191
+
192
+ hash256( '6fe6b145a3908a4d6616b13c1109717add8672c900' )
193
+ #=> "02335f08b8fe4ddad263a50b7a33c5d38ea1cbd8fd2056a1320a3ddece541711"
194
+
195
+ # and so on
196
+ ```
197
+
198
+
199
+ #### Hash Function Helpers
200
+
201
+ **HASH160 - RMD160(SHA256(X))**
202
+
203
+ All-in-one "best-of-both-worlds" helper - first hash with sha256 and than hash with rmd160. Why? Get the higher security of sha256 and the smaller size of rmd160.
204
+
205
+
206
+ ``` ruby
207
+ hash160( '02b9d1cc0b793b03b9f64d022e9c67d5f32670b03f636abf0b3147b34123d13990' )
208
+ #=> "e6b145a3908a4d6616b13c1109717add8672c900"
209
+
210
+ hash160( '02b4632d08485ff1df2db55b9dafd23347d1c47a457072a1e87be26896549a8737' )
211
+ #=> "93ce48570b55c42c2af816aeaba06cfee1224fae"
212
+ ```
213
+
214
+
215
+ **HASH256 - SHA256(SHA256(X))**
216
+
217
+ All-in-one double sha256 hash helper, that is, first hash with sha256 and than hash with sha256 again. Why? Arguably higher security.
218
+
219
+ > SHA256(SHA256(X)) was proposed by Ferguson and Schneier in their excellent book "Practical Cryptography"
220
+ > (later updated by Ferguson, Schneier, and Kohno and renamed "Cryptography Engineering") as a way to make SHA256 invulnerable
221
+ > to "length-extension" attack. They called it "SHA256D".
222
+
223
+
224
+ ``` ruby
225
+ hash256( '6fe6b145a3908a4d6616b13c1109717add8672c900' )
226
+ #=> "02335f08b8fe4ddad263a50b7a33c5d38ea1cbd8fd2056a1320a3ddece541711"
227
+ ```
228
+
229
+ #### Base58 Encoding / Decoding Helpers
230
+
231
+ **BASE58**
232
+
233
+ Base58 encoding / decoding with leading zero bytes (in hex or binary strings) getting encoded from `00` to `1` and back:
234
+
235
+ ``` ruby
236
+ base58( "516b6fcd0f" ) #=> "ABnLTmg"
237
+ base58( "00000000000000000000123456789abcdef0" ) #=> "111111111143c9JGph3DZ"
238
+ # or with optional 0x or 0X prefix
239
+ base58( "0x516b6fcd0f" ) #=> "ABnLTmg"
240
+ base58( "0x00000000000000000000123456789abcdef0" ) #=> "111111111143c9JGph3DZ"
241
+
242
+ unbase58( "ABnLTmg" ) #=> "516b6fcd0f"
243
+ unbase58( "111111111143c9JGph3DZ" ) #=> "00000000000000000000123456789abcdef0"
244
+ ```
245
+
246
+
247
+ **BASE58CHECK - BASE58(X || SHA256(SHA256(X))[:4])**
248
+
249
+ Base58 encoding with an extra 4-byte secure hash checksum.
250
+
251
+ ``` ruby
252
+ base58check( "516b6fcd0f" ) #=> "237LSrY9NUUas"
253
+ base58check( "00f54a5851e9372b87810a8e60cdd2e7cfd80b6e31" ) #=> "1PMycacnJaSqwwJqjawXBErnLsZ7RkXUAs"
254
+
255
+ unbase58check( "237LSrY9NUUas" ) #=> "516b6fcd0f"
256
+ unbase58check( "1PMycacnJaSqwwJqjawXBErnLsZ7RkXUAs" ) #=> "00f54a5851e9372b87810a8e60cdd2e7cfd80b6e31"
257
+ ```
258
+
259
+
260
+
261
+ ### Public Key Signature Algorithms
262
+
263
+
264
+ **Elliptic Curve Digital Signature Algorithm (ECDSA)**
265
+
266
+
267
+ Private Key
268
+
269
+ An ECDSA (Elliptic Curve Digital Signature Algorithm) private key is a random number between 1 and the order of the elliptic curve group.
270
+
271
+
272
+ ``` ruby
273
+ # Auto-generate (random) private key
274
+ private_key = EC::PrivateKey.generate # by default uses Secp256k1 curve (used in Bitcoin and Ethereum)
275
+
276
+ private_key.to_i
277
+ #=> 29170346885894798724849267297784761178669026868482995474159965944722616190552
278
+ private_key.to_s
279
+ #=> "407dd4ccde53d30f3a9cda74ceccb247f3997466964786b59e4d68e93e8f8658"
280
+ ```
281
+
282
+
283
+ Derive / (Auto-)Calculate the Public Key - Enter Elliptic Curve (EC) Cryptography
284
+
285
+ The public key (`K`) are two numbers (that is, a point with the coordinates x and y) computed by multiplying
286
+ the generator point (`G`) of the curve with the private key (`k`) e.g. `K=k*G`.
287
+ This is equivalent to adding the generator to itself `k` times.
288
+ Magic?
289
+ Let's try:
290
+
291
+
292
+ ``` ruby
293
+ # This private key is just an example. It should be much more secure!
294
+ private_key = EC::PrivateKey.new( 1234 ) # by default uses Secp256k1 curve (used in Bitcoin and Ethereum)
295
+
296
+ public_key = private_key.public_key ## the "magic" one-way K=k*G curve multiplication (K=public key,k=private key, G=generator point)
297
+ point = public_key.point
298
+
299
+ point.x
300
+ #=> 102884003323827292915668239759940053105992008087520207150474896054185180420338
301
+ point.y
302
+ #=> 49384988101491619794462775601349526588349137780292274540231125201115197157452
303
+
304
+ point.x.to_s(16)
305
+ #=> "e37648435c60dcd181b3d41d50857ba5b5abebe279429aa76558f6653f1658f2"
306
+ point.y.to_s(16)
307
+ #=> "6d2ee9a82d4158f164ae653e9c6fa7f982ed8c94347fc05c2d068ff1d38b304c"
308
+ ```
309
+
310
+
311
+ Sign a transaction with an (elliptic curve) private key:
312
+
313
+ ``` ruby
314
+ # Step 1 - Calculate the Transaction (tx) Hash
315
+ tx = 'from: Alice to: Bob cryptos: 43_000_000_000'
316
+ txhash = sha256( tx )
317
+
318
+ # Step 2 - Get the Signer's Private key
319
+ private_key = EC::PrivateKey.new( 1234 ) # This private key is just an example. It should be much more secure!
320
+
321
+ # Sign!
322
+ signature = private_key.sign( txhash )
323
+ # -or-
324
+ signature = EC.sign( txhash, private_key )
325
+
326
+ signature.r
327
+ #=> 80563021554295584320113598933963644829902821722081604563031030942154621916407
328
+ signature.s
329
+ #=> 58316177618967642068351252425530175807242657664855230973164972803783751708604
330
+
331
+ signature.r.to_s(16)
332
+ #=> "3306a2f81ad2b2f62ebe0faec129545bc772babe1ca5e70f6e56556b406464c0"
333
+ signature.s.to_s(16)
334
+ #=> "4fe202bb0835758f514cd4a0787986f8f6bf303df629dc98c5b1a438a426f49a"
335
+ ```
336
+
337
+
338
+ Verify a signed transaction with an (elliptic curve) public key:
339
+
340
+ ``` ruby
341
+ # Step 1 - Calculate the Transaction (tx) Hash
342
+ tx = 'from: Alice to: Bob cryptos: 43_000_000_000'
343
+ txhash = sha256( tx )
344
+
345
+ # Step 2 - Get the Signer's Public Key
346
+ public_key = EC::PublicKey.new(
347
+ 102884003323827292915668239759940053105992008087520207150474896054185180420338,
348
+ 49384988101491619794462775601349526588349137780292274540231125201115197157452
349
+ )
350
+
351
+ # Step 3 - Get the Transaction's Signature
352
+ signature = EC::Signature.new(
353
+ 80563021554295584320113598933963644829902821722081604563031030942154621916407,
354
+ 58316177618967642068351252425530175807242657664855230973164972803783751708604
355
+ )
356
+
357
+ # Don't Trust - Verify
358
+ public_key.verify?( txhash, signature )
359
+ # -or-
360
+ EC.verify?( txhash, signature, public_key )
361
+ #=> true
362
+
363
+
364
+ # or using hexadecimal numbers
365
+
366
+ public_key = EC::PublicKey.new(
367
+ 0xe37648435c60dcd181b3d41d50857ba5b5abebe279429aa76558f6653f1658f2,
368
+ 0x6d2ee9a82d4158f164ae653e9c6fa7f982ed8c94347fc05c2d068ff1d38b304c
369
+ )
370
+
371
+ signature = EC::Signature.new(
372
+ 0x3306a2f81ad2b2f62ebe0faec129545bc772babe1ca5e70f6e56556b406464c0,
373
+ 0x4fe202bb0835758f514cd4a0787986f8f6bf303df629dc98c5b1a438a426f49a
374
+ )
375
+
376
+ public_key.verify?( txhash, signature )
377
+ # -or-
378
+ EC.verify?( txhash, signature, public_key )
379
+ #=> true
380
+ ```
381
+
382
+
383
+ To sum up:
384
+
385
+ - The (raw) private key is a 256-bit unsigned integer number
386
+ - The (raw) public key is a point (x,y), that is, two 256-bit unsigned integer numbers - derived (calculated) from the private key
387
+ - A (raw) signature is composed of (r,s), that is, two 256-bit unsigned integer numbers
388
+
389
+ That's all the magic.
390
+
391
+
392
+
393
+
394
+
395
+ ## Real-World Examples / Cookbook
396
+
397
+ **Bitcoin Chains**
398
+
399
+ - [Derive the Bitcoin (Elliptic Curve) Public Key from the Private Key](#derive-the-bitcoin-elliptic-curve-public-key-from-the-private-key)
400
+ - [Generate the Bitcoin (Base58) Address from the (Elliptic Curve) Public Key](#generate-the-bitcoin-base58-address-from-the-elliptic-curve-public-key)
401
+ - [Encode the Bitcoin Private Key in the Wallet Import Format (WIF)](#encode-the-bitcoin-private-key-in-the-wallet-import-format-wif)
402
+
403
+ **Dodge "Shiba Inu" Chains**
404
+
405
+ - [Derive the Dodge (Elliptic Curve) Public Key from the Private Key](#derive-the-dodge-elliptic-curve-public-key-from-the-private-key)
406
+ - [Generate the Dodge Address from the (Elliptic Curve) Public Key](#generate-the-dodge-address-from-the-elliptic-curve-public-key)
407
+
408
+
409
+ **Litecoin Chains**
410
+ - [Derive the Litecoin (Elliptic Curve) Public Key from the Private Key](#derive-the-litecoin-elliptic-curve-public-key-from-the-private-key)
411
+ - [Generate the Litecoin Address from the (Elliptic Curve) Public Key](#generate-the-litecoin-address-from-the-elliptic-curve-public-key)
412
+
413
+
414
+
415
+ **Ethereum Chains**
416
+
417
+ - [Derive the Ethereum (Elliptic Curve) Public Key from the Private Key](#derive-the-ethereum-elliptic-curve-public-key-from-the-private-key)
418
+ - [Generate the Ethereum Address from the (Elliptic Curve) Public Key](#generate-the-ethereum-address-from-the-elliptic-curve-public-key)
419
+
420
+
421
+
422
+
423
+ ## Bitcoin (BTC), Bitcoin Cash (BCH), Bitcoin Cash Satoshi Vision (BSV), Bitcoin Cash ABC (BCHA)
424
+
425
+ **Bitcon Public Service Announcement:**
426
+
427
+ > Bitcoin number go up because more people want bitcoin. Bitcoin becomes more and more valuable.
428
+ >
429
+ > - 1,000 HODLers
430
+ > - 10,000 HODLers
431
+ > - 100,000 HODLers
432
+ > - 1,000,000 HODLers
433
+ > - 10,000,000 HODLers
434
+ > - 100,000,000 HODLers
435
+ > - 1,000,000,000 HODLers
436
+ > - 10,000,000,000 HODLers
437
+ > - 100,000,000,000 HODLers and on and on
438
+ >
439
+ > People will come to understand bitcon.
440
+ >
441
+ > -- Dan McArdle, Bitcoin "There is No Alternative", Bitcoin is the New (Gold) Standard
442
+
443
+ **[BEWARE: Yes, Bitcoin Is a Ponzi - Learn How the Investment Fraud Works »](https://github.com/openblockchains/bitcoin-ponzi)**
444
+
445
+
446
+ ### Derive the Bitcoin (Elliptic Curve) Public Key from the Private Key
447
+
448
+ A private key in bitcoin is a 32-byte (256-bit) unsigned / positive integer number.
449
+
450
+ Or more precise the private key is a random number between 1
451
+ and the order of the elliptic curve secp256k1.
452
+
453
+ ``` ruby
454
+ EC::SECP256K1.order
455
+ #=> 115792089237316195423570985008687907852837564279074904382605163141518161494337
456
+
457
+ # or in hexadecimal (base16)
458
+ EC::SECP256K1.order.to_s(16)
459
+ #=> "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"
460
+ ```
461
+
462
+ #### Step 1 - Let's generate a private key
463
+
464
+ ``` ruby
465
+ private_key = EC::PrivateKey.generate # alice
466
+ private_key.to_i
467
+ #=> 50303382071965675924643368363408442017264130870580001935435312336103014915707
468
+ private_key.to_s
469
+ #=> "6f36b48dd130618049ca27e1909debdf3665cf0df0ade0986f0c50123107de7b"
470
+
471
+ private_key = EC::PrivateKey.generate # bob
472
+ private_key.to_i
473
+ #=> 96396065671557366547785856940504404648366202869823009146014078671352808008442
474
+ private_key.to_s
475
+ #=> "d51e3d5ce8fbc6e574cf78d1c46e8936c26f38b002b954d0eac8aef195d6eafa"
476
+ ```
477
+
478
+ Or use your own (secure) random generator.
479
+ Trivia Note: The smallest possible (BUT HIGHLY UNSECURE)
480
+ private key is 1 (not 0).
481
+
482
+ ``` ruby
483
+ def generate_key
484
+ 1 + SecureRandom.random_number( EC::SECP256K1.order - 1 )
485
+ end
486
+
487
+ generate_key # alice
488
+ #=> 66010624277151619503613090016410344678572543187504521309126248385615121289833
489
+
490
+ generate_key # bob
491
+ #=> 10004433477200726182517873544056418402326985168039465080040800405880945722868
492
+ ```
493
+
494
+
495
+ Aside: What's Base 6? Let's Roll the Dice
496
+
497
+ An important part of creating a private key is ensuring the random number
498
+ is truly random.
499
+ Physical randomness is better than computer generated pseudo-randomness.
500
+ The easiest way to generate physical randomness is with a dice.
501
+ To create a private key you only need one six-sided die
502
+ which you roll ninety nine times.
503
+ Stopping each time to record the value of the die.
504
+ When recording the values follow these rules: 1=1, 2=2, 3=3, 4=4, 5=5, 6=0.
505
+ By doing this you are recording the big random number, your private key,
506
+ in base 6 format.
507
+
508
+ ``` ruby
509
+ def roll_dice
510
+ SecureRandom.random_number( 6 ) ## returning 0,1,2,3,4, or 5
511
+ end
512
+
513
+ priv_base6 = 99.times.reduce('') { |buf,_| buf << roll_dice.to_s }
514
+ #=> "413130205513310000115530450343345150251504444013455422453552225503020102150031231134314351124254004"
515
+ ```
516
+
517
+ Exercise:
518
+ Turn the ninety nine character base 6 private key into a base 10 or base 16 number.
519
+
520
+ ``` ruby
521
+ priv = priv_base6.to_i(6) ## convert to decimal (base 10) from roll-the-dice (base 6) string
522
+ #=> 77254760463198588454157792320308725646096652667800343330432100522222375944308
523
+ priv.to_s(16)
524
+ #=> "aacca516ccbf72dac2c4c447b9f64d12855685e99810ffcf7763a12da6c04074"
525
+ ```
526
+
527
+
528
+ Aside: What's Base 2? Let's Flip A Coin - Heads or Tails?
529
+
530
+ Triva Quiz: For an (unsigned) 256-bit number - how many times
531
+ do you need to flip the coin?
532
+
533
+
534
+
535
+
536
+ #### Step 2 - Let's derive / calculate the public key from the private key - Enter elliptic curve (EC) cryptography
537
+
538
+ The public key (`K`) are two numbers (that is, a point with the coordinates x and y) computed by multiplying
539
+ the generator point (`G`) of the curve with the private key (`k`) e.g. `K=k*G`.
540
+ This is equivalent to adding the generator to itself `k` times.
541
+ Magic?
542
+ Let's try:
543
+
544
+
545
+ ``` ruby
546
+ # note: by default uses Secp256k1 curve (used in Bitcoin)
547
+ private_key = EC::PrivateKey.new( 50303382071965675924643368363408442017264130870580001935435312336103014915707 )
548
+
549
+ public_key = private_key.public_key ## the "magic" one-way K=k*G curve multiplication (K=public key,k=private key, G=generator point)
550
+ point = public_key.point
551
+
552
+ point.x
553
+ #=> 17761672841523182714332746445483761684317159074072585653954580096478387916431
554
+ point.y
555
+ #=> 81286693084077906561204577435230199871025343781583806206090259868058973358862
556
+ ```
557
+
558
+ and convert the point to the compressed or uncompressed
559
+ Standards for Efficient Cryptography (SEC)
560
+ format used in Bitcoin:
561
+
562
+ ``` ruby
563
+ point.to_s( :compressed )
564
+ #=> "022744c02580b4905349bc481a60c308c2d98d823d44888835047f6bc5c38c4e8f"
565
+ point.to_s( :uncompressed )
566
+ #=> "042744c02580b4905349bc481a60c308c2d98d823d44888835047f6bc5c38c4e8fb3b6a34b90a571f6c2a1113dd5ff4576f61bbf3e970a6e148fa02bf9eb7bcb0e"
567
+ ```
568
+
569
+
570
+ References
571
+
572
+ - [Private key @ Learn me a bitcoin](https://learnmeabitcoin.com/technical/private-key)
573
+ - [Public key @ Learn me a bitcoin](https://learnmeabitcoin.com/technical/public-key)
574
+
575
+
576
+ ### Generate the Bitcoin (Base58) Address from the (Elliptic Curve) Public Key
577
+
578
+ Let's follow the steps from [How to create Bitcoin Address](https://en.bitcoin.it/wiki/Technical_background_of_version_1_Bitcoin_addresses#How_to_create_Bitcoin_Address):
579
+
580
+ ``` ruby
581
+ # Lets start with the public key ("raw" hex string encoded in compressed format)
582
+ pk = "0250863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b2352"
583
+
584
+ # 1. Perform SHA-256 hashing on the public key
585
+ step1 = sha256( pk )
586
+ #=> "0b7c28c9b7290c98d7438e70b3d3f7c848fbd7d1dc194ff83f4f7cc9b1378e98"
587
+
588
+ # 2. Perform RIPEMD-160 hashing on the result of SHA-256
589
+ step2 = ripemd160( step1 )
590
+ #=> "f54a5851e9372b87810a8e60cdd2e7cfd80b6e31"
591
+
592
+ # 3. Add version byte in front of RIPEMD-160 hash (0x00 for Bitcoin Main Network)
593
+ step3 = "00" + step2
594
+ #=> "00f54a5851e9372b87810a8e60cdd2e7cfd80b6e31"
595
+
596
+ # 4. Perform SHA-256 hash on the extended RIPEMD-160 result
597
+ step4 = sha256( step3 )
598
+ #=> "ad3c854da227c7e99c4abfad4ea41d71311160df2e415e713318c70d67c6b41c"
599
+
600
+ # 5. Perform SHA-256 hash on the result of the previous SHA-256 hash
601
+ step5 = sha256( step4 )
602
+ #=> "c7f18fe8fcbed6396741e58ad259b5cb16b7fd7f041904147ba1dcffabf747fd"
603
+
604
+ # 6. Take the first 4 bytes of the second SHA-256 hash. This is the address checksum
605
+ step6 = step5[0..7] # note: 4 bytes in hex string are 8 digits/chars
606
+ #=> "c7f18fe8"
607
+
608
+ # 7. Add the 4 checksum bytes from step 6 at the end of
609
+ # extended RIPEMD-160 hash from step 3.
610
+ # This is the 25-byte binary Bitcoin Address.
611
+ step7 = step3 + step6
612
+ #=> "00f54a5851e9372b87810a8e60cdd2e7cfd80b6e31c7f18fe8"
613
+
614
+ # 8. Convert the result from a byte string into a base58 string using Base58 encoding.
615
+ # This is the most commonly used Bitcoin Address format.
616
+ addr = base58( step7 )
617
+ #=> "1PMycacnJaSqwwJqjawXBErnLsZ7RkXUAs"
618
+ ```
619
+
620
+ Or let's try again with the shortcut helpers:
621
+
622
+ - `HASH160 - RMD160(SHA256(X))`
623
+ - `BASE58CHECK - BASE58(X || SHA256(SHA256(X))[:4])`
624
+
625
+ ``` ruby
626
+ # Lets start with the public key ("raw" hex string encoded in compressed format)
627
+ pk = "0250863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b2352"
628
+
629
+ # 1. Perform HASH-160 hashing on the public key
630
+ # a) Perform SHA-256 hashing on the public key
631
+ # b) Perform RIPEMD-160 hashing on the result of SHA-256
632
+ step1 = hash160( pk )
633
+ #=> "f54a5851e9372b87810a8e60cdd2e7cfd80b6e31"
634
+
635
+ # 2. Add version byte in front of RIPEMD-160 hash (0x00 for Bitoin Main Network)
636
+ step2 = "00" + step1
637
+ #=> "00f54a5851e9372b87810a8e60cdd2e7cfd80b6e31"
638
+
639
+ # 3. Encode with BASE58CHECK
640
+ # a) Perform SHA-256 hash on the extended RIPEMD-160 result
641
+ # b) Perform SHA-256 hash on the result of the previous SHA-256 hash
642
+ # c) Take the first 4 bytes of the second SHA-256 hash. This is the address checksum
643
+ # d) Add the 4 checksum bytes at the end of
644
+ # extended RIPEMD-160 hash from step 2.
645
+ # This is the 25-byte binary Bitcoin Address.
646
+ # e) Convert the result from a byte string into a base58 string
647
+ # using Base58 encoding.
648
+ # This is the most commonly used Bitcoin Address format.
649
+ addr = base58check( step2 )
650
+ #=> "1PMycacnJaSqwwJqjawXBErnLsZ7RkXUAs"
651
+ ```
652
+
653
+
654
+ References
655
+
656
+ - [How to create Bitcoin Address](https://en.bitcoin.it/wiki/Technical_background_of_version_1_Bitcoin_addresses#How_to_create_Bitcoin_Address)
657
+ - [Ruby Quiz #15 - Generate the Bitcoin (Base58) Address from the (Elliptic Curve) Public Key](https://github.com/planetruby/quiz/tree/master/015)
658
+
659
+
660
+
661
+ ### Encode the Bitcoin Private Key in the Wallet Import Format (WIF)
662
+
663
+
664
+ A Wallet Import Format (WIF) private key is a standard private key, but with a few added extras:
665
+
666
+ - Version Byte prefix - The network the private key is to be used on.
667
+ - `0x80` = Mainnet
668
+ - `0xEF` = Testnet
669
+ - Compression Byte suffix (optional) - Flag if the private key is used to create a compressed public key.
670
+ - `0x01`
671
+ - Checksum - Useful for detecting errors/typos when you type out your private key; calculated using the first 4 bytes of the double sha256 hash `SHA256(SHA256(X))[:4]`.
672
+
673
+ This is all then converted to Base58, which shortens the string and makes it easier to transcribe.
674
+
675
+ ``` ruby
676
+ privatekey = "ef235aacf90d9f4aadd8c92e4b2562e1d9eb97f0df9ba3b508258739cb013db2"
677
+ extended = "80" + privatekey + "01"
678
+ #=> "80ef235aacf90d9f4aadd8c92e4b2562e1d9eb97f0df9ba3b508258739cb013db201"
679
+ checksum = hash256( extended )[0..7]
680
+ #=> "66557e53"
681
+ extendedchecksum = extended + checksum
682
+ #=> "80ef235aacf90d9f4aadd8c92e4b2562e1d9eb97f0df9ba3b508258739cb013db20166557e53"
683
+ wif = base58( extendedchecksum )
684
+ #=> "L5EZftvrYaSudiozVRzTqLcHLNDoVn7H5HSfM9BAN6tMJX8oTWz6"
685
+ ```
686
+
687
+ Or let's try again with the base58check (`BASE58(X || SHA256(SHA256(X))[:4])`) shortcut helper:
688
+
689
+ ``` ruby
690
+ privatekey = "ef235aacf90d9f4aadd8c92e4b2562e1d9eb97f0df9ba3b508258739cb013db2"
691
+ extended = "80" + privatekey + "01"
692
+ #=> "80ef235aacf90d9f4aadd8c92e4b2562e1d9eb97f0df9ba3b508258739cb013db201"
693
+ wif = base58check( extended )
694
+ #=> "L5EZftvrYaSudiozVRzTqLcHLNDoVn7H5HSfM9BAN6tMJX8oTWz6"
695
+ ```
696
+
697
+ References
698
+
699
+ - [How to create a WIF private key @ Learn me a bitcoin](https://learnmeabitcoin.com/technical/wif)
700
+ - [Private key to WIF @ Wallet import format](https://en.bitcoin.it/wiki/Wallet_import_format)
701
+
702
+
703
+ Bonus: Bitcon Tip - How to Buy Bitcoin (The CO₂-Friendly Way)
704
+
705
+ > 1. Take one $50 bill, five $10 bills, or ten $5 bills (I wouldn't recommend change - stay with paper money).
706
+ > 2. Go to the bathroom.
707
+ > 3. Lift the lid of the loo.
708
+ > 4. Throw money in.
709
+ > 5. Flush down water.
710
+ >
711
+ > Congrats! You just purchased $50 worth of Bitcoin - without fucking the planet!
712
+ >
713
+ > -- Trolly McTrollface, Bitcon Greater Fool Court Jester
714
+
715
+ Read more [Crypto Quotes »](https://github.com/openblockchains/crypto-quotes)
716
+
717
+
718
+
719
+
720
+
721
+ ## Dodge
722
+
723
+ > Even fun money is money, and a toy cryptocurrency can be turned into real money;
724
+ > the supply of gullibility is deep, if not infinite.
725
+ > So the shibes started dreaming of getting rich for free...
726
+ >
727
+ > -- David Gerard, [Confused About Dogecoin? Here's How It (Doesn't) Work](https://foreignpolicy.com/2021/02/11/dogecoin-how-does-it-work-elon-musk-cryptocurrency/)
728
+ >
729
+ >
730
+ > Dogecoin is the people's crypto.
731
+ > The future currency of earth and mars. Much wow!
732
+ >
733
+ > -- Elon Musk, [February 2021](https://twitter.com/elonmusk/status/1357241340313141249)
734
+
735
+ <!--
736
+ sources:
737
+ https://twitter.com/elonmusk/status/1357241340313141249
738
+ https://twitter.com/elonmusk/status/1357914696645414913
739
+ https://twitter.com/elonmusk/status/1357902434580918274
740
+ -->
741
+
742
+
743
+
744
+ ### Derive the Dodge (Elliptic Curve) Public Key from the Private Key
745
+
746
+ Short version: Same as in Ethereum, Bitcoin, Litecoin
747
+
748
+ Long version:
749
+ A private key in dodge is a 32-byte (256-bit) unsigned / positive integer number.
750
+
751
+ Or more precise the private key is a random number between 1
752
+ and the order of the elliptic curve secp256k1.
753
+
754
+
755
+ ``` ruby
756
+ EC::SECP256K1.order
757
+ #=> 115792089237316195423570985008687907852837564279074904382605163141518161494337
758
+
759
+ # or in hexadecimal (base16)
760
+ EC::SECP256K1.order.to_s(16)
761
+ #=> "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"
762
+ ```
763
+
764
+
765
+ #### Step 1 - Let's generate a private key
766
+
767
+ ``` ruby
768
+ private_key = EC::PrivateKey.generate # alice
769
+ private_key.to_i
770
+ #=> 50303382071965675924643368363408442017264130870580001935435312336103014915707
771
+ private_key.to_s
772
+ #=> "6f36b48dd130618049ca27e1909debdf3665cf0df0ade0986f0c50123107de7b"
773
+
774
+ private_key = EC::PrivateKey.generate # bob
775
+ private_key.to_i
776
+ #=> 96396065671557366547785856940504404648366202869823009146014078671352808008442
777
+ private_key.to_s
778
+ #=> "d51e3d5ce8fbc6e574cf78d1c46e8936c26f38b002b954d0eac8aef195d6eafa"
779
+ ```
780
+
781
+
782
+ #### Step 2 - Let's derive / calculate the public key from the private key - Enter elliptic curve (EC) cryptography
783
+
784
+ The public key (`K`) are two numbers (that is, a point with the coordinates x and y) computed by multiplying
785
+ the generator point (`G`) of the curve with the private key (`k`) e.g. `K=k*G`.
786
+ This is equivalent to adding the generator to itself `k` times.
787
+ Magic?
788
+ Let's try:
789
+
790
+
791
+ ``` ruby
792
+ # note: by default uses Secp256k1 curve (used in Dodge)
793
+ private_key = EC::PrivateKey.new( 50303382071965675924643368363408442017264130870580001935435312336103014915707 )
794
+
795
+ public_key = private_key.public_key ## the "magic" one-way K=k*G curve multiplication (K=public key,k=private key, G=generator point)
796
+ point = public_key.point
797
+
798
+ point.x
799
+ #=> 17761672841523182714332746445483761684317159074072585653954580096478387916431
800
+ point.y
801
+ #=> 81286693084077906561204577435230199871025343781583806206090259868058973358862
802
+ ```
803
+
804
+ and convert the point to the compressed or uncompressed
805
+ Standards for Efficient Cryptography (SEC)
806
+ format used in Dodge:
807
+
808
+ ``` ruby
809
+ point.to_s( :compressed )
810
+ #=> "022744c02580b4905349bc481a60c308c2d98d823d44888835047f6bc5c38c4e8f"
811
+ point.to_s( :uncompressed )
812
+ #=> "042744c02580b4905349bc481a60c308c2d98d823d44888835047f6bc5c38c4e8fb3b6a34b90a571f6c2a1113dd5ff4576f61bbf3e970a6e148fa02bf9eb7bcb0e"
813
+ ```
814
+
815
+ ### Generate the Dodge Address from the (Elliptic Curve) Public Key
816
+
817
+ Short version:
818
+ Same as bitcoin or litecoin.
819
+ Only difference - Add the version byte `0x1e` prefix for Dodge Main Network - P2PKH (pay to public key hash).
820
+
821
+
822
+ Long version:
823
+ Let's use the shortcut hash function helpers:
824
+
825
+ - `HASH160 - RMD160(SHA256(X))`
826
+ - `BASE58CHECK - BASE58(X || SHA256(SHA256(X))[:4])`
827
+
828
+ ``` ruby
829
+ # Lets start with the public key ("raw" hex string encoded in compressed format)
830
+ pk = "022744c02580b4905349bc481a60c308c2d98d823d44888835047f6bc5c38c4e8f"
831
+
832
+ # 1. Perform HASH-160 hashing on the public key
833
+ # a) Perform SHA-256 hashing on the public key
834
+ # b) Perform RIPEMD-160 hashing on the result of SHA-256
835
+ step1 = hash160( pk )
836
+ #=> "a1f37969bcb547cd9c3a28fa07c2269ef813340a"
837
+
838
+ # 2. Add version byte in front of RIPEMD-160 hash (0x1e for Dodge Main Network)
839
+ step2 = "1e" + step1
840
+ #=> "1ea1f37969bcb547cd9c3a28fa07c2269ef813340a"
841
+
842
+ # 3. Encode with BASE58CHECK
843
+ # a) Perform SHA-256 hash on the extended RIPEMD-160 result
844
+ # b) Perform SHA-256 hash on the result of the previous SHA-256 hash
845
+ # c) Take the first 4 bytes of the second SHA-256 hash. This is the address checksum
846
+ # d) Add the 4 checksum bytes at the end of
847
+ # extended RIPEMD-160 hash from step 2.
848
+ # This is the 25-byte binary Dodge Address.
849
+ # e) Convert the result from a byte string into a base58 string
850
+ # using Base58 encoding.
851
+ # This is the most commonly used Dodge Address format.
852
+ addr = base58check( step2 )
853
+ #=> "DKuR12onkdp5GxC5c8DgXhGe4Z2AqCK3Xh"
854
+ ```
855
+
856
+
857
+ ## Litecoin
858
+
859
+ ### Derive the Litecoin (Elliptic Curve) Public Key from the Private Key
860
+
861
+ Short version: Same as in Ethereum, Bitcoin, Dodge.
862
+
863
+ ### Generate the Litecoin Address from the (Elliptic Curve) Public Key
864
+
865
+ Short version: Same as in Bitcoin or Dodge.
866
+ Only difference - Add the version byte `0x30` prefix for Litecoin Main Network - P2PKH (pay to public key hash).
867
+
868
+
869
+
870
+
871
+
872
+ ## Ethereum
873
+
874
+ ### Derive the Ethereum (Elliptic Curve) Public Key from the Private Key
875
+
876
+ A private key in ethereum is a 32-byte (256-bit) unsigned / positive integer number.
877
+
878
+ Or more precise the private key is a random number between 1
879
+ and the order of the elliptic curve secp256k1.
880
+
881
+
882
+ ``` ruby
883
+ EC::SECP256K1.order
884
+ #=> 115792089237316195423570985008687907852837564279074904382605163141518161494337
885
+
886
+ # or in hexadecimal (base16)
887
+ EC::SECP256K1.order.to_s(16)
888
+ #=> "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"
889
+ ```
890
+
891
+ Note: A "raw" private key in ethereum is the same as in bitcoin, litecoin, dodge & co using the same elliptic curve secp256k1.
892
+ See [Derive the Bitcoin (Elliptic Curve) Public Key from the Private Key](#derive-the-bitcoin-elliptic-curve-public-key-from-the-private-key) above.
893
+
894
+
895
+
896
+ #### Step 1 - Let's generate a private key
897
+
898
+ ``` ruby
899
+ private_key = EC::PrivateKey.generate # alice
900
+ private_key.to_i
901
+ #=> 50303382071965675924643368363408442017264130870580001935435312336103014915707
902
+ private_key.to_s
903
+ #=> "6f36b48dd130618049ca27e1909debdf3665cf0df0ade0986f0c50123107de7b"
904
+
905
+ private_key = EC::PrivateKey.generate # bob
906
+ private_key.to_i
907
+ #=> 96396065671557366547785856940504404648366202869823009146014078671352808008442
908
+ private_key.to_s
909
+ #=> "d51e3d5ce8fbc6e574cf78d1c46e8936c26f38b002b954d0eac8aef195d6eafa"
910
+ ```
911
+
912
+ Or use your own (secure) random number.
913
+ Let's follow along the example
914
+ in the [Mastering Ethereum book](https://github.com/ethereumbook/ethereumbook/blob/develop/04keys-addresses.asciidoc#generating-a-private-key-from-a-random-number) and let's use the random number:
915
+ `0xf8f8a2f43c8376ccb0871305060d7b27b0554d2cc72bccf41b2705608452f315`.
916
+
917
+ ``` ruby
918
+ private_key = EC::PrivateKey.new( 0xf8f8a2f43c8376ccb0871305060d7b27b0554d2cc72bccf41b2705608452f315 )
919
+ private_key.to_i
920
+ #=> 112612889188223089164322846106333497020645518262799935528047458345719983960853
921
+ private_key.to_s
922
+ #=> "f8f8a2f43c8376ccb0871305060d7b27b0554d2cc72bccf41b2705608452f315"
923
+ ```
924
+
925
+ #### Step 2 - Let's derive / calculate the public key from the private key - Enter elliptic curve (EC) cryptography
926
+
927
+ The public key (`K`) are two numbers (that is, a point with the coordinates x and y) computed by multiplying
928
+ the generator point (`G`) of the curve with the private key (`k`) e.g. `K=k*G`.
929
+ This is equivalent to adding the generator to itself `k` times.
930
+ Magic?
931
+ Let's try:
932
+
933
+
934
+ ``` ruby
935
+ # note: by default uses Secp256k1 curve (used in Ethereum)
936
+ private_key = EC::PrivateKey.new( 0xf8f8a2f43c8376ccb0871305060d7b27b0554d2cc72bccf41b2705608452f315 )
937
+
938
+ public_key = private_key.public_key ## the "magic" one-way K=k*G curve multiplication (K=public key,k=private key, G=generator point)
939
+ point = public_key.point
940
+
941
+ point.x
942
+ #=> 17761672841523182714332746445483761684317159074072585653954580096478387916431
943
+ point.y
944
+ #=> 81286693084077906561204577435230199871025343781583806206090259868058973358862
945
+
946
+ # or in hexa(decimal) - base 16
947
+ point.x.to_s(16)
948
+ #=> "6e145ccef1033dea239875dd00dfb4fee6e3348b84985c92f103444683bae07b"
949
+ point.y.to_s(16)
950
+ #=> "83b5c38e5e2b0c8529d7fa3f64d46daa1ece2d9ac14cab9477d042c84c32ccd0"
951
+ ```
952
+
953
+ and convert the point to the raw uncompressed
954
+ format used in Ethereum:
955
+
956
+ ``` ruby
957
+ ## add together the two points (x,y) in a hex string
958
+ "%64x%64x" % [point.x, point.y]
959
+ #=> "6e145ccef1033dea239875dd00dfb4fee6e3348b84985c92f103444683bae07b83b5c38e5e2b0c8529d7fa3f64d46daa1ece2d9ac14cab9477d042c84c32ccd0"
960
+
961
+ # or
962
+ ("%64x" % point.x) + ("%64x" % point.y)
963
+ #=> "6e145ccef1033dea239875dd00dfb4fee6e3348b84985c92f103444683bae07b83b5c38e5e2b0c8529d7fa3f64d46daa1ece2d9ac14cab9477d042c84c32ccd0"
964
+ ```
965
+
966
+ References
967
+
968
+ - [Keys and Addresses in Mastering Ethereum](https://github.com/ethereumbook/ethereumbook/blob/develop/04keys-addresses.asciidoc#keys-and-addresses)
969
+
970
+
971
+
972
+ ### Generate the Ethereum Address from the (Elliptic Curve) Public Key
973
+
974
+ Let's again follow along the example
975
+ in the [Mastering Ethereum book](https://github.com/ethereumbook/ethereumbook/blob/develop/04keys-addresses.asciidoc#ethereum-addresses) and let's (re)use the public key (from above):
976
+
977
+
978
+ Step 1: Use the keccak256 hashing function
979
+ to calculate the hash of the public key
980
+
981
+ ``` ruby
982
+ pub = "6e145ccef1033dea239875dd00dfb4fee6e3348b84985c92f103444683bae07b83b5c38e5e2b0c8529d7fa3f64d46daa1ece2d9ac14cab9477d042c84c32ccd0"
983
+ hash = keccak256( pub )
984
+ #=> "2a5bc342ed616b5ba5732269001d3f1ef827552ae1114027bd3ecf1f086ba0f9"
985
+ ```
986
+
987
+ Step 2: Keep only the last 20 bytes (least significant bytes), this is the ethereum address
988
+
989
+ ``` ruby
990
+ hash[24,40] ## last 20 bytes of 32 (skip first 12 bytes (12x2=24 hex chars))
991
+ hash[-40..-1] ## -or- last 20 bytes (40 hex chars)
992
+ hash[-40,40] ## -or- last 20 bytes (40 hex chars)
993
+ #=> "001d3f1ef827552ae1114027bd3ecf1f086ba0f9"
994
+ ```
995
+
996
+ Note: Most often you will see ethereum addresses with the prefix `0x` that indicates
997
+ they are hexadecimal-encoded, like this: `0x001d3f1ef827552ae1114027bd3ecf1f086ba0f9`.
998
+
999
+ References
1000
+
1001
+ - [Keys and Addresses in Mastering Ethereum](https://github.com/ethereumbook/ethereumbook/blob/develop/04keys-addresses.asciidoc#keys-and-addresses)
1002
+
1003
+
1004
+
1005
+
1006
+ ## Install
1007
+
1008
+ Just install the gem:
1009
+
1010
+ $ gem install crypto-lite
1011
+
1012
+
1013
+ ## License
1014
+
1015
+ The scripts are dedicated to the public domain.
1016
+ Use it as you please with no restrictions whatsoever.
1017
+
1018
+
1019
+ ## Questions? Comments?
1020
+
1021
+ Send them along to the [wwwmake forum](http://groups.google.com/group/wwwmake).
1022
+ Thanks!
1023
+