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