cryptocoin 0.0.1b
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +23 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +85 -0
- data/Rakefile +2 -0
- data/cryptocoin.gemspec +24 -0
- data/lib/cryptocoin/core_ext/integer.rb +24 -0
- data/lib/cryptocoin/core_ext/string.rb +30 -0
- data/lib/cryptocoin/digest.rb +36 -0
- data/lib/cryptocoin/merkle_tree.rb +78 -0
- data/lib/cryptocoin/network/bitcoin.rb +9 -0
- data/lib/cryptocoin/network/dogecoin.rb +9 -0
- data/lib/cryptocoin/network/litecoin.rb +9 -0
- data/lib/cryptocoin/network.rb +53 -0
- data/lib/cryptocoin/protocol/block_header.rb +58 -0
- data/lib/cryptocoin/protocol/inventory_vector.rb +28 -0
- data/lib/cryptocoin/protocol/message/addr.rb +29 -0
- data/lib/cryptocoin/protocol/message/alert.rb +0 -0
- data/lib/cryptocoin/protocol/message/block.rb +13 -0
- data/lib/cryptocoin/protocol/message/getaddr.rb +17 -0
- data/lib/cryptocoin/protocol/message/getblocks.rb +44 -0
- data/lib/cryptocoin/protocol/message/getdata.rb +31 -0
- data/lib/cryptocoin/protocol/message/getheaders.rb +44 -0
- data/lib/cryptocoin/protocol/message/headers.rb +30 -0
- data/lib/cryptocoin/protocol/message/inv.rb +31 -0
- data/lib/cryptocoin/protocol/message/mempool.rb +16 -0
- data/lib/cryptocoin/protocol/message/notfound.rb +31 -0
- data/lib/cryptocoin/protocol/message/ping.rb +24 -0
- data/lib/cryptocoin/protocol/message/pong.rb +24 -0
- data/lib/cryptocoin/protocol/message/reject.rb +54 -0
- data/lib/cryptocoin/protocol/message/tx.rb +11 -0
- data/lib/cryptocoin/protocol/message/verack.rb +16 -0
- data/lib/cryptocoin/protocol/message/version.rb +59 -0
- data/lib/cryptocoin/protocol/message.rb +27 -0
- data/lib/cryptocoin/protocol/net_addr.rb +55 -0
- data/lib/cryptocoin/protocol/packet.rb +74 -0
- data/lib/cryptocoin/protocol/var_len_int.rb +85 -0
- data/lib/cryptocoin/protocol/var_len_str.rb +18 -0
- data/lib/cryptocoin/protocol.rb +8 -0
- data/lib/cryptocoin/script/op_code/constants.rb +157 -0
- data/lib/cryptocoin/script/op_code/functions.rb +515 -0
- data/lib/cryptocoin/script/op_code.rb +59 -0
- data/lib/cryptocoin/script.rb +234 -0
- data/lib/cryptocoin/structure/address.rb +64 -0
- data/lib/cryptocoin/structure/block.rb +109 -0
- data/lib/cryptocoin/structure/key_pair.rb +57 -0
- data/lib/cryptocoin/structure/merkle_branch.rb +37 -0
- data/lib/cryptocoin/structure/transaction/input.rb +80 -0
- data/lib/cryptocoin/structure/transaction/output.rb +49 -0
- data/lib/cryptocoin/structure/transaction.rb +94 -0
- data/lib/cryptocoin/version.rb +3 -0
- data/lib/cryptocoin.rb +29 -0
- data/spec/script_spec.rb +42 -0
- data/spec/spec_helper.rb +20 -0
- metadata +145 -0
@@ -0,0 +1,157 @@
|
|
1
|
+
module Cryptocoin
|
2
|
+
class Script
|
3
|
+
# Taken from the Bitcoin official client
|
4
|
+
class OpCode
|
5
|
+
module Constants
|
6
|
+
# push value onto stack
|
7
|
+
OP_0 = 0x00
|
8
|
+
OP_FALSE = OP_0
|
9
|
+
OP_PUSHDATA0 = 0x01
|
10
|
+
OP_PUSHDATA1 = 0x4c
|
11
|
+
OP_PUSHDATA2 = 0x4d
|
12
|
+
OP_PUSHDATA4 = 0x4e
|
13
|
+
OP_1NEGATE = 0x4f
|
14
|
+
OP_RESERVED = 0x50
|
15
|
+
OP_1 = 0x51
|
16
|
+
OP_TRUE = OP_1
|
17
|
+
OP_2 = 0x52
|
18
|
+
OP_3 = 0x53
|
19
|
+
OP_4 = 0x54
|
20
|
+
OP_5 = 0x55
|
21
|
+
OP_6 = 0x56
|
22
|
+
OP_7 = 0x57
|
23
|
+
OP_8 = 0x58
|
24
|
+
OP_9 = 0x59
|
25
|
+
OP_10 = 0x5a
|
26
|
+
OP_11 = 0x5b
|
27
|
+
OP_12 = 0x5c
|
28
|
+
OP_13 = 0x5d
|
29
|
+
OP_14 = 0x5e
|
30
|
+
OP_15 = 0x5f
|
31
|
+
OP_16 = 0x60
|
32
|
+
|
33
|
+
# control
|
34
|
+
OP_NOP = 0x61
|
35
|
+
OP_VER = 0x62
|
36
|
+
OP_IF = 0x63
|
37
|
+
OP_NOTIF = 0x64
|
38
|
+
OP_VERIF = 0x65
|
39
|
+
OP_VERNOTIF = 0x66
|
40
|
+
OP_ELSE = 0x67
|
41
|
+
OP_ENDIF = 0x68
|
42
|
+
OP_VERIFY = 0x69
|
43
|
+
OP_RETURN = 0x6a
|
44
|
+
|
45
|
+
# stack ops
|
46
|
+
OP_TOALTSTACK = 0x6b
|
47
|
+
OP_FROMALTSTACK = 0x6c
|
48
|
+
OP_2DROP = 0x6d
|
49
|
+
OP_2DUP = 0x6e
|
50
|
+
OP_3DUP = 0x6f
|
51
|
+
OP_2OVER = 0x70
|
52
|
+
OP_2ROT = 0x71
|
53
|
+
OP_2SWAP = 0x72
|
54
|
+
OP_IFDUP = 0x73
|
55
|
+
OP_DEPTH = 0x74
|
56
|
+
OP_DROP = 0x75
|
57
|
+
OP_DUP = 0x76
|
58
|
+
OP_NIP = 0x77
|
59
|
+
OP_OVER = 0x78
|
60
|
+
OP_PICK = 0x79
|
61
|
+
OP_ROLL = 0x7a
|
62
|
+
OP_ROT = 0x7b
|
63
|
+
OP_SWAP = 0x7c
|
64
|
+
OP_TUCK = 0x7d
|
65
|
+
|
66
|
+
# splice ops
|
67
|
+
OP_CAT = 0x7e
|
68
|
+
OP_SUBSTR = 0x7f
|
69
|
+
OP_LEFT = 0x80
|
70
|
+
OP_RIGHT = 0x81
|
71
|
+
OP_SIZE = 0x82
|
72
|
+
|
73
|
+
# bit logic
|
74
|
+
OP_INVERT = 0x83
|
75
|
+
OP_AND = 0x84
|
76
|
+
OP_OR = 0x85
|
77
|
+
OP_XOR = 0x86
|
78
|
+
OP_EQUAL = 0x87
|
79
|
+
OP_EQUALVERIFY = 0x88
|
80
|
+
OP_RESERVED1 = 0x89
|
81
|
+
OP_RESERVED2 = 0x8a
|
82
|
+
|
83
|
+
# numeric
|
84
|
+
OP_1ADD = 0x8b
|
85
|
+
OP_1SUB = 0x8c
|
86
|
+
OP_2MUL = 0x8d
|
87
|
+
OP_2DIV = 0x8e
|
88
|
+
OP_NEGATE = 0x8f
|
89
|
+
OP_ABS = 0x90
|
90
|
+
OP_NOT = 0x91
|
91
|
+
OP_0NOTEQUAL = 0x92
|
92
|
+
|
93
|
+
OP_ADD = 0x93
|
94
|
+
OP_SUB = 0x94
|
95
|
+
OP_MUL = 0x95
|
96
|
+
OP_DIV = 0x96
|
97
|
+
OP_MOD = 0x97
|
98
|
+
OP_LSHIFT = 0x98
|
99
|
+
OP_RSHIFT = 0x99
|
100
|
+
|
101
|
+
OP_BOOLAND = 0x9a
|
102
|
+
OP_BOOLOR = 0x9b
|
103
|
+
OP_NUMEQUAL = 0x9c
|
104
|
+
OP_NUMEQUALVERIFY = 0x9d
|
105
|
+
OP_NUMNOTEQUAL = 0x9e
|
106
|
+
OP_LESSTHAN = 0x9f
|
107
|
+
OP_GREATERTHAN = 0xa0
|
108
|
+
OP_LESSTHANOREQUAL = 0xa1
|
109
|
+
OP_GREATERTHANOREQUAL = 0xa2
|
110
|
+
OP_MIN = 0xa3
|
111
|
+
OP_MAX = 0xa4
|
112
|
+
|
113
|
+
OP_WITHIN = 0xa5
|
114
|
+
|
115
|
+
# crypto
|
116
|
+
OP_RIPEMD160 = 0xa6
|
117
|
+
OP_SHA1 = 0xa7
|
118
|
+
OP_SHA256 = 0xa8
|
119
|
+
OP_HASH160 = 0xa9
|
120
|
+
OP_HASH256 = 0xaa
|
121
|
+
OP_CODESEPARATOR = 0xab
|
122
|
+
OP_CHECKSIG = 0xac
|
123
|
+
OP_CHECKSIGVERIFY = 0xad
|
124
|
+
OP_CHECKMULTISIG = 0xae
|
125
|
+
OP_CHECKMULTISIGVERIFY = 0xaf
|
126
|
+
|
127
|
+
# expansion
|
128
|
+
OP_NOP1 = 0xb0
|
129
|
+
OP_NOP2 = 0xb1
|
130
|
+
OP_NOP3 = 0xb2
|
131
|
+
OP_NOP4 = 0xb3
|
132
|
+
OP_NOP5 = 0xb4
|
133
|
+
OP_NOP6 = 0xb5
|
134
|
+
OP_NOP7 = 0xb6
|
135
|
+
OP_NOP8 = 0xb7
|
136
|
+
OP_NOP9 = 0xb8
|
137
|
+
OP_NOP10 = 0xb9
|
138
|
+
|
139
|
+
# template matching params
|
140
|
+
OP_SMALLDATA = 0xf9
|
141
|
+
OP_SMALLINTEGER = 0xfa
|
142
|
+
OP_PUBKEYS = 0xfb
|
143
|
+
OP_PUBKEYHASH = 0xfd
|
144
|
+
OP_PUBKEY = 0xfe
|
145
|
+
|
146
|
+
OP_INVALIDOPCODE = 0xff
|
147
|
+
|
148
|
+
def self.const_get(*args)
|
149
|
+
super(*args)
|
150
|
+
rescue NameError => msg
|
151
|
+
return OP_PUSHDATA0 if args[0] == "OP_PUSHDATA0"
|
152
|
+
raise NameError, msg
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
@@ -0,0 +1,515 @@
|
|
1
|
+
require 'cryptocoin/core_ext/integer'
|
2
|
+
require 'cryptocoin/core_ext/string'
|
3
|
+
require 'cryptocoin/script/op_code/constants'
|
4
|
+
require 'digest/sha2'
|
5
|
+
require 'digest/rmd160'
|
6
|
+
|
7
|
+
module Cryptocoin
|
8
|
+
class Script
|
9
|
+
class OpCode
|
10
|
+
module Functions
|
11
|
+
include Cryptocoin::Script::OpCode::Constants
|
12
|
+
|
13
|
+
# One of a kind function
|
14
|
+
# Sends back the stack, modified string, raw, seek
|
15
|
+
def op_pushdata(stack, opcode, script, script_string, raw, seek)
|
16
|
+
bytes = case opcode.hex
|
17
|
+
when OP_PUSHDATA0..OP_PUSHDATA1
|
18
|
+
opcode.raw
|
19
|
+
when OP_PUSHDATA1
|
20
|
+
seek+=1
|
21
|
+
script[seek-1]
|
22
|
+
when OP_PUSHDATA2
|
23
|
+
seek+=2
|
24
|
+
script[seek-2..seek]
|
25
|
+
when OP_PUSHDATA4
|
26
|
+
seek+=4
|
27
|
+
script[seek-4..seek]
|
28
|
+
end
|
29
|
+
|
30
|
+
bytes = bytes.unpack('H*')[0].to_i(16)
|
31
|
+
|
32
|
+
unless OP_PUSHDATA0..OP_PUSHDATA1 === opcode.hex
|
33
|
+
raw += [bytes].pack('H*')
|
34
|
+
script_string.push(bytes)
|
35
|
+
end
|
36
|
+
|
37
|
+
# Read the value from the bytes and see how much to read
|
38
|
+
# return nil if invalid according to spec
|
39
|
+
return false if bytes > 520
|
40
|
+
j = script[seek..seek+bytes-1]
|
41
|
+
script_string.push(j.unpack('H*')[0])
|
42
|
+
raw += j
|
43
|
+
stack.push(j)
|
44
|
+
seek+=bytes
|
45
|
+
[stack, script_string, raw, seek]
|
46
|
+
end
|
47
|
+
|
48
|
+
def op_numeric(stack, opcode)
|
49
|
+
stack.push((opcode.hex - (OP_1 - 1)).to_openssl_bn)
|
50
|
+
end
|
51
|
+
|
52
|
+
def op_if(stack, exec_stack, opcode)
|
53
|
+
require_stack stack do
|
54
|
+
val = false
|
55
|
+
i = stack.pop
|
56
|
+
if !!i.to_openssl_bn_int
|
57
|
+
val = true if opcode.hex == OP_IF
|
58
|
+
else
|
59
|
+
val = true if opcode.hex == OP_NOTIF
|
60
|
+
end
|
61
|
+
exec_stack.push(val)
|
62
|
+
[stack, exec_stack]
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def op_else(exec_stack)
|
67
|
+
require_stack exec_stack do
|
68
|
+
exec_stack[-1] = !exec_stack[-1]
|
69
|
+
exec_stack
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def op_endif(exec_stack)
|
74
|
+
require_stack exec_stack do
|
75
|
+
exec_stack.pop
|
76
|
+
exec_stack
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def op_verify(stack, transaction_valid)
|
81
|
+
require_stack stack do
|
82
|
+
i = stack.pop
|
83
|
+
if i.to_openssl_bn_int == 0
|
84
|
+
stack.push(i)
|
85
|
+
transaction_valid = false
|
86
|
+
end
|
87
|
+
[stack, transaction_valid]
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def op_toaltstack(stack, alt_stack)
|
92
|
+
require_stack stack do
|
93
|
+
alt_stack.push(stack.pop)
|
94
|
+
end
|
95
|
+
[stack, alt_stack]
|
96
|
+
end
|
97
|
+
|
98
|
+
def op_fromaltstack(stack, alt_stack)
|
99
|
+
require_stack alt_stack do
|
100
|
+
stack.push(alt_stack.pop)
|
101
|
+
end
|
102
|
+
[stack, alt_stack]
|
103
|
+
end
|
104
|
+
|
105
|
+
def op_2drop(stack)
|
106
|
+
require_stack stack, 2 do
|
107
|
+
2.times do
|
108
|
+
stack.pop
|
109
|
+
end
|
110
|
+
stack
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def op_2dup(stack)
|
115
|
+
require_stack stack, 2 do
|
116
|
+
i = stack[-1]
|
117
|
+
j = stack[-2]
|
118
|
+
stack.push(i, j)
|
119
|
+
stack
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def op_3dup(stack)
|
124
|
+
require_stack stack, 3 do
|
125
|
+
i = stack[-1]
|
126
|
+
j = stack[-2]
|
127
|
+
k = stack[-3]
|
128
|
+
stack.push(i, j, k)
|
129
|
+
stack
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def op_2over(stack)
|
134
|
+
require_stack stack, 4 do
|
135
|
+
i = stack[-3]
|
136
|
+
j = stack[-4]
|
137
|
+
stack.push(i, j)
|
138
|
+
stack
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def op_2rot(stack)
|
143
|
+
require_stack stack, 6 do
|
144
|
+
i = stack.slize!(-6,2)
|
145
|
+
stack.push(i).flatten!
|
146
|
+
stack
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def op_2swap(stack)
|
151
|
+
require_stack stack, 4 do
|
152
|
+
i = stack.pop(2)
|
153
|
+
j = stack.pop(2)
|
154
|
+
stack.push(i, j)
|
155
|
+
stack
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def op_ifdup(stack)
|
160
|
+
require_stack stack do
|
161
|
+
stack.push(stack.last) if stack.last != 0.to_openssl_bn_int
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
def op_depth(stack)
|
166
|
+
stack.push(stack.size.to_openssl_bn)
|
167
|
+
stack
|
168
|
+
end
|
169
|
+
|
170
|
+
def op_nop
|
171
|
+
# Doesn't do anything
|
172
|
+
true
|
173
|
+
end
|
174
|
+
|
175
|
+
def op_drop(stack)
|
176
|
+
require_stack stack do
|
177
|
+
stack.pop
|
178
|
+
stack
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def op_dup(stack)
|
183
|
+
require_stack stack do
|
184
|
+
stack.push(stack.last)
|
185
|
+
stack
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
def op_nip(stack)
|
190
|
+
require_stack stack, 2 do
|
191
|
+
stack.slice!(-2)
|
192
|
+
stack
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
def op_over(stack)
|
197
|
+
require_stack stack, 2 do
|
198
|
+
stack.push(stack.slice(-2))
|
199
|
+
stack
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
def op_pick_or_roll(stack, opcode)
|
204
|
+
require_stack stack, 2 do
|
205
|
+
p = stack.pop
|
206
|
+
i = stack.slice(p, 1) if opcode.hex == OP_PICK
|
207
|
+
i = stack.slice!(p, 1) if opcode.hex == OP_ROLL
|
208
|
+
stack.push(i)
|
209
|
+
stack
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
def op_rot(stack)
|
214
|
+
require_stack stack, 3 do
|
215
|
+
i = stack.slice!(-3,1)
|
216
|
+
stack.push(i)
|
217
|
+
stack
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
def op_swap(stack)
|
222
|
+
require_stack stack, 2 do
|
223
|
+
i = stack.slice!(-2,1)
|
224
|
+
stack.push(i)
|
225
|
+
stack
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
def op_tuck(stack)
|
230
|
+
require_stack stack, 2 do
|
231
|
+
stack.insert(-3, stack.last)
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
# Pushes the size of the item at the top of the stack
|
236
|
+
# Note: the stack processing is done in binary, and Ruby treats
|
237
|
+
# binary as strings
|
238
|
+
def op_size(stack)
|
239
|
+
stack.push([stack.last.bytesize].pack('C*'))
|
240
|
+
stack
|
241
|
+
end
|
242
|
+
|
243
|
+
# Reference client treats OP_RETURN as fail condition
|
244
|
+
# for script. OP_RETURN sets the transaction as invalid
|
245
|
+
# but otherwise the script can be valid
|
246
|
+
def op_return
|
247
|
+
false
|
248
|
+
end
|
249
|
+
|
250
|
+
def op_verify(stack, transaction_valid)
|
251
|
+
require_stack stack do
|
252
|
+
i = stack.pop
|
253
|
+
if i.to_bn.to_i == 0
|
254
|
+
stack.push(i)
|
255
|
+
transaction_valid = false
|
256
|
+
end
|
257
|
+
[stack, transaction_valid]
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
def op_equal(stack)
|
262
|
+
require_stack stack, 2 do
|
263
|
+
i, j = stack.pop(2)
|
264
|
+
stack.push(i == j ? 1 : 0)
|
265
|
+
stack
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
def single_stack_arithmetic(stack, opcode)
|
270
|
+
require_stack stack do
|
271
|
+
i = stack.pop.to_openssl_bn_int
|
272
|
+
case opcode.hex
|
273
|
+
when OP_1ADD
|
274
|
+
i += 1
|
275
|
+
when OP_1SUB
|
276
|
+
i -= 1
|
277
|
+
when OP_NEGATE
|
278
|
+
i = -i
|
279
|
+
when OP_ABS
|
280
|
+
i = i.abs
|
281
|
+
when OP_NOT
|
282
|
+
i = (i == 0)
|
283
|
+
when OP_0NOTEQUAL
|
284
|
+
i = (i != 0)
|
285
|
+
end
|
286
|
+
stack.push(i.to_openssl_bn)
|
287
|
+
stack
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
def double_stack_arithmetic(stack)
|
292
|
+
require_stack stack, 2 do
|
293
|
+
i, j = stack.pop.map { |e| e.to_openssl_bn_int }
|
294
|
+
case opcode.hex
|
295
|
+
when OP_ADD
|
296
|
+
k = i + j
|
297
|
+
when OP_SUB
|
298
|
+
k = i - j
|
299
|
+
when OP_BOOLAND
|
300
|
+
k = (i != 0 and j != 0)
|
301
|
+
when OP_BOOLOR
|
302
|
+
k = (i != 0 or j != 0)
|
303
|
+
when OP_NUMEQUAL, OP_NUMEQUALVERIFY
|
304
|
+
k = (i == j)
|
305
|
+
op_verify if @opcode == OP_NUMEQUALVERIFY
|
306
|
+
when OP_NUMNOTEQUAL
|
307
|
+
k = (i != j)
|
308
|
+
when OP_LESSTHAN
|
309
|
+
k = (i < j)
|
310
|
+
when OP_GREATERTHAN
|
311
|
+
k = (i > j)
|
312
|
+
when OP_LESSTHANOREQUAL
|
313
|
+
k = (i <= j)
|
314
|
+
when OP_GREATERTHANOREQUAL
|
315
|
+
k = (i >= j)
|
316
|
+
when OP_MIN
|
317
|
+
k = (i < j ? i : j)
|
318
|
+
when OP_MAX
|
319
|
+
k = (i < j ? j : i)
|
320
|
+
end
|
321
|
+
stack.push(k.to_openssl_bn)
|
322
|
+
stack
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
def op_within(stack)
|
327
|
+
require_stack stack do
|
328
|
+
i, j, k = stack.pop(3).map{|e| e.to_openssl_bn_int}
|
329
|
+
l = (j <= i and i < k)
|
330
|
+
stack.push(l.to_openssl_bn)
|
331
|
+
stack
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
def digest(stack, opcode)
|
336
|
+
require_stack stack do
|
337
|
+
i = stack.pop
|
338
|
+
case opcode.hex
|
339
|
+
when OP_RIPEMD160
|
340
|
+
j = Digest::RMD160.digest(i)
|
341
|
+
when OP_SHA256
|
342
|
+
j = Digest::SHA256.digest(i)
|
343
|
+
when OP_SHA1
|
344
|
+
j = Digest::SHA1.digest(i)
|
345
|
+
when OP_HASH160
|
346
|
+
j = Digest::RMD160.digest(Digest::SHA256.digest(i))
|
347
|
+
when OP_HASH256
|
348
|
+
j = Digest::SHA256.digest(Digest::SHA256.digest(i))
|
349
|
+
end
|
350
|
+
stack.push(j)
|
351
|
+
stack
|
352
|
+
end
|
353
|
+
end
|
354
|
+
|
355
|
+
def op_codeseparator(seek)
|
356
|
+
seek # Allow for future changes to this opcode
|
357
|
+
end
|
358
|
+
|
359
|
+
# One of the two opcodes that requires outside knowledge from
|
360
|
+
# the stack itself, since the transaction information isn't
|
361
|
+
# directly part of the script
|
362
|
+
def op_checksig(stack, script, code_separator, transaction)
|
363
|
+
pubkey = stack.pop
|
364
|
+
sig = stack.pop
|
365
|
+
|
366
|
+
hash_type = sig[-1].unpack('C')[0]
|
367
|
+
signature = sig[0..-2]
|
368
|
+
|
369
|
+
if is_canonical_pubkey?(pubkey) and is_canonical_signature?(signature)
|
370
|
+
stack = check_sig(signature, hash_type, pubkey, script, code_separator, transaction)
|
371
|
+
return stack.push(0.to_openssl_bn) if !stack
|
372
|
+
stack.push(1.to_openssl_bn)
|
373
|
+
else
|
374
|
+
stack.push(0.to_openssl_bn)
|
375
|
+
end
|
376
|
+
stack
|
377
|
+
end
|
378
|
+
|
379
|
+
def op_multisig(stack, script, code_separator, transaction, opcode_count)
|
380
|
+
require_stack do
|
381
|
+
i = stack.pop.to_openssl_bn_int
|
382
|
+
return false if !i.between?(1,19) #inclusive
|
383
|
+
opcode_count += i
|
384
|
+
return false if opcode_count > 201
|
385
|
+
return false if stack.size < i+1
|
386
|
+
j = stack.size
|
387
|
+
while stack.size > j-i
|
388
|
+
stack = op_checksig(stack, script, code_separator, transaction)
|
389
|
+
return stack.push(0.to_openssl_bn) if !stack
|
390
|
+
end
|
391
|
+
stack.push(1.to_openssl_bn)
|
392
|
+
end
|
393
|
+
end
|
394
|
+
|
395
|
+
private
|
396
|
+
|
397
|
+
def check_sig(signature, hash_type, pubkey, script, code_separator, transaction)
|
398
|
+
# get the script from codeseparator to end as subscript
|
399
|
+
# remove codeseparator from resulting script
|
400
|
+
# remove signature from script
|
401
|
+
subscript = Cryptocoin::Script.new(script[code_separator..-1])
|
402
|
+
subscript.is_subscript! # calls for removal of op_separate and signature
|
403
|
+
|
404
|
+
tx_copy = transaction.copy # in case we need to reset tx_copy
|
405
|
+
tx_copy.inputs.each do |i|
|
406
|
+
if i.index == @input_index
|
407
|
+
i.script_sig_length = Cryptocoin::Protocol::VarLenInt.from_int(subscript.raw.bytesize)
|
408
|
+
i.script_sig = subscript.raw
|
409
|
+
else
|
410
|
+
i.script_sig_length = 0.to_openssl_bn
|
411
|
+
i.script_sig = 0.to_openssl_bn
|
412
|
+
end
|
413
|
+
end
|
414
|
+
case hash_type
|
415
|
+
when 2
|
416
|
+
# SIGHASH_NONE
|
417
|
+
tx_copy.out_length = Cryptocoin::Protocol::VarLenInt.from_int(0)
|
418
|
+
tx_copy.outputs = ''
|
419
|
+
tx_copy.inputs.each do |i|
|
420
|
+
i.sequence = [0].pack('V') unless i == @input_index
|
421
|
+
end
|
422
|
+
when 3
|
423
|
+
# SIGHASH_SINGLE
|
424
|
+
if input_index >= tx_copy.outputs.length
|
425
|
+
# Special case, see https://github.com/bitcoinj/bitcoinj/blob/4df728a7d9210dc9ac5a5ae5188c89f5e9d41852/core/src/main/java/com/google/bitcoin/core/Transaction.java#L1018
|
426
|
+
# We're essentially resetting the transaction due to a bug
|
427
|
+
tx_copy = transaction
|
428
|
+
hash = Digest::SHA256([0100000000000000000000000000000000000000000000000000000000000000].pack('C*'))
|
429
|
+
bug = true
|
430
|
+
else
|
431
|
+
n_o = []
|
432
|
+
tx_copy.outputs.each do |o|
|
433
|
+
if o.index == @input_index
|
434
|
+
n_o.push(i)
|
435
|
+
elsif o.index < @input_index
|
436
|
+
# TODO: Implement this in a transaction builder
|
437
|
+
n_o.push(Cryptocoin::Structure::Transaction::Output.new(0, [-1].pack('q') + Cryptocoin::Protocol::VarLenInt.from_int(0)))
|
438
|
+
end
|
439
|
+
end
|
440
|
+
tx_copy.outputs = n_o
|
441
|
+
tx_copy.inputs.each do |i|
|
442
|
+
i.sequence = 0.to_openssl_bn_int
|
443
|
+
end
|
444
|
+
end
|
445
|
+
when 80
|
446
|
+
# SIGHASH_ANYONECANPAY
|
447
|
+
n_i = []
|
448
|
+
tx_copy.inputs.each do |i|
|
449
|
+
n_i.push(i) if i.index == @input.index
|
450
|
+
end
|
451
|
+
end
|
452
|
+
if !bug
|
453
|
+
# Do this if there's a bug in the reference client *SIGHASH_SINGLE*
|
454
|
+
i = tx_copy.raw + [hash_type].pack('V')
|
455
|
+
hash = Digest::SHA256.digest(Digest::SHA256.digest(i))
|
456
|
+
end
|
457
|
+
begin
|
458
|
+
k = OpenSSL::PKey::EC.new("secp256k1")
|
459
|
+
k.public_key = OpenSSL::PKey::EC::Point.new(k.group, OpenSSL::BN.new(pubkey.unpack('H*')[0], 16))
|
460
|
+
if k.dsa_verify_asn1(hash, signature)
|
461
|
+
stack.push(1.to_openssl_bn)
|
462
|
+
else
|
463
|
+
stack.push(0.to_openssl_bn)
|
464
|
+
end
|
465
|
+
rescue OpenSSL::PKey::ECError, OpenSSL::PKey::EC::Point::Error
|
466
|
+
stack.push(0.to_openssl_bn)
|
467
|
+
end
|
468
|
+
stack
|
469
|
+
end
|
470
|
+
|
471
|
+
def is_canonical_signature?(sig)
|
472
|
+
return false if sig.bytesize < 9
|
473
|
+
return false if sig.bytesize > 73
|
474
|
+
return false if !["\x01", "\x02", "\x03", "\x80"].include?(sig[-1])
|
475
|
+
return false if sig[0] != "\x30"
|
476
|
+
return false if sig[1].to_bn_to_i != sig.bytesize-3
|
477
|
+
r_length = sig[3].to_bn.to_i
|
478
|
+
return false if 5 + r_length >= sig.bytesize
|
479
|
+
s_length = sig[5+r_length]
|
480
|
+
return false if r_length + s_length + 7 != sig.bytesize
|
481
|
+
r = sig[4, r_length]
|
482
|
+
return false if r[-2] != "\x02"
|
483
|
+
return false if r.bytesize == 0
|
484
|
+
return false if r.bytes.inject{|x,y| (x<<8) | y} & 0x80
|
485
|
+
return false if r.bytesize > 1 and (r[0] == "\x00" and !(r[1].getbyte(0) & 0x80))
|
486
|
+
true
|
487
|
+
end
|
488
|
+
|
489
|
+
def is_canonical_pubkey?(pubkey)
|
490
|
+
return false if pubkey.bytesize < 33
|
491
|
+
case pubkey[0]
|
492
|
+
when "\x04"
|
493
|
+
# uncompressed pubkey
|
494
|
+
return false if pubkey.bytesize != 65
|
495
|
+
when "\x02", "\x03"
|
496
|
+
# compressed pubkey
|
497
|
+
return false if pubkey.bytesize != 33
|
498
|
+
else
|
499
|
+
# invalid first byte
|
500
|
+
return false
|
501
|
+
end
|
502
|
+
true
|
503
|
+
end
|
504
|
+
|
505
|
+
def require_stack(stack, size=1, &block)
|
506
|
+
if stack.size >= size
|
507
|
+
yield
|
508
|
+
else
|
509
|
+
nil
|
510
|
+
end
|
511
|
+
end
|
512
|
+
end
|
513
|
+
end
|
514
|
+
end
|
515
|
+
end
|