tapyrus 0.3.1 → 0.3.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dc2e90197905239fab7d891f05da735cf1fb2df0127abbb1ca38c1299130914d
4
- data.tar.gz: 36a9a028b360a238077bd30c2380b3c722983d5dbd7e5f5d9e6e1d2dbd1408c0
3
+ metadata.gz: fe8d938cb082800dbacfbdbebc6ab00d14a40693a92a4df46f967d0535f9e337
4
+ data.tar.gz: b6a51b4a565435d2a5a4f65d6fbcec3420464d6067742c64d00651919de22d6d
5
5
  SHA512:
6
- metadata.gz: e336315f9e68a361edf4b0e2dec290a6e37f666375badc13336391289b773084d57ac324fa5e1b3334faa6400d931abd24dda05345901767a29e9f11251200bc
7
- data.tar.gz: a1a3df8abf276b794eed62cd7b238d57fa909315f116d5f12c4b472e32b24c8da1ff8cc62e656fb985cf5728e24a7821580b1f24f09613535a2be4b23f3bf1fa
6
+ metadata.gz: c2ead3ceffe67d128f94af033ff788fbb15a283416af5ed2afe915ad8af6dc34e36e6e5ad7e21fa94ea2137e8cde1441a3b15228402b46243b582e21ab0dea1d
7
+ data.tar.gz: 1dbefaca1c96fa263ba870f8f892f33a1161c8d7ba0e2ecedad1aea3af98112cb8836e03f85201a1c2d0febe010b49f73e4497195eca90e157081d4a049f265e
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Tapyrusrb [![Build Status](https://travis-ci.org/chaintope/tapyrusrb.svg?branch=master)](https://travis-ci.org/chaintope/tapyrusrb) [![Gem Version](https://badge.fury.io/rb/tapyrus.svg)](https://badge.fury.io/rb/tapyrus) [![MIT License](http://img.shields.io/badge/license-MIT-blue.svg?style=flat)](LICENSE)
1
+ # Tapyrusrb [![Build Status](https://github.com/chaintope/tapyrusrb/actions/workflows/ruby.yml/badge.svg?branch=master)](https://github.com/chaintope/tapyrusrb/actions/workflows/ruby.yml) [![Gem Version](https://badge.fury.io/rb/tapyrus.svg)](https://badge.fury.io/rb/tapyrus) [![MIT License](http://img.shields.io/badge/license-MIT-blue.svg?style=flat)](LICENSE)
2
2
 
3
3
  Tapyrusrb is a Ruby implementation of [Tapyrus](https://github.com/chaintope/tapyrus-core) Protocol.
4
4
 
@@ -0,0 +1,71 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'tapyrus'
4
+ require 'terminal-table'
5
+
6
+
7
+ print "Enter scriptPubkey: "
8
+ script_pubkey_hex = gets.chomp
9
+ script_pubkey = Tapyrus::Script.parse_from_payload(script_pubkey_hex.htb)
10
+ puts script_pubkey unless script_pubkey_hex.empty?
11
+
12
+ print "Enter scriptSig: "
13
+ script_sig_hex = gets.chomp
14
+ script_sig = Tapyrus::Script.parse_from_payload(script_sig_hex.htb)
15
+ puts script_sig unless script_sig_hex.empty?
16
+
17
+ unless script_sig.push_only?
18
+ warn "scriptSig has non-push opcode."
19
+ puts
20
+ end
21
+
22
+ if script_pubkey_hex.empty? && script_sig.empty?
23
+ puts "Empty script."
24
+ exit
25
+ end
26
+
27
+ print "Enter tx: "
28
+ tx_hex = gets.chomp
29
+ tx = nil
30
+ input_index = nil
31
+ unless tx_hex.length == 0
32
+ print "Enter index of the input: "
33
+ input_index = gets.chomp
34
+ begin
35
+ tx = Tapyrus::Tx.parse_from_payload(tx_hex.htb)
36
+ rescue StandardError
37
+ warn "Invalid tx data."
38
+ exit
39
+ end
40
+ if input_index.empty?
41
+ warn "Index of input missing."
42
+ exit
43
+ end
44
+ input_index = input_index.to_i
45
+ end
46
+
47
+ begin
48
+ debugger = Tapyrus::ScriptDebugger.new(script_pubkey: script_pubkey, script_sig: script_sig, tx: tx, index: input_index)
49
+ rescue ArgumentError => e
50
+ warn e.message
51
+ exit
52
+ end
53
+
54
+ puts "The Script is ready to be executed; you can step execution it by putting the Enter key."
55
+ print "> "
56
+ while cmd = gets.chomp
57
+ if cmd.length == 0
58
+ result = debugger.step
59
+ if result.halt?
60
+ puts result.message if result.message
61
+ warn result.error
62
+ exit
63
+ elsif result.finished?
64
+ puts "Execution finished."
65
+ exit
66
+ else
67
+ result.print_result
68
+ end
69
+ end
70
+ print "> "
71
+ end
@@ -104,7 +104,7 @@ module Tapyrus
104
104
  end
105
105
  end
106
106
 
107
- # Check this header contains upgrade aggregated publiec key.
107
+ # Check this header contains upgrade aggregated public key.
108
108
  # @return [Boolean] if contains return true, otherwise false.
109
109
  def upgrade_agg_pubkey?
110
110
  x_field_type == X_FILED_TYPES[:aggregate_pubkey]
@@ -94,8 +94,6 @@ module Tapyrus
94
94
  # 80 bytes of data, +1 for OP_RETURN, +2 for the pushdata opcodes.
95
95
  MAX_OP_RETURN_RELAY = 83
96
96
 
97
- SIG_VERSION = [:base]
98
-
99
97
  # for script error
100
98
  SCRIPT_ERR_OK = 0
101
99
  SCRIPT_ERR_UNKNOWN_ERROR = 1
@@ -10,6 +10,7 @@ module Tapyrus
10
10
 
11
11
  INVALID_PRIV_KEY = 'Private key is not in range [1..n-1].'
12
12
  INVALID_CHECKSUM = 'Invalid checksum.'
13
+ INVALID_PRIV_LENGTH = 'Private key must be 32 bytes.'
13
14
  end
14
15
  end
15
16
  end
@@ -25,7 +25,8 @@ module Tapyrus
25
25
  l = Tapyrus.hmac_sha512('Tapyrus seed', seed.htb)
26
26
  left = l[0..31].bth.to_i(16)
27
27
  raise 'invalid key' if left >= CURVE_ORDER || left == 0
28
- ext_key.key = Tapyrus::Key.new(priv_key: l[0..31].bth, key_type: Tapyrus::Key::TYPES[:compressed])
28
+ l_priv = ECDSA::Format::IntegerOctetString.encode(left, 32)
29
+ ext_key.key = Tapyrus::Key.new(priv_key: l_priv.bth, key_type: Tapyrus::Key::TYPES[:compressed])
29
30
  ext_key.chain_code = l[32..-1]
30
31
  ext_key
31
32
  end
@@ -107,7 +108,8 @@ module Tapyrus
107
108
  raise 'invalid key' if left >= CURVE_ORDER
108
109
  child_priv = (left + key.priv_key.to_i(16)) % CURVE_ORDER
109
110
  raise 'invalid key ' if child_priv >= CURVE_ORDER
110
- new_key.key = Tapyrus::Key.new(priv_key: child_priv.to_even_length_hex.rjust(64, '0'), key_type: key_type)
111
+ child_priv = ECDSA::Format::IntegerOctetString.encode(child_priv, 32)
112
+ new_key.key = Tapyrus::Key.new(priv_key: child_priv.bth, key_type: key_type)
111
113
  new_key.chain_code = l[32..-1]
112
114
  new_key.ver = version
113
115
  new_key
@@ -275,7 +277,8 @@ module Tapyrus
275
277
  l = Tapyrus.hmac_sha512(chain_code, data)
276
278
  left = l[0..31].bth.to_i(16)
277
279
  raise 'invalid key' if left >= CURVE_ORDER
278
- p1 = Tapyrus::Key.new(priv_key: left.to_s(16), key_type: Tapyrus::Key::TYPES[:uncompressed]).to_point
280
+ l_priv = ECDSA::Format::IntegerOctetString.encode(left, 32)
281
+ p1 = Tapyrus::Key.new(priv_key: l_priv.bth, key_type: Tapyrus::Key::TYPES[:uncompressed]).to_point
279
282
  p2 = Tapyrus::Key.new(pubkey: pubkey, key_type: key_type).to_point
280
283
  new_key.pubkey = (p1 + p2).to_hex
281
284
  new_key.chain_code = l[32..-1]
data/lib/tapyrus/key.rb CHANGED
@@ -41,7 +41,11 @@ module Tapyrus
41
41
  end
42
42
  @secp256k1_module = Tapyrus.secp_impl
43
43
  @priv_key = priv_key
44
- raise ArgumentError, Errors::Messages::INVALID_PRIV_KEY unless validate_private_key_range(@priv_key) if @priv_key
44
+
45
+ if @priv_key
46
+ raise ArgumentError, Errors::Messages::INVALID_PRIV_KEY unless validate_private_key_range(@priv_key)
47
+ raise ArgumentError, Errors::Messages::INVALID_PRIV_LENGTH unless @priv_key.htb.bytesize == 32
48
+ end
45
49
  if pubkey
46
50
  @pubkey = pubkey
47
51
  else
@@ -0,0 +1,164 @@
1
+ module Tapyrus
2
+ class ScriptDebugger
3
+ attr_reader :script_pubkey
4
+ attr_reader :script_sig
5
+ attr_reader :tx_checker
6
+ attr_reader :interpreter
7
+
8
+ attr_accessor :target_script
9
+ attr_accessor :is_redeem
10
+ attr_accessor :chunk_index
11
+ attr_accessor :chunk_size
12
+ attr_accessor :chunks
13
+ attr_accessor :stack_copy
14
+
15
+ # @param [Tapyrus::Script] script_pubkey
16
+ # @param [Tapyrus::Script] script_sig
17
+ # @param [Tapyrus::Tx] tx (optional)
18
+ # @param [Integer] index (optional) input index
19
+ # @raise [ArgumentError]
20
+ def initialize(script_pubkey:, script_sig:, tx: nil, index: nil)
21
+ @script_pubkey = script_pubkey
22
+ @script_sig = script_sig
23
+ if tx
24
+ raise ArgumentError, 'index should be specified' if index.nil?
25
+ @tx_checker = Tapyrus::TxChecker.new(tx: tx, input_index: index)
26
+ if (tx_checker.tx.in.size - 1) < tx_checker.input_index
27
+ raise ArgumentError, "Tx does not have #{tx_checker.input_index}-th input."
28
+ end
29
+ else
30
+ @tx_checker = EmptyTxChecker.new
31
+ end
32
+ @interpreter = Tapyrus::ScriptInterpreter.new(checker: tx_checker)
33
+ @interpreter.reset_params
34
+ @chunk_index = 0
35
+ @target_script = script_sig
36
+ @chunks = target_script.chunks.each
37
+ @chunk_size = target_script.chunks.length
38
+ @stack_copy = nil
39
+ end
40
+
41
+ def step
42
+ if chunk_size == chunk_index
43
+ if target_script == script_sig
44
+ @stack_copy = interpreter.stack.dup
45
+ @target_script = script_pubkey
46
+ @interpreter.reset_params
47
+ @chunks = target_script.chunks.each
48
+ @chunk_index = 0
49
+ @chunk_size = target_script.chunks.length
50
+ elsif target_script == script_pubkey
51
+ if interpreter.stack.empty? || !interpreter.cast_to_bool(interpreter.stack.last.htb)
52
+ return(
53
+ StepResult.error(
54
+ current_stack: interpreter.stack.dup,
55
+ error: 'Script evaluated without error but finished with a false/empty top stack element'
56
+ )
57
+ )
58
+ end
59
+ if script_pubkey.p2sh?
60
+ interpreter.stack = stack_copy
61
+ redeem_script = Tapyrus::Script.parse_from_payload(interpreter.stack.pop.htb)
62
+ @target_script = redeem_script
63
+ @chunks = target_script.chunks.each
64
+ @chunk_index = 0
65
+ @chunk_size = target_script.chunks.length
66
+ else
67
+ return StepResult.finished(current_stack: interpreter.stack.dup)
68
+ end
69
+ else
70
+ return StepResult.finished(current_stack: interpreter.stack.dup)
71
+ end
72
+ end
73
+ result = step_process(interpreter, target_script, chunks.next, chunk_index, is_redeem)
74
+ return result if result.is_a?(StepResult)
75
+ @chunk_index += 1
76
+ StepResult.success(current_stack: interpreter.stack.dup, message: result)
77
+ end
78
+
79
+ private
80
+
81
+ def step_process(interpreter, script, chunk, index, is_redeem_script)
82
+ message =
83
+ chunk.pushdata? ? "PUSH #{chunk.pushed_data.bth}" : "APPLY #{Tapyrus::Opcodes.opcode_to_name(chunk.opcode)}"
84
+ begin
85
+ result = interpreter.next_step(script, chunk, index, is_redeem_script)
86
+ if result.is_a?(FalseClass)
87
+ return(
88
+ StepResult.error(current_stack: interpreter.stack.dup, error: "script failed. Reason: #{interpreter.error}")
89
+ )
90
+ end
91
+ message
92
+ rescue TxUnspecifiedError => e
93
+ return StepResult.error(current_stack: interpreter.stack.dup, error: e.message, message: message)
94
+ end
95
+ end
96
+ end
97
+
98
+ class StepResult
99
+ STATUS_RUNNING = 'running'
100
+ STATUS_HALT = 'halt'
101
+ STATUS_FINISHED = 'finished'
102
+
103
+ STATUSES = [STATUS_RUNNING, STATUS_HALT, STATUS_FINISHED]
104
+
105
+ attr_reader :status
106
+ attr_reader :current_stack
107
+ attr_reader :message
108
+ attr_reader :error
109
+
110
+ # @param [String] status
111
+ # @param [Array] current_stack
112
+ # @param [String] message
113
+ # @param [String] error an error message.
114
+ def initialize(status, current_stack: [], message: nil, error: nil)
115
+ raise ArgumentError, 'Unsupported status specified.' unless STATUSES.include?(status)
116
+ @status = status
117
+ @current_stack = current_stack
118
+ @error = error
119
+ @message = message
120
+ end
121
+
122
+ def self.error(current_stack: [], error:, message: nil)
123
+ StepResult.new(STATUS_HALT, current_stack: current_stack, error: error, message: message)
124
+ end
125
+
126
+ def self.success(current_stack: [], message: nil)
127
+ StepResult.new(STATUS_RUNNING, current_stack: current_stack, message: message)
128
+ end
129
+
130
+ def self.finished(current_stack: [])
131
+ StepResult.new(STATUS_FINISHED, current_stack: current_stack)
132
+ end
133
+
134
+ def halt?
135
+ status == STATUS_HALT
136
+ end
137
+
138
+ def finished?
139
+ status == STATUS_FINISHED
140
+ end
141
+
142
+ def stack_table
143
+ rows = current_stack.map { |s| [s] }.reverse
144
+ Terminal::Table.new(title: 'Current Stack', rows: rows)
145
+ end
146
+
147
+ def print_result
148
+ puts message if message
149
+ puts stack_table
150
+ end
151
+ end
152
+
153
+ class TxUnspecifiedError < StandardError
154
+ end
155
+
156
+ class EmptyTxChecker
157
+ def check_sig(script_sig, pubkey, script_code)
158
+ raise TxUnspecifiedError, 'Signature verification failed. You need to enter tx and input index.'
159
+ end
160
+ def verify_sig(sig, pubkey, digest, allow_hybrid: false)
161
+ raise TxUnspecifiedError, 'Signature verification failed. You need to enter tx and input index.'
162
+ end
163
+ end
164
+ end