tapyrus 0.2.6 → 0.2.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (119) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +37 -0
  3. data/.prettierignore +3 -0
  4. data/.prettierrc.yaml +3 -0
  5. data/.ruby-version +1 -1
  6. data/CODE_OF_CONDUCT.md +7 -7
  7. data/README.md +14 -17
  8. data/Rakefile +3 -3
  9. data/lib/openassets/marker_output.rb +0 -4
  10. data/lib/openassets/payload.rb +4 -10
  11. data/lib/openassets.rb +0 -2
  12. data/lib/schnorr/sign_to_contract.rb +51 -0
  13. data/lib/schnorr/signature.rb +3 -6
  14. data/lib/schnorr.rb +14 -9
  15. data/lib/tapyrus/base58.rb +7 -6
  16. data/lib/tapyrus/bip175.rb +67 -0
  17. data/lib/tapyrus/block.rb +1 -2
  18. data/lib/tapyrus/block_header.rb +15 -9
  19. data/lib/tapyrus/bloom_filter.rb +5 -3
  20. data/lib/tapyrus/chain_params.rb +1 -4
  21. data/lib/tapyrus/chainparams/dev.yml +3 -2
  22. data/lib/tapyrus/chainparams/prod.yml +3 -2
  23. data/lib/tapyrus/constants.rb +29 -23
  24. data/lib/tapyrus/errors.rb +1 -3
  25. data/lib/tapyrus/ext/ecdsa.rb +4 -4
  26. data/lib/tapyrus/ext/json_parser.rb +1 -4
  27. data/lib/tapyrus/ext.rb +1 -1
  28. data/lib/tapyrus/ext_key.rb +44 -32
  29. data/lib/tapyrus/key.rb +31 -35
  30. data/lib/tapyrus/key_path.rb +15 -12
  31. data/lib/tapyrus/logger.rb +20 -16
  32. data/lib/tapyrus/merkle_tree.rb +22 -20
  33. data/lib/tapyrus/message/addr.rb +1 -7
  34. data/lib/tapyrus/message/base.rb +0 -3
  35. data/lib/tapyrus/message/block.rb +2 -9
  36. data/lib/tapyrus/message/block_transaction_request.rb +3 -6
  37. data/lib/tapyrus/message/block_transactions.rb +2 -6
  38. data/lib/tapyrus/message/block_txn.rb +0 -4
  39. data/lib/tapyrus/message/cmpct_block.rb +1 -7
  40. data/lib/tapyrus/message/error.rb +1 -4
  41. data/lib/tapyrus/message/fee_filter.rb +1 -4
  42. data/lib/tapyrus/message/filter_add.rb +0 -4
  43. data/lib/tapyrus/message/filter_clear.rb +0 -4
  44. data/lib/tapyrus/message/filter_load.rb +2 -5
  45. data/lib/tapyrus/message/get_addr.rb +0 -4
  46. data/lib/tapyrus/message/get_block_txn.rb +0 -4
  47. data/lib/tapyrus/message/get_blocks.rb +0 -3
  48. data/lib/tapyrus/message/get_data.rb +1 -4
  49. data/lib/tapyrus/message/get_headers.rb +1 -3
  50. data/lib/tapyrus/message/header_and_short_ids.rb +3 -9
  51. data/lib/tapyrus/message/headers.rb +0 -4
  52. data/lib/tapyrus/message/headers_parser.rb +3 -8
  53. data/lib/tapyrus/message/inv.rb +1 -4
  54. data/lib/tapyrus/message/inventories_parser.rb +2 -7
  55. data/lib/tapyrus/message/inventory.rb +12 -5
  56. data/lib/tapyrus/message/mem_pool.rb +0 -4
  57. data/lib/tapyrus/message/merkle_block.rb +4 -9
  58. data/lib/tapyrus/message/network_addr.rb +7 -6
  59. data/lib/tapyrus/message/not_found.rb +0 -3
  60. data/lib/tapyrus/message/ping.rb +0 -3
  61. data/lib/tapyrus/message/pong.rb +0 -3
  62. data/lib/tapyrus/message/prefilled_tx.rb +0 -4
  63. data/lib/tapyrus/message/reject.rb +0 -3
  64. data/lib/tapyrus/message/send_cmpct.rb +1 -3
  65. data/lib/tapyrus/message/send_headers.rb +0 -3
  66. data/lib/tapyrus/message/tx.rb +0 -4
  67. data/lib/tapyrus/message/ver_ack.rb +1 -5
  68. data/lib/tapyrus/message/version.rb +2 -5
  69. data/lib/tapyrus/message.rb +14 -16
  70. data/lib/tapyrus/mnemonic.rb +17 -15
  71. data/lib/tapyrus/network/connection.rb +0 -3
  72. data/lib/tapyrus/network/message_handler.rb +61 -60
  73. data/lib/tapyrus/network/peer.rb +13 -12
  74. data/lib/tapyrus/network/peer_discovery.rb +10 -9
  75. data/lib/tapyrus/network/pool.rb +12 -12
  76. data/lib/tapyrus/network.rb +0 -2
  77. data/lib/tapyrus/node/cli.rb +12 -14
  78. data/lib/tapyrus/node/configuration.rb +1 -3
  79. data/lib/tapyrus/node/spv.rb +2 -3
  80. data/lib/tapyrus/node.rb +1 -1
  81. data/lib/tapyrus/opcodes.rb +9 -7
  82. data/lib/tapyrus/out_point.rb +5 -5
  83. data/lib/tapyrus/rpc/http_server.rb +21 -22
  84. data/lib/tapyrus/rpc/request_handler.rb +42 -44
  85. data/lib/tapyrus/rpc/tapyrus_core_client.rb +67 -25
  86. data/lib/tapyrus/rpc.rb +1 -0
  87. data/lib/tapyrus/script/color.rb +10 -0
  88. data/lib/tapyrus/script/multisig.rb +13 -12
  89. data/lib/tapyrus/script/script.rb +99 -88
  90. data/lib/tapyrus/script/script_error.rb +1 -4
  91. data/lib/tapyrus/script/script_interpreter.rb +439 -399
  92. data/lib/tapyrus/script/tx_checker.rb +20 -10
  93. data/lib/tapyrus/secp256k1/native.rb +14 -15
  94. data/lib/tapyrus/secp256k1/rfc6979.rb +7 -4
  95. data/lib/tapyrus/secp256k1/ruby.rb +10 -12
  96. data/lib/tapyrus/secp256k1.rb +0 -4
  97. data/lib/tapyrus/slip39/share.rb +41 -29
  98. data/lib/tapyrus/slip39/sss.rb +107 -57
  99. data/lib/tapyrus/slip39.rb +20 -5
  100. data/lib/tapyrus/store/chain_entry.rb +0 -4
  101. data/lib/tapyrus/store/db/level_db.rb +5 -9
  102. data/lib/tapyrus/store/db.rb +0 -2
  103. data/lib/tapyrus/store/spv_chain.rb +11 -17
  104. data/lib/tapyrus/store.rb +1 -3
  105. data/lib/tapyrus/tx.rb +45 -37
  106. data/lib/tapyrus/tx_builder.rb +158 -0
  107. data/lib/tapyrus/tx_in.rb +1 -6
  108. data/lib/tapyrus/tx_out.rb +2 -7
  109. data/lib/tapyrus/util.rb +20 -7
  110. data/lib/tapyrus/validation.rb +12 -11
  111. data/lib/tapyrus/version.rb +1 -1
  112. data/lib/tapyrus/wallet/account.rb +22 -18
  113. data/lib/tapyrus/wallet/base.rb +12 -9
  114. data/lib/tapyrus/wallet/db.rb +6 -9
  115. data/lib/tapyrus/wallet/master_key.rb +2 -4
  116. data/lib/tapyrus.rb +8 -30
  117. data/tapyrusrb.gemspec +13 -14
  118. metadata +26 -7
  119. data/.travis.yml +0 -14
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ba1dec1b7532b15985c9233604dc63ad38b4a11e61d4bbc63d54cebdb291b3d6
4
- data.tar.gz: 3b7cb3c9e41df3693ac45b22084108b1ec682fd753a10ff95cf0d50133bff959
3
+ metadata.gz: 9cf211d0ab36f04dbc16d8ee2c60c1f86bc33b5b2d8c68378c7c550e7c0697db
4
+ data.tar.gz: 831801fc796432c6c61ee167dd6acc4778ef49853699babb95614a7765e37fd0
5
5
  SHA512:
