elliptic 0.1.0 → 0.2.0

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