elliptic 0.1.0 → 0.2.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: ef1dcaf22384ecedc56973cf3e2a75bb5da817bb6d5dcaa65f5559e48d4731d4
4
- data.tar.gz: a4b7cf7b207cddae72ddd7a5a2cd848fe41e824d56284f46ffb65e3332f96d50
3
+ metadata.gz: 50c1f0afa4d55fd9b936ddc1ef0c38ede63054432aae99aa2b717ba21bc819c7
4
+ data.tar.gz: e9d57e5bfece39941288e66fd9b087d99660dfa25a42e723b69f96f85c690fd0
5
5
  SHA512:
6
- metadata.gz: f78242b719f4871949419099adde1cb3f209d11f176f761aefba7d7828a597ff30f1e4b75fae8ed1048612a226f9dabc4758f21be01466c486851ee483f00a84
7
- data.tar.gz: e4561b2707ec6c5dce8e5e09d7dbc516dc5434dbbce7e03e773f6ef8ff0aff7610c9998da0e9c27b9baec976b71e97dccc853c8e9c548a5904476a5297822475
6
+ metadata.gz: 56cc6e7d72f921b61701d6ca2d1d25383b91377607752db4f96a7d12c56881fdfda1bcccfe2177ff8695114de81822ea9fbc8b0ccecfa1546f4c678393b2b933
7
+ data.tar.gz: c8ec4acab2b3495b8937bee4e7488d6d3922b31a6ec13473a877ea30249319e0c8eacc4c89062cd76d3e1a4c078c95d36579b2b420b2a55e931ace6be9b69692
data/README.md CHANGED
@@ -73,10 +73,10 @@ An ECDSA (Elliptic Curve Digital Signature Algorithm) private key is a random nu
73
73
  ``` ruby
74
74
  require 'elliptic'
75
75
 
76
- # note: Algo will auto-generate (random) private key if no private key passed in
77
- algo = EC::Algo.new # by default uses Secp256k1 curve (used in Bitcoin and Ethereum)
76
+ # Auto-generate (random) private key
77
+ private_key = EC::PrivateKey.generate # by default uses Secp256k1 curve (used in Bitcoin and Ethereum)
78
78
 
79
- algo.private_key
79
+ private_key.to_i
80
80
  #=> 72190737707147846840353520312904745954595478835413056312168022784020322830309
81
81
  ```
82
82
 
@@ -92,11 +92,10 @@ Let's try:
92
92
 
93
93
  ``` ruby
94
94
  # This private key is just an example. It should be much more secure!
95
- privatekey = 1234
95
+ private_key = EC::PrivateKey.new( 1234 ) # by default uses Secp256k1 curve (used in Bitcoin and Ethereum)
96
96
 
97
- # Elliptic curve (EC) machinery - pass in our own key
98
- algo = EC::Algo.new( privatekey ) # by default uses Secp256k1 curve (used in Bitcoin and Ethereum)
99
- point = algo.public_key ## the "magic" one-way K=k*G curve multiplication (K=public key,k=private key, G=generator point)
97
+ public_key = private_key.public_key ## the "magic" one-way K=k*G curve multiplication (K=public key,k=private key, G=generator point)
98
+ point = public_key.point
100
99
 
101
100
  point.x
102
101
  #=> 102884003323827292915668239759940053105992008087520207150474896054185180420338
@@ -120,10 +119,12 @@ tx = 'from: Alice to: Bob cryptos: 43_000_000_000'
120
119
  txhash = Digest::SHA256.digest( tx )
121
120
 
122
121
  # Step 2 - Get the Signer's Private key
123
- privatekey = 1234 # This private key is just an example. It should be much more secure!
122
+ private_key = EC::PrivateKey.new( 1234 ) # This private key is just an example. It should be much more secure!
124
123
 
125
124
  # Sign!
126
- signature = EC.sign( txhash, privatekey )
125
+ signature = private_key.sign( txhash )
126
+ # -or-
127
+ signature = EC.sign( txhash, private_key )
127
128
 
128
129
  signature.r
129
130
  #=> 80563021554295584320113598933963644829902821722081604563031030942154621916407
@@ -145,7 +146,7 @@ tx = 'from: Alice to: Bob cryptos: 43_000_000_000'
145
146
  txhash = Digest::SHA256.digest( tx )
146
147
 
147
148
  # Step 2 - Get the Signer's Public Key
148
- pubkey = EC::Point.new(
149
+ public_key = EC::PublicKey.new(
149
150
  102884003323827292915668239759940053105992008087520207150474896054185180420338,
150
151
  49384988101491619794462775601349526588349137780292274540231125201115197157452
151
152
  )
@@ -157,13 +158,15 @@ signature = EC::Signature.new(
157
158
  )
158
159
 
159
160
  # Don't Trust - Verify
160
- EC.valid_signature?( txhash, pubkey, signature )
161
+ public_key.verify?( txhash, signature )
162
+ # -or-
163
+ EC.verify?( txhash, signature, public_key )
161
164
  #=> true
162
165
 
163
166
 
164
167
  # or using hexadecimal numbers
165
168
 
166
- pubkey = EC::Point.new(
169
+ public_key = EC::PublicKey.new(
167
170
  0xe37648435c60dcd181b3d41d50857ba5b5abebe279429aa76558f6653f1658f2,
168
171
  0x6d2ee9a82d4158f164ae653e9c6fa7f982ed8c94347fc05c2d068ff1d38b304c
169
172
  )
@@ -173,7 +176,9 @@ signature = EC::Signature.new(
173
176
  0x4fe202bb0835758f514cd4a0787986f8f6bf303df629dc98c5b1a438a426f49a
174
177
  )
175
178
 
176
- EC.valid_signature?( txhash, pubkey, signature )
179
+ public_key.verify?( txhash, signature )
180
+ # -or-
181
+ EC.verify?( txhash, signature, public_key )
177
182
  #=> true
178
183
  ```
