vault-tree 0.1.0 → 0.3.3

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 (97) hide show
  1. data/.gitignore +7 -3
  2. data/CHANGE_LOG.md +15 -0
  3. data/Gemfile.lock +15 -5
  4. data/README.md +12 -15
  5. data/Rakefile +19 -4
  6. data/features/.nav +11 -0
  7. data/features/contracts/asymmetric_vault.feature +23 -0
  8. data/features/contracts/block_chain_key_transfer.feature +34 -0
  9. data/features/contracts/one_two_three.feature +22 -0
  10. data/features/contracts/readme.md +111 -0
  11. data/features/contracts_and_vaults.md +134 -0
  12. data/features/contributing_to_vault_tree.md +42 -0
  13. data/features/decision_tree.md +16 -0
  14. data/features/enforcement_problem.md +20 -0
  15. data/features/exceptions.feature +56 -5
  16. data/features/install_and_usage.md +57 -0
  17. data/features/keywords/assembled_shamir_key.feature +57 -0
  18. data/features/keywords/contents.feature +24 -0
  19. data/features/keywords/decryption_key.feature +10 -0
  20. data/features/keywords/dh_key.feature +56 -0
  21. data/features/keywords/external_data.feature +11 -0
  22. data/features/keywords/generated_shamir_key.feature +55 -0
  23. data/features/keywords/key.feature +38 -0
  24. data/features/keywords/master_passphrase.feature +68 -0
  25. data/features/keywords/public_encryption_key.feature +14 -0
  26. data/features/keywords/random_number.feature +44 -0
  27. data/features/keywords/readme.md +3 -0
  28. data/features/keywords/split_key.feature +54 -0
  29. data/features/keywords/unlocked.feature +51 -0
  30. data/features/manipulating_contracts.md +84 -0
  31. data/features/readme.md +6 -0
  32. data/features/steps/asymmetric_vault.steps.rb +41 -0
  33. data/features/steps/block_chain_key_transfer.steps.rb +43 -0
  34. data/features/steps/core.steps.rb +57 -104
  35. data/features/steps/exceptions.steps.rb +45 -1
  36. data/features/steps/one_two_three.steps.rb +57 -0
  37. data/features/steps/secret_sharing.steps.rb +36 -0
  38. data/features/support/contract_fixtures/asymmetric_vault.0.1.0.json +69 -0
  39. data/{spec/support/fixtures → features/support/contract_fixtures}/blank_simple_test_contract.json +0 -0
  40. data/features/support/contract_fixtures/block_chain_key_transfer.0.1.0.json +59 -0
  41. data/{spec/support/fixtures → features/support/contract_fixtures}/broken_contract.json +0 -0
  42. data/features/support/contract_fixtures/one_two_three.0.7.0.json +108 -0
  43. data/{spec/support/fixtures → features/support/contract_fixtures}/simple_test_contract.json +0 -0
  44. data/features/support/contract_fixtures/template.json +33 -0
  45. data/features/what_is_vault_tree.md +18 -0
  46. data/lib/vault-tree.rb +23 -6
  47. data/lib/vault-tree/contract/close_validator.rb +0 -7
  48. data/lib/vault-tree/contract/contract.rb +13 -2
  49. data/lib/vault-tree/contract/doorman.rb +22 -21
  50. data/lib/vault-tree/contract/vault.rb +18 -2
  51. data/lib/vault-tree/exceptions/exception_template.erb +0 -0
  52. data/lib/vault-tree/exceptions/failed_unlock_attempt.rb +6 -0
  53. data/lib/vault-tree/exceptions/vault_tree_exception.rb +18 -0
  54. data/lib/vault-tree/keywords/assembled_shamir_key.rb +44 -0
  55. data/lib/vault-tree/keywords/{vault_contents.rb → contents.rb} +0 -0
  56. data/lib/vault-tree/keywords/decryption_key.rb +1 -6
  57. data/lib/vault-tree/keywords/{shared_key.rb → dh_key.rb} +2 -2
  58. data/lib/vault-tree/keywords/external_data.rb +19 -0
  59. data/lib/vault-tree/keywords/generated_shamir_key.rb +57 -0
  60. data/lib/vault-tree/keywords/key.rb +13 -0
  61. data/lib/vault-tree/keywords/keyword_interpreter.rb +6 -6
  62. data/lib/vault-tree/keywords/public_encryption_key.rb +1 -5
  63. data/lib/vault-tree/keywords/random_number.rb +1 -1
  64. data/lib/vault-tree/keywords/split_key.rb +19 -0
  65. data/lib/vault-tree/keywords/unlocked.rb +1 -1
  66. data/lib/vault-tree/lock_smith.rb +182 -0
  67. data/lib/vault-tree/lock_smith/assembled_shamir_key.rb +64 -0
  68. data/lib/vault-tree/lock_smith/dh_key_pair.rb +10 -0
  69. data/lib/vault-tree/lock_smith/generated_shamir_key.rb +65 -0
  70. data/lib/vault-tree/lock_smith/split_key.rb +23 -0
  71. data/lib/vault-tree/{config/path_helpers.rb → path_helpers.rb} +26 -2
  72. data/lib/vault-tree/util/json.rb +1 -0
  73. data/lib/vault-tree/{config → util}/string.rb +1 -5
  74. data/lib/vault-tree/version.rb +1 -1
  75. data/spec/assembled_shamir_key_spec.rb +79 -0
  76. data/spec/generated_shamir_key_spec.rb +52 -0
  77. data/spec/lock_smith_spec.rb +90 -0
  78. data/spec/secret_sharing_spec.rb +43 -0
  79. data/support/scripts/libsodium_ubuntu.sh +1 -1
  80. data/vault-tree.gemspec +3 -2
  81. metadata +123 -41
  82. data/features/core.feature +0 -44
  83. data/lib/vault-tree/config/dependencies.rb +0 -4
  84. data/lib/vault-tree/config/lib.rb +0 -2
  85. data/lib/vault-tree/lock_smith/asymmetric_cipher.rb +0 -31
  86. data/lib/vault-tree/lock_smith/crypto_hash.rb +0 -11
  87. data/lib/vault-tree/lock_smith/digital_signature.rb +0 -32
  88. data/lib/vault-tree/lock_smith/encryption_key_pair.rb +0 -25
  89. data/lib/vault-tree/lock_smith/random_number.rb +0 -11
  90. data/lib/vault-tree/lock_smith/shared_key_pair.rb +0 -12
  91. data/lib/vault-tree/lock_smith/signing_key_pair.rb +0 -25
  92. data/lib/vault-tree/lock_smith/symmetric_cipher.rb +0 -25
  93. data/spec/app/locksmith/asymmetric_cipher_spec.rb +0 -25
  94. data/spec/app/locksmith/signing_key_pair_spec.rb +0 -22
  95. data/spec/spec_helper.rb +0 -5
  96. data/spec/support/fixtures/one_two_three-0.5.0.EXP.json +0 -105
  97. data/spec/support/fixtures/reference_contract.1.0.0.json +0 -227
