tapyrus 0.1.0 → 0.2.4

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.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +7 -15
  3. data/exe/tapyrusrbd +2 -2
  4. data/lib/openassets/util.rb +2 -4
  5. data/lib/schnorr.rb +83 -0
  6. data/lib/schnorr/signature.rb +38 -0
  7. data/lib/tapyrus.rb +11 -18
  8. data/lib/tapyrus/block.rb +3 -38
  9. data/lib/tapyrus/block_header.rb +70 -41
  10. data/lib/tapyrus/chain_params.rb +13 -36
  11. data/lib/tapyrus/chainparams/{regtest.yml → dev.yml} +10 -19
  12. data/lib/tapyrus/chainparams/{mainnet.yml → prod.yml} +7 -19
  13. data/lib/tapyrus/constants.rb +12 -34
  14. data/lib/tapyrus/errors.rb +17 -0
  15. data/lib/tapyrus/ext.rb +5 -0
  16. data/lib/tapyrus/ext/ecdsa.rb +39 -0
  17. data/lib/tapyrus/ext/json_parser.rb +47 -0
  18. data/lib/tapyrus/ext_key.rb +42 -23
  19. data/lib/tapyrus/key.rb +47 -40
  20. data/lib/tapyrus/message.rb +2 -2
  21. data/lib/tapyrus/message/base.rb +1 -0
  22. data/lib/tapyrus/message/block.rb +4 -4
  23. data/lib/tapyrus/message/cmpct_block.rb +3 -5
  24. data/lib/tapyrus/message/header_and_short_ids.rb +1 -1
  25. data/lib/tapyrus/message/headers.rb +1 -1
  26. data/lib/tapyrus/message/merkle_block.rb +1 -1
  27. data/lib/tapyrus/message/tx.rb +2 -2
  28. data/lib/tapyrus/network/peer.rb +1 -15
  29. data/lib/tapyrus/node/cli.rb +15 -11
  30. data/lib/tapyrus/node/configuration.rb +1 -1
  31. data/lib/tapyrus/node/spv.rb +1 -1
  32. data/lib/tapyrus/opcodes.rb +5 -0
  33. data/lib/tapyrus/out_point.rb +1 -1
  34. data/lib/tapyrus/rpc/request_handler.rb +7 -6
  35. data/lib/tapyrus/rpc/tapyrus_core_client.rb +17 -15
  36. data/lib/tapyrus/script/color.rb +79 -0
  37. data/lib/tapyrus/script/multisig.rb +0 -27
  38. data/lib/tapyrus/script/script.rb +74 -89
  39. data/lib/tapyrus/script/script_error.rb +8 -14
  40. data/lib/tapyrus/script/script_interpreter.rb +65 -86
  41. data/lib/tapyrus/script/tx_checker.rb +21 -5
  42. data/lib/tapyrus/secp256k1.rb +1 -0
  43. data/lib/tapyrus/secp256k1/native.rb +93 -20
  44. data/lib/tapyrus/secp256k1/rfc6979.rb +43 -0
  45. data/lib/tapyrus/secp256k1/ruby.rb +63 -54
  46. data/lib/tapyrus/store/chain_entry.rb +3 -2
  47. data/lib/tapyrus/store/db/level_db.rb +58 -0
  48. data/lib/tapyrus/store/spv_chain.rb +29 -11
  49. data/lib/tapyrus/tx.rb +18 -160
  50. data/lib/tapyrus/tx_in.rb +4 -11
  51. data/lib/tapyrus/tx_out.rb +2 -1
  52. data/lib/tapyrus/util.rb +8 -0
  53. data/lib/tapyrus/validation.rb +1 -6
  54. data/lib/tapyrus/version.rb +1 -1
  55. data/lib/tapyrus/wallet/account.rb +1 -0
  56. data/lib/tapyrus/wallet/master_key.rb +1 -0
  57. data/tapyrusrb.gemspec +3 -3
  58. metadata +44 -39
  59. data/lib/tapyrus/chainparams/testnet.yml +0 -41
  60. data/lib/tapyrus/descriptor.rb +0 -147
  61. data/lib/tapyrus/script_witness.rb +0 -38
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 73863e0b35030aee45baa96661f5bbd0322e78381be022d8372e620f8cd8668c
4
- data.tar.gz: 3f6378420bb9940a4829e378bb9975c67f5e5c5b61e4c5e077d85f83e0f59715
3
+ metadata.gz: 6e7f821324dfe56eb103457c17b585792e2cc250c3738f59f1665aa4a831a917
4
+ data.tar.gz: 1faa2850c7dfe07d9be35c75e3c9500e10ef39725db64fc01d88de5548894068
5
5
  SHA512:
