@derec-alliance/react-native 0.0.1

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.
Files changed (65) hide show
  1. package/DeRec.podspec +25 -0
  2. package/LICENSE +201 -0
  3. package/README.md +222 -0
  4. package/android/CMakeLists.txt +38 -0
  5. package/android/build.gradle +79 -0
  6. package/android/src/main/AndroidManifest.xml +12 -0
  7. package/android/src/main/java/org/derec/DeRecModule.kt +56 -0
  8. package/android/src/main/java/org/derec/DeRecPackage.kt +24 -0
  9. package/android/src/main/jni/OnLoad.cpp +39 -0
  10. package/android/src/main/jniLibs/arm64-v8a/libderec_library.a +0 -0
  11. package/android/src/main/jniLibs/armeabi-v7a/libderec_library.a +0 -0
  12. package/android/src/main/jniLibs/x86_64/libderec_library.a +0 -0
  13. package/cpp/Convert.cpp +50 -0
  14. package/cpp/Convert.h +38 -0
  15. package/cpp/DeRecInstaller.cpp +186 -0
  16. package/cpp/DeRecInstaller.h +28 -0
  17. package/cpp/Invoker.h +20 -0
  18. package/cpp/JsCallbackBridge.cpp +144 -0
  19. package/cpp/JsCallbackBridge.h +148 -0
  20. package/cpp/Primitives.cpp +1193 -0
  21. package/cpp/Primitives.h +39 -0
  22. package/cpp/ProtocolHost.cpp +613 -0
  23. package/cpp/ProtocolHost.h +88 -0
  24. package/cpp/RuntimeInvoker.h +29 -0
  25. package/cpp/StoreCallbacks.cpp +1293 -0
  26. package/cpp/StoreCallbacks.h +111 -0
  27. package/cpp/WorkerThread.cpp +74 -0
  28. package/cpp/WorkerThread.h +54 -0
  29. package/cpp/derec_ffi.h +2145 -0
  30. package/ios/DeRec.h +23 -0
  31. package/ios/DeRec.mm +39 -0
  32. package/ios/DeRecFFI.xcframework/Info.plist +48 -0
  33. package/ios/DeRecFFI.xcframework/ios-arm64/Headers/derec_ffi.h +2145 -0
  34. package/ios/DeRecFFI.xcframework/ios-arm64/libderec_library.a +0 -0
  35. package/ios/DeRecFFI.xcframework/ios-arm64_x86_64-simulator/Headers/derec_ffi.h +2145 -0
  36. package/ios/DeRecFFI.xcframework/ios-arm64_x86_64-simulator/libderec_library.a +0 -0
  37. package/lib/binary.d.ts +19 -0
  38. package/lib/binary.js +164 -0
  39. package/lib/codec.d.ts +16 -0
  40. package/lib/codec.js +80 -0
  41. package/lib/errors.d.ts +23 -0
  42. package/lib/errors.js +35 -0
  43. package/lib/index.d.ts +4 -0
  44. package/lib/index.js +27 -0
  45. package/lib/messages.d.ts +41 -0
  46. package/lib/messages.js +192 -0
  47. package/lib/native.d.ts +11 -0
  48. package/lib/native.js +40 -0
  49. package/lib/primitives.d.ts +137 -0
  50. package/lib/primitives.js +329 -0
  51. package/lib/protocol.d.ts +188 -0
  52. package/lib/protocol.js +514 -0
  53. package/lib/types.d.ts +1014 -0
  54. package/lib/types.js +63 -0
  55. package/package.json +55 -0
  56. package/react-native.config.js +19 -0
  57. package/src/binary.ts +182 -0
  58. package/src/codec.ts +79 -0
  59. package/src/errors.ts +45 -0
  60. package/src/index.ts +7 -0
  61. package/src/messages.ts +192 -0
  62. package/src/native.ts +52 -0
  63. package/src/primitives.ts +770 -0
  64. package/src/protocol.ts +621 -0
  65. package/src/types.ts +1040 -0
