liability-proof 0.0.3 → 0.0.4

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: 977147c8250bb363215bad2fd155bc13aec6269f
4
- data.tar.gz: c84794a53390071cb9800bf692eff4c0e2bf2b0d
3
+ metadata.gz: 4797e8b0a6476b62e63295f314d67be4d6e38720
4
+ data.tar.gz: 62cae3a120745d3cd0c374ce6090f14061dbc3c8
5
5
  SHA512:
6
- metadata.gz: 662738943559c4e770f91d11de77a39af291418c775b8a0b7a774aa710bf5d51e3f5a60e26a887c4486676c815df9eb1615314391ce65e2d82861eac84dbae89
7
- data.tar.gz: e5e98a75e127860b41ed67cc102a8bc370c0ffdea3b6960daf59b9599ea346e7e5fec3311307d8ec2a7d6a9683949f6ea64f9d0a3104bb75f1cfd19035e2f395
6
+ metadata.gz: b2377f8e93174f8ada47fa7bc3a4eac28c6d657253e4726de973011a7bb3bb74e5c2cd78ee9c78ca764506d2e8c9f4de5f8d604abb9928ba28c77b766eb6da11
7
+ data.tar.gz: fc588a9d2eb4c957c18c85d9fc754460f068f635eec771787eb860bd21f4ff5a88d6c86e8f83f4bec8c7e2d6bba789accfd431bd061fde2c66999f5812d6a042
data/README.markdown CHANGED
@@ -21,10 +21,18 @@ As command line tool:
21
21
  # https://github.com/olalonde/blind-liability-proof#serialized-data-formats-work-in-progress--draft
22
22
  lproof generate -f accounts.json
23
23
 
24
- # verify specified partial tree is valid, i.e. the root node calculated from
24
+ # Use -F switch to save numbers as Float instead of String. Save numbers as
25
+ # String preserve precision well, but some other verification tools doesn't
26
+ # work well with it, so -F is provided for compatibility only.
27
+ lproof generate -f accounts.json -F
28
+
29
+ # Verify specified partial tree is valid, i.e. the root node calculated from
25
30
  # from the partial tree matches the root node in root.json
26
31
  lproof verify -r root.json -f partial_trees/jan.json
27
32
 
33
+ # Pretty print a partial tree or any other json file
34
+ lproof pp -f partial_trees/jan.json
35
+
28
36
  As library: check `LiabilityProof::Generator` and `LiabilityProof::Verifier` for example.
29
37
 
30
38
  ### License ###
data/bin/lproof CHANGED
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
+ $:.unshift File.expand_path('../../lib', __FILE__)
3
4
  require 'liability-proof'
4
5
  require 'optparse'
5
6
 
@@ -9,12 +10,13 @@ opt_parser = OptionParser.new do |opt|
9
10
  opt.banner = "Usage: #{$0} COMMAND [OPTIONS]"
10
11
  opt.separator ""
11
12
  opt.separator "Commands"
12
- opt.separator " generate: generate json of root node and partial trees"
13
- opt.separator " verify: verify specified partial tree is valid (matches root node)"
13
+ opt.separator " generate (g): generate json of root node and partial trees"
14
+ opt.separator " verify (v): verify specified partial tree is valid (matches root node)"
15
+ opt.separator " prettyprint (pp): pretty print generated json"
14
16
  opt.separator ""
15
17
  opt.separator "Options"
16
18
 
17
- opt.on("-f", "--file source.json", "Specify source file. For generate command, it should contain accounts data; for verify command, it should contain the partial tree.") do |f|
19
+ opt.on("-f", "--file source.json", "Specify source file. For generate command, it should contain accounts data; for verify command, it should contain the partial tree; for prettyprint command it specify the json to print.") do |f|
18
20
  options[:file] = f
19
21
  end
20
22
 
@@ -26,15 +28,32 @@ opt_parser = OptionParser.new do |opt|
26
28
  opt.on("--partial-trees-dir DIR", "Specify the directory to store generated partial tree json files, default to 'partial_trees'.") do |d|
27
29
  options[:partial_trees_dir] = d
28
30
  end