6
- metadata.gz: 5ffa34b251d363ade9355430980d50d233c104071b15f46535fee2009b8826f4b163891e384cec997b72e2680387cd3d200b55a41c4ebda8c359fdf6f965f091
7
- data.tar.gz: c3860a9b13c2f43ef55b47cb985eb9467d5c4fdf9f1436b6c0e97b9a1b04a2ecdcd726e0103baa5ccd302753cc460f0240c0cd76c32cc08347e46e997e0ec7d6
6
+ metadata.gz: 3299a042ff5f3fa919d4732c1c7c9288cef3bdb213267171d7fa733b53929479b83abb333be1820304fbb593cda742fd8240d8589424536a044901e92cf96823
7
+ data.tar.gz: c579e85d346cb81290e5854c303147f32dbe1df3049f4190f05af1fded387aaf7cf7cc4170761fa9eaf409c174b7b37f9f3031193c442567bc95e5d8b1b02e2f
data/README.md CHANGED
@@ -12,7 +12,7 @@ Tapyrusrb supports following feature:
12
12
  * Tapyrus script interpreter
13
13
  * De/serialization of Tapyrus protocol network messages
14
14
  * De/serialization of blocks and transactions
15
- * Key generation and verification for ECDSA, including [BIP-32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki) and [BIP-39](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki) supports.
15
+ * Key generation and verification for Schnorr and ECDSA (including [BIP-32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki) and [BIP-39](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki) supports).
16
16
  * ECDSA signature(RFC6979 -Deterministic ECDSA, LOW-S, LOW-R support)
17
17
  * [WIP] SPV node
18
18
  * [WIP] 0ff-chain protocol
@@ -65,29 +65,21 @@ And then add to your .rb file:
65
65
 
66
66
  The parameters of the blockchain are managed by `Tapyrus::ChainParams`. Switch chain parameters as follows:
67
67
 
68
- * mainnet
68
+ * prod
69
69
 
70
70
  ```ruby
71
- Tapyrus.chain_params = :mainnet
71
+ Tapyrus.chain_params = :prod
72
72
  ```
73
73
 
74
- This parameter is described in https://github.com/chaintope/tapyrusrb/blob/master/lib/tapyrus/chainparams/mainnet.yml.
74
+ This parameter is described in https://github.com/chaintope/tapyrusrb/blob/master/lib/tapyrus/chainparams/prod.yml.
75
75
 
76
- * testnet
76
+ * dev
77
77
 
78
78
  ```ruby
79
- Tapyrus.chain_params = :testnet
79
+ Tapyrus.chain_params = :dev
80
80
  ```
81
81
 
82
- This parameter is described in https://github.com/chaintope/tapyrusrb/blob/master/lib/tapyrus/chainparams/testnet.yml.
83
-
84
- * regtest
85
-
86
- ```ruby
87
- Tapyrus.chain_params = :regtest
88
- ```
89
-
90
- This parameter is described in https://github.com/chaintope/tapyrusrb/blob/master/lib/tapyrus/chainparams/regtest.yml.
82
+ This parameter is described in https://github.com/chaintope/tapyrusrb/blob/master/lib/tapyrus/chainparams/dev.yml.
91
83
 
92
84
  ## Contributing
93
85
 
@@ -16,11 +16,11 @@ end
16
16
 
17
17
  class Tapyrusrbd < Thor
18
18
 
19
- class_option :network, aliases: '-n', default: :mainnet
19
+ class_option :network, aliases: '-n', default: :prod
20
20
 
