elliptic 1.0.0 → 1.0.1
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 +4 -4
- data/Manifest.txt +5 -0
- data/lib/elliptic/private_key.rb +82 -0
- data/lib/elliptic/public_key.rb +85 -0
- data/lib/elliptic/signature.rb +41 -0
- data/lib/elliptic/version.rb +1 -1
- data/test/test_decode.rb +85 -0
- data/test/test_openssl.rb +40 -0
- metadata +6 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ff30ac78fc3b9f3528bec550afdfffc4bdc7c4f7049edf67280ba48150d6ce95
|
4
|
+
data.tar.gz: bb13fa5c43a30149dab2457a7ef78ec3c6478122e80c8fd450b99ed8e6998f31
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 48c3b6ffda0ee6f94aa43fe31fc963be9228aba19adff661ad63bbfc8737be084d8db2c412cee9fa85e7cb9d8fee97fb6e46eb0d752dfdc2bbf6ba0dcf6d322b
|
7
|
+
data.tar.gz: fb14d75d44756fe762f86b81425d6e13796bca980a3b8a5bbecef824fe363085366d3af51a6fffbd5de28d113af304960de1b6a06289cf3138c89a2e7915dc3c
|
data/Manifest.txt
CHANGED
@@ -4,7 +4,12 @@ README.md
|
|
4
4
|
Rakefile
|
5
5
|
i/secp256k1.png
|
6
6
|
lib/elliptic.rb
|
7
|
+
lib/elliptic/private_key.rb
|
8
|
+
lib/elliptic/public_key.rb
|
9
|
+
lib/elliptic/signature.rb
|
7
10
|
lib/elliptic/version.rb
|
8
11
|
test/helper.rb
|
12
|
+
test/test_decode.rb
|
13
|
+
test/test_openssl.rb
|
9
14
|
test/test_sign.rb
|
10
15
|
test/test_version.rb
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module EC
|
2
|
+
|
3
|
+
class PrivateKey
|
4
|
+
def self.convert( *args, **kwargs )
|
5
|
+
if args.size==1 && args[0].is_a?( PrivateKey )
|
6
|
+
args[0] ## pass through as is (already a private key)
|
7
|
+
else
|
8
|
+
new( args[0], group: kwargs[:group] )
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
|
13
|
+
def self.decode_pem( str ) new( str ); end
|
14
|
+
def self.decode_der( str ) new( str ); end
|
15
|
+
|
16
|
+
## todo/check: only use (allow) base64 for
|
17
|
+
## der (binary)-encoded? why? why not?
|
18
|
+
def self.decode_base64( str ) new( Base64.decode64(str)); end
|
19
|
+
|
20
|
+
class << self
|
21
|
+
alias_method :from_pem, :decode_pem
|
22
|
+
alias_method :from_der, :decode_der
|
23
|
+
alias_method :from_base64, :decode_base64
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
def self.generate( group: nil ) new( group: group ); end
|
28
|
+
|
29
|
+
|
30
|
+
def initialize( input=nil, group: nil )
|
31
|
+
if input.nil? ## auto-generate new key
|
32
|
+
ec_group = GROUP[ group || 'secp256k1' ]
|
33
|
+
@pkey = OpenSSL::PKey::EC.new( ec_group )
|
34
|
+
@pkey.generate_key # note: will generate private/public key pair
|
35
|
+
elsif input.is_a?( Integer )
|
36
|
+
ec_group = GROUP[ group || 'secp256k1' ]
|
37
|
+
@pkey = OpenSSL::PKey::EC.new( ec_group )
|
38
|
+
@pkey.private_key = OpenSSL::BN.new( input )
|
39
|
+
## auto-calculate public key too
|
40
|
+
@pkey.public_key = @pkey.group.generator.mul( @pkey.private_key )
|
41
|
+
else ## assume string with possible der/pem/etc. encoding
|
42
|
+
## todo/check: add hex-string auto-detect too - why? why not?
|
43
|
+
@pkey = OpenSSL::PKey::EC.new( input )
|
44
|
+
## todo/check: make sure public key gets restored too with pem/der-encoding??
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
def to_i() @pkey.private_key.to_i; end
|
50
|
+
## todo/check/fix: make it always a 32 byte (64 hex chars) string
|
51
|
+
## even with leading zeros !!! - why? why not?
|
52
|
+
def to_s() @pkey.private_key.to_i.to_s(16); end
|
53
|
+
|
54
|
+
|
55
|
+
def to_pem() @pkey.to_pem; end
|
56
|
+
def to_der() @pkey.to_der; end
|
57
|
+
def to_base64() Base64.encode64( to_der ); end
|
58
|
+
|
59
|
+
|
60
|
+
|
61
|
+
def public_key
|
62
|
+
## cache returned public key - why? why not?
|
63
|
+
@pub ||= PublicKey.new( @pkey.public_key )
|
64
|
+
@pub
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
def sign( message )
|
69
|
+
signature_der = @pkey.dsa_sign_asn1( message )
|
70
|
+
Signature.decode_der( signature_der )
|
71
|
+
end
|
72
|
+
|
73
|
+
|
74
|
+
################
|
75
|
+
## more helpers for debugging / internals
|
76
|
+
def group() @pkey.group; end
|
77
|
+
def to_text() @pkey.to_text; end
|
78
|
+
def private?() @pkey.private?; end ## todo/check: keep - needed? - why? why not?
|
79
|
+
def public?() @pkey.public?; end ## todo/check: keep - needed? - why? why not?
|
80
|
+
end # class PrivateKey
|
81
|
+
|
82
|
+
end ## module EC
|
@@ -0,0 +1,85 @@
|
|
1
|
+
module EC
|
2
|
+
|
3
|
+
|
4
|
+
class PublicKey
|
5
|
+
def self.convert( *args, **kwargs )
|
6
|
+
if args.size==1 && args[0].is_a?( PublicKey )
|
7
|
+
args[0] ## pass through as is (already a public key)
|
8
|
+
else
|
9
|
+
new( *args, group: kwargs[:group] )
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
|
15
|
+
def self.decode_pem( str ) new( str ); end
|
16
|
+
def self.decode_der( str ) new( str ); end
|
17
|
+
|
18
|
+
## todo/check: only use (allow) base64 for
|
19
|
+
## der (binary)-encoded? why? why not?
|
20
|
+
def self.decode_base64( str ) new( Base64.decode64(str)); end
|
21
|
+
|
22
|
+
class << self
|
23
|
+
alias_method :from_pem, :decode_pem
|
24
|
+
alias_method :from_der, :decode_der
|
25
|
+
alias_method :from_base64, :decode_base64
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
def initialize( *args, group: nil )
|
30
|
+
if args.size == 2 ## assume (x,y) raw integer points
|
31
|
+
@pt = Point.new( *args, group: group )
|
32
|
+
point = @pt.to_ec_point ## convert point to openssl (native) class
|
33
|
+
@pkey = OpenSSL::PKey::EC.new( point.group )
|
34
|
+
@pkey.public_key = point
|
35
|
+
elsif args[0].is_a?( Point ) ||
|
36
|
+
args[0].is_a?( OpenSSL::PKey::EC::Point )
|
37
|
+
## "restore" public key (only) from point for verify
|
38
|
+
## - OpenSSL::PKey::EC::Point ## assume public key only (restore pkey object for verify?)
|
39
|
+
## - Point
|
40
|
+
point = if args[0].is_a?( Point )
|
41
|
+
@pt = args[0]
|
42
|
+
@pt.to_ec_point
|
43
|
+
else
|
44
|
+
args[0] ## assume it is already OpenSSL::PKey::EC::Point
|
45
|
+
end
|
46
|
+
|
47
|
+
## note: (auto)get group from point
|
48
|
+
@pkey = OpenSSL::PKey::EC.new( point.group )
|
49
|
+
@pkey.public_key = point
|
50
|
+
else ## assume string in pem/der/base64
|
51
|
+
@pkey = OpenSSL::PKey::EC.new( args[0] )
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
|
57
|
+
def point
|
58
|
+
## cache returned point - why? why not?
|
59
|
+
@pt ||= Point.new( @pkey.public_key )
|
60
|
+
@pt
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
def to_pem() @pkey.to_pem; end
|
65
|
+
def to_der() @pkey.to_der; end
|
66
|
+
def to_base64() Base64.encode64( to_der ); end
|
67
|
+
|
68
|
+
|
69
|
+
def verify?( message, signature )
|
70
|
+
signature_der = signature.to_der
|
71
|
+
@pkey.dsa_verify_asn1( message, signature_der )
|
72
|
+
end
|
73
|
+
alias_method :valid_signature?, :verify?
|
74
|
+
|
75
|
+
|
76
|
+
###
|
77
|
+
## more helpers for debugging / internals
|
78
|
+
def group() @pkey.group; end
|
79
|
+
def to_text() @pkey.to_text; end
|
80
|
+
def private?() @pkey.private?; end ## todo/check: keep - needed? - why? why not?
|
81
|
+
def public?() @pkey.public?; end ## todo/check: keep - needed? - why? why not?
|
82
|
+
end # class PublicKey
|
83
|
+
|
84
|
+
|
85
|
+
end ## module EC
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module EC
|
2
|
+
|
3
|
+
class Signature
|
4
|
+
|
5
|
+
def self.decode_der( der )
|
6
|
+
asn1 = OpenSSL::ASN1.decode( der )
|
7
|
+
r = asn1.value[0].value.to_i
|
8
|
+
s = asn1.value[1].value.to_i
|
9
|
+
new(r, s)
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.decode_base64( str )
|
13
|
+
decode_der( Base64.decode64( str ) )
|
14
|
+
end
|
15
|
+
|
16
|
+
class << self
|
17
|
+
alias_method :from_der, :decode_der
|
18
|
+
alias_method :from_base64, :decode_base64
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
|
23
|
+
attr_reader :r, :s
|
24
|
+
def initialize(r, s)
|
25
|
+
@r, @s = r, s
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_der
|
29
|
+
asn1 = OpenSSL::ASN1::Sequence.new [
|
30
|
+
OpenSSL::ASN1::Integer.new( @r ),
|
31
|
+
OpenSSL::ASN1::Integer.new( @s ),
|
32
|
+
]
|
33
|
+
asn1.to_der
|
34
|
+
end
|
35
|
+
|
36
|
+
def to_base64
|
37
|
+
Base64.encode64( to_der ).gsub("\n", '' )
|
38
|
+
end
|
39
|
+
end ## class Signature
|
40
|
+
|
41
|
+
end ## module EC
|
data/lib/elliptic/version.rb
CHANGED
data/test/test_decode.rb
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
###
|
2
|
+
# to run use
|
3
|
+
# ruby -I ./lib -I ./test test/test_decode.rb
|
4
|
+
|
5
|
+
|
6
|
+
require 'helper'
|
7
|
+
|
8
|
+
|
9
|
+
class TestDecode < MiniTest::Test
|
10
|
+
|
11
|
+
|
12
|
+
def test_import_export
|
13
|
+
|
14
|
+
private_key = EC::PrivateKey.generate
|
15
|
+
puts "PrivateKey#to_i:"
|
16
|
+
puts private_key.to_i
|
17
|
+
puts "PrivateKey#to_s:"
|
18
|
+
puts private_key.to_s
|
19
|
+
puts "PrivateKey#to_pem:"
|
20
|
+
puts private_key.to_pem
|
21
|
+
puts "PrivateKey#to_der (binary / asn1):"
|
22
|
+
puts private_key.to_der
|
23
|
+
pp private_key.to_der
|
24
|
+
puts "PrivateKey#to_base64:"
|
25
|
+
puts private_key.to_base64
|
26
|
+
|
27
|
+
public_key = private_key.public_key
|
28
|
+
assert_equal false, public_key.private? ## make sure (derived) public key has no private key included/attached
|
29
|
+
|
30
|
+
puts "PublicKey#point:"
|
31
|
+
pp public_key.point
|
32
|
+
puts "PublicKey#point.to_s:"
|
33
|
+
puts public_key.point.to_s
|
34
|
+
puts "PublicKey#to_pem:"
|
35
|
+
puts public_key.to_pem
|
36
|
+
puts "PublicKey#to_der (binary / asn1):"
|
37
|
+
puts public_key.to_der
|
38
|
+
pp public_key.to_der
|
39
|
+
puts "PublicKey#to_base64:"
|
40
|
+
puts public_key.to_base64
|
41
|
+
|
42
|
+
|
43
|
+
|
44
|
+
[
|
45
|
+
EC::PrivateKey.new( private_key.to_i ),
|
46
|
+
|
47
|
+
EC::PrivateKey.new( private_key.to_pem ),
|
48
|
+
EC::PrivateKey.decode_pem( private_key.to_pem ),
|
49
|
+
|
50
|
+
EC::PrivateKey.new( private_key.to_der ),
|
51
|
+
EC::PrivateKey.decode_der( private_key.to_der ),
|
52
|
+
|
53
|
+
EC::PrivateKey.decode_base64( private_key.to_base64 ),
|
54
|
+
].each do |private_key_decoded|
|
55
|
+
assert_equal private_key_decoded.to_i, private_key.to_i
|
56
|
+
assert private_key_decoded.private?
|
57
|
+
assert private_key_decoded.public?
|
58
|
+
|
59
|
+
assert_equal false, private_key_decoded.public_key.private?
|
60
|
+
assert_equal private_key_decoded.public_key.point.to_s, public_key.point.to_s
|
61
|
+
assert_equal private_key_decoded.public_key.point.x, public_key.point.x
|
62
|
+
assert_equal private_key_decoded.public_key.point.y, public_key.point.y
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
[
|
67
|
+
EC::PublicKey.new( public_key.point ),
|
68
|
+
|
69
|
+
EC::PublicKey.new( public_key.to_pem ),
|
70
|
+
EC::PublicKey.decode_pem( public_key.to_pem ),
|
71
|
+
|
72
|
+
EC::PublicKey.new( public_key.to_der ),
|
73
|
+
EC::PublicKey.decode_der( public_key.to_der ),
|
74
|
+
|
75
|
+
EC::PublicKey.decode_base64( public_key.to_base64 ),
|
76
|
+
].each do |public_key_decoded|
|
77
|
+
assert_equal public_key_decoded.point.to_s, public_key.point.to_s
|
78
|
+
assert_equal public_key_decoded.point.x, public_key.point.x
|
79
|
+
assert_equal public_key_decoded.point.y, public_key.point.y
|
80
|
+
assert public_key_decoded.public?
|
81
|
+
assert_equal false, public_key_decoded.private?
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
end # class TestDecode
|
@@ -0,0 +1,40 @@
|
|
1
|
+
###
|
2
|
+
# to run use
|
3
|
+
# ruby -I ./lib -I ./test test/test_openssl.rb
|
4
|
+
|
5
|
+
|
6
|
+
require 'helper'
|
7
|
+
|
8
|
+
|
9
|
+
## test some "basic" openssl (binding) machinery
|
10
|
+
## for source, see https://github.com/ruby/openssl
|
11
|
+
|
12
|
+
class TestOpenssl < MiniTest::Test
|
13
|
+
|
14
|
+
def test_version
|
15
|
+
puts "OPENSSL_VERSION: #{OpenSSL::OPENSSL_VERSION}"
|
16
|
+
puts "OPENSSL_LIBRARY_VERSION: #{OpenSSL::OPENSSL_LIBRARY_VERSION}"
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
def test_bn
|
21
|
+
[999,
|
22
|
+
-999,
|
23
|
+
2**107-1,
|
24
|
+
-(2**107-1)].each do |num|
|
25
|
+
assert_equal OpenSSL::BN.new( num ), num.to_bn
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_bn_to_hex
|
30
|
+
[
|
31
|
+
[999, "03E7"],
|
32
|
+
[-999, "-03E7"],
|
33
|
+
[2**107-1, "07FFFFFFFFFFFFFFFFFFFFFFFFFF"],
|
34
|
+
[-(2**107-1), "-07FFFFFFFFFFFFFFFFFFFFFFFFFF"]
|
35
|
+
].each do |item|
|
36
|
+
assert_equal item[1], item[0].to_bn.to_s(16)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
end # class TestOpenssl
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: elliptic
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gerald Bauer
|
@@ -60,8 +60,13 @@ files:
|
|
60
60
|
- Rakefile
|
61
61
|
- i/secp256k1.png
|
62
62
|
- lib/elliptic.rb
|
63
|
+
- lib/elliptic/private_key.rb
|
64
|
+
- lib/elliptic/public_key.rb
|
65
|
+
- lib/elliptic/signature.rb
|
63
66
|
- lib/elliptic/version.rb
|
64
67
|
- test/helper.rb
|
68
|
+
- test/test_decode.rb
|
69
|
+
- test/test_openssl.rb
|
65
70
|
- test/test_sign.rb
|
66
71
|
- test/test_version.rb
|
67
72
|
homepage: https://github.com/rubycoco/blockchain
|