@@ -0,0 +1,68 @@
1
+ Feature: Master Passphrase
2
+
3
+ ```javascript
4
+ "lock_with": "MASTER_PASSPHRASE",
5
+ "unlock_with": "MASTER_PASSPHRASE"
6
+ ```
7
+
8
+ The master password can be thought of as the secure password for the system that is executing the contract. It should never be shared or transfered between parties.
9
+
10
+ Vault Tree prevents this value from ever being stored within a vault. If you attempt to store the master password within a vault, an exception will be thrown.
11
+
12
+ As a best practice you should minimize the number of vaults that are locked or
13
+ unlocked with your master password. Specifically, consider randomly generating a
14
+ contract secret and then locking it with your master password. Then you can lock
15
+ other vaults with this randomly generated ephemeral secret when you want store
16
+ confidential contract data.
17
+
18
+ Scenario: Close And Open With Master Password
19
+ Given the blank contract:
20
+ """javascript
21
+ {
22
+ "header": {},
23
+ "vaults": {
24
+ "random_vault_key":{
25
+ "description":"Random Number",
26
+ "fill_with": "RANDOM_NUMBER",
27
+ "lock_with": "MASTER_PASSPHRASE",
28
+ "unlock_with": "MASTER_PASSPHRASE",
29
+ "contents": ""
30
+ },
31
+ "message":{
32
+ "description": "Simple Congratulations Message",
33
+ "fill_with": "EXTERNAL_DATA",
34
+ "lock_with": "KEY['random_vault_key']",
35
+ "unlock_with": "KEY['random_vault_key']",
36
+ "contents": ""
37
+ }
38
+ }
39
+ }
40
+ """
41
+ When I lock a message in a vault with my Master Password
42
+ Then I can recover the message with my Master Password
43
+
44
+ Scenario: Missing Passphrase
45
+ Given the blank contract:
46
+ """javascript
47
+ {
48
+ "header": {},
49
+ "vaults": {
50
+ "random_vault_key":{
51
+ "description":"Random Number",
52
+ "fill_with": "RANDOM_NUMBER",
53
+ "lock_with": "MASTER_PASSPHRASE",
54
+ "unlock_with": "MASTER_PASSPHRASE",
55
+ "contents": ""
56
+ },
57
+ "message":{
58
+ "description": "Simple Congratulations Message",
59
+ "fill_with": "EXTERNAL_DATA",
60
+ "lock_with": "KEY['random_vault_key']",
61
+ "unlock_with": "KEY['random_vault_key']",
62
+ "contents": ""
63
+ }
64
+ }
65
+ }
66
+ """
67
+ When I attempt fill a vault without providing a master passphrase
68
+ Then a MissingPassphrase exception is raised
@@ -0,0 +1,14 @@
1
+ Feature: Public Encryption Key
2
+
3
+
4
+ ```javascript
5
+ "fill_with": "PUBLIC_ENCRYPTION_KEY['decryption_key_vault_id']",
6
+ ```
7
+
8
+ Public encryption keys are derived from their corresponding private decryption key.
9
+
10
+ This Keyword takes one argument the vault ID containing the associated private
11
+ key.
12
+
13
+ Public encryption keys and private decryption keys are used to build DH Keys
14
+ to lock and unlock asymmetric vaults.
@@ -0,0 +1,44 @@
1
+ Feature: Random Number
2
+
3
+ The keyword
4
+
5
+ ```javascript
6
+ RANDOM_NUMBER
7
+ ```
8
+
9
+ behaves as expected.
10
+
11
+ When used, the Vault Tree library generates a Cryptographic Hash of a random number and places it in the designated vault.
12
+
13
+ You should use this keyword to build secure symmetric Vault keys.
14
+
15
+ Scenario: Close And Open With Random Key
16
+ Given the blank contract:
17
+ """javascript
18
+ {
19
+ "header": {
20
+ "title":"Close And Open With Random Key"
21
+ },
22
+ "vaults": {
23
+ "random_vault_key":{
24
+ "description":"Random Number",
25
+ "fill_with": "RANDOM_NUMBER",
26
+ "lock_with": "MASTER_PASSPHRASE",
27
+ "unlock_with": "MASTER_PASSPHRASE",
28
+ "contents": ""
29
+ },
30
+
31
+ "message_locked_with_random":{
32
+ "description":"A simple message locked with a random number",
33
+ "fill_with": "EXTERNAL_DATA",
34
+ "lock_with": "KEY['random_vault_key']",
35
+ "unlock_with": "KEY['random_vault_key']",
36
+ "contents": ""
37
+ }
38
+
39
+ }
40
+ }
41
+ """
42
+ When I lock away a random vault key
43
+ And I use the random key to lock a message
44
+ Then I can recover the message with the Random Key
@@ -0,0 +1,3 @@
1
+ The Vault Tree DSL provides keywords that allow you to craft the behavior of your contract in useful ways.
2
+
3
+ Keywords are expressed with all capital letters and can take **Vault Ids** as arguments.
@@ -0,0 +1,54 @@
1
+ Feature: Split Key
2
+
3
+ ```javascript
4
+ SPLIT_KEY['id_1','id_2','id_3']
5
+ ```
6
+ Split Key is a simple for of secret sharing.
7
+
8
+ Scenario: Close And Open With Split Key
9
+ Given the blank contract:
10
+ """javascript
11
+ {
12
+ "header": {},
13
+ "vaults": {
14
+ "a_consent_key":{
15
+ "fill_with": "RANDOM_NUMBER",
16
+ "lock_with": "EXTERNAL_DATA",
17
+ "unlock_with": "EXTERNAL_DATA",
18
+ "contents": ""
19
+ },
20
+
21
+ "b_consent_key":{
22
+ "fill_with": "RANDOM_NUMBER",
23
+ "lock_with": "EXTERNAL_DATA",
24
+ "unlock_with": "EXTERNAL_DATA",
25
+ "contents": ""
26
+ },
27
+
28
+ "c_consent_key":{
29
+ "fill_with": "RANDOM_NUMBER",
30
+ "lock_with": "EXTERNAL_DATA",
31
+ "unlock_with": "EXTERNAL_DATA",
32
+ "contents": ""
33
+ },
34
+
35
+ "abc_joint_consent_key":{
36
+ "fill_with": "RANDOM_NUMBER",
37
+ "lock_with": "SPLIT_KEY['a_consent_key','b_consent_key','c_consent_key']",
38
+ "unlock_with": "SPLIT_KEY['a_consent_key','b_consent_key','c_consent_key']",
39
+ "contents": ""
40
+ },
41
+
42
+ "abc_consent_message":{
43
+ "fill_with": "EXTERNAL_DATA",
44
+ "lock_with": "KEY['abc_joint_consent_key']",
45
+ "unlock_with": "KEY['abc_joint_consent_key']",
46
+ "contents": ""
47
+ }
48
+ }
49
+ }
50
+ """
51
+ And Consent keys for parties A, B, and C
52
+ When I lock a message in a vault using a split key
53
+ Then I can recover the message if each party gives consent
54
+ And I cannot recover the message if one party fails to give consent
@@ -0,0 +1,51 @@
1
+ Feature: Unlocked
2
+
3
+ ```javascript
4
+ "lock_with": "UNLOCKED",
5
+ "unlock_with": "UNLOCKED"
6
+ ```
7
+
8
+ This keyword should be used to make vault contents accessable to anyone.
9
+
10
+ When the contract interpreter reads this keyword it simply hashes the actual string _"UNLOCKED"_ and uses the resulting digest as the symmetric vault key.
11
+
12
+ Scenario: Transfer Key Via Unlocked Vault
13
+ Given the blank contract:
14
+ """javascript
15
+ {
16
+ "header": {},
17
+ "vaults": {
18
+ "random_vault_key":{
19
+ "description":"Random Number",
20
+ "fill_with": "RANDOM_NUMBER",
21
+ "lock_with": "MASTER_PASSPHRASE",
22
+ "unlock_with": "MASTER_PASSPHRASE",
23
+ "contents": ""
24
+ },
25
+ "message_locked_with_random":{
26
+ "description":"A simple message locked with a random number",
27
+ "fill_with": "EXTERNAL_DATA",
28
+ "lock_with": "KEY['random_vault_key']",
29
+ "unlock_with": "KEY['random_vault_key']",
30
+ "contents": ""
31
+ },
32
+ "unlocked_random_key":{
33
+ "description":"An unlocked random key",
34
+ "fill_with": "KEY['random_vault_key']",
35
+ "lock_with": "UNLOCKED",
36
+ "unlock_with": "UNLOCKED",
37
+ "contents": ""
38
+ },
39
+ "message_locked_with_unlocked_random_number":{
40
+ "fill_with": "CONTENTS['message_locked_with_random']",
41
+ "lock_with": "KEY['unlocked_random_key']",
42
+ "unlock_with": "KEY['unlocked_random_key']",
43
+ "contents": ""
44
+ }
45
+ }
46
+ }
47
+ """
48
+ When I lock away a random vault key
49
+ And I use the random key to lock a message
50
+ And I put this random key in an unlocked vault
51
+ Then another user can recover the message with the Unlocked Random Key
@@ -0,0 +1,84 @@
1
+ Contracts are a central part of the [Vault Tree Project]. Here is what you
2
+ need to know:
3
+
4
+ * A Vault Tree Contract is simply a [JSON] text file
5
+ * Every contract is composed of two parts:
6
+ - The **Header** section, which includes helpful meta data
7
+ - The **Vaults** section, which can be any collection of _vaults_ that form the
8
+ contract.
9
+ * The way in which you, the contract author, organize the vaults will determine the **Self-Enforcing Terms** of your contract.
10
+ * Each vault will typically contain either an **external data** string that is provided by one of the contract
11
+ participants, or a key to anther vault.
12
+
13
+ ### Writing and Simulating Contracts
14
+
15
+ If you've made it to this far, then you're ready to build some stuff. You're
16
+ thinking to yourself:
17
+
18
+ * For my Vault Tree Contract to be useful it probably needs to involve more than one person.
19
+ * I think I can write a contract, but I really need a way to test it out and think through all the different scenarios.
20
+ * When my final contract is complete it might involve network calls to pass it
21
+ between parties, queries the Bitcoin Block Chain, or some other crazy step involving the outside world.
22
+
23
+ What I really need is a way to **Simulate** how the contract will be used in real life ...
24
+
25
+ Enter [Cucumber].
26
+
27
+ [Cucumber]: https://github.com/cucumber/cucumber
28
+
29
+ Cucumber is a tool designed to test complicated full stack web applications. However, we are going to use it for a slightly different purpose.
30
+
31
+ Take a look at this simple example:
32
+
33
+ ```Gherkin
34
+ Scenario: Alice and Bob Execute the One Two Three Contract
35
+ Given Alice has the blank contract
36
+ When she locks all of her attributes
37
+ And she sends the contract to Bob
38
+ Then Bob can access all of her public attributes
39
+ When Bob locks his attributes
40
+ And He fills and locks each of the three main vaults
41
+ Then Alice can execute the contract to recover the final message
42
+ ```
43
+
44
+ Great. So we wrote down how the contract is used in some funny looking format ... so what.
45
+
46
+ Well, what if we associate each one of these steps in the scenario with some simple Ruby code that interacts with the Vault Tree API. Here are the first three step definitions:
47
+
48
+ ```Ruby
49
+ # This file: "features/core/one_two_three/one_two_three.steps.rb"
50
+ # Associated Contract: "core/one_two_three.0.7.0.json"
51
+
52
+ Given(/^Alice has the blank contract$/) do
53
+ contract_path = VaultTree::ContractsRepo::PathHelpers.core_contracts('one_two_three.0.7.0.json')
54
+ @contract_json = File.read(contract_path)
55
+ end
56
+
57
+ When(/^she locks all of her attributes$/) do
58
+ @contract = VaultTree::Contract.new(@contract_json, master_passphrase: 'ALICE_SECURE_PASS', external_data: {})
59
+ @contract = @contract.close_vault('alice_decryption_key')
60
+ @contract = @contract.close_vault('alice_public_encryption_key')
61
+ end
62
+
63
+ When(/^she sends the contract to Bob$/) do
64
+ @contract_json = @contract.as_json
65
+ @bobs_external_data = {"congratulations_message" => "CONGRATS! YOU OPENED THE THIRD VAULT."}
66
+ @contract = VaultTree::Contract.new(@contract_json, master_passphrase: 'BOB_SECURE_PASS', external_data: @bobs_external_data)
67
+ end
68
+ ```
69
+
70
+ Not only can we easily run the contract throught the library to test that it
71
+ works, we have a straight forward mechanism for simulating otherwise complicated
72
+ steps like sending the JSON representation of the contact _over the wire_.
73
+
74
+ Some items to keep in mind when you run Cucumber scenarios:
75
+
76
+ * Run `rake` instead of `cucumber` when in the VM `/vagrant` dir
77
+ * This will:
78
+ - Take care of the wierd cucumber configuration flags needed to handle the unconventional directory structure.
79
+ - Execute all cucumber scenarios associated with contracts in the `/core` directory
80
+
81
+ [JSON]: http://www.json.org
82
+ [Vault Tree Homepage]: http://www.vault-tree.org
83
+ [Vault Tree Project]: http://www.vault-tree.org
84
+
@@ -0,0 +1,6 @@
1
+ #### Vault Tree Developer Documentation
2
+
3
+ If you are coming to this page from a redirect and are unfamiliar with Vault Tree,
4
+ take a look at the [Homepage] for an overview of the project.
5
+
6
+ [Homepage]: http://vault-tree.org
@@ -0,0 +1,41 @@
1
+ Given(/^Alice has the blank asymmetric vault contract$/) do
2
+ contract_path = VaultTree::PathHelpers.core_contracts('asymmetric_vault.0.1.0.json')
3
+ @contract_json = File.read(contract_path)
4
+ end
5
+
6
+ When(/^she locks all of her public and private keys$/) do
7
+ @contract = VaultTree::Contract.new(@contract_json, master_passphrase: 'ALICE_SECURE_PASS', external_data: {})
8
+ @contract = @contract.close_vault('alice_contract_secret')
9
+ @contract = @contract.close_vault('alice_decryption_key')
10
+ @contract = @contract.close_vault('alice_public_encryption_key')
11
+ end
12
+
13
+ When(/^she sends the contract to Bob over the internet$/) do
14
+ @contract_json = @contract.as_json
15
+ @bobs_external_data = {"message" => "CONGRATS ALICE! YOU UNLOCKED THE SECRET MESSAGE WITH A DH KEY."}
16
+ @contract = VaultTree::Contract.new(@contract_json, master_passphrase: 'BOB_SECURE_PASS', external_data: @bobs_external_data)
17
+ end
18
+
19
+ Then(/^Bob can access of her public keys but not her private keys$/) do
20
+ @contents = @contract.retrieve_contents('alice_public_encryption_key')
21
+ end
22
+
23
+ When(/^Bob locks his public and private keys$/) do
24
+ @contract = @contract.close_vault('bob_decryption_key')
25
+ @contract = @contract.close_vault('bob_public_encryption_key')
26
+ end
27
+
28
+ When(/^He fills and locks the vault containing the message using a DH_KEY$/) do
29
+ @contract = @contract.close_vault('message')
30
+ end
31
+
32
+
33
+ When(/^he sends the contract back to Alice over the internet$/) do
34
+ @contract_json = @contract.as_json
35
+ @contract = VaultTree::Contract.new(@contract_json, master_passphrase: 'ALICE_SECURE_PASS', external_data: {})
36
+ end
37
+
38
+ Then(/^Alice can unlock the message with a DH_KEY$/) do
39
+ puts @contract.retrieve_contents('message')
40
+ @contract.retrieve_contents('message').should == @bobs_external_data['message']
41
+ end
@@ -0,0 +1,43 @@
1
+ Given(/^the SENDER has the blank contract template$/) do
2
+ contract_path = VaultTree::PathHelpers.core_contracts('block_chain_key_transfer.0.1.0.json')
3
+ @contract_json = File.read(contract_path)
4
+ end
5
+
6
+ Given(/^the SENDER chooses an origin address and a concealed destination address$/) do
7
+ @sender_external_data =
8
+ {
9
+ 'sender_origin_wallet_address' => '1XJEBF8EUBF855NEBHVENPFE9JE74E',
10
+ 'sender_concealed_destination_wallet_address' => '1JVKE8HD5JDHFEJHF678JEH8DEJGHE',
11
+ 'sender_btc_signing_key' => 'BITCOIN_SIGNING_KEY_KEEP_IT_SECRET'
12
+ }
13
+ @contract = VaultTree::Contract.new(@contract_json, master_passphrase: 'SENDER_SECURE_PASS', external_data: @sender_external_data)
14
+ @contract = @contract.close_vault('sender_origin_wallet_address')
15
+ @contract = @contract.close_vault('sender_concealed_destination_wallet_address')
16
+ end
17
+
18
+ Given(/^he locks away the secret BTC signing key$/) do
19
+ @contract = @contract.close_vault('sender_btc_signing_key')
20
+ end
21
+
22
+ When(/^the SENDER transfers the contract to the RECEIVER$/) do
23
+ @contract_json_over_the_wire = @contract.as_json
24
+ @contract = VaultTree::Contract.new(@contract_json_over_the_wire, master_passphrase: 'RECEIVER_SECURE_PASS')
25
+ end
26
+
27
+ Then(/^the RECEIVER can access the origin wallet address$/) do
28
+ @contract.retrieve_contents('sender_origin_wallet_address').should == @sender_external_data['sender_origin_wallet_address']
29
+ end
30
+
31
+ When(/^the SENDER reveals the hidden wallet address by transfering bitcoins from the origin address$/) do
32
+ @contract_json = @contract.as_json # save the json state
33
+ wallet_address_from_watching_blockchain = @sender_external_data['sender_concealed_destination_wallet_address']
34
+ @receiver_external_data = { 'receiver_revealed_destination_wallet_address' => wallet_address_from_watching_blockchain}
35
+ @contract = VaultTree::Contract.new(@contract_json, master_passphrase: 'RECEIVER_SECURE_PASS', external_data: @receiver_external_data)
36
+ @contract = @contract.close_vault('receiver_revealed_destination_wallet_address')
37
+ end
38
+
39
+ Then(/^the RECEIVER can unlock the vault to recover the transfered signing key$/) do
40
+ transfered_secret_key = @contract.retrieve_contents('sender_btc_signing_key')
41
+ transfered_secret_key.should == @sender_external_data['sender_btc_signing_key']
42
+ puts "PROPERLY TRANSFERED: #{transfered_secret_key} !"
43
+ end
@@ -1,105 +1,3 @@
1
- Given(/^Alice has the blank contract$/) do
2
- contract_path = VaultTree::PathHelpers.reference_contract
3
- @contract_json = File.read(contract_path)
4
- end
5
-
6
- # Change this to just attributes vice public attributes
7
- When(/^she locks all of her attributes$/) do
8
- @contract = VaultTree::Contract.new(@contract_json, master_passphrase: 'ALICE_SECURE_PASS', external_data: {})
9
- @contract = @contract.close_vault('alice_decryption_key')
10
- @contract = @contract.close_vault('alice_public_encryption_key')
11
- end
12
-
13
- When(/^she sends the contract to Bob$/) do
14
- @contract_json = @contract.as_json
15
- @bobs_external_data = {"congratulations_message" => "CONGRATS! YOU OPENED THE THIRD VAULT."}
16
- @contract = VaultTree::Contract.new(@contract_json, master_passphrase: 'BOB_SECURE_PASS', external_data: @bobs_external_data)
17
- end
18
-
19
- Then(/^Bob can access her public attributes$/) do
20
- @contents = @contract.retrieve_contents('alice_public_encryption_key')
21
- end
22
-
23
- When(/^Bob locks his attributes$/) do
24
-
25
- @contract = @contract.close_vault('bob_decryption_key')
26
- # Verify can reopen
27
- @contract.retrieve_contents('bob_decryption_key')
28
-
29
- @contract = @contract.close_vault('congratulations_message')
30
- # Verify can reopen
31
- @contract.retrieve_contents('congratulations_message')
32
-
33
- @contract = @contract.close_vault('vault_two_key')
34
- # Verify they can reopen
35
- @contract.retrieve_contents('vault_two_key')
36
-
37
- @contract = @contract.close_vault('vault_three_key')
38
- # Verify they can reopen
39
- @contract.retrieve_contents('vault_three_key')
40
-
41
- @contract = @contract.close_vault('bob_public_encryption_key')
42
- # Verify they can reopen
43
- @contract.retrieve_contents('bob_public_encryption_key')
44
- end
45
-
46
- When(/^He fills and locks each of the three vaults$/) do
47
- @contract = @contract.close_vault('first')
48
- @contract = @contract.close_vault('second')
49
- @contract = @contract.close_vault('third')
50
- end
51
-
52
- Then(/^Alice can execute the contract to recover the final message$/) do
53
- @contract_json = @contract.as_json
54
- @contract = VaultTree::Contract.new(@contract_json, master_passphrase: 'ALICE_SECURE_PASS', external_data: {})
55
- puts @contract.retrieve_contents('third')
56
- @contract.retrieve_contents('third').should == @bobs_external_data['congratulations_message']
57
- end
58
-
59
- Given(/^the SENDER has the blank BTC Key Transfer template$/) do
60
- contract_path = VaultTree::PathHelpers.reference_contract
61
- @contract_json = File.read(contract_path)
62
- end
63
-
64
- Given(/^the SENDER chooses an origin wallet address and concealed destination address$/) do
65
- @sender_external_data =
66
- {
67
- 'sender_origin_wallet_address' => '1XJEBF8EUBF855NEBHVENPFE9JE74E',
68
- 'sender_concealed_destination_wallet_address' => '1JVKE8HD5JDHFEJHF678JEH8DEJGHE',
69
- 'sender_btc_signing_key' => 'BITCOIN_SIGNING_KEY_KEEP_IT_SECRET'
70
- }
71
- @contract = VaultTree::Contract.new(@contract_json, master_passphrase: 'SENDER_SECURE_PASS', external_data: @sender_external_data)
72
- @contract = @contract.close_vault('sender_origin_wallet_address')
73
- @contract = @contract.close_vault('sender_concealed_destination_wallet_address')
74
- end
75
-
76
- Given(/^he locks away the secret BTC signing key$/) do
77
- @contract = @contract.close_vault('sender_btc_signing_key')
78
- end
79
-
80
- When(/^the SENDER transfers the Vault\-Tree contract to the RECEIVER$/) do
81
- @contract_json_over_the_wire = @contract.as_json
82
- @contract = VaultTree::Contract.new(@contract_json_over_the_wire, master_passphrase: 'RECEIVER_SECURE_PASS')
83
- end
84
-
85
- Then(/^the RECEIVER can access the origin wallet address$/) do
86
- @contract.retrieve_contents('sender_origin_wallet_address').should == @sender_external_data['sender_origin_wallet_address']
87
- end
88
-
89
- When(/^the SENDER reveals the hidden wallet address by Blockchain payment from the origin address$/) do
90
- @contract_json = @contract.as_json # save the json state
91
- wallet_address_from_watching_blockchain = @sender_external_data['sender_concealed_destination_wallet_address']
92
- @receiver_external_data = { 'receiver_revealed_destination_wallet_address' => wallet_address_from_watching_blockchain}
93
- @contract = VaultTree::Contract.new(@contract_json, master_passphrase: 'RECEIVER_SECURE_PASS', external_data: @receiver_external_data)
94
- @contract = @contract.close_vault('receiver_revealed_destination_wallet_address')
95
- end
96
-
97
- Then(/^the RECEIVER can unlock the vault to recover the transfered signing key$/) do
98
- transfered_secret_key = @contract.retrieve_contents('sender_btc_signing_key')
99
- transfered_secret_key.should == @sender_external_data['sender_btc_signing_key']
100
- puts "PROPERLY TRANSFERED: #{transfered_secret_key} !"
101
- end
102
-
103
1
  Given(/^I have a blank reference contract$/) do