21
21
  desc 'start', 'start tapyrusrb daemon.'
22
22
  def start
23
- network = options['network'] ? options['network'].to_sym : :mainnet
23
+ network = options['network'] ? options['network'].to_sym : :prod
24
24
  Tapyrus.chain_params = network
25
25
  FileUtils.mkdir_p(Tapyrus.base_dir)
26
26
  execute_daemon(['start', network: network])
@@ -18,10 +18,8 @@ module OpenAssets
18
18
  end
19
19
 
20
20
  def oa_version_byte
21
- case Tapyrus.chain_params.network
22
- when 'mainnet' then OA_VERSION_BYTE
23
- when 'testnet', 'regtest' then OA_VERSION_BYTE_TESTNET
24
- end
21
+ return OA_VERSION_BYTE if Tapyrus.chain_params.prod?
22
+ return OA_VERSION_BYTE_TESTNET if Tapyrus.chain_params.dev?
25
23
  end
26
24
  end
27
25
  end
@@ -0,0 +1,83 @@
1
+ module Schnorr
2
+ autoload :Signature, 'schnorr/signature'
3
+
4
+ module_function
5
+
6
+ GROUP = ECDSA::Group::Secp256k1
7
+ ALGO16 = 'SCHNORR + SHA256'
8
+
9
+ # Generate schnorr signature.
10
+ # @param message (String) A message to be signed with binary format.
11
+ # @param private_key (Integer) The private key.
12
+ # (The number of times to add the generator point to itself to get the public key.)
13
+ # @return (Schnorr::Signature)
14
+ def sign(message, private_key)
15
+ raise 'The message must be a 32-byte array.' unless message.bytesize == 32
16
+ raise 'private_key is zero or over the curve order.' if private_key == 0 || private_key >= GROUP.order
17
+
18
+ p = GROUP.new_point(private_key)
19
+ secret = ECDSA::Format::IntegerOctetString.encode(private_key, GROUP.byte_length)
20
+ secret = secret + message + ALGO16
21
+ nonce = Tapyrus::Secp256k1::RFC6979.generate_rfc6979_nonce(secret, '')
22
+
23
+ k0 = nonce % GROUP.order
24
+ raise 'Creation of signature failed. k is zero' if k0.zero?
25
+
26
+ r = GROUP.new_point(k0)
27
+ k = ECDSA::PrimeField.jacobi(r.y, GROUP.field.prime) == 1 ? k0 : GROUP.order - k0
28
+
29
+ e = create_challenge(r.x, p, message)
30
+
31
+ Schnorr::Signature.new(r.x, (k + e * private_key) % GROUP.order)
32
+ end
33
+
34
+ # Verifies the given {Signature} and returns true if it is valid.
35
+ # @param message (String) A message to be signed with binary format.
36
+ # @param public_key (String) The public key with binary format.
37
+ # @param signature (String) The signature with binary format.
38
+ # @return (Boolean) whether signature is valid.
39
+ def valid_sig?(message, signature, public_key)
40
+ check_sig!(message, signature, public_key)
41
+ rescue InvalidSignatureError, ECDSA::Format::DecodeError
42
+ false
43
+ end
44
+
45
+ # Verifies the given {Signature} and raises an {InvalidSignatureError} if it is invalid.
46
+ # @param message (String) A message to be signed with binary format.
47
+ # @param public_key (String) The public key with binary format.
48
+ # @param signature (String) The signature with binary format.
49
+ # @return (Boolean)
50
+ def check_sig!(message, signature, public_key)
51
+ sig = Schnorr::Signature.decode(signature)
52
+ pubkey = ECDSA::Format::PointOctetString.decode(public_key, GROUP)
53
+ field = GROUP.field
54
+
55
+ raise Schnorr::InvalidSignatureError, 'Invalid signature: r is not in the field.' unless field.include?(sig.r)
56
+ raise Schnorr::InvalidSignatureError, 'Invalid signature: s is not in the field.' unless field.include?(sig.s)
57
+ raise Schnorr::InvalidSignatureError, 'Invalid signature: r is zero.' if sig.r.zero?
58
+ raise Schnorr::InvalidSignatureError, 'Invalid signature: s is zero.' if sig.s.zero?
59
+ raise Schnorr::InvalidSignatureError, 'Invalid signature: r is larger than field size.' if sig.r >= field.prime
60
+ raise Schnorr::InvalidSignatureError, 'Invalid signature: s is larger than group order.' if sig.s >= GROUP.order
61
+
62
+ e = create_challenge(sig.r, pubkey, message)
63
+
64
+ r = GROUP.new_point(sig.s) + pubkey.multiply_by_scalar(e).negate
65
+
66
+ if r.infinity? || r.x != sig.r || ECDSA::PrimeField.jacobi(r.y, GROUP.field.prime) != 1
67
+ raise Schnorr::InvalidSignatureError, 'signature verification failed.'
68
+ end
69
+
70
+ true
71
+ end
72
+
73
+ # create signature digest.
74
+ # @param (Integer) x a x coordinate for R.
75
+ # @param (ECDSA::Point) p a public key.
76
+ # @return (Integer) digest e.
77
+ def create_challenge(x, p, message)
78
+ r_x = ECDSA::Format::IntegerOctetString.encode(x, GROUP.byte_length)
79
+ p_str= p.to_hex.htb
80
+ (ECDSA.normalize_digest(Digest::SHA256.digest(r_x + p_str + message), GROUP.bit_length)) % GROUP.order
81
+ end
82
+
83
+ end
@@ -0,0 +1,38 @@
1
+ module Schnorr
2
+
3
+ class InvalidSignatureError < StandardError; end
4
+
5
+ # Instances of this class represents Schnorr signatures,
6
+ # which are simply a pair of integers named `r` and `s`.
7
+ class Signature
8
+
9
+ attr_reader :r
10
+ attr_reader :s
11
+
12
+ # @param r (Integer) the value of r.
13
+ # @param s (Integer) the value of s.
14
+ def initialize(r, s)
15
+ @r, @s = r, s
16
+ r.is_a?(Integer) or raise ArgumentError, 'r is not an integer.'
17
+ s.is_a?(Integer) or raise ArgumentError, 's is not an integer.'
18
+ end
19
+
20
+ # Parse a string to a {Signature}.
21
+ # @param string (String) signature string with binary format.
22
+ # @return (Signature) signature instance.
23
+ def self.decode(string)
24
+ raise InvalidSignatureError, 'Invalid schnorr signature length.' unless string.bytesize == 64
25
+ r = string[0...32].unpack('H*').first.to_i(16)
26
+ s = string[32..-1].unpack('H*').first.to_i(16)
27
+ new(r, s)
28
+ end
29
+
30
+ # Encode signature to string.
31
+ # @return (String) encoded signature.
32
+ def encode
33
+ ECDSA::Format::IntegerOctetString.encode(r, 32) + ECDSA::Format::IntegerOctetString.encode(s, 32)
34
+ end
35
+
36
+ end
37
+
38
+ end
@@ -6,14 +6,15 @@ require 'eventmachine'
6
6
  require 'ecdsa'
