immudb 0.1.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.
@@ -0,0 +1,31 @@
1
+ # Copyright 2021 CodeNotary, Inc. All rights reserved.
2
+
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ # Unless required by applicable law or agreed to in writing, software
8
+ # distributed under the License is distributed on an "AS IS" BASIS,
9
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+ # See the License for the specific language governing permissions and
11
+ # limitations under the License.
12
+
13
+ module Immudb
14
+ class Interceptor < GRPC::ClientInterceptor
15
+ attr_accessor :token
16
+
17
+ def request_response(request: nil, call: nil, method: nil, metadata: nil)
18
+ metadata["authorization"] = "Bearer #{token}" if token
19
+ begin
20
+ super
21
+ rescue GRPC::Unknown => e
22
+ raise Error, e.details
23
+ end
24
+ end
25
+
26
+ # hide token
27
+ def inspect
28
+ to_s
29
+ end
30
+ end
31
+ end
data/lib/immudb/kv.rb ADDED
@@ -0,0 +1,25 @@
1
+ # Copyright 2021 CodeNotary, Inc. All rights reserved.
2
+
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ # Unless required by applicable law or agreed to in writing, software
8
+ # distributed under the License is distributed on an "AS IS" BASIS,
9
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+ # See the License for the specific language governing permissions and
11
+ # limitations under the License.
12
+
13
+ module Immudb
14
+ class KV
15
+ def initialize(key, value)
16
+ @key = key
17
+ @value = value
18
+ end
19
+
20
+ def digest
21
+ valdigest = Digest::SHA256.digest(@value.nil? ? "" : @value)
22
+ Digest::SHA256.digest(@key + valdigest)
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,23 @@
1
+ # Copyright 2021 CodeNotary, Inc. All rights reserved.
2
+
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ # Unless required by applicable law or agreed to in writing, software
8
+ # distributed under the License is distributed on an "AS IS" BASIS,
9
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+ # See the License for the specific language governing permissions and
11
+ # limitations under the License.
12
+
13
+ module Immudb
14
+ class LinearProof
15
+ attr_reader :sourceTxID, :targetTxID, :terms
16
+
17
+ def initialize(sourceTxID, targetTxID, terms)
18
+ @sourceTxID = sourceTxID
19
+ @targetTxID = targetTxID
20
+ @terms = terms
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,36 @@
1
+ # Copyright 2021 CodeNotary, Inc. All rights reserved.
2
+
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ # Unless required by applicable law or agreed to in writing, software
8
+ # distributed under the License is distributed on an "AS IS" BASIS,
9
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+ # See the License for the specific language governing permissions and
11
+ # limitations under the License.
12
+
13
+ module Immudb
14
+ class RootService
15
+ def initialize
16
+ @dbname = nil
17
+ @cache = nil
18
+ @service = nil
19
+ end
20
+
21
+ def init(dbname, service)
22
+ @dbname = dbname
23
+ @service = service
24
+ state = @service.current_state(Google::Protobuf::Empty.new)
25
+ @cache = state
26
+ end
27
+
28
+ def get
29
+ @cache ||= @service.current_state(Google::Protobuf::Empty.new)
30
+ end
31
+
32
+ def set(root)
33
+ @cache = root
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,15 @@
1
+ module Immudb
2
+ class SqlResult
3
+ attr_reader :columns, :rows, :column_types
4
+
5
+ def initialize(columns, rows, column_types)
6
+ @columns = columns
7
+ @rows = rows
8
+ @column_types = column_types
9
+ end
10
+
11
+ def to_a
12
+ @rows.map { |r| @columns.zip(r).to_h }
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,26 @@
1
+ # Copyright 2021 CodeNotary, Inc. All rights reserved.
2
+
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ # Unless required by applicable law or agreed to in writing, software
8
+ # distributed under the License is distributed on an "AS IS" BASIS,
9
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+ # See the License for the specific language governing permissions and
11
+ # limitations under the License.
12
+
13
+ module Immudb
14
+ class State
15
+ # names must match Schema::ImmutableState
16
+ attr_reader :db, :txId, :txHash, :publicKey, :signature
17
+
18
+ def initialize(db:, txId:, txHash:, publicKey:, signature:)
19
+ @db = db
20
+ @txId = txId
21
+ @txHash = txHash
22
+ @publicKey = publicKey
23
+ @signature = signature
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,227 @@
1
+ # Copyright 2021 CodeNotary, Inc. All rights reserved.
2
+
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ # Unless required by applicable law or agreed to in writing, software
8
+ # distributed under the License is distributed on an "AS IS" BASIS,
9
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+ # See the License for the specific language governing permissions and
11
+ # limitations under the License.
12
+
13
+ module Immudb
14
+ class Store
15
+ class << self
16
+ def tx_from(stx)
17
+ entries = []
18
+ stx.entries.each do |e|
19
+ i = TXe.new
20
+ i.h_value = digest_from(e.hValue)
21
+ i.v_off = e.vOff
22
+ i.value_len = e.vLen.to_i
23
+ i.set_key(e.key)
24
+ entries << i
25
+ end
26
+ tx = new_tx_with_entries(entries)
27
+ tx.ID = stx.metadata.id
28
+ tx.PrevAlh = digest_from(stx.metadata.prevAlh)
29
+ tx.Ts = stx.metadata.ts
30
+ tx.BlTxID = stx.metadata.blTxId
31
+ tx.BlRoot = digest_from(stx.metadata.blRoot)
32
+ tx.build_hash_tree
33
+ tx.calc_alh
34
+ tx
35
+ end
36
+
37
+ def tx_metadata_from(txmFrom)
38
+ txm = TxMetadata.new
39
+ txm.iD = txmFrom.id
40
+ txm.prevAlh = digest_from(txmFrom.prevAlh)
41
+ txm.ts = txmFrom.ts
42
+ txm.nEntries = txmFrom.nentries.to_i
43
+ txm.eh = digest_from(txmFrom.eH)
44
+ txm.blTxID = txmFrom.blTxId
45
+ txm.blRoot = digest_from(txmFrom.blRoot)
46
+ txm
47
+ end
48
+
49
+ def encode_key(key)
50
+ SET_KEY_PREFIX + key
51
+ end
52
+
53
+ def encode_kv(key, value)
54
+ KV.new(SET_KEY_PREFIX + key, PLAIN_VALUE_PREFIX + value)
55
+ end
56
+
57
+ def encode_reference(key, referencedKey, atTx)
58
+ refVal = REFERENCE_VALUE_PREFIX + [atTx].pack("Q>") + SET_KEY_PREFIX + referencedKey
59
+ KV.new(SET_KEY_PREFIX + key, refVal)
60
+ end
61
+
62
+ def linear_proof_from(lp)
63
+ LinearProof.new(lp.sourceTxId, lp.TargetTxId, lp.terms)
64
+ end
65
+
66
+ def digest_from(sliced_digest)
67
+ sliced_digest[0, 32]
68
+ end
69
+
70
+ def digests_from(sliced_terms)
71
+ sliced_terms.map(&:dup)
72
+ end
73
+
74
+ def verify_inclusion(proof, digest, root)
75
+ return false if proof.nil?
76
+ leaf = LEAF_PREFIX + digest
77
+ calc_root = Digest::SHA256.digest(leaf)
78
+ i = proof.leaf
79
+ r = proof.width - 1
80
+ proof.terms.to_a.each do |t|
81
+ b = NODE_PREFIX
82
+ if i % 2 == 0 && i != r
83
+ b = b + calc_root + t
84
+ else
85
+ b = b + t + calc_root
86
+ end
87
+ calc_root = Digest::SHA256.digest(b)
88
+ i = i.div(2)
89
+ r = r.div(2)
90
+ end
91
+ i == r && root == calc_root
92
+ end
93
+
94
+ def verify_dual_proof(proof, sourceTxID, targetTxID, sourceAlh, targetAlh)
95
+ if proof.nil? || proof.sourceTxMetadata.nil? || proof.targetTxMetadata.nil? || proof.sourceTxMetadata.iD != sourceTxID || proof.targetTxMetadata.iD != targetTxID
96
+ return false
97
+ end
98
+ if proof.sourceTxMetadata.iD == 0 || proof.sourceTxMetadata.iD > proof.targetTxMetadata.iD
99
+ return false
100
+ end
101
+ if sourceAlh != proof.sourceTxMetadata.alh
102
+ return false
103
+ end
104
+ if targetAlh != proof.targetTxMetadata.alh
105
+ return false
106
+ end
107
+ if sourceTxID < proof.targetTxMetadata.blTxID && !verify_inclusion_aht(proof.inclusionProof, sourceTxID, proof.targetTxMetadata.blTxID, leaf_for(sourceAlh), proof.targetTxMetadata.blRoot)
108
+ return false
109
+ end
110
+ if proof.sourceTxMetadata.blTxID > 0 && !verify_consistency(proof.consistencyProof, proof.sourceTxMetadata.blTxID, proof.targetTxMetadata.blTxID, proof.sourceTxMetadata.blRoot, proof.targetTxMetadata.blRoot)
111
+ return false
112
+ end
113
+ if proof.targetTxMetadata.blTxID > 0 && !verify_last_inclusion(proof.lastInclusionProof, proof.targetTxMetadata.blTxID, leaf_for(proof.targetBlTxAlh), proof.targetTxMetadata.blRoot)
114
+ return false
115
+ end
116
+ if sourceTxID < proof.targetTxMetadata.blTxID
117
+ verify_linear_proof(proof.linearProof, proof.targetTxMetadata.blTxID, targetTxID, proof.targetBlTxAlh, targetAlh)
118
+ else
119
+ verify_linear_proof(proof.linearProof, sourceTxID, targetTxID, sourceAlh, targetAlh)
120
+ end
121
+ end
122
+
123
+ private
124
+
125
+ def new_tx_with_entries(entries)
126
+ tx = Tx.new
127
+ tx.ID = 0
128
+ tx.entries = entries
129
+ tx.nentries = entries.length
130
+ tx.htree = HTree.new(entries.length)
131
+ tx
132
+ end
133
+
134
+ def leaf_for(d)
135
+ b = LEAF_PREFIX + d
136
+ Digest::SHA256.digest(b)
137
+ end
138
+
139
+ def verify_inclusion_aht(iproof, i, j, iLeaf, jRoot)
140
+ if i > j || i == 0 || i < j && iproof.length == 0
141
+ return false
142
+ end
143
+ i1 = i - 1
144
+ j1 = j - 1
145
+ ciRoot = iLeaf
146
+ iproof.each do |h|
147
+ if i1 % 2 == 0 && i1 != j1
148
+ b = NODE_PREFIX + ciRoot + h
149
+ else
150
+ b = NODE_PREFIX + h + ciRoot
151
+ end
152
+ ciRoot = Digest::SHA256.digest(b)
153
+ i1 = i1 >> 1
154
+ j1 = j1 >> 1
155
+ end
156
+ jRoot == ciRoot
157
+ end
158
+
159
+ def verify_consistency(cproof, i, j, iRoot, jRoot)
160
+ if i > j || i == 0 || (i < j && cproof.length == 0)
161
+ return false
162
+ end
163
+ if i == j && cproof.length == 0
164
+ return iRoot == jRoot
165
+ end
166
+
167
+ fn = i - 1
168
+ sn = j - 1
169
+ while fn % 2 == 1
170
+ fn = fn >> 1
171
+ sn = sn >> 1
172
+ end
173
+ ciRoot, cjRoot = cproof[0], cproof[0]
174
+ cproof[1..-1].each do |h|
175
+ if fn % 2 == 1 || fn == sn
176
+ b = NODE_PREFIX + h + ciRoot
177
+ ciRoot = Digest::SHA256.digest(b)
178
+ b = NODE_PREFIX + h + cjRoot
179
+ cjRoot = Digest::SHA256.digest(b)
180
+ while fn % 2 == 0 && fn != 0
181
+ fn = fn >> 1
182
+ sn = sn >> 1
183
+ end
184
+ else
185
+ b = NODE_PREFIX + cjRoot + h
186
+ cjRoot = Digest::SHA256.digest(b)
187
+ end
188
+ fn = fn >> 1
189
+ sn = sn >> 1
190
+ end
191
+ iRoot == ciRoot && jRoot == cjRoot
192
+ end
193
+
194
+ def verify_last_inclusion(iproof, i, leaf, root)
195
+ if i == 0
196
+ return false
197
+ end
198
+ i1 = i - 1
199
+ iroot = leaf
200
+ iproof.each do |h|
201
+ b = NODE_PREFIX + h + iroot
202
+ iroot = Digest::SHA256.digest(b)
203
+ i1 >>= 1
204
+ end
205
+ root == iroot
206
+ end
207
+
208
+ def verify_linear_proof(proof, sourceTxID, targetTxID, sourceAlh, targetAlh)
209
+ if proof.nil? || proof.sourceTxID != sourceTxID || proof.targetTxID != targetTxID
210
+ return false
211
+ end
212
+
213
+ if proof.sourceTxID == 0 || proof.sourceTxID > proof.targetTxID || proof.terms.length == 0 || sourceAlh != proof.terms[0]
214
+ return false
215
+ end
216
+
217
+ calculatedAlh = proof.terms[0]
218
+ (1...proof.terms.length).each do |i|
219
+ bs = [proof.sourceTxID + i].pack("Q>") + calculatedAlh + proof.terms[i]
220
+ calculatedAlh = Digest::SHA256.digest(bs)
221
+ end
222
+
223
+ targetAlh == calculatedAlh
224
+ end
225
+ end
226
+ end
227
+ end
data/lib/immudb/tx.rb ADDED
@@ -0,0 +1,56 @@
1
+ # Copyright 2021 CodeNotary, Inc. All rights reserved.
2
+
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ # Unless required by applicable law or agreed to in writing, software
8
+ # distributed under the License is distributed on an "AS IS" BASIS,
9
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+ # See the License for the specific language governing permissions and
11
+ # limitations under the License.
12
+
13
+ module Immudb
14
+ class Tx
15
+ attr_accessor :ID, :Ts, :BlTxID, :BlRoot, :PrevAlh, :nentries, :entries, :htree, :Alh
16
+
17
+ def build_hash_tree
18
+ digests = []
19
+ @entries.each do |e|
20
+ digests << e.digest
21
+ end
22
+ @htree.build_with(digests)
23
+ end
24
+
25
+ def calc_alh
26
+ calc_innerhash
27
+ bi = [@ID].pack("Q>") + @PrevAlh + @InnerHash
28
+ @Alh = Digest::SHA256.digest(bi)
29
+ end
30
+
31
+ def calc_innerhash
32
+ bj = [@Ts, @nentries].pack("Q>L>") + eh
33
+ bj += [@BlTxID].pack("Q>") + @BlRoot
34
+ @InnerHash = Digest::SHA256.digest(bj)
35
+ end
36
+
37
+ def eh
38
+ @htree.root
39
+ end
40
+
41
+ def proof(key)
42
+ kindex = nil
43
+ # find index of element holding given key
44
+ @entries.each_with_index do |v, k|
45
+ if v.key == key
46
+ kindex = k
47
+ break
48
+ end
49
+ end
50
+ if kindex.nil?
51
+ raise KeyError
52
+ end
53
+ @htree.inclusion_proof(kindex)
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,26 @@
1
+ # Copyright 2021 CodeNotary, Inc. All rights reserved.
2
+
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ # Unless required by applicable law or agreed to in writing, software
8
+ # distributed under the License is distributed on an "AS IS" BASIS,
9
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+ # See the License for the specific language governing permissions and
11
+ # limitations under the License.
12
+
13
+ module Immudb
14
+ class TxMetadata
15
+ attr_accessor :iD, :prevAlh, :ts, :nEntries, :eh, :blTxID, :blRoot
16
+
17
+ def alh
18
+ bi = [@iD].pack("Q>") + @prevAlh
19
+ bj = [@ts.to_i, @nEntries.to_i].pack("Q>L>")
20
+ bj = bj + @eh + [@blTxID].pack("Q>") + @blRoot
21
+ inner_hash = Digest::SHA256.digest(bj)
22
+ bi = bi + inner_hash
23
+ Digest::SHA256.digest(bi)
24
+ end
25
+ end
26
+ end
data/lib/immudb/txe.rb ADDED
@@ -0,0 +1,27 @@
1
+ # Copyright 2021 CodeNotary, Inc. All rights reserved.
2
+
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ # Unless required by applicable law or agreed to in writing, software
8
+ # distributed under the License is distributed on an "AS IS" BASIS,
9
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+ # See the License for the specific language governing permissions and
11
+ # limitations under the License.
12
+
13
+ module Immudb
14
+ class TXe
15
+ attr_accessor :key_len, :key, :value_len, :h_value, :v_off
16
+
17
+ def set_key(key)
18
+ @key = key.dup
19
+ @key_len = key.length
20
+ end
21
+
22
+ def digest
23
+ b = @key + @h_value
24
+ Digest::SHA256.digest(b)
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,3 @@
1
+ module Immudb
2
+ VERSION = "0.1.0"
3
+ end
data/lib/immudb.rb ADDED
@@ -0,0 +1,35 @@
1
+ # stdlib
2
+ require "net/http"
3
+ require "openssl"
4
+ require "time"
5
+
6
+ # grpc
7
+ require "immudb/grpc/schema_pb"
8
+ require "immudb/grpc/schema_services_pb"
9
+
10
+ # modules
11
+ require "immudb/client"
12
+ require "immudb/constants"
13
+ require "immudb/dual_proof"
14
+ require "immudb/htree"
15
+ require "immudb/inclusion_proof"
16
+ require "immudb/interceptor"
17
+ require "immudb/kv"
18
+ require "immudb/linear_proof"
19
+ require "immudb/root_service"
20
+ require "immudb/sql_result"
21
+ require "immudb/state"
22
+ require "immudb/store"
23
+ require "immudb/tx"
24
+ require "immudb/tx_metadata"
25
+ require "immudb/txe"
26
+ require "immudb/version"
27
+
28
+ module Immudb
29
+ class Error < StandardError; end
30
+ class VerificationError < Error
31
+ def message
32
+ "Verification failed"
33
+ end
34
+ end
35
+ end
metadata ADDED
@@ -0,0 +1,78 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: immudb
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Andrew Kane
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-12-31 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: grpc
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'
27
+ description:
28
+ email: andrew@ankane.org
29
+ executables: []
30
+ extensions: []
31
+ extra_rdoc_files: []
32
+ files:
33
+ - CHANGELOG.md
34
+ - LICENSE.txt
35
+ - README.md
36
+ - lib/immudb.rb
37
+ - lib/immudb/client.rb
38
+ - lib/immudb/constants.rb
39
+ - lib/immudb/dual_proof.rb
40
+ - lib/immudb/grpc/schema_pb.rb
41
+ - lib/immudb/grpc/schema_services_pb.rb
42
+ - lib/immudb/htree.rb
43
+ - lib/immudb/inclusion_proof.rb
44
+ - lib/immudb/interceptor.rb
45
+ - lib/immudb/kv.rb
46
+ - lib/immudb/linear_proof.rb
47
+ - lib/immudb/root_service.rb
48
+ - lib/immudb/sql_result.rb
49
+ - lib/immudb/state.rb
50
+ - lib/immudb/store.rb
51
+ - lib/immudb/tx.rb
52
+ - lib/immudb/tx_metadata.rb
53
+ - lib/immudb/txe.rb
54
+ - lib/immudb/version.rb
55
+ homepage: https://github.com/ankane/immudb-ruby
56
+ licenses:
57
+ - Apache-2.0
58
+ metadata: {}
59
+ post_install_message:
60
+ rdoc_options: []
61
+ require_paths:
62
+ - lib
63
+ required_ruby_version: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '2.6'
68
+ required_rubygems_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: '0'
73
+ requirements: []
74
+ rubygems_version: 3.2.32
75
+ signing_key:
76
+ specification_version: 4
77
+ summary: Ruby client for immudb
78
+ test_files: []