crypto-lite 0.1.0 → 0.3.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d7c97262d69928c8f9b51816fcf3fff1f5bc61ba5bf49bc81d011ec9567be877
4
- data.tar.gz: bfb41f345684cc2f27256e64d95f4a4535b908784f6353643bfef251c83262b7
3
+ metadata.gz: e32db0712ee1ed53c0720f9dee44533ffb8482e3d9ac6f5bd7a7e6a5c716cdc8
4
+ data.tar.gz: c3e8da15486a23e26d72c97c96bfc4f4c1847c420e7bff833c0ed87efe61303c
5
5
  SHA512:
6
- metadata.gz: 450adb10806e9944fafc4fdf04bb3b09a59fa6fc20ac62a8c9b48b780711ef23555174765b7f545ded98607185bad5488f116a691b34d253de7b7cd30d84fd62
7
- data.tar.gz: 524b2c9ae838156c20eb313a045057974e51339e912c48f6945864429ecfd958a7cc8236a83fbbd0121ebc119c2b4a0e76b4b55383b9e64e9ccee35363e912ea
6
+ metadata.gz: a6593de7e55dbaa353cef41df3cf25cf04fd17cef78f9e2c62fbdcf0bf234627e4ec0dc2f238a341d5de8fa8b3ae33045cb8cf468c80f5ea8a55f312ff7cc0a0
7
+ data.tar.gz: 2e54d60bd80f34568ff7a6852fc3da01d3066131d4c177c023c1c15b4497fe18af7ad28851668b9c45223cab4f7eb8089759fc9e51fac714820b4a7d3a509ef7
@@ -3,9 +3,16 @@ Manifest.txt
3
3
  README.md
4
4
  Rakefile
5
5
  lib/crypto-lite.rb
6
+ lib/crypto-lite/config.rb
7
+ lib/crypto-lite/helper.rb
8
+ lib/crypto-lite/metal.rb
9
+ lib/crypto-lite/sign_rsa.rb
6
10
  lib/crypto-lite/version.rb
7
11
  lib/crypto.rb
8
12
  lib/crypto/lite.rb
9
13
  test/helper.rb
14
+ test/test_base58.rb
15
+ test/test_bitcoin_addr.rb
10
16
  test/test_hash.rb
17
+ test/test_hash_sha.rb
11
18
  test/test_version.rb
data/README.md CHANGED
@@ -12,31 +12,49 @@
12
12
 
13
13
  ### Secure Hashing / Hash Functions
14
14
 
15
- SHA256 - Secure Hash Algorithm (SHA) 256-bits (32 bytes)
15
+ **SHA256 - Secure Hash Algorithm (SHA) 256-Bit (32 Bytes)**
16
16
 
17
17
 
18
18
  ``` ruby
19
19
  require 'crypto' ## or use require 'crypto-lite'
20
20
 
21
21
  ## try abc
22
- sha256( "abc" ) #=> "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
23
- sha256( "abc".b ) #=> "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
24
- sha256( "\x61\x62\x63" ) #=> "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
25
- sha256( 0x616263 ) #=> "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
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.
26
42
 
27
- pp sha256hex( '616263' ) #=> "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
28
- pp sha256hex( '0x616263' ) #=> "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
29
- pp sha256hex( '0X616263' ) #=> "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
30
43
 
44
+ Onwards with more sha256 examples:
31
45
 
46
+ ``` ruby
32
47
  ## try a
33
48
  sha256( "a" ) #=> "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb"
34
49
  sha256( "\x61" ) #=> "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb"
35
50
  sha256( 0b01100001 ) #=> "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb"
36
51
  sha256( 0x61 ) #=> "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb"
37
52
 
38
- sha256hex( '61' ) #=> "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb"
39
- sha256hex( '0x61' ) #=> "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb"
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"
40
58
 
41
59
 
42
60
  ## try some more
