btcruby 1.0.4 → 1.0.5
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/.gitignore +2 -0
- data/README.md +12 -0
- data/RELEASE_NOTES.md +5 -0
- data/lib/btcruby/address.rb +1 -1
- data/lib/btcruby/block_header.rb +0 -2
- data/lib/btcruby/merkle_tree.rb +91 -0
- data/lib/btcruby/open_assets/asset_address.rb +2 -2
- data/lib/btcruby/open_assets/issuance_id.rb +0 -2
- data/lib/btcruby/version.rb +1 -1
- data/lib/btcruby.rb +1 -0
- data/spec/merkle_tree_spec.rb +30 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7296b8cbca8113b4795a800e581c220afdbe9b12
|
4
|
+
data.tar.gz: a318bf76d773d9f4bc4955e03bd70f0006bbaf1a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ef71f62233c862f300abe91608cdc9f100a2ccdcc91f011436f543805fdceb0d8ff795240973a898edb1939c2ceceac43c00329430a0e78914bb97fe6ca5ae94
|
7
|
+
data.tar.gz: de2350b6b17e8c3de1f9e563916bdea830ed23fb0758e49ae1ea30de9d6ae4615fe786015860c1bf707f7a18e6c290eb52695ea77dc6bc63cf34ea546052fd3c
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -52,6 +52,18 @@ $ bundle install
|
|
52
52
|
$ rake
|
53
53
|
```
|
54
54
|
|
55
|
+
## How to publish a gem
|
56
|
+
|
57
|
+
1. Edit version.rb to bump the version.
|
58
|
+
2. Update `RELEASE_NOTES.md`.
|
59
|
+
3. Commit changes and tag it with new version.
|
60
|
+
4. Generate and publish the gem:
|
61
|
+
|
62
|
+
```
|
63
|
+
$ gem build btcruby
|
64
|
+
$ gem push btcruby-<version>.gem
|
65
|
+
```
|
66
|
+
|
55
67
|
## Authors
|
56
68
|
|
57
69
|
* [Oleg Andreev](http://oleganza.com/)
|
data/RELEASE_NOTES.md
CHANGED
data/lib/btcruby/address.rb
CHANGED
data/lib/btcruby/block_header.rb
CHANGED
@@ -0,0 +1,91 @@
|
|
1
|
+
module BTC
|
2
|
+
class MerkleTree
|
3
|
+
|
4
|
+
attr_reader :merkle_root
|
5
|
+
|
6
|
+
def initialize(hashes: nil, transactions: nil, items: nil)
|
7
|
+
raise ArgumentError, "None of the arguments are used" if !transactions && !hashes && !items
|
8
|
+
if transactions
|
9
|
+
hashes = transactions.map{|tx| tx.transaction_hash}
|
10
|
+
elsif items
|
11
|
+
hashes = items.map{|item| BTC.hash256(item) }
|
12
|
+
end
|
13
|
+
raise ArgumentError, "Empty list is not allowed" if hashes.size == 0
|
14
|
+
@hashes = hashes
|
15
|
+
end
|
16
|
+
|
17
|
+
def merkle_root
|
18
|
+
@merkle_root ||= compute_merkle_root
|
19
|
+
end
|
20
|
+
|
21
|
+
def tail_duplicates?
|
22
|
+
if !@merkle_root
|
23
|
+
@merkle_root = compute_merkle_root
|
24
|
+
end
|
25
|
+
@tail_duplicates
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def compute_merkle_root
|
31
|
+
# Based on original Satoshi implementation + vulnerability detection API:
|
32
|
+
# WARNING! If you're reading this because you're learning about crypto
|
33
|
+
# and/or designing a new system that will use merkle trees, keep in mind
|
34
|
+
# that the following merkle tree algorithm has a serious flaw related to
|
35
|
+
# duplicate txids, resulting in a vulnerability (CVE-2012-2459).
|
36
|
+
#
|
37
|
+
# The reason is that if the number of hashes in the list at a given time
|
38
|
+
# is odd, the last one is duplicated before computing the next level (which
|
39
|
+
# is unusual in Merkle trees). This results in certain sequences of
|
40
|
+
# transactions leading to the same merkle root. For example, these two
|
41
|
+
# trees:
|
42
|
+
#
|
43
|
+
# A A
|
44
|
+
# / \ / \
|
45
|
+
# B C B C
|
46
|
+
# / \ | / \ / \
|
47
|
+
# D E F D E F F
|
48
|
+
# / \ / \ / \ / \ / \ / \ / \
|
49
|
+
# 1 2 3 4 5 6 1 2 3 4 5 6 5 6
|
50
|
+
#
|
51
|
+
# for transaction lists [1,2,3,4,5,6] and [1,2,3,4,5,6,5,6] (where 5 and
|
52
|
+
# 6 are repeated) result in the same root hash A (because the hash of both
|
53
|
+
# of (F) and (F,F) is C).
|
54
|
+
#
|
55
|
+
# The vulnerability results from being able to send a block with such a
|
56
|
+
# transaction list, with the same merkle root, and the same block hash as
|
57
|
+
# the original without duplication, resulting in failed validation. If the
|
58
|
+
# receiving node proceeds to mark that block as permanently invalid
|
59
|
+
# however, it will fail to accept further unmodified (and thus potentially
|
60
|
+
# valid) versions of the same block. We defend against this by detecting
|
61
|
+
# the case where we would hash two identical hashes at the end of the list
|
62
|
+
# together, and treating that identically to the block having an invalid
|
63
|
+
# merkle root. Assuming no double-SHA256 collisions, this will detect all
|
64
|
+
# known ways of changing the transactions without affecting the merkle
|
65
|
+
# root.
|
66
|
+
|
67
|
+
@tail_duplicates = false
|
68
|
+
|
69
|
+
tree = @hashes.dup
|
70
|
+
j = 0
|
71
|
+
size = tree.size
|
72
|
+
while size > 1
|
73
|
+
i = 0
|
74
|
+
while i < size
|
75
|
+
i2 = [i + 1, size - 1].min
|
76
|
+
if i2 == i + 1 && i2 + 1 == size && tree[j+i] == tree[j+i2]
|
77
|
+
# Two identical hashes at the end of the list at a particular level.
|
78
|
+
@tail_duplicates = true
|
79
|
+
end
|
80
|
+
hash = BTC.hash256(tree[j+i] + tree[j+i2])
|
81
|
+
tree << hash
|
82
|
+
i += 2
|
83
|
+
end
|
84
|
+
j += size
|
85
|
+
size = (size + 1) / 2
|
86
|
+
end
|
87
|
+
tree.last
|
88
|
+
end
|
89
|
+
|
90
|
+
end # MerkleTree
|
91
|
+
end # BTC
|
@@ -20,7 +20,7 @@ module BTC
|
|
20
20
|
if string
|
21
21
|
_raw_data ||= Base58.data_from_base58check(string)
|
22
22
|
raise FormatError, "Too short AssetAddress" if _raw_data.bytesize < 2
|
23
|
-
raise FormatError, "Invalid namespace for AssetAddress" if _raw_data.bytes[0] !=
|
23
|
+
raise FormatError, "Invalid namespace for AssetAddress" if _raw_data.bytes[0] != self.class.mainnet_version
|
24
24
|
@bitcoin_address = BTC::Address.mux_parse_raw_data(_raw_data[1..-1])
|
25
25
|
@base58check_string = string
|
26
26
|
elsif bitcoin_address
|
@@ -46,7 +46,7 @@ module BTC
|
|
46
46
|
end
|
47
47
|
|
48
48
|
def data_for_base58check_encoding
|
49
|
-
BTC::Data.data_from_bytes([
|
49
|
+
BTC::Data.data_from_bytes([self.class.mainnet_version]) + @bitcoin_address.data_for_base58check_encoding
|
50
50
|
end
|
51
51
|
end
|
52
52
|
end
|
@@ -13,8 +13,6 @@ module BTC
|
|
13
13
|
125 # 's' prefix
|
14
14
|
end
|
15
15
|
|
16
|
-
# Instantiates AssetID with output, output script or raw hash.
|
17
|
-
# To compute an Asset ID for the Asset Definition file, use `trim_script_prefix: true`.
|
18
16
|
def initialize(string: nil, hash: nil, network: nil, outpoint: nil, amount: nil, _raw_data: nil)
|
19
17
|
if outpoint || amount
|
20
18
|
raise ArgumentError, "Outpoint is missing" if !outpoint
|
data/lib/btcruby/version.rb
CHANGED
data/lib/btcruby.rb
CHANGED
@@ -34,6 +34,7 @@ require_relative 'btcruby/transaction_builder.rb'
|
|
34
34
|
require_relative 'btcruby/proof_of_work.rb'
|
35
35
|
require_relative 'btcruby/block_header.rb'
|
36
36
|
require_relative 'btcruby/block.rb'
|
37
|
+
require_relative 'btcruby/merkle_tree.rb'
|
37
38
|
require_relative 'btcruby/open_assets.rb'
|
38
39
|
|
39
40
|
# TODO:
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
describe BTC::MerkleTree do
|
3
|
+
|
4
|
+
it "should compute root of one hash equal to that hash" do
|
5
|
+
hash = "5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456"
|
6
|
+
MerkleTree.new(hashes: [hash.from_hex]).merkle_root.to_hex.must_equal hash
|
7
|
+
end
|
8
|
+
|
9
|
+
it "merkle root of 2 hashes must equal hash(a+b)" do
|
10
|
+
a = "9c2e4d8fe97d881430de4e754b4205b9c27ce96715231cffc4337340cb110280".from_hex
|
11
|
+
b = "0c08173828583fc6ecd6ecdbcca7b6939c49c242ad5107e39deb7b0a5996b903".from_hex
|
12
|
+
r = "7de236613dd3d9fa1d86054a84952f1e0df2f130546b394a4d4dd7b76997f607".from_hex
|
13
|
+
r.to_hex.must_equal BTC.hash256(a+b).to_hex
|
14
|
+
mt = MerkleTree.new(hashes: [a,b])
|
15
|
+
mt.tail_duplicates?.must_equal false
|
16
|
+
mt.merkle_root.to_hex.must_equal r.to_hex
|
17
|
+
end
|
18
|
+
|
19
|
+
it "merkle root of 3 hashes must equal Hash(Hash(a+b)+Hash(c+c))" do
|
20
|
+
a = "9c2e4d8fe97d881430de4e754b4205b9c27ce96715231cffc4337340cb110280".from_hex
|
21
|
+
b = "0c08173828583fc6ecd6ecdbcca7b6939c49c242ad5107e39deb7b0a5996b903".from_hex
|
22
|
+
c = "80903da4e6bbdf96e8ff6fc3966b0cfd355c7e860bdd1caa8e4722d9230e40ac".from_hex
|
23
|
+
r = "5b7534123197114fa7e7459075f39d89ffab74b5c3f31fad48a025b931ff5a01".from_hex
|
24
|
+
r.to_hex.must_equal BTC.hash256(BTC.hash256(a+b)+BTC.hash256(c+c)).to_hex
|
25
|
+
mt = MerkleTree.new(hashes: [a,b,c])
|
26
|
+
mt.tail_duplicates?.must_equal false
|
27
|
+
mt.merkle_root.to_hex.must_equal r.to_hex
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: btcruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Oleg Andreev
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2015-07-
|
12
|
+
date: 2015-07-08 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: ffi
|
@@ -92,6 +92,7 @@ files:
|
|
92
92
|
- lib/btcruby/hash_id.rb
|
93
93
|
- lib/btcruby/key.rb
|
94
94
|
- lib/btcruby/keychain.rb
|
95
|
+
- lib/btcruby/merkle_tree.rb
|
95
96
|
- lib/btcruby/network.rb
|
96
97
|
- lib/btcruby/opcode.rb
|
97
98
|
- lib/btcruby/open_assets.rb
|
@@ -140,6 +141,7 @@ files:
|
|
140
141
|
- spec/diagnostics_spec.rb
|
141
142
|
- spec/key_spec.rb
|
142
143
|
- spec/keychain_spec.rb
|
144
|
+
- spec/merkle_tree_spec.rb
|
143
145
|
- spec/network_spec.rb
|
144
146
|
- spec/open_assets/asset_address_spec.rb
|
145
147
|
- spec/open_assets/asset_id_spec.rb
|