6
- metadata.gz: f82c7815830b1eb9aba88b0247acf36cb64f9ab47802e6b05c6dc4e167503baf85fa1696bfc59fe79cd78c8866b0638b2022cb52b3c924e2db34f09c06d01370
7
- data.tar.gz: 8cdeec0c475d32f905b245f3b2a8ef9551d4ee55a1e21abe9a5b1f38b1dfe6fb317cfa85387899b5d0d5667bf19278654fee800b0b90234fa1407cd9f1703f8b
6
+ metadata.gz: 84092b5fd80adc5a7121d3923c9fa4350dde4b271b19df1ed1b39579b0589862087e9c73916650948231c4bd3f1ad9b0d58c38711bad7be2e571466f2f46b2e4
7
+ data.tar.gz: 14389a4e0df4fc5eb78c5ae9c63de6aab4a2a10fe52dcc8e655fe17fa6d6056422c6f0a9233dfc452a14f95480af7081570307124203ec1cbbbb11e77a5731ef
@@ -0,0 +1,37 @@
1
+ # This workflow uses actions that are not certified by GitHub.
2
+ # They are provided by a third-party and are governed by
3
+ # separate terms of service, privacy policy, and support
4
+ # documentation.
5
+ # This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
6
+ # For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
7
+
8
+ name: Ruby
9
+
10
+ on:
11
+ push:
12
+ branches: [master]
13
+ pull_request:
14
+ branches: [master]
15
+
16
+ jobs:
17
+ test:
18
+ runs-on: ubuntu-latest
19
+ strategy:
20
+ matrix:
21
+ ruby-version: ["2.5", "2.6", "2.7", "3.0"]
22
+
23
+ steps:
24
+ - run: sudo apt install libleveldb-dev
25
+ - uses: actions/checkout@v2
26
+ - name: Set up Ruby
27
+ # To automatically get bug fixes and new Ruby versions for ruby/setup-ruby,
28
+ # change this to (see https://github.com/ruby/setup-ruby#versioning):
29
+ # uses: ruby/setup-ruby@v1
30
+ uses: ruby/setup-ruby@473e4d8fe5dd94ee328fdfca9f8c9c7afc9dae5e
31
+ with:
32
+ ruby-version: ${{ matrix.ruby-version }}
33
+ bundler-cache: true # runs 'bundle install' and caches installed gems automatically
34
+ - name: Run prettier
35
+ run: bundle exec rbprettier --check .
36
+ - name: Run tests
37
+ run: bundle exec rake
data/.prettierignore ADDED
@@ -0,0 +1,3 @@
1
+ /vendor/
2
+ /tmp/
3
+ /spec/fixtures/**/*.json
data/.prettierrc.yaml ADDED
@@ -0,0 +1,3 @@
1
+ printWidth: 120
2
+ trailingComma: "none"
3
+ rubyArrayLiteral: false
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 2.6.3
1
+ 3.0.2
data/CODE_OF_CONDUCT.md CHANGED
@@ -12,13 +12,13 @@ body size, race, ethnicity, age, religion, or nationality.
12
12
 
