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 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