contracthashtool 0.0.1 → 0.0.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5ea9a50c8b3de136a68cb441d43095480f5a56a6
4
- data.tar.gz: 4d4289f4a76d6798e9915c4a0f4f845c57539e4f
3
+ metadata.gz: 08284e65956a5805962806d2f4ba2748d792655c
4
+ data.tar.gz: 9a2aa606c96675f60d95ef93329256526ec098cc
5
5
  SHA512:
6
- metadata.gz: cd2dd769fb0e97861e4af5cc90ee490663ed43d982b4a1892b751b8babee6b6eed7ed4a39a364ecc50a066d431217df89410f1c563d8c929c639f6d22d23b415
7
- data.tar.gz: b55a653977efabc2c6dbc92ab1fff871943bf1ca2450aef613938214c96996764ce8520de51c0ed696a174ea977288ad73536a66e3d0330c3b41122c09a42aef
6
+ metadata.gz: c330b0fb70042dc4c010e07ce86b21304cb6418fab35f2f096990b051c83ec1c89f05bb895193e2caf765588f97702bb8a9388ed13b6435177bcb08d7195323a
7
+ data.tar.gz: 615298ef744d2d9dd860e73d9375307cc86ba4cece7eaf8d7eb649076fbf5778851a69b060f94f7962809e2348b5302e77255e6d5fba1d587ab663a7c6c69dfa
data/README.md CHANGED
@@ -1,6 +1,8 @@
1
- # Contracthashtool
1
+ # contracthashtool-ruby
2
2
 
3
- Ruby port of https://github.com/Blockstream/contracthashtool
3
+ Ruby port of: https://github.com/Blockstream/contracthashtool
4
+
5
+ See also Appendix A of: https://blockstream.com/sidechains.pdf
4
6
 
5
7
  ## Installation
6
8
 
@@ -26,22 +28,52 @@ require 'bitcoin'
26
28
 
27
29
  Bitcoin.network = :testnet3
28
30
 
29
- r = '5121038695b28f1649c711aedb1fec8df54874334cfb7ddf31ba3132a94d00bdc9715251ae'
30
- p = 'cMcpaCT6pHkyS4347i4rSmecaQtLiu1eH28NWmBiePn8bi6N4kzh'
31
- a = 'mqWkEAFeQdrQvyaWNRn5vijPJeiQAjtxL2'
32
- n = '3a11be476485a6273fad4a0e09117d42'
31
+ # Example parameters from the original tool's usage().
32
+
33
+ redeem_script_template = '5121038695b28f1649c711aedb1fec8df54874334cfb7ddf31ba3132a94d00bdc9715251ae'
34
+ payee_address = 'mqWkEAFeQdrQvyaWNRn5vijPJeiQAjtxL2'
35
+ nonce_hex = '3a11be476485a6273fad4a0e09117d42'
36
+ private_key_wif = 'cMcpaCT6pHkyS4347i4rSmecaQtLiu1eH28NWmBiePn8bi6N4kzh'
37
+
38
+ # Someone wanting to send funds to the sidechain would call this
39
+ # to calculate a P2SH address to send to. They would then send the
40
+ # MDFs (mutually distrusting functionaries) the target address
41
+ # and nonce so they are able to locate the subsequent transaction.
42
+ # The caller would then send the desired amount of coin to the P2SH
43
+ # address to initiate the peg protocol.
44
+
45
+ nonce, redeem_script, p2sh_address =
46
+ Contracthashtool.generate(redeem_script_template, payee_address, nonce_hex)
47
+
48
+ puts "nonce: #{nonce}"
49
+ puts "P2SH address: #{p2sh_address}"
50
+ puts "new redeem script: #{redeem_script}"
51
+
52
+ # Each MDF would call this to derive a private key to redeem the
53
+ # cross-chain seed transaction after the confirmation period lapses.
54
+ # They would then presumably create and sign a transaction on the
55
+ # sidechain paying the desired amount of sidecoin to the target address.
56
+ # And then we've succeeded in executing one direction of a federated peg.
57
+ # Rinse, wash, and repeat to go back.
58
+
59
+ key = Contracthashtool.claim(private_key_wif, payee_address, nonce)
60
+ puts "new privkey: #{key.to_base58}"
33
61
 
34
- nonce, p2sh_address = Contracthashtool.generate(r,a,n)
35
- puts "nonce: #{nonce}, address: #{p2sh_address}"
62
+ # Verify homomorphic derivation was successful.
36
63
 
