bitcoin-ruby 0.0.19 → 0.0.20
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +3 -4
- data/Gemfile.lock +1 -1
- data/README.rdoc +3 -5
- data/lib/bitcoin/ffi/openssl.rb +74 -70
- data/lib/bitcoin/version.rb +1 -1
- data/spec/unit/bitcoin/bitcoin_spec.rb +52 -71
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e51bd4140526e976852120dfe9344601ad9caf197ff5698830809d806b083e61
|
4
|
+
data.tar.gz: 13edf822bb99da797c2f6d14a6da8cf37ef1c5fb0c13da52c41504d368569407
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 17b545b9b7185e214ced2e054083023cc5dbf2913e8dbc070a05cffe6dc2eec302f8c2d7fb06fc66d8f9d045807e06a9dd35f2ed7753a5b68a4ac3d924dcc402
|
7
|
+
data.tar.gz: eb8c40b9bda53151c1d564964f35ea695cb02b68fb5856fc720faf9a63674486c1ac116c8d0aa6987efdb3f4f68cd3698c1acb9624c0acaba2b98fcb6826690a
|
data/.travis.yml
CHANGED
data/Gemfile.lock
CHANGED
data/README.rdoc
CHANGED
data/lib/bitcoin/ffi/openssl.rb
CHANGED
@@ -10,16 +10,68 @@ module Bitcoin
|
|
10
10
|
if FFI::Platform.windows?
|
11
11
|
ffi_lib 'libeay32', 'ssleay32'
|
12
12
|
else
|
13
|
-
ffi_lib [
|
13
|
+
ffi_lib [
|
14
|
+
'libssl.so.1.1.0', 'libssl.so.1.1',
|
15
|
+
'libssl.so.1.0.0', 'libssl.so.10',
|
16
|
+
'ssl'
|
17
|
+
]
|
14
18
|
end
|
15
19
|
|
16
20
|
NID_secp256k1 = 714 # rubocop:disable Naming/ConstantName
|
17
21
|
POINT_CONVERSION_COMPRESSED = 2
|
18
22
|
POINT_CONVERSION_UNCOMPRESSED = 4
|
19
23
|
|
20
|
-
|
21
|
-
|
22
|
-
|
24
|
+
# OpenSSL 1.1.0 version as a numerical version value as defined in:
|
25
|
+
# https://www.openssl.org/docs/man1.1.0/man3/OpenSSL_version.html
|
26
|
+
VERSION_1_1_0_NUM = 0x10100000
|
27
|
+
|
28
|
+
# OpenSSL 1.1.0 engine constants, taken from:
|
29
|
+
# https://github.com/openssl/openssl/blob/2be8c56a39b0ec2ec5af6ceaf729df154d784a43/include/openssl/crypto.h
|
30
|
+
OPENSSL_INIT_ENGINE_RDRAND = 0x00000200
|
31
|
+
OPENSSL_INIT_ENGINE_DYNAMIC = 0x00000400
|
32
|
+
OPENSSL_INIT_ENGINE_CRYPTODEV = 0x00001000
|
33
|
+
OPENSSL_INIT_ENGINE_CAPI = 0x00002000
|
34
|
+
OPENSSL_INIT_ENGINE_PADLOCK = 0x00004000
|
35
|
+
OPENSSL_INIT_ENGINE_ALL_BUILTIN = (
|
36
|
+
OPENSSL_INIT_ENGINE_RDRAND |
|
37
|
+
OPENSSL_INIT_ENGINE_DYNAMIC |
|
38
|
+
OPENSSL_INIT_ENGINE_CRYPTODEV |
|
39
|
+
OPENSSL_INIT_ENGINE_CAPI |
|
40
|
+
OPENSSL_INIT_ENGINE_PADLOCK
|
41
|
+
)
|
42
|
+
|
43
|
+
# OpenSSL 1.1.0 load strings constant, taken from:
|
44
|
+
# https://github.com/openssl/openssl/blob/c162c126be342b8cd97996346598ecf7db56130f/include/openssl/ssl.h
|
45
|
+
OPENSSL_INIT_LOAD_SSL_STRINGS = 0x00200000
|
46
|
+
|
47
|
+
# This is the very first function we need to use to determine what version
|
48
|
+
# of OpenSSL we are interacting with.
|
49
|
+
begin
|
50
|
+
attach_function :OpenSSL_version_num, [], :ulong
|
51
|
+
rescue FFI::NotFoundError
|
52
|
+
attach_function :SSLeay, [], :long
|
53
|
+
end
|
54
|
+
|
55
|
+
# Returns the version of SSL present.
|
56
|
+
#
|
57
|
+
# @return [Integer] version number as an integer.
|
58
|
+
def self.version
|
59
|
+
if self.respond_to?(:OpenSSL_version_num)
|
60
|
+
OpenSSL_version_num()
|
61
|
+
else
|
62
|
+
SSLeay()
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
if version >= VERSION_1_1_0_NUM
|
67
|
+
# Initialization procedure for the library was changed in OpenSSL 1.1.0
|
68
|
+
attach_function :OPENSSL_init_ssl, [:uint64, :pointer], :int
|
69
|
+
else
|
70
|
+
attach_function :SSL_library_init, [], :int
|
71
|
+
attach_function :ERR_load_crypto_strings, [], :void
|
72
|
+
attach_function :SSL_load_error_strings, [], :void
|
73
|
+
end
|
74
|
+
|
23
75
|
attach_function :RAND_poll, [], :int
|
24
76
|
|
25
77
|
attach_function :BN_CTX_free, [:pointer], :int
|
@@ -28,7 +80,6 @@ module Bitcoin
|
|
28
80
|
attach_function :BN_bin2bn, %i[pointer int pointer], :pointer
|
29
81
|
attach_function :BN_bn2bin, %i[pointer pointer], :int
|
30
82
|
attach_function :BN_cmp, %i[pointer pointer], :int
|
31
|
-
attach_function :BN_copy, %i[pointer pointer], :pointer
|
32
83
|
attach_function :BN_dup, [:pointer], :pointer
|
33
84
|
attach_function :BN_free, [:pointer], :int
|
34
85
|
attach_function :BN_mod_inverse, %i[pointer pointer pointer pointer], :pointer
|
@@ -51,22 +102,17 @@ module Bitcoin
|
|
51
102
|
attach_function :EC_KEY_set_private_key, %i[pointer pointer], :int
|
52
103
|
attach_function :EC_KEY_set_public_key, %i[pointer pointer], :int
|
53
104
|
attach_function :EC_POINT_free, [:pointer], :int
|
54
|
-
attach_function :EC_POINT_is_at_infinity, %i[pointer pointer], :int
|
55
105
|
attach_function :EC_POINT_mul, %i[pointer pointer pointer pointer pointer pointer], :int
|
56
106
|
attach_function :EC_POINT_new, [:pointer], :pointer
|
57
107
|
attach_function :EC_POINT_set_compressed_coordinates_GFp,
|
58
108
|
%i[pointer pointer pointer int pointer], :int
|
59
|
-
attach_function :d2i_ECPrivateKey, %i[pointer pointer long], :pointer
|
60
|
-
attach_function :i2d_ECPrivateKey, %i[pointer pointer], :int
|
61
109
|
attach_function :i2o_ECPublicKey, %i[pointer pointer], :uint
|
62
|
-
attach_function :EC_KEY_check_key, [:pointer], :uint
|
63
110
|
attach_function :ECDSA_do_sign, %i[pointer uint pointer], :pointer
|
64
111
|
attach_function :BN_num_bits, [:pointer], :int
|
65
112
|
attach_function :ECDSA_SIG_free, [:pointer], :void
|
66
113
|
attach_function :EC_POINT_add, %i[pointer pointer pointer pointer pointer], :int
|
67
114
|
attach_function :EC_POINT_point2hex, %i[pointer pointer int pointer], :string
|
68
115
|
attach_function :EC_POINT_hex2point, %i[pointer string pointer pointer], :pointer
|
69
|
-
attach_function :ECDSA_SIG_new, [], :pointer
|
70
116
|
attach_function :d2i_ECDSA_SIG, %i[pointer pointer long], :pointer
|
71
117
|
attach_function :i2d_ECDSA_SIG, %i[pointer pointer], :int
|
72
118
|
attach_function :OPENSSL_free, :CRYPTO_free, [:pointer], :void
|
@@ -82,68 +128,17 @@ module Bitcoin
|
|
82
128
|
private_key = [private_key].pack('H*') if private_key.bytesize >= (32 * 2)
|
83
129
|
private_key_hex = private_key.unpack('H*')[0]
|
84
130
|
|
85
|
-
|
86
|
-
|
87
|
-
private_key =
|
88
|
-
|
89
|
-
init_ffi_ssl
|
90
|
-
eckey = EC_KEY_new_by_curve_name(NID_secp256k1)
|
91
|
-
# priv_key = BN_bin2bn(private_key, private_key.size, BN_new())
|
92
|
-
priv_key = BN_bin2bn(private_key, private_key.size - 1, BN_new())
|
93
|
-
|
94
|
-
group = EC_KEY_get0_group(eckey)
|
95
|
-
order = BN_new()
|
96
|
-
ctx = BN_CTX_new()
|
97
|
-
EC_GROUP_get_order(group, order, ctx)
|
98
|
-
|
99
|
-
pub_key = EC_POINT_new(group)
|
100
|
-
EC_POINT_mul(group, pub_key, priv_key, nil, nil, ctx)
|
101
|
-
EC_KEY_set_private_key(eckey, priv_key)
|
102
|
-
EC_KEY_set_public_key(eckey, pub_key)
|
103
|
-
|
104
|
-
BN_free(order)
|
105
|
-
BN_CTX_free(ctx)
|
106
|
-
EC_POINT_free(pub_key)
|
107
|
-
BN_free(priv_key)
|
108
|
-
|
109
|
-
length = i2d_ECPrivateKey(eckey, nil)
|
110
|
-
buf = FFI::MemoryPointer.new(:uint8, length)
|
111
|
-
ptr = FFI::MemoryPointer.new(:pointer).put_pointer(0, buf)
|
112
|
-
priv_hex = if i2d_ECPrivateKey(eckey, ptr) == length
|
113
|
-
size = buf.get_array_of_uint8(8, 1)[0]
|
114
|
-
buf.get_array_of_uint8(9, size).pack('C*').rjust(32, "\x00").unpack('H*')[0]
|
115
|
-
# der_to_private_key( ptr.read_pointer.read_string(length).unpack("H*")[0] )
|
116
|
-
end
|
131
|
+
group = OpenSSL::PKey::EC::Group.new('secp256k1')
|
132
|
+
key = OpenSSL::PKey::EC.new(group)
|
133
|
+
key.private_key = OpenSSL::BN.new(private_key_hex, 16)
|
134
|
+
key.public_key = group.generator.mul(key.private_key)
|
117
135
|
|
136
|
+
priv_hex = key.private_key.to_bn.to_s(16).downcase.rjust(64, '0')
|
118
137
|
if priv_hex != private_key_hex
|
119
138
|
raise 'regenerated wrong private_key, raise here before generating a faulty public_key too!'
|
120
139
|
end
|
121
140
|
|
122
|
-
|
123
|
-
buf = FFI::MemoryPointer.new(:uint8, length)
|
124
|
-
ptr = FFI::MemoryPointer.new(:pointer).put_pointer(0, buf)
|
125
|
-
pub_hex = buf.read_string(length).unpack('H*')[0] if i2o_ECPublicKey(eckey, ptr) == length
|
126
|
-
|
127
|
-
EC_KEY_free(eckey)
|
128
|
-
|
129
|
-
[priv_hex, pub_hex]
|
130
|
-
end
|
131
|
-
|
132
|
-
# extract private key from uncompressed DER format
|
133
|
-
def self.der_to_private_key(der_hex)
|
134
|
-
init_ffi_ssl
|
135
|
-
# k = EC_KEY_new_by_curve_name(NID_secp256k1)
|
136
|
-
# kp = FFI::MemoryPointer.new(:pointer).put_pointer(0, eckey)
|
137
|
-
|
138
|
-
buf = FFI::MemoryPointer.from_string([der_hex].pack('H*'))
|
139
|
-
ptr = FFI::MemoryPointer.new(:pointer).put_pointer(0, buf)
|
140
|
-
|
141
|
-
# ec_key = d2i_ECPrivateKey(kp, ptr, buf.size-1)
|
142
|
-
ec_key = d2i_ECPrivateKey(nil, ptr, buf.size - 1)
|
143
|
-
return nil if ec_key.null?
|
144
|
-
bn = EC_KEY_get0_private_key(ec_key)
|
145
|
-
BN_bn2bin(bn, buf)
|
146
|
-
buf.read_string(32).unpack('H*')[0]
|
141
|
+
[priv_hex, key.public_key.to_bn.to_s(16).downcase]
|
147
142
|
end
|
148
143
|
|
149
144
|
# Given the components of a signature and a selector value, recover and
|
@@ -395,9 +390,18 @@ module Bitcoin
|
|
395
390
|
def self.init_ffi_ssl
|
396
391
|
@ssl_loaded ||= false
|
397
392
|
return if @ssl_loaded
|
398
|
-
|
399
|
-
|
400
|
-
|
393
|
+
|
394
|
+
if version >= VERSION_1_1_0_NUM
|
395
|
+
OPENSSL_init_ssl(
|
396
|
+
OPENSSL_INIT_LOAD_SSL_STRINGS | OPENSSL_INIT_ENGINE_ALL_BUILTIN,
|
397
|
+
nil
|
398
|
+
)
|
399
|
+
else
|
400
|
+
SSL_library_init()
|
401
|
+
ERR_load_crypto_strings()
|
402
|
+
SSL_load_error_strings()
|
403
|
+
end
|
404
|
+
|
401
405
|
RAND_poll()
|
402
406
|
@ssl_loaded = true
|
403
407
|
end
|
data/lib/bitcoin/version.rb
CHANGED
@@ -772,82 +772,63 @@ describe Bitcoin do
|
|
772
772
|
end
|
773
773
|
end
|
774
774
|
|
775
|
-
describe '
|
776
|
-
|
777
|
-
|
778
|
-
|
779
|
-
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
|
785
|
-
|
786
|
-
|
787
|
-
|
788
|
-
|
789
|
-
Bitcoin::OpenSSL_EC.der_to_private_key(der)
|
790
|
-
).to eq('a29fe0f28b2936dbc89f889f74cd1f0662d18a873ac15d6cd417b808db1ccd0a')
|
775
|
+
describe 'signing and verifying messages' do
|
776
|
+
context 'testnet' do
|
777
|
+
before { Bitcoin.network = :testnet3 }
|
778
|
+
|
779
|
+
it 'verifies the signature of a testnet address' do
|
780
|
+
expect(
|
781
|
+
Bitcoin.verify_message(
|
782
|
+
'mwPVMbZQgkpwJJt2YP3sLSgbEBQw3FWZSc',
|
783
|
+
'H5GER0Nz+L7TPZMQzXtv0hnLSsyfPok9lkdHIv01vksREpEpOhTPTonU1xvy' \
|
784
|
+
'PAOIIKhU3++Ol+LaWKWmsfyxDXk=',
|
785
|
+
'A' * 500
|
786
|
+
)
|
787
|
+
).to be true
|
788
|
+
end
|
791
789
|
end
|
792
790
|
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
|
804
|
-
|
805
|
-
|
806
|
-
|
791
|
+
context 'mainnet' do
|
792
|
+
before { Bitcoin.network = :bitcoin }
|
793
|
+
let(:address_and_keys1) do
|
794
|
+
%w[
|
795
|
+
1QFqqMUD55ZV3PJEJZtaKCsQmjLT6JkjvJ
|
796
|
+
12b004fff7f4b69ef8650e767f18f11ede158148b425660723b9f9a66e61f747
|
797
|
+
040b4c866585dd868a9d62348a9cd008d6a312937048fff31670e7e920cfc7a7 \
|
798
|
+
447b5f0bba9e01e6fe4735c8383e6e7a3347a0fd72381b8f797a19f694054e5a69
|
799
|
+
]
|
800
|
+
end
|
801
|
+
let(:address_and_keys2) do
|
802
|
+
%w[
|
803
|
+
1NoJrossxPBKfCHuJXT4HadJrXRE9Fxiqs
|
804
|
+
12b004fff7f4b69ef8650e767f18f11ede158148b425660723b9f9a66e61f747
|
805
|
+
030b4c866585dd868a9d62348a9cd008d6a312937048fff31670e7e920cfc7a744
|
806
|
+
]
|
807
807
|
end
|
808
808
|
|
809
|
-
|
810
|
-
|
811
|
-
|
812
|
-
|
813
|
-
|
814
|
-
|
815
|
-
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
822
|
-
|
823
|
-
|
824
|
-
|
825
|
-
|
826
|
-
|
827
|
-
|
828
|
-
|
829
|
-
|
830
|
-
16.times.each do |count|
|
831
|
-
signature = Bitcoin.sign_message(
|
832
|
-
key.private_key_hex,
|
833
|
-
key.public_key_hex,
|
834
|
-
format('Very secret message %<count>d: 11', count: count)
|
809
|
+
it 'successfully signs and verifies the message' do
|
810
|
+
[address_and_keys1, address_and_keys2].each do |_addr, privkey, _pubkey|
|
811
|
+
key = Bitcoin.open_key(privkey)
|
812
|
+
16.times.each do |count|
|
813
|
+
signature = Bitcoin.sign_message(
|
814
|
+
key.private_key_hex,
|
815
|
+
key.public_key_hex,
|
816
|
+
format('Very secret message %<count>d: 11', count: count)
|
817
|
+
)
|
818
|
+
expect(
|
819
|
+
Bitcoin.verify_message(
|
820
|
+
signature['address'],
|
821
|
+
'invalid-signature',
|
822
|
+
signature['message']
|
823
|
+
)
|
824
|
+
).to be false
|
825
|
+
expect(
|
826
|
+
Bitcoin.verify_message(
|
827
|
+
signature['address'],
|
828
|
+
signature['signature'],
|
829
|
+
signature['message']
|
835
830
|
)
|
836
|
-
|
837
|
-
Bitcoin.verify_message(
|
838
|
-
signature['address'],
|
839
|
-
'invalid-signature',
|
840
|
-
signature['message']
|
841
|
-
)
|
842
|
-
).to be false
|
843
|
-
expect(
|
844
|
-
Bitcoin.verify_message(
|
845
|
-
signature['address'],
|
846
|
-
signature['signature'],
|
847
|
-
signature['message']
|
848
|
-
)
|
849
|
-
).to be true
|
850
|
-
end
|
831
|
+
).to be true
|
851
832
|
end
|
852
833
|
end
|
853
834
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bitcoin-ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.20
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- lian
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-12-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ffi
|