forked from google/trillian
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtrillian_log_api.proto
424 lines (370 loc) · 14.2 KB
/
trillian_log_api.proto
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
// Copyright 2016 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
syntax = "proto3";
package trillian;
option go_package = "github.com/google/trillian";
option java_multiple_files = true;
option java_outer_classname = "TrillianLogApiProto";
option java_package = "com.google.trillian.proto";
import "google/api/annotations.proto";
import "google/protobuf/timestamp.proto";
import "google/rpc/status.proto";
import "trillian.proto";
// Provides access to a Verifiable Log data structure as defined in the
// [Verifiable Data Structures](docs/papers/VerifiableDataStructures.pdf) paper.
//
// The API supports adding new entries to be integrated into the log's tree. It
// does not provide arbitrary tree modifications. Additionally, it has read
// operations such as obtaining tree leaves, inclusion/consistency proofs etc.
service TrillianLog {
// Adds a single leaf to the queue.
rpc QueueLeaf(QueueLeafRequest) returns (QueueLeafResponse) {
option (google.api.http) = {
post: "/v1beta1/logs/{log_id}/leaves"
body: "*"
};
}
// Adds a single leaf with an assigned sequence number.
rpc AddSequencedLeaf(AddSequencedLeafRequest)
returns (AddSequencedLeafResponse) {
option (google.api.http) = {
post: "/v1beta1/logs/{log_id}/leaves:sequenced"
body: "*"
};
}
//
// No direct equivalent at the storage level.
//
// Returns inclusion proof for a leaf with a given index in a given tree.
// If the requested tree_size is larger than the server is aware of,
// the response will include the known log root and an empty proof.
rpc GetInclusionProof(GetInclusionProofRequest)
returns (GetInclusionProofResponse) {
option (google.api.http) = {
get: "/v1beta1/logs/{log_id}/leaves/{leaf_index}:inclusion_proof"
};
}
// Returns inclusion proof for a leaf with a given Merkle hash in a given
// tree.
rpc GetInclusionProofByHash(GetInclusionProofByHashRequest)
returns (GetInclusionProofByHashResponse) {
option (google.api.http) = {
get: "/v1beta1/logs/{log_id}/leaves:inclusion_by_hash"
};
}
// Returns consistency proof between two versions of a given tree.
// If the requested tree size is larger than the server is aware of,
// the response will include the known log root and an empty proof.
rpc GetConsistencyProof(GetConsistencyProofRequest)
returns (GetConsistencyProofResponse) {
option (google.api.http) = {
get: "/v1beta1/logs/{log_id}:consistency_proof"
};
}
// Returns the latest signed log root for a given tree. Corresponds to the
// ReadOnlyLogTreeTX.LatestSignedLogRoot storage interface. The server will
// return InvalidArgument if first_tree_size is greater than the
// LatestSignedLogRoot available to that server.
rpc GetLatestSignedLogRoot(GetLatestSignedLogRootRequest)
returns (GetLatestSignedLogRootResponse) {
option (google.api.http) = {
get: "/v1beta1/logs/{log_id}/roots:latest"
};
}
// Returns the total number of leaves that have been integrated into the
// given tree. Corresponds to the ReadOnlyLogTreeTX.GetSequencedLeafCount
// storage interface.
// DO NOT USE - FOR DEBUGGING/TEST ONLY
rpc GetSequencedLeafCount(GetSequencedLeafCountRequest)
returns (GetSequencedLeafCountResponse) {
option (google.api.http) = {
get: "/v1beta1/logs/{log_id}/leaves:sequenced_count"
};
}
// Returns log entry and the corresponding inclusion proof for a given leaf
// index in a given tree. If the requested tree is unavailable but the leaf is
// in scope for the current tree, return a proof in that tree instead.
rpc GetEntryAndProof(GetEntryAndProofRequest)
returns (GetEntryAndProofResponse) {
option (google.api.http) = {
get: "/v1beta1/logs/{log_id}/leaves/{leaf_index}"
};
}
//
// Initialisation APIs.
//
rpc InitLog(InitLogRequest) returns (InitLogResponse) {
option (google.api.http) = {
post: "/v1beta1/logs/{log_id}:init"
};
}
//
// Batch APIs. Correspond to `storage.ReadOnlyLogTreeTX` batch queries.
//
// Adds a batch of leaves to the queue.
rpc QueueLeaves(QueueLeavesRequest) returns (QueueLeavesResponse) {}
// Stores leaves from the provided batch and associates them with the log
// positions according to the `LeafIndex` field. The indices must be
// contiguous.
rpc AddSequencedLeaves(AddSequencedLeavesRequest)
returns (AddSequencedLeavesResponse) {}
// Returns a batch of leaves located in the provided positions.
rpc GetLeavesByIndex(GetLeavesByIndexRequest)
returns (GetLeavesByIndexResponse) {}
// Returns a batch of leaves in a sequential range.
rpc GetLeavesByRange(GetLeavesByRangeRequest)
returns (GetLeavesByRangeResponse) {}
// Returns a batch of leaves by their `merkle_leaf_hash` values.
rpc GetLeavesByHash(GetLeavesByHashRequest)
returns (GetLeavesByHashResponse) {}
}
// ChargeTo describes the user(s) associated with the request whose quota should
// be checked and charged.
message ChargeTo {
// user is a list of personality-defined strings.
// Trillian will treat them as /User/%{user}/... keys when checking and
// charging quota.
// If one or more of the specified users has insufficient quota, the
// request will be denied.
//
// As an example, a Certificate Transparency frontend might set the following
// user strings when sending a QueueLeaves request to the Trillian log:
// - The requesting IP address.
// This would limit the number of requests per IP.
// - The "intermediate-<hash>" for each of the intermediate certificates in
// the submitted chain.
// This would have the effect of limiting the rate of submissions under
// a given intermediate/root.
repeated string user = 1;
}
message QueueLeafRequest {
int64 log_id = 1;
LogLeaf leaf = 2;
ChargeTo charge_to = 3;
}
message QueueLeafResponse {
QueuedLogLeaf queued_leaf = 2;
}
message AddSequencedLeafRequest {
int64 log_id = 1;
LogLeaf leaf = 2;
ChargeTo charge_to = 3;
}
message AddSequencedLeafResponse {
QueuedLogLeaf result = 2;
}
message GetInclusionProofRequest {
int64 log_id = 1;
int64 leaf_index = 2;
int64 tree_size = 3;
ChargeTo charge_to = 4;
}
message GetInclusionProofResponse {
// The proof field may be empty if the requested tree_size was larger
// than that available at the server (e.g. because there is skew between
// server instances, and an earlier client request was processed by a
// more up-to-date instance). In this case, the signed_log_root
// field will indicate the tree size that the server is aware of, and
// the proof field will be empty.
Proof proof = 2;
SignedLogRoot signed_log_root = 3;
}
message GetInclusionProofByHashRequest {
int64 log_id = 1;
bytes leaf_hash = 2;
int64 tree_size = 3;
bool order_by_sequence = 4;
ChargeTo charge_to = 5;
}
message GetInclusionProofByHashResponse {
// Logs can potentially contain leaves with duplicate hashes so it's possible
// for this to return multiple proofs.
repeated Proof proof = 2;
SignedLogRoot signed_log_root = 3;
}
message GetConsistencyProofRequest {
int64 log_id = 1;
int64 first_tree_size = 2;
int64 second_tree_size = 3;
ChargeTo charge_to = 4;
}
message GetConsistencyProofResponse {
// The proof field may be empty if the requested tree_size was larger
// than that available at the server (e.g. because there is skew between
// server instances, and an earlier client request was processed by a
// more up-to-date instance). In this case, the signed_log_root
// field will indicate the tree size that the server is aware of, and
// the proof field will be empty.
Proof proof = 2;
SignedLogRoot signed_log_root = 3;
}
message GetLatestSignedLogRootRequest {
int64 log_id = 1;
ChargeTo charge_to = 2;
// If first_tree_size is non-zero, the response will include a consistency
// proof between first_tree_size and the new tree size (if not smaller).
int64 first_tree_size = 3;
}
message GetLatestSignedLogRootResponse {
SignedLogRoot signed_log_root = 2;
// proof is filled if first_tree_size in GetLatestSignedLogRootRequest is
// non-zero.
Proof proof = 3;
}
message GetSequencedLeafCountRequest {
int64 log_id = 1;
ChargeTo charge_to = 2;
}
message GetSequencedLeafCountResponse {
int64 leaf_count = 2;
}
message GetEntryAndProofRequest {
int64 log_id = 1;
int64 leaf_index = 2;
int64 tree_size = 3;
ChargeTo charge_to = 4;
}
message GetEntryAndProofResponse {
Proof proof = 2;
LogLeaf leaf = 3;
SignedLogRoot signed_log_root = 4;
}
message InitLogRequest {
int64 log_id = 1;
ChargeTo charge_to = 2;
}
message InitLogResponse {
SignedLogRoot created = 1;
}
message QueueLeavesRequest {
int64 log_id = 1;
repeated LogLeaf leaves = 2;
ChargeTo charge_to = 3;
}
message QueueLeavesResponse {
// Same number and order as in the corresponding request.
repeated QueuedLogLeaf queued_leaves = 2;
}
message AddSequencedLeavesRequest {
int64 log_id = 1;
repeated LogLeaf leaves = 2;
ChargeTo charge_to = 4;
}
message AddSequencedLeavesResponse {
// Same number and order as in the corresponding request.
repeated QueuedLogLeaf results = 2;
}
message GetLeavesByIndexRequest {
int64 log_id = 1;
repeated int64 leaf_index = 2;
ChargeTo charge_to = 5;
}
message GetLeavesByIndexResponse {
// TODO(gbelvin) reply with error codes. Reuse QueuedLogLeaf?
repeated LogLeaf leaves = 2;
SignedLogRoot signed_log_root = 3;
}
message GetLeavesByRangeRequest {
int64 log_id = 1;
int64 start_index = 2;
int64 count = 3;
ChargeTo charge_to = 4;
}
message GetLeavesByRangeResponse {
// Returned log leaves starting from the `start_index` of the request, in
// order. There may be fewer than `request.count` leaves returned, if the
// requested range extended beyond the size of the tree or if the server opted
// to return fewer leaves than requested.
repeated LogLeaf leaves = 1;
SignedLogRoot signed_log_root = 2;
}
message GetLeavesByHashRequest {
int64 log_id = 1;
repeated bytes leaf_hash = 2;
bool order_by_sequence = 3;
ChargeTo charge_to = 5;
}
message GetLeavesByHashResponse {
// TODO(gbelvin) reply with error codes. Reuse QueuedLogLeaf?
repeated LogLeaf leaves = 2;
SignedLogRoot signed_log_root = 3;
}
// A result of submitting an entry to the log. Output only.
// TODO(pavelkalinnikov): Consider renaming it to AddLogLeafResult or the like.
message QueuedLogLeaf {
// The leaf as it was stored by Trillian. Empty unless `status.code` is:
// - `google.rpc.OK`: the `leaf` data is the same as in the request.
// - `google.rpc.ALREADY_EXISTS` or 'google.rpc.FAILED_PRECONDITION`: the
// `leaf` is the conflicting one already in the log.
LogLeaf leaf = 1;
// The status of adding the leaf.
// - `google.rpc.OK`: successfully added.
// - `google.rpc.ALREADY_EXISTS`: the leaf is a duplicate of an already
// existing one. Either `leaf_identity_hash` is the same in the `LOG`
// mode, or `leaf_index` in the `PREORDERED_LOG`.
// - `google.rpc.FAILED_PRECONDITION`: A conflicting entry is already
// present in the log, e.g., same `leaf_index` but different `leaf_data`.
google.rpc.Status status = 2;
}
// A leaf of the log's Merkle tree, corresponds to a single log entry. Each leaf
// has a unique `leaf_index` in the scope of this tree.
message LogLeaf {
// Output only. The hash over `leaf_data`.
bytes merkle_leaf_hash = 1;
// Required. The arbitrary data associated with this log entry. Validity of
// this field is governed by the call site (personality).
bytes leaf_value = 2;
// The arbitrary metadata, e.g., a timestamp.
bytes extra_data = 3;
// Output only in `LOG` mode. Required in `PREORDERED_LOG` mode.
// The index of the leaf in the Merkle tree, i.e., the position of the
// corresponding entry in the log. For normal logs this value will be
// assigned by the LogSigner.
int64 leaf_index = 4;
// The hash over the identity of this leaf. If empty, assumed to be the same
// as `merkle_leaf_hash`. It is a mechanism for the personality to provide a
// hint to Trillian that two leaves should be considered "duplicates" even
// though their `leaf_value`s differ.
//
// E.g., in a CT personality multiple `add-chain` calls for an identical
// certificate would produce differing `leaf_data` bytes (due to the
// presence of SCT elements), with just this information Trillian would be
// unable to determine that. Within the context of the CT personality, these
// entries are dupes, so it sets `leaf_identity_hash` to `H(cert)`, which
// allows Trillian to detect the duplicates.
//
// Continuing the CT example, for a CT mirror personality (which must allow
// dupes since the source log could contain them), the part of the
// personality which fetches and submits the entries might set
// `leaf_identity_hash` to `H(leaf_index||cert)`.
// TODO(pavelkalinnikov): Consider instead using `H(cert)` and allowing
// identity hash dupes in `PREORDERED_LOG` mode, for it can later be
// upgraded to `LOG` which will need to correctly detect duplicates with
// older entries when new ones get queued.
bytes leaf_identity_hash = 5;
// Output only. The time at which this leaf was passed to `QueueLeaves`.
// This value will be determined and set by the LogServer. Equals zero if
// the entry was submitted without queuing.
google.protobuf.Timestamp queue_timestamp = 6;
// Output only. The time at which this leaf was integrated into the tree.
// This value will be determined and set by the LogSigner.
google.protobuf.Timestamp integrate_timestamp = 7;
}
// A consistency or inclusion proof for a Merkle tree. Output only.
message Proof {
int64 leaf_index = 1;
// Contained internal node details, no longer provided to clients.
reserved 2;
repeated bytes hashes = 3;
}