zold 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
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