crypto-lite 0.3.0 → 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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +3 -3
- data/README.md +1023 -511
- data/Rakefile +34 -34
- 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 -148
- 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 +7 -7
data/README.md
CHANGED
@@ -1,511 +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
|
-
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
|
-
#=>
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
point.
|
298
|
-
|
299
|
-
point.
|
300
|
-
#=>
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
point.
|
305
|
-
#=> "
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
#
|
320
|
-
|
321
|
-
#
|
322
|
-
signature =
|
323
|
-
|
324
|
-
signature.
|
325
|
-
|
326
|
-
signature.
|
327
|
-
#=>
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
signature.
|
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
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
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
|
+
|