13
13
  Examples of unacceptable behavior by participants include:
14
14
 
15
- * The use of sexualized language or imagery
16
- * Personal attacks
17
- * Trolling or insulting/derogatory comments
18
- * Public or private harassment
19
- * Publishing other's private information, such as physical or electronic
15
+ - The use of sexualized language or imagery
16
+ - Personal attacks
17
+ - Trolling or insulting/derogatory comments
18
+ - Public or private harassment
19
+ - Publishing other's private information, such as physical or electronic
20
20
  addresses, without explicit permission
21
- * Other unethical or unprofessional conduct
21
+ - Other unethical or unprofessional conduct
22
22
 
23
23
  Project maintainers have the right and responsibility to remove, edit, or
24
24
  reject comments, commits, code, wiki edits, issues, and other contributions
@@ -46,4 +46,4 @@ version 1.3.0, available at
46
46
  [http://contributor-covenant.org/version/1/3/0/][version]
47
47
 
48
48
  [homepage]: http://contributor-covenant.org
49
- [version]: http://contributor-covenant.org/version/1/3/0/
49
+ [version]: http://contributor-covenant.org/version/1/3/0/
data/README.md CHANGED
@@ -1,21 +1,20 @@
1
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)
2
2
 
3
-
4
3
  Tapyrusrb is a Ruby implementation of [Tapyrus](https://github.com/chaintope/tapyrus-core) Protocol.
5
4
 
6
- NOTE: Tapyrusrb work in progress, and there is a possibility of incompatible change.
5
+ NOTE: Tapyrusrb work in progress, and there is a possibility of incompatible change.
7
6
 
8
7
  ## Features
9
8
 
10
9
  Tapyrusrb supports following feature:
11
10
 
12
- * Tapyrus script interpreter
13
- * De/serialization of Tapyrus protocol network messages
14
- * De/serialization of blocks and transactions
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
- * ECDSA signature(RFC6979 -Deterministic ECDSA, LOW-S, LOW-R support)
17
- * [WIP] SPV node
18
- * [WIP] 0ff-chain protocol
11
+ - Tapyrus script interpreter
12
+ - De/serialization of Tapyrus protocol network messages
13
+ - De/serialization of blocks and transactions
14
+ - 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).
15
+ - ECDSA signature(RFC6979 -Deterministic ECDSA, LOW-S, LOW-R support)
16
+ - [WIP] SPV node
17
+ - [WIP] 0ff-chain protocol
19
18
 