179
184
 
@@ -66,8 +66,7 @@ module EC
66
66
 
67
67
  ## encoded_point is the octet string representation of the point.
68
68
  ## This must be either a String or an OpenSSL::BN
69
- prefix = '04'
70
- hex = prefix + ("%064x" % @x) + ("%064x" % @y)
69
+ hex = '04' + ("%064x" % @x) + ("%064x" % @y)
71
70
  bin = [hex].pack( 'H*' )
72
71
 
73
72
  ec_group = GROUP[ group || 'secp256k1' ]
@@ -89,62 +88,54 @@ module EC
89
88
  end
90
89
 
91
90
  ## return OpenSSL::PKey::EC::Point - find a better name? e.g. to_raw/native or such - why? why not?
92
- def to_point() @pt; end
91
+ def to_ec_point() @pt; end
93
92
  end
94
93
 
95
94
 
96
95
 
97
96
 
98
- class Algo
99
- def initialize( input=nil, group: nil )
100
-
101
- ## case 1) "restore" public key (only) from point for verify
102
- if input.is_a?( OpenSSL::PKey::EC::Point ) || ## assume public key only (restore pkey object for verify?)
103
- input.is_a?( Point )
104
-
105
- point = input.is_a?( Point ) ? input.to_point : input
106
-
107
- ## note: (auto)get group from point
108
- @pkey = OpenSSL::PKey::EC.new( point.group )
109
- @pkey.public_key = point
110
- else ## case 2) build a private/public key pair
111
-
112
- ec_group = GROUP[ group || 'secp256k1' ]
113
- @pkey = OpenSSL::PKey::EC.new( ec_group )
114
-
115
- if input.nil? ## auto-generate new key
116
- @pkey.generate_key
117
- else
118
- num = if input.is_a?( String )
119
- input.to_i( 16 )
120
- else ## assume (big) integer
121
- input
122
- end
123
- @pkey.private_key = OpenSSL::BN.new( num )
124
- ## auto-calculate public key too
125
- @pkey.public_key = @pkey.group.generator.mul( @pkey.private_key )
126
- end
97
+ class PublicKey
98
+ def self.convert( *args, **kwargs )
99
+ if args.size==1 && args[0].is_a?( PublicKey )
100
+ args[0] ## pass through as is (already a public key)
101
+ else
102
+ new( *args, group: kwargs[:group] )
127
103
  end
128
104
  end
129
105
 
130
106
 
131
- def group() @pkey.group; end
132
107
 
133
- def public?() @pkey.public?; end
134
- def private?() @pkey.private?; end
108
+ def initialize( *args, group: nil )
109
+ point = if args.size == 2 ## assume (x,y) raw integer points
110
+ @pt = Point.new( *args, group: group )
111
+ @pt.to_ec_point ## convert point to openssl (native) class
112
+ else
113
+ ## "restore" public key (only) from point for verify
114
+ ## - OpenSSL::PKey::EC::Point ## assume public key only (restore pkey object for verify?)
115
+ ## - Point
116
+ if args[0].is_a?( Point )
117
+ @pt = args[0]
118
+ @pt.to_ec_point
119
+ else
120
+ args[0] ## assume it is already OpenSSL::PKey::EC::Point
121
+ end
122
+ end
123
+
124
+ ## note: (auto)get group from point
125
+ @pkey = OpenSSL::PKey::EC.new( point.group )
126
+ @pkey.public_key = point
127
+ end
135
128
 
