zold 0.0.2 → 0.0.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: eac3eaa4c1b7deef7a78ebc9f2a2df4f1147915f
4
- data.tar.gz: 8c44a0f790e2818968ab1ddefb0a5a53e3cef554
3
+ metadata.gz: 7bb038912f96db88c1268faf5d5a30f310af4cac
4
+ data.tar.gz: 9505bbb9a1bc261b644b9f5aa81e43cbedab3aa8
5
5
  SHA512:
6
- metadata.gz: 2679e0dca7013b7e38d69f109a0bb7e227093dc53ed548e35d34e83a29092763320f4e2666a3b8c33fe87a3609f6223486719892dba01b16ffca3e6fd3debbdb
7
- data.tar.gz: 20cb11dbf878ef86fee4a49ba49d767e1d02707891940b178355be83fba162d1bcea611606c3b0429d299a393caf3a54fbbf68df33221b1e36923b95f540200d
6
+ metadata.gz: 0b222bbd35b0dd243c6f40e3143ee1c2603567f7920db1aa540d298524dd6c239e6e8f8af8834980f55c5b077cc5a8b2d847e1a51176dd25191d3f9813573de5
7
+ data.tar.gz: a7f4dc09dc1c4df5833af8d479b02c14c8befb8253c20a59a6b8f9aacf86ea39c5744f6cc5e4ad970a233d2141cb77fe53918a9296b87cf6ccc88c5c2ee13dff
data/README.md CHANGED
@@ -1,5 +1,18 @@
1
1
  <img src="http://www.zold.io/logo.svg" width="64px" height="64px"/>
2
2
 
