@derec-alliance/nodejs 0.0.1-alpha.6 → 0.0.1-alpha.8
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.
- package/README.md +401 -71
- package/derec_library.d.ts +369 -221
- package/derec_library.js +1376 -400
- package/derec_library_bg.wasm +0 -0
- package/derec_library_bg.wasm.d.ts +77 -11
- package/index.d.ts +1214 -0
- package/index.js +106 -0
- package/package.json +6 -4
package/index.d.ts
ADDED
|
@@ -0,0 +1,1214 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// Copyright (c) 2026 DeRec Alliance. All rights reserved.
|
|
3
|
+
|
|
4
|
+
export interface SecretStore {
|
|
5
|
+
load(
|
|
6
|
+
secretId: string,
|
|
7
|
+
channelId: string,
|
|
8
|
+
kind: 0 | 1 | 2,
|
|
9
|
+
): Promise<Uint8Array | null | undefined>;
|
|
10
|
+
/**
|
|
11
|
+
* Load secrets of the same `kind` for several channels in one call,
|
|
12
|
+
* scoped to `secretId`. Must return an array with one entry per input
|
|
13
|
+
* id, in the same order, using `null` (or `undefined`) for channels
|
|
14
|
+
* with no stored secret of `kind`.
|
|
15
|
+
*/
|
|
16
|
+
loadMany(
|
|
17
|
+
secretId: string,
|
|
18
|
+
channelIds: string[],
|
|
19
|
+
kind: 0 | 1 | 2,
|
|
20
|
+
missingPolicy: "skip" | "fail",
|
|
21
|
+
): Promise<Array<Uint8Array | null | undefined>>;
|
|
22
|
+
save(
|
|
23
|
+
secretId: string,
|
|
24
|
+
channelId: string,
|
|
25
|
+
kind: 0 | 1 | 2,
|
|
26
|
+
value: Uint8Array,
|
|
27
|
+
): Promise<void>;
|
|
28
|
+
remove(secretId: string, channelId: string, kind: 0 | 1 | 2): Promise<void>;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface ChannelStore {
|
|
32
|
+
load(secretId: string, channelId: string): Promise<Uint8Array | null | undefined>;
|
|
33
|
+
save(secretId: string, channelId: string, bytes: Uint8Array): Promise<void>;
|
|
34
|
+
listChannels(secretId: string): Promise<string[]>;
|
|
35
|
+
remove(secretId: string, channelId: string): Promise<boolean>;
|
|
36
|
+
linkChannel(
|
|
37
|
+
secretId: string,
|
|
38
|
+
channelId: string,
|
|
39
|
+
linkedChannelId: string,
|
|
40
|
+
): Promise<void>;
|
|
41
|
+
linkedChannels(secretId: string, channelId: string): Promise<string[]>;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface Share {
|
|
45
|
+
secretId: string;
|
|
46
|
+
version: number;
|
|
47
|
+
bytes: Uint8Array;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface ShareStore {
|
|
51
|
+
load(secretId: string, channelId: string, versions: number[]): Promise<Share[]>;
|
|
52
|
+
loadMany(
|
|
53
|
+
secretId: string,
|
|
54
|
+
channelIds: string[],
|
|
55
|
+
versions: number[],
|
|
56
|
+
): Promise<Share[]>;
|
|
57
|
+
loadAll(secretId: string, channelIds: string[]): Promise<Share[]>;
|
|
58
|
+
save(secretId: string, channelId: string, share: Share): Promise<void>;
|
|
59
|
+
latestVersion(secretId: string): Promise<number | null>;
|
|
60
|
+
removeChannel(secretId: string, channelId: string): Promise<void>;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export interface UserSecretEntry {
|
|
64
|
+
id: Uint8Array;
|
|
65
|
+
name: string;
|
|
66
|
+
data: Uint8Array;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export interface UserSecrets {
|
|
70
|
+
version: number;
|
|
71
|
+
secrets: UserSecretEntry[];
|
|
72
|
+
description?: string;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Persistence for the user-facing secret contents, keyed by `secretId`.
|
|
77
|
+
* One `secretId` maps to at most one stored snapshot — the most recent
|
|
78
|
+
* `start(ProtectSecret)` value. Read back by the pair-completion
|
|
79
|
+
* auto-publish hook so freshly-paired peers receive the current secret.
|
|
80
|
+
*/
|
|
81
|
+
export interface UserSecretStore {
|
|
82
|
+
loadLatest(secretId: string): Promise<UserSecrets | null | undefined>;
|
|
83
|
+
saveLatest(secretId: string, value: UserSecrets): Promise<void>;
|
|
84
|
+
remove(secretId: string): Promise<void>;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* In-flight orchestrator state persistence. The library treats item
|
|
89
|
+
* payloads as opaque JSON blobs — `save` writes the blob, `load`
|
|
90
|
+
* returns the exact blob it received, `remove` drops the row, and
|
|
91
|
+
* `loadAll` returns every blob whose `kind` matches the requested
|
|
92
|
+
* category (`0` = PendingVerification, `1` = PendingRecovery,
|
|
93
|
+
* `2` = PendingUnpair, `3` = SharingRound).
|
|
94
|
+
*
|
|
95
|
+
* Rows are keyed by `(secretId, StateKey)` — the `keyJson` buffer is
|
|
96
|
+
* a JSON object `{ kind, channel_id?, version? }` matching the `kind`
|
|
97
|
+
* numbering above. The library will `save`/`load`/`remove` under the
|
|
98
|
+
* same key across a session, so implementations can hash the entire
|
|
99
|
+
* `keyJson` buffer or unpack its fields (`kind` + `channel_id` +
|
|
100
|
+
* `version`) as the composite key.
|
|
101
|
+
*
|
|
102
|
+
* Save is full-replacement upsert — accumulator-style state
|
|
103
|
+
* (PendingRecovery and SharingRound) grows via load-modify-save cycles
|
|
104
|
+
* from the library; no per-row append primitive is required.
|
|
105
|
+
*/
|
|
106
|
+
export interface StateStore {
|
|
107
|
+
save(secretId: string, itemJson: Uint8Array): Promise<void>;
|
|
108
|
+
load(
|
|
109
|
+
secretId: string,
|
|
110
|
+
keyJson: Uint8Array,
|
|
111
|
+
): Promise<Uint8Array | null | undefined>;
|
|
112
|
+
remove(secretId: string, keyJson: Uint8Array): Promise<boolean>;
|
|
113
|
+
loadAll(secretId: string, kind: 0 | 1 | 2 | 3): Promise<Uint8Array[]>;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export interface Transport {
|
|
117
|
+
send(endpoint: { protocol: string; uri: string }, message: Uint8Array): Promise<void>;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export enum SenderKind {
|
|
121
|
+
Owner = 0,
|
|
122
|
+
Helper = 1,
|
|
123
|
+
ReplicaSource = 3,
|
|
124
|
+
ReplicaDestination = 4,
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Selects how the initiator's public encryption material is delivered in a
|
|
129
|
+
* `ContactMessage`.
|
|
130
|
+
*
|
|
131
|
+
* - `InlineKeys` (default): keys are embedded in the contact itself.
|
|
132
|
+
* - `HashedKeys`: only a SHA-384 commitment to the keys is in the contact;
|
|
133
|
+
* the scanner must fetch the actual keys over the wire via the `PrePair`
|
|
134
|
+
* round-trip and verify them against the commitment before pairing.
|
|
135
|
+
* - `NoKeys`: no key material and no commitment. The contact carries only
|
|
136
|
+
* `channel_id`, `nonce`, and `transport_protocol` — small enough to be
|
|
137
|
+
* hand-typed or dictated. Keys are generated on the fly by the contact
|
|
138
|
+
* creator when the `PrePairRequest` arrives; the scanner accepts them
|
|
139
|
+
* without cryptographic verification. Trust rests entirely on the OOB
|
|
140
|
+
* delivery channel being fully trusted (e.g. a verified email from an
|
|
141
|
+
* already-KYC-authenticated institution). Applications MUST rate-limit
|
|
142
|
+
* inbound `PrePairRequest`s per channel and expire outstanding NoKeys
|
|
143
|
+
* contacts on a short timer.
|
|
144
|
+
*/
|
|
145
|
+
export enum ContactMode {
|
|
146
|
+
InlineKeys = 0,
|
|
147
|
+
HashedKeys = 1,
|
|
148
|
+
NoKeys = 2,
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export enum FlowKind {
|
|
152
|
+
Pairing = 0,
|
|
153
|
+
Discovery = 1,
|
|
154
|
+
ProtectSecret = 2,
|
|
155
|
+
VerifyShares = 3,
|
|
156
|
+
RecoverSecret = 4,
|
|
157
|
+
Unpair = 5,
|
|
158
|
+
UpdateChannelInfo = 6,
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export type UnpairAck = "required" | "not_required";
|
|
162
|
+
|
|
163
|
+
export interface ContactMessage {
|
|
164
|
+
channel_id: bigint;
|
|
165
|
+
/** `ContactMode` numeric value (0 = INLINE_KEYS, 1 = HASHED_KEYS, 2 = NO_KEYS). */
|
|
166
|
+
contact_mode: number;
|
|
167
|
+
transport_protocol?: TransportProtocol;
|
|
168
|
+
nonce: bigint;
|
|
169
|
+
/** Present only when `contact_mode === ContactMode.InlineKeys`. */
|
|
170
|
+
mlkem_encapsulation_key?: Uint8Array;
|
|
171
|
+
/** Present only when `contact_mode === ContactMode.InlineKeys`. */
|
|
172
|
+
ecies_public_key?: Uint8Array;
|
|
173
|
+
/** Present only when `contact_mode === ContactMode.HashedKeys`. SHA-384 digest (48 bytes). */
|
|
174
|
+
contact_binding_hash?: Uint8Array;
|
|
175
|
+
timestamp?: Timestamp;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export interface UserSecret {
|
|
179
|
+
|
|
180
|
+
id: Uint8Array;
|
|
181
|
+
name: string;
|
|
182
|
+
data: Uint8Array;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export type Target = bigint | bigint[] | null;
|
|
186
|
+
|
|
187
|
+
export interface PairingParams {
|
|
188
|
+
kind: SenderKind;
|
|
189
|
+
contact: ContactMessage;
|
|
190
|
+
|
|
191
|
+
peerCommunicationInfo?: Record<string, string>;
|
|
192
|
+
}
|
|
193
|
+
export interface DiscoveryParams {
|
|
194
|
+
target?: Target;
|
|
195
|
+
}
|
|
196
|
+
export interface ProtectSecretParams {
|
|
197
|
+
secrets: UserSecret[];
|
|
198
|
+
description?: string;
|
|
199
|
+
}
|
|
200
|
+
export interface VerifySharesParams {
|
|
201
|
+
secretId: bigint | string;
|
|
202
|
+
version: number;
|
|
203
|
+
target?: Target;
|
|
204
|
+
}
|
|
205
|
+
export interface RecoverSecretParams {
|
|
206
|
+
|
|
207
|
+
secretId: bigint | string;
|
|
208
|
+
version: number;
|
|
209
|
+
}
|
|
210
|
+
export interface UnpairParams {
|
|
211
|
+
channel_id: string;
|
|
212
|
+
|
|
213
|
+
memo?: string;
|
|
214
|
+
}
|
|
215
|
+
export interface UpdateChannelInfoParams {
|
|
216
|
+
target?: Target;
|
|
217
|
+
|
|
218
|
+
/** New communication-info map. `null`/absent leaves the peer's stored
|
|
219
|
+
* map untouched; pass an empty object to clear it. */
|
|
220
|
+
communication_info?: Record<string, string>;
|
|
221
|
+
|
|
222
|
+
/** New transport endpoint. Absent leaves it untouched. */
|
|
223
|
+
transport_protocol?: { uri: string; protocol: number };
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
export type DeRecEvent =
|
|
227
|
+
| {
|
|
228
|
+
type: "PairingCompleted";
|
|
229
|
+
/** Long-term `channel_id` both peers atomically rotated to at handshake completion. */
|
|
230
|
+
channel_id: string;
|
|
231
|
+
/** Transient `channel_id` used only during pairing (the one that traveled on the ContactMessage). No longer resolves in library state. */
|
|
232
|
+
pairing_channel_id: string;
|
|
233
|
+
kind: SenderKind;
|
|
234
|
+
peer_communication_info?: Record<string, string>;
|
|
235
|
+
}
|
|
236
|
+
| {
|
|
237
|
+
type: "ActionRequired";
|
|
238
|
+
channel_id: string;
|
|
239
|
+
|
|
240
|
+
action: Uint8Array;
|
|
241
|
+
|
|
242
|
+
action_kind: string;
|
|
243
|
+
peer_communication_info?: Record<string, string>;
|
|
244
|
+
|
|
245
|
+
sender_kind?: SenderKind;
|
|
246
|
+
|
|
247
|
+
version?: number;
|
|
248
|
+
share_description?: string;
|
|
249
|
+
|
|
250
|
+
share_secret_id?: string;
|
|
251
|
+
}
|
|
252
|
+
| { type: "ShareStored"; channel_id: string; version: number }
|
|
253
|
+
| { type: "ShareConfirmed"; channel_id: string; version: number }
|
|
254
|
+
| { type: "ShareRejected"; channel_id: string; version: number; status: number; memo: string }
|
|
255
|
+
| { type: "SharingComplete"; version: number; confirmed_count: number; failed_count: number; threshold_met: boolean }
|
|
256
|
+
| { type: "ShareVerified"; channel_id: string; version: number }
|
|
257
|
+
| {
|
|
258
|
+
type: "SecretsDiscovered";
|
|
259
|
+
channel_id: string;
|
|
260
|
+
|
|
261
|
+
secrets: Array<{ secret_id: string; versions: Array<{ version: number; description: string }> }>;
|
|
262
|
+
}
|
|
263
|
+
| { type: "RecoveryShareReceived"; channel_id: string; shares_received: number }
|
|
264
|
+
| { type: "RecoveryShareError"; channel_id: string; shares_received: number; error: string }
|
|
265
|
+
/** Recovery completed — the typed `Secret` snapshot the owner
|
|
266
|
+
* originally protected. Mirrors `ReplicaSecretReceived.secret`:
|
|
267
|
+
* `secrets` is the user-facing `Vec<UserSecret>` the application
|
|
268
|
+
* fed to `start(FlowKind.ProtectSecret)`; `helpers`, `replicas`
|
|
269
|
+
* and `owner_replica_id` are the roster snapshot captured at
|
|
270
|
+
* distribution time. The library handles the two-stage
|
|
271
|
+
* `DeRecSecret` → `Secret` protobuf decode internally. */
|
|
272
|
+
| {
|
|
273
|
+
type: "SecretRecovered";
|
|
274
|
+
secret: {
|
|
275
|
+
helpers: Array<{
|
|
276
|
+
channel_id: string;
|
|
277
|
+
transport_uri: string;
|
|
278
|
+
shared_key: Uint8Array;
|
|
279
|
+
communication_info: Record<string, string>;
|
|
280
|
+
}>;
|
|
281
|
+
secrets: Array<{
|
|
282
|
+
id: Uint8Array;
|
|
283
|
+
name: string;
|
|
284
|
+
data: Uint8Array;
|
|
285
|
+
}>;
|
|
286
|
+
/** Replica composite. Absent when this `secret_id` has no
|
|
287
|
+
* replica setup. Carries the destination roster, the
|
|
288
|
+
* per-helper share map, and the 32-byte group key. Required
|
|
289
|
+
* by `restore` to rebuild replica channels without re-pairing. */
|
|
290
|
+
replicas?: {
|
|
291
|
+
replicas: Array<{
|
|
292
|
+
channel_id: string;
|
|
293
|
+
transport_uri: string;
|
|
294
|
+
communication_info: Record<string, string>;
|
|
295
|
+
replica_id: string;
|
|
296
|
+
sender_kind: number;
|
|
297
|
+
}>;
|
|
298
|
+
shared_key: Uint8Array;
|
|
299
|
+
};
|
|
300
|
+
owner_replica_id: string;
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
| { type: "Unpaired"; channel_id: string }
|
|
305
|
+
|
|
306
|
+
| { type: "UnpairRejected"; channel_id: string; status: number; memo: string }
|
|
307
|
+
|
|
308
|
+
/** Contact creator answered the scanner's `PrePairRequest` with a
|
|
309
|
+
* non-Ok status (HashedKeys flow). Distinct from a cryptographic
|
|
310
|
+
* hash mismatch, which surfaces as a thrown error from `process()`. */
|
|
311
|
+
| { type: "PrePairRejected"; channel_id: string; status: number; memo: string }
|
|
312
|
+
|
|
313
|
+
/** Fires alongside `PairingCompleted` on replica-mode pair handshakes.
|
|
314
|
+
* `peer_replica_id` is the peer's hex-encoded `u64` (matches the wire
|
|
315
|
+
* `derec.replica_id` representation). The local side's role
|
|
316
|
+
* (`ReplicaSource` vs `ReplicaDestination`) is on the persisted
|
|
317
|
+
* channel record — replica pairings are unidirectional, so there is
|
|
318
|
+
* no separate "role in pair" field. */
|
|
319
|
+
| {
|
|
320
|
+
type: "ReplicaPaired";
|
|
321
|
+
channel_id: string;
|
|
322
|
+
peer_replica_id: string;
|
|
323
|
+
}
|
|
324
|
+
/** A `ReplicaSource` peer pushed a secret sync on a
|
|
325
|
+
* `ReplicaDestination` channel. The library decoded the
|
|
326
|
+
* `ReplicaSecretPayload`; the app installs `secret.secrets` and
|
|
327
|
+
* optionally uses `shares` for recovery. `from_replica_id` and the
|
|
328
|
+
* `replica_id` fields inside `secret` are hex-encoded `u64`. */
|
|
329
|
+
| {
|
|
330
|
+
type: "ReplicaSecretReceived";
|
|
331
|
+
channel_id: string;
|
|
332
|
+
from_replica_id: string;
|
|
333
|
+
secret_id: string;
|
|
334
|
+
version: number;
|
|
335
|
+
secret: {
|
|
336
|
+
helpers: Array<{
|
|
337
|
+
channel_id: string;
|
|
338
|
+
transport_uri: string;
|
|
339
|
+
shared_key: Uint8Array;
|
|
340
|
+
communication_info: Record<string, string>;
|
|
341
|
+
}>;
|
|
342
|
+
secrets: Array<{
|
|
343
|
+
id: Uint8Array;
|
|
344
|
+
name: string;
|
|
345
|
+
data: Uint8Array;
|
|
346
|
+
}>;
|
|
347
|
+
/** Replica composite. Absent when this `secret_id` has no
|
|
348
|
+
* replica setup. The same shape as `SecretRecovered.secret.replicas`. */
|
|
349
|
+
replicas?: {
|
|
350
|
+
replicas: Array<{
|
|
351
|
+
channel_id: string;
|
|
352
|
+
transport_uri: string;
|
|
353
|
+
communication_info: Record<string, string>;
|
|
354
|
+
replica_id: string;
|
|
355
|
+
sender_kind: number;
|
|
356
|
+
}>;
|
|
357
|
+
shared_key: Uint8Array;
|
|
358
|
+
};
|
|
359
|
+
owner_replica_id: string;
|
|
360
|
+
};
|
|
361
|
+
shares: Array<{
|
|
362
|
+
channel_id: string;
|
|
363
|
+
committed_share: Uint8Array;
|
|
364
|
+
}>;
|
|
365
|
+
}
|
|
366
|
+
/** Peer's ack of a secret sync we sent. `status` is the `StatusEnum`
|
|
367
|
+
* integer (0 = Ok), `memo` is the peer's explanation. */
|
|
368
|
+
| {
|
|
369
|
+
type: "ReplicaSecretAcked";
|
|
370
|
+
channel_id: string;
|
|
371
|
+
from_replica_id: string;
|
|
372
|
+
secret_id: string;
|
|
373
|
+
version: number;
|
|
374
|
+
status: number;
|
|
375
|
+
memo: string;
|
|
376
|
+
}
|
|
377
|
+
/** A peer announced an updated `communication_info` map and/or
|
|
378
|
+
* transport endpoint via `start(FlowKind.UpdateChannelInfo)`.
|
|
379
|
+
* Surfaces on both sides — the initiator sees its own update echo
|
|
380
|
+
* back after the responder accepts. */
|
|
381
|
+
| {
|
|
382
|
+
type: "ChannelInfoUpdated";
|
|
383
|
+
channel_id: string;
|
|
384
|
+
}
|
|
385
|
+
/** The peer answered our outbound `UpdateChannelInfo` with a
|
|
386
|
+
* non-`Ok` status. Local state is not rolled back — the app decides
|
|
387
|
+
* whether to retry. */
|
|
388
|
+
| {
|
|
389
|
+
type: "ChannelInfoUpdateRejected";
|
|
390
|
+
channel_id: string;
|
|
391
|
+
status: number;
|
|
392
|
+
memo: string;
|
|
393
|
+
}
|
|
394
|
+
/** Emitted by `process()` in place of `ActionRequired` when the
|
|
395
|
+
* configured {@link AutoAcceptPolicy} opts in to the inbound
|
|
396
|
+
* action's flow. The same event vec carries the flow's completion
|
|
397
|
+
* events (e.g. `ShareStored`, `PairingCompleted`). Use this purely
|
|
398
|
+
* for observability — no further action is required. `action_kind`
|
|
399
|
+
* is the same label vocabulary as `ActionRequired.action_kind`
|
|
400
|
+
* (`"Pairing"`, `"StoreShare"`, …). */
|
|
401
|
+
| { type: "AutoAccepted"; channel_id: string; action_kind: string }
|
|
402
|
+
| { type: "NoOp" }
|
|
403
|
+
/** A pairing handshake was dispatched successfully. `kind` is the
|
|
404
|
+
* local party's role — same value the subsequent `PairingCompleted`
|
|
405
|
+
* will carry. Emitted by `start(Pairing)`. */
|
|
406
|
+
| { type: "PairingStarted"; channel_id: string; kind: SenderKind }
|
|
407
|
+
/** A discovery request was dispatched to `channel_id`. Emitted per
|
|
408
|
+
* targeted helper by `start(Discovery)`. */
|
|
409
|
+
| { type: "DiscoveryStarted"; channel_id: string }
|
|
410
|
+
/** A discovery request could not be dispatched to `channel_id`. Other
|
|
411
|
+
* targeted channels are unaffected. */
|
|
412
|
+
| { type: "DiscoveryFailed"; channel_id: string; error: string }
|
|
413
|
+
/** A share-storage request was dispatched to `channel_id`. Emitted per
|
|
414
|
+
* targeted peer by `start(ProtectSecret)`. */
|
|
415
|
+
| { type: "ProtectSecretStarted"; channel_id: string; version: number }
|
|
416
|
+
/** A share-storage request could not be dispatched to `channel_id`. */
|
|
417
|
+
| {
|
|
418
|
+
type: "ProtectSecretFailed";
|
|
419
|
+
channel_id: string;
|
|
420
|
+
version: number;
|
|
421
|
+
error: string;
|
|
422
|
+
}
|
|
423
|
+
/** A verify-share challenge was dispatched to `channel_id`. */
|
|
424
|
+
| { type: "VerifySharesStarted"; channel_id: string; version: number }
|
|
425
|
+
/** A verify-share challenge could not be dispatched to `channel_id`. */
|
|
426
|
+
| {
|
|
427
|
+
type: "VerifySharesFailed";
|
|
428
|
+
channel_id: string;
|
|
429
|
+
version: number;
|
|
430
|
+
error: string;
|
|
431
|
+
}
|
|
432
|
+
/** A recovery share request was dispatched to `channel_id`. */
|
|
433
|
+
| { type: "RecoverSecretStarted"; channel_id: string; version: number }
|
|
434
|
+
/** A recovery share request could not be dispatched to `channel_id`. */
|
|
435
|
+
| {
|
|
436
|
+
type: "RecoverSecretFailed";
|
|
437
|
+
channel_id: string;
|
|
438
|
+
version: number;
|
|
439
|
+
error: string;
|
|
440
|
+
}
|
|
441
|
+
/** An unpair request was dispatched to `channel_id`. Followed by an
|
|
442
|
+
* `Unpaired` event once the peer acknowledges (or in the same event
|
|
443
|
+
* vec, under `UnpairAck.NotRequired`). */
|
|
444
|
+
| { type: "UnpairStarted"; channel_id: string }
|
|
445
|
+
/** An update-channel-info request was dispatched to `channel_id`. */
|
|
446
|
+
| { type: "UpdateChannelInfoStarted"; channel_id: string }
|
|
447
|
+
/** An update-channel-info request could not be dispatched to
|
|
448
|
+
* `channel_id`. */
|
|
449
|
+
| { type: "UpdateChannelInfoFailed"; channel_id: string; error: string };
|
|
450
|
+
|
|
451
|
+
/**
|
|
452
|
+
* Per-flow auto-accept policy. When a field is `true`, `process()`
|
|
453
|
+
* internally accepts the matching inbound request and emits
|
|
454
|
+
* `AutoAccepted` in place of `ActionRequired`. Every field defaults
|
|
455
|
+
* to `false`.
|
|
456
|
+
*
|
|
457
|
+
* Per-field caveats (read before enabling in production):
|
|
458
|
+
* - `pairing` — covers standard and replica pairing. Replica pairing
|
|
459
|
+
* remains `Pending` until both sides run `verifyFingerprint()`, so
|
|
460
|
+
* auto-accept is safe for replicas. Standard pairing transitions to
|
|
461
|
+
* `Paired` immediately.
|
|
462
|
+
* - `prePair` — turns the initiator into a request-amplification
|
|
463
|
+
* oracle. Anyone who knows a HashedKeys contact's nonce can elicit a
|
|
464
|
+
* key-publish response. Keep off unless you control both ends of
|
|
465
|
+
* the transport.
|
|
466
|
+
* - `unpair` — destructive. Accepting deletes the local channel
|
|
467
|
+
* record before any UI confirmation.
|
|
468
|
+
* - `updateChannelInfo` — silently overwrites the channel record with
|
|
469
|
+
* the peer's announced transport / communication info.
|
|
470
|
+
*/
|
|
471
|
+
export interface AutoAcceptPolicy {
|
|
472
|
+
pairing?: boolean;
|
|
473
|
+
prePair?: boolean;
|
|
474
|
+
storeShare?: boolean;
|
|
475
|
+
verifyShare?: boolean;
|
|
476
|
+
discovery?: boolean;
|
|
477
|
+
getShare?: boolean;
|
|
478
|
+
unpair?: boolean;
|
|
479
|
+
updateChannelInfo?: boolean;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
/**
|
|
483
|
+
* Fluent builder for {@link DeRecProtocol}. Mirrors the Rust
|
|
484
|
+
* `DeRecProtocolBuilder` and the dotnet `DeRecProtocolBuilder`
|
|
485
|
+
* method-for-method so a developer who already knows one SDK can move
|
|
486
|
+
* between them without reaching for reference docs.
|
|
487
|
+
*
|
|
488
|
+
* Required setters: `withChannelStore`, `withShareStore`,
|
|
489
|
+
* `withSecretStore`, `withTransport`, `withOwnTransport`. Calling
|
|
490
|
+
* `build()` without all five throws.
|
|
491
|
+
*/
|
|
492
|
+
export declare class DeRecProtocolBuilder {
|
|
493
|
+
/**
|
|
494
|
+
* Construct a builder bound to a specific secret. `secretId`
|
|
495
|
+
* identifies the single secret this protocol instance manages.
|
|
496
|
+
* Apps that juggle multiple secrets instantiate one
|
|
497
|
+
* {@link DeRecProtocol} per id.
|
|
498
|
+
*/
|
|
499
|
+
constructor(secretId: bigint | number);
|
|
500
|
+
|
|
501
|
+
withChannelStore(store: ChannelStore): DeRecProtocolBuilder;
|
|
502
|
+
withShareStore(store: ShareStore): DeRecProtocolBuilder;
|
|
503
|
+
withSecretStore(store: SecretStore): DeRecProtocolBuilder;
|
|
504
|
+
withUserSecretStore(store: UserSecretStore): DeRecProtocolBuilder;
|
|
505
|
+
withStateStore(store: StateStore): DeRecProtocolBuilder;
|
|
506
|
+
withTransport(transport: Transport): DeRecProtocolBuilder;
|
|
507
|
+
withOwnTransport(endpoint: { uri: string; protocol: string }): DeRecProtocolBuilder;
|
|
508
|
+
|
|
509
|
+
/** Default: 3. */
|
|
510
|
+
withThreshold(threshold: number): DeRecProtocolBuilder;
|
|
511
|
+
/** Default: 3. */
|
|
512
|
+
withKeepVersionsCount(count: number): DeRecProtocolBuilder;
|
|
513
|
+
/** Seconds. Default: 300 (5 minutes). Clamped to at least 1. */
|
|
514
|
+
withTimeout(timeoutInSecs: number): DeRecProtocolBuilder;
|
|
515
|
+
/** Default: empty. */
|
|
516
|
+
withCommunicationInfo(info: Record<string, string>): DeRecProtocolBuilder;
|
|
517
|
+
/** Default: false. */
|
|
518
|
+
withAutoRespondOnFailure(enabled: boolean): DeRecProtocolBuilder;
|
|
519
|
+
/** Default: "required". */
|
|
520
|
+
withUnpairAck(ack: UnpairAck): DeRecProtocolBuilder;
|
|
521
|
+
/**
|
|
522
|
+
* When `true`, every outbound channel-mode request stamps
|
|
523
|
+
* `request.replyTo = ownTransport` so the responder routes its reply
|
|
524
|
+
* back here even if the channel's stored peer endpoint points
|
|
525
|
+
* elsewhere. Default: false.
|
|
526
|
+
*/
|
|
527
|
+
withAutoReplyTo(enabled: boolean): DeRecProtocolBuilder;
|
|
528
|
+
/**
|
|
529
|
+
* Per-flow auto-accept policy. When a field is `true`, `process()`
|
|
530
|
+
* internally accepts the matching inbound request and emits
|
|
531
|
+
* `AutoAccepted` in place of `ActionRequired`. See
|
|
532
|
+
* {@link AutoAcceptPolicy} for per-field caveats.
|
|
533
|
+
*
|
|
534
|
+
* Default: empty policy (every flow off).
|
|
535
|
+
*/
|
|
536
|
+
withAutoAccept(policy: AutoAcceptPolicy): DeRecProtocolBuilder;
|
|
537
|
+
/**
|
|
538
|
+
* Stable per-device replica id. Required to participate in any
|
|
539
|
+
* `ReplicaSource` / `ReplicaDestination` pairing. The id must be
|
|
540
|
+
* stable across restarts. Default: unset.
|
|
541
|
+
*/
|
|
542
|
+
withReplicaId(id: bigint | number): DeRecProtocolBuilder;
|
|
543
|
+
|
|
544
|
+
/**
|
|
545
|
+
* Finalize the configuration. Throws if any of the required setters
|
|
546
|
+
* was not called.
|
|
547
|
+
*/
|
|
548
|
+
build(): DeRecProtocol;
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
export declare class DeRecProtocol {
|
|
552
|
+
/** Use {@link DeRecProtocolBuilder} to construct instances. */
|
|
553
|
+
private constructor();
|
|
554
|
+
|
|
555
|
+
/** The secret identifier this protocol instance is bound to. */
|
|
556
|
+
secretId(): bigint;
|
|
557
|
+
|
|
558
|
+
/**
|
|
559
|
+
* Generate an out-of-band contact message used to bootstrap pairing.
|
|
560
|
+
*
|
|
561
|
+
* @param channelId Optional channel identifier. Pass `null` /
|
|
562
|
+
* `undefined` to have the library generate one.
|
|
563
|
+
* @param contactMode `ContactMode.InlineKeys` embeds the public keys
|
|
564
|
+
* directly in the contact. `ContactMode.HashedKeys`
|
|
565
|
+
* embeds only a SHA-384 binding hash (keys are
|
|
566
|
+
* fetched later via the `PrePair` round-trip).
|
|
567
|
+
* `HashedKeys` requires `ownTransportUri` to be
|
|
568
|
+
* ephemeral.
|
|
569
|
+
*/
|
|
570
|
+
/**
|
|
571
|
+
* Single entry point for all three `ContactMode` variants.
|
|
572
|
+
*
|
|
573
|
+
* @param channelId `null`/`undefined` lets the library mint a random id.
|
|
574
|
+
* @param contactMode `InlineKeys` embeds keys directly; `HashedKeys`
|
|
575
|
+
* embeds only a SHA-384 commitment (keys fetched via `PrePair`);
|
|
576
|
+
* `NoKeys` carries no key material — the creator generates keys on the
|
|
577
|
+
* fly when the `PrePairRequest` arrives. Only appropriate for `NoKeys`
|
|
578
|
+
* when the OOB delivery channel is fully trusted.
|
|
579
|
+
* @param nonce `null`/`undefined` lets the library generate a fresh
|
|
580
|
+
* random `bigint`. Required for `NoKeys` where callers typically pick
|
|
581
|
+
* a small human-typable value.
|
|
582
|
+
*/
|
|
583
|
+
createContact(
|
|
584
|
+
channelId: bigint | null | undefined,
|
|
585
|
+
contactMode: ContactMode,
|
|
586
|
+
nonce?: bigint | null,
|
|
587
|
+
): Promise<ContactMessage>;
|
|
588
|
+
|
|
589
|
+
start(flowKind: FlowKind.Pairing, params: PairingParams): Promise<DeRecEvent[]>;
|
|
590
|
+
start(flowKind: FlowKind.Discovery, params: DiscoveryParams): Promise<DeRecEvent[]>;
|
|
591
|
+
start(flowKind: FlowKind.ProtectSecret, params: ProtectSecretParams): Promise<DeRecEvent[]>;
|
|
592
|
+
start(flowKind: FlowKind.VerifyShares, params: VerifySharesParams): Promise<DeRecEvent[]>;
|
|
593
|
+
start(flowKind: FlowKind.RecoverSecret, params: RecoverSecretParams): Promise<DeRecEvent[]>;
|
|
594
|
+
start(flowKind: FlowKind.Unpair, params: UnpairParams): Promise<DeRecEvent[]>;
|
|
595
|
+
start(flowKind: FlowKind.UpdateChannelInfo, params: UpdateChannelInfoParams): Promise<DeRecEvent[]>;
|
|
596
|
+
|
|
597
|
+
/**
|
|
598
|
+
* Replace this node's local <c>communication_info</c> map. Does not
|
|
599
|
+
* contact peers — follow up with
|
|
600
|
+
* <c>start(FlowKind.UpdateChannelInfo, ...)</c> to propagate.
|
|
601
|
+
*/
|
|
602
|
+
setCommunicationInfo(info: Record<string, string>): void;
|
|
603
|
+
|
|
604
|
+
/**
|
|
605
|
+
* Replace this node's local transport endpoint. IMPORTANT: keep the
|
|
606
|
+
* old endpoint operational during the changeover (see the Rust docs
|
|
607
|
+
* on the matching setter for the discipline).
|
|
608
|
+
*/
|
|
609
|
+
setOwnTransport(uri: string, protocol: string): void;
|
|
610
|
+
|
|
611
|
+
process(message: Uint8Array): Promise<DeRecEvent[]>;
|
|
612
|
+
|
|
613
|
+
accept(actionBytes: Uint8Array): Promise<DeRecEvent[]>;
|
|
614
|
+
|
|
615
|
+
reject(actionBytes: Uint8Array, status: number, memo: string): Promise<void>;
|
|
616
|
+
|
|
617
|
+
/**
|
|
618
|
+
* Derive the human-readable fingerprint for a paired channel. Both sides
|
|
619
|
+
* of a replica pair compute the same fingerprint from the shared key —
|
|
620
|
+
* users compare them out of band before calling `verifyFingerprint`.
|
|
621
|
+
*/
|
|
622
|
+
getFingerprint(channelId: bigint | number): Promise<string>;
|
|
623
|
+
|
|
624
|
+
/**
|
|
625
|
+
* Verify `fingerprint` against the channel's locally-derived one. On
|
|
626
|
+
* match, the channel transitions from `Pending` to `Paired`. Returns
|
|
627
|
+
* `true` on confirmation, `false` on mismatch.
|
|
628
|
+
*/
|
|
629
|
+
verifyFingerprint(channelId: bigint | number, fingerprint: string): Promise<boolean>;
|
|
630
|
+
|
|
631
|
+
/**
|
|
632
|
+
* Rebuild this protocol's `secret_id` namespace from a recovered
|
|
633
|
+
* `Secret`. Mirrors the Rust `DeRecProtocol::restore` — pass the
|
|
634
|
+
* typed `secret` carried by the `SecretRecovered` event verbatim.
|
|
635
|
+
*
|
|
636
|
+
* Errors surface as structured objects with a `code` field:
|
|
637
|
+
*
|
|
638
|
+
* | code | meaning |
|
|
639
|
+
* |--------------------|------------------------------------------------------------------|
|
|
640
|
+
* | `ALREADY_RESTORED` | A user-secret snapshot already exists for this `secret_id`. |
|
|
641
|
+
* | `CONFLICT` | Channels live at canonical helper / replica ids. The error |
|
|
642
|
+
* | | carries `channel_ids: string[]` listing the collisions. |
|
|
643
|
+
* | `INVARIANT` | The recovered `Secret` is internally inconsistent. |
|
|
644
|
+
* | `STORAGE` | A store I/O call failed mid-restore. |
|
|
645
|
+
*/
|
|
646
|
+
restore(
|
|
647
|
+
recoveredSecret: Extract<DeRecEvent, { type: "SecretRecovered" }>["secret"],
|
|
648
|
+
version: number,
|
|
649
|
+
): Promise<DeRecEvent[]>;
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
/**
|
|
653
|
+
* Envelope-level helpers that operate on raw `DeRecMessage` bytes without
|
|
654
|
+
* touching the encrypted inner payload. Useful for primitive-only consumers
|
|
655
|
+
* that need to set or read the `traceId` correlation token themselves
|
|
656
|
+
* (`DeRecProtocol` handles trace_id end-to-end automatically).
|
|
657
|
+
*/
|
|
658
|
+
export declare const envelope: {
|
|
659
|
+
/**
|
|
660
|
+
* Re-stamp `traceId` on an outbound envelope. Returns the re-encoded
|
|
661
|
+
* bytes. The encrypted inner message is untouched.
|
|
662
|
+
*/
|
|
663
|
+
apply_trace_id(envelope_bytes: Uint8Array, trace_id: bigint): Uint8Array;
|
|
664
|
+
|
|
665
|
+
/**
|
|
666
|
+
* Read `traceId` off an inbound envelope. Returns `0n` when unset (the
|
|
667
|
+
* protobuf default is indistinguishable from an explicit zero).
|
|
668
|
+
*/
|
|
669
|
+
read_trace_id(envelope_bytes: Uint8Array): bigint;
|
|
670
|
+
};
|
|
671
|
+
|
|
672
|
+
export interface Timestamp {
|
|
673
|
+
|
|
674
|
+
seconds: bigint;
|
|
675
|
+
nanos: number;
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
export interface DeRecResult {
|
|
679
|
+
status: number;
|
|
680
|
+
memo: string;
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
export interface GetSecretIdsVersionsRequestMessage {
|
|
684
|
+
timestamp?: Timestamp;
|
|
685
|
+
/** Ephemeral endpoint where the requester wants the response routed.
|
|
686
|
+
* Absent means "use the channel's stored peer endpoint". */
|
|
687
|
+
reply_to?: TransportProtocol;
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
export interface VersionList {
|
|
691
|
+
secret_id: bigint;
|
|
692
|
+
versions: VersionListEntry[];
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
export interface VersionListEntry {
|
|
696
|
+
version: number;
|
|
697
|
+
version_description: string;
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
export interface GetSecretIdsVersionsResponseMessage {
|
|
701
|
+
result?: DeRecResult;
|
|
702
|
+
secret_list: VersionList[];
|
|
703
|
+
timestamp?: Timestamp;
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
export interface VersionEntry {
|
|
707
|
+
version: number;
|
|
708
|
+
description: string;
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
export interface SecretVersionEntry {
|
|
712
|
+
secret_id: bigint;
|
|
713
|
+
versions: VersionEntry[];
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
export interface TransportProtocol {
|
|
717
|
+
uri: string;
|
|
718
|
+
|
|
719
|
+
protocol: number;
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
export interface CommunicationInfoKeyValue {
|
|
723
|
+
key: string;
|
|
724
|
+
string_value: string | null;
|
|
725
|
+
bytes_value: Uint8Array | null;
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
export interface CommunicationInfo {
|
|
729
|
+
communication_info_entries: CommunicationInfoKeyValue[];
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
// `ContactMessage` is defined once above (line ~87) and covers both
|
|
733
|
+
// `INLINE_KEYS` and `HASHED_KEYS` modes.
|
|
734
|
+
|
|
735
|
+
|
|
736
|
+
export interface ParameterRange {
|
|
737
|
+
min_share_size: bigint;
|
|
738
|
+
max_share_size: bigint;
|
|
739
|
+
min_time_between_verifications: bigint;
|
|
740
|
+
max_time_between_verifications: bigint;
|
|
741
|
+
min_time_between_share_updates: bigint;
|
|
742
|
+
max_time_between_share_updates: bigint;
|
|
743
|
+
min_unresponsive_deletion_timeout: bigint;
|
|
744
|
+
max_unresponsive_deletion_timeout: bigint;
|
|
745
|
+
min_unresponsive_deactivation_timeout: bigint;
|
|
746
|
+
max_unresponsive_deactivation_timeout: bigint;
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
export interface PairRequestMessage {
|
|
750
|
+
sender_kind: number;
|
|
751
|
+
mlkem_ciphertext: Uint8Array;
|
|
752
|
+
ecies_public_key: Uint8Array;
|
|
753
|
+
nonce: bigint;
|
|
754
|
+
communication_info?: CommunicationInfo;
|
|
755
|
+
parameter_range?: ParameterRange;
|
|
756
|
+
transport_protocol?: TransportProtocol;
|
|
757
|
+
timestamp?: Timestamp;
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
export interface PairResponseMessage {
|
|
761
|
+
result?: DeRecResult;
|
|
762
|
+
nonce: bigint;
|
|
763
|
+
communication_info?: CommunicationInfo;
|
|
764
|
+
parameter_range?: ParameterRange;
|
|
765
|
+
timestamp?: Timestamp;
|
|
766
|
+
/**
|
|
767
|
+
* Post-handshake rekey channel id. Both sides switch their local channel
|
|
768
|
+
* record to this value once the response is accepted. Derived by the
|
|
769
|
+
* responder as `SHA-384(u64_be(originalChannelId) || sharedKey)[..8]`
|
|
770
|
+
* interpreted as big-endian `u64`, and validated by the requester against
|
|
771
|
+
* its own derivation. Zero on rejection (non-Ok `result.status`).
|
|
772
|
+
*/
|
|
773
|
+
channel_id: bigint;
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
export interface PrePairRequestMessage {
|
|
777
|
+
nonce: bigint;
|
|
778
|
+
transport_protocol?: TransportProtocol;
|
|
779
|
+
timestamp?: Timestamp;
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
export interface PrePairResponseMessage {
|
|
783
|
+
result?: DeRecResult;
|
|
784
|
+
/** Present only when `result.status === Ok`. */
|
|
785
|
+
mlkem_encapsulation_key?: Uint8Array;
|
|
786
|
+
/** Present only when `result.status === Ok`. */
|
|
787
|
+
ecies_public_key?: Uint8Array;
|
|
788
|
+
nonce: bigint;
|
|
789
|
+
timestamp?: Timestamp;
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
export interface GetShareRequestMessage {
|
|
793
|
+
secret_id: bigint;
|
|
794
|
+
version: number;
|
|
795
|
+
timestamp?: Timestamp;
|
|
796
|
+
/** Ephemeral response endpoint; see `replyTo` semantics. */
|
|
797
|
+
reply_to?: TransportProtocol;
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
export interface GetShareResponseMessage {
|
|
801
|
+
share_algorithm: number;
|
|
802
|
+
|
|
803
|
+
committed_de_rec_share: Uint8Array;
|
|
804
|
+
result?: DeRecResult;
|
|
805
|
+
timestamp?: Timestamp;
|
|
806
|
+
/** Echoed from the request so the Owner can correlate responses across
|
|
807
|
+
* concurrent recoveries without inspecting the share bytes. */
|
|
808
|
+
secret_id: bigint;
|
|
809
|
+
/** Echoed from the request for the same correlation reasons as `secret_id`. */
|
|
810
|
+
version: number;
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
export interface SiblingHash {
|
|
814
|
+
is_left: boolean;
|
|
815
|
+
hash: Uint8Array;
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
export interface CommittedDeRecShare {
|
|
819
|
+
|
|
820
|
+
de_rec_share: Uint8Array;
|
|
821
|
+
commitment: Uint8Array;
|
|
822
|
+
merkle_path: SiblingHash[];
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
export interface StoreShareRequestMessage {
|
|
826
|
+
|
|
827
|
+
share: Uint8Array;
|
|
828
|
+
share_algorithm: number;
|
|
829
|
+
version: number;
|
|
830
|
+
keep_list: number[];
|
|
831
|
+
version_description: string;
|
|
832
|
+
timestamp?: Timestamp;
|
|
833
|
+
secret_id: bigint;
|
|
834
|
+
/** Ephemeral response endpoint; see `replyTo` semantics. */
|
|
835
|
+
reply_to?: TransportProtocol;
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
export interface StoreShareResponseMessage {
|
|
839
|
+
result?: DeRecResult;
|
|
840
|
+
version: number;
|
|
841
|
+
timestamp?: Timestamp;
|
|
842
|
+
secret_id: bigint;
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
export interface UnpairRequestMessage {
|
|
846
|
+
memo: string;
|
|
847
|
+
timestamp?: Timestamp;
|
|
848
|
+
/** Ephemeral response endpoint; see `replyTo` semantics. */
|
|
849
|
+
reply_to?: TransportProtocol;
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
export interface UnpairResponseMessage {
|
|
853
|
+
result?: DeRecResult;
|
|
854
|
+
timestamp?: Timestamp;
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
export interface VerifyShareRequestMessage {
|
|
858
|
+
secret_id: bigint;
|
|
859
|
+
version: number;
|
|
860
|
+
nonce: bigint;
|
|
861
|
+
timestamp?: Timestamp;
|
|
862
|
+
/** Ephemeral response endpoint; see `replyTo` semantics. */
|
|
863
|
+
reply_to?: TransportProtocol;
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
export interface VerifyShareResponseMessage {
|
|
867
|
+
result?: DeRecResult;
|
|
868
|
+
secret_id: bigint;
|
|
869
|
+
version: number;
|
|
870
|
+
nonce: bigint;
|
|
871
|
+
hash: Uint8Array;
|
|
872
|
+
timestamp?: Timestamp;
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
export interface ProduceResult {
|
|
876
|
+
|
|
877
|
+
envelope: Uint8Array;
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
export interface SharingResponseProduceResult extends ProduceResult {
|
|
881
|
+
committed_share: CommittedDeRecShare;
|
|
882
|
+
secret_id: bigint;
|
|
883
|
+
version: number;
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
export interface CreateContactResult {
|
|
887
|
+
contact_message: ContactMessage;
|
|
888
|
+
|
|
889
|
+
secret_key: Uint8Array;
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
export interface PairingRequestProduceResult extends ProduceResult {
|
|
893
|
+
initiator_contact_message: ContactMessage;
|
|
894
|
+
|
|
895
|
+
secret_key: Uint8Array;
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
export interface PairingResponseProduceResult extends ProduceResult {
|
|
899
|
+
peer_transport_protocol: TransportProtocol;
|
|
900
|
+
|
|
901
|
+
shared_key: Uint8Array;
|
|
902
|
+
|
|
903
|
+
/**
|
|
904
|
+
* Post-handshake rekey channel id the responder is committing to.
|
|
905
|
+
* Callers MUST atomically rename their local channel record from the
|
|
906
|
+
* pre-rekey id (the one passed to `pairing.response.produce`) to this
|
|
907
|
+
* value as part of accepting the response.
|
|
908
|
+
*/
|
|
909
|
+
channel_id: bigint;
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
export interface PairingProcessResult {
|
|
913
|
+
|
|
914
|
+
shared_key: Uint8Array;
|
|
915
|
+
|
|
916
|
+
/**
|
|
917
|
+
* Post-handshake rekey channel id — already validated against the
|
|
918
|
+
* caller's own derivation. Callers MUST atomically rename their local
|
|
919
|
+
* channel record from the pre-rekey id (the one in the contact) to this
|
|
920
|
+
* value.
|
|
921
|
+
*/
|
|
922
|
+
channel_id: bigint;
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
export interface ProducePrePairResult {
|
|
926
|
+
|
|
927
|
+
envelope: Uint8Array;
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
export interface PrePairRequestExtractResult {
|
|
931
|
+
|
|
932
|
+
request: PrePairRequestMessage;
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
export interface PrePairResponseExtractResult {
|
|
936
|
+
|
|
937
|
+
response: PrePairResponseMessage;
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
export interface ProcessPrePairResult {
|
|
941
|
+
|
|
942
|
+
/** Initiator's ML-KEM-768 encapsulation key, validated against the
|
|
943
|
+
* contact's `contactBindingHash`. */
|
|
944
|
+
mlkem_encapsulation_key: Uint8Array;
|
|
945
|
+
|
|
946
|
+
/** Initiator's ECIES public key, validated against the contact's
|
|
947
|
+
* `contactBindingHash`. */
|
|
948
|
+
ecies_public_key: Uint8Array;
|
|
949
|
+
|
|
950
|
+
/** Nonce echoed from the original `ContactMessage`. */
|
|
951
|
+
nonce: bigint;
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
export interface SplitResult {
|
|
955
|
+
/** Map keyed by channel id (`bigint`). */
|
|
956
|
+
shares: Map<bigint, CommittedDeRecShare>;
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
export interface RecoverResult {
|
|
960
|
+
secret_data: Uint8Array;
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
export interface UnpairingProcessResult {
|
|
964
|
+
acknowledged: boolean;
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
export interface DiscoveryProcessResult {
|
|
968
|
+
secret_list: SecretVersionEntry[];
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
export type DeRecErrorCategory =
|
|
972
|
+
| "pairing"
|
|
973
|
+
| "recovery"
|
|
974
|
+
| "discovery"
|
|
975
|
+
| "sharing"
|
|
976
|
+
| "verification"
|
|
977
|
+
| "unpairing"
|
|
978
|
+
| "derec_message"
|
|
979
|
+
| "secret_store"
|
|
980
|
+
| "channel_store"
|
|
981
|
+
| "share_store"
|
|
982
|
+
| "input"
|
|
983
|
+
| "protobuf"
|
|
984
|
+
| "invariant"
|
|
985
|
+
| "wasm";
|
|
986
|
+
|
|
987
|
+
export interface DeRecError {
|
|
988
|
+
category: DeRecErrorCategory;
|
|
989
|
+
code: string;
|
|
990
|
+
message: string;
|
|
991
|
+
status?: number;
|
|
992
|
+
memo?: string;
|
|
993
|
+
expected?: number;
|
|
994
|
+
got?: number;
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
export declare const primitives: {
|
|
998
|
+
discovery: {
|
|
999
|
+
request: {
|
|
1000
|
+
/**
|
|
1001
|
+
* @param reply_to Optional ephemeral response endpoint. `null` /
|
|
1002
|
+
* `undefined` means "no override" (the responder
|
|
1003
|
+
* routes to the channel's stored peer endpoint).
|
|
1004
|
+
*/
|
|
1005
|
+
produce(
|
|
1006
|
+
channel_id: bigint,
|
|
1007
|
+
shared_key: Uint8Array,
|
|
1008
|
+
reply_to?: TransportProtocol | null,
|
|
1009
|
+
): ProduceResult;
|
|
1010
|
+
extract(envelope_bytes: Uint8Array, shared_key: Uint8Array): { request: GetSecretIdsVersionsRequestMessage };
|
|
1011
|
+
};
|
|
1012
|
+
response: {
|
|
1013
|
+
produce(channel_id: bigint, secret_list: SecretVersionEntry[], shared_key: Uint8Array): ProduceResult;
|
|
1014
|
+
extract(envelope_bytes: Uint8Array, shared_key: Uint8Array): { response: GetSecretIdsVersionsResponseMessage };
|
|
1015
|
+
process(response: GetSecretIdsVersionsResponseMessage): DiscoveryProcessResult;
|
|
1016
|
+
};
|
|
1017
|
+
};
|
|
1018
|
+
pairing: {
|
|
1019
|
+
request: {
|
|
1020
|
+
/**
|
|
1021
|
+
* Creates an out-of-band `ContactMessage` to bootstrap pairing.
|
|
1022
|
+
*
|
|
1023
|
+
* @param channel_id Identifier for the local pairing session.
|
|
1024
|
+
* @param contact_mode `ContactMode.InlineKeys` embeds the keys directly;
|
|
1025
|
+
* `ContactMode.HashedKeys` embeds only a SHA-384
|
|
1026
|
+
* commitment and the scanner must complete a
|
|
1027
|
+
* `PrePair` round-trip first.
|
|
1028
|
+
* @param transport_protocol Endpoint the scanner uses to talk back. For
|
|
1029
|
+
* `HashedKeys` mode it MUST be ephemeral.
|
|
1030
|
+
*/
|
|
1031
|
+
create_contact(
|
|
1032
|
+
channel_id: bigint,
|
|
1033
|
+
contact_mode: ContactMode | number,
|
|
1034
|
+
transport_protocol: TransportProtocol,
|
|
1035
|
+
): CreateContactResult;
|
|
1036
|
+
encode_contact(contact_message: ContactMessage): Uint8Array;
|
|
1037
|
+
decode_contact(bytes: Uint8Array): ContactMessage;
|
|
1038
|
+
produce(
|
|
1039
|
+
kind: SenderKind,
|
|
1040
|
+
transport_protocol: TransportProtocol,
|
|
1041
|
+
contact_message: ContactMessage,
|
|
1042
|
+
communication_info: CommunicationInfo | null,
|
|
1043
|
+
parameter_range: ParameterRange | null,
|
|
1044
|
+
): PairingRequestProduceResult;
|
|
1045
|
+
|
|
1046
|
+
extract(envelope_bytes: Uint8Array, secret_key: Uint8Array): { request: PairRequestMessage };
|
|
1047
|
+
|
|
1048
|
+
/**
|
|
1049
|
+
* Scanner-side: build a plaintext `PrePairRequest` envelope when the
|
|
1050
|
+
* contact was sent in `HashedKeys` mode. The keys obtained via the
|
|
1051
|
+
* matching `PrePairResponse` MUST be checked against the contact's
|
|
1052
|
+
* binding hash with `pairing.response.process_pre_pair` before
|
|
1053
|
+
* proceeding to a normal `produce`.
|
|
1054
|
+
*/
|
|
1055
|
+
produce_pre_pair(
|
|
1056
|
+
transport_protocol: TransportProtocol,
|
|
1057
|
+
contact_message: ContactMessage,
|
|
1058
|
+
): ProducePrePairResult;
|
|
1059
|
+
|
|
1060
|
+
/**
|
|
1061
|
+
* Initiator-side: decode an inbound plaintext `PrePairRequest`
|
|
1062
|
+
* envelope.
|
|
1063
|
+
*/
|
|
1064
|
+
extract_pre_pair(envelope_bytes: Uint8Array): PrePairRequestExtractResult;
|
|
1065
|
+
};
|
|
1066
|
+
response: {
|
|
1067
|
+
produce(
|
|
1068
|
+
channel_id: bigint,
|
|
1069
|
+
request: PairRequestMessage,
|
|
1070
|
+
secret_key: Uint8Array,
|
|
1071
|
+
communication_info: CommunicationInfo | null,
|
|
1072
|
+
parameter_range: ParameterRange | null,
|
|
1073
|
+
): PairingResponseProduceResult;
|
|
1074
|
+
|
|
1075
|
+
extract(envelope_bytes: Uint8Array, secret_key: Uint8Array): { response: PairResponseMessage };
|
|
1076
|
+
process(
|
|
1077
|
+
contact_message: ContactMessage,
|
|
1078
|
+
response: PairResponseMessage,
|
|
1079
|
+
secret_key: Uint8Array,
|
|
1080
|
+
): PairingProcessResult;
|
|
1081
|
+
|
|
1082
|
+
/**
|
|
1083
|
+
* Contact-creator side: publish the actual public keys back to the
|
|
1084
|
+
* scanner in response to a `PrePairRequest`.
|
|
1085
|
+
*/
|
|
1086
|
+
produce_pre_pair(
|
|
1087
|
+
channel_id: bigint,
|
|
1088
|
+
request: PrePairRequestMessage,
|
|
1089
|
+
secret_key: Uint8Array,
|
|
1090
|
+
): ProducePrePairResult;
|
|
1091
|
+
|
|
1092
|
+
/**
|
|
1093
|
+
* Scanner-side: decode an inbound plaintext `PrePairResponse`
|
|
1094
|
+
* envelope.
|
|
1095
|
+
*/
|
|
1096
|
+
extract_pre_pair(envelope_bytes: Uint8Array): PrePairResponseExtractResult;
|
|
1097
|
+
|
|
1098
|
+
/**
|
|
1099
|
+
* Scanner-side: validate the `PrePairResponse` against the contact's
|
|
1100
|
+
* SHA-384 binding hash. Returns the validated public keys + echoed
|
|
1101
|
+
* nonce on match; throws on mismatch.
|
|
1102
|
+
*/
|
|
1103
|
+
process_pre_pair(
|
|
1104
|
+
contact_message: ContactMessage,
|
|
1105
|
+
response: PrePairResponseMessage,
|
|
1106
|
+
): ProcessPrePairResult;
|
|
1107
|
+
};
|
|
1108
|
+
};
|
|
1109
|
+
recovery: {
|
|
1110
|
+
request: {
|
|
1111
|
+
produce(
|
|
1112
|
+
channel_id: bigint,
|
|
1113
|
+
secret_id: bigint,
|
|
1114
|
+
version: number,
|
|
1115
|
+
shared_key: Uint8Array,
|
|
1116
|
+
/** See `discovery.request.produce.reply_to`. */
|
|
1117
|
+
reply_to?: TransportProtocol | null,
|
|
1118
|
+
): ProduceResult;
|
|
1119
|
+
extract(envelope_bytes: Uint8Array, shared_key: Uint8Array): { request: GetShareRequestMessage };
|
|
1120
|
+
};
|
|
1121
|
+
response: {
|
|
1122
|
+
produce(
|
|
1123
|
+
channel_id: bigint,
|
|
1124
|
+
request: GetShareRequestMessage,
|
|
1125
|
+
stored_share_request: StoreShareRequestMessage,
|
|
1126
|
+
shared_key: Uint8Array,
|
|
1127
|
+
): ProduceResult;
|
|
1128
|
+
extract(envelope_bytes: Uint8Array, shared_key: Uint8Array): { response: GetShareResponseMessage };
|
|
1129
|
+
recover(secret_id: bigint, version: number, responses: GetShareResponseMessage[]): RecoverResult;
|
|
1130
|
+
};
|
|
1131
|
+
};
|
|
1132
|
+
sharing: {
|
|
1133
|
+
request: {
|
|
1134
|
+
split(
|
|
1135
|
+
channels: bigint[],
|
|
1136
|
+
secret_id: bigint,
|
|
1137
|
+
version: number,
|
|
1138
|
+
secret_data: Uint8Array,
|
|
1139
|
+
threshold: number,
|
|
1140
|
+
): SplitResult;
|
|
1141
|
+
produce(
|
|
1142
|
+
channel_id: bigint,
|
|
1143
|
+
version: number,
|
|
1144
|
+
secret_id: bigint,
|
|
1145
|
+
committed_share: CommittedDeRecShare,
|
|
1146
|
+
keep_list: number[],
|
|
1147
|
+
description: string,
|
|
1148
|
+
shared_key: Uint8Array,
|
|
1149
|
+
/** See `discovery.request.produce.reply_to`. */
|
|
1150
|
+
reply_to?: TransportProtocol | null,
|
|
1151
|
+
): ProduceResult;
|
|
1152
|
+
extract(envelope_bytes: Uint8Array, shared_key: Uint8Array): { request: StoreShareRequestMessage };
|
|
1153
|
+
};
|
|
1154
|
+
response: {
|
|
1155
|
+
produce(
|
|
1156
|
+
channel_id: bigint,
|
|
1157
|
+
request: StoreShareRequestMessage,
|
|
1158
|
+
shared_key: Uint8Array,
|
|
1159
|
+
): SharingResponseProduceResult;
|
|
1160
|
+
extract(envelope_bytes: Uint8Array, shared_key: Uint8Array): { response: StoreShareResponseMessage };
|
|
1161
|
+
process(version: number, response: StoreShareResponseMessage): void;
|
|
1162
|
+
};
|
|
1163
|
+
};
|
|
1164
|
+
unpairing: {
|
|
1165
|
+
request: {
|
|
1166
|
+
produce(
|
|
1167
|
+
channel_id: bigint,
|
|
1168
|
+
memo: string,
|
|
1169
|
+
shared_key: Uint8Array,
|
|
1170
|
+
/** See `discovery.request.produce.reply_to`. */
|
|
1171
|
+
reply_to?: TransportProtocol | null,
|
|
1172
|
+
): ProduceResult;
|
|
1173
|
+
extract(envelope_bytes: Uint8Array, shared_key: Uint8Array): { request: UnpairRequestMessage };
|
|
1174
|
+
};
|
|
1175
|
+
response: {
|
|
1176
|
+
produce(channel_id: bigint, shared_key: Uint8Array): ProduceResult;
|
|
1177
|
+
extract(envelope_bytes: Uint8Array, shared_key: Uint8Array): { response: UnpairResponseMessage };
|
|
1178
|
+
process(response: UnpairResponseMessage): UnpairingProcessResult;
|
|
1179
|
+
};
|
|
1180
|
+
};
|
|
1181
|
+
verification: {
|
|
1182
|
+
request: {
|
|
1183
|
+
produce(
|
|
1184
|
+
channel_id: bigint,
|
|
1185
|
+
secret_id: bigint,
|
|
1186
|
+
version: number,
|
|
1187
|
+
shared_key: Uint8Array,
|
|
1188
|
+
/** See `discovery.request.produce.reply_to`. */
|
|
1189
|
+
reply_to?: TransportProtocol | null,
|
|
1190
|
+
): ProduceResult;
|
|
1191
|
+
extract(envelope_bytes: Uint8Array, shared_key: Uint8Array): { request: VerifyShareRequestMessage };
|
|
1192
|
+
};
|
|
1193
|
+
response: {
|
|
1194
|
+
produce(
|
|
1195
|
+
channel_id: bigint,
|
|
1196
|
+
request: VerifyShareRequestMessage,
|
|
1197
|
+
shared_key: Uint8Array,
|
|
1198
|
+
share_content: Uint8Array,
|
|
1199
|
+
): ProduceResult;
|
|
1200
|
+
extract(envelope_bytes: Uint8Array, shared_key: Uint8Array): { response: VerifyShareResponseMessage };
|
|
1201
|
+
|
|
1202
|
+
/** `request` must be the request the owner previously produced
|
|
1203
|
+
* for this challenge (kept by the caller in a per-channel
|
|
1204
|
+
* pending-verification map). Responses whose
|
|
1205
|
+
* `(nonce, secret_id, version)` triple doesn't match are
|
|
1206
|
+
* rejected — that's the anti-replay gate. */
|
|
1207
|
+
process(
|
|
1208
|
+
request: VerifyShareRequestMessage,
|
|
1209
|
+
response: VerifyShareResponseMessage,
|
|
1210
|
+
share_content: Uint8Array,
|
|
1211
|
+
): boolean;
|
|
1212
|
+
};
|
|
1213
|
+
};
|
|
1214
|
+
};
|