mssmt 0.2.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/mssmt/branch_node.rb +12 -2
- data/lib/mssmt/computed_node.rb +25 -0
- data/lib/mssmt/leaf_node.rb +4 -0
- data/lib/mssmt/proof.rb +59 -2
- data/lib/mssmt/tree.rb +2 -0
- data/lib/mssmt/version.rb +1 -1
- data/lib/mssmt.rb +5 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d07e68431e9d8539727c514f6bbe42006709b980214d6fdeaca0cb6fb0613d5d
|
4
|
+
data.tar.gz: 76da8e23b8b45119ab20fc875657688dd26dd2b24a8dc82f7704162c6ae61a24
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3dc973a5f83f8399af0b617a34db243464d15878e27fe1b748ba576622c7a7d7e28e5ac736efef4d0e4a4e53231525aad6a8d4e99d3b1b6f732948dc72a8dc3c
|
7
|
+
data.tar.gz: 482b24550810aa7c070b0b51845088094d17d4afca4a1ae60677c58be3fecf89eaf88651b3795eca268a05f08b7d265602ee6fb6c699a06a1bf80d8bb450c659
|
data/lib/mssmt/branch_node.rb
CHANGED
@@ -5,6 +5,10 @@ module MSSMT
|
|
5
5
|
class BranchNode
|
6
6
|
attr_reader :left, :right, :node_hash, :sum
|
7
7
|
|
8
|
+
# Constructor
|
9
|
+
# @param [MSSMT::LeafNode|MSSMT::BranchNode] left
|
10
|
+
# @param [MSSMT::LeafNode|MSSMT::BranchNode] right
|
11
|
+
# @raise [MSSMT::OverflowError]
|
8
12
|
def initialize(left, right)
|
9
13
|
if !left.is_a?(BranchNode) && !left.is_a?(LeafNode)
|
10
14
|
raise ArgumentError, "left must be a branch or leaf node"
|
@@ -16,15 +20,21 @@ module MSSMT
|
|
16
20
|
@left = left
|
17
21
|
@right = right
|
18
22
|
@sum = left.sum + right.sum
|
23
|
+
if @sum > Tree::MAX_SUM_VALUE
|
24
|
+
raise OverflowError, "sum: #{sum} is overflow"
|
25
|
+
end
|
26
|
+
|
19
27
|
@node_hash =
|
20
28
|
Digest::SHA256.digest(
|
21
29
|
"#{left.node_hash}#{right.node_hash}#{[@sum].pack("Q>")}"
|
22
30
|
)
|
23
31
|
end
|
24
32
|
|
33
|
+
# Check whether same branch|computed node or not.
|
34
|
+
# @return [Boolean]
|
25
35
|
def ==(other)
|
26
|
-
return false unless
|
27
|
-
node_hash == other.node_hash
|
36
|
+
return false unless [BranchNode, ComputedNode].include?(other.class)
|
37
|
+
node_hash == other.node_hash && sum == other.sum
|
28
38
|
end
|
29
39
|
end
|
30
40
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MSSMT
|
4
|
+
# Node within a MS-SMT that has already had its node_hash and sum computed, i.e., its preimage is not available.
|
5
|
+
class ComputedNode
|
6
|
+
attr_reader :node_hash, :sum
|
7
|
+
|
8
|
+
# Constructor
|
9
|
+
# @param [String] node_hash node hash with binary format.
|
10
|
+
# @param [Integer] sum
|
11
|
+
# @raise [MSSMT::OverflowError]
|
12
|
+
def initialize(node_hash, sum)
|
13
|
+
@node_hash = node_hash
|
14
|
+
if sum > Tree::MAX_SUM_VALUE
|
15
|
+
raise OverflowError, "sum: #{sum} is overflow"
|
16
|
+
end
|
17
|
+
@sum = sum
|
18
|
+
end
|
19
|
+
|
20
|
+
def ==(other)
|
21
|
+
return false unless [BranchNode, ComputedNode].include?(other.class)
|
22
|
+
node_hash == other.node_hash && sum == other.sum
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/mssmt/leaf_node.rb
CHANGED
@@ -8,8 +8,12 @@ module MSSMT
|
|
8
8
|
# Constructor
|
9
9
|
# @param [String] value node value with binary format.
|
10
10
|
# @param [Integer] sum integer value associated with the value
|
11
|
+
# @raise [MSSMT::OverflowError]
|
11
12
|
def initialize(value, sum)
|
12
13
|
@value = value
|
14
|
+
if sum > Tree::MAX_SUM_VALUE
|
15
|
+
raise OverflowError, "sum: #{sum} is overflow"
|
16
|
+
end
|
13
17
|
@sum = sum
|
14
18
|
end
|
15
19
|
|
data/lib/mssmt/proof.rb
CHANGED
@@ -17,8 +17,7 @@ module MSSMT
|
|
17
17
|
bits = Array.new(nodes.length, false)
|
18
18
|
compact_nodes = []
|
19
19
|
nodes.each.each_with_index do |node, i|
|
20
|
-
|
21
|
-
if node.node_hash == Tree.empty_tree[Tree::MAX_LEVEL - 1].node_hash
|
20
|
+
if node.node_hash == Tree.empty_tree[Tree::MAX_LEVEL - i].node_hash
|
22
21
|
bits[i] = true
|
23
22
|
else
|
24
23
|
compact_nodes << node
|
@@ -49,6 +48,21 @@ module MSSMT
|
|
49
48
|
@bits = bits
|
50
49
|
end
|
51
50
|
|
51
|
+
# Decode compressed proof.
|
52
|
+
# @param [String] compressed proof with binary fomat.
|
53
|
+
# @return [MSSMT::CompressedProof]
|
54
|
+
def self.decode(data)
|
55
|
+
buf = data.is_a?(StringIO) ? data : StringIO.new(data)
|
56
|
+
nodes_len = buf.read(2).unpack1("n")
|
57
|
+
nodes =
|
58
|
+
nodes_len.times.map do
|
59
|
+
ComputedNode.new(buf.read(32), buf.read(8).unpack1("Q>"))
|
60
|
+
end
|
61
|
+
bytes = buf.read(MSSMT::Tree::MAX_LEVEL / 8)
|
62
|
+
bits = unpack_bits(bytes.unpack("C*"))
|
63
|
+
CompressedProof.new(nodes, bits)
|
64
|
+
end
|
65
|
+
|
52
66
|
# Decompress a compressed merkle proof by replacing its bit vector with the empty nodes it represents.
|
53
67
|
# @return [MSSMT::Proof]
|
54
68
|
def decompress
|
@@ -64,5 +78,48 @@ module MSSMT
|
|
64
78
|
end
|
65
79
|
Proof.new(full_nodes)
|
66
80
|
end
|
81
|
+
|
82
|
+
# Encode the compressed proof.
|
83
|
+
# @return [String] encoded string.
|
84
|
+
def encode
|
85
|
+
buf = [nodes.length].pack("n")
|
86
|
+
nodes.each do |node|
|
87
|
+
buf << node.node_hash
|
88
|
+
buf << [node.sum].pack("Q>")
|
89
|
+
end
|
90
|
+
buf << pack_bits.pack("C*")
|
91
|
+
buf
|
92
|
+
end
|
93
|
+
|
94
|
+
def ==(other)
|
95
|
+
return false unless other.is_a?(CompressedProof)
|
96
|
+
bits == other.bits && nodes == other.nodes
|
97
|
+
end
|
98
|
+
|
99
|
+
private
|
100
|
+
|
101
|
+
def pack_bits
|
102
|
+
bytes = Array.new((bits.length + 8 - 1) / 8, 0)
|
103
|
+
bits.each_with_index do |b, i|
|
104
|
+
next unless b
|
105
|
+
byte_index = i / 8
|
106
|
+
bit_index = i % 8
|
107
|
+
bytes[byte_index] |= (1 << bit_index)
|
108
|
+
end
|
109
|
+
bytes
|
110
|
+
end
|
111
|
+
|
112
|
+
def self.unpack_bits(bytes)
|
113
|
+
bit_len = bytes.length * 8
|
114
|
+
bits = Array.new(bit_len, false)
|
115
|
+
bit_len.times do |i|
|
116
|
+
byte_index = i / 8
|
117
|
+
bit_index = i % 8
|
118
|
+
bits[i] = ((bytes[byte_index] >> bit_index) & 1) == 1
|
119
|
+
end
|
120
|
+
bits
|
121
|
+
end
|
122
|
+
|
123
|
+
private_class_method :unpack_bits
|
67
124
|
end
|
68
125
|
end
|
data/lib/mssmt/tree.rb
CHANGED
data/lib/mssmt/version.rb
CHANGED
data/lib/mssmt.rb
CHANGED
@@ -8,9 +8,14 @@ module MSSMT
|
|
8
8
|
class Error < StandardError
|
9
9
|
end
|
10
10
|
|
11
|
+
# Error when sum overflows
|
12
|
+
class OverflowError < Error
|
13
|
+
end
|
14
|
+
|
11
15
|
autoload :Store, "mssmt/store"
|
12
16
|
autoload :LeafNode, "mssmt/leaf_node"
|
13
17
|
autoload :BranchNode, "mssmt/branch_node"
|
18
|
+
autoload :ComputedNode, "mssmt/computed_node"
|
14
19
|
autoload :Tree, "mssmt/tree"
|
15
20
|
autoload :Proof, "mssmt/proof"
|
16
21
|
autoload :CompressedProof, "mssmt/proof"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mssmt
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- azuchi
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-10-
|
11
|
+
date: 2022-10-30 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Ruby implementation of Merkle Sum Sparse Merkle Tree
|
14
14
|
email:
|
@@ -32,6 +32,7 @@ files:
|
|
32
32
|
- bin/setup
|
33
33
|
- lib/mssmt.rb
|
34
34
|
- lib/mssmt/branch_node.rb
|
35
|
+
- lib/mssmt/computed_node.rb
|
35
36
|
- lib/mssmt/leaf_node.rb
|
36
37
|
- lib/mssmt/proof.rb
|
37
38
|
- lib/mssmt/store.rb
|