@@ -44,125 +62,431 @@ sha256( "Hello, Cryptos!" ) #=> "33eedea60b0662c66c289ceba71863a864cf84b00e1000
44
62
  ```
45
63
 
46
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
+
47
259
 
48
260
 
49
261
  ### Public Key Signature Algorithms
50
262
 
51
- RSA - Rivest-Shamir-Adleman
52
-
53
-
54
-
55
- ``` ruby
56
- alice_key, alice_pub = RSA.generate_keys
57
-
58
- alice_key
59
- #=> "-----BEGIN RSA PRIVATE KEY-----
60
- # MIIEpAIBAAKCAQEAzLpmAQ+MbUTHU1XxzEaQXqiOvk0Vu/skztaMWz+UoGYWU6eW
61
- # cr7zVt/Y0SYqzD8LkYireX22FxNNFfhgu3/uC5yTl+dri6PD6NDAmrG+1cyE8kZZ
62
- # MGq91wQEemZPuesjTgKEvwZbknjodIKOAP35QycMr4PuWICSrCjhJLrClI7jInTZ
63
- # LOLtD5w5U7/xLOJAIfuhjUA4wrFCLJGPe7214KWgDCLmsan4/GVUloUKa6KAHJiH
64
- # q4tNxNdSrbOlluZbKQl8REhXOCIb5bEX2KnbQT0nPgKkuOlXgZ7jeyOIk0FG1RGa
65
- # FvcGu8LieMgT39WltcHJLblNkDr9YDRGiNiThQIDAQABAoIBAQCE/FPEPqBeXj4I
66
- # MRzHL9MZ2e4XSaVjnYjUXuN/ZnaaFpZMMuF0mfshpHiHq35DfHR8TcXtPi6pIJ2D
67
- # NvtG8JvlqQjqtKXUaEWbFvb1xZ4L7TUy12WaIMw+PlrWU11YjJg7VUF7gJq9M5L0
68
- # E9ZAaLmg2F3SKSYLEUG1WTyeij5ZFqouNjZxD2xo5U5Agy2UVm2D9aUm/n4g8Wnr
69
- # HybadhD6V9+BsZ2e9Q6CamHRah9Hs4nDPnycPFXpbs32wx9nvACPMg5+/Fqxr/ZK
70
- # cPM4syVBW0lNhpTzhHkPvimAgwgqJYvAj/o9nQnq5i1XyVyXp3uKVnld3FCddf9i
71
- # ovQMPmVlAoGBAPHtUKRehy8df/Zw6oGz0WcZCTjEwZ9DEb5rFN9Pr2IyvOhmZ3UJ
72
- # JNx9WmiiGB44dbnafMtr2Ya7u4OAM6e190BbcJKTnpWqVlsXw/wyQqIgJb3AtFu4
73
- # 91mqsDepOWsfs1IjTgmR1OM29WXjGoPHtV9E6//uVmVsciEvkCtcRfGDAoGBANij
74
- # IbZ3mL1rr8uRT/czPLkZ3KPLsJhPriuc6yyOq+tqQ6d3u/1DjKxoeYa7Jbyj7Dwl
75
- # 2wHQf9vRz3Kb2Mw+hPcHGDO9aBWxvZXjxxrVk6g1Ei0mvIP0k8ZbnlReK3cr5ktl
76
- # aY/ZWDDVPpY4aqkcOIbAAi95jPlpb2LsntijxoBXAoGABPJRP8sfAHud7jAI23YN
77
- # xgnhAmQjgVohtr8Bwj8i2uMmsanGW8JAGrIFczY9QADvh0lMW+xsmjCkeN/aLoet
78
- # 8obsGlMiXvUIpvwpabKtYhs+Kk8SYP27MP4odDrljacsR3WpVtDAhZTOF7M5C5C9
79
- # yKDkImuBILnC66LJU9mjJHkCgYEAntDxDSCeQ/dnOBh+hB323UgdXaMdAnwflm+C
80
- # ZPbvCDWuBV6c3W2g+l/Y/7HBV4rgy7OA29KreU5WA5JHHGyU87gqwPuRC55y+yiy
81
- # NXTvu7e0bI9iUmaB00AlUXp76PCw8wMUoVVX9uzN5jjT0MgUlIy8zWsRs2LdOqt3
82
- # RCDEjB8CgYAO6ZptzyJ4FS7ucjKfjig5WMOiKMcIUtTG9qedHmE2Z6vt3g0SQWaD
83
- # zJJacSoRHAdRK61vOlg4k+9/9LjffDrk9uT555BDbYqKWlmST7JMfvO7EpaIMYUu
84
- # CN7+3Rx9gSLyScqtAYiT/LgYgL1Vc6/e0XHaVjA85kPvUDKb785oFg==
85
- # -----END RSA PRIVATE KEY-----"
86
-
87
- alice_pub
88
- #=> "-----BEGIN PUBLIC KEY-----
89
- # MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzLpmAQ+MbUTHU1XxzEaQ
90
- # XqiOvk0Vu/skztaMWz+UoGYWU6eWcr7zVt/Y0SYqzD8LkYireX22FxNNFfhgu3/u
91
- # C5yTl+dri6PD6NDAmrG+1cyE8kZZMGq91wQEemZPuesjTgKEvwZbknjodIKOAP35
92
- # QycMr4PuWICSrCjhJLrClI7jInTZLOLtD5w5U7/xLOJAIfuhjUA4wrFCLJGPe721
93
- # 4KWgDCLmsan4/GVUloUKa6KAHJiHq4tNxNdSrbOlluZbKQl8REhXOCIb5bEX2Knb
94
- # QT0nPgKkuOlXgZ7jeyOIk0FG1RGaFvcGu8LieMgT39WltcHJLblNkDr9YDRGiNiT
95
- # hQIDAQAB
96
- # -----END PUBLIC KEY-----"
97
-
98
- bob_key, bob_pub = RSA.generate_keys
99
-
100
- bob_key
101
- #=> "-----BEGIN RSA PRIVATE KEY-----
102
- # MIIEpAIBAAKCAQEAzADannvKlfVkZmKA4EDIxTW0HiJzjD6Auh8wLi02+iz2BScz
103
- # fECA65Zv+KHfc1B9AWMqGeBIwFE49NrsnXiZwZR3DqcFS8WbnVqpntvhwzlEARna
104
- # RWmZ2XjloD7fxILbXtWfMFNjwSfaK0bpArLkrt9d8eni+JI42+ptIWs/bVynACqm
105
- # DqOTjoEgajuHVpxHtskPNQrsjxzP+umsUWkbE0iaO7oN1pcgZIR4VRr0bz/3Juif
106
- # WmiCgwbDZo1WolfveoCacVsfAB1iesxeWnrGIJUjq8Mqsu9mQz1dg6RF4ElwNJ57
107
- # G3T3nlW+qpVBZDU2sHFqUFxbGmWPdRUn1yn4KwIDAQABAoIBAQCOCwotz4P/Zh3C
108
- # LFQP0Qv6RKplURejTuHStmSVwmXFTAkBDYqLuV4Kq3TLaepsIF7p2GI4IjKFtggy
109
- # dTzLaG2mm/lJ+oF1gOIZbkcslW1cwULYgWe5bQ3ynntEWIL2ESctoRB2VZnfpCAE
110
- # ghs8BdO071I6Xt/qs+VjOpdB7ar8OYhFc1vhwiI03FKbjuScH0CQOETIeLCqK5tC
111
- # qPnjMTYdaTp/NgcZujsOeOBgbARLzGtCaESbmXHO6mPDkEED5uqZzsNBtdCZIGMF
112
- # ApJkZbF6xSRizQhwwRlak1jCkAk2VCYpKPMiop1+cbjs3jU3RyP94RHc/yKo2Rzm
113
- # HCl35XYBAoGBAPJDMV9W2scRsMlLw9In3ZzWtammcouE0oXEgizK61Cg/5C5E06a
114
- # 5anrfwF5bURBANKBqTSHV0u71C2fHs1KO+B+EHzQ4DKsXldCSv2PR/0A6lmF9AIL
115
- # DFfup/mU55plbqCnjJe2BOUrOmurSd5MbWtShRdGri/LBqF58BFgT+U1AoGBANeS
116
- # RZDsCWelZPGN8Wxp9zxhu1AClNO9S7ITjZOQTYlghCVKAkS1wvB/6TIjaw8DyREs
117
- # f6WvtkzQA/vZc4mXE+YM/calL8ee3wVEJJzlGBfuh8mQhxtiLa5PTl7Icv/R8DGV
118
- # 9hU9GkJgWdi/+Plpqdcv79OWVMTB7igmoN8PAPPfAoGAKqatwI04AygYKbhPB2bB
119
- # W2Vpoi6NqAaAUdCg4mXvO8i8daw/u+0FVf8B4y6PkB6pmGX/diIFum2dE1MaRyY0
120
- # mHdZS8AyWHmEOnSPY0igceiBWbV9mgZ769c2d3hBtir5aQtWczc2cWpE5MPJQ3vN
121
- # H8HtcIWfEQb7ad5f548/QakCgYEAwFDjNRYOkePQ+Vrbjg+/HKRH+mpDId9Xv4eI
122
- # H6R2N9/eJHIxMeFCB1Ll1PAaG6wR3ftn6YWnykEtvKpTU+VvQCZI5MYLqTgH2Ofh
123
- # DgOoCfmoNF922SwuerqPvSlwxt8hPOt/PZVkbuEMZr1lPgVRGwPOHmKYP2yPrkw/
124
- # 6p+1BtsCgYABmMLgWhXVD19XxNHm8XpGnPWTEjqAYrw6I5yDUwNhB0n4129qaC+x
125
- # MWrdslKBmQh1r1U5QoSSL0CY4Ef5qN02uZl15FN1kYQzZA6kJi+MoBsjzrZCvzsc
126
- # Bbahpg363PyHC75zgvazvOr4tK3mzaRi5RNTMgivTVu4FyhkRdJ5wQ==
127
- # -----END RSA PRIVATE KEY-----"
128
-
129
- bob_pub
130
- #=> "-----BEGIN PUBLIC KEY-----
131
- # MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzADannvKlfVkZmKA4EDI
132
- # xTW0HiJzjD6Auh8wLi02+iz2BSczfECA65Zv+KHfc1B9AWMqGeBIwFE49NrsnXiZ
133
- # wZR3DqcFS8WbnVqpntvhwzlEARnaRWmZ2XjloD7fxILbXtWfMFNjwSfaK0bpArLk
134
- # rt9d8eni+JI42+ptIWs/bVynACqmDqOTjoEgajuHVpxHtskPNQrsjxzP+umsUWkb
135
- # E0iaO7oN1pcgZIR4VRr0bz/3JuifWmiCgwbDZo1WolfveoCacVsfAB1iesxeWnrG
136
- # IJUjq8Mqsu9mQz1dg6RF4ElwNJ57G3T3nlW+qpVBZDU2sHFqUFxbGmWPdRUn1yn4
137
- # KwIDAQAB
138
- # -----END PUBLIC KEY-----"
139
-
140
-
141
- tx = "from: alice, to: bob, $21"
142
- tx_hash = sha256( tx )
143
- #=> "426a472a6c69bf68354391b7822393bea3952cde9df8949ad7a0f5f405b2fcb5"
144
-
145
- tx_signature = RSA.sign( tx_hash, alice_key )
146
- #=> "xfhzC6tzXYmA5rFAFybJ9KeWnTcTnC0Plt7cSHky6ZSdBZRKz/sfFcpyIN7w
147
- # jWrdPwEREA3nwNu/HSpiGRBFr+lu/YgWGNp6HLGPeL7uHGAfmWPyU5WRzGzf
148
- # iEs5B6kdJ3S8LSbP0hkOD8AOgZLPeU5rzA4+/Ymt8e/UOVwwka6Gj13yoBua
149
- # mSdsVuQfgh2VpySejCz4ykYlMSHK8Kx8QFt+QbyI5QZUy2dFh6HlcnHR+G9A
150
- # RMRZ1vAuQhYqtDSsxwRcZCSFsc6uctAvsgFinhqy6ls5VpcXfuKwZhKAw3Di
151
- # E2MYUnT7+i38Mq26iWzgmDbpOrVCO5tjlSiHY1731A=="
152
-
153
- RSA.valid_signature?( tx_hash, tx_signature, alice_pub )
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
+ #=> 72190737707147846840353520312904745954595478835413056312168022784020322830309
278
+ ```
279
+
280
+
281
+ (Auto-)Calculate the Public Key - Enter Elliptic Curve (EC) Cryptography
282
+
283
+ The public key are two numbers (that is, a point with the coordinates x and y) computed by multiplying
284
+ the generator point (`G`) of the curve with the private key.
285
+ This is equivalent to adding the generator to itself `private_key` times.
286
+ Magic?
287
+ Let's try:
288
+
289
+
290
+ ``` ruby
291
+ # This private key is just an example. It should be much more secure!
292
+ private_key = EC::PrivateKey.new( 1234 ) # by default uses Secp256k1 curve (used in Bitcoin and Ethereum)
293
+
294
+ public_key = private_key.public_key ## the "magic" one-way K=k*G curve multiplication (K=public key,k=private key, G=generator point)
295
+ point = public_key.point
296
+
297
+ point.x
298
+ #=> 102884003323827292915668239759940053105992008087520207150474896054185180420338
299
+ point.y
300
+ #=> 49384988101491619794462775601349526588349137780292274540231125201115197157452
301
+
302
+ point.x.to_s(16)
303
+ #=> "e37648435c60dcd181b3d41d50857ba5b5abebe279429aa76558f6653f1658f2"
304
+ point.y.to_s(16)
305
+ #=> "6d2ee9a82d4158f164ae653e9c6fa7f982ed8c94347fc05c2d068ff1d38b304c"
306
+ ```
307
+
308
+
309
+ Sign a transaction with an (elliptic curve) private key:
310
+
311
+ ``` ruby
312
+ # Step 1 - Calculate the Transaction (tx) Hash
313
+ tx = 'from: Alice to: Bob cryptos: 43_000_000_000'
314
+ txhash = sha256( tx )
315
+
316
+ # Step 2 - Get the Signer's Private key
317
+ private_key = EC::PrivateKey.new( 1234 ) # This private key is just an example. It should be much more secure!
318
+
319
+ # Sign!
320
+ signature = private_key.sign( txhash )
321
+ # -or-
322
+ signature = EC.sign( txhash, private_key )
323
+
324
+ signature.r
325
+ #=> 80563021554295584320113598933963644829902821722081604563031030942154621916407
326
+ signature.s
327
+ #=> 58316177618967642068351252425530175807242657664855230973164972803783751708604
328
+
329
+ signature.r.to_s(16)
330
+ #=> "3306a2f81ad2b2f62ebe0faec129545bc772babe1ca5e70f6e56556b406464c0"
331
+ signature.s.to_s(16)
332
+ #=> "4fe202bb0835758f514cd4a0787986f8f6bf303df629dc98c5b1a438a426f49a"
333
+ ```
334
+
335
+
336
+ Verify a signed transaction with an (elliptic curve) public key:
337
+
338
+ ``` ruby
339
+ # Step 1 - Calculate the Transaction (tx) Hash
340
+ tx = 'from: Alice to: Bob cryptos: 43_000_000_000'
341
+ txhash = sha256( tx )
342
+
343
+ # Step 2 - Get the Signer's Public Key
344
+ public_key = EC::PublicKey.new(
345
+ 102884003323827292915668239759940053105992008087520207150474896054185180420338,
346
+ 49384988101491619794462775601349526588349137780292274540231125201115197157452
347
+ )
348
+
349
+ # Step 3 - Get the Transaction's Signature
350
+ signature = EC::Signature.new(
351
+ 80563021554295584320113598933963644829902821722081604563031030942154621916407,
352
+ 58316177618967642068351252425530175807242657664855230973164972803783751708604
353
+ )
354
+
355
+ # Don't Trust - Verify
356
+ public_key.verify?( txhash, signature )
357
+ # -or-
358
+ EC.verify?( txhash, signature, public_key )
154
359
  #=> true