31
+
32
+ options[:use_float] = false
33
+ opt.on("-F", "--use-float", "Print numbers as Float number instead of String in json files. This option is only provided to generating data in compatible format with some verification tools, don't use it unless neccessary. Default to false.") do |f|
34
+ options[:use_float] = true
35
+ end
36
+
37
+ options[:float_nonce] = false
38
+ opt.on("--float-nonce", "Use float number as nonce. This option is only provided for compatibility with some verification tools. Default to false.") do |f|
39
+ options[:float_nonce] = true
40
+ end
41
+
42
+ opt.on("-b", "--blp-format", "Generate json in blind-liability-proof format. Default to false.") do |f|
43
+ options[:use_float] = true
44
+ options[:float_nonce] = true
45
+ end
29
46
  end
30
47
 
31
48
  opt_parser.parse!
32
49
 
33
50
  case ARGV[0]
34
- when 'generate'
51
+ when 'generate', 'g'
35
52
  LiabilityProof::Generator.new(options).write!
36
- when 'verify'
53
+ when 'verify', 'v'
37
54
  LiabilityProof::Verifier.new(options).verify!
55
+ when 'prettyprint', 'pp'
56
+ LiabilityProof::PrettyPrinter.new(options).print
38
57
  else
39
58
  puts opt_parser
40
59
  end
@@ -1,4 +1,3 @@
1
- require 'json'
2
1
  require 'fileutils'
3
2
 
4
3
  module LiabilityProof
@@ -12,17 +11,7 @@ module LiabilityProof
12
11
  FileUtils.mkdir @partial_trees_dir unless File.exists?(@partial_trees_dir)
13
12
 
14
13
  accounts = JSON.parse File.read(@accounts_path)
15
- @tree = LiabilityProof::Tree.new accounts
16
- end
17
-
18
- def root_json
19
- { 'root' => {
20
- 'hash' => @tree.root.hash,
21
- 'value' => @tree.root.value_string }}
22
- end
23
-
24
- def partial_tree_json(user)
25
- { 'partial_tree' => @tree.partial(user) }
14
+ @tree = LiabilityProof::Tree.new accounts, options
26
15
  end
27
16
 
28
17
  def write!
@@ -34,13 +23,13 @@ module LiabilityProof
34
23
 
35
24
  def write_root_json
36
25
  File.open(@root_path, 'w') do |f|
37
- f.write JSON.dump(root_json)
26
+ f.write JSON.dump(@tree.root_json)
38
27
  end
39
28
  end
40
29
 
41
30
  def write_partial_tree(user)
42
31
  File.open(File.join(@partial_trees_dir, "#{user}.json"), 'w') do |f|
43
- f.write JSON.dump(partial_tree_json(user))
32
+ f.write JSON.dump(@tree.partial_json(user))
44
33
  end
45
34
  end
46
35
 
@@ -0,0 +1,49 @@
1
+ module LiabilityProof
2
+ class PrettyPrinter
3
+
4
+ def initialize(options)
5
+ @json_path = options.delete(:file)
6
+ raise ArgumentError, "file to print unspecified" unless @json_path
7
+
8
+ @json = JSON.parse File.read(@json_path)
9
+ end
10
+
11
+ def print
12
+ if Hash === @json && @json.keys.first == 'partial_tree'
13
+ print_tree @json['partial_tree']
14
+ else
15
+ ap @json
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ def print_tree(node, depth=0)
22
+ print_node node, depth
23
+
24
+ if node.has_key?('left') && node.has_key?('right')
25
+ print_tree node['left'], depth+1
26
+ print_tree node['right'], depth+1
27
+ else # leaf
28
+ end
29
+ end
30
+
31
+ def print_node(node, depth)
32
+ tab = " |"*depth + "_ "
33
+ text = lable node
34
+ puts "#{tab}#{text}"
35
+ end
36
+
37
+ def lable(node)
38
+ if data = node['data']
39
+ if data['user']
40
+ "#{data['user']}, #{data['nonce']}, #{data['value']}"
41
+ else
42
+ "#{data['value']}, #{data['hash']}"
43
+ end
44
+ else
45
+ ''
46
+ end
47
+ end
48
+ end
49
+ end
@@ -4,25 +4,19 @@ module LiabilityProof
4
4
  class LeafNode < Struct.new(:user, :value, :nonce, :hash)
