btcruby 1.0.9 → 1.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/RELEASE_NOTES.md +7 -0
- data/lib/btcruby.rb +12 -3
- data/lib/btcruby/open_assets/issuance_id.rb +1 -1
- data/lib/btcruby/{opcode.rb → script/opcode.rb} +0 -0
- data/lib/btcruby/{script.rb → script/script.rb} +0 -0
- data/lib/btcruby/script/script_error.rb +139 -0
- data/lib/btcruby/script/script_flags.rb +55 -0
- data/lib/btcruby/script/script_interpreter.rb +886 -0
- data/lib/btcruby/script/script_number.rb +254 -0
- data/lib/btcruby/script/signature_checker.rb +14 -0
- data/lib/btcruby/{signature_hashtype.rb → script/signature_hashtype.rb} +0 -0
- data/lib/btcruby/script/test_signature_checker.rb +53 -0
- data/lib/btcruby/script/transaction_signature_checker.rb +66 -0
- data/lib/btcruby/transaction_input.rb +1 -1
- data/lib/btcruby/version.rb +1 -1
- data/lib/btcruby/wire_format.rb +40 -8
- data/spec/open_assets/issuance_id_spec.rb +5 -5
- data/spec/wire_format_spec.rb +22 -4
- metadata +12 -5
@@ -0,0 +1,254 @@
|
|
1
|
+
module BTC
|
2
|
+
# (Based on CScriptNum)
|
3
|
+
# Numeric opcodes (OP_1ADD, etc) are restricted to operating on 4-byte integers.
|
4
|
+
# The semantics are subtle, though: operands must be in the range [-2^31 +1...2^31 -1],
|
5
|
+
# but results may overflow (and are valid as long as they are not used in a subsequent
|
6
|
+
# numeric operation). ScriptNumber enforces those semantics by storing results as
|
7
|
+
# an int64 and allowing out-of-range values to be returned as a vector of bytes but
|
8
|
+
# throwing an exception if arithmetic is done or the result is interpreted as an integer.
|
9
|
+
class ScriptNumberError < ArgumentError; end
|
10
|
+
|
11
|
+
class ScriptNumber
|
12
|
+
DEFAULT_MAX_SIZE = 4
|
13
|
+
|
14
|
+
INT64_MAX = 0x7fffffffffffffff
|
15
|
+
INT64_MIN = -INT64_MAX - 1
|
16
|
+
|
17
|
+
def initialize(integer: nil, boolean: nil, data: nil, hex: nil, require_minimal: true, max_size: DEFAULT_MAX_SIZE)
|
18
|
+
if integer
|
19
|
+
assert(integer >= INT64_MIN && integer <= INT64_MAX, "Integer must be within int64 range")
|
20
|
+
@integer = integer
|
21
|
+
elsif data || hex
|
22
|
+
data ||= BTC.from_hex(hex)
|
23
|
+
if data.bytesize > max_size
|
24
|
+
raise ScriptNumberError, "script number overflow (#{data.bytesize} > #{max_size})"
|
25
|
+
end
|
26
|
+
if require_minimal && data.bytesize > 0
|
27
|
+
# Check that the number is encoded with the minimum possible
|
28
|
+
# number of bytes.
|
29
|
+
#
|
30
|
+
# If the most-significant-byte - excluding the sign bit - is zero
|
31
|
+
# then we're not minimal. Note how this test also rejects the
|
32
|
+
# negative-zero encoding, 0x80.
|
33
|
+
if (data.bytes.last & 0x7f) == 0
|
34
|
+
# One exception: if there's more than one byte and the most
|
35
|
+
# significant bit of the second-most-significant-byte is set
|
36
|
+
# it would conflict with the sign bit. An example of this case
|
37
|
+
# is +-255, which encode to 0xff00 and 0xff80 respectively.
|
38
|
+
# (big-endian).
|
39
|
+
if data.bytesize <= 1 || (data.bytes[data.bytesize - 2] & 0x80) == 0
|
40
|
+
raise ScriptNumberError, "non-minimally encoded script number"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
@integer = self.class.decode_integer(data)
|
45
|
+
elsif boolean == false || boolean == true
|
46
|
+
@integer = boolean ? 1 : 0
|
47
|
+
else
|
48
|
+
raise ArgumentError
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# Operators
|
53
|
+
|
54
|
+
def ==(other); @integer == other.to_i; end
|
55
|
+
def !=(other); @integer != other.to_i; end
|
56
|
+
def <=(other); @integer <= other.to_i; end
|
57
|
+
def <(other); @integer < other.to_i; end
|
58
|
+
def >=(other); @integer >= other.to_i; end
|
59
|
+
def >(other); @integer > other.to_i; end
|
60
|
+
|
61
|
+
def +(other); self.class.new(integer: @integer + other.to_i); end
|
62
|
+
def -(other); self.class.new(integer: @integer - other.to_i); end
|
63
|
+
|
64
|
+
def +@
|
65
|
+
self
|
66
|
+
end
|
67
|
+
|
68
|
+
def -@
|
69
|
+
assert(@integer > INT64_MIN && @integer <= INT64_MAX, "Integer will not be within int64 range after negation")
|
70
|
+
self.class.new(integer: -@integer)
|
71
|
+
end
|
72
|
+
|
73
|
+
|
74
|
+
|
75
|
+
# Conversion Methods
|
76
|
+
|
77
|
+
def to_i
|
78
|
+
@integer
|
79
|
+
end
|
80
|
+
|
81
|
+
def to_s
|
82
|
+
@integer.to_s
|
83
|
+
end
|
84
|
+
|
85
|
+
def data
|
86
|
+
self.class.encode_integer(@integer)
|
87
|
+
end
|
88
|
+
|
89
|
+
def to_hex
|
90
|
+
BTC.to_hex(data)
|
91
|
+
end
|
92
|
+
|
93
|
+
def self.decode_integer(data)
|
94
|
+
return 0 if data.empty?
|
95
|
+
|
96
|
+
result = 0
|
97
|
+
|
98
|
+
bytes = data.bytes
|
99
|
+
bytes.each_with_index do |byte, i|
|
100
|
+
result |= bytes[i] << 8*i
|
101
|
+
end
|
102
|
+
|
103
|
+
# If the input vector's most significant byte is 0x80, remove it from
|
104
|
+
# the result's msb and return a negative.
|
105
|
+
if (bytes.last & 0x80) != 0
|
106
|
+
return -(result & ~(0x80 << (8 * (bytes.size - 1))));
|
107
|
+
end
|
108
|
+
return result
|
109
|
+
end
|
110
|
+
|
111
|
+
def self.encode_integer(value)
|
112
|
+
return "".b if value == 0
|
113
|
+
|
114
|
+
result = []
|
115
|
+
negative = value < 0
|
116
|
+
absvalue = negative ? -value : value
|
117
|
+
|
118
|
+
while absvalue != 0
|
119
|
+
result.push(absvalue & 0xff)
|
120
|
+
absvalue >>= 8
|
121
|
+
end
|
122
|
+
|
123
|
+
# - If the most significant byte is >= 0x80 and the value is positive, push a
|
124
|
+
# new zero-byte to make the significant byte < 0x80 again.
|
125
|
+
#
|
126
|
+
# - If the most significant byte is >= 0x80 and the value is negative, push a
|
127
|
+
# new 0x80 byte that will be popped off when converting to an integral.
|
128
|
+
#
|
129
|
+
# - If the most significant byte is < 0x80 and the value is negative, add
|
130
|
+
# 0x80 to it, since it will be subtracted and interpreted as a negative when
|
131
|
+
# converting to an integral.
|
132
|
+
|
133
|
+
if (result.last & 0x80) != 0
|
134
|
+
result.push(negative ? 0x80 : 0)
|
135
|
+
elsif negative
|
136
|
+
result[result.size - 1] = result.last | 0x80
|
137
|
+
end
|
138
|
+
|
139
|
+
BTC.data_from_bytes(result)
|
140
|
+
end
|
141
|
+
|
142
|
+
def assert(condition, message)
|
143
|
+
raise message if !condition
|
144
|
+
end
|
145
|
+
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
if $0 == __FILE__
|
150
|
+
require 'btcruby'
|
151
|
+
|
152
|
+
include BTC
|
153
|
+
def run_tests
|
154
|
+
|
155
|
+
# Decoding
|
156
|
+
|
157
|
+
[-1000000000000000,-10000,-100,-1,0,1,10,1000,100000000000000].each do |i|
|
158
|
+
should_equal(ScriptNumber.new(integer: i).to_i, i, "Must return integer as-is.")
|
159
|
+
end
|
160
|
+
|
161
|
+
should_equal(ScriptNumber.new(data: "").to_i, 0, "Must parse empty string as zero.")
|
162
|
+
should_equal(ScriptNumber.new(data: "\x01").to_i, 1, "Must parse 0x01 as 1.")
|
163
|
+
should_equal(ScriptNumber.new(data: "\xff").to_i, -127, "Must parse 0xff as -127.")
|
164
|
+
should_equal(ScriptNumber.new(data: "\xff\x00").to_i, 255, "Must parse 0xff00 as 255.")
|
165
|
+
should_equal(ScriptNumber.new(data: "\x81").to_i, -1, "Must parse 0x81 as -1.")
|
166
|
+
should_equal(ScriptNumber.new(data: "\x8f").to_i, -15, "Must parse 0x8f as -0x0f.")
|
167
|
+
should_equal(ScriptNumber.new(data: "\x00\x81").to_i, -256, "Must parse 0x0081 as -256.")
|
168
|
+
should_equal(ScriptNumber.new(data: "\xff\x80").to_i, -255, "Must decode -255.")
|
169
|
+
|
170
|
+
should_raise('non-minimally encoded script number') { ScriptNumber.new(data: "\x00") }
|
171
|
+
should_raise('non-minimally encoded script number') { ScriptNumber.new(data: "\x80") }
|
172
|
+
should_raise('non-minimally encoded script number') { ScriptNumber.new(data: "\x00\x80") }
|
173
|
+
should_raise('non-minimally encoded script number') { ScriptNumber.new(data: "\x01\x80") }
|
174
|
+
should_raise('non-minimally encoded script number') { ScriptNumber.new(data: "\x00\x00\x80") }
|
175
|
+
should_raise('non-minimally encoded script number') { ScriptNumber.new(data: "\x00\x10\x80") }
|
176
|
+
should_raise('non-minimally encoded script number') { ScriptNumber.new(data: "\x10\x00\x80") }
|
177
|
+
should_raise('script number overflow (3 > 2)') { ScriptNumber.new(data: "\x00\x00\x80", max_size: 2) }
|
178
|
+
|
179
|
+
# Encoding
|
180
|
+
|
181
|
+
should_equal(ScriptNumber.new(integer: 0).to_hex, "")
|
182
|
+
should_equal(ScriptNumber.new(integer: 1).to_hex, "01")
|
183
|
+
should_equal(ScriptNumber.new(integer: -1).to_hex, "81")
|
184
|
+
should_equal(ScriptNumber.new(integer: 255).to_hex, "ff00")
|
185
|
+
should_equal(ScriptNumber.new(integer: -255).to_hex, "ff80")
|
186
|
+
should_equal(ScriptNumber.new(integer: 0xffff).to_hex, "ffff00")
|
187
|
+
should_equal(ScriptNumber.new(integer: -0xffff).to_hex, "ffff80")
|
188
|
+
|
189
|
+
# Back and forth test
|
190
|
+
|
191
|
+
(-100000..10000).each do |i|
|
192
|
+
d = ScriptNumber.new(integer: i).data
|
193
|
+
#puts BTC.to_hex(d) if i % 16 == 0
|
194
|
+
i2 = ScriptNumber.new(data: d).to_i
|
195
|
+
should_equal(i, i2)
|
196
|
+
end
|
197
|
+
|
198
|
+
# Booleans
|
199
|
+
|
200
|
+
should_equal(ScriptNumber.new(boolean: true), 1)
|
201
|
+
should_equal(ScriptNumber.new(boolean: false), 0)
|
202
|
+
|
203
|
+
# Equality
|
204
|
+
|
205
|
+
should_equal(ScriptNumber.new(integer: 0) == 0, true)
|
206
|
+
should_equal(ScriptNumber.new(integer: 1) == 1, true)
|
207
|
+
should_equal(ScriptNumber.new(integer: -1) == -1, true)
|
208
|
+
|
209
|
+
should_equal(ScriptNumber.new(integer: 0) == ScriptNumber.new(integer: 0), true)
|
210
|
+
should_equal(ScriptNumber.new(integer: 1) == ScriptNumber.new(integer: 1), true)
|
211
|
+
should_equal(ScriptNumber.new(integer: -1) == ScriptNumber.new(integer: -1), true)
|
212
|
+
|
213
|
+
should_equal(ScriptNumber.new(integer: 0) != 0, false)
|
214
|
+
should_equal(ScriptNumber.new(integer: 1) != 1, false)
|
215
|
+
should_equal(ScriptNumber.new(integer: -1) != -1, false)
|
216
|
+
|
217
|
+
should_equal(ScriptNumber.new(integer: 0) != ScriptNumber.new(integer: 0), false)
|
218
|
+
should_equal(ScriptNumber.new(integer: 1) != ScriptNumber.new(integer: 1), false)
|
219
|
+
should_equal(ScriptNumber.new(integer: -1) != ScriptNumber.new(integer: -1), false)
|
220
|
+
|
221
|
+
# Arithmetic
|
222
|
+
|
223
|
+
sn = ScriptNumber.new(integer: 123)
|
224
|
+
sn -= 1
|
225
|
+
should_equal(sn, 122)
|
226
|
+
|
227
|
+
puts "All tests passed."
|
228
|
+
end
|
229
|
+
|
230
|
+
def should_equal(a, b, msg = 'Must equal')
|
231
|
+
a == b or raise "#{msg} Expected #{b.inspect}, received #{a.inspect}."
|
232
|
+
end
|
233
|
+
|
234
|
+
def should_raise(message)
|
235
|
+
raised = false
|
236
|
+
begin
|
237
|
+
yield
|
238
|
+
rescue => e
|
239
|
+
if e.message == message
|
240
|
+
raised = true
|
241
|
+
else
|
242
|
+
raise "Raised unexpected exception: #{e}"
|
243
|
+
end
|
244
|
+
end
|
245
|
+
if !raised
|
246
|
+
raise "Should have raised #{message.inspect}!"
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
run_tests
|
251
|
+
end
|
252
|
+
|
253
|
+
|
254
|
+
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module BTC
|
2
|
+
# Protocol for signature checkers
|
3
|
+
module SignatureChecker
|
4
|
+
# Returns a boolean indicating if signature is valid for the given public key
|
5
|
+
def check_signature(script_signature: nil, public_key:nil, script:nil)
|
6
|
+
false
|
7
|
+
end
|
8
|
+
# Returns a boolean indicating if lock time is valid.
|
9
|
+
# lock_time is ScriptNumber instance.
|
10
|
+
def check_lock_time(lock_time)
|
11
|
+
false
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
File without changes
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module BTC
|
2
|
+
class TestSignatureChecker
|
3
|
+
include SignatureChecker
|
4
|
+
|
5
|
+
def initialize(signature_hash: nil, timestamp: nil)
|
6
|
+
@signature_hash = signature_hash
|
7
|
+
@timestamp = timestamp
|
8
|
+
end
|
9
|
+
|
10
|
+
# for testing check_signature
|
11
|
+
def signature_hash
|
12
|
+
@signature_hash
|
13
|
+
end
|
14
|
+
|
15
|
+
# for testing check_lock_time
|
16
|
+
def timestamp
|
17
|
+
@timestamp
|
18
|
+
end
|
19
|
+
|
20
|
+
def check_signature(script_signature:nil, public_key:nil, script:nil)
|
21
|
+
# Signature must be long enough to contain a sighash byte.
|
22
|
+
return false if script_signature.size < 1
|
23
|
+
|
24
|
+
# Extract raw ECDSA signature by stripping off the last hashtype byte
|
25
|
+
ecdsa_sig = script_signature[0..-2]
|
26
|
+
|
27
|
+
key = BTC::Key.new(public_key: public_key)
|
28
|
+
result = key.verify_ecdsa_signature(ecdsa_sig, hash)
|
29
|
+
return result
|
30
|
+
end
|
31
|
+
|
32
|
+
def check_lock_time(lock_time)
|
33
|
+
# There are two times of nLockTime: lock-by-blockheight
|
34
|
+
# and lock-by-blocktime, distinguished by whether
|
35
|
+
# nLockTime < LOCKTIME_THRESHOLD.
|
36
|
+
#
|
37
|
+
# We want to compare apples to apples, so fail the script
|
38
|
+
# if the type of nLockTime being tested is not the same as
|
39
|
+
# the nLockTime in the transaction.
|
40
|
+
if !(
|
41
|
+
(timestamp < LOCKTIME_THRESHOLD && lock_time < LOCKTIME_THRESHOLD) ||
|
42
|
+
(timestamp >= LOCKTIME_THRESHOLD && lock_time >= LOCKTIME_THRESHOLD)
|
43
|
+
)
|
44
|
+
return false
|
45
|
+
end
|
46
|
+
|
47
|
+
# Now that we know we're comparing apples-to-apples, the
|
48
|
+
# comparison is a simple numeric one.
|
49
|
+
return timestamp >= lock_time
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module BTC
|
2
|
+
class TransactionSignatureChecker
|
3
|
+
include SignatureChecker
|
4
|
+
|
5
|
+
attr_accessor :transaction
|
6
|
+
attr_accessor :input_index
|
7
|
+
def initialize(transaction: nil, input_index: nil)
|
8
|
+
@transaction = transaction
|
9
|
+
@input_index = input_index
|
10
|
+
end
|
11
|
+
|
12
|
+
def check_signature(script_signature:nil, public_key:nil, script:nil)
|
13
|
+
# Signature must be long enough to contain a sighash byte.
|
14
|
+
return false if script_signature.size < 1
|
15
|
+
|
16
|
+
hashtype = script_signature[-1].bytes.first
|
17
|
+
|
18
|
+
# Extract raw ECDSA signature by stripping off the last hashtype byte
|
19
|
+
ecdsa_sig = script_signature[0..-2]
|
20
|
+
|
21
|
+
key = BTC::Key.new(public_key: public_key)
|
22
|
+
hash = @transaction.signature_hash(input_index: @input_index, output_script: script, hash_type: hashtype)
|
23
|
+
result = key.verify_ecdsa_signature(ecdsa_sig, hash)
|
24
|
+
return result
|
25
|
+
end
|
26
|
+
|
27
|
+
def check_lock_time(lock_time)
|
28
|
+
# There are two times of nLockTime: lock-by-blockheight
|
29
|
+
# and lock-by-blocktime, distinguished by whether
|
30
|
+
# nLockTime < LOCKTIME_THRESHOLD.
|
31
|
+
#
|
32
|
+
# We want to compare apples to apples, so fail the script
|
33
|
+
# if the type of nLockTime being tested is not the same as
|
34
|
+
# the nLockTime in the transaction.
|
35
|
+
if !(
|
36
|
+
(@transaction.lock_time < LOCKTIME_THRESHOLD && lock_time < LOCKTIME_THRESHOLD) ||
|
37
|
+
(@transaction.lock_time >= LOCKTIME_THRESHOLD && lock_time >= LOCKTIME_THRESHOLD)
|
38
|
+
)
|
39
|
+
return false
|
40
|
+
end
|
41
|
+
|
42
|
+
# Now that we know we're comparing apples-to-apples, the
|
43
|
+
# comparison is a simple numeric one.
|
44
|
+
if lock_time > @transaction.lock_time
|
45
|
+
return false
|
46
|
+
end
|
47
|
+
|
48
|
+
# Finally the nLockTime feature can be disabled and thus
|
49
|
+
# CHECKLOCKTIMEVERIFY bypassed if every txin has been
|
50
|
+
# finalized by setting nSequence to maxint. The
|
51
|
+
# transaction would be allowed into the blockchain, making
|
52
|
+
# the opcode ineffective.
|
53
|
+
#
|
54
|
+
# Testing if this vin is not final is sufficient to
|
55
|
+
# prevent this condition. Alternatively we could test all
|
56
|
+
# inputs, but testing just this input minimizes the data
|
57
|
+
# required to prove correct CHECKLOCKTIMEVERIFY execution.
|
58
|
+
if @transaction.inputs[@input_index].final?
|
59
|
+
return false
|
60
|
+
end
|
61
|
+
|
62
|
+
return true
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|
@@ -78,7 +78,7 @@ module BTC
|
|
78
78
|
@previous_hash = previous_hash || ZERO_HASH256
|
79
79
|
@previous_hash = BTC.hash_from_id(previous_id) if previous_id
|
80
80
|
@previous_index = previous_index || INVALID_INDEX
|
81
|
-
@coinbase_data = coinbase_data
|
81
|
+
@coinbase_data = coinbase_data || "".b
|
82
82
|
@signature_script = signature_script || BTC::Script.new
|
83
83
|
@sequence = sequence || MAX_SEQUENCE
|
84
84
|
end
|
data/lib/btcruby/version.rb
CHANGED
data/lib/btcruby/wire_format.rb
CHANGED
@@ -184,12 +184,44 @@ module BTC
|
|
184
184
|
|
185
185
|
intbuf + stringbuf
|
186
186
|
end
|
187
|
-
|
188
|
-
|
187
|
+
|
188
|
+
|
189
|
+
# Reads varint length prefix, then calls the block appropriate number of times to read the items.
|
190
|
+
# Returns an array of items.
|
191
|
+
def read_array(data: nil, stream: nil, offset: 0)
|
192
|
+
count, len = read_varint(data: data, stream: stream, offset: offset)
|
193
|
+
return [nil, len] if !count
|
194
|
+
(0...count).map do |i|
|
195
|
+
yield
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
def encode_array(array, &block)
|
200
|
+
write_array(array, &block)
|
201
|
+
end
|
202
|
+
|
203
|
+
def write_array(array, data: nil, stream: nil, &block)
|
204
|
+
raise ArgumentError, "Array must be present" if !array
|
205
|
+
raise ArgumentError, "Parsing block must be present" if !block
|
206
|
+
intbuf = write_varint(array.size, data: data, stream: stream)
|
207
|
+
array.inject(intbuf) do |buf, e|
|
208
|
+
string = block.call(e)
|
209
|
+
stringbuf = BTC::Data.ensure_binary_encoding(string)
|
210
|
+
data << stringbuf if data
|
211
|
+
stream.write(stringbuf) if stream
|
212
|
+
buf << stringbuf
|
213
|
+
buf
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
|
218
|
+
|
219
|
+
|
220
|
+
|
189
221
|
# LEB128 encoding used in Open Assets protocol
|
190
|
-
|
222
|
+
|
191
223
|
# Decodes an unsigned integer encoded in LEB128.
|
192
|
-
# Returns `[value, length]` where `value` is an integer decoded from LEB128 and `length`
|
224
|
+
# Returns `[value, length]` where `value` is an integer decoded from LEB128 and `length`
|
193
225
|
# is a number of bytes read (includes length prefix and offset bytes).
|
194
226
|
def read_uleb128(data: nil, stream: nil, offset: 0)
|
195
227
|
if (data && stream) || (!data && !stream)
|
@@ -252,8 +284,8 @@ module BTC
|
|
252
284
|
stream.write(buf) if stream
|
253
285
|
buf
|
254
286
|
end
|
255
|
-
|
256
|
-
|
287
|
+
|
288
|
+
|
257
289
|
|
258
290
|
PACK_FORMAT_UINT8 = "C".freeze
|
259
291
|
PACK_FORMAT_INT8 = "c".freeze
|
@@ -291,11 +323,11 @@ module BTC
|
|
291
323
|
def read_int32le(data: nil, stream: nil, offset: 0)
|
292
324
|
_read_fixint(name: :int32le, length: 4, pack_format: PACK_FORMAT_INT32LE, data: data, stream: stream, offset: offset)
|
293
325
|
end
|
294
|
-
|
326
|
+
|
295
327
|
def read_uint32be(data: nil, stream: nil, offset: 0) # used in BIP32
|
296
328
|
_read_fixint(name: :uint32be, length: 4, pack_format: PACK_FORMAT_UINT32BE, data: data, stream: stream, offset: offset)
|
297
329
|
end
|
298
|
-
|
330
|
+
|
299
331
|
def read_int32be(data: nil, stream: nil, offset: 0)
|
300
332
|
_read_fixint(name: :int32be, length: 4, pack_format: PACK_FORMAT_INT32BE, data: data, stream: stream, offset: offset)
|
301
333
|
end
|