20
19
  ## Requirements
21
20
 
@@ -25,13 +24,13 @@ If you use node features, please install level DB as follows.
25
24
 
26
25
  #### install LevelDB
27
26
 
28
- * for Ubuntu
27
+ - for Ubuntu
29
28
 
30
- $ sudo apt-get install libleveldb-dev
29
+ $ sudo apt-get install libleveldb-dev
31
30
 
32
- + for Mac
31
+ * for Mac
33
32
 
34
- $ brew install leveldb
33
+ $ brew install leveldb
35
34
 
36
35
  and put `leveldb-native` in your Gemfile and run bundle install.
37
36
 
@@ -65,7 +64,7 @@ And then add to your .rb file:
65
64
 
66
65
  The parameters of the blockchain are managed by `Tapyrus::ChainParams`. Switch chain parameters as follows:
67
66
 
68
- * prod
67
+ - prod
69
68
 
70
69
  ```ruby
71
70
  Tapyrus.chain_params = :prod
@@ -73,7 +72,7 @@ Tapyrus.chain_params = :prod
73
72
 
74
73
  This parameter is described in https://github.com/chaintope/tapyrusrb/blob/master/lib/tapyrus/chainparams/prod.yml.
75
74
 
76
- * dev
75
+ - dev
77
76
 
78
77
  ```ruby
79
78
  Tapyrus.chain_params = :dev
@@ -85,8 +84,6 @@ This parameter is described in https://github.com/chaintope/tapyrusrb/blob/maste
85
84
 
86
85
  Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/tapyrusrb. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
87
86
 
88
-
89
87
  ## License
90
88
 
91
89
  The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
92
-
data/Rakefile CHANGED
@@ -1,6 +1,6 @@
1
- require "bundler/gem_tasks"
2
- require "rspec/core/rake_task"
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
3
 
4
4
  RSpec::Core::RakeTask.new(:spec)
5
5
 
6
- task :default => :spec
6
+ task default: :spec
@@ -1,7 +1,5 @@
1
1
  module OpenAssets
2
-
3
2
  module MarkerOutput
4
-
5
3
  # whether this output is marker output for open assets.
6
4
  def open_assets_marker?
7
5
  return false unless script_pubkey.op_return?
@@ -14,7 +12,5 @@ module OpenAssets
14
12
  return nil unless script_pubkey.op_return?
15
13
  Payload.parse_from_payload(script_pubkey.op_return_data)
16
14
  end
17
-
18
15
  end
19
-
20
16
  end
@@ -1,13 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module OpenAssets
4
-
5
4
  MARKER = "\x4f\x41"
6
5
  VERSION = "\x01\x00"
7
6
 
8
7
  # the open assets payload
9
8
  class Payload
10
-
11
9
  attr_accessor :quantities
12
10
  attr_accessor :metadata
13
11
 
@@ -26,14 +24,12 @@ module OpenAssets
26
24
  count = Tapyrus.unpack_var_int_from_io(buf)
27
25
  return nil unless count
28
26
  quantities = []
29
- count.times do
30
- quantities << LEB128.decode_unsigned(buf, buf.pos)
31
- end
27
+ count.times { quantities << LEB128.decode_unsigned(buf, buf.pos) }
32
28
  metadata_length = Tapyrus.unpack_var_int_from_io(buf)
33
29
  return nil if metadata_length.nil? || buf.length < metadata_length + buf.pos
34
30
  metadata = buf.read(metadata_length).each_byte.map(&:chr).join
35
31
  new(quantities, metadata)
