immudb 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []