immudb 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/lib/immudb/client.rb +81 -47
- data/lib/immudb/database.rb +33 -0
- data/lib/immudb/dual_proof.rb +1 -1
- data/lib/immudb/{txe.rb → entry_spec.rb} +7 -11
- data/lib/immudb/grpc/schema_pb.rb +309 -17
- data/lib/immudb/grpc/schema_services_pb.rb +38 -11
- data/lib/immudb/htree.rb +0 -21
- data/lib/immudb/kv_metadata.rb +88 -0
- data/lib/immudb/linear_proof.rb +2 -8
- data/lib/immudb/schema.rb +119 -0
- data/lib/immudb/store.rb +56 -72
- data/lib/immudb/tx.rb +60 -23
- data/lib/immudb/tx_entry.rb +34 -0
- data/lib/immudb/tx_header.rb +62 -0
- data/lib/immudb/version.rb +1 -1
- data/lib/immudb.rb +6 -2
- metadata +10 -5
data/lib/immudb/htree.rb
CHANGED
@@ -95,26 +95,5 @@ module Immudb
|
|
95
95
|
end
|
96
96
|
end
|
97
97
|
end
|
98
|
-
|
99
|
-
def self.inclusion_proof_from(iproof)
|
100
|
-
h = InclusionProof.new
|
101
|
-
h.leaf = iproof.leaf.to_i
|
102
|
-
h.width = iproof.width.to_i
|
103
|
-
h.terms = Store.digest_from(iproof.terms)
|
104
|
-
h
|
105
|
-
end
|
106
|
-
|
107
|
-
def self.dual_proof_from(dproof)
|
108
|
-
dp = DualProof.new
|
109
|
-
dp.sourceTxMetadata = Store.tx_metadata_from(dproof.sourceTxMetadata)
|
110
|
-
dp.targetTxMetadata = Store.tx_metadata_from(dproof.targetTxMetadata)
|
111
|
-
dp.inclusionProof = Store.digest_from(dproof.inclusionProof)
|
112
|
-
# use digests_from?
|
113
|
-
dp.consistencyProof = Store.digests_from(dproof.consistencyProof)
|
114
|
-
dp.targetBlTxAlh = Store.digest_from(dproof.targetBlTxAlh)
|
115
|
-
dp.lastInclusionProof = Store.digests_from(dproof.lastInclusionProof)
|
116
|
-
dp.linearProof = Store.linear_proof_from(dproof.linearProof)
|
117
|
-
dp
|
118
|
-
end
|
119
98
|
end
|
120
99
|
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# Copyright 2022 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 KVMetadata
|
15
|
+
DELETED_ATTR_CODE = 0
|
16
|
+
EXPIRES_AT_ATTR_CODE = 1
|
17
|
+
NON_INDEXABLE_ATTR_CODE = 2
|
18
|
+
|
19
|
+
def initialize
|
20
|
+
@attributes = {}
|
21
|
+
@readonly = false
|
22
|
+
end
|
23
|
+
|
24
|
+
def as_deleted(deleted)
|
25
|
+
if @readonly
|
26
|
+
raise Error, "Read-only"
|
27
|
+
elsif !deleted
|
28
|
+
@attributes.delete(DELETED_ATTR_CODE)
|
29
|
+
else
|
30
|
+
@attributes[DELETED_ATTR_CODE] = nil
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def deleted?
|
35
|
+
@attributes.key?(DELETED_ATTR_CODE)
|
36
|
+
end
|
37
|
+
|
38
|
+
def expires_at(expires_at)
|
39
|
+
if @readonly
|
40
|
+
raise Error, "Read-only"
|
41
|
+
end
|
42
|
+
@attributes[EXPIRES_AT_ATTR_CODE] = expires_at
|
43
|
+
end
|
44
|
+
|
45
|
+
def non_expirable
|
46
|
+
@attributes.delete(EXPIRES_AT_ATTR_CODE)
|
47
|
+
end
|
48
|
+
|
49
|
+
def expirable?
|
50
|
+
@attributes.key?(EXPIRES_AT_ATTR_CODE)
|
51
|
+
end
|
52
|
+
|
53
|
+
def expiration_time
|
54
|
+
if @attributes.key?(EXPIRES_AT_ATTR_CODE)
|
55
|
+
@attributes[EXPIRES_AT_ATTR_CODE]
|
56
|
+
else
|
57
|
+
raise Error, "Non-expirable"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def as_non_indexable(non_indexable)
|
62
|
+
if @readonly
|
63
|
+
raise Error, "Read-only"
|
64
|
+
elsif !non_indexable
|
65
|
+
@attributes.delete(NON_INDEXABLE_ATTR_CODE)
|
66
|
+
else
|
67
|
+
@attributes[NON_INDEXABLE_ATTR_CODE] = nil
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def non_indexable?
|
72
|
+
@attributes.key?(NON_INDEXABLE_ATTR_CODE)
|
73
|
+
end
|
74
|
+
|
75
|
+
def bytes
|
76
|
+
b = "".b
|
77
|
+
[DELETED_ATTR_CODE, EXPIRES_AT_ATTR_CODE, NON_INDEXABLE_ATTR_CODE].each do |attr_code|
|
78
|
+
if @attributes.key?(attr_code)
|
79
|
+
b += [attr_code].pack("C")
|
80
|
+
if attr_code == EXPIRES_AT_ATTR_CODE
|
81
|
+
b += [@attributes[attr_code].to_i].pack("Q>")
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
b
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
data/lib/immudb/linear_proof.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright
|
1
|
+
# Copyright 2022 CodeNotary, Inc. All rights reserved.
|
2
2
|
|
3
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
4
|
# you may not use this file except in compliance with the License.
|
@@ -12,12 +12,6 @@
|
|
12
12
|
|
13
13
|
module Immudb
|
14
14
|
class LinearProof
|
15
|
-
|
16
|
-
|
17
|
-
def initialize(sourceTxID, targetTxID, terms)
|
18
|
-
@sourceTxID = sourceTxID
|
19
|
-
@targetTxID = targetTxID
|
20
|
-
@terms = terms
|
21
|
-
end
|
15
|
+
attr_accessor :sourceTxID, :targetTxID, :terms
|
22
16
|
end
|
23
17
|
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
# Copyright 2022 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
|
+
module Schema
|
15
|
+
class << self
|
16
|
+
def tx_from_proto(stx)
|
17
|
+
header = ::Immudb::TxHeader.new
|
18
|
+
header.iD = stx.header.id
|
19
|
+
header.ts = stx.header.ts
|
20
|
+
header.blTxID = stx.header.blTxId
|
21
|
+
header.blRoot = digest_from_proto(stx.header.blRoot)
|
22
|
+
header.prevAlh = digest_from_proto(stx.header.prevAlh)
|
23
|
+
|
24
|
+
header.version = stx.header.version.to_i
|
25
|
+
header.metadata = tx_metadata_from_proto(stx.header.metadata)
|
26
|
+
|
27
|
+
header.nentries = stx.header.nentries.to_i
|
28
|
+
header.eh = digest_from_proto(stx.header.eH)
|
29
|
+
|
30
|
+
entries = []
|
31
|
+
stx.entries.each do |e|
|
32
|
+
entries <<
|
33
|
+
::Immudb::TxEntry.new(
|
34
|
+
e.key,
|
35
|
+
kv_metadata_from_proto(e.metadata),
|
36
|
+
e.vLen.to_i,
|
37
|
+
digest_from_proto(e.hValue),
|
38
|
+
0
|
39
|
+
)
|
40
|
+
end
|
41
|
+
|
42
|
+
tx = Store.new_tx_with_entries(header, entries)
|
43
|
+
|
44
|
+
tx.build_hash_tree
|
45
|
+
|
46
|
+
tx
|
47
|
+
end
|
48
|
+
|
49
|
+
def kv_metadata_from_proto(md)
|
50
|
+
return nil if md.nil?
|
51
|
+
kvmd = ::Immudb::KVMetadata.new()
|
52
|
+
kvmd.as_deleted(md.deleted)
|
53
|
+
|
54
|
+
unless md.expiration.nil?
|
55
|
+
kvmd.expires_at(Time.at(md.expiration.expiresAt))
|
56
|
+
end
|
57
|
+
|
58
|
+
kvmd.as_non_indexable(md.nonIndexable)
|
59
|
+
|
60
|
+
kvmd
|
61
|
+
end
|
62
|
+
|
63
|
+
def inclusion_proof_from_proto(iproof)
|
64
|
+
ip = ::Immudb::InclusionProof.new
|
65
|
+
ip.leaf = iproof.leaf.to_i
|
66
|
+
ip.width = iproof.width.to_i
|
67
|
+
ip.terms = digests_from_proto(iproof.terms)
|
68
|
+
ip
|
69
|
+
end
|
70
|
+
|
71
|
+
def dual_proof_from_proto(dproof)
|
72
|
+
dp = ::Immudb::DualProof.new
|
73
|
+
dp.sourceTxHeader = tx_header_from_proto(dproof.sourceTxHeader)
|
74
|
+
dp.targetTxHeader = tx_header_from_proto(dproof.targetTxHeader)
|
75
|
+
dp.inclusionProof = digests_from_proto(dproof.inclusionProof)
|
76
|
+
dp.consistencyProof = digests_from_proto(dproof.consistencyProof)
|
77
|
+
dp.targetBlTxAlh = digest_from_proto(dproof.targetBlTxAlh)
|
78
|
+
dp.lastInclusionProof = digests_from_proto(dproof.lastInclusionProof)
|
79
|
+
dp.linearProof = linear_proof_from_proto(dproof.linearProof)
|
80
|
+
dp
|
81
|
+
end
|
82
|
+
|
83
|
+
def tx_header_from_proto(hdr)
|
84
|
+
txh = ::Immudb::TxHeader.new
|
85
|
+
txh.iD = hdr.id
|
86
|
+
txh.prevAlh = digest_from_proto(hdr.prevAlh)
|
87
|
+
txh.ts = hdr.ts
|
88
|
+
txh.version = hdr.version.to_i
|
89
|
+
txh.metadata = tx_metadata_from_proto(hdr.metadata)
|
90
|
+
txh.nentries = hdr.nentries.to_i
|
91
|
+
txh.eh = digest_from_proto(hdr.eH)
|
92
|
+
txh.blTxID = hdr.blTxId
|
93
|
+
txh.blRoot = digest_from_proto(hdr.blRoot)
|
94
|
+
txh
|
95
|
+
end
|
96
|
+
|
97
|
+
def tx_metadata_from_proto(md)
|
98
|
+
return nil if md.nil?
|
99
|
+
::Immudb::TxMetadata.new
|
100
|
+
end
|
101
|
+
|
102
|
+
def linear_proof_from_proto(lproof)
|
103
|
+
lp = ::Immudb::LinearProof.new
|
104
|
+
lp.sourceTxID = lproof.sourceTxId
|
105
|
+
lp.targetTxID = lproof.TargetTxId
|
106
|
+
lp.terms = digests_from_proto(lproof.terms)
|
107
|
+
lp
|
108
|
+
end
|
109
|
+
|
110
|
+
def digest_from_proto(sliced_digest)
|
111
|
+
sliced_digest[0, 32]
|
112
|
+
end
|
113
|
+
|
114
|
+
def digests_from_proto(sliced_terms)
|
115
|
+
sliced_terms.map(&:dup)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
data/lib/immudb/store.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright
|
1
|
+
# Copyright 2022 CodeNotary, Inc. All rights reserved.
|
2
2
|
|
3
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
4
|
# you may not use this file except in compliance with the License.
|
@@ -13,62 +13,14 @@
|
|
13
13
|
module Immudb
|
14
14
|
class Store
|
15
15
|
class << self
|
16
|
-
def
|
17
|
-
|
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
|
16
|
+
def new_tx_with_entries(header, entries)
|
17
|
+
htree = HTree.new(entries.length)
|
65
18
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
sliced_terms.map(&:dup)
|
19
|
+
tx = Tx.new
|
20
|
+
tx.header = header
|
21
|
+
tx.entries = entries
|
22
|
+
tx.htree = htree
|
23
|
+
tx
|
72
24
|
end
|
73
25
|
|
74
26
|
def verify_inclusion(proof, digest, root)
|
@@ -92,43 +44,75 @@ module Immudb
|
|
92
44
|
end
|
93
45
|
|
94
46
|
def verify_dual_proof(proof, sourceTxID, targetTxID, sourceAlh, targetAlh)
|
95
|
-
if proof.nil? || proof.
|
47
|
+
if proof.nil? || proof.sourceTxHeader.nil? || proof.targetTxHeader.nil? || proof.sourceTxHeader.iD != sourceTxID || proof.targetTxHeader.iD != targetTxID
|
96
48
|
return false
|
97
49
|
end
|
98
|
-
if proof.
|
50
|
+
if proof.sourceTxHeader.iD == 0 || proof.sourceTxHeader.iD > proof.targetTxHeader.iD
|
99
51
|
return false
|
100
52
|
end
|
101
|
-
if sourceAlh != proof.
|
53
|
+
if sourceAlh != proof.sourceTxHeader.alh
|
102
54
|
return false
|
103
55
|
end
|
104
|
-
if targetAlh != proof.
|
56
|
+
if targetAlh != proof.targetTxHeader.alh
|
105
57
|
return false
|
106
58
|
end
|
107
|
-
if sourceTxID < proof.
|
59
|
+
if sourceTxID < proof.targetTxHeader.blTxID && !verify_inclusion_aht(proof.inclusionProof, sourceTxID, proof.targetTxHeader.blTxID, leaf_for(sourceAlh), proof.targetTxHeader.blRoot)
|
108
60
|
return false
|
109
61
|
end
|
110
|
-
if proof.
|
62
|
+
if proof.sourceTxHeader.blTxID > 0 && !verify_consistency(proof.consistencyProof, proof.sourceTxHeader.blTxID, proof.targetTxHeader.blTxID, proof.sourceTxHeader.blRoot, proof.targetTxHeader.blRoot)
|
111
63
|
return false
|
112
64
|
end
|
113
|
-
if proof.
|
65
|
+
if proof.targetTxHeader.blTxID > 0 && !verify_last_inclusion(proof.lastInclusionProof, proof.targetTxHeader.blTxID, leaf_for(proof.targetBlTxAlh), proof.targetTxHeader.blRoot)
|
114
66
|
return false
|
115
67
|
end
|
116
|
-
if sourceTxID < proof.
|
117
|
-
verify_linear_proof(proof.linearProof, proof.
|
68
|
+
if sourceTxID < proof.targetTxHeader.blTxID
|
69
|
+
verify_linear_proof(proof.linearProof, proof.targetTxHeader.blTxID, targetTxID, proof.targetBlTxAlh, targetAlh)
|
118
70
|
else
|
119
71
|
verify_linear_proof(proof.linearProof, sourceTxID, targetTxID, sourceAlh, targetAlh)
|
120
72
|
end
|
121
73
|
end
|
122
74
|
|
75
|
+
def entry_spec_digest_for(version)
|
76
|
+
if version == 0
|
77
|
+
method(:entry_spec_digest_v0)
|
78
|
+
elsif version == 1
|
79
|
+
method(:entry_spec_digest_v1)
|
80
|
+
else
|
81
|
+
# TODO raise ErrUnsupportedTxVersion
|
82
|
+
raise VerificationError
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
123
86
|
private
|
124
87
|
|
125
|
-
def
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
88
|
+
def entry_spec_digest_v0(kv)
|
89
|
+
md = Digest::SHA256.new
|
90
|
+
md.update(kv.key)
|
91
|
+
valmd = Digest::SHA256.new
|
92
|
+
valmd.update(kv.value)
|
93
|
+
md.update(valmd.digest)
|
94
|
+
md.digest
|
95
|
+
end
|
96
|
+
|
97
|
+
def entry_spec_digest_v1(kv)
|
98
|
+
mdbs = "".b
|
99
|
+
if !kv.metadata.nil?
|
100
|
+
mdbs = kv.metadata.bytes
|
101
|
+
end
|
102
|
+
mdLen = mdbs.length
|
103
|
+
kLen = kv.key.length
|
104
|
+
b = "".b
|
105
|
+
b = b + [mdLen].pack("n")
|
106
|
+
b = b + mdbs
|
107
|
+
b = b + [kLen].pack("n")
|
108
|
+
b = b + kv.key
|
109
|
+
|
110
|
+
md = Digest::SHA256.new
|
111
|
+
md.update(b)
|
112
|
+
valmd = Digest::SHA256.new
|
113
|
+
valmd.update(kv.value)
|
114
|
+
md.update(valmd.digest)
|
115
|
+
md.digest
|
132
116
|
end
|
133
117
|
|
134
118
|
def leaf_for(d)
|
data/lib/immudb/tx.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright
|
1
|
+
# Copyright 2022 CodeNotary, Inc. All rights reserved.
|
2
2
|
|
3
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
4
|
# you may not use this file except in compliance with the License.
|
@@ -12,35 +12,37 @@
|
|
12
12
|
|
13
13
|
module Immudb
|
14
14
|
class Tx
|
15
|
-
attr_accessor :
|
15
|
+
attr_accessor :header, :entries, :htree
|
16
|
+
|
17
|
+
def initialize
|
18
|
+
@header = nil
|
19
|
+
@entries = nil
|
20
|
+
@htree = nil
|
21
|
+
end
|
22
|
+
|
23
|
+
def tx_entry_digest
|
24
|
+
if @header.version == 0
|
25
|
+
method(:tx_entry_digest_v1_1)
|
26
|
+
elsif @header.version == 1
|
27
|
+
method(:tx_entry_digest_v1_2)
|
28
|
+
else
|
29
|
+
raise VerificationError
|
30
|
+
end
|
31
|
+
end
|
16
32
|
|
17
33
|
def build_hash_tree
|
18
34
|
digests = []
|
35
|
+
tx_entry_digest = self.tx_entry_digest
|
19
36
|
@entries.each do |e|
|
20
|
-
digests << e
|
37
|
+
digests << tx_entry_digest.call(e)
|
21
38
|
end
|
22
39
|
@htree.build_with(digests)
|
40
|
+
root = @htree.root
|
41
|
+
@header.eh = root
|
23
42
|
end
|
24
43
|
|
25
|
-
def
|
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)
|
44
|
+
def index_of(key)
|
42
45
|
kindex = nil
|
43
|
-
# find index of element holding given key
|
44
46
|
@entries.each_with_index do |v, k|
|
45
47
|
if v.key == key
|
46
48
|
kindex = k
|
@@ -48,9 +50,44 @@ module Immudb
|
|
48
50
|
end
|
49
51
|
end
|
50
52
|
if kindex.nil?
|
51
|
-
raise
|
53
|
+
raise VerificationError
|
54
|
+
end
|
55
|
+
kindex
|
56
|
+
end
|
57
|
+
|
58
|
+
def proof(key)
|
59
|
+
kindex = index_of(key)
|
60
|
+
htree.inclusion_proof(kindex)
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def tx_entry_digest_v1_1(e)
|
66
|
+
unless e.md.nil?
|
67
|
+
# TODO raise ErrMetadataUnsupported
|
68
|
+
raise Error, "Metadata not supported"
|
69
|
+
end
|
70
|
+
md = Digest::SHA256.new
|
71
|
+
md.update(e.k)
|
72
|
+
md.update(e.hVal)
|
73
|
+
md.digest
|
74
|
+
end
|
75
|
+
|
76
|
+
def tx_entry_digest_v1_2(e)
|
77
|
+
mdbs = "".b
|
78
|
+
if !e.md.nil?
|
79
|
+
mdbs = e.md.bytes
|
52
80
|
end
|
53
|
-
|
81
|
+
mdLen = mdbs.length
|
82
|
+
b = "".b
|
83
|
+
b = b + [mdLen].pack("n")
|
84
|
+
b = b + mdbs
|
85
|
+
b = b + [e.kLen].pack("n")
|
86
|
+
b = b + e.k
|
87
|
+
md = Digest::SHA256.new
|
88
|
+
md.update(b)
|
89
|
+
md.update(e.hVal)
|
90
|
+
md.digest
|
54
91
|
end
|
55
92
|
end
|
56
93
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# Copyright 2022 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 TxEntry
|
15
|
+
attr_reader :k, :kLen, :md, :vLen, :hVal, :vOff
|
16
|
+
|
17
|
+
def initialize(key, md, vLen, hVal, vOff)
|
18
|
+
@k = key
|
19
|
+
@kLen = key.length
|
20
|
+
@md = md
|
21
|
+
@vLen = vLen
|
22
|
+
@hVal = hVal
|
23
|
+
@vOff = vOff
|
24
|
+
end
|
25
|
+
|
26
|
+
def key
|
27
|
+
@k
|
28
|
+
end
|
29
|
+
|
30
|
+
def metadata
|
31
|
+
@md
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# Copyright 2022 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 TxHeader
|
15
|
+
attr_accessor :iD, :ts, :blTxID, :blRoot, :prevAlh, :version, :metadata, :nentries, :eh
|
16
|
+
|
17
|
+
def initialize
|
18
|
+
@iD = nil
|
19
|
+
@ts = nil
|
20
|
+
@blTxID = nil
|
21
|
+
@blRoot = nil
|
22
|
+
@prevAlh = nil
|
23
|
+
|
24
|
+
@version = nil
|
25
|
+
@metadata = TxMetadata.new
|
26
|
+
|
27
|
+
@nentries = nil
|
28
|
+
@eh = nil
|
29
|
+
end
|
30
|
+
|
31
|
+
def inner_hash
|
32
|
+
md = Digest::SHA256.new
|
33
|
+
md.update([@ts].pack("Q>"))
|
34
|
+
md.update([@version].pack("n"))
|
35
|
+
if @version == 0
|
36
|
+
md.update([@nentries].pack("n"))
|
37
|
+
elsif @version == 1
|
38
|
+
mdbs = "".b
|
39
|
+
if !@metadata.nil?
|
40
|
+
mdbs = @metadata.bytes
|
41
|
+
end
|
42
|
+
md.update([mdbs.length].pack("n"))
|
43
|
+
md.update(mdbs)
|
44
|
+
md.update([@nentries].pack("N"))
|
45
|
+
else
|
46
|
+
raise VerificationError, "missing tx hash calculation method for version #{@version}"
|
47
|
+
end
|
48
|
+
md.update(@eh)
|
49
|
+
md.update([@blTxID].pack("Q>"))
|
50
|
+
md.update(@blRoot)
|
51
|
+
md.digest
|
52
|
+
end
|
53
|
+
|
54
|
+
def alh
|
55
|
+
md = Digest::SHA256.new
|
56
|
+
md.update([@iD].pack("Q>"))
|
57
|
+
md.update(@prevAlh)
|
58
|
+
md.update(inner_hash)
|
59
|
+
md.digest
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
data/lib/immudb/version.rb
CHANGED
data/lib/immudb.rb
CHANGED
@@ -4,25 +4,29 @@ require "openssl"
|
|
4
4
|
require "time"
|
5
5
|
|
6
6
|
# grpc
|
7
|
-
require "immudb/grpc/schema_pb"
|
8
7
|
require "immudb/grpc/schema_services_pb"
|
9
8
|
|
10
9
|
# modules
|
11
10
|
require "immudb/client"
|
12
11
|
require "immudb/constants"
|
12
|
+
require "immudb/database"
|
13
13
|
require "immudb/dual_proof"
|
14
|
+
require "immudb/entry_spec"
|
14
15
|
require "immudb/htree"
|
15
16
|
require "immudb/inclusion_proof"
|
16
17
|
require "immudb/interceptor"
|
17
18
|
require "immudb/kv"
|
19
|
+
require "immudb/kv_metadata"
|
18
20
|
require "immudb/linear_proof"
|
19
21
|
require "immudb/root_service"
|
22
|
+
require "immudb/schema"
|
20
23
|
require "immudb/sql_result"
|
21
24
|
require "immudb/state"
|
22
25
|
require "immudb/store"
|
23
26
|
require "immudb/tx"
|
27
|
+
require "immudb/tx_entry"
|
28
|
+
require "immudb/tx_header"
|
24
29
|
require "immudb/tx_metadata"
|
25
|
-
require "immudb/txe"
|
26
30
|
require "immudb/version"
|
27
31
|
|
28
32
|
module Immudb
|