bitcoin-ruby 0.0.19 → 0.0.20
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/.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
|