crypto-lite 0.2.3 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +3 -3
- data/README.md +1023 -501
- data/Rakefile +34 -33
- data/lib/crypto/lite.rb +2 -2
- data/lib/crypto-lite/config.rb +32 -32
- data/lib/crypto-lite/helper.rb +25 -25
- data/lib/crypto-lite/metal.rb +135 -128
- data/lib/crypto-lite/sign_rsa.rb +29 -29
- data/lib/crypto-lite/version.rb +23 -23
- data/lib/crypto-lite.rb +145 -147
- data/lib/crypto.rb +2 -2
- data/test/helper.rb +11 -11
- data/test/test_base58.rb +36 -36
- data/test/test_bitcoin_addr.rb +58 -58
- data/test/test_hash.rb +47 -47
- data/test/test_hash_sha.rb +90 -87
- data/test/test_version.rb +19 -19
- metadata +21 -7
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/
|
6
|
-
* bugs :: [github.com/
|
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
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
sha256( "
|
49
|
-
sha256(
|
50
|
-
sha256(
|
51
|
-
|
52
|
-
|
53
|
-
sha256( hex: '
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
The
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
"
|
138
|
-
|
139
|
-
|
140
|
-
"
|
141
|
-
"
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
"
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
"
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
sha256( hex: '
|
166
|
-
|
167
|
-
|
168
|
-
sha256( hex: '
|
169
|
-
sha256( hex: '
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
sha256( '
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
> (
|
220
|
-
>
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
base58( "
|
237
|
-
|
238
|
-
|
239
|
-
base58( "
|
240
|
-
|
241
|
-
|
242
|
-
unbase58( "
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
base58check( "
|
253
|
-
|
254
|
-
|
255
|
-
unbase58check( "
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
#
|
274
|
-
#
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
#
|
294
|
-
#
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
#
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
#
|
319
|
-
#
|
320
|
-
|
321
|
-
#
|
322
|
-
|
323
|
-
#
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
#
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
#
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
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
|
+
|