5
5
  include ::LiabilityProof::Tree::Node
6
6
 
7
- def initialize(account)
8
- value = BigDecimal.new(account['value'] || account['balance'])
9
- super(account['user'], value)
7
+ def initialize(user, value, nonce, hash=nil)
8
+ raise ArgumentError, "value must be BigDecimal" unless value.is_a?(BigDecimal)
10
9
 
11
- self.nonce = account['nonce'] || generate_nonce
12
- self.hash = account['hash'] || generate_hash
10
+ super(user, value, nonce)
11
+ self.hash = hash || generate_hash
13
12
 
14
- if account['user'] && account['hash'] && account['nonce']
15
- raise ArgumentError, "Hash doesn't match" if generate_hash != account['hash']
13
+ if user && hash && nonce
14
+ raise ArgumentError, "Hash doesn't match" if generate_hash != hash
16
15
  end
17
16
  end
18
17
 
19
18
  private
20
19
 
21
- # a 16 bytes random string encoded in 32 hex digits
22
- def generate_nonce
23
- OpenSSL::Random.random_bytes(16).unpack("H*").first
24
- end
25
-
26
20
  # a sha256 hash encoded in 64 hex digits
27
21
  def generate_hash
28
22
  LiabilityProof.sha256_base64 "#{user}|#{value_string}|#{nonce}"
@@ -3,14 +3,18 @@ module LiabilityProof
3
3
 
4
4
  module Node
5
5
 
6
- def as_json
7
- { 'value' => value_string, 'hash' => hash }
6
+ def as_json(use_float=false)
7
+ { 'value' => formatted_value(use_float), 'hash' => hash }
8
8
  end
9
9
 
10
10
  def value_string
11
11
  value.to_s('F')
12
12
  end
13
13
 
14
+ def formatted_value(use_float)
15
+ use_float ? value.to_f : value_string
16
+ end
17
+
14
18
  end
15
19
 
16
20
  end
@@ -1,5 +1,4 @@
1
1
  require 'base64'
2
- require 'bigdecimal'
3
2
  require 'openssl'
4
3
 
5
4
  module LiabilityProof
@@ -11,12 +10,21 @@ module LiabilityProof
11
10
 
12
11
  attr :root, :indices
13
12
 
14
- def initialize(accounts)
13
+ def initialize(accounts, options={})
15
14
  raise ArgumentError, 'accounts is empty' unless accounts && accounts.size > 0
16
15
 
17
- @accounts = accounts
18
- @root = generate
19
- @indices = Hash[index_leaves(@root)]
16
+ @use_float = options.delete(:use_float)
17
+ @float_nonce = options.delete(:float_nonce)
18
+
19
+ @accounts = accounts
20
+ @root = generate
21
+ @indices = Hash[index_leaves(@root)]
22
+ end
23
+
24
+ def root_json
25
+ { 'root' => {
26
+ 'hash' => root.hash,
27
+ 'value' => root.formatted_value(@use_float) }}
20
28
  end
21
29
 
22
30
  def partial(user)
@@ -25,11 +33,15 @@ module LiabilityProof
25
33
  h
26
34
  end
27
35
 
36
+ def partial_json(user)
37
+ { 'partial_tree' => partial(user) }
38
+ end
39
+
28
40
  private
29
41
 
30
42
  def _partial(user, node, index, acc)
31
43
  if node.is_a?(LeafNode)
32
- acc['data'] = node.as_json
44
+ acc['data'] = node.as_json(@use_float)
33
45
 
34
46
  if node.user == user