36
- rescue
32
+ rescue StandardError
37
33
  # LEB128#decode_unsigned raise 'undefined method `unpack' for nil:NilClass'
38
34
  # for invalid format such as "018f8f" (the most significant bit of the last byte should be 0)
39
35
  nil
@@ -44,11 +40,9 @@ module OpenAssets
44
40
  payload = String.new
45
41
  payload << MARKER
46
42
  payload << VERSION
47
- payload << Tapyrus.pack_var_int(quantities.size) << quantities.map{|q| LEB128.encode_unsigned(q).read }.join
48
- payload << Tapyrus.pack_var_int(metadata.length) << metadata.bytes.map{|b| sprintf("%02x", b)}.join.htb
43
+ payload << Tapyrus.pack_var_int(quantities.size) << quantities.map { |q| LEB128.encode_unsigned(q).read }.join
44
+ payload << Tapyrus.pack_var_int(metadata.length) << metadata.bytes.map { |b| sprintf('%02x', b) }.join.htb
49
45
  payload
50
46
  end
51
-
52
47
  end
53
-
54
48
  end
data/lib/openassets.rb CHANGED
@@ -1,9 +1,7 @@
1
1
  require 'leb128'
2
2
 
3
3
  module OpenAssets
4
-
5
4
  autoload :MarkerOutput, 'openassets/marker_output'
6
5
  autoload :Payload, 'openassets/payload'
7
6
  autoload :Util, 'openassets/util'
8
-
9
7
  end
@@ -0,0 +1,51 @@
1
+ module Schnorr
2
+ module SignToContract
3
+ module_function
4
+
5
+ GROUP = ECDSA::Group::Secp256k1
6
+
7
+ # Generate schnorr signature for sign-to-signature.
8
+ # @param message [String] A message to be signed with binary format.
9
+ # @param private_key [Integer] The private key.
10
+ # @param contract [String] A contract information with 32-bytes binary format.
11
+ # @return [(Schnorr::Signature, ECDSA::Point)] signature and point to prove the commitment to contract.
12
+ def sign(message, private_key, contract)
13
+ raise 'The message must be a 32-byte array.' unless message.bytesize == 32
14
+ raise 'private_key is zero or over the curve order.' if private_key == 0 || private_key >= GROUP.order
15
+ raise 'The contract must be a 32-byte binary string.' unless contract.bytesize == 32
16
+
17
+ p = GROUP.new_point(private_key)
18
+ k0 = Schnorr.deterministic_nonce(message, private_key)
19
+
20
+ k1, r = tweak(k0, contract)
21
+
22
+ q = GROUP.new_point(k1)
23
+ k = ECDSA::PrimeField.jacobi(q.y, GROUP.field.prime) == 1 ? k1 : GROUP.order - k1
24
+
25
+ e = Schnorr.create_challenge(q.x, p, message)
26
+
27
+ [Schnorr::Signature.new(q.x, (k + e * private_key) % GROUP.order), r]
28
+ end
29
+
30
+ def tweak(k, contract)
31
+ r = GROUP.new_point(k)
32
+ rx = ECDSA::Format::IntegerOctetString.encode(r.x, GROUP.byte_length)
33
+ h = Tapyrus.sha256(rx + contract)
34
+ k1 = (k + h.bth.to_i(16)) % GROUP.order
35
+ raise 'Creation of signature failed. k + h(R || c) is zero' if k1.zero?
36
+ [k1, r]
37
+ end
38
+
39
+ # Validate contract
40
+ # @param r [ECDSA::Point] point to prove the commitment.
41
+ # @param signature [Schnorr::Signature] signature.
42
+ # @param contract [String] A contract information with 32-bytes binary format.
43
+ # @return true if commitment for contract is valid, otherwise false
44
+ def valid_contract?(r, signature, contract)
45
+ rx = ECDSA::Format::IntegerOctetString.encode(r.x, GROUP.byte_length)
46
+ commitment = Tapyrus.sha256(rx + contract).bth.to_i(16) % GROUP.order
47
+ point = r + GROUP.generator.multiply_by_scalar(commitment)
48
+ signature.r == point.x
49
+ end
50
+ end
51
+ end
@@ -1,11 +1,10 @@
1
1
  module Schnorr
2
-
3
- class InvalidSignatureError < StandardError; end
2
+ class InvalidSignatureError < StandardError
3
+ end
4
4
 
5
5
  # Instances of this class represents Schnorr signatures,