7
7
  require 'securerandom'
8
8
  require 'json'
9
- require 'bech32'
10
9
  require 'ffi'
11
10
  require 'observer'
12
11
  require 'tmpdir'
13
12
  require_relative 'openassets'
13
+ require_relative 'schnorr'
14
14
 
15
15
  module Tapyrus
16
16
 
17
+ autoload :Ext, 'tapyrus/ext'
17
18
  autoload :Util, 'tapyrus/util'
18
19
  autoload :ChainParams, 'tapyrus/chain_params'
19
20
  autoload :Message, 'tapyrus/message'
@@ -29,7 +30,6 @@ module Tapyrus
29
30
  autoload :TxIn, 'tapyrus/tx_in'
30
31
  autoload :TxOut, 'tapyrus/tx_out'
31
32
  autoload :OutPoint, 'tapyrus/out_point'
32
- autoload :ScriptWitness, 'tapyrus/script_witness'
33
33
  autoload :MerkleTree, 'tapyrus/merkle_tree'
34
34
  autoload :Key, 'tapyrus/key'
35
35
  autoload :ExtKey, 'tapyrus/ext_key'
@@ -46,18 +46,20 @@ module Tapyrus
46
46
  autoload :Wallet, 'tapyrus/wallet'
47
47
  autoload :BloomFilter, 'tapyrus/bloom_filter'