35
47
  acc['data'].merge!({
@@ -43,17 +55,33 @@ module LiabilityProof
43
55
  follow_child = node.send follow_direction
44
56
  other_child = node.send other_direction
45
57
 
46
- acc[other_direction.to_s] = { 'data' => other_child.as_json }
58
+ acc[other_direction.to_s] = { 'data' => other_child.as_json(@use_float) }
47
59
  acc[follow_direction.to_s] = { 'data' => nil }
48
60
  _partial user, follow_child, index, acc[follow_direction.to_s]
49
61
  end
50
62
  end
51
63
 
52
64
  def generate
53
- leaves = @accounts.map {|a| LeafNode.new(a) }
65
+ leaves = @accounts.map do |a|
66
+ user = a['user']
67
+ value = ::BigDecimal.new a['balance']
68
+ nonce = a['nonce'] || generate_nonce
69
+ LeafNode.new(user, value, nonce)
70
+ end
71
+
54
72
  combine leaves
55
73
  end
56
74
 
75
+ def generate_nonce
76
+ if @float_nonce
77
+ # a float number like 0.123456789, for compatibility with blp
78
+ rand
79
+ else
80
+ # a 16 bytes random string encoded in 32 hex digits
81
+ OpenSSL::Random.random_bytes(16).unpack("H*").first
82
+ end
83
+ end
84
+
57
85
  def combine(nodes)
58
86
  return nodes.first if nodes.size <= 1
59
87
 
@@ -1,5 +1,3 @@
1
- require 'json'
2
-
3
1
  module LiabilityProof
4
2
  class Verifier
5
3
 
@@ -22,7 +20,11 @@ module LiabilityProof
22
20
 
23
21
  def match?
24
22
  partial_tree = partial_tree_json['partial_tree']
25
- reduce(partial_tree).as_json == expect_root
23
+
24
+ use_float = expect_root['value'].is_a?(Float)
25
+ @reduced_root = reduce(partial_tree).as_json(use_float)
26
+
27
+ @reduced_root == expect_root
26
28
  end
27
29
 
28
30
  def verify!
@@ -31,18 +33,28 @@ module LiabilityProof
31
33
  puts "User: #{@user_node.user}"
32
34
  puts "Balance: #{@user_node.value_string}"
33
35
  else
34
- raise "Mismatch! Expected root: #{expect_root.inspect}"
36
+ raise "Mismatch! Expected root: #{expect_root.inspect}, calculated root: #{@reduced_root.inspect}"
35
37
  end
36
38
  rescue
37
39
  puts "INVALID partial tree!"
38
40
  puts "ERROR: #{$!}"
41
+ puts "Expected root:"
42
+ ap expect_root
43
+ if @reduced_root
44
+ puts "Calculated root:"
45
+ ap @reduced_root
46
+ end
39
47
  end
40
48
 
41
49
  private
42
50
 
43
51
  def reduce(node)
44
52
  if node['data']
45
- leaf = Tree::LeafNode.new node['data']
53
+ user = node['data']['user']
54
+ value = ::BigDecimal.new node['data']['value'].to_s
55
+ nonce = node['data']['nonce']
56
+ hash = node['data']['hash']
57
+ leaf = Tree::LeafNode.new user, value, nonce, hash
46
58
  @user_node = leaf if leaf.user
47
59
  leaf
48
60
  else
@@ -1,3 +1,3 @@
1
1
  module LiabilityProof
2
- VERSION = '0.0.3'
2
+ VERSION = '0.0.4'
3
3
  end
@@ -1,8 +1,13 @@
1
+ require 'json'
2
+ require 'bigdecimal'
3
+ require 'awesome_print'
4
+
1
5
  module LiabilityProof
2
6
 
3
- autoload :Tree, 'liability-proof/tree'
4
- autoload :Generator, 'liability-proof/generator'
5
- autoload :Verifier, 'liability-proof/verifier'
7
+ autoload :Tree, 'liability-proof/tree'
8
+ autoload :Generator, 'liability-proof/generator'
9
+ autoload :Verifier, 'liability-proof/verifier'
10
+ autoload :PrettyPrinter, 'liability-proof/pretty_printer'
6
11
 
7
12
  module_function
8
13
 
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: liability-proof
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peatio Opensource
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-03-17 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2014-03-18 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: awesome_print
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
13
27
  description: Check https://iwilcox.me.uk/2014/proving-bitcoin-reserves for more details.
14
28
  email:
15
29
  - community@peatio.com
@@ -22,6 +36,7 @@ files:
22
36
  - bin/lproof
23
37
  - lib/liability-proof.rb
24
38
  - lib/liability-proof/generator.rb
39
+ - lib/liability-proof/pretty_printer.rb
25
40
  - lib/liability-proof/tree.rb
26
41
  - lib/liability-proof/tree/interior_node.rb
27
42
  - lib/liability-proof/tree/leaf_node.rb