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 +4 -4
- data/README.markdown +9 -1
- data/bin/lproof +24 -5
- data/lib/liability-proof/generator.rb +3 -14
- data/lib/liability-proof/pretty_printer.rb +49 -0
- data/lib/liability-proof/tree/leaf_node.rb +6 -12
- data/lib/liability-proof/tree/node.rb +6 -2
- data/lib/liability-proof/tree.rb +36 -8
- data/lib/liability-proof/verifier.rb +17 -5
- data/lib/liability-proof/version.rb +1 -1
- data/lib/liability-proof.rb +8 -3
- metadata +18 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4797e8b0a6476b62e63295f314d67be4d6e38720
|
4
|
+
data.tar.gz: 62cae3a120745d3cd0c374ce6090f14061dbc3c8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
#
|
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:
|
13
|
-
opt.separator " verify:
|
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(
|
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(
|
8
|
-
value
|
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
|
-
|
12
|
-
self.hash =
|
10
|
+
super(user, value, nonce)
|
11
|
+
self.hash = hash || generate_hash
|
13
12
|
|
14
|
-
if
|
15
|
-
raise ArgumentError, "Hash doesn't match" if generate_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' =>
|
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
|
data/lib/liability-proof/tree.rb
CHANGED
@@ -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
|
-
@
|
18
|
-
@
|
19
|
-
|
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
|
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
|
-
|
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
|
-
|
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
|
data/lib/liability-proof.rb
CHANGED
@@ -1,8 +1,13 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'bigdecimal'
|
3
|
+
require 'awesome_print'
|
4
|
+
|
1
5
|
module LiabilityProof
|
2
6
|
|
3
|
-
autoload :Tree,
|
4
|
-
autoload :Generator,
|
5
|
-
autoload :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.
|
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-
|
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
|