48
48
  autoload :KeyPath, 'tapyrus/key_path'
49
- autoload :Descriptor, 'tapyrus/descriptor'
50
49
  autoload :SLIP39, 'tapyrus/slip39'
50
+ autoload :Color, 'tapyrus/script/color'
51
+ autoload :Errors, 'tapyrus/errors'
51
52
 
52
53
  require_relative 'tapyrus/constants'
54
+ require_relative 'tapyrus/ext/ecdsa'
53
55
 
54
56
  extend Util
55
57
 
56
- @chain_param = :mainnet
58
+ @chain_param = :prod
57
59
 
58
60
  # set tapyrus network chain params
59
61
  def self.chain_params=(name)
60
- raise "chain params for #{name} is not defined." unless %i(mainnet testnet regtest).include?(name.to_sym)
62
+ raise "chain params for #{name} is not defined." unless %i(prod dev).include?(name.to_sym)
61
63
  @current_chain = nil
62
64
  @chain_param = name.to_sym
63
65
  end
@@ -66,12 +68,10 @@ module Tapyrus
66
68
  def self.chain_params
67
69
  return @current_chain if @current_chain
68
70
  case @chain_param
69
- when :mainnet
70
- @current_chain = Tapyrus::ChainParams.mainnet
71
- when :testnet
72
- @current_chain = Tapyrus::ChainParams.testnet
73
- when :regtest
74
- @current_chain = Tapyrus::ChainParams.regtest
71
+ when :prod
72
+ @current_chain = Tapyrus::ChainParams.prod
73
+ when :dev
74
+ @current_chain = Tapyrus::ChainParams.dev
75
75
  end
76
76
  @current_chain
77
77
  end
@@ -209,11 +209,4 @@ module Tapyrus
209
209
  end
210
210
  end
211
211
 
212
- class ::ECDSA::Signature
213
- # convert signature to der string.
214
- def to_der
215
- ECDSA::Format::SignatureDerString.encode(self)
216
- end
217
- end
218
-
219
212
  end
@@ -1,5 +1,6 @@
1
1
  module Tapyrus
2
2
  class Block
3
+ include Tapyrus::Util
3
4
 
4
5
  attr_accessor :header
5
6
  attr_accessor :transactions
@@ -21,23 +22,6 @@ module Tapyrus
21
22
  header.block_hash
22
23
  end
23
24
 
24
- # calculate block weight
25
- def weight
26
- stripped_size * (WITNESS_SCALE_FACTOR - 1) + size
27
- end
28
-
29
- # calculate total size (include witness data.)
30
- def size
31
- 80 + Tapyrus.pack_var_int(transactions.size).bytesize +
32
- transactions.inject(0){|sum, tx| sum + (tx.witness? ? tx.serialize_witness_format.bytesize : tx.serialize_old_format.bytesize)}
33
- end
34
-
35
- # calculate base size (not include witness data.)
36
- def stripped_size
37
- 80 + Tapyrus.pack_var_int(transactions.size).bytesize +
38
- transactions.inject(0){|sum, tx| sum + tx.serialize_old_format.bytesize}
39
- end
40
-
41
25
  # check the merkle root in the block header matches merkle root calculated from tx list.
42
26
  def valid_merkle_root?
43
27
  calculate_merkle_root == header.merkle_root
@@ -48,29 +32,10 @@ module Tapyrus
48
32
  Tapyrus::MerkleTree.build_from_leaf(transactions.map(&:tx_hash)).merkle_root
49
33
  end
50
34
 
