mssmt 0.2.0 → 0.4.0
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 +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
|