elliptic-lite 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: f2c2286683b5a48f1839bf0bbe75f2ef28f21e8a981c0b541979a2eebd303296
4
+ data.tar.gz: b68f47cca4cdb8a4f9b9881b7069f1fb3310f8126541b6b729b7745c2de4d49a
5
+ SHA512:
6
+ metadata.gz: 654d87c1b81c2268de218aed9311b445d40b616be9e111fe4475c017fcc4786acaf418151748e231719cb8bc80d82025ed0498e06b7f05aa032178aeb6c3ee9f
7
+ data.tar.gz: 18e2cbd29db18c580a7e229a649ff31c9c5def8ea51eb1c3b6752863758ed59078eb158c1d72659a492ff70ab7a4b23eb2893c80c06a960bfc834fe0f3ee5c22
data/CHANGELOG.md ADDED
@@ -0,0 +1,3 @@
1
+ ### 0.0.1 / 2021-06-06
2
+
3
+ * Everything is new. First release
data/Manifest.txt ADDED
@@ -0,0 +1,16 @@
1
+ CHANGELOG.md
2
+ Manifest.txt
3
+ README.md
4
+ Rakefile
5
+ lib/elliptic-lite.rb
6
+ lib/elliptic-lite/base.rb
7
+ lib/elliptic-lite/field.rb
8
+ lib/elliptic-lite/point.rb
9
+ lib/elliptic-lite/secp256k1.rb
10
+ lib/elliptic-lite/signature.rb
11
+ lib/elliptic-lite/version.rb
12
+ lib/elliptic/lite.rb
13
+ test/helper.rb
14
+ test/test_field.rb
15
+ test/test_point.rb
16
+ test/test_signature.rb
data/README.md ADDED
@@ -0,0 +1,399 @@
1
+ # elliptic-lite - elliptic curve cryptography from scratch / zero - start with finite fields, add elliptic curve points and point addition and scalar multiplications, add the elliptic curve digital signature algorithm (ECDSA) using the secp256k1 curve / group to sign and verify messages and more
2
+
3
+
4
+ * home :: [github.com/rubycoco/blockchain](https://github.com/rubycoco/blockchain)
5
+ * bugs :: [github.com/rubycoco/blockchain/issues](https://github.com/rubycoco/blockchain/issues)
6
+ * gem :: [rubygems.org/gems/elliptic-lite](https://rubygems.org/gems/elliptic-lite)
7
+ * rdoc :: [rubydoc.info/gems/elliptic-lite](http://rubydoc.info/gems/elliptic-lite)
8
+
9
+
10
+
11
+
12
+ ## Usage
13
+
14
+
15
+ ### Finite Fields
16
+
17
+ Let's start with definining a finite field (mod 13), that is,
18
+ `F₁₃ = [0,1,2,3,4,5,6,7,8,9,10,11,12]` where the mod(ulus) is always
19
+ a prime number - and the prime number is 13 in this case:
20
+
21
+
22
+
23
+ ``` ruby
24
+ require 'elliptic-lite'
25
+
26
+
27
+ class F₁₃ < FiniteField::Element
28
+ def self.prime() 13; end
29
+ end
30
+
31
+ F₁₃.prime #=> 13
32
+
33
+ F₁₃.include?( 0 ) #=> true
34
+ F₁₃.include?( 12 ) #=> true
35
+ F₁₃.include?( 13 ) #=> false
36
+ ```
37
+
38
+ Let's try addition, subtraction, multiplication, exponentiation (power), and division
39
+ with finite fields
40
+ using the class-level `add`/`sub`/`mul`/`pow`/`div` methods:
41
+
42
+
43
+ ``` ruby
44
+ F₁₃.add( 7, 12 ) #=> 6
45
+ F₁₃.sub( 7, 12 ) #=> 8
46
+ F₁₃.mul( 3, 12 ) #=> 10
47
+ F₁₃.pow( 3, 3 ) #=> 1
48
+ ```
49
+
50
+ Let's try a finite field (mod 19):
51
+
52
+ ``` ruby
53
+ F₁₉ = FiniteField.new(19)
54
+
55
+ F₁₉.div( 7, 5 ) #=> 9
56
+ ```
57
+
58
+
59
+
60
+ And optional in a more object-oriented way with
61
+ overloaded math operators (`+`/`-`/`*`/`**`/`/`):
62
+
63
+ ``` ruby
64
+ a = F₁₃[7]
65
+ b = F₁₃[12]
66
+ c = F₁₃[6]
67
+ a+b == c #=> true
68
+
69
+ c = F₁₃[8]
70
+ a-b == c #=> true
71
+
72
+ a = F₁₃[3]
73
+ b = F₁₃[12]
74
+ c = F₁₃[10]
75
+ a*b == c #=> true
76
+
77
+ a = F₁₃[3]
78
+ b = F₁₃[1]
79
+ a**3 == b #=> true
80
+ a*a*a == b #=> true
81
+ a*a*a == a**3 #=> true
82
+
83
+ a = F₁₉[2]
84
+ b = F₁₉[7]
85
+ c = F₁₉[3]
86
+ a/b == c #=> true
87
+
88
+
89
+ # -or-
90
+ F₁₃[7] + F₁₃[12] == F₁₃[6]
91
+ F₁₃[7] - F₁₃[12] == F₁₃[8]
92
+ F₁₃[3] * F₁₃[12] == F₁₃[10]
93
+ F₁₃[3] ** 3 == F₁₃[1]
94
+ F₁₃[3] * F₁₃[3] * F₁₃[3] == F₁₃[1]
95
+ F₁₃[3] ** 3 == F₁₃[3] * F₁₃[3] * F₁₃[3]
96
+
97
+ F₁₉[2] / F₁₉[7] == F₁₉[3]
98
+ ```
99
+
100
+
101
+
102
+ ### Elliptic Curves & Elliptic Curve Points (Over Integer Numbers)
103
+
104
+
105
+ Let's define an elliptic curve - `y³ = x² + ax + b` where a is 5 and b is 7:
106
+
107
+ ``` ruby
108
+ CURVE_5_7 = Curve.new( a: 5, b: 7 )
109
+ ```
110
+
111
+ And let's define a point class - a point being a pair of x/y-coordinates - for the elliptic curve `y³ = x² + 5x + 7` (with `a=5` and `b=7`):
112
+
113
+ ``` ruby
114
+ class Point_5_7 < Point
115
+ def self.curve() CURVE_5_7; end
116
+ end
117
+
118
+ p1 = Point_5_7.new( -1, -1 ) # point with x/y coords: -1/-1
119
+ p2 = Point_5_7.new( -1, -2 ) # raise ArgumentError!! point NOT on curve
120
+
121
+ Point_5_7.on_curve?( -1, -1 ) #=> true
122
+ Point_5_7.on_curve?( -1, -2 ) #=> false
123
+
124
+ #-or-
125
+ p1 = Point_5_7[ -1, -1 ]
126
+ p2 = Point_5_7[ -1, -2 ]
127
+
128
+ # and the infinity point
129
+ inf = Point_5_7[ :infinity ]
130
+ inf.infinity? #=> true
131
+ ```
132
+
133
+ Let's try point addition on the `y³ = x² + 5x + 7` elliptic curve (with `a=5` and `b=7`):
134
+
135
+ ``` ruby
136
+ p1 = Point_5_7[-1, -1]
137
+ p2 = Point_5_7[-1, 1]
138
+ inf = Point_5_7[ :infinity ]
139
+
140
+ p1 + inf #=> Point_5_7[-1,-1]
141
+ inf + p2 #=> Point_5_7[-1,1]
142
+ p1 + p2 #=> Point_5_7[:infinity]
143
+
144
+ p1 = Point_5_7[ 2, 5]
145
+ p2 = Point_5_7[-1,-1]
146
+ p1 + p2 #=> Point_5_7[3,-7]
147
+
148
+ p1 = Point_5_7[-1,-1]
149
+ p1 + p1 #=> Point_5_7[18,77]
150
+ ```
151
+
152
+
153
+
154
+ ### Elliptic Curves & Elliptic Points Over Finite Fields
155
+
156
+ Let's change from "plain vanilla" integer numbers
157
+ to finite fields. Let's try F₂₂₃ - a finite field (mod 223)
158
+ where the mod(ulus) is the prime number 223.
159
+
160
+ ``` ruby
161
+ class F₂₂₃ < FiniteField::Element
162
+ def self.prime() 223; end
163
+ end
164
+ ```
165
+
166
+ Let's define an elliptic curve over F₂₂₃ - `y³ = x² + ax + b` where a is 0 and b is 7:
167
+
168
+ ``` ruby
169
+ CURVE_F₂₂₃0_7 = Curve.new( a: 0, b: 7, f: F₂₂₃ )
170
+ ```
171
+
172
+ And let's define a point class:
173
+
174
+ ``` ruby
175
+ class Point_F₂₂₃0_7 < Point
176
+ def self.curve() CURVE_F₂₂₃0_7; end
177
+ end
178
+ ```
179
+
180
+ And let's try point addition:
181
+
182
+ ``` ruby
183
+ p1 = Point_F₂₂₃0_7[ 192, 105 ]
184
+ p2 = Point_F₂₂₃0_7[ 17, 56 ]
185
+ p1 + p2 #=> Point_F₂₂₃0_7[170,142]
186
+
187
+ p1 = Point_F₂₂₃0_7[ 170, 142 ]
188
+ p2 = Point_F₂₂₃0_7[ 60, 139 ]
189
+ p1 + p2 #=> Point_F₂₂₃0_7[220,181]
190
+
191
+ p1 = Point_F₂₂₃0_7[ 47, 71 ]
192
+ p2 = Point_F₂₂₃0_7[ 17, 56 ]
193
+ p1 + p2 #=> Point_F₂₂₃0_7[215,68]
194
+ ```
195
+
196
+ And finally let's try scalar point multiplication:
197
+
198
+ ``` ruby
199
+ p = Point_F₂₂₃0_7[ 192, 105 ]
200
+ p+p #=> Point_F₂₂₃0_7[49,71]
201
+
202
+ p = Point_F₂₂₃0_7[ 143, 98 ]
203
+ p+p #=> Point_F₂₂₃0_7[64,168]
204
+
205
+ p = Point_F₂₂₃0_7[ 47, 71 ]
206
+ p+p #=> Point_F₂₂₃0_7[36,111]
207
+ p+p+p+p #=> Point_F₂₂₃0_7[194,51]
208
+ p+p+p+p+p+p+p+p #=> Point_F₂₂₃0_7[116,55]
209
+ p+p+p+p+p+p+p+p+p+p+p+p+p+p+p+p+p+p+p+p+p #=> Point_F₂₂₃0_7[:infinity]
210
+
211
+ #-or-
212
+
213
+ 2*p #=> Point_F₂₂₃0_7[36,111]
214
+ 4*p #=> Point_F₂₂₃0_7[194,51]
215
+ 8*p #=> Point_F₂₂₃0_7[116,55]
216
+ 21*p #=> Point_F₂₂₃0_7[:infinity]
217
+ ```
218
+
219
+ Or let's try the from 1 to inifinity, that is, the order of the group
220
+ using the generating point (47/71):
221
+
222
+ ``` ruby
223
+ p = Point_F₂₂₃0_7[ 47, 71 ]
224
+ (1..21).each do |s|
225
+ product = s*p
226
+ puts " #{s}*#{p.inspect} => #{product.inspect}"
227
+ end
228
+ ```
229
+
230
+ resulting in:
231
+
232
+ ```
233
+ 1*Point_F₂₂₃0_7[47,71] => Point_F₂₂₃0_7[47,71]
234
+ 2*Point_F₂₂₃0_7[47,71] => Point_F₂₂₃0_7[36,111]
235
+ 3*Point_F₂₂₃0_7[47,71] => Point_F₂₂₃0_7[15,137]
236
+ 4*Point_F₂₂₃0_7[47,71] => Point_F₂₂₃0_7[194,51]
237
+ 5*Point_F₂₂₃0_7[47,71] => Point_F₂₂₃0_7[126,96]
238
+ 6*Point_F₂₂₃0_7[47,71] => Point_F₂₂₃0_7[139,137]
239
+ 7*Point_F₂₂₃0_7[47,71] => Point_F₂₂₃0_7[92,47]
240
+ 8*Point_F₂₂₃0_7[47,71] => Point_F₂₂₃0_7[116,55]
241
+ 9*Point_F₂₂₃0_7[47,71] => Point_F₂₂₃0_7[69,86]
242
+ 10*Point_F₂₂₃0_7[47,71] => Point_F₂₂₃0_7[154,150]
243
+ 11*Point_F₂₂₃0_7[47,71] => Point_F₂₂₃0_7[154,73]
244
+ 12*Point_F₂₂₃0_7[47,71] => Point_F₂₂₃0_7[69,137]
245
+ 13*Point_F₂₂₃0_7[47,71] => Point_F₂₂₃0_7[116,168]
246
+ 14*Point_F₂₂₃0_7[47,71] => Point_F₂₂₃0_7[92,176]
247
+ 15*Point_F₂₂₃0_7[47,71] => Point_F₂₂₃0_7[139,86]
248
+ 16*Point_F₂₂₃0_7[47,71] => Point_F₂₂₃0_7[126,127]
249
+ 17*Point_F₂₂₃0_7[47,71] => Point_F₂₂₃0_7[194,172]
250
+ 18*Point_F₂₂₃0_7[47,71] => Point_F₂₂₃0_7[15,86]
251
+ 19*Point_F₂₂₃0_7[47,71] => Point_F₂₂₃0_7[36,112]
252
+ 20*Point_F₂₂₃0_7[47,71] => Point_F₂₂₃0_7[47,152]
253
+ 21*Point_F₂₂₃0_7[47,71] => Point_F₂₂₃0_7[:infinity]
254
+ ```
255
+
256
+
257
+
258
+ ## What's secp256k1?
259
+
260
+
261
+ Let's use the elliptic curve defined by secp256k1 and in use
262
+ for the public-key cryptography by Dodge, Bitcoin, Ethereum and many others.
263
+
264
+ secp256k1 refers to the parameters of the elliptic curve. The name represents the specific parameters of curve:
265
+
266
+ - sec: stands for Standards for Efficient Cryptography
267
+ - p: indicates that what follows are the parameters of the curve
268
+ - 256: length in bits of the field size
269
+ - k: Kolbitz curve, as opposed to random. The non-random construction allows for efficient construction
270
+ - 1: sequence number
271
+
272
+
273
+ Let's start with the finite field
274
+ using a big prime number (almost 2**256), that is,
275
+ `2**256 - 2**32 - 977`
276
+ or
277
+ ` 115792089237316195423570985008687907853269984665640564039457584007908834671663`:
278
+
279
+
280
+ ``` ruby
281
+ class S256Field < FiniteField::Element
282
+ P = 2**256 - 2**32 - 977
283
+ def self.prime() P; end
284
+ end
285
+ ```
286
+
287
+ Let's define an elliptic curve over - `y³ = x² + ax + b` where a is 0 and b is 7
288
+ and let's define a point class:
289
+
290
+ ``` ruby
291
+ class S256Point < Point
292
+ def self.curve() @curve ||= Curve.new( a: 0, b: 7, f: S256Field ); end
293
+ end
294
+ ```
295
+
296
+ And let's define the group for the generation point (g)
297
+ with the order (n):
298
+
299
+ ``` ruby
300
+ SECP256K1 = Group.new(
301
+ g: S256Point.new( 0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798,
302
+ 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 ),
303
+ n: 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141
304
+ )
305
+ ```
306
+
307
+ That are all the standard secp256k1 parameters to use the
308
+ Elliptic Curve Digital Signature Algorithm (ECDSA).
309
+ Let's try to verify a signature (r,s) for a message (z)
310
+ given a public key (that is, a point on the secp256k1 curve):
311
+
312
+
313
+ ``` ruby
314
+ pubkey = PublicKey.new( 0x887387e452b8eacc4acfde10d9aaf7f6d9a0f975aabb10d006e4da568744d06c,
315
+ 0x61de6d95231cd89026e286df3b6ae4a894a3378e393e93a0f45b666329a0ae34 )
316
+
317
+ # signature 1
318
+ z = 0xec208baa0fc1c19f708a9ca96fdeff3ac3f230bb4a7ba4aede4942ad003c0f60
319
+ r = 0xac8d1c87e51d0d441be8b3dd5b05c8795b48875dffe00b7ffcfac23010d3a395
320
+ s = 0x68342ceff8935ededd102dd876ffd6ba72d6a427a3edb13d26eb0781cb423c4
321
+
322
+ sig = Signature.new( r, s )
323
+ pubkey.verify?( z, sig ) #=> true
324
+
325
+
326
+ # signature 2
327
+ z = 0x7c076ff316692a3d7eb3c3bb0f8b1488cf72e1afcd929e29307032997a838a3d
328
+ r = 0xeff69ef2b1bd93a66ed5219add4fb51e11a840f404876325a1e8ffe0529a2c
329
+ s = 0xc7207fee197d27c618aea621406f6bf5ef6fca38681d82b2f06fddbdce6feab6
330
+
331
+ sig = Signature.new( r, s )
332
+ pubkey.verify?( z, sig ) #=> true
333
+ ```
334
+
335
+
336
+ And let's sign a message using a private key (that is, a 256-bit integer
337
+ of the order (n) of the generation point):
338
+
339
+ ``` ruby
340
+ e = 12345 ## private key - note: do NOT use - only for learning
341
+ key = PrivateKey.new( e )
342
+
343
+ z_hex = Digest::SHA256.hexdigest( 'Programming Elliptic Curve Cryptography!' )
344
+ z = z_hex.to_i( 16 ) ## convert 256-bit (32-byte) hexstring to (big) integer number
345
+
346
+ sig = key.sign( z )
347
+ sig.r #=> 35839919642726191515862186078164267963984698217861116280002507416364797996230
348
+ sig.s #=> 34481949470477153440646085306694123309931748956488082604284303792820502002529
349
+
350
+
351
+ pubkey = key.pubkey ## derive public key from private
352
+ # And let's verify signature using public key
353
+ pubkey.verify?( z, sig ) #=> true
354
+
355
+ # -or-
356
+ pubkey = PublicKey.new(
357
+ 0xf01d6b9018ab421dd410404cb869072065522bf85734008f105cf385a023a80f,
358
+ 0x0eba29d0f0c5408ed681984dc525982abefccd9f7ff01dd26da4999cf3f6a295 )
359
+
360
+ sig = Signature.new(
361
+ 35839919642726191515862186078164267963984698217861116280002507416364797996230,
362
+ 34481949470477153440646085306694123309931748956488082604284303792820502002529 )
363
+
364
+ pubkey.verify?( z, sig ) #=> true
365
+ ```
366
+
367
+
368
+ That's it.
369
+
370
+
371
+
372
+
373
+ **Bitcon Public Service Announcement:**
374
+
375
+ > If we all buy Bitcoin from one another at ever higher
376
+ > prices we'll all be rich beyond our wildest dreams.
377
+ >
378
+ > -- Trolly McTrollface
379
+
380
+ **[BEWARE: Yes, Bitcoin Is a Ponzi - Learn How the Investment Fraud Works »](https://github.com/openblockchains/bitcoin-ponzi)**
381
+
382
+
383
+ ## Install
384
+
385
+ Just install the gem:
386
+
387
+ $ gem install elliptic-lite
388
+
389
+
390
+ ## License
391
+
392
+ The scripts are dedicated to the public domain.
393
+ Use it as you please with no restrictions whatsoever.
394
+
395
+
396
+ ## Questions? Comments?
397
+
398
+ Send them along to the [wwwmake forum](http://groups.google.com/group/wwwmake).
399
+ Thanks!
data/Rakefile ADDED
@@ -0,0 +1,29 @@
1
+ require 'hoe'
2
+ require './lib/elliptic-lite/version.rb'
3
+
4
+ Hoe.spec 'elliptic-lite' do
5
+
6
+ self.version = ECCLite::VERSION
7
+
8
+ self.summary = "elliptic-lite - elliptic curve cryptography from scratch / zero - start with finite fields, add elliptic curve points and point addition and scalar multiplications, add the elliptic curve digital signature algorithm (ECDSA) using the secp256k1 curve / group to sign and verify messages and more"
9
+ self.description = summary
10
+
11
+ self.urls = { home: 'https://github.com/rubycoco/blockchain' }
12
+
13
+ self.author = 'Gerald Bauer'
14
+ self.email = 'wwwmake@googlegroups.com'
15
+
16
+ # switch extension to .markdown for gihub formatting
17
+ self.readme_file = 'README.md'
18
+ self.history_file = 'CHANGELOG.md'
19
+
20
+ self.extra_deps = [
21
+ ]
22
+
23
+ self.licenses = ['Public Domain']
24
+
25
+ self.spec_extras = {
26
+ required_ruby_version: '>= 2.3'
27
+ }
28
+
29
+ end