51
- # check the witness commitment in coinbase tx matches witness commitment calculated from tx list.
52
- def valid_witness_commitment?
53
- transactions[0].witness_commitment == calculate_witness_commitment
54
- end
55
-
56
- # calculate witness commitment from tx list.
57
- def calculate_witness_commitment
58
- witness_hashes = [COINBASE_WTXID]
59
- witness_hashes += (transactions[1..-1].map(&:witness_hash))
60
- reserved_value = transactions[0].inputs[0].script_witness.stack.map(&:bth).join
61
- root_hash = Tapyrus::MerkleTree.build_from_leaf(witness_hashes).merkle_root
62
- Tapyrus.double_sha256([root_hash + reserved_value].pack('H*')).bth
63
- end
64
-
65
35
  # return this block height. block height is included in coinbase.
66
- # if block version under 1, height does not include in coinbase, so return nil.
36
+ # @return [Integer] block height.
67
37
  def height
68
- return nil if header.version < 2
69
- coinbase_tx = transactions[0]
70
- return nil unless coinbase_tx.coinbase_tx?
71
- buf = StringIO.new(coinbase_tx.inputs[0].script_sig.to_payload)
72
- len = Tapyrus.unpack_var_int_from_io(buf)
73
- buf.read(len).reverse.bth.to_i(16)
38
+ transactions.first.in.first.out_point.index
74
39
  end
75
40
 
76
41
  end
@@ -2,61 +2,70 @@ module Tapyrus
2
2
 
3
3
  # Block Header
4
4
  class BlockHeader
5
+ include Tapyrus::HexConverter
6
+ extend Tapyrus::Util
7
+ include Tapyrus::Util
5
8
 
6
- attr_accessor :version
9
+ X_FILED_TYPES = {none: 0, aggregate_pubkey: 1}
10
+
11
+ attr_accessor :features
7
12
  attr_accessor :prev_hash
8
13
  attr_accessor :merkle_root
9
- attr_accessor :time # unix timestamp
10
- attr_accessor :bits
11
- attr_accessor :nonce
12
-
13
- def initialize(version, prev_hash, merkle_root, time, bits, nonce)
14
- @version = version
14
+ attr_accessor :im_merkle_root # merkel root of immulable merkle tree which consist of immutable txid.
15
+ attr_accessor :time # unix timestamp
16
+ attr_accessor :x_field_type
17
+ attr_accessor :x_field
18
+ attr_accessor :proof
19
+
20
+ def initialize(features, prev_hash, merkle_root, im_merkle_root, time, x_field_type, x_field, proof = nil)
21
+ @features = features
15
22
  @prev_hash = prev_hash
16
23
  @merkle_root = merkle_root
24
+ @im_merkle_root = im_merkle_root
17
25
  @time = time
18
- @bits = bits
19
- @nonce = nonce
26
+ @x_field_type = x_field_type
27
+ @x_field = x_field
28
+ @proof = proof
20
29
  end
21
30
 
22
31
  def self.parse_from_payload(payload)
23
- version, prev_hash, merkle_root, time, bits, nonce = payload.unpack('Va32a32VVV')
24
- new(version, prev_hash.bth, merkle_root.bth, time, bits, nonce)
25
- end
26
-
27
- def to_payload
28
- [version, prev_hash.htb, merkle_root.htb, time, bits, nonce].pack('Va32a32VVV')
32
+ buf = payload.is_a?(String) ? StringIO.new(payload) : payload
33
+ features, prev_hash, merkle_root, im_merkle_root, time, x_filed_type = buf.read(105).unpack('Va32a32a32Vc')
34
+ x_field = buf.read(unpack_var_int_from_io(buf)) unless x_filed_type == X_FILED_TYPES[:none]
35
+ proof = buf.read(unpack_var_int_from_io(buf))
36
+ new(features, prev_hash.bth, merkle_root.bth, im_merkle_root.bth, time, x_filed_type, x_field ? x_field.bth : x_field, proof.bth)
29
37
  end
30
38
 