@@ -0,0 +1,770 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 DeRec Alliance. All rights reserved.
3
+
4
+ /**
5
+ * The stateless primitive surface, shaped identically to
6
+ * `@derec-alliance/nodejs`.
7
+ *
8
+ * Primitives are synchronous: they are pure byte transforms with no store or
9
+ * transport callbacks, so they run on the JavaScript thread. `sharing.request.
10
+ * split` does real cryptographic work, which is why an application that needs
11
+ * it off-thread should drive it through `DeRecProtocol` instead.
12
+ *
13
+ * Each function marshals between the typed surface and the C ABI's own shapes
14
+ * — protobuf wire bytes for messages, hand-packed little-endian containers for
15
+ * the three set-valued arguments. See `./messages` and `./binary`. Nothing
16
+ * here interprets a protocol value: no defaulting, no clamping, no branching
17
+ * on what a field contains.
18
+ */
19
+
20
+ import {
21
+ decodeCommittedShareEntries,
22
+ decodeSecretList,
23
+ encodeSecretList,
24
+ encodeShareResponses,
25
+ } from './binary';
26
+ import { jsonFromBytes, jsonToBytes, utf8Encode } from './codec';
27
+ import {
28
+ MessageKind,
29
+ decodeMessage,
30
+ encodeMessage,
31
+ encodeOptionalMessage,
32
+ plainMessage,
33
+ reviveMessage,
34
+ } from './messages';
35
+ import { getNative } from './native';
36
+ import type {
37
+ CommittedDeRecShare,
38
+ CommunicationInfo,
39
+ ContactMessage,
40
+ ContactMode,
41
+ CreateContactResult,
42
+ DiscoveryProcessResult,
43
+ GetSecretIdsVersionsRequestMessage,
44
+ GetSecretIdsVersionsResponseMessage,
45
+ GetShareRequestMessage,
46
+ GetShareResponseMessage,
47
+ PairRequestMessage,
48
+ PairResponseMessage,
49
+ PairingProcessResult,
50
+ PairingRequestProduceResult,
51
+ PairingResponseProduceResult,
52
+ ParameterRange,
53
+ PrePairRequestExtractResult,
54
+ PrePairRequestMessage,
55
+ PrePairResponseExtractResult,
56
+ PrePairResponseMessage,
57
+ ProcessPrePairResult,
58
+ ProducePrePairResult,
59
+ ProduceResult,
60
+ RecoverResult,
61
+ SecretVersionEntry,
62
+ SenderKind,
63
+ SharingResponseProduceResult,
64
+ SplitResult,
65
+ StoreShareRequestMessage,
66
+ StoreShareResponseMessage,
67
+ TransportProtocol,
68
+ UnpairRequestMessage,
69
+ UnpairResponseMessage,
70
+ UnpairingProcessResult,
71
+ VerifyShareRequestMessage,
72
+ VerifyShareResponseMessage,
73
+ } from './types';
74
+
75
+ /** Shape of the `__DeRec` host object: every member is a plain callable, since
76
+ * the JSI layer exposes host functions this way and TypeScript has no static
77
+ * knowledge of them. */
78
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
79
+ type NativeHost = Record<string, (...args: any[]) => any>;
80
+
81
+ function call(name: string, ...args: unknown[]): unknown {
82
+ return (getNative() as never as NativeHost)[name](...args);
83
+ }
84
+
85
+ function bytes(value: unknown): Uint8Array {
86
+ return new Uint8Array(value as ArrayBuffer);
87
+ }
88
+
89
+ /** `null` and `undefined` both mean "no override" for every optional
90
+ * `TransportProtocol` argument; the C ABI reads a zero-length buffer as
91
+ * absent. */
92
+ function replyTo(value: TransportProtocol | null | undefined): Uint8Array {
93
+ return encodeOptionalMessage(MessageKind.TransportProtocol, value);
94
+ }
95
+
96
+ /**
97
+ * `ContactMessage` keeps its own dedicated codec rather than going through
98
+ * the generic message codec: `encode_contact_message` /
99
+ * `decode_contact_message` also enforce the mode/field invariant — an
100
+ * `InlineKeys` contact must carry keys, a `HashedKeys` one must carry only
101
+ * the commitment — so a malformed contact is rejected here rather than
102
+ * travelling.
103
+ */
104
+ function encodeContact(contact_message: ContactMessage): Uint8Array {
105
+ return bytes(
106
+ call('encode_contact_message', jsonToBytes(plainMessage(contact_message))),
107
+ );
108
+ }
109
+
110
+ function decodeContact(wire: Uint8Array | ArrayBuffer): ContactMessage {
111
+ const json = call('decode_contact_message', wire) as ArrayBuffer;
112
+ return reviveMessage(jsonFromBytes(json)) as ContactMessage;
113
+ }
114
+
115
+ const discovery = {
116
+ request: {
117
+ produce(
118
+ channel_id: bigint,
119
+ shared_key: Uint8Array,
120
+ reply_to?: TransportProtocol | null,
121
+ ): ProduceResult {
122
+ const envelope = call(
123
+ 'produce_get_secret_ids_versions_request_message',
124
+ channel_id,
125
+ shared_key,
126
+ replyTo(reply_to),
127
+ );
128
+ return { envelope: bytes(envelope) };
129
+ },
130
+
131
+ extract(
132
+ envelope_bytes: Uint8Array,
133
+ shared_key: Uint8Array,
134
+ ): { request: GetSecretIdsVersionsRequestMessage } {
135
+ const result = call(
136
+ 'extract_get_secret_ids_versions_request',
137
+ envelope_bytes,
138
+ shared_key,
139
+ ) as { request_proto_bytes: ArrayBuffer };
140
+ return {
141
+ request: decodeMessage<GetSecretIdsVersionsRequestMessage>(
142
+ MessageKind.GetSecretIdsVersionsRequest,
143
+ result.request_proto_bytes,
144
+ ),
145
+ };
146
+ },
147
+ },
148
+
149
+ response: {
150
+ produce(
151
+ channel_id: bigint,
152
+ secret_list: SecretVersionEntry[],
153
+ shared_key: Uint8Array,
154
+ ): ProduceResult {
155
+ const envelope = call(
156
+ 'produce_get_secret_ids_versions_response_message',
157
+ channel_id,
158
+ encodeSecretList(secret_list),
159
+ shared_key,
160
+ );
161
+ return { envelope: bytes(envelope) };
162
+ },
163
+
164
+ extract(
165
+ envelope_bytes: Uint8Array,
166
+ shared_key: Uint8Array,
167
+ ): { response: GetSecretIdsVersionsResponseMessage } {
168
+ const result = call(
169
+ 'extract_get_secret_ids_versions_response',
170
+ envelope_bytes,
171
+ shared_key,
172
+ ) as { response_proto_bytes: ArrayBuffer };
173
+ return {
174
+ response: decodeMessage<GetSecretIdsVersionsResponseMessage>(
175
+ MessageKind.GetSecretIdsVersionsResponse,
176
+ result.response_proto_bytes,
177
+ ),
178
+ };
179
+ },
180
+
181
+ process(response: GetSecretIdsVersionsResponseMessage): DiscoveryProcessResult {
182
+ const packed = call(
183
+ 'process_get_secret_ids_versions_response_message',
184
+ encodeMessage(MessageKind.GetSecretIdsVersionsResponse, response),
185
+ );
186
+ return { secret_list: decodeSecretList(packed as ArrayBuffer) };
187
+ },
188
+ },
189
+ };
190
+
191
+ const pairing = {
192
+ request: {
193
+ create_contact(
194
+ channel_id: bigint,
195
+ contact_mode: ContactMode | number,
196
+ transport_protocol: TransportProtocol,
197
+ ): CreateContactResult {
198
+ // The C entry point also accepts a caller-supplied nonce behind a
199
+ // presence flag. `@derec-alliance/nodejs` has no such parameter, so the
200
+ // flag is 0 and the library generates one — the same behaviour, not a
201
+ // default invented here.
202
+ const result = call(
203
+ 'create_contact_message',
204
+ channel_id,
205
+ contact_mode,
206
+ encodeMessage(MessageKind.TransportProtocol, transport_protocol),
207
+ 0,
208
+ 0n,
209
+ ) as { contact_wire_bytes: ArrayBuffer; secret_key_material: ArrayBuffer };
210
+ return {
211
+ contact_message: decodeContact(result.contact_wire_bytes),
212
+ secret_key: bytes(result.secret_key_material),
213
+ };
214
+ },
215
+
216
+ /** Proto-encodes a `ContactMessage`. Rejects a contact that violates the
217
+ * mode/field invariant rather than serializing it. */
218
+ encode_contact: encodeContact,
219
+
220
+ /** Decodes proto `ContactMessage` bytes. Rejects a contact that violates
221
+ * the mode/field invariant rather than returning it. */
222
+ decode_contact: decodeContact,
223
+
224
+ produce(
225
+ kind: SenderKind,
226
+ transport_protocol: TransportProtocol,
227
+ contact_message: ContactMessage,
228
+ communication_info: CommunicationInfo | null,
229
+ parameter_range: ParameterRange | null,
230
+ ): PairingRequestProduceResult {
231
+ const result = call(
232
+ 'produce_pair_request_message',
233
+ kind,
234
+ encodeMessage(MessageKind.TransportProtocol, transport_protocol),
235
+ encodeContact(contact_message),
236
+ encodeOptionalMessage(MessageKind.CommunicationInfo, communication_info),
237
+ encodeOptionalMessage(MessageKind.ParameterRange, parameter_range),
238
+ ) as {
239
+ request_wire_bytes: ArrayBuffer;
240
+ initiator_contact_message_wire_bytes: ArrayBuffer;
241
+ secret_key_material: ArrayBuffer;
242
+ };
243
+ return {
244
+ envelope: bytes(result.request_wire_bytes),
245
+ initiator_contact_message: decodeContact(
246
+ result.initiator_contact_message_wire_bytes,
247
+ ),
248
+ secret_key: bytes(result.secret_key_material),
249
+ };
250
+ },
251
+
252
+ extract(envelope_bytes: Uint8Array, secret_key: Uint8Array): { request: PairRequestMessage } {
253
+ const result = call('extract_pair_request', envelope_bytes, secret_key) as {
254
+ request_proto_bytes: ArrayBuffer;
255
+ };
256
+ return {
257
+ request: decodeMessage<PairRequestMessage>(
258
+ MessageKind.PairRequest,
259
+ result.request_proto_bytes,
260
+ ),
261
+ };
262
+ },
263
+
264
+ produce_pre_pair(
265
+ transport_protocol: TransportProtocol,
266
+ contact_message: ContactMessage,
267
+ ): ProducePrePairResult {
268
+ const envelope = call(
269
+ 'produce_pre_pair_request_message',
270
+ encodeMessage(MessageKind.TransportProtocol, transport_protocol),
271
+ encodeContact(contact_message),
272
+ );
273
+ return { envelope: bytes(envelope) };
274
+ },
275
+
276
+ extract_pre_pair(envelope_bytes: Uint8Array): PrePairRequestExtractResult {
277
+ const result = call('extract_pre_pair_request', envelope_bytes) as {
278
+ request_proto_bytes: ArrayBuffer;
279
+ };
280
+ return {
281
+ request: decodeMessage<PrePairRequestMessage>(
282
+ MessageKind.PrePairRequest,
283
+ result.request_proto_bytes,
284
+ ),
285
+ };
286
+ },
287
+ },
288
+
289
+ response: {
290
+ produce(
291
+ channel_id: bigint,
292
+ request: PairRequestMessage,
293
+ secret_key: Uint8Array,
294
+ communication_info: CommunicationInfo | null,
295
+ parameter_range: ParameterRange | null,
296
+ ): PairingResponseProduceResult {
297
+ const result = call(
298
+ 'produce_pair_response_message',
299
+ channel_id,
300
+ encodeMessage(MessageKind.PairRequest, request),
301
+ secret_key,
302
+ encodeOptionalMessage(MessageKind.CommunicationInfo, communication_info),
303
+ encodeOptionalMessage(MessageKind.ParameterRange, parameter_range),
304
+ ) as {
305
+ response_wire_bytes: ArrayBuffer;
306
+ peer_transport_protocol: ArrayBuffer;
307
+ shared_key: ArrayBuffer;
308
+ channel_id: bigint;
309
+ };
310
+ return {
311
+ envelope: bytes(result.response_wire_bytes),
312
+ peer_transport_protocol: decodeMessage<TransportProtocol>(
313
+ MessageKind.TransportProtocol,
314
+ result.peer_transport_protocol,
315
+ ),
316
+ shared_key: bytes(result.shared_key),
317
+ channel_id: result.channel_id,
318
+ };
319
+ },
320
+
321
+ extract(
322
+ envelope_bytes: Uint8Array,
323
+ secret_key: Uint8Array,
324
+ ): { response: PairResponseMessage } {
325
+ const result = call('extract_pair_response', envelope_bytes, secret_key) as {
326
+ response_proto_bytes: ArrayBuffer;
327
+ };
328
+ return {
329
+ response: decodeMessage<PairResponseMessage>(
330
+ MessageKind.PairResponse,
331
+ result.response_proto_bytes,
332
+ ),
333
+ };
334
+ },
335
+
336
+ process(
337
+ contact_message: ContactMessage,
338
+ response: PairResponseMessage,
339
+ secret_key: Uint8Array,
340
+ ): PairingProcessResult {
341
+ const result = call(
342
+ 'process_pair_response_message',
343
+ encodeContact(contact_message),
344
+ encodeMessage(MessageKind.PairResponse, response),
345
+ secret_key,
346
+ ) as { shared_key: ArrayBuffer; channel_id: bigint };
347
+ return { shared_key: bytes(result.shared_key), channel_id: result.channel_id };
348
+ },
349
+
350
+ produce_pre_pair(
351
+ channel_id: bigint,
352
+ request: PrePairRequestMessage,
353
+ secret_key: Uint8Array,
354
+ ): ProducePrePairResult {
355
+ const envelope = call(
356
+ 'produce_pre_pair_response_message',
357
+ channel_id,
358
+ encodeMessage(MessageKind.PrePairRequest, request),
359
+ secret_key,
360
+ );
361
+ return { envelope: bytes(envelope) };
362
+ },
363
+
364
+ extract_pre_pair(envelope_bytes: Uint8Array): PrePairResponseExtractResult {
365
+ const result = call('extract_pre_pair_response', envelope_bytes) as {
366
+ response_proto_bytes: ArrayBuffer;
367
+ };
368
+ return {
369
+ response: decodeMessage<PrePairResponseMessage>(
370
+ MessageKind.PrePairResponse,
371
+ result.response_proto_bytes,
372
+ ),
373
+ };
374
+ },
375
+
376
+ process_pre_pair(
377
+ contact_message: ContactMessage,
378
+ response: PrePairResponseMessage,
379
+ ): ProcessPrePairResult {
380
+ const result = call(
381
+ 'process_pre_pair_response_message',
382
+ encodeContact(contact_message),
383
+ encodeMessage(MessageKind.PrePairResponse, response),
384
+ ) as {
385
+ mlkem_encapsulation_key: ArrayBuffer;
386
+ ecies_public_key: ArrayBuffer;
387
+ nonce: bigint;
388
+ };
389
+ return {
390
+ mlkem_encapsulation_key: bytes(result.mlkem_encapsulation_key),
391
+ ecies_public_key: bytes(result.ecies_public_key),
392
+ nonce: result.nonce,
393
+ };
394
+ },
395
+ },
396
+ };
397
+
398
+ const recovery = {
399
+ request: {
400
+ produce(
401
+ channel_id: bigint,
402
+ secret_id: bigint,
403
+ version: number,
404
+ shared_key: Uint8Array,
405
+ reply_to?: TransportProtocol | null,
406
+ ): ProduceResult {
407
+ const envelope = call(
408
+ 'produce_get_share_request_message',
409
+ channel_id,
410
+ secret_id,
411
+ version,
412
+ shared_key,
413
+ replyTo(reply_to),
414
+ );
415
+ return { envelope: bytes(envelope) };
416
+ },
417
+
418
+ extract(
419
+ envelope_bytes: Uint8Array,
420
+ shared_key: Uint8Array,
421
+ ): { request: GetShareRequestMessage } {
422
+ const result = call('extract_get_share_request', envelope_bytes, shared_key) as {
423
+ request_proto_bytes: ArrayBuffer;
424
+ };
425
+ return {
426
+ request: decodeMessage<GetShareRequestMessage>(
427
+ MessageKind.GetShareRequest,
428
+ result.request_proto_bytes,
429
+ ),
430
+ };
431
+ },
432
+ },
433
+
434
+ response: {
435
+ produce(
436
+ channel_id: bigint,
437
+ request: GetShareRequestMessage,
438
+ stored_share_request: StoreShareRequestMessage,
439
+ shared_key: Uint8Array,
440
+ ): ProduceResult {
441
+ const envelope = call(
442
+ 'produce_get_share_response_message',
443
+ channel_id,
444
+ encodeMessage(MessageKind.GetShareRequest, request),
445
+ encodeMessage(MessageKind.StoreShareRequest, stored_share_request),
446
+ shared_key,
447
+ );
448
+ return { envelope: bytes(envelope) };
449
+ },
450
+
451
+ extract(
452
+ envelope_bytes: Uint8Array,
453
+ shared_key: Uint8Array,
454
+ ): { response: GetShareResponseMessage } {
455
+ const result = call('extract_get_share_response', envelope_bytes, shared_key) as {
456
+ response_proto_bytes: ArrayBuffer;
457
+ };
458
+ return {
459
+ response: decodeMessage<GetShareResponseMessage>(
460
+ MessageKind.GetShareResponse,
461
+ result.response_proto_bytes,
462
+ ),
463
+ };
464
+ },
465
+
466
+ recover(
467
+ secret_id: bigint,
468
+ version: number,
469
+ responses: GetShareResponseMessage[],
470
+ ): RecoverResult {
471
+ const packed = encodeShareResponses(
472
+ responses.map((response) => encodeMessage(MessageKind.GetShareResponse, response)),
473
+ );
474
+ const secret = call('recover_from_share_responses', packed, secret_id, version);
475
+ return { secret_data: bytes(secret) };
476
+ },
477
+ },
478
+ };
479
+
480
+ const sharing = {
481
+ request: {
482
+ split(
483
+ channels: bigint[],
484
+ secret_id: bigint,
485
+ version: number,
486
+ secret_data: Uint8Array,
487
+ threshold: number,
488
+ ): SplitResult {
489
+ const packed = call('protect_secret', secret_id, secret_data, channels, threshold, version);
490
+ const shares = new Map<bigint, CommittedDeRecShare>();
491
+ for (const entry of decodeCommittedShareEntries(packed as ArrayBuffer)) {
492
+ shares.set(
493
+ entry.channelId,
494
+ decodeMessage<CommittedDeRecShare>(MessageKind.CommittedDeRecShare, entry.shareProto),
495
+ );
496
+ }
497
+ return { shares };
498
+ },
499
+
500
+ produce(
501
+ channel_id: bigint,
502
+ version: number,
503
+ secret_id: bigint,
504
+ committed_share: CommittedDeRecShare,
505
+ keep_list: number[],
506
+ description: string,
507
+ shared_key: Uint8Array,
508
+ reply_to?: TransportProtocol | null,
509
+ ): ProduceResult {
510
+ const envelope = call(
511
+ 'produce_store_share_request_message',
512
+ channel_id,
513
+ version,
514
+ secret_id,
515
+ encodeMessage(MessageKind.CommittedDeRecShare, committed_share),
516
+ keep_list,
517
+ utf8Encode(description),
518
+ shared_key,
519
+ replyTo(reply_to),
520
+ );
521
+ return { envelope: bytes(envelope) };
522
+ },
523
+
524
+ extract(
525
+ envelope_bytes: Uint8Array,
526
+ shared_key: Uint8Array,
527
+ ): { request: StoreShareRequestMessage } {
528
+ const result = call('extract_store_share_request', envelope_bytes, shared_key) as {
529
+ request_proto_bytes: ArrayBuffer;
530
+ };
531
+ return {
532
+ request: decodeMessage<StoreShareRequestMessage>(
533
+ MessageKind.StoreShareRequest,
534
+ result.request_proto_bytes,
535
+ ),
536
+ };
537
+ },
538
+ },
539
+
540
+ response: {
541
+ produce(
542
+ channel_id: bigint,
543
+ request: StoreShareRequestMessage,
544
+ shared_key: Uint8Array,
545
+ ): SharingResponseProduceResult {
546
+ const result = call(
547
+ 'produce_store_share_response_message',
548
+ channel_id,
549
+ encodeMessage(MessageKind.StoreShareRequest, request),
550
+ shared_key,
551
+ ) as {
552
+ wire_bytes: ArrayBuffer;
553
+ committed_share_bytes: ArrayBuffer;
554
+ secret_id: bigint;
555
+ version: number;
556
+ };
557
+ return {
558
+ envelope: bytes(result.wire_bytes),
559
+ committed_share: decodeMessage<CommittedDeRecShare>(
560
+ MessageKind.CommittedDeRecShare,
561
+ result.committed_share_bytes,
562
+ ),
563
+ secret_id: result.secret_id,
564
+ version: result.version,
565
+ };
566
+ },
567
+
568
+ extract(
569
+ envelope_bytes: Uint8Array,
570
+ shared_key: Uint8Array,
571
+ ): { response: StoreShareResponseMessage } {
572
+ const result = call('extract_store_share_response', envelope_bytes, shared_key) as {
573
+ response_proto_bytes: ArrayBuffer;
574
+ };
575
+ return {
576
+ response: decodeMessage<StoreShareResponseMessage>(
577
+ MessageKind.StoreShareResponse,
578
+ result.response_proto_bytes,
579
+ ),
580
+ };
581
+ },
582
+
583
+ process(version: number, response: StoreShareResponseMessage): void {
584
+ call(
585
+ 'process_store_share_response_message',
586
+ version,
587
+ encodeMessage(MessageKind.StoreShareResponse, response),
588
+ );
589
+ },
590
+ },
591
+ };
592
+
593
+ const unpairing = {
594
+ request: {
595
+ produce(
596
+ channel_id: bigint,
597
+ memo: string,
598
+ shared_key: Uint8Array,
599
+ reply_to?: TransportProtocol | null,
600
+ ): ProduceResult {
601
+ const envelope = call(
602
+ 'produce_unpair_request_message',
603
+ channel_id,
604
+ utf8Encode(memo),
605
+ shared_key,
606
+ replyTo(reply_to),
607
+ );
608
+ return { envelope: bytes(envelope) };
609
+ },
610
+
611
+ extract(
612
+ envelope_bytes: Uint8Array,
613
+ shared_key: Uint8Array,
614
+ ): { request: UnpairRequestMessage } {
615
+ const result = call('extract_unpair_request', envelope_bytes, shared_key) as {
616
+ request_proto_bytes: ArrayBuffer;
617
+ };
618
+ return {
619
+ request: decodeMessage<UnpairRequestMessage>(
620
+ MessageKind.UnpairRequest,
621
+ result.request_proto_bytes,
622
+ ),
623
+ };
624
+ },
625
+ },
626
+
627
+ response: {
628
+ produce(channel_id: bigint, shared_key: Uint8Array): ProduceResult {
629
+ const envelope = call('produce_unpair_response_message', channel_id, shared_key);
630
+ return { envelope: bytes(envelope) };
631
+ },
632
+
633
+ extract(
634
+ envelope_bytes: Uint8Array,
635
+ shared_key: Uint8Array,
636
+ ): { response: UnpairResponseMessage } {
637
+ const result = call('extract_unpair_response', envelope_bytes, shared_key) as {
638
+ response_proto_bytes: ArrayBuffer;
639
+ };
640
+ return {
641
+ response: decodeMessage<UnpairResponseMessage>(
642
+ MessageKind.UnpairResponse,
643
+ result.response_proto_bytes,
644
+ ),
645
+ };
646
+ },
647
+
648
+ /**
649
+ * `acknowledged` is `true` for every value this can return. The library's
650
+ * `unpairing::response::process` yields `ProcessResult { acknowledged:
651
+ * true }` on success and an error on a non-Ok peer status, and the C ABI
652
+ * carries only the error — so a refusal arrives as a thrown `DeRecError`,
653
+ * never as `acknowledged: false`. The field exists because
654
+ * `@derec-alliance/nodejs` surfaces it, where serde serializes the same
655
+ * constant.
656
+ */
657
+ process(response: UnpairResponseMessage): UnpairingProcessResult {
658
+ call('process_unpair_response_message', encodeMessage(MessageKind.UnpairResponse, response));
659
+ return { acknowledged: true };
660
+ },
661
+ },
662
+ };
663
+
664
+ const verification = {
665
+ request: {
666
+ produce(
667
+ channel_id: bigint,
668
+ secret_id: bigint,
669
+ version: number,
670
+ shared_key: Uint8Array,
671
+ reply_to?: TransportProtocol | null,
672
+ ): ProduceResult {
673
+ const envelope = call(
674
+ 'produce_verify_share_request_message',
675
+ channel_id,
676
+ secret_id,
677
+ version,
678
+ shared_key,
679
+ replyTo(reply_to),
680
+ );
681
+ return { envelope: bytes(envelope) };
682
+ },
683
+
684
+ extract(
685
+ envelope_bytes: Uint8Array,
686
+ shared_key: Uint8Array,
687
+ ): { request: VerifyShareRequestMessage } {
688
+ const result = call('extract_verify_share_request', envelope_bytes, shared_key) as {
689
+ request_proto_bytes: ArrayBuffer;
690
+ };
691
+ return {
692
+ request: decodeMessage<VerifyShareRequestMessage>(
693
+ MessageKind.VerifyShareRequest,
694
+ result.request_proto_bytes,
695
+ ),
696
+ };
697
+ },
698
+ },
699
+
700
+ response: {
701
+ produce(
702
+ channel_id: bigint,
703
+ request: VerifyShareRequestMessage,
704
+ shared_key: Uint8Array,
705
+ share_content: Uint8Array,
706
+ ): ProduceResult {
707
+ const envelope = call(
708
+ 'produce_verify_share_response_message',
709
+ channel_id,
710
+ encodeMessage(MessageKind.VerifyShareRequest, request),
711
+ shared_key,
712
+ share_content,
713
+ );
714
+ return { envelope: bytes(envelope) };
715
+ },
716
+
717
+ extract(
718
+ envelope_bytes: Uint8Array,
719
+ shared_key: Uint8Array,
720
+ ): { response: VerifyShareResponseMessage } {
721
+ const result = call('extract_verify_share_response', envelope_bytes, shared_key) as {
722
+ response_proto_bytes: ArrayBuffer;
723
+ };
724
+ return {
725
+ response: decodeMessage<VerifyShareResponseMessage>(
726
+ MessageKind.VerifyShareResponse,
727
+ result.response_proto_bytes,
728
+ ),
729
+ };
730
+ },
731
+
732
+ /** `request` must be the request the owner previously produced for this
733
+ * challenge. Responses whose `(nonce, secret_id, version)` triple does
734
+ * not match are rejected — that is the anti-replay gate. */
735
+ process(
736
+ request: VerifyShareRequestMessage,
737
+ response: VerifyShareResponseMessage,
738
+ share_content: Uint8Array,
739
+ ): boolean {
740
+ return call(
741
+ 'process_verify_share_response_message',
742
+ encodeMessage(MessageKind.VerifyShareRequest, request),
743
+ encodeMessage(MessageKind.VerifyShareResponse, response),
744
+ share_content,
745
+ ) as boolean;
746
+ },
747
+ },
748
+ };
749
+
750
+ export const primitives = {
751
+ discovery,
752
+ pairing,
753
+ recovery,
754
+ sharing,
755
+ unpairing,
756
+ verification,
757
+ };
758
+
759
+ /**
760
+ * Envelope-level helpers that operate on raw `DeRecMessage` bytes without
761
+ * touching the encrypted inner payload.
762
+ */
763
+ export const envelope = {
764
+ apply_trace_id(envelope_bytes: Uint8Array, trace_id: bigint): Uint8Array {
765
+ return bytes(call('apply_trace_id_to_envelope', envelope_bytes, trace_id));
766
+ },
767
+ read_trace_id(envelope_bytes: Uint8Array): bigint {
768
+ return call('read_trace_id_from_envelope', envelope_bytes) as bigint;
769
+ },
770
+ };