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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bc50f962065de3f0ceaeebaa7715ab5e32d03a882d7df11022e6e4bc90b459d1
4
- data.tar.gz: 020cb3cfedb35c8c3a6cd123d9b772e666e9b9fe19f301c07acc6ca27a193ca6
3
+ metadata.gz: d07e68431e9d8539727c514f6bbe42006709b980214d6fdeaca0cb6fb0613d5d
4
+ data.tar.gz: 76da8e23b8b45119ab20fc875657688dd26dd2b24a8dc82f7704162c6ae61a24
5
5
  SHA512:
6
- metadata.gz: 468f823bbba1cff9549b5977a98270ec215e3ccf7b8057bcdd0642fd99da280233a0a821254fc2fb4c294d638ccaa6443cf04abd8a99fd4e61de6f2c51f169a1
7
- data.tar.gz: 17f30d1180c82d4b4862c752b842e725e5d9527f1ad7f80b5e8eeb3e0d2573b127531afbfda474017103b97b21acbf3d1f1e891398686fdf06256dd3d246dc06
6
+ metadata.gz: 3dc973a5f83f8399af0b617a34db243464d15878e27fe1b748ba576622c7a7d7e28e5ac736efef4d0e4a4e53231525aad6a8d4e99d3b1b6f732948dc72a8dc3c
7
+ data.tar.gz: 482b24550810aa7c070b0b51845088094d17d4afca4a1ae60677c58be3fecf89eaf88651b3795eca268a05f08b7d265602ee6fb6c699a06a1bf80d8bb450c659
@@ -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 other.is_a?(BranchNode)
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
@@ -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
- # puts "#{node.node_hash}:#{Tree.empty_tree[Tree::MAX_LEVEL - 1].node_hash}"
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
@@ -9,6 +9,8 @@ module MSSMT
9
9
  MAX_LEVEL = HASH_SIZE * 8
10
10
  # Index of the last bit for MS-SMT keys
11
11
  LAST_BIT_INDEX = MAX_LEVEL - 1
12
+ # Maximum sum value
13
+ MAX_SUM_VALUE = 0xffffffffffffffff
12
14
 
13
15
  attr_reader :store
14
16
 
data/lib/mssmt/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MSSMT
4
- VERSION = "0.2.0"
4
+ VERSION = "0.4.0"
5
5
  end
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.2.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-26 00:00:00.000000000 Z
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