31
- # compute difficulty target from bits.
32
- def difficulty_target
33
- exponent = ((bits >> 24) & 0xff)
34
- mantissa = bits & 0x7fffff
35
- mantissa *= -1 if (bits & 0x800000) > 0
36
- (mantissa * 2 ** (8 * (exponent - 3)))
39
+ def to_payload(skip_proof = false)
40
+ payload = [features, prev_hash.htb, merkle_root.htb, im_merkle_root.htb, time, x_field_type].pack('Va32a32a32Vc')
41
+ payload << pack_var_string(x_field.htb) unless x_field_type == X_FILED_TYPES[:none]
42
+ payload << pack_var_string(proof.htb) if proof && !skip_proof
43
+ payload
37
44
  end
38
45
 
39
- def hash
40
- calc_hash.to_i(16)
46
+ # Calculate hash using sign which does not contains proof.
47
+ # @return [String] hash of block without proof.
48
+ def hash_for_sign
49
+ Tapyrus.double_sha256(to_payload(true)).bth
41
50
  end
42
51
 
52
+ # Calculate block hash
53
+ # @return [String] hash of block with hex format.
43
54
  def block_hash
44
- calc_hash
55
+ Tapyrus.double_sha256(to_payload).bth
45
56
  end
46
57
 
47
58
  # block hash(big endian)
59
+ # @return [String] block id which is reversed version of block hash.
48
60
  def block_id
49
61
  block_hash.rhex
50
62
  end
51
63
 
52
64
  # evaluate block header
53
- def valid?
54
- valid_pow? && valid_timestamp?
55
- end
56
-
57
- # evaluate valid proof of work.
58
- def valid_pow?
59
- block_id.hex < difficulty_target
65
+ # @param [String] agg_pubkey aggregated public key for signers with hex format.
66
+ # @return [Boolean] result.
67
+ def valid?(agg_pubkey)
68
+ valid_timestamp? && valid_proof?(agg_pubkey) && valid_x_field?
60
69
  end
61
70
 
62
71
  # evaluate valid timestamp.
@@ -65,22 +74,42 @@ module Tapyrus
65
74
  time <= Time.now.to_i + Tapyrus::MAX_FUTURE_BLOCK_TIME
66
75
  end
67
76
 
68
- # compute chain work of this block.
69
- # @return [Integer] a chain work.
70
- def work
71
- target = difficulty_target
72
- return 0 if target < 1
73
- 115792089237316195423570985008687907853269984665640564039457584007913129639936.div(target + 1) # 115792089237316195423570985008687907853269984665640564039457584007913129639936 is 2**256
77
+ # Check whether proof is valid.
78
+ # @param [String] agg_pubkey aggregated public key for signers with hex format.
79
+ # @return [Boolean] Return true if proof is valid, otherwise return false.
80
+ def valid_proof?(agg_pubkey)
81
+ pubkey = Tapyrus::Key.new(pubkey: agg_pubkey)
82
+ msg = hash_for_sign.htb
83
+ pubkey.verify(proof.htb, msg, algo: :schnorr)
84
+ end
85
+
86
+ # Check whether x_field is valid.
87
+ # @return [Boolean] if valid return true, otherwise false
88
+ def valid_x_field?
89
+ case x_field_type
90
+ when X_FILED_TYPES[:none] then
91
+ x_field.nil?
92
+ when X_FILED_TYPES[:aggregate_pubkey] then
93
+ Tapyrus::Key.new(pubkey: x_field).fully_valid_pubkey?
94
+ else
95
+ false
96
+ end
97
+ end
98
+
99
+ # Check this header contains upgrade aggregated publiec key.
100
+ # @return [Boolean] if contains return true, otherwise false.
101
+ def upgrade_agg_pubkey?
102
+ x_field_type == X_FILED_TYPES[:aggregate_pubkey]
74
103
  end
75
104
 
76
105
  def ==(other)
77
106
  other && other.to_payload == to_payload
78
107
  end
79
108
 
80
- private
81
-
82
- def calc_hash
83
- Tapyrus.double_sha256(to_payload).bth
109
+ # get bytesize.
110
+ # @return [Integer] bytesize.
111
+ def size
112
+ to_payload.bytesize
84
113
  end
85
114
 
86
115
  end