129
+ def group() @pkey.group; end
136
130
 
137
- ## todo/check/fix: fix case with no private_key if passed in point/public key for verify!!!
138
- def private_key() @pkey.private_key.to_i; end
139
- alias_method :priv_key, :private_key ## add signing_key alias too?
140
131
 
141
- def public_key() @public_key ||= Point.new( @pkey.public_key ); end
132
+ def point
133
+ ## cache returned point - why? why not?
134
+ @pt ||= Point.new( @pkey.public_key )
135
+ @pt
136
+ end
142
137
 
143
138
 
144
- def sign( message )
145
- signature_der = @pkey.dsa_sign_asn1( message )
146
- Signature.decode_der( signature_der )
147
- end
148
139
 
149
140
  def verify?( message, signature )
150
141
  signature_der = signature.to_der
@@ -152,20 +143,81 @@ module EC
152
143
  end
153
144
  alias_method :valid_signature?, :verify?
154
145
 
155
-
146
+ ## helpers for debugging
156
147
  def to_text() @pkey.to_text; end
157
- end
148
+ def public?() @pkey.public?; end ## todo/check: keep - needed? - why? why not?
149
+ end # class PublicKey
150
+
151
+
152
+
153
+
154
+ class PrivateKey
155
+ def self.convert( *args, **kwargs )
156
+ if args.size==1 && args[0].is_a?( PrivateKey )
157
+ args[0] ## pass through as is (alread a private key)
158
+ else
159
+ new( args[0], group: kwargs[:group] )
160
+ end
161
+ end
162
+
163
+
164
+ def self.generate( group: nil ) new( group: group ); end
165
+
166
+ def initialize( input=nil, group: nil )
167
+ ec_group = GROUP[ group || 'secp256k1' ]
168
+ @pkey = OpenSSL::PKey::EC.new( ec_group )
169
+
170
+ if input.nil? ## auto-generate new key
171
+ @pkey.generate_key
172
+ else
173
+ num = if input.is_a?( String ) ## assume hex string
174
+ input.to_i( 16 )
175
+ else ## assume integer
176
+ input
177
+ end
178
+ @pkey.private_key = OpenSSL::BN.new( num )
179
+ ## auto-calculate public key too
180
+ @pkey.public_key = @pkey.group.generator.mul( @pkey.private_key )
181
+ end
182
+ end
183
+
184
+ def to_i() @pkey.private_key.to_i; end
185
+ ## todo/check/fix: make it always a 32 byte (64 hex chars) string
186
+ ## even with leading zeros !!! - why? why not?
187
+ def to_s() @pkey.private_key.to_i.to_s(16); end
188
+
189
+ def group() @pkey.group; end
190
+
191
+
192
+ def public_key
193
+ ## cache returned public key - why? why not?
194
+ @pub ||= PublicKey.new( @pkey.public_key )
195
+ @pub
196
+ end
197
+
198
+
199
+ def sign( message )
200
+ signature_der = @pkey.dsa_sign_asn1( message )
201
+ Signature.decode_der( signature_der )
202
+ end
203
+
204
+ ## helpers for debugging
205
+ def to_text() @pkey.to_text; end
206
+ def private?() @pkey.private?; end ## todo/check: keep - needed? - why? why not?
207
+ end # class PrivateKey
208
+
209
+
158
210
 
159
211
 
160
212
 
161
213
  def self.sign( message, priv_key )
162
- algo = Algo.new( priv_key )
163
- algo.sign( message )
214
+ signer = PrivateKey.convert( priv_key )
215
+ signer.sign( message )
164
216
  end
165
217
 
166
- def self.verify?( message, pub_key, signature )
167
- algo = Algo.new( pub_key )
168
- algo.verify?( message, signature )
218
+ def self.verify?( message, signature, pub_key )
219
+ verifier = PublicKey.convert( pub_key )
220
+ verifier.verify?( message, signature )
169
221
  end
170
222
 
171
223
  class << self
@@ -4,7 +4,7 @@
4
4
  module EC
5
5
 
6
6
  MAJOR = 0
7
- MINOR = 1
7
+ MINOR = 2
8
8
  PATCH = 0
9
9
  VERSION = [MAJOR,MINOR,PATCH].join('.')
10
10
 
@@ -10,76 +10,76 @@ class TestSign < MiniTest::Test
10
10
 
11
11
 
12
12
  def test_keys