104
2
  contract_path = VaultTree::PathHelpers.reference_contract
105
3
  @contract_json = File.read(contract_path)
@@ -151,7 +49,7 @@ Given(/^I have access to the another user's unlocked public key$/) do
151
49
  @contract = @contract.close_vault('my_public_key')
152
50
  end
153
51
 
154
- Given(/^I lock a simple message with a shared key$/) do
52
+ Given(/^I lock a simple message with a DH Key$/) do
155
53
  @contract_json = @contract.as_json
156
54
  @external_data = {"asymmetric_message" => "CONGRATS! YOU OPENED THE ASYMMETRIC VAULT."}
157
55
  @contract = VaultTree::Contract.new(@contract_json, master_passphrase: 'MY_SECURE_PASS', external_data: @external_data)
@@ -163,6 +61,61 @@ When(/^I transfer the contract to the other user$/) do
163
61
  @contract = VaultTree::Contract.new(@contract_json, master_passphrase: 'ANOTHER_USERS_SECURE_PASS')
164
62
  end
165
63
 
166
- Then(/^they can create a shared key and unlock the message$/) do
64
+ Then(/^they can create a DH Key and unlock the message$/) do
167
65
  @contract.retrieve_contents('asymmetric_message').should == @external_data['asymmetric_message']
168
66
  end
67
+
68
+ Given(/^Consent keys for parties A, B, and C$/) do
69
+ @locking_consent_keys = {
70
+ "a_consent_key" => "A_SECRET_CONSENT_KEY",
71
+ "b_consent_key" => "B_SECRET_CONSENT_KEY",
72
+ "c_consent_key" => "C_SECRET_CONSENT_KEY"
73
+ }
74
+ end
75
+
76
+ When(/^I lock a message in a vault using a split key$/) do
77
+ @message = {"abc_consent_message" => "A, B, AND C ALL AGREED TO OPEN THE VAULT." }
78
+ @external_data = @locking_consent_keys.merge(@message)
79
+ @contract = VaultTree::Contract.new(@contract_json, external_data: @external_data)
80
+ @contract = @contract.close_vault('a_consent_key')
81
+ @contract = @contract.close_vault('b_consent_key')
82
+ @contract = @contract.close_vault('c_consent_key')
83
+ @contract = @contract.close_vault('abc_joint_consent_key')
84
+ @contract = @contract.close_vault('abc_consent_message')
85
+ @contract_json = @contract.as_json
86
+ end
87
+
88
+ Then(/^I can recover the message if each party gives consent$/) do
89
+ @unlocking_consent_keys = {
90
+ "a_consent_key" => "A_SECRET_CONSENT_KEY",
91
+ "b_consent_key" => "B_SECRET_CONSENT_KEY",
92
+ "c_consent_key" => "C_SECRET_CONSENT_KEY"
93
+ }
94
+ @contract = VaultTree::Contract.new(@contract_json, external_data: @unlocking_consent_keys)
95
+ @contract.retrieve_contents('abc_consent_message').should == @external_data['abc_consent_message']
96
+ puts @contract.retrieve_contents('abc_consent_message')
97
+ end
98
+
99
+ Then(/^I cannot recover the message if one party fails to give consent$/) do
100
+ @incomplete_unlocking_consent_keys = {
101
+ "a_consent_key" => "A_WRONG_SECRET_CONSENT_KEY",
102
+ "b_consent_key" => "B_SECRET_CONSENT_KEY",
103
+ "c_consent_key" => "C_SECRET_CONSENT_KEY"
104
+ }
105
+ @contract = VaultTree::Contract.new(@contract_json, external_data: @incomplete_unlocking_consent_keys)
106
+ expect{@contract.retrieve_contents('abc_consent_message')}.to raise_error(VaultTree::Exceptions::FailedUnlockAttempt)
107
+ end
108
+
109
+ Given(/^the blank contract:$/) do |string|
110
+ @contract_json = string
111
+ end
112
+
113
+ When(/^I lock a message in a vault using a symmetric vault key$/) do
114
+ @external_data = {"message" => "CONGRATS! YOU OPENED THE VAULT."}
115
+ @contract = VaultTree::Contract.new(@contract_json, master_passphrase: 'MY_SECURE_PASS', external_data: @external_data)
116
+ @contract = @contract.close_vault('message')
117
+ end
118
+
119
+ Then(/^I can recover the message using the same key$/) do
120
+ @contract.retrieve_contents('message').should == @external_data['message']
121
+ end