elliptic-lite 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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