6
6
  # which are simply a pair of integers named `r` and `s`.
7
7
  class Signature
8
-
9
8
  attr_reader :r
10
9
  attr_reader :s
11
10
 
@@ -32,7 +31,5 @@ module Schnorr
32
31
  def encode
33
32
  ECDSA::Format::IntegerOctetString.encode(r, 32) + ECDSA::Format::IntegerOctetString.encode(s, 32)
34
33
  end
35
-
36
34
  end
37
-
38
- end
35
+ end
data/lib/schnorr.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  module Schnorr
2
2
  autoload :Signature, 'schnorr/signature'
3
+ autoload :SignToContract, 'schnorr/sign_to_contract'
3
4
 
4
5
  module_function
5
6
 
@@ -16,12 +17,7 @@ module Schnorr
16
17
  raise 'private_key is zero or over the curve order.' if private_key == 0 || private_key >= GROUP.order
17
18
 
18
19
  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?
20
+ k0 = deterministic_nonce(message, private_key)
25
21
 
26
22
  r = GROUP.new_point(k0)
27
23
  k = ECDSA::PrimeField.jacobi(r.y, GROUP.field.prime) == 1 ? k0 : GROUP.order - k0
@@ -31,6 +27,16 @@ module Schnorr
31
27
  Schnorr::Signature.new(r.x, (k + e * private_key) % GROUP.order)
32
28
  end
33
29
 
30
+ def deterministic_nonce(message, private_key)
31
+ secret = ECDSA::Format::IntegerOctetString.encode(private_key, GROUP.byte_length)
32
+ secret = secret + message + ALGO16
33
+ nonce = Tapyrus::Secp256k1::RFC6979.generate_rfc6979_nonce(secret, '')
34
+
35
+ k0 = nonce % GROUP.order
36
+ raise 'Creation of signature failed. k is zero' if k0.zero?
37
+ k0
38
+ end
39
+
34
40
  # Verifies the given {Signature} and returns true if it is valid.
35
41
  # @param message (String) A message to be signed with binary format.
36
42
  # @param public_key (String) The public key with binary format.
@@ -76,8 +82,7 @@ module Schnorr
76
82
  # @return (Integer) digest e.
77
83
  def create_challenge(x, p, message)
78
84
  r_x = ECDSA::Format::IntegerOctetString.encode(x, GROUP.byte_length)
79
- p_str= p.to_hex.htb
85
+ p_str = p.to_hex.htb
80
86
  (ECDSA.normalize_digest(Digest::SHA256.digest(r_x + p_str + message), GROUP.bit_length)) % GROUP.order
81
87
  end
82
-
83
- end
88
+ end
@@ -1,5 +1,4 @@
1
1
  module Tapyrus
2
-
3
2
  # Base58Check encoding
4
3
  # https://en.bitcoin.it/wiki/Base58Check_encoding
5
4
  module Base58
@@ -23,16 +22,18 @@ module Tapyrus
23
22
  # decode base58 string to hex value.
24
23
  def decode(base58_val)
25
24
  int_val = 0