13
- algo = EC::Algo.new( 1234 )
14
- assert_equal 1234, algo.private_key
15
- assert_equal "secp256k1", algo.group.curve_name
13
+ private_key = EC::PrivateKey.new( 1234 )
14
+ assert_equal 1234, private_key.to_i
15
+ assert_equal "secp256k1", private_key.group.curve_name
16
16
 
17
- public_key = algo.public_key
17
+ public_key = private_key.public_key
18
18
  assert_equal 102884003323827292915668239759940053105992008087520207150474896054185180420338,
19
- public_key.x
19
+ public_key.point.x
20
20
 
21
21
  assert_equal 49384988101491619794462775601349526588349137780292274540231125201115197157452,
22
- public_key.y
22
+ public_key.point.y
23
23
 
24
24
  assert_equal "e37648435c60dcd181b3d41d50857ba5b5abebe279429aa76558f6653f1658f2",
25
- public_key.x.to_s(16)
25
+ public_key.point.x.to_s(16)
26
26
  assert_equal "6d2ee9a82d4158f164ae653e9c6fa7f982ed8c94347fc05c2d068ff1d38b304c",
27
- public_key.y.to_s(16)
27
+ public_key.point.y.to_s(16)
28
28
 
29
29
  assert_equal "02e37648435c60dcd181b3d41d50857ba5b5abebe279429aa76558f6653f1658f2",
30
- public_key.to_s( :compressed )
30
+ public_key.point.to_s( :compressed )
31
31
 
32
32
  assert_equal "04e37648435c60dcd181b3d41d50857ba5b5abebe279429aa76558f6653f1658f26d2ee9a82d4158f164ae653e9c6fa7f982ed8c94347fc05c2d068ff1d38b304c",
33
- public_key.to_s
33
+ public_key.point.to_s
34
34
  end
35
35
 
36
36
  def test_sign
37
- algo = EC::Algo.new( 1234 )
38
- priv_key = algo.private_key
37
+ private_key = EC::PrivateKey.new( 1234 )
39
38
 
40
39
  message = Digest::SHA256.digest( "hello" )
41
40
 
42
41
  ## note: sign uses a secure random generated temp key
43
42
  ## every signature is different!!!
44
- signature = EC.sign( message, priv_key )
43
+ signature = EC.sign( message, private_key )
45
44
  pp signature.to_der
46
45
 
47
- signature = EC.sign( message, priv_key )
46
+ signature = EC.sign( message, private_key )
48
47
  pp signature.to_der
49
48
 
50
- signature = EC.sign( message, priv_key )
49
+ signature = private_key.sign( message )
51
50
  pp signature.to_der
52
51
 
53
- pp algo.sign( message )
52
+ signature = private_key.sign( message )
53
+ pp signature.to_der
54
54
 
55
55
 
56
56
  ### verify
57
- public_key = algo.public_key
57
+ public_key = private_key.public_key
58
58
 
59
- assert EC.verify?( message, public_key, signature )
60
- assert EC.valid_signature?( message, public_key, signature )
59
+ assert EC.verify?( message, signature, public_key )
60
+ assert EC.valid_signature?( message, signature, public_key )
61
61
 
62
- assert algo.verify?( message, signature )
63
- assert algo.valid_signature?( message, signature )
62
+ assert public_key.verify?( message, signature )
63
+ assert public_key.valid_signature?( message, signature )
64
64
 
65
65
  ## public key from point (x,y)
66
66
  point = EC::Point.new(
67
67
  102884003323827292915668239759940053105992008087520207150474896054185180420338,
68
68
  49384988101491619794462775601349526588349137780292274540231125201115197157452)
69
- assert EC.verify?( message, point, signature )
69
+ assert EC.verify?( message, signature, point )
70
70
 
71
71
  ## signature from r,s values
72
72
  signature = EC::Signature.new(
73
73
  17435452009115387225781053203681496505351828576563920844344513414624978140095,
74
74
  57357162317582879484266879619863223941116872722080991745355058707843528515381)
75
- assert EC.verify?( message, point, signature )
75
+ assert EC.verify?( message, signature, point )
76
76
 
77
77
 
78
78
 
79
79
  ## tamper with message
80
80
  message = Digest::SHA256.digest( "hellox" )
81
- assert_equal false, EC.verify?( message, public_key, signature )
82
- assert_equal false, algo.verify?( message, signature )
81
+ assert_equal false, EC.verify?( message, signature, public_key )
82
+ assert_equal false, public_key.verify?( message, signature )
83
83
  end
84
84
 
85
85
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: elliptic
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gerald Bauer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-01-22 00:00:00.000000000 Z
11
+ date: 2021-01-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rdoc