3
+ [![Managed by Zerocracy](http://www.0crat.com/badge/C91QJT4CF.svg)](http://www.0crat.com/p/C91QJT4CF)
4
+ [![DevOps By Rultor.com](http://www.rultor.com/b/yegor256/Zold)](http://www.rultor.com/p/yegor256/Zold)
5
+ [![We recommend RubyMine](http://img.teamed.io/rubymine-recommend.svg)](https://www.jetbrains.com/ruby/)
6
+
7
+ [![Build Status](https://travis-ci.org/zerocracy/zold.svg)](https://travis-ci.org/zerocracy/zold)
8
+ [![Build status](https://ci.appveyor.com/api/projects/status/orvfo2qgmd1d7a2i?svg=true)](https://ci.appveyor.com/project/zerocracy/zold)
9
+ [![PDD status](http://www.0pdd.com/svg?name=zerocracy/zold)](http://www.0pdd.com/p?name=zerocracy/zold)
10
+ [![Gem Version](https://badge.fury.io/rb/zold.svg)](http://badge.fury.io/rb/zold)
11
+ [![Test Coverage](https://img.shields.io/codecov/c/github/zerocracy/zold.svg)](https://codecov.io/github/zerocracy/zold?branch=master)
12
+
13
+ [![Dependency Status](https://gemnasium.com/zerocracy/zold.svg)](https://gemnasium.com/zerocracy/zold)
14
+ [![Maintainability](https://api.codeclimate.com/v1/badges/7489c1d2bacde40ffc09/maintainability)](https://codeclimate.com/github/zerocracy/zold/maintainability)
15
+
3
16
  **NOTICE**: It's an experiment and a very early draft! Please, feel free to
4
17
  submit your ideas or pull requests.
5
18
 
@@ -8,123 +21,144 @@ ZOLD is a crypto currency.
8
21
  ZOLD is going to solve these problems:
9
22
 
10
23
  * Blockchain is slow and [doesn't scale](https://en.wikipedia.org/wiki/Bitcoin_scalability_problem)
11
- * Crypto mining makes strangers rich
12
- * High volatility makes cryptos suitable only for the black market
24
+ * Crypto mining makes irrelevant strangers rich
25
+ * High volatility makes cryptos suitable mostly for the black market
13
26
 
14
27
  ZOLD is:
15
28
 
16
29
  * Fast
17
30
  * Scalable
18
31
  * Anonymous
19
- * As stable as USD
20
32
 
21
33
  ZOLD principles include:
22
34
 
23
- * There is only one issuer: [Zerocracy, Inc.](http://www.zerocracy.com)
24
- * The only way to get ZOLD is to earn it (or to buy from someone)
25
- * [Zerocracy](http://www.zerocracy.com) guarantees to buy back for $1/ZOLD
26
- * No history of transactions
27
- * Consistency is guaranteed by protocols, not data
28
35
  * The entire code base is open source
36
+ * There is no mining; the only way to get ZOLD is to receive it from someone else
37
+ * Only 2<sup>63</sup> numerals (no fractions) can technically be issued
38
+ * The first wallet belongs to the issuer and may have a negative balance
39
+ * A wallet is an XML file
40
+ * There is no central ledger, each wallet has its own personal ledger
41
+ * Each transaction in the ledger is confirmed by [RSA](https://simple.wikipedia.org/wiki/RSA_%28algorithm%29) encryption
29
42
  * The network of communicating nodes maintains wallets of users
30
- * At least 16 redundant copies of each wallet must exist
31
- * Each node has a trust level, as an integer (negatives mean no trust)
32
- * Each node earns 0.16% of each transaction it processes
33
- * Nodes lose trust when the information they provide can't be proven by other nodes
34
- * The list of 16 highly trusted "backbone" nodes is hardcoded in this Git repository
35
- * The wallet no.0 belongs to [Zerocracy](http://www.zerocracy.com) and may have a negative balance
43
+ * Anyone can add a node to the network
36
44
 
37
45
  ## How to Use
38
46
 
39
- Install [Rubygems](https://rubygems.org/pages/download) and then run:
47
+ Install Ruby 2.2+, [Rubygems](https://rubygems.org/pages/download), and then run:
40
48
 
41
49
  ```bash
42
- gem install zold
50
+ $ gem install zold
43
51
  ```
44
52
 
45
53
  Then, either run it as a node:
46
54
 
47
55
  ```bash
48
- zold run
56
+ $ zold start
49
57
  ```
50
58
 
51
59
  Or do one of the following:
52
60
 
53
- * `zold create` creates a new wallet (you have to provide PGP keys)
54
- * `zold pay` sends a payment
55
- * `zold check` checks the balance of a wallet
61
+ * `zold init` creates a new wallet (you have to provide PGP keys)
62
+ * `zold pull` pulls a wallet from the network
63
+ * `zold send` creates a new transaction
64
+ * `zold push` pushes a wallet to the network
56
65
 
57
66
  For more options just run:
58
67
 
59
68
  ```bash
60
- zold --help
69
+ $ zold --help
61
70
  ```
62
71
 
63
- ## Architecture
64
-
65
- Each running node contains a list of wallets; each wallet contains:
66
-
67
- * ID: unsigned 64-bit integer
68
- * Public PGP key of the owner: 256 bytes (2048 bits)
69
- * Balance: signed 128-bit integer (in 10<sup>-12</sup>)
70
- * Version: unsigned 64-bit integer
72
+ ## Glossary
71
73
 
72
- The wallet with the largest `version` number contains the current balance.
74
+ A **node** is an HTTP server with a RESTful API, a maintainer of wallets.
73
75
 
74
- There is a [3PC](https://en.wikipedia.org/wiki/Three-phase_commit_protocol)
75
- protocol to make payments:
76
+ A **client** is a command line Ruby gem [`zold`](https://rubygems.org/gems/zold).
76
77
 
77
- 1. A node locks a place in a distributed payment queue.
78
+ A **wallet** is an XML file with a ledger of all transactions inside.
78
79
 
79
- 2. The node confirms the payment.
80
+ A **transaction** is a money transferring operation between two wallets.
80
81
 
81
- 3. Other nodes modify balances of sender's and recepient's wallets.
82
+ ## Data
82
83
 
83
- **Phase I**.
84
- Each node maintains a queue of payments, where each payment includes:
84
+ A wallet may look like this:
85
85
 
86
- * Payment ID: unsigned 32-bit integer unique for the node
87
- * Sender wallet ID and version
88
- * Recepient wallet ID and version
89
- * Processor wallet ID and version
90
- * Amount
91
- * PGP sign of the sender
92
- * List of friend IPs and their payment IDs in their queues
93
-
94
- When a lock request arrives, the node asks its most trustable "friends" (other nodes) to
95
- lock a place in their queues and then compares their responses. If the three versions
96
- they managed to lock are not exactly the same, it asks them
97
- to try to lock again. The process repeats, until all friends' replies are similar.
98
-
99
- To find the current balance of three wallets, each friend asks its friends around.
100
-
101
- **Phase II**.
102
- The node sends a confirmation request to its friends, which includes
103
- their payment IDs.
86
+ ```xml
87
+ <wallet>
88
+ <id>123456</id>
89
+ <pkey><!-- public RSA key, 256 bytes --></pkey>
90
+ <ledger>
91
+ [...]
92
+ <txn id="35">
93
+ <date>2017-07-19T21:24:51.136Z</date>
94
+ <beneficiary>927284</beneficiary>
95
+ <amount>-560</amount>
96
+ <sign><!-- RSA signature of the payer --></sign>
97
+ </txn>
98
+ </ledger>
99
+ </wallet>
100
+ ```
104
101
 
105
- **Phase III**.
106
- Each node modifies the balances in its local list of wallets and responds
107
- with a payment confirmation status. The payment gets removed from the queue.
102
+ Wallet `<id>` is an unsigned 32-bit integer.
108
103
 
109
- ## Consistency and Security
104
+ Transaction `id` is an unsigned 16-bit integer.
110
105
 
111
- The list of friends is hard-coded in the software. It includes only the
112
- nodes that are trusted by the creators of this software. The list may be
113
- extended in runtime, using the statistics of the most actively contributing
114
- nodes.
106
+ Transaction `date` is an unsigned 32-bit integer, meaning
107
+ milliseconds since
108
+ [epoch](https://en.wikipedia.org/wiki/Epoch_%28reference_date%29).
115
109
 
116
- If, at Phase I, some node doesn't synchronize its responses with other
117
- nodes in more than eight attempts, it loses its trust level.
110
+ All amounts are signed 64-bit integers, where 1ZLD by convention equals to
111
+ 2<sup>24</sup> (16,777,216). Thus, the technical capacity
112
+ of the currency is 549,755,813,888 (half a trillion).
118
113
 
119
- To avoid long-lasting locks of the queue, a payment is removed from the
120
- queue if it stays there for longer than 60 seconds.
114
+ The `<sign>` exists only in transactions with negative `amount`.
115
+ It contains an RSA signature of a data block, created by the wallet owner:
116
+ `date`, `amount`, `beneficiary` and
117
+ 64 bytes of [salt](https://en.wikipedia.org/wiki/Salt_%28cryptography%29).
121
118
 
122
- ## Concerns
119
+ The list of a few backbone nodes is hard-coded in this Git repository.
123
120
 
124
- A DoS attack to the distribution payment queue is a potential threat.
121
+ ## Architecture
125
122
 
126
- Maybe it will be necessary to pay volunteers for the nodes they
127
- keep online 24x7.
123
+ **Pull**.
124
+ The client connects to a random closest node and pulls a wallet. If the node
125
+ doesn't have the wallet, it tries to find it in the network.
126
+ Then, it calculates and prints the balance to the user.
127
+
128
+ **Commit**.
129
+ The user provides the amount and the destination wallet name. The client
130
+ finds the mediator node in the network. The client
131
+ pulls the destination wallet and adds
132
+ a new XML element `<txn>` to both wallets.
133
+
134
+ **Push**.
135
+ The client sends two wallets to the mediator, which checks
136
+ the validity of the deduction and propagates
137
+ both wallets to other nodes in a [2PC](https://en.wikipedia.org/wiki/Two-phase_commit_protocol)
138
+ manner: acknowledgment first, commit next.
139
+ If a node receives a wallet that contains transactions that are younger
140
+ than transactions in its local copy, a merge operation is
141
+ performed. If the balance after the merge is negative, the push is rejected.
142
+
143
+ **Init**.
144
+ The client creates an empty wallet XML and asks one of the backbone
145
+ nodes to generate a new `id` for it.
146
+
147
+ **Start**.
148
+ The node manifests itself to one of the backbone nodes, which
149
+ propagates the manifestation to other nodes, they propagate further.
150
+ When any node goes down, the node that detected such a situation,
151
+ notifies other nodes and they exlude the failed node from the list.
152
+
153
+ ## Corner Cases
154
+
155
+ **Too long wallet**.
156
+ If a wallet has too many transactions, its validation will take too long, since
157
+ will require many cross-wallet checks. How to solve this?
158
+
159
+ **DDoS**.
160
+ We may have too many simultaneous `push` operations to the network,
161
+ which may/will cause troubles. What to do?
128
162
 
129
163
  ## License (MIT)
130
164
 
data/bin/zold CHANGED
@@ -24,26 +24,82 @@
24
24
  STDOUT.sync = true
25
25
 
26
26
  require 'slop'
27
+ require 'rainbow'
27
28
  require_relative '../lib/zold'
28
29
  require_relative '../lib/zold/version'
30
+ require_relative '../lib/zold/wallet'
31
+ require_relative '../lib/zold/log'
32
+ require_relative '../lib/zold/key'
33
+ require_relative '../lib/zold/commands/init'
34
+ require_relative '../lib/zold/commands/send'
29
35
 
30
36
  opts = Slop.parse(ARGV, strict: true, help: true) do |o|
31
- o.banner = "Usage (#{Zold::VERSION}): zold [options] command"
37
+ o.banner = "Usage: zold [options] command [arguments]
38
+ Available commands:
39
+ #{Rainbow('init').green} [id]
40
+ Creates a new wallet with the required ID or a random one
41
+ #{Rainbow('pull').green} [id...]
42
+ Pulls all local wallets and new ones explicitly required
43
+ #{Rainbow('send').green} source target amount
44
+ Send ZOLD from one wallet to another
45
+ #{Rainbow('push').green} [id...]
46
+ Push all local wallets or the ones required
47
+ Available options:"
48
+ o.string '-d', '--dir',
49
+ 'The directory where wallets are stored (default: current directory)',
50
+ default: '.'
51
+ o.string '-p', '--private-key',
52
+ 'The location of RSA private key (default: ~/.ssh/id_rsa)',
53
+ default: '~/.ssh/id_rsa'
54
+ o.string '-u', '--public-key',
55
+ 'The location of RSA public key (default: ~/.ssh/id_rsa.pub)',
56
+ default: '~/.ssh/id_rsa.pub'
32
57
  o.bool '-h', '--help', 'Show these instructions'
33
- o.bool '-v', '--version', 'Show current version'
58
+ o.on '-v', '--version', 'Show current version' do
59
+ puts Zold::VERSION
60
+ exit
61
+ end
34
62
  end
35
63
 
36
- if opts.help?
37
- puts opts
38
- exit
39
- end
64
+ log = Zold::Log.new
40
65
 
41
- if opts.version?
42
- puts Zold::VERSION
66
+ if opts.help?
67
+ log.info(opts.to_s)
43
68
  exit
44
69
  end
45
70
 
46
71
  Encoding.default_external = Encoding::UTF_8
47
72
  Encoding.default_internal = Encoding::UTF_8
48
73
 
49
- # to be implemented...
74
+ raise 'Command is required' if opts.arguments.empty?
75
+
76
+ command = opts.arguments[0]
77
+
78
+ case command
79
+ when 'init'
80
+ id = opts.arguments[1] ? opts.arguments[1] : SecureRandom.uuid
81
+ Zold::Init.new(
82
+ wallet: Zold::Wallet.new(File.join(opts['dir'], "#{id}.xml")),
83
+ id: id,
84
+ pubkey: Zold::Key.new(opts['public-key']),
85
+ log: log
86
+ ).run
87
+ when 'send'
88
+ Zold::Send.new(
89
+ payer: Zold::Wallet.new(
90
+ File.join(opts['dir'], "#{opts.arguments[1]}.xml")
91
+ ),
92
+ receiver: Zold::Wallet.new(
93
+ File.join(opts['dir'], "#{opts.arguments[2]}.xml")
94
+ ),
95
+ amount: opts.arguments[3].to_f * 2 ** 24,
96
+ pvtkey: Zold::Key.new(opts['private-key']),
97
+ log: log
98
+ ).run
99
+ when 'pull'
100
+ raise 'PULL is not implemented yet'
101
+ when 'push'
102
+ raise 'PUSH is not implemented yet'
103
+ else
104
+ raise "Command '#{command}' is not supported"
105
+ end
data/fixtures/id_rsa ADDED
@@ -0,0 +1,51 @@
1
+ -----BEGIN RSA PRIVATE KEY-----
2
+ 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
51
+ -----END RSA PRIVATE KEY-----
@@ -0,0 +1 @@
1
+ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDXDkUZ8wM1ZimCMewg4ZDJdSl+OOjGzM8iSaqSJNCvqC+o3k+Bh8/A44V6xBXiuudu22h82SqlhlMH5ch+Nt/jUgah29PXUx5QhtAkOqJdwalrG+TB/XOYyfUpx5SpCNMO6+TkssUW8UsGQqMkR9oKfZ8PPZbgK4qWWnjl5b+gE3wuMwlV9GOWrWfifnhoA+Fb/AiD4983qQsDfkYANIFxCY9qd8LFoVu6cyYseEZxgGgPEevNbT3Pb/57S+o+tC6x822WWQPDYbFHSBOMUNyX4xGCzJa/cJDWYnnBd88Po8nlm2M84lGr2GTuJkW55H8IZrVQX3i/P9YuxDiiHMal4DivLC9Yt7WxlCRXWDAbrvkg6lECMJyaGlv8yiElAw5WcCQDLLEx9JPNVfeg3KYIC+u2oaRDrbU/+M0XAGxZj0pQ398+ne4Begr+LCgFFgKQavP53dxPup/nvC+CVqZAXA4Kk4MYJ4sajWh5YwTP8yw+CpN7N5tigvxalpgeRJytAT5QY/aa2m9Ph/H8vqOxB9Up10AqsZIjy+y0KSa6dBJtxNtq1k4Rr5IjDaDn8fZx2c7jIigNrnsloRUyWp844axefeCnEHQJ+CYMoj16523vJcd36ewRz56U3qfqDWRyn66CSZPxmKd1BhyCBYzGjV1gSOdCN7j8LT6OwGwHXQ== test@zold.io
@@ -0,0 +1,44 @@
1
+ # encoding: utf-8
2
+
3
+ # Copyright (c) 2018 Zerocracy, Inc.
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the 'Software'), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in all
13
+ # copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ # SOFTWARE.
22
+
23
+ require_relative '../log.rb'
24
+
25
+ # INIT command.
26
+ # Author:: Yegor Bugayenko (yegor256@gmail.com)
27
+ # Copyright:: Copyright (c) 2018 Zerocracy, Inc.
28
+ # License:: MIT
29
+ module Zold
30
+ # Init command
31
+ class Init
32
+ def initialize(wallet:, id:, pubkey:, log: Log.new)
33
+ @wallet = wallet
34
+ @id = id
35
+ @pubkey = pubkey
36
+ @log = log
37
+ end
38
+
39
+ def run
40
+ @wallet.init(@id, @pubkey)
41
+ @log.info("#{@wallet} initialized as #{@id}")
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,45 @@
1
+ # encoding: utf-8
2
+
3
+ # Copyright (c) 2018 Zerocracy, Inc.
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the 'Software'), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in all
13
+ # copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ # SOFTWARE.
22
+
23
+ require_relative '../log.rb'
24
+
25
+ # SEND command.
26
+ # Author:: Yegor Bugayenko (yegor256@gmail.com)
27
+ # Copyright:: Copyright (c) 2018 Zerocracy, Inc.
28
+ # License:: MIT
29
+ module Zold
30
+ # Money sending command
31
+ class Send
32
+ def initialize(payer:, receiver:, amount:, pvtkey:, log: Log.new)
33
+ @payer = payer
34
+ @receiver = receiver
35
+ @amount = amount
36
+ @pvtkey = pvtkey
37
+ @log = log
38
+ end
39
+
40
+ def run
41
+ @receiver.add(@payer.sub(@amount, @receiver.id, @pvtkey))
42
+ @log.info("#{@amount} sent from #{@payer} to #{@receiver}")
43
+ end
44
+ end
45
+ end
data/lib/zold/key.rb ADDED
@@ -0,0 +1,152 @@
1
+ # encoding: utf-8
2
+
3
+ # Copyright (c) 2018 Zerocracy, Inc.
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the 'Software'), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in all
13
+ # copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ # SOFTWARE.
22
+
23
+ require 'openssl'
24
+ require 'base64'
25
+
26
+ # The RSA key (either private or public).
27
+ # Author:: Yegor Bugayenko (yegor256@gmail.com)
28
+ # Copyright:: Copyright (c) 2018 Zerocracy, Inc.
29
+ # License:: MIT
30
+ module Zold
31
+ # A key
32
+ class Key
33
+ def initialize(file)
34
+ @file = file
35
+ end
36
+
37
+ def to_s
38
+ rsa.to_s.strip
39
+ end
40
+
41
+ def encrypt(text)
42
+ Base64.encode64(rsa.private_encrypt(text))
43
+ end
44
+
45
+ private
46
+
47
+ def rsa
48
+ raise "Can't find RSA key at #{@file}" unless File.exist?(@file)
49
+ text = File.read(File.expand_path(@file)).strip
50
+ unless text.start_with?('-----BEGIN')
51
+ text = OpenSSHKeyConverter.decode_pubkey(text.split[1])
52
+ end
53
+ OpenSSL::PKey::RSA.new(text)
54
+ end
55
+ end
56
+ end
57
+
58
+ # Stolen from: https://gist.github.com/tombh/f66de84fd3a63e670ad9
59
+ module OpenSSHKeyConverter
60
+ # The components in a openssh .pub / known_host RSA public key.
61
+ RSA_COMPONENTS = ['ssh-rsa', :e, :n].freeze
62
+ # The components in a openssh .pub / known_host DSA public key.
63
+ DSA_COMPONENTS = ['ssh-dss', :p, :q, :g, :pub_key].freeze
64
+
65
+ # Encodes a key's public part in the format found in .pub & known_hosts files.
66
+ def self.encode_pubkey(key)
67
+ case key
68
+ when OpenSSL::PKey::RSA
69
+ components = RSA_COMPONENTS
70
+ when OpenSSL::PKey::DSA
71
+ components = DSA_COMPONENTS
72
+ else
73
+ raise "Unsupported key type #{key.class.name}"
74
+ end
75
+ components.map! { |c| c.is_a?(Symbol) ? encode_mpi(key.send(c)) : c }
76
+ # ruby tries to be helpful and adds new lines every 60 bytes :(
77
+ [pack_pubkey_components(components)].pack('m').delete("\n")
78
+ end
79
+
80
+ # Decodes an openssh public key from the format of .pub & known_hosts files.
81
+ def self.decode_pubkey(string)
82
+ components = unpack_pubkey_components Base64.decode64(string)
83
+ case components.first
84
+ when RSA_COMPONENTS.first
85
+ ops = RSA_COMPONENTS.zip components
86
+ key = OpenSSL::PKey::RSA.new
87
+ when DSA_COMPONENTS.first
88
+ ops = DSA_COMPONENTS.zip components
89
+ key = OpenSSL::PKey::DSA.new
90
+ else
91
+ raise "Unsupported key type #{components.first}"
92
+ end
93
+ ops.each do |o|
94
+ next unless o.first.is_a? Symbol
95
+ key.send "#{o.first}=", decode_mpi(o.last)
96
+ end
97
+ key
98
+ end
99
+
100
+ # Loads a serialized key from an IO instance (File, StringIO).
101
+ def self.load_key(io)
102
+ key_from_string io.read
103
+ end
104
+
105
+ # Reads a serialized key from a string.
106
+ def self.key_from_string(serialized_key)
107
+ header = first_line serialized_key
108
+ if header.index 'RSA'
109
+ OpenSSL::PKey::RSA.new serialized_key
110
+ elsif header.index 'DSA'
111
+ OpenSSL::PKey::DSA.new serialized_key
112
+ else
113
+ raise 'Unknown key type'
114
+ end
115
+ end
116
+
117
+ # Extracts the first line of a string.
118
+ def self.first_line(string)
119
+ string[0, string.index(/\r|\n/) || string.len]
120
+ end
121
+
122
+ # Unpacks the string components in an openssh-encoded pubkey.
123
+ def self.unpack_pubkey_components(str)
124
+ cs = []
125
+ i = 0
126
+ while i < str.length
127
+ len = str[i, 4].unpack('N').first
128
+ cs << str[i + 4, len]
129
+ i += 4 + len
130
+ end
131
+ cs
132
+ end
133
+
134
+ # Packs string components into an openssh-encoded pubkey.
135
+ def self.pack_pubkey_components(strings)
136
+ (strings.map { |s| [s.length].pack('N') }).zip(strings).flatten.join
137
+ end
138
+
139
+ # Decodes an openssh-mpi-encoded integer.
140
+ def self.decode_mpi(mpi_str)
141
+ mpi_str.unpack('C*').inject(0) { |a, e| (a << 8) | e }
142
+ end
143
+
144
+ # Encodes an openssh-mpi-encoded integer.
145
+ def self.encode_mpi(n)
146
+ chars = []
147
+ n = n.to_i
148
+ chars << (n & 0xff) && n >>= 8 while n != 0
149
+ chars << 0 if chars.empty? || chars.last >= 0x80
150
+ chars.reverse.pack('C*')
151
+ end
152
+ end
data/lib/zold/log.rb ADDED
@@ -0,0 +1,36 @@
1
+ # encoding: utf-8
2
+
3
+ # Copyright (c) 2018 Zerocracy, Inc.
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the 'Software'), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in all
13
+ # copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ # SOFTWARE.
22
+
23
+ require 'rainbow'
24
+
25
+ # The log.
26
+ # Author:: Yegor Bugayenko (yegor256@gmail.com)
27
+ # Copyright:: Copyright (c) 2018 Zerocracy, Inc.
28
+ # License:: MIT
29
+ module Zold
30
+ # Logging
31
+ class Log
32
+ def info(msg)
33
+ puts msg
34
+ end
35
+ end
36
+ end
data/lib/zold/version.rb CHANGED
@@ -25,5 +25,5 @@
25
25
  # Copyright:: Copyright (c) 2018 Zerocracy, Inc.
26
26
  # License:: MIT
27
27
  module Zold
28
- VERSION = '0.0.2'.freeze
28
+ VERSION = '0.0.3'.freeze
29
29
  end
@@ -0,0 +1,97 @@
1
+ # encoding: utf-8
2
+
3
+ # Copyright (c) 2018 Zerocracy, Inc.
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the 'Software'), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in all
13
+ # copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ # SOFTWARE.
22
+
23
+ require 'nokogiri'
24
+ require 'time'
25
+
26
+ # The wallet.
27
+ # Author:: Yegor Bugayenko (yegor256@gmail.com)
28
+ # Copyright:: Copyright (c) 2018 Zerocracy, Inc.
29
+ # License:: MIT
30
+ module Zold
31
+ # A single wallet
32
+ class Wallet
33
+ def initialize(file)
34
+ @file = file
35
+ end
36
+
37
+ def to_s
38
+ "Z#{id}"
39
+ end
40
+
41
+ def init(id, pubkey)
42
+ File.write(
43
+ @file,
44
+ Nokogiri::XML::Builder.new do |xml|
45
+ xml.wallet do
46
+ xml.id_ id
47
+ xml.pkey pubkey.to_s
48
+ xml.ledger {}
49
+ end
50
+ end.to_xml
51
+ )
52
+ end
53
+
54
+ def id
55
+ xml.xpath('/wallet/id/text()').to_s.to_i
56
+ end
57
+
58
+ def balance
59
+ xml.xpath('/wallet/ledger/txn/amount/text()')
60
+ .map(&:to_s)
61
+ .map(&:to_i)
62
+ .inject(0) { |sum, n| sum + n }
63
+ end
64
+
65
+ def sub(amount, target, pvtkey)
66
+ txn = 1
67
+ date = Time.now.iso8601
68
+ doc = xml
69
+ t = doc.xpath('/wallet/ledger')[0].add_child('<txn/>')[0]
70
+ t['id'] = txn
71
+ t.add_child('<date/>')[0].content = date
72
+ t.add_child('<amount/>')[0].content = -amount
73
+ t.add_child('<beneficiary/>')[0].content = target
74
+ t.add_child('<sign/>')[0].content = pvtkey.encrypt(
75
+ "#{date} #{amount} #{target}"
76
+ )
77
+ File.write(@file, doc.to_s)
78
+ { id: txn, date: date, amount: amount, beneficiary: id }
79
+ end
80
+
81
+ def add(txn)
82
+ doc = xml
83
+ t = doc.xpath('/wallet/ledger')[0].add_child('<txn/>')[0]
84
+ t['id'] = "/#{txn[:id]}"
85
+ t.add_child('<date/>')[0].content = txn[:date]
86
+ t.add_child('<amount/>')[0].content = txn[:amount]
87
+ t.add_child('<beneficiary/>')[0].content = txn[:beneficiary]
88
+ File.write(@file, doc.to_s)
89
+ end
90
+
91
+ private
92
+
93
+ def xml
94
+ Nokogiri::XML(File.read(@file))
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,45 @@
1
+ # encoding: utf-8
2
+
3
+ # Copyright (c) 2018 Zerocracy, Inc.
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the 'Software'), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in all
13
+ # copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ # SOFTWARE.
22
+
23
+ require 'minitest/autorun'
24
+ require 'tmpdir'
25
+ require_relative '../../lib/zold/wallet.rb'
26
+ require_relative '../../lib/zold/key.rb'
27
+ require_relative '../../lib/zold/commands/init.rb'
28
+
29
+ # INIT test.
30
+ # Author:: Yegor Bugayenko (yegor256@gmail.com)
31
+ # Copyright:: Copyright (c) 2018 Zerocracy, Inc.
32
+ # License:: MIT
33
+ class TestInit < Minitest::Test
34
+ def test_initializes_wallet
35
+ Dir.mktmpdir 'test' do |dir|
36
+ wallet = Zold::Wallet.new(File.join(dir, 'source.xml'))
37
+ Zold::Init.new(
38
+ wallet: wallet,
39
+ id: 1,
40
+ pubkey: Zold::Key.new('fixtures/id_rsa.pub')
41
+ ).run
42
+ assert wallet.balance.zero?
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,50 @@
1
+ # encoding: utf-8
2
+
3
+ # Copyright (c) 2018 Zerocracy, Inc.
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the 'Software'), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in all
13
+ # copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ # SOFTWARE.
22
+
23
+ require 'minitest/autorun'
24
+ require 'tmpdir'
25
+ require_relative '../../lib/zold/wallet.rb'
26
+ require_relative '../../lib/zold/key.rb'
27
+ require_relative '../../lib/zold/commands/send.rb'
28
+
29
+ # SEND test.
30
+ # Author:: Yegor Bugayenko (yegor256@gmail.com)
31
+ # Copyright:: Copyright (c) 2018 Zerocracy, Inc.
32
+ # License:: MIT
33
+ class TestSend < Minitest::Test
34
+ def test_sends_from_wallet_to_wallet
35
+ Dir.mktmpdir 'test' do |dir|
36
+ source = Zold::Wallet.new(File.join(dir, 'source.xml'))
37
+ source.init(1, Zold::Key.new('fixtures/id_rsa.pub'))
38
+ target = Zold::Wallet.new(File.join(dir, 'target.xml'))
39
+ target.init(2, Zold::Key.new('fixtures/id_rsa.pub'))
40
+ Zold::Send.new(
41
+ payer: source,
42
+ receiver: target,
43
+ amount: 100,
44
+ pvtkey: Zold::Key.new('fixtures/id_rsa')
45
+ ).run
46
+ assert source.balance == -100
47
+ assert target.balance == 100
48
+ end
49
+ end
50
+ end
data/test/test_key.rb ADDED
@@ -0,0 +1,43 @@
1
+ # encoding: utf-8
2
+
3
+ # Copyright (c) 2018 Zerocracy, Inc.
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the 'Software'), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in all
13
+ # copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ # SOFTWARE.
22
+
23
+ require 'minitest/autorun'
24
+ require 'tmpdir'
25
+ require_relative '../lib/zold/key.rb'
26
+
27
+ # Key test.
28
+ # Author:: Yegor Bugayenko (yegor256@gmail.com)
29
+ # Copyright:: Copyright (c) 2018 Zerocracy, Inc.
30
+ # License:: MIT
31
+ class TestKey < Minitest::Test
32
+ def test_reads_public_rsa
33
+ key = Zold::Key.new('fixtures/id_rsa.pub')
34
+ assert key.to_s.start_with?("-----BEGIN PUBLIC KEY-----\nMIICI")
35
+ assert key.to_s.end_with?("EAAQ==\n-----END PUBLIC KEY-----")
36
+ end
37
+
38
+ def test_reads_private_rsa
39
+ key = Zold::Key.new('fixtures/id_rsa')
40
+ assert key.to_s.start_with?("-----BEGIN RSA PRIVATE KEY-----\nMIIJJ")
41
+ assert key.to_s.end_with?("Sg==\n-----END RSA PRIVATE KEY-----")
42
+ end
43
+ end
@@ -0,0 +1,43 @@
1
+ # encoding: utf-8
2
+
3
+ # Copyright (c) 2018 Zerocracy, Inc.
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the 'Software'), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in all
13
+ # copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ # SOFTWARE.
22
+
23
+ require 'minitest/autorun'
24
+ require 'tmpdir'
25
+ require_relative '../lib/zold/key.rb'
26
+ require_relative '../lib/zold/wallet.rb'
27
+
28
+ # Wallet test.
29
+ # Author:: Yegor Bugayenko (yegor256@gmail.com)
30
+ # Copyright:: Copyright (c) 2018 Zerocracy, Inc.
31
+ # License:: MIT
32
+ class TestWallet < Minitest::Test
33
+ def test_adds_transaction
34
+ Dir.mktmpdir 'test' do |dir|
35
+ file = File.join(dir, 'source.xml')
36
+ wallet = Zold::Wallet.new(file)
37
+ wallet.init(1, Zold::Key.new('fixtures/id_rsa.pub'))
38
+ amount = 123
39
+ wallet.sub(amount, 100, Zold::Key.new('fixtures/id_rsa'))
40
+ assert wallet.balance == -amount
41
+ end
42
+ end
43
+ end
data/zold.gemspec CHANGED
@@ -40,7 +40,7 @@ Gem::Specification.new do |s|
40
40
  s.description = 'Non-blockchain cryptocurrency'
41
41
  s.authors = ['Yegor Bugayenko']
42
42
  s.email = 'yegor256@gmail.com'
43
- s.homepage = 'http://github.com/yegor256/zold'
43
+ s.homepage = 'http://github.com/zerocracy/zold'
44
44
  s.files = `git ls-files`.split($RS)
45
45
  s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
46
46
  s.test_files = s.files.grep(%r{^(test|spec|features)/})
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: zold
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yegor Bugayenko
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-01-30 00:00:00.000000000 Z
11
+ date: 2018-02-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: nokogiri
@@ -193,12 +193,23 @@ files:
193
193
  - features/gem_package.feature
194
194
  - features/step_definitions/steps.rb
195
195
  - features/support/env.rb
196
+ - fixtures/id_rsa
197
+ - fixtures/id_rsa.pub
196
198
  - lib/zold.rb
199
+ - lib/zold/commands/init.rb
200
+ - lib/zold/commands/send.rb
201
+ - lib/zold/key.rb
202
+ - lib/zold/log.rb
197
203
  - lib/zold/version.rb
204
+ - lib/zold/wallet.rb
205
+ - test/commands/test_init.rb
206
+ - test/commands/test_send.rb
198
207
  - test/test__helper.rb
208
+ - test/test_key.rb
209
+ - test/test_wallet.rb
199
210
  - test/test_zold.rb
200
211
  - zold.gemspec
201
- homepage: http://github.com/yegor256/zold
212
+ homepage: http://github.com/zerocracy/zold
202
213
  licenses:
203
214
  - MIT
204
215
  metadata: {}
@@ -228,5 +239,9 @@ test_files:
228
239
  - features/gem_package.feature
229
240
  - features/step_definitions/steps.rb
230
241
  - features/support/env.rb
242
+ - test/commands/test_init.rb
243
+ - test/commands/test_send.rb
231
244
  - test/test__helper.rb
245
+ - test/test_key.rb
246
+ - test/test_wallet.rb
232
247
  - test/test_zold.rb