37
- key = Contracthashtool.claim(p,a,n)
38
- puts "new privkey: #{key.to_base58}
64
+ signature = key.sign_message("derp")
65
+ script = Bitcoin::Script.new([redeem_script].pack("H*"))
66
+ pubkey = Bitcoin::Key.new(nil, script.get_multisig_pubkeys.first.unpack("H*").first)
67
+ raise "nope" unless pubkey.verify_message(signature, "derp")
39
68
  ```
40
69
 
41
- ## Contributing
70
+ <pre>
71
+ <code>
72
+ $ bundle exec ruby test.rb
73
+ nonce: 3a11be476485a6273fad4a0e09117d42
74
+ P2SH address: 2MvGPFfDXbJZyH79u187VNZbuCgyRBhcdsw
75
+ new redeem script: 512102944aba05d40d8df1724f8ab2f5f3a58d052d26aedc93e175534cb782becc8ff751ae
76
+ new privkey: cSBD8yM62R82RfbugiGK8Lui9gdMB81NtZBckxe5YxRsDSKySwHK
77
+ </code>
78
+ </pre>
42
79
 
43
- 1. Fork it ( https://github.com/[my-github-username]/contracthashtool/fork )
44
- 2. Create your feature branch (`git checkout -b my-new-feature`)
45
- 3. Commit your changes (`git commit -am 'Add some feature'`)
46
- 4. Push to the branch (`git push origin my-new-feature`)
47
- 5. Create a new Pull Request
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
10
10
  spec.email = ["andy.alness@gmail.com"]
11
11
  spec.summary = %q{Ruby port of contracthashtool}
12
12
  spec.description = %q{Ruby port of Blockstream's contracthashtool for federated peg support}
13
- spec.homepage = ""
13
+ spec.homepage = "https://github.com/aalness/contracthashtool-ruby"
14
14
  spec.license = "MIT"
15
15
 
16
16
  spec.files = `git ls-files -z`.split("\x0")
@@ -21,6 +21,6 @@ Gem::Specification.new do |spec|
21
21
  spec.add_development_dependency "bundler", "~> 1.7"
22
22
  spec.add_development_dependency "rake", "~> 10.0"
23
23
 
24
- spec.add_dependency "bitcoin-ruby"
25
- spec.add_dependency "ffi"
24
+ spec.add_dependency "bitcoin-ruby", "~> 0.0", ">= 0.0.6"
25
+ spec.add_dependency "ffi", "~> 1.9"
26
26
  end
@@ -6,13 +6,13 @@ require "ffi"
6
6
  module Contracthashtool
7
7
 
8
8
  # generate a contract address
9
- def self.generate(redeem_script_hex, payee_address, nonce_hex=nil)
9
+ def self.generate(redeem_script_hex, payee_address_or_ascii, nonce_hex=nil)
10
10
  redeem_script = Bitcoin::Script.new([redeem_script_hex].pack("H*"))
11
11
  raise "only multisig redeem scripts are currently supported" unless redeem_script.is_multisig?
12
- nonce_hex, data = compute_data(payee_address, nonce_hex)
12
+ nonce_hex, data = compute_data(payee_address_or_ascii, nonce_hex)
13
13
 
14
14
  derived_keys = []
15
- group = OpenSSL::PKey::EC::Group.new('secp256k1')
15
+ group = OpenSSL::PKey::EC::Group.new("secp256k1")
16
16
  redeem_script.get_multisig_pubkeys.each do |pubkey|
17
17
  tweak = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new("SHA256"), pubkey, data).to_i(16)
18
18
  raise "order exceeded, pick a new nonce" if tweak >= group.order
@@ -26,19 +26,19 @@ module Contracthashtool
26
26
  end
27
27
 
28
28
  m = redeem_script.get_signatures_required
29
- p2sh_script = Bitcoin::Script.to_p2sh_multisig_script(m, *derived_keys)[0]
29
+ p2sh_script, redeem_script = Bitcoin::Script.to_p2sh_multisig_script(m, *derived_keys)
30
30
 
31
- [ nonce_hex, Bitcoin::Script.new(p2sh_script).get_p2sh_address ]
31
+ [ nonce_hex, redeem_script.unpack("H*")[0], Bitcoin::Script.new(p2sh_script).get_p2sh_address ]
32
32
  end
33
33
 
34
34
  # claim a contract
35
- def self.claim(private_key_wif, payee_address, nonce_hex)
35
+ def self.claim(private_key_wif, payee_address_or_ascii, nonce_hex)
36
36
  key = Bitcoin::Key.from_base58(private_key_wif)
37
- data = compute_data(payee_address, nonce_hex)[1]
37
+ data = compute_data(payee_address_or_ascii, nonce_hex)[1]
38
38
 
39
39
  pubkey = [key.pub].pack("H*")
40
40
  tweak = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new("SHA256"), pubkey, data).to_i(16)
41
- group = OpenSSL::PKey::EC::Group.new('secp256k1')
41
+ group = OpenSSL::PKey::EC::Group.new("secp256k1")
42
42
  raise "order exceeded, verify parameters" if tweak >= group.order
43
43
 
44
44
  derived_key = (tweak + key.priv.to_i(16)) % group.order
@@ -46,25 +46,30 @@ module Contracthashtool
46
46
  end
47
47
 
48
48
  # compute HMAC data
49
- def self.compute_data(address, nonce_hex)
49
+ def self.compute_data(address_or_ascii, nonce_hex)
50
50
  nonce = nonce_hex ? [nonce_hex].pack("H32") : SecureRandom.random_bytes(16)
51
- hash160 = [Bitcoin.hash160_from_address(address)].pack("H*")
52
- address_type = Bitcoin.address_type(address)
53
- case address_type
54
- when :hash160
55
- address_type = "P2PH"
56
- when :p2sh
57
- address_type = "P2SH"
51
+ if Bitcoin.valid_address?(address_or_ascii)
52
+ address_type = Bitcoin.address_type(address_or_ascii)
53
+ case address_type
54
+ when :hash160
55
+ address_type = "P2PH"
56
+ when :p2sh
57
+ address_type = "P2SH"
58
+ else
59
+ raise "unsupported address type #{address_type}"
60
+ end
61
+ contract_bytes = [Bitcoin.hash160_from_address(address_or_ascii)].pack("H*")
58
62
  else
59
- raise "unsuppoorted address type #{address_type}"
63
+ address_type = "TEXT"
64
+ contract_bytes = address_or_ascii
60
65
  end
61
- [ nonce.unpack("H*")[0], address_type + nonce + hash160 ]
66
+ [ nonce.unpack("H*")[0], address_type + nonce + contract_bytes ]
62
67
  end
63
68
 
64
69
  # lifted from https://github.com/GemHQ/money-tree
65
70
  module EC_ADD
66
71
  extend ::FFI::Library
67
- ffi_lib 'ssl'
72
+ ffi_lib "ssl"
68
73
 
69
74
  NID_secp256k1 = 714
70
75
  POINT_CONVERSION_COMPRESSED = 2
@@ -1,3 +1,3 @@
1
1
  module Contracthashtool
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: contracthashtool
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andy Alness
@@ -42,30 +42,36 @@ dependencies:
42
42
  name: bitcoin-ruby
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.0'
45
48
  - - ">="
46
49
  - !ruby/object:Gem::Version
47
- version: '0'
50
+ version: 0.0.6
48
51
  type: :runtime
49
52
  prerelease: false
50
53
  version_requirements: !ruby/object:Gem::Requirement
51
54
  requirements:
55
+ - - "~>"
56
+ - !ruby/object:Gem::Version
57
+ version: '0.0'
52
58
  - - ">="
53
59
  - !ruby/object:Gem::Version
54
- version: '0'
60
+ version: 0.0.6
55
61
  - !ruby/object:Gem::Dependency
56
62
  name: ffi
57
63
  requirement: !ruby/object:Gem::Requirement
58
64
  requirements:
59
- - - ">="
65
+ - - "~>"
60
66
  - !ruby/object:Gem::Version
61
- version: '0'
67
+ version: '1.9'
62
68
  type: :runtime
63
69
  prerelease: false
64
70
  version_requirements: !ruby/object:Gem::Requirement
65
71
  requirements:
66
- - - ">="
72
+ - - "~>"
67
73
  - !ruby/object:Gem::Version
68
- version: '0'
74
+ version: '1.9'
69
75
  description: Ruby port of Blockstream's contracthashtool for federated peg support
70
76
  email:
71
77
  - andy.alness@gmail.com
@@ -81,7 +87,7 @@ files:
81
87
  - contracthashtool.gemspec
82
88
  - lib/contracthashtool.rb
83
89
  - lib/contracthashtool/version.rb
84
- homepage: ''
90
+ homepage: https://github.com/aalness/contracthashtool-ruby
85
91
  licenses:
86
92
  - MIT
87
93
  metadata: {}