155
360
 
156
- tx = "from: alice, to: bob, $22"
157
- tx_hash = sha256( tx )
158
- #=> "e899604bb4c95d2f1a7cfe561ad65941769e2064bdbbcaa79eb64ce0a2832380"
159
361
 
160
- RSA.valid_signature?( tx_hash, tx_signature, alice_pub )
161
- #=> false
362
+ # or using hexadecimal numbers
363
+
364
+ public_key = EC::PublicKey.new(
365
+ 0xe37648435c60dcd181b3d41d50857ba5b5abebe279429aa76558f6653f1658f2,
366
+ 0x6d2ee9a82d4158f164ae653e9c6fa7f982ed8c94347fc05c2d068ff1d38b304c
367
+ )
368
+
369
+ signature = EC::Signature.new(
370
+ 0x3306a2f81ad2b2f62ebe0faec129545bc772babe1ca5e70f6e56556b406464c0,
371
+ 0x4fe202bb0835758f514cd4a0787986f8f6bf303df629dc98c5b1a438a426f49a
372
+ )
373
+
374
+ public_key.verify?( txhash, signature )
375
+ # -or-
376
+ EC.verify?( txhash, signature, public_key )
377
+ #=> true
162
378
  ```
163
379
 
164
380
 
165
- and some more.
381
+ To sum up:
382
+
383
+ - The (raw) private key is a 256-bit unsigned integer number
384
+ - The (raw) public key is a point (x,y), that is, two 256-bit unsigned integer numbers - derived (calculated) from the private key
385
+ - A (raw) signature is composed of (r,s), that is, two 256-bit unsigned integer numbers
386
+
387
+ That's all the magic.
388
+
389
+
390
+
391
+
392
+ ## Examples
393
+
394
+ ### Generate the Bitcoin (Base58) Address from the (Elliptic Curve) Public Key
395
+
396
+ 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):
397
+
398
+ ``` ruby
399
+ # Lets start with the public key ("raw" hex string encoded)
400
+ pk = "0250863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b2352"
401
+
402
+ # 1. Perform SHA-256 hashing on the public key
403
+ step1 = sha256( pk )
404
+ #=> "0b7c28c9b7290c98d7438e70b3d3f7c848fbd7d1dc194ff83f4f7cc9b1378e98"
405
+
406
+ # 2. Perform RIPEMD-160 hashing on the result of SHA-256
407
+ step2 = ripemd160( step1 )
408
+ #=> "f54a5851e9372b87810a8e60cdd2e7cfd80b6e31"
409
+
410
+ # 3. Add version byte in front of RIPEMD-160 hash (0x00 for Main Network)
411
+ step3 = "00" + step2
412
+ #=> "00f54a5851e9372b87810a8e60cdd2e7cfd80b6e31"
413
+
414
+ # 4. Perform SHA-256 hash on the extended RIPEMD-160 result
415
+ step4 = sha256( step3 )
416
+ #=> "ad3c854da227c7e99c4abfad4ea41d71311160df2e415e713318c70d67c6b41c"
417
+
418
+ # 5. Perform SHA-256 hash on the result of the previous SHA-256 hash
419
+ step5 = sha256( step4 )
420
+ #=> "c7f18fe8fcbed6396741e58ad259b5cb16b7fd7f041904147ba1dcffabf747fd"
421
+
422
+ # 6. Take the first 4 bytes of the second SHA-256 hash. This is the address checksum
423
+ step6 = step5[0..7] # note: 4 bytes in hex string are 8 digits/chars
424
+ #=> "c7f18fe8"
425
+
426
+ # 7. Add the 4 checksum bytes from step 6 at the end of
427
+ # extended RIPEMD-160 hash from step 3.
428
+ # This is the 25-byte binary Bitcoin Address.
429
+ step7 = step3 + step6
430
+ #=> "00f54a5851e9372b87810a8e60cdd2e7cfd80b6e31c7f18fe8"
431
+
432
+ # 8. Convert the result from a byte string into a base58 string using Base58 encoding.
433
+ # This is the most commonly used Bitcoin Address format.
434
+ addr = base58( step7 )
435
+ #=> "1PMycacnJaSqwwJqjawXBErnLsZ7RkXUAs"
436
+ ```
437
+
438
+ Or let's try again with the shortcut helpers:
439
+
440
+ - `HASH160 - RMD160(SHA256(X))`
441
+ - `BASE58CHECK - BASE58(X || SHA256(SHA256(X))[:4])`
442
+
443
+ ``` ruby
444
+ # Lets start with the public key ("raw" hex string encoded)
445
+ pk = "0250863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b2352"
446
+
447
+ # 1. Perform HASH-160 hashing on the public key
448
+ # a) Perform SHA-256 hashing on the public key
449
+ # b) Perform RIPEMD-160 hashing on the result of SHA-256
450
+ step1 = hash160( pk )
451
+ #=> "f54a5851e9372b87810a8e60cdd2e7cfd80b6e31"
452
+
453
+ # 2. Add version byte in front of RIPEMD-160 hash (0x00 for Main Network)
454
+ step2 = "00" + step1
455
+ #=> "00f54a5851e9372b87810a8e60cdd2e7cfd80b6e31"
456
+
457
+ # 3. Encode with BASE58CHECK
458
+ # a) Perform SHA-256 hash on the extended RIPEMD-160 result
459
+ # b) Perform SHA-256 hash on the result of the previous SHA-256 hash
460
+ # c) Take the first 4 bytes of the second SHA-256 hash. This is the address checksum
461
+ # d) Add the 4 checksum bytes at the end of
462
+ # extended RIPEMD-160 hash from step 2.
463
+ # This is the 25-byte binary Bitcoin Address.
464
+ # e) Convert the result from a byte string into a base58 string
465
+ # using Base58 encoding.
466
+ # This is the most commonly used Bitcoin Address format.
467
+ addr = base58check( step2 )
468
+ #=> "1PMycacnJaSqwwJqjawXBErnLsZ7RkXUAs"
469
+ ```
470
+
471
+
472
+ References
473
+
474
+ - [How to create Bitcoin Address](https://en.bitcoin.it/wiki/Technical_background_of_version_1_Bitcoin_addresses#How_to_create_Bitcoin_Address)
475
+ - [Ruby Quiz #15 - Generate the Bitcoin (Base58) Address from the (Elliptic Curve) Public Key](https://github.com/planetruby/quiz/tree/master/015)
476
+
477
+ Bonus: Bitcon Tip - How to Buy Bitcoin (The CO₂-Friendly Way)
478
+
479
+ > 1. Take one $50 bill, five $10 bills, or ten $5 bills (I wouldn't recommend change - stay with paper money).
480
+ > 2. Go to the bathroom.
481
+ > 3. Lift the lid of the loo.
482
+ > 4. Throw money in.
483
+ > 5. Flush down water.
484
+ >
485
+ > Congrats! You just purchased $50 worth of Bitcoin - without fucking the planet!
486
+ >
487
+ > -- Trolly McTrollface, Bitcon Greater Fool Court Jester
488
+
489
+ Read more [Crypto Quotes »](https://github.com/openblockchains/crypto-quotes)
166
490
 
167
491
 
168
492