26
- base58_val.reverse.split(//).each_with_index do |char,index|
27
- raise ArgumentError, 'Value passed not a valid Base58 String.' if (char_index = ALPHABET.index(char)).nil?
28
- int_val += char_index * (SIZE ** index)
29
- end
25
+ base58_val
26
+ .reverse
27
+ .split(//)
28
+ .each_with_index do |char, index|
29
+ raise ArgumentError, 'Value passed not a valid Base58 String.' if (char_index = ALPHABET.index(char)).nil?
30
+ int_val += char_index * (SIZE**index)
31
+ end
30
32
  s = int_val.to_even_length_hex
31
33
  s = '' if s == '00'
32
34
  leading_zero_bytes = (base58_val.match(/^([1]+)/) ? $1 : '').size
33
35
  s = ('00' * leading_zero_bytes) + s if leading_zero_bytes > 0
34
36
  s
35
37
  end
36
-
37
38
  end
38
39
  end
@@ -0,0 +1,67 @@
1
+ module Tapyrus
2
+ # Key generation based on BIP-175
3
+ #
4
+ # @example
5
+ #
6
+ # master = Tapyrus::ExtKey.from_base58('xprv9s21ZrQH143K2JF8RafpqtKiTbsbaxEeUaMnNHsm5o6wCW3z8ySyH4UxFVSfZ8n7ESu7fgir8imbZKLYVBxFPND1pniTZ81vKfd45EHKX73')
7
+ # bip175 = Tapyrus::BIP175.from_private_key(master)
8
+ # bip175 << "foo"
9
+ # bip175 << "bar"
10
+ # bip175.addr
11
+ # > 1C7f322izqMqLzZzfzkPAjxBzprxDi47Yf
12
+ #
13
+ # @see https://github.com/bitcoin/bips/blob/master/bip-0175.mediawiki
14
+ class BIP175
15
+ PURPOSE_TYPE = 175
16
+
17
+ attr_accessor :payment_base
18
+
19
+ def initialize
20
+ @contracts = []
21
+ end
22
+
23
+ # @param key [Tapyrus::ExtKey] master private extended key
24
+ def self.from_ext_key(key)
25
+ raise ArgumentError, 'key should be Tapyrus::ExtKey' unless key.is_a?(Tapyrus::ExtKey)
26
+ raise ArgumentError, 'key should be master private extended key' unless key.master?
27
+ new.tap do |bip175|
28
+ bip175.payment_base =
29
+ key.derive(PURPOSE_TYPE, true).derive(Tapyrus.chain_params.bip44_coin_type, true).ext_pubkey
30
+ end
31
+ end
32
+
33
+ # @param key [Tapyrus::ExtPubkey] contract base public key
34
+ def self.from_ext_pubkey(key)
35
+ raise ArgumentError, 'key should be Tapyrus::ExtPubkey' unless key.is_a?(Tapyrus::ExtPubkey)
36
+ new.tap { |bip175| bip175.payment_base = key }
37
+ end
38
+
39
+ # Add value of hashed contract
40
+ # @param contract [String] contract information
41
+ def add(contract)
42
+ @contracts << Tapyrus.sha256(contract)
43
+ self
44
+ end
45
+ alias << add
46
+
47
+ # Return combined hash consist of payment_base and contract hashes
48
+ # @return [String] contract_hash
49
+ def combined_hash
50
+ hashes = @contracts.map { |c| c.bth }.sort
51
+ concatenated_hash = [payment_base.to_base58].concat(hashes).join
52
+ Tapyrus.sha256(concatenated_hash)
53
+ end
54
+
55
+ # Return pay-to-contract extended public key
56
+ # @return [Tapyrus::ExtPubkey] extended public key
57
+ def pubkey
58
+ # Split every 2 bytes
59
+ paths = combined_hash.unpack('S>*')
60
+ paths.inject(payment_base) { |key, p| key.derive(p) }
61
+ end
62
+
63
+ def addr
64
+ pubkey.addr
65
+ end
66
+ end
67
+ end
data/lib/tapyrus/block.rb CHANGED
@@ -37,6 +37,5 @@ module Tapyrus
37
37
  def height
38
38
  transactions.first.in.first.out_point.index
39
39
  end
40
-
41
40
  end
42
- end
41
+ end
@@ -1,18 +1,17 @@
1
1
  module Tapyrus
2
-
3
2
  # Block Header
4
3
  class BlockHeader
5
4
  include Tapyrus::HexConverter
6
5
  extend Tapyrus::Util
7
6
  include Tapyrus::Util
8
7
 
9
- X_FILED_TYPES = {none: 0, aggregate_pubkey: 1}
8
+ X_FILED_TYPES = { none: 0, aggregate_pubkey: 1 }
10
9
 
11
10
  attr_accessor :features
12
11
  attr_accessor :prev_hash
13
12
  attr_accessor :merkle_root
14
13
  attr_accessor :im_merkle_root # merkel root of immulable merkle tree which consist of immutable txid.
15
- attr_accessor :time # unix timestamp
14
+ attr_accessor :time # unix timestamp
16
15
  attr_accessor :x_field_type
17
16
  attr_accessor :x_field
18
17
  attr_accessor :proof
@@ -33,7 +32,16 @@ module Tapyrus
33
32
  features, prev_hash, merkle_root, im_merkle_root, time, x_filed_type = buf.read(105).unpack('Va32a32a32Vc')
34
33
  x_field = buf.read(unpack_var_int_from_io(buf)) unless x_filed_type == X_FILED_TYPES[:none]
35
34
  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)
35
+ new(
36
+ features,
37
+ prev_hash.bth,
38
+ merkle_root.bth,
39
+ im_merkle_root.bth,
40
+ time,
41
+ x_filed_type,
42
+ x_field ? x_field.bth : x_field,
43
+ proof.bth
44
+ )
37
45
  end
38
46
 
39
47
  def to_payload(skip_proof = false)
@@ -87,9 +95,9 @@ module Tapyrus
87
95
  # @return [Boolean] if valid return true, otherwise false
88
96
  def valid_x_field?
89
97
  case x_field_type
90
- when X_FILED_TYPES[:none] then
98
+ when X_FILED_TYPES[:none]
91
99
  x_field.nil?
92
- when X_FILED_TYPES[:aggregate_pubkey] then
100
+ when X_FILED_TYPES[:aggregate_pubkey]
93
101
  Tapyrus::Key.new(pubkey: x_field).fully_valid_pubkey?
94
102
  else
95
103
  false
@@ -111,7 +119,5 @@ module Tapyrus
111
119
  def size
112
120
  to_payload.bytesize
113
121
  end
114
-
115
122
  end
116
-
117
- end
123
+ end
@@ -1,4 +1,4 @@
1
- require "murmurhash3"
1
+ require 'murmurhash3'
2
2
  module Tapyrus
3
3
  class BloomFilter
4
4
  LN2_SQUARED = 0.4804530139182014246671025263266649717305529515945455 # log(2) ** 2
@@ -23,6 +23,7 @@ module Tapyrus
23
23
  # The size S of the filter in bytes is given by (-1 / pow(log(2), 2) * N * log(P)) / 8
24
24
  len = [[(-elements_length * Math.log(fp_rate) / (LN2_SQUARED * 8)).to_i, MAX_BLOOM_FILTER_SIZE].min, 1].max
25
25
  filter = Array.new(len, 0)
26
+
26
27
  # The number of hash functions required is given by S * 8 / N * log(2)
27
28
  hash_funcs = [[(filter.size * 8 * LN2 / elements_length).to_i, MAX_HASH_FUNCS].min, 1].max
28
29
  BloomFilter.new(filter, hash_funcs, tweak)
@@ -59,8 +60,9 @@ module Tapyrus
59
60
  end
60
61
 
61
62
  private
63
+
62
64
  def to_hash(data, i)
63
- MurmurHash3::V32.str_hash(data, (i * 0xfba4c795 + tweak) & 0xffffffff) % (filter.length * 8)
65
+ MurmurHash3::V32.str_hash(data, (i * 0xfba4c795 + tweak) & 0xffffffff) % (filter.length * 8)
64
66
  end
65
67
 
66
68
  def set_bit(data)
@@ -72,7 +74,7 @@ module Tapyrus
72
74
  end
73
75
 
74
76
  def full?
75
- @full |= filter.all? {|byte| byte == 0xff}
77
+ @full |= filter.all? { |byte| byte == 0xff }
76
78
  end
77
79
  end
78
80
  end
@@ -1,10 +1,8 @@
1
1
  require 'yaml'
2
2
 
3
3
  module Tapyrus
4
-
5
4
  # Network parameter class
6
5
  class ChainParams
7
-
8
6
  attr_reader :network
9
7
  attr_reader :magic_head
10
8
  attr_reader :message_magic
@@ -63,5 +61,4 @@ module Tapyrus
63
61
 
64
62
  private_class_method :init
65
63
  end
66
-
67
- end
64
+ end
@@ -1,4 +1,5 @@
1
- --- !ruby/object:Tapyrus::ChainParams
1
+ ---
2
+ !ruby/object:Tapyrus::ChainParams
2
3
  network: "dev"
3
4
  magic_head: "0b110907"
4
5
  message_magic: "Tapyrus Signed Message:\n"
@@ -26,4 +27,4 @@ target_spacing: 600 # block interval
26
27
  max_money: 21000000
27
28
  bip34_height: 227931
28
29
  dns_seeds:
29
- bip44_coin_type: 1
30
+ bip44_coin_type: 1
@@ -1,4 +1,5 @@
1
- --- !ruby/object:Tapyrus::ChainParams
1
+ ---
2
+ !ruby/object:Tapyrus::ChainParams
2
3
  network: "prod"
3
4
  magic_head: "f9beb4d9"
4
5
  message_magic: "Tapyrus Signed Message:\n"
@@ -26,4 +27,4 @@ target_spacing: 600 # block interval
26
27
  max_money: 21000000
27
28
  bip34_height: 227931
28
29
  dns_seeds:
29
- bip44_coin_type: 0
30
+ bip44_coin_type: 0