tapyrus 0.2.6 → 0.2.10
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/.github/workflows/ruby.yml +37 -0
- data/.prettierignore +3 -0
- data/.prettierrc.yaml +3 -0
- data/.ruby-version +1 -1
- data/CODE_OF_CONDUCT.md +7 -7
- data/README.md +14 -17
- data/Rakefile +3 -3
- data/lib/openassets/marker_output.rb +0 -4
- data/lib/openassets/payload.rb +4 -10
- data/lib/openassets.rb +0 -2
- data/lib/schnorr/sign_to_contract.rb +51 -0
- data/lib/schnorr/signature.rb +3 -6
- data/lib/schnorr.rb +14 -9
- data/lib/tapyrus/base58.rb +7 -6
- data/lib/tapyrus/bip175.rb +67 -0
- data/lib/tapyrus/block.rb +1 -2
- data/lib/tapyrus/block_header.rb +15 -9
- data/lib/tapyrus/bloom_filter.rb +5 -3
- data/lib/tapyrus/chain_params.rb +1 -4
- data/lib/tapyrus/chainparams/dev.yml +3 -2
- data/lib/tapyrus/chainparams/prod.yml +3 -2
- data/lib/tapyrus/constants.rb +29 -23
- data/lib/tapyrus/errors.rb +1 -3
- data/lib/tapyrus/ext/ecdsa.rb +4 -4
- data/lib/tapyrus/ext/json_parser.rb +1 -4
- data/lib/tapyrus/ext.rb +1 -1
- data/lib/tapyrus/ext_key.rb +44 -32
- data/lib/tapyrus/key.rb +31 -35
- data/lib/tapyrus/key_path.rb +15 -12
- data/lib/tapyrus/logger.rb +20 -16
- data/lib/tapyrus/merkle_tree.rb +22 -20
- data/lib/tapyrus/message/addr.rb +1 -7
- data/lib/tapyrus/message/base.rb +0 -3
- data/lib/tapyrus/message/block.rb +2 -9
- data/lib/tapyrus/message/block_transaction_request.rb +3 -6
- data/lib/tapyrus/message/block_transactions.rb +2 -6
- data/lib/tapyrus/message/block_txn.rb +0 -4
- data/lib/tapyrus/message/cmpct_block.rb +1 -7
- data/lib/tapyrus/message/error.rb +1 -4
- data/lib/tapyrus/message/fee_filter.rb +1 -4
- data/lib/tapyrus/message/filter_add.rb +0 -4
- data/lib/tapyrus/message/filter_clear.rb +0 -4
- data/lib/tapyrus/message/filter_load.rb +2 -5
- data/lib/tapyrus/message/get_addr.rb +0 -4
- data/lib/tapyrus/message/get_block_txn.rb +0 -4
- data/lib/tapyrus/message/get_blocks.rb +0 -3
- data/lib/tapyrus/message/get_data.rb +1 -4
- data/lib/tapyrus/message/get_headers.rb +1 -3
- data/lib/tapyrus/message/header_and_short_ids.rb +3 -9
- data/lib/tapyrus/message/headers.rb +0 -4
- data/lib/tapyrus/message/headers_parser.rb +3 -8
- data/lib/tapyrus/message/inv.rb +1 -4
- data/lib/tapyrus/message/inventories_parser.rb +2 -7
- data/lib/tapyrus/message/inventory.rb +12 -5
- data/lib/tapyrus/message/mem_pool.rb +0 -4
- data/lib/tapyrus/message/merkle_block.rb +4 -9
- data/lib/tapyrus/message/network_addr.rb +7 -6
- data/lib/tapyrus/message/not_found.rb +0 -3
- data/lib/tapyrus/message/ping.rb +0 -3
- data/lib/tapyrus/message/pong.rb +0 -3
- data/lib/tapyrus/message/prefilled_tx.rb +0 -4
- data/lib/tapyrus/message/reject.rb +0 -3
- data/lib/tapyrus/message/send_cmpct.rb +1 -3
- data/lib/tapyrus/message/send_headers.rb +0 -3
- data/lib/tapyrus/message/tx.rb +0 -4
- data/lib/tapyrus/message/ver_ack.rb +1 -5
- data/lib/tapyrus/message/version.rb +2 -5
- data/lib/tapyrus/message.rb +14 -16
- data/lib/tapyrus/mnemonic.rb +17 -15
- data/lib/tapyrus/network/connection.rb +0 -3
- data/lib/tapyrus/network/message_handler.rb +61 -60
- data/lib/tapyrus/network/peer.rb +13 -12
- data/lib/tapyrus/network/peer_discovery.rb +10 -9
- data/lib/tapyrus/network/pool.rb +12 -12
- data/lib/tapyrus/network.rb +0 -2
- data/lib/tapyrus/node/cli.rb +12 -14
- data/lib/tapyrus/node/configuration.rb +1 -3
- data/lib/tapyrus/node/spv.rb +2 -3
- data/lib/tapyrus/node.rb +1 -1
- data/lib/tapyrus/opcodes.rb +9 -7
- data/lib/tapyrus/out_point.rb +5 -5
- data/lib/tapyrus/rpc/http_server.rb +21 -22
- data/lib/tapyrus/rpc/request_handler.rb +42 -44
- data/lib/tapyrus/rpc/tapyrus_core_client.rb +67 -25
- data/lib/tapyrus/rpc.rb +1 -0
- data/lib/tapyrus/script/color.rb +10 -0
- data/lib/tapyrus/script/multisig.rb +13 -12
- data/lib/tapyrus/script/script.rb +99 -88
- data/lib/tapyrus/script/script_error.rb +1 -4
- data/lib/tapyrus/script/script_interpreter.rb +439 -399
- data/lib/tapyrus/script/tx_checker.rb +20 -10
- data/lib/tapyrus/secp256k1/native.rb +14 -15
- data/lib/tapyrus/secp256k1/rfc6979.rb +7 -4
- data/lib/tapyrus/secp256k1/ruby.rb +10 -12
- data/lib/tapyrus/secp256k1.rb +0 -4
- data/lib/tapyrus/slip39/share.rb +41 -29
- data/lib/tapyrus/slip39/sss.rb +107 -57
- data/lib/tapyrus/slip39.rb +20 -5
- data/lib/tapyrus/store/chain_entry.rb +0 -4
- data/lib/tapyrus/store/db/level_db.rb +5 -9
- data/lib/tapyrus/store/db.rb +0 -2
- data/lib/tapyrus/store/spv_chain.rb +11 -17
- data/lib/tapyrus/store.rb +1 -3
- data/lib/tapyrus/tx.rb +45 -37
- data/lib/tapyrus/tx_builder.rb +158 -0
- data/lib/tapyrus/tx_in.rb +1 -6
- data/lib/tapyrus/tx_out.rb +2 -7
- data/lib/tapyrus/util.rb +20 -7
- data/lib/tapyrus/validation.rb +12 -11
- data/lib/tapyrus/version.rb +1 -1
- data/lib/tapyrus/wallet/account.rb +22 -18
- data/lib/tapyrus/wallet/base.rb +12 -9
- data/lib/tapyrus/wallet/db.rb +6 -9
- data/lib/tapyrus/wallet/master_key.rb +2 -4
- data/lib/tapyrus.rb +8 -30
- data/tapyrusrb.gemspec +13 -14
- metadata +26 -7
- data/.travis.yml +0 -14
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9cf211d0ab36f04dbc16d8ee2c60c1f86bc33b5b2d8c68378c7c550e7c0697db
|
|
4
|
+
data.tar.gz: 831801fc796432c6c61ee167dd6acc4778ef49853699babb95614a7765e37fd0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
data/.prettierrc.yaml
ADDED
data/.ruby-version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
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
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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
|
-
|
|
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 [](https://travis-ci.org/chaintope/tapyrusrb) [](https://badge.fury.io/rb/tapyrus) [](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
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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
|
-
|
|
27
|
+
- for Ubuntu
|
|
29
28
|
|
|
30
|
-
|
|
29
|
+
$ sudo apt-get install libleveldb-dev
|
|
31
30
|
|
|
32
|
-
|
|
31
|
+
* for Mac
|
|
33
32
|
|
|
34
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,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
|
data/lib/openassets/payload.rb
CHANGED
|
@@ -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
|
|
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(
|
|
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
|
@@ -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
|
data/lib/schnorr/signature.rb
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
module Schnorr
|
|
2
|
-
|
|
3
|
-
|
|
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
|
-
|
|
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
|
data/lib/tapyrus/base58.rb
CHANGED
|
@@ -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
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
data/lib/tapyrus/block_header.rb
CHANGED
|
@@ -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
|
|
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(
|
|
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]
|
|
98
|
+
when X_FILED_TYPES[:none]
|
|
91
99
|
x_field.nil?
|
|
92
|
-
when X_FILED_TYPES[:aggregate_pubkey]
|
|
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
|
data/lib/tapyrus/bloom_filter.rb
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
require
|
|
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)
|
|
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
|
data/lib/tapyrus/chain_params.rb
CHANGED
|
@@ -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
|
-
---
|
|
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
|
-
---
|
|
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
|