@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,2145 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 DeRec Alliance. All rights reserved.
3
+ //
4
+ // GENERATED FILE - DO NOT EDIT.
5
+ // Regenerate with: scripts/prepare-react-native-package.sh
6
+
7
+ #ifndef DEREC_FFI_H
8
+ #define DEREC_FFI_H
9
+
10
+ #include <stdarg.h>
11
+ #include <stdbool.h>
12
+ #include <stddef.h>
13
+ #include <stdint.h>
14
+ #include <stdlib.h>
15
+
16
+ /**
17
+ * `share` bytes carry a **full `Secret` payload** (`DeRecSecret` proto)
18
+ * instead of a single VSS share fragment. Used on replica channels —
19
+ * every replica holds an identical copy of the secret rather than a
20
+ * reconstructable fragment of it.
21
+ *
22
+ * Disambiguates the payload semantics on the wire; the receiver's
23
+ * `Channel.peer_role` is the authoritative source of truth, but a distinct
24
+ * `share_algorithm` value lets wire dumps and middle-boxes tell the two
25
+ * payload shapes apart without channel-state context.
26
+ */
27
+ #define SHARE_ALGORITHM_REPLICA_SECRET 1
28
+
29
+ /**
30
+ * Latest encoding major version, used for all new encodes. Bump only on a
31
+ * breaking format change, adding the matching `vN` module and match arm.
32
+ */
33
+ #define LATEST 2
34
+
35
+ /**
36
+ * Minimum number of shares required to reconstruct the secret, absent an
37
+ * explicit [`DeRecProtocolBuilder::with_threshold`] call. This is the sole
38
+ * definition of the value — [`DeRecProtocolBuilder::new`] and the FFI
39
+ * config's serde default both read it rather than each hardcoding `3`.
40
+ */
41
+ #define DEFAULT_THRESHOLD 3
42
+
43
+ /**
44
+ * Number of recent share versions each helper retains, absent an explicit
45
+ * [`DeRecProtocolBuilder::with_keep_versions_count`] call. Sole definition
46
+ * of the value; see [`DEFAULT_THRESHOLD`].
47
+ */
48
+ #define DEFAULT_KEEP_VERSIONS_COUNT 3
49
+
50
+ /**
51
+ * Maximum accepted transport URI length, in bytes.
52
+ *
53
+ * Matches the de-facto 2048-byte limit most HTTP stacks enforce
54
+ * for request URIs. Pairing payloads embed the URI verbatim, so
55
+ * capping it also bounds the propagated blob size.
56
+ */
57
+ #define MAX_TRANSPORT_URI_LEN 2048
58
+
59
+ #define DEREC_CATEGORY_OK 0
60
+
61
+ #define DEREC_CATEGORY_FFI 1
62
+
63
+ #define DEREC_CATEGORY_PAIRING 2
64
+
65
+ #define DEREC_CATEGORY_SHARING 3
66
+
67
+ #define DEREC_CATEGORY_RECOVERY 4
68
+
69
+ #define DEREC_CATEGORY_VERIFICATION 5
70
+
71
+ #define DEREC_CATEGORY_DISCOVERY 6
72
+
73
+ #define DEREC_CATEGORY_UNPAIRING 7
74
+
75
+ #define DEREC_CATEGORY_DEREC_MESSAGE 8
76
+
77
+ #define DEREC_CATEGORY_SECRET_STORE 9
78
+
79
+ #define DEREC_CATEGORY_CHANNEL_STORE 10
80
+
81
+ #define DEREC_CATEGORY_SHARE_STORE 11
82
+
83
+ #define DEREC_CATEGORY_INVALID_INPUT 12
84
+
85
+ #define DEREC_CATEGORY_PROTOBUF 13
86
+
87
+ #define DEREC_CATEGORY_INVARIANT 14
88
+
89
+ #define DEREC_CATEGORY_STATE_STORE 15
90
+
91
+ #define DEREC_CODE_OK 0
92
+
93
+ #define DEREC_CODE_NON_OK_STATUS 1
94
+
95
+ #define DEREC_CODE_VERSION_MISMATCH 2
96
+
97
+ #define DEREC_CODE_INVARIANT 3
98
+
99
+ #define DEREC_CODE_INVALID_INPUT 4
100
+
101
+ #define DEREC_CODE_PROTOBUF_DECODE 5
102
+
103
+ #define DEREC_CODE_PROTOBUF_ENCODE 6
104
+
105
+ #define DEREC_CODE_PROTOCOL_VIOLATION 7
106
+
107
+ #define DEREC_CODE_STORE_ERROR 8
108
+
109
+ #define DEREC_CODE_BUILDER_ERROR 9
110
+
111
+ /**
112
+ * `SecretStore::load_many(.., MissingPolicy::Fail)` returned because one or
113
+ * more channels had no `SharedKey` entry. The formatted `message` carries
114
+ * the missing channel ids (e.g. `"secret store: missing SharedKey entries
115
+ * for channel(s): [42, 7]"`). `category` is
116
+ * [`DEREC_CATEGORY_SECRET_STORE`].
117
+ */
118
+ #define DEREC_CODE_MISSING_SHARED_KEY 10
119
+
120
+ /**
121
+ * Flow or inbound message attempted against a channel where this node holds
122
+ * the wrong [`derec_proto::SenderKind`]. Surfaced as
123
+ * [`DEREC_CATEGORY_INVALID_INPUT`].
124
+ */
125
+ #define DEREC_CODE_ROLE_MISMATCH 11
126
+
127
+ /**
128
+ * The protocol was constructed without `with_replica_id(..)` but a
129
+ * replica-mode flow was attempted. Returned by every entry point that
130
+ * requires local replica identity. `DEREC_CATEGORY_INVALID_INPUT`.
131
+ */
132
+ #define DEREC_CODE_REPLICA_ID_NOT_CONFIGURED 12
133
+
134
+ /**
135
+ * `start(Pairing)` was called for a `channel_id` that already has a
136
+ * `Paired` channel record. Returned by both the inline-keys and
137
+ * hashed-keys branches of `start`. `DEREC_CATEGORY_INVALID_INPUT`.
138
+ */
139
+ #define DEREC_CODE_CHANNEL_ALREADY_PAIRED 13
140
+
141
+ /**
142
+ * `derec_protocol_restore` precondition: a `UserSecrets` snapshot
143
+ * already exists for the protocol's `secret_id`. The application must
144
+ * clear it before retrying. `DEREC_CATEGORY_INVALID_INPUT`.
145
+ */
146
+ #define DEREC_CODE_ALREADY_RESTORED 14
147
+
148
+ /**
149
+ * `derec_protocol_restore` precondition: one or more channels live at
150
+ * canonical helper / replica ids carried by the recovered `Secret`.
151
+ * `DeRecError::message` formats the collision list as
152
+ * `"restore conflict: channel(s) [a, b, ...]"`.
153
+ * `DEREC_CATEGORY_INVALID_INPUT`.
154
+ */
155
+ #define DEREC_CODE_RESTORE_CONFLICT 15
156
+
157
+ /**
158
+ * A replica pairing named a `replica_id` already held by another member of
159
+ * the group, this device included. Assignment is the application's, so this
160
+ * is a configuration fault: assign a distinct id and pair again.
161
+ * `DEREC_CATEGORY_INVALID_INPUT`.
162
+ */
163
+ #define DEREC_CODE_REPLICA_ID_CONFLICT 16
164
+
165
+ #define DEREC_CODE_ENCRYPTION 20
166
+
167
+ #define DEREC_CODE_KEYGEN 21
168
+
169
+ #define DEREC_CODE_FINISH_PAIRING_INITIATOR 22
170
+
171
+ #define DEREC_CODE_FINISH_PAIRING_RESPONDER 23
172
+
173
+ #define DEREC_CODE_EMPTY_TRANSPORT_URI 40
174
+
175
+ #define DEREC_CODE_INVALID_CONTACT_MESSAGE 41
176
+
177
+ #define DEREC_CODE_INVALID_PAIR_REQUEST_MESSAGE 42
178
+
179
+ #define DEREC_CODE_INVALID_PAIR_RESPONSE_MESSAGE 43
180
+
181
+ /**
182
+ * `HashedKeys` pairing — the scanner recomputed the SHA-384 binding hash
183
+ * over the public keys published in `PrePairResponseMessage` and got a
184
+ * digest that doesn't match `ContactMessage.contactBindingHash`. Surfaced
185
+ * as [`DEREC_CATEGORY_PAIRING`]. Distinct from a generic
186
+ * [`DEREC_CODE_PROTOCOL_VIOLATION`] so applications can flag this with
187
+ * the security-relevant framing it deserves (the contact the user
188
+ * scanned does not match the keys they would pair with).
189
+ */
190
+ #define DEREC_CODE_PREPAIR_HASH_MISMATCH 44
191
+
192
+ /**
193
+ * A replica-mode pairing arrived without the reserved
194
+ * `derec.replica_id` key in `CommunicationInfo`.
195
+ * `DEREC_CATEGORY_PAIRING`.
196
+ */
197
+ #define DEREC_CODE_MISSING_REPLICA_ID 45
198
+
199
+ /**
200
+ * A non-replica pairing carried the reserved `derec.replica_id` key in
201
+ * `CommunicationInfo`. `DEREC_CATEGORY_PAIRING`.
202
+ */
203
+ #define DEREC_CODE_UNEXPECTED_REPLICA_ID 46
204
+
205
+ /**
206
+ * The peer's [`derec_proto::ParameterRange`] does not overlap the
207
+ * locally-configured one on some field (e.g. `local.minShareSize >
208
+ * peer.maxShareSize`). `DEREC_CATEGORY_PAIRING`. The
209
+ * [`DeRecError::message`](DeRecError) carries the field name and
210
+ * both `(min, max)` pairs.
211
+ */
212
+ #define DEREC_CODE_INCOMPATIBLE_PARAMETER_RANGE 47
213
+
214
+ #define DEREC_CODE_EMPTY_CHANNELS 60
215
+
216
+ #define DEREC_CODE_DUPLICATE_CHANNEL_ID 61
217
+
218
+ #define DEREC_CODE_INVALID_THRESHOLD 62
219
+
220
+ #define DEREC_CODE_EMPTY_SECRET_DATA 63
221
+
222
+ #define DEREC_CODE_VSS_SHARE_FAILED 64
223
+
224
+ #define DEREC_CODE_EMPTY_RESPONSES 80
225
+
226
+ #define DEREC_CODE_EMPTY_COMMITTED_DEREC_SHARE 81
227
+
228
+ #define DEREC_CODE_DECODE_COMMITTED_DEREC_SHARE 82
229
+
230
+ #define DEREC_CODE_DECODE_DEREC_SHARE 83
231
+
232
+ #define DEREC_CODE_SECRET_ID_MISMATCH 84
233
+
234
+ #define DEREC_CODE_RECONSTRUCTION_FAILED 85
235
+
236
+ /**
237
+ * VSS reconstruction succeeded but the resulting bytes did not decode as
238
+ * the canonical `DeRecSecret` / `Secret` protobuf. Almost always a sign
239
+ * of share corruption.
240
+ */
241
+ #define DEREC_CODE_MALFORMED_RECOVERED_SECRET 86
242
+
243
+ #define DEREC_CODE_FFI_NULL_PTR 100
244
+
245
+ #define DEREC_CODE_FFI_BAD_LENGTH 101
246
+
247
+ #define DEREC_CODE_FFI_BAD_UTF8 102
248
+
249
+ #define DEREC_CODE_FFI_BAD_PROTO 103
250
+
251
+ #define DEREC_CODE_FFI_INVALID_ENUM 104
252
+
253
+ #define DEREC_CODE_FFI_BAD_SHARED_KEY 105
254
+
255
+ #define DEREC_CODE_FFI_NUL_IN_STRING 106
256
+
257
+ /**
258
+ * Transport URI/protocol pair failed [`crate::transport::validate`]:
259
+ * length cap, control character, unknown protocol discriminant, or
260
+ * URI scheme that doesn't match the declared `Protocol`. Surfaced
261
+ * as [`DEREC_CATEGORY_INVALID_INPUT`]. The
262
+ * [`DeRecError::message`](DeRecError) carries the specific reason.
263
+ */
264
+ #define DEREC_CODE_TRANSPORT_INVALID 120
265
+
266
+ /**
267
+ * Discriminants selecting which message [`derec_decode_message_json`] and
268
+ * [`derec_encode_message_json`] operate on.
269
+ *
270
+ * Mirrored in `bindings/test_fixture/enums.json`, which every SDK asserts
271
+ * against, so a message added here cannot reach a binding as a silently
272
+ * unhandled value.
273
+ */
274
+ #define DEREC_MESSAGE_KIND_PAIR_REQUEST 0
275
+
276
+ #define DEREC_MESSAGE_KIND_PAIR_RESPONSE 1
277
+
278
+ #define DEREC_MESSAGE_KIND_PRE_PAIR_REQUEST 2
279
+
280
+ #define DEREC_MESSAGE_KIND_PRE_PAIR_RESPONSE 3
281
+
282
+ #define DEREC_MESSAGE_KIND_GET_SECRET_IDS_VERSIONS_REQUEST 4
283
+
284
+ #define DEREC_MESSAGE_KIND_GET_SECRET_IDS_VERSIONS_RESPONSE 5
285
+
286
+ #define DEREC_MESSAGE_KIND_GET_SHARE_REQUEST 6
287
+
288
+ #define DEREC_MESSAGE_KIND_GET_SHARE_RESPONSE 7
289
+
290
+ #define DEREC_MESSAGE_KIND_STORE_SHARE_REQUEST 8
291
+
292
+ #define DEREC_MESSAGE_KIND_STORE_SHARE_RESPONSE 9
293
+
294
+ #define DEREC_MESSAGE_KIND_UNPAIR_REQUEST 10
295
+
296
+ #define DEREC_MESSAGE_KIND_UNPAIR_RESPONSE 11
297
+
298
+ #define DEREC_MESSAGE_KIND_VERIFY_SHARE_REQUEST 12
299
+
300
+ #define DEREC_MESSAGE_KIND_VERIFY_SHARE_RESPONSE 13
301
+
302
+ /**
303
+ * Not a standalone message on the wire, but it crosses this FFI on its own
304
+ * as the `transport_protocol` argument of `create_contact_message` and the
305
+ * `peer_transport_protocol` result of `produce_pair_response_message`.
306
+ */
307
+ #define DEREC_MESSAGE_KIND_TRANSPORT_PROTOCOL 14
308
+
309
+ /**
310
+ * Crosses on its own as the `communication_info` argument of the pairing
311
+ * produce calls. See [`DEREC_MESSAGE_KIND_TRANSPORT_PROTOCOL`].
312
+ */
313
+ #define DEREC_MESSAGE_KIND_COMMUNICATION_INFO 15
314
+
315
+ /**
316
+ * Crosses on its own as the `parameter_range` argument of the pairing
317
+ * produce calls. See [`DEREC_MESSAGE_KIND_TRANSPORT_PROTOCOL`].
318
+ */
319
+ #define DEREC_MESSAGE_KIND_PARAMETER_RANGE 16
320
+
321
+ /**
322
+ * Crosses on its own as the `committed_share` argument of
323
+ * `produce_store_share_request_message` and as the `committed_share_bytes`
324
+ * result of `produce_store_share_response_message`.
325
+ */
326
+ #define DEREC_MESSAGE_KIND_COMMITTED_DEREC_SHARE 17
327
+
328
+ /**
329
+ * Numeric flow-kind identifiers — must match the dotnet `FlowKind` enum.
330
+ */
331
+ #define FLOW_KIND_PAIRING 0
332
+
333
+ #define FLOW_KIND_DISCOVERY 1
334
+
335
+ #define FLOW_KIND_PROTECT_SECRET 2
336
+
337
+ #define FLOW_KIND_VERIFY_SHARES 3
338
+
339
+ #define FLOW_KIND_RECOVER_SECRET 4
340
+
341
+ #define FLOW_KIND_UNPAIR 5
342
+
343
+ #define FLOW_KIND_UPDATE_CHANNEL_INFO 6
344
+
345
+ /**
346
+ * Replica catch-up. Takes no parameters: the group and this device's own
347
+ * version are both read from the stores.
348
+ */
349
+ #define FLOW_KIND_SYNC_CHECK 7
350
+
351
+ /**
352
+ * Remove a member from the replica group. Params:
353
+ * `{ "replica_id": "<decimal>", "memo": "<optional>" }`.
354
+ */
355
+ #define FLOW_KIND_REMOVE_REPLICA 8
356
+
357
+ /**
358
+ * Opaque handle returned by [`derec_protocol_new`] and consumed by
359
+ * every other entry point in this module. Holds the protocol instance + the
360
+ * per-handle tokio runtime used to drive the async core synchronously.
361
+ *
362
+ * The `inner` protocol is wrapped in [`std::sync::Mutex`] so concurrent
363
+ * FFI calls from different host threads (.NET worker pool, Node.js
364
+ * worker_threads, etc.) are safe by construction. Each entry point
365
+ * locks the mutex for the duration of its call, serializing access to
366
+ * the protocol state — no `&mut DeRecProtocolHandle` is ever
367
+ * materialized, so aliased `&mut` references (which would be immediate
368
+ * undefined behavior) cannot arise even under contention. The tokio
369
+ * `Runtime` itself is `Sync` and accepts `&self` `block_on`, but
370
+ * holding the protocol lock across `block_on` also serializes runtime
371
+ * invocations on the current-thread executor.
372
+ */
373
+ typedef struct DeRecProtocolHandle DeRecProtocolHandle;
374
+
375
+ /**
376
+ * DeRec protocol version supported by this SDK.
377
+ *
378
+ * This type represents the protocol-level version carried in the
379
+ * [`DeRecMessage`](derec_proto::DeRecMessage) envelope:
380
+ *
381
+ * - `protocolVersionMajor`
382
+ * - `protocolVersionMinor`
383
+ *
384
+ * This is **not** the same as the Rust crate version, npm package version,
385
+ * or NuGet package version. Package versions identify SDK releases, while
386
+ * `ProtocolVersion` identifies the DeRec wire protocol version expected by
387
+ * protocol messages.
388
+ *
389
+ * # Fields
390
+ *
391
+ * * `major` - Protocol major version.
392
+ * * `minor` - Protocol minor version.
393
+ *
394
+ * # Compatibility
395
+ *
396
+ * The compatibility policy associated with protocol major/minor versions is
397
+ * defined by the DeRec protocol specification, not by this helper type.
398
+ *
399
+ * # Example
400
+ *
401
+ * ```rust
402
+ * use derec_library::protocol_version::ProtocolVersion;
403
+ *
404
+ * let version = ProtocolVersion::current();
405
+ *
406
+ * assert!(version.major >= 0);
407
+ * assert!(version.minor >= 0);
408
+ * ```
409
+ */
410
+ typedef struct ProtocolVersion ProtocolVersion;
411
+
412
+ typedef struct DeRecError {
413
+ int32_t category;
414
+ int32_t code;
415
+ /**
416
+ * Owned C string. Null on success. Released by [`derec_free_error`].
417
+ */
418
+ char *message;
419
+ /**
420
+ * Valid when `code == DEREC_CODE_NON_OK_STATUS`.
421
+ */
422
+ int32_t peer_status;
423
+ /**
424
+ * Owned C string. Null when not applicable. Released by [`derec_free_error`].
425
+ */
426
+ char *peer_memo;
427
+ /**
428
+ * Valid when `code == DEREC_CODE_VERSION_MISMATCH`.
429
+ */
430
+ uint32_t expected;
431
+ /**
432
+ * Valid when `code == DEREC_CODE_VERSION_MISMATCH`.
433
+ */
434
+ uint32_t got;
435
+ } DeRecError;
436
+
437
+ typedef struct DeRecBuffer {
438
+ uint8_t *ptr;
439
+ size_t len;
440
+ } DeRecBuffer;
441
+
442
+ typedef struct ProduceGetSecretIdsVersionsRequestMessageResult {
443
+ struct DeRecError error;
444
+ struct DeRecBuffer envelope_wire_bytes;
445
+ } ProduceGetSecretIdsVersionsRequestMessageResult;
446
+
447
+ typedef struct ExtractGetSecretIdsVersionsRequestResult {
448
+ struct DeRecError error;
449
+ uint64_t channel_id;
450
+ /**
451
+ * prost-encoded inner `GetSecretIdsVersionsRequestMessage` bytes.
452
+ * Empty buffer when extraction fails. SDK consumers decode this
453
+ * to inspect optional fields such as `reply_to`.
454
+ */
455
+ struct DeRecBuffer request_proto_bytes;
456
+ } ExtractGetSecretIdsVersionsRequestResult;
457
+
458
+ typedef struct ProduceGetSecretIdsVersionsResponseMessageResult {
459
+ struct DeRecError error;
460
+ struct DeRecBuffer envelope_wire_bytes;
461
+ } ProduceGetSecretIdsVersionsResponseMessageResult;
462
+
463
+ typedef struct ExtractGetSecretIdsVersionsResponseResult {
464
+ struct DeRecError error;
465
+ uint64_t channel_id;
466
+ /**
467
+ * Inner `GetSecretIdsVersionsResponseMessage` proto bytes for chaining
468
+ * into [`process_get_secret_ids_versions_response_message`].
469
+ */
470
+ struct DeRecBuffer response_proto_bytes;
471
+ } ExtractGetSecretIdsVersionsResponseResult;
472
+
473
+ typedef struct ProcessGetSecretIdsVersionsResponseMessageResult {
474
+ struct DeRecError error;
475
+ /**
476
+ * Validated secret list in the format documented at the module level.
477
+ */
478
+ struct DeRecBuffer secret_list_bytes;
479
+ } ProcessGetSecretIdsVersionsResponseMessageResult;
480
+
481
+ typedef struct ApplyTraceIdResult {
482
+ struct DeRecError error;
483
+ /**
484
+ * Re-encoded envelope bytes with `trace_id` overwritten. Empty on error.
485
+ */
486
+ struct DeRecBuffer wire_bytes;
487
+ } ApplyTraceIdResult;
488
+
489
+ typedef struct ReadTraceIdResult {
490
+ struct DeRecError error;
491
+ /**
492
+ * Trace id read off the envelope. Zero on error (also zero if the
493
+ * sender did not set one — the protobuf default is indistinguishable).
494
+ */
495
+ uint64_t trace_id;
496
+ } ReadTraceIdResult;
497
+
498
+ /**
499
+ * Result of a message JSON codec call. `bytes` is UTF-8 JSON for
500
+ * [`derec_decode_message_json`] and protobuf wire bytes for
501
+ * [`derec_encode_message_json`]; it is empty when `error` is non-zero.
502
+ */
503
+ typedef struct DeRecMessageJsonResult {
504
+ struct DeRecError error;
505
+ struct DeRecBuffer bytes;
506
+ } DeRecMessageJsonResult;
507
+
508
+ typedef struct CreateContactMessageResult {
509
+ struct DeRecError error;
510
+ struct DeRecBuffer contact_wire_bytes;
511
+ /**
512
+ * Opaque pairing secret key material. See module docs.
513
+ */
514
+ struct DeRecBuffer secret_key_material;
515
+ } CreateContactMessageResult;
516
+
517
+ typedef struct EncodeContactMessageResult {
518
+ struct DeRecError error;
519
+ /**
520
+ * Proto-encoded `ContactMessage`, ready to publish out of band.
521
+ */
522
+ struct DeRecBuffer wire_bytes;
523
+ } EncodeContactMessageResult;
524
+
525
+ typedef struct DecodeContactMessageResult {
526
+ struct DeRecError error;
527
+ /**
528
+ * UTF-8 JSON object. See [`encode_contact_message`] for the shape.
529
+ */
530
+ struct DeRecBuffer contact_json;
531
+ } DecodeContactMessageResult;
532
+
533
+ typedef struct ProducePairRequestMessageResult {
534
+ struct DeRecError error;
535
+ struct DeRecBuffer request_wire_bytes;
536
+ struct DeRecBuffer initiator_contact_message_wire_bytes;
537
+ /**
538
+ * Opaque pairing secret key material. See module docs.
539
+ */
540
+ struct DeRecBuffer secret_key_material;
541
+ } ProducePairRequestMessageResult;
542
+
543
+ typedef struct ExtractPairRequestResult {
544
+ struct DeRecError error;
545
+ uint64_t channel_id;
546
+ /**
547
+ * Inner `PairRequestMessage` proto bytes for chaining into
548
+ * [`produce_pair_response_message`].
549
+ */
550
+ struct DeRecBuffer request_proto_bytes;
551
+ } ExtractPairRequestResult;
552
+
553
+ typedef struct ProducePairResponseMessageResult {
554
+ struct DeRecError error;
555
+ struct DeRecBuffer response_wire_bytes;
556
+ struct DeRecBuffer peer_transport_protocol;
557
+ struct DeRecBuffer shared_key;
558
+ /**
559
+ * Post-handshake rekey channel id the responder is committing to.
560
+ * Callers MUST atomically rename their local channel record from the
561
+ * pre-rekey id (the one passed to `produce_pair_response_message`) to
562
+ * this value as part of accepting the response. Zero on error.
563
+ */
564
+ uint64_t channel_id;
565
+ } ProducePairResponseMessageResult;
566
+
567
+ typedef struct ExtractPairResponseResult {
568
+ struct DeRecError error;
569
+ uint64_t channel_id;
570
+ /**
571
+ * Inner `PairResponseMessage` proto bytes for chaining into
572
+ * [`process_pair_response_message`].
573
+ */
574
+ struct DeRecBuffer response_proto_bytes;
575
+ } ExtractPairResponseResult;
576
+
577
+ /**
578
+ * `shared_key` is populated only on success; empty on peer rejection (see
579
+ * [`crate::interop::ffi::error`]).
580
+ */
581
+ typedef struct ProcessPairResponseMessageResult {
582
+ struct DeRecError error;
583
+ struct DeRecBuffer shared_key;
584
+ /**
585
+ * Post-handshake rekey channel id — already validated against the
586
+ * caller's own derivation. Callers MUST atomically rename their local
587
+ * channel record from the pre-rekey id (the one in the contact) to
588
+ * this value. Zero on error.
589
+ */
590
+ uint64_t channel_id;
591
+ } ProcessPairResponseMessageResult;
592
+
593
+ typedef struct ProducePrePairRequestMessageResult {
594
+ struct DeRecError error;
595
+ /**
596
+ * Serialized outer plaintext `DeRecMessage` envelope carrying a
597
+ * `PrePairRequestMessage`. Ready to send over transport.
598
+ */
599
+ struct DeRecBuffer envelope_wire_bytes;
600
+ } ProducePrePairRequestMessageResult;
601
+
602
+ typedef struct ExtractPrePairRequestResult {
603
+ struct DeRecError error;
604
+ /**
605
+ * Channel identifier decoded from the outer envelope's routing field.
606
+ */
607
+ uint64_t channel_id;
608
+ /**
609
+ * Inner `PrePairRequestMessage` proto bytes for chaining into
610
+ * [`produce_pre_pair_response_message`].
611
+ */
612
+ struct DeRecBuffer request_proto_bytes;
613
+ } ExtractPrePairRequestResult;
614
+
615
+ typedef struct ProducePrePairResponseMessageResult {
616
+ struct DeRecError error;
617
+ /**
618
+ * Serialized outer plaintext `DeRecMessage` envelope carrying a
619
+ * `PrePairResponseMessage`. Ready to send over transport.
620
+ */
621
+ struct DeRecBuffer envelope_wire_bytes;
622
+ } ProducePrePairResponseMessageResult;
623
+
624
+ typedef struct ExtractPrePairResponseResult {
625
+ struct DeRecError error;
626
+ /**
627
+ * Channel identifier decoded from the outer envelope's routing field.
628
+ */
629
+ uint64_t channel_id;
630
+ /**
631
+ * Inner `PrePairResponseMessage` proto bytes for chaining into
632
+ * [`process_pre_pair_response_message`].
633
+ */
634
+ struct DeRecBuffer response_proto_bytes;
635
+ } ExtractPrePairResponseResult;
636
+
637
+ /**
638
+ * On success the two key buffers hold the validated public keys republished
639
+ * by the contact creator. On failure (status non-Ok, hash mismatch, etc.)
640
+ * both buffers are empty; consult `error`.
641
+ */
642
+ typedef struct ProcessPrePairResponseMessageResult {
643
+ struct DeRecError error;
644
+ struct DeRecBuffer mlkem_encapsulation_key;
645
+ struct DeRecBuffer ecies_public_key;
646
+ /**
647
+ * Nonce echoed from the original `ContactMessage`. Zero on failure.
648
+ */
649
+ uint64_t nonce;
650
+ } ProcessPrePairResponseMessageResult;
651
+
652
+ /**
653
+ * Result type for [`derec_protocol_new`].
654
+ */
655
+ typedef struct DeRecProtocolNewResult {
656
+ struct DeRecError error;
657
+ /**
658
+ * On success, the opaque handle. On error, null.
659
+ */
660
+ struct DeRecProtocolHandle *handle;
661
+ } DeRecProtocolNewResult;
662
+
663
+ /**
664
+ * Caller-supplied callbacks for channel persistence.
665
+ *
666
+ * All function pointers are invoked synchronously from the protocol's
667
+ * async core (the FFI shim drives futures with `block_on`). Buffer
668
+ * ownership for any byte payload returned via out-parameters belongs
669
+ * to the caller; the shim copies into a Rust `Vec` and then calls
670
+ * [`Self::free_buffer`] to release the original allocation.
671
+ *
672
+ * Return code convention:
673
+ * - `0` on success
674
+ * - `1` on "not found" (only meaningful for `load`)
675
+ * - any other value indicates a backend failure; the shim wraps it as
676
+ * [`ChannelStoreError::Backend`]
677
+ *
678
+ * # Addressing a record
679
+ *
680
+ * `load`, `save` and `remove` take a `(channel_id, replica_id)` pair. A
681
+ * `replica_id` of `0` — the value [`crate::types::ReplicaId`] reserves as
682
+ * "absent" — addresses the helper channel at `channel_id`.
683
+ *
684
+ * Any other value addresses that member of the replica group, and the member
685
+ * is keyed by **`replica_id` alone**. The accompanying `channel_id` is
686
+ * context, not part of the key: a member moves between channels during an
687
+ * admission handover while remaining the same member, and a lookup that
688
+ * required both to match would miss it exactly when the move needs to be
689
+ * observed. Backends therefore keep two maps — helpers by `channel_id`,
690
+ * members by `replica_id` — not one keyed by the pair.
691
+ *
692
+ * The `bytes` payload of `save`, and the buffer `load` returns, are a
693
+ * JSON-encoded [`crate::protocol::types::ChannelRecord`]. `list_helpers` and
694
+ * `list_replicas` return a JSON array of
695
+ * [`crate::protocol::types::HelperChannel`] and
696
+ * [`crate::protocol::types::ReplicaMember`] respectively.
697
+ *
698
+ * The order `list_replicas` returns is significant in exactly one situation —
699
+ * it selects the successor when the group's source is removed. See
700
+ * [`crate::protocol::DeRecChannelStore::replicas`] for the full contract.
701
+ */
702
+ typedef struct ChannelStoreCallbacks {
703
+ void *user_data;
704
+ int32_t (*load)(void *user_data,
705
+ uint64_t secret_id,
706
+ uint64_t channel_id,
707
+ uint64_t replica_id,
708
+ uint8_t **out_ptr,
709
+ size_t *out_len);
710
+ int32_t (*save)(void *user_data,
711
+ uint64_t secret_id,
712
+ uint64_t channel_id,
713
+ uint64_t replica_id,
714
+ const uint8_t *bytes,
715
+ size_t len);
716
+ int32_t (*remove)(void *user_data,
717
+ uint64_t secret_id,
718
+ uint64_t channel_id,
719
+ uint64_t replica_id,
720
+ uint32_t *out_existed);
721
+ int32_t (*list_helpers)(void *user_data, uint64_t secret_id, uint8_t **out_ptr, size_t *out_len);
722
+ int32_t (*list_replicas)(void *user_data, uint64_t secret_id, uint8_t **out_ptr, size_t *out_len);
723
+ int32_t (*link_channel)(void *user_data, uint64_t secret_id, uint64_t a, uint64_t b);
724
+ int32_t (*linked_channels)(void *user_data,
725
+ uint64_t secret_id,
726
+ uint64_t channel_id,
727
+ uint8_t **out_ptr,
728
+ size_t *out_len);
729
+ void (*free_buffer)(void *user_data, uint8_t *ptr, size_t len);
730
+ } ChannelStoreCallbacks;
731
+
732
+ /**
733
+ * Caller-supplied callbacks for secret persistence.
734
+ */
735
+ typedef struct SecretStoreCallbacks {
736
+ void *user_data;
737
+ int32_t (*load)(void *user_data,
738
+ uint64_t secret_id,
739
+ uint64_t channel_id,
740
+ uint32_t kind,
741
+ uint8_t **out_ptr,
742
+ size_t *out_len);
743
+ int32_t (*save)(void *user_data,
744
+ uint64_t secret_id,
745
+ uint64_t channel_id,
746
+ uint32_t kind,
747
+ const uint8_t *bytes,
748
+ size_t len);
749
+ int32_t (*remove)(void *user_data, uint64_t secret_id, uint64_t channel_id, uint32_t kind);
750
+ void (*free_buffer)(void *user_data, uint8_t *ptr, size_t len);
751
+ } SecretStoreCallbacks;
752
+
753
+ /**
754
+ * Caller-supplied callbacks for share persistence. Variable-length
755
+ * arrays (`channel_ids[]`, `versions[]`) cross the FFI as JSON
756
+ * strings, matching the `Vec<u8>` ↔ JSON-array convention used for
757
+ * every other wire-format buffer in this module.
758
+ */
759
+ typedef struct ShareStoreCallbacks {
760
+ void *user_data;
761
+ int32_t (*load)(void *user_data,
762
+ uint64_t secret_id,
763
+ uint64_t channel_id,
764
+ const uint8_t *versions_json_ptr,
765
+ size_t versions_json_len,
766
+ uint8_t **out_ptr,
767
+ size_t *out_len);
768
+ int32_t (*load_many)(void *user_data,
769
+ uint64_t secret_id,
770
+ const uint8_t *channel_ids_json_ptr,
771
+ size_t channel_ids_json_len,
772
+ const uint8_t *versions_json_ptr,
773
+ size_t versions_json_len,
774
+ uint8_t **out_ptr,
775
+ size_t *out_len);
776
+ int32_t (*load_all)(void *user_data,
777
+ uint64_t secret_id,
778
+ const uint8_t *channel_ids_json_ptr,
779
+ size_t channel_ids_json_len,
780
+ uint8_t **out_ptr,
781
+ size_t *out_len);
782
+ int32_t (*latest_version)(void *user_data,
783
+ uint64_t secret_id,
784
+ uint32_t *out_has_version,
785
+ uint32_t *out_version);
786
+ int32_t (*save)(void *user_data,
787
+ uint64_t secret_id,
788
+ uint64_t channel_id,
789
+ const uint8_t *share_json_ptr,
790
+ size_t share_json_len);
791
+ int32_t (*remove_channel)(void *user_data, uint64_t secret_id, uint64_t channel_id);
792
+ void (*free_buffer)(void *user_data, uint8_t *ptr, size_t len);
793
+ } ShareStoreCallbacks;
794
+
795
+ /**
796
+ * Caller-supplied callbacks for the user-secret store. Methods cross
797
+ * the FFI keyed by `secret_id`; the `UserSecrets` payload travels as a
798
+ * JSON buffer matching [`UserSecretsRecord`].
799
+ */
800
+ typedef struct UserSecretStoreCallbacks {
801
+ void *user_data;
802
+ /**
803
+ * `load_latest(secret_id, out_ptr, out_len)` — writes the JSON
804
+ * payload (or `out_len = 0` if absent). Caller releases the buffer
805
+ * via `free_buffer`.
806
+ */
807
+ int32_t (*load_latest)(void *user_data, uint64_t secret_id, uint8_t **out_ptr, size_t *out_len);
808
+ /**
809
+ * `save_latest(secret_id, value_json_ptr, value_json_len)`.
810
+ */
811
+ int32_t (*save_latest)(void *user_data,
812
+ uint64_t secret_id,
813
+ const uint8_t *value_json_ptr,
814
+ size_t value_json_len);
815
+ /**
816
+ * `remove(secret_id)` — idempotent.
817
+ */
818
+ int32_t (*remove)(void *user_data, uint64_t secret_id);
819
+ void (*free_buffer)(void *user_data, uint8_t *ptr, size_t len);
820
+ } UserSecretStoreCallbacks;
821
+
822
+ /**
823
+ * Caller-supplied callbacks for orchestrator in-flight state
824
+ * ([`DeRecStateStore`]). The item and key travel as JSON buffers
825
+ * matching [`StateItemRecord`] / [`StateKeyRecord`].
826
+ *
827
+ * # Return codes
828
+ *
829
+ * - `load`: `0` = found (record written), `1` = not found (empty
830
+ * payload), other = backend failure.
831
+ * - `remove`: `0` = ok (`*out_removed` set to `0` or `1`), other =
832
+ * backend failure.
833
+ * - `save` / `load_all`: `0` = ok, other = backend failure.
834
+ */
835
+ typedef struct StateStoreCallbacks {
836
+ void *user_data;
837
+ int32_t (*save)(void *user_data,
838
+ uint64_t secret_id,
839
+ const uint8_t *item_json_ptr,
840
+ size_t item_json_len);
841
+ int32_t (*load)(void *user_data,
842
+ uint64_t secret_id,
843
+ const uint8_t *key_json_ptr,
844
+ size_t key_json_len,
845
+ uint8_t **out_ptr,
846
+ size_t *out_len);
847
+ int32_t (*remove)(void *user_data,
848
+ uint64_t secret_id,
849
+ const uint8_t *key_json_ptr,
850
+ size_t key_json_len,
851
+ uint32_t *out_removed);
852
+ int32_t (*load_all)(void *user_data,
853
+ uint64_t secret_id,
854
+ uint32_t kind,
855
+ uint8_t **out_ptr,
856
+ size_t *out_len);
857
+ void (*free_buffer)(void *user_data, uint8_t *ptr, size_t len);
858
+ } StateStoreCallbacks;
859
+
860
+ /**
861
+ * Caller-supplied transport callback.
862
+ */
863
+ typedef struct TransportCallbacks {
864
+ void *user_data;
865
+ int32_t (*send)(void *user_data,
866
+ const uint8_t *uri_ptr,
867
+ size_t uri_len,
868
+ int32_t protocol,
869
+ const uint8_t *bytes,
870
+ size_t len);
871
+ } TransportCallbacks;
872
+
873
+ /**
874
+ * Result type for [`derec_protocol_remove_expired_channels`].
875
+ */
876
+ typedef struct DeRecRemovedChannelsResult {
877
+ struct DeRecError error;
878
+ /**
879
+ * On success, a heap-owned UTF-8 JSON array of removed channel ids as
880
+ * decimal strings — e.g. `["12","4096"]`. Decimal strings rather than
881
+ * JSON numbers because `u64` ids exceed `Number.MAX_SAFE_INTEGER`;
882
+ * this matches every other id crossing this boundary. Caller releases
883
+ * via [`crate::interop::ffi::common::derec_free_buffer`].
884
+ */
885
+ struct DeRecBuffer channels;
886
+ } DeRecRemovedChannelsResult;
887
+
888
+ /**
889
+ * Result type for entry points that return a `Vec<DeRecEvent>`.
890
+ */
891
+ typedef struct DeRecProtocolEventsResult {
892
+ struct DeRecError error;
893
+ /**
894
+ * UTF-8 JSON array of events. See [`crate::interop::ffi::protocol::events`]
895
+ * for the per-variant shape. Caller releases via
896
+ * [`crate::interop::ffi::derec_free_buffer`].
897
+ */
898
+ struct DeRecBuffer events_json;
899
+ } DeRecProtocolEventsResult;
900
+
901
+ /**
902
+ * Result type for fingerprint accessors.
903
+ */
904
+ typedef struct DeRecProtocolFingerprintResult {
905
+ struct DeRecError error;
906
+ /**
907
+ * On success, owned C string (heap-allocated). Caller releases via
908
+ * [`crate::interop::ffi::common::derec_free_string`].
909
+ */
910
+ char *fingerprint;
911
+ } DeRecProtocolFingerprintResult;
912
+
913
+ /**
914
+ * Result type for [`derec_protocol_create_contact`].
915
+ */
916
+ typedef struct DeRecProtocolCreateContactResult {
917
+ struct DeRecError error;
918
+ /**
919
+ * prost-encoded [`derec_proto::ContactMessage`] on success.
920
+ * Caller releases via [`crate::interop::ffi::derec_free_buffer`].
921
+ */
922
+ struct DeRecBuffer contact_wire_bytes;
923
+ } DeRecProtocolCreateContactResult;
924
+
925
+ typedef struct DeRecProtocolVersion {
926
+ uint32_t major;
927
+ uint32_t minor;
928
+ } DeRecProtocolVersion;
929
+
930
+ typedef struct ProduceGetShareRequestMessageResult {
931
+ struct DeRecError error;
932
+ struct DeRecBuffer request_wire_bytes;
933
+ } ProduceGetShareRequestMessageResult;
934
+
935
+ typedef struct ExtractGetShareRequestResult {
936
+ struct DeRecError error;
937
+ uint64_t channel_id;
938
+ /**
939
+ * Inner `GetShareRequestMessage` proto bytes for chaining into
940
+ * [`produce_get_share_response_message`].
941
+ */
942
+ struct DeRecBuffer request_proto_bytes;
943
+ } ExtractGetShareRequestResult;
944
+
945
+ typedef struct ProduceGetShareResponseMessageResult {
946
+ struct DeRecError error;
947
+ struct DeRecBuffer response_wire_bytes;
948
+ } ProduceGetShareResponseMessageResult;
949
+
950
+ typedef struct ExtractGetShareResponseResult {
951
+ struct DeRecError error;
952
+ uint64_t channel_id;
953
+ /**
954
+ * Inner `GetShareResponseMessage` proto bytes. Accumulate across helpers
955
+ * and pass to [`recover_from_share_responses`].
956
+ */
957
+ struct DeRecBuffer response_proto_bytes;
958
+ } ExtractGetShareResponseResult;
959
+
960
+ typedef struct RecoverFromShareResponsesResult {
961
+ struct DeRecError error;
962
+ struct DeRecBuffer secret_data;
963
+ } RecoverFromShareResponsesResult;
964
+
965
+ typedef struct ProtectSecretResult {
966
+ struct DeRecError error;
967
+ /**
968
+ * Committed shares in the format documented at the module level.
969
+ */
970
+ struct DeRecBuffer shares_wire_bytes;
971
+ } ProtectSecretResult;
972
+
973
+ typedef struct ProduceStoreShareRequestMessageResult {
974
+ struct DeRecError error;
975
+ struct DeRecBuffer wire_bytes;
976
+ } ProduceStoreShareRequestMessageResult;
977
+
978
+ typedef struct ExtractStoreShareRequestResult {
979
+ struct DeRecError error;
980
+ uint64_t channel_id;
981
+ /**
982
+ * Inner `StoreShareRequestMessage` proto bytes for chaining into
983
+ * [`produce_store_share_response_message`].
984
+ */
985
+ struct DeRecBuffer request_proto_bytes;
986
+ } ExtractStoreShareRequestResult;
987
+
988
+ /**
989
+ * `committed_share_bytes` is the serialized [`CommittedDeRecShare`] the
990
+ * helper should persist locally for later recovery responses.
991
+ */
992
+ typedef struct ProduceStoreShareResponseMessageResult {
993
+ struct DeRecError error;
994
+ struct DeRecBuffer wire_bytes;
995
+ struct DeRecBuffer committed_share_bytes;
996
+ uint64_t secret_id;
997
+ uint32_t version;
998
+ } ProduceStoreShareResponseMessageResult;
999
+
1000
+ typedef struct ExtractStoreShareResponseResult {
1001
+ struct DeRecError error;
1002
+ uint64_t channel_id;
1003
+ /**
1004
+ * Inner `StoreShareResponseMessage` proto bytes for chaining into
1005
+ * [`process_store_share_response_message`].
1006
+ */
1007
+ struct DeRecBuffer response_proto_bytes;
1008
+ } ExtractStoreShareResponseResult;
1009
+
1010
+ typedef struct ProcessStoreShareResponseMessageResult {
1011
+ struct DeRecError error;
1012
+ } ProcessStoreShareResponseMessageResult;
1013
+
1014
+ typedef struct ProduceUnpairRequestMessageResult {
1015
+ struct DeRecError error;
1016
+ struct DeRecBuffer request_wire_bytes;
1017
+ } ProduceUnpairRequestMessageResult;
1018
+
1019
+ typedef struct ExtractUnpairRequestResult {
1020
+ struct DeRecError error;
1021
+ uint64_t channel_id;
1022
+ /**
1023
+ * Decrypted memo. Release with `derec_free_string`.
1024
+ */
1025
+ char *memo;
1026
+ /**
1027
+ * prost-encoded inner `UnpairRequestMessage` bytes. SDK consumers
1028
+ * decode this to inspect optional fields such as `reply_to`.
1029
+ */
1030
+ struct DeRecBuffer request_proto_bytes;
1031
+ } ExtractUnpairRequestResult;
1032
+
1033
+ typedef struct ProduceUnpairResponseMessageResult {
1034
+ struct DeRecError error;
1035
+ struct DeRecBuffer response_wire_bytes;
1036
+ } ProduceUnpairResponseMessageResult;
1037
+
1038
+ typedef struct ExtractUnpairResponseResult {
1039
+ struct DeRecError error;
1040
+ uint64_t channel_id;
1041
+ /**
1042
+ * Inner `UnpairResponseMessage` proto bytes for chaining into
1043
+ * [`process_unpair_response_message`].
1044
+ */
1045
+ struct DeRecBuffer response_proto_bytes;
1046
+ } ExtractUnpairResponseResult;
1047
+
1048
+ typedef struct ProcessUnpairResponseResult {
1049
+ struct DeRecError error;
1050
+ } ProcessUnpairResponseResult;
1051
+
1052
+ typedef struct ProduceVerifyShareRequestMessageResult {
1053
+ struct DeRecError error;
1054
+ struct DeRecBuffer request_wire_bytes;
1055
+ } ProduceVerifyShareRequestMessageResult;
1056
+
1057
+ typedef struct ExtractVerifyShareRequestResult {
1058
+ struct DeRecError error;
1059
+ uint64_t channel_id;
1060
+ /**
1061
+ * Inner `VerifyShareRequestMessage` proto bytes for chaining into
1062
+ * [`produce_verify_share_response_message`].
1063
+ */
1064
+ struct DeRecBuffer request_proto_bytes;
1065
+ } ExtractVerifyShareRequestResult;
1066
+
1067
+ typedef struct ProduceVerifyShareResponseMessageResult {
1068
+ struct DeRecError error;
1069
+ struct DeRecBuffer response_wire_bytes;
1070
+ } ProduceVerifyShareResponseMessageResult;
1071
+
1072
+ typedef struct ExtractVerifyShareResponseResult {
1073
+ struct DeRecError error;
1074
+ uint64_t channel_id;
1075
+ /**
1076
+ * Inner `VerifyShareResponseMessage` proto bytes for chaining into
1077
+ * [`process_verify_share_response_message`].
1078
+ */
1079
+ struct DeRecBuffer response_proto_bytes;
1080
+ } ExtractVerifyShareResponseResult;
1081
+
1082
+ /**
1083
+ * `is_valid` is meaningful only on success. Peer rejection surfaces on
1084
+ * `error` (see [`crate::interop::ffi::error`]).
1085
+ */
1086
+ typedef struct VerifyShareResponseResult {
1087
+ struct DeRecError error;
1088
+ bool is_valid;
1089
+ } VerifyShareResponseResult;
1090
+
1091
+
1092
+
1093
+ #ifdef __cplusplus
1094
+ extern "C" {
1095
+ #endif // __cplusplus
1096
+
1097
+ /**
1098
+ * Releases a [`DeRecBuffer`] previously returned by the SDK.
1099
+ *
1100
+ * Safe to call with a null pointer.
1101
+ *
1102
+ * # Safety
1103
+ *
1104
+ * `ptr` must have been allocated by the DeRec SDK and `len` must match the
1105
+ * original allocation length.
1106
+ */
1107
+ void derec_free_buffer(uint8_t *ptr, size_t len);
1108
+
1109
+ /**
1110
+ * Releases a standalone C string previously returned by the SDK.
1111
+ *
1112
+ * For strings owned by a [`crate::interop::ffi::error::DeRecError`], use
1113
+ * [`crate::interop::ffi::error::derec_free_error`] which releases both owned strings
1114
+ * in one call. Safe to call with a null pointer.
1115
+ *
1116
+ * # Safety
1117
+ *
1118
+ * `ptr` must have been allocated by the DeRec SDK.
1119
+ */
1120
+ void derec_free_string(char *ptr);
1121
+
1122
+ /**
1123
+ * # Safety
1124
+ *
1125
+ * Non-null input pointers must point to the corresponding readable byte ranges.
1126
+ */
1127
+ struct ProduceGetSecretIdsVersionsRequestMessageResult produce_get_secret_ids_versions_request_message(uint64_t channel_id,
1128
+ const uint8_t *shared_key_ptr,
1129
+ size_t shared_key_len,
1130
+ const uint8_t *reply_to_ptr,
1131
+ size_t reply_to_len);
1132
+
1133
+ /**
1134
+ * # Safety
1135
+ *
1136
+ * Non-null input pointers must point to the corresponding readable byte ranges.
1137
+ */
1138
+ struct ExtractGetSecretIdsVersionsRequestResult extract_get_secret_ids_versions_request(const uint8_t *request_ptr,
1139
+ size_t request_len,
1140
+ const uint8_t *shared_key_ptr,
1141
+ size_t shared_key_len);
1142
+
1143
+ /**
1144
+ * `secret_list_ptr` / `secret_list_len` must follow the binary format
1145
+ * documented at the module level.
1146
+ *
1147
+ * # Safety
1148
+ *
1149
+ * Non-null input pointers must point to the corresponding readable byte ranges.
1150
+ */
1151
+ struct ProduceGetSecretIdsVersionsResponseMessageResult produce_get_secret_ids_versions_response_message(uint64_t channel_id,
1152
+ const uint8_t *secret_list_ptr,
1153
+ size_t secret_list_len,
1154
+ const uint8_t *shared_key_ptr,
1155
+ size_t shared_key_len);
1156
+
1157
+ /**
1158
+ * # Safety
1159
+ *
1160
+ * Non-null input pointers must point to the corresponding readable byte ranges.
1161
+ */
1162
+ struct ExtractGetSecretIdsVersionsResponseResult extract_get_secret_ids_versions_response(const uint8_t *response_ptr,
1163
+ size_t response_len,
1164
+ const uint8_t *shared_key_ptr,
1165
+ size_t shared_key_len);
1166
+
1167
+ /**
1168
+ * `response_proto_ptr` / `response_proto_len` must be the
1169
+ * `response_proto_bytes` returned by
1170
+ * [`extract_get_secret_ids_versions_response`].
1171
+ *
1172
+ * # Safety
1173
+ *
1174
+ * Non-null input pointers must point to the corresponding readable byte ranges.
1175
+ */
1176
+ struct ProcessGetSecretIdsVersionsResponseMessageResult process_get_secret_ids_versions_response_message(const uint8_t *response_proto_ptr,
1177
+ size_t response_proto_len);
1178
+
1179
+ /**
1180
+ * Overwrite `trace_id` on an already-produced envelope and return the
1181
+ * re-encoded bytes.
1182
+ *
1183
+ * Mirrors [`crate::derec_message::apply_trace_id`]. Useful for FFI consumers
1184
+ * using primitives directly: the `produce_*_request_message` family emits
1185
+ * envelopes with `trace_id = 0`, so callers who want correlation produce +
1186
+ * then call this. The orchestrator does this automatically end-to-end.
1187
+ *
1188
+ * # Safety
1189
+ *
1190
+ * `envelope_ptr` must point to a readable byte range of length `envelope_len`.
1191
+ */
1192
+ struct ApplyTraceIdResult apply_trace_id_to_envelope(const uint8_t *envelope_ptr,
1193
+ size_t envelope_len,
1194
+ uint64_t trace_id);
1195
+
1196
+ /**
1197
+ * Read `trace_id` off an envelope without touching the encrypted inner
1198
+ * payload. Pair with [`apply_trace_id_to_envelope`] for primitive-level
1199
+ * request/response correlation.
1200
+ *
1201
+ * # Safety
1202
+ *
1203
+ * `envelope_ptr` must point to a readable byte range of length `envelope_len`.
1204
+ */
1205
+ struct ReadTraceIdResult read_trace_id_from_envelope(const uint8_t *envelope_ptr,
1206
+ size_t envelope_len);
1207
+
1208
+ /**
1209
+ * Releases the owned strings carried by a [`DeRecError`]. After
1210
+ * returning, `error.message` and `error.peer_memo` are both null —
1211
+ * an accidental second call is a safe no-op.
1212
+ *
1213
+ * # Safety
1214
+ *
1215
+ * `error` must either be null (in which case this function is a
1216
+ * no-op) or point to a fully-initialized [`DeRecError`] produced by
1217
+ * the DeRec SDK. The function takes the value by pointer so it can
1218
+ * null out `message` and `peer_memo` after freeing them, neutralizing
1219
+ * the obvious double-free vector that a by-value signature creates
1220
+ * — callers that re-invoke `derec_free_error` on the same struct
1221
+ * then see a null-pointer no-op instead of corrupting the heap.
1222
+ */
1223
+ void derec_free_error(struct DeRecError *error);
1224
+
1225
+ /**
1226
+ * Static NUL-terminated name for a `DEREC_CATEGORY_*` value.
1227
+ *
1228
+ * Returns `"unknown"` for unrecognized values. The returned pointer has
1229
+ * static lifetime and must **not** be freed.
1230
+ */
1231
+ const char *derec_error_category_name(int32_t category);
1232
+
1233
+ /**
1234
+ * Static NUL-terminated name for a `DEREC_CODE_*` value.
1235
+ *
1236
+ * Returns `"unknown"` for unrecognized values. The returned pointer has
1237
+ * static lifetime and must **not** be freed.
1238
+ */
1239
+ const char *derec_error_code_name(int32_t code);
1240
+
1241
+ /**
1242
+ * Decodes protobuf wire bytes into the JSON mirror of `kind`.
1243
+ *
1244
+ * The returned buffer is UTF-8 JSON and must be released with
1245
+ * `derec_free_buffer`.
1246
+ *
1247
+ * # Safety
1248
+ *
1249
+ * `proto_ptr` must point to `proto_len` readable bytes, or be null with
1250
+ * `proto_len` zero.
1251
+ */
1252
+ struct DeRecMessageJsonResult derec_decode_message_json(int32_t kind,
1253
+ const uint8_t *proto_ptr,
1254
+ size_t proto_len);
1255
+
1256
+ /**
1257
+ * Encodes the JSON mirror of `kind` into protobuf wire bytes.
1258
+ *
1259
+ * The returned buffer must be released with `derec_free_buffer`.
1260
+ *
1261
+ * # Safety
1262
+ *
1263
+ * `json_ptr` must point to `json_len` readable bytes, or be null with
1264
+ * `json_len` zero.
1265
+ */
1266
+ struct DeRecMessageJsonResult derec_encode_message_json(int32_t kind,
1267
+ const uint8_t *json_ptr,
1268
+ size_t json_len);
1269
+
1270
+ /**
1271
+ * Single entry point for all three modes:
1272
+ * - `contact_mode == 0` (`INLINE_KEYS`) — keys inlined in contact.
1273
+ * - `contact_mode == 1` (`HASHED_KEYS`) — binding hash inlined; keys via PrePair.
1274
+ * - `contact_mode == 2` (`NO_KEYS`) — no key material; keys generated on the
1275
+ * fly by the responder when the `PrePairRequest` arrives.
1276
+ *
1277
+ * `has_nonce == 0` lets the library generate a fresh random `u64`.
1278
+ * `has_nonce == 1` uses the supplied `nonce` value verbatim; required for
1279
+ * `NO_KEYS` where callers typically pick a small human-typable value.
1280
+ *
1281
+ * On success `secret_key_material` is populated for `INLINE_KEYS` and
1282
+ * `HASHED_KEYS`; it is empty for `NO_KEYS` (no keys exist at
1283
+ * contact-creation time).
1284
+ *
1285
+ * # Safety
1286
+ *
1287
+ * Non-null input pointers must point to the corresponding readable byte ranges.
1288
+ */
1289
+ struct CreateContactMessageResult create_contact_message(uint64_t channel_id,
1290
+ int32_t contact_mode,
1291
+ const uint8_t *transport_protocol_ptr,
1292
+ size_t transport_protocol_len,
1293
+ uint32_t has_nonce,
1294
+ uint64_t nonce);
1295
+
1296
+ /**
1297
+ * Structurally validate a proto-encoded `ContactMessage`. Returns a
1298
+ * successful [`DeRecError`] iff the contact's `(contact_mode, inline keys,
1299
+ * binding hash)` tuple satisfies the per-mode invariants enforced by the
1300
+ * pairing primitives. Intended for bindings to call at their parse
1301
+ * boundary (e.g. `FromProtoBytes`) so that the decoded value handed to
1302
+ * application code is guaranteed well-formed.
1303
+ *
1304
+ * Failure codes:
1305
+ * - [`DEREC_CODE_FFI_BAD_PROTO`] if the bytes do not decode as a
1306
+ * `ContactMessage`.
1307
+ * - The library's `InvalidContactMessage` error code on any structural
1308
+ * violation (unknown `contact_mode`, mode/field mismatch, wrong
1309
+ * binding-hash length).
1310
+ *
1311
+ * # Safety
1312
+ *
1313
+ * `contact_message_ptr` must point to a readable range of
1314
+ * `contact_message_len` bytes (or be null with `len == 0`).
1315
+ */
1316
+ struct DeRecError validate_contact_message(const uint8_t *contact_message_ptr,
1317
+ size_t contact_message_len);
1318
+
1319
+ /**
1320
+ * Encodes a JSON [`ContactMessageDto`] to `ContactMessage` proto wire bytes.
1321
+ * Structurally validates the input first so a locally-constructed contact
1322
+ * that violates the mode/field invariant is rejected at the boundary rather
1323
+ * than silently serialized.
1324
+ *
1325
+ * The JSON shape is [`ContactMessageDto`]'s serde representation with one
1326
+ * adjustment applied at this seam: `channel_id` and `nonce` are decimal
1327
+ * strings, matching the `u64`-as-decimal-string convention every other FFI
1328
+ * JSON payload uses (see [`crate::interop::ffi::protocol::flow`]) because a host
1329
+ * whose numbers are IEEE-754 doubles cannot round-trip a full-width `u64`.
1330
+ * A plain JSON number is also accepted for either field.
1331
+ *
1332
+ * # Safety
1333
+ *
1334
+ * `contact_json_ptr` must point to a readable range of `contact_json_len`
1335
+ * bytes (or be null with `len == 0`).
1336
+ */
1337
+ struct EncodeContactMessageResult encode_contact_message(const uint8_t *contact_json_ptr,
1338
+ size_t contact_json_len);
1339
+
1340
+ /**
1341
+ * Decodes proto-encoded `ContactMessage` wire bytes into the JSON
1342
+ * [`ContactMessageDto`] shape described on [`encode_contact_message`].
1343
+ * Structurally validates the decoded value before returning it to
1344
+ * application code so consumers can trust the mode/field invariants
1345
+ * documented on the wire format.
1346
+ *
1347
+ * # Safety
1348
+ *
1349
+ * `contact_wire_ptr` must point to a readable range of `contact_wire_len`
1350
+ * bytes (or be null with `len == 0`).
1351
+ */
1352
+ struct DecodeContactMessageResult decode_contact_message(const uint8_t *contact_wire_ptr,
1353
+ size_t contact_wire_len);
1354
+
1355
+ /**
1356
+ * `communication_info_ptr` may be null / zero-length to indicate no
1357
+ * communication info; otherwise it must be serialized [`CommunicationInfo`]
1358
+ * proto bytes. `parameter_range_ptr` follows the same convention and
1359
+ * carries serialized [`derec_proto::ParameterRange`] bytes.
1360
+ *
1361
+ * # Safety
1362
+ *
1363
+ * Non-null input pointers must point to the corresponding readable byte ranges.
1364
+ */
1365
+ struct ProducePairRequestMessageResult produce_pair_request_message(int32_t sender_kind,
1366
+ const uint8_t *transport_protocol_ptr,
1367
+ size_t transport_protocol_len,
1368
+ const uint8_t *contact_message_ptr,
1369
+ size_t contact_message_len,
1370
+ const uint8_t *communication_info_ptr,
1371
+ size_t communication_info_len,
1372
+ const uint8_t *parameter_range_ptr,
1373
+ size_t parameter_range_len);
1374
+
1375
+ /**
1376
+ * # Safety
1377
+ *
1378
+ * Non-null input pointers must point to the corresponding readable byte ranges.
1379
+ */
1380
+ struct ExtractPairRequestResult extract_pair_request(const uint8_t *request_ptr,
1381
+ size_t request_len,
1382
+ const uint8_t *secret_key_material_ptr,
1383
+ size_t secret_key_material_len);
1384
+
1385
+ /**
1386
+ * `request_proto_ptr` / `request_proto_len` must be the `request_proto_bytes`
1387
+ * returned by [`extract_pair_request`]. `communication_info_ptr` may be null /
1388
+ * zero-length to indicate no communication info.
1389
+ *
1390
+ * `parameter_range_ptr` may be null / zero-length to indicate no
1391
+ * parameter range; otherwise it must be serialized
1392
+ * [`derec_proto::ParameterRange`] proto bytes.
1393
+ *
1394
+ * # Safety
1395
+ *
1396
+ * Non-null input pointers must point to the corresponding readable byte ranges.
1397
+ */
1398
+ struct ProducePairResponseMessageResult produce_pair_response_message(uint64_t channel_id,
1399
+ const uint8_t *request_proto_ptr,
1400
+ size_t request_proto_len,
1401
+ const uint8_t *secret_key_material_ptr,
1402
+ size_t secret_key_material_len,
1403
+ const uint8_t *communication_info_ptr,
1404
+ size_t communication_info_len,
1405
+ const uint8_t *parameter_range_ptr,
1406
+ size_t parameter_range_len);
1407
+
1408
+ /**
1409
+ * # Safety
1410
+ *
1411
+ * Non-null input pointers must point to the corresponding readable byte ranges.
1412
+ */
1413
+ struct ExtractPairResponseResult extract_pair_response(const uint8_t *response_ptr,
1414
+ size_t response_len,
1415
+ const uint8_t *secret_key_material_ptr,
1416
+ size_t secret_key_material_len);
1417
+
1418
+ /**
1419
+ * `response_proto_ptr` / `response_proto_len` must be the
1420
+ * `response_proto_bytes` returned by [`extract_pair_response`].
1421
+ *
1422
+ * # Safety
1423
+ *
1424
+ * Non-null input pointers must point to the corresponding readable byte ranges.
1425
+ */
1426
+ struct ProcessPairResponseMessageResult process_pair_response_message(const uint8_t *contact_message_ptr,
1427
+ size_t contact_message_len,
1428
+ const uint8_t *response_proto_ptr,
1429
+ size_t response_proto_len,
1430
+ const uint8_t *secret_key_material_ptr,
1431
+ size_t secret_key_material_len);
1432
+
1433
+ /**
1434
+ * Builds a plaintext `PrePairRequestMessage` envelope. Used by the scanner
1435
+ * when the contact was sent with `contact_mode == HASHED_KEYS`. The envelope
1436
+ * is unencrypted — no shared key exists yet — so the caller does not pass
1437
+ * secret key material here.
1438
+ *
1439
+ * # Safety
1440
+ *
1441
+ * Non-null input pointers must point to the corresponding readable byte ranges.
1442
+ */
1443
+ struct ProducePrePairRequestMessageResult produce_pre_pair_request_message(const uint8_t *transport_protocol_ptr,
1444
+ size_t transport_protocol_len,
1445
+ const uint8_t *contact_message_ptr,
1446
+ size_t contact_message_len);
1447
+
1448
+ /**
1449
+ * Decodes a plaintext `PrePairRequestMessage` envelope.
1450
+ *
1451
+ * # Safety
1452
+ *
1453
+ * Non-null input pointers must point to the corresponding readable byte ranges.
1454
+ */
1455
+ struct ExtractPrePairRequestResult extract_pre_pair_request(const uint8_t *envelope_ptr,
1456
+ size_t envelope_len);
1457
+
1458
+ /**
1459
+ * Builds a plaintext `PrePairResponseMessage` envelope republishing the
1460
+ * initiator's public keys. The keys come from `secret_key_material` (which
1461
+ * retains them alongside the secrets in `HASHED_KEYS` flows).
1462
+ *
1463
+ * `request_proto_ptr` / `request_proto_len` must be the `request_proto_bytes`
1464
+ * returned by [`extract_pre_pair_request`].
1465
+ *
1466
+ * # Safety
1467
+ *
1468
+ * Non-null input pointers must point to the corresponding readable byte ranges.
1469
+ */
1470
+ struct ProducePrePairResponseMessageResult produce_pre_pair_response_message(uint64_t channel_id,
1471
+ const uint8_t *request_proto_ptr,
1472
+ size_t request_proto_len,
1473
+ const uint8_t *secret_key_material_ptr,
1474
+ size_t secret_key_material_len);
1475
+
1476
+ /**
1477
+ * Decodes a plaintext `PrePairResponseMessage` envelope.
1478
+ *
1479
+ * # Safety
1480
+ *
1481
+ * Non-null input pointers must point to the corresponding readable byte ranges.
1482
+ */
1483
+ struct ExtractPrePairResponseResult extract_pre_pair_response(const uint8_t *envelope_ptr,
1484
+ size_t envelope_len);
1485
+
1486
+ /**
1487
+ * Scanner-side: validates a decoded `PrePairResponseMessage` against the
1488
+ * original `ContactMessage`'s SHA-384 binding hash. On success returns the
1489
+ * validated public keys and echoed nonce. On any failure (non-Ok status,
1490
+ * hash mismatch, nonce mismatch, missing fields) returns an error and
1491
+ * empty buffers.
1492
+ *
1493
+ * `response_proto_ptr` / `response_proto_len` must be the
1494
+ * `response_proto_bytes` returned by [`extract_pre_pair_response`].
1495
+ *
1496
+ * # Safety
1497
+ *
1498
+ * Non-null input pointers must point to the corresponding readable byte ranges.
1499
+ */
1500
+ struct ProcessPrePairResponseMessageResult process_pre_pair_response_message(const uint8_t *contact_message_ptr,
1501
+ size_t contact_message_len,
1502
+ const uint8_t *response_proto_ptr,
1503
+ size_t response_proto_len);
1504
+
1505
+ /**
1506
+ * Constructs a [`crate::protocol::DeRecProtocol`] with scalar config
1507
+ * bundled as JSON, for FFI callers that cannot pass many native
1508
+ * arguments in a single call — e.g. Go via `purego` (no cgo), which
1509
+ * panics with "too many stack arguments" past a handful of
1510
+ * parameters. Scalar configuration is bundled into a single JSON
1511
+ * buffer; `communication_info` stays a separate proto-encoded
1512
+ * `CommunicationInfo` buffer; the 6 store/transport callback structs
1513
+ * are still passed as individual pointers, since purego marshals
1514
+ * pointer-sized arguments natively.
1515
+ *
1516
+ * `config_json` must deserialize to the following shape — all field
1517
+ * names `snake_case`. `secret_id`, `own_transport_uri` and
1518
+ * `own_transport_protocol` are the only genuinely required fields;
1519
+ * `threshold`, `keep_versions_count`, `auto_respond_on_failure`,
1520
+ * `unpair_ack`, `auto_reply_to` and `auto_accept` may each be omitted, in
1521
+ * which case the value matches
1522
+ * [`crate::protocol::DeRecProtocolBuilder::new`]'s own default for that
1523
+ * setting — see [`ProtocolConfig`]'s field-level `#[serde(default)]`
1524
+ * attributes, which read the same constants the builder does:
1525
+ *
1526
+ * ```json
1527
+ * {
1528
+ * "secret_id": "12345678901234567890",
1529
+ * "own_transport_uri": "https://example.com/derec",
1530
+ * "own_transport_protocol": 1,
1531
+ * "threshold": 3,
1532
+ * "keep_versions_count": 2,
1533
+ * "timeout_in_secs": 30,
1534
+ * "auto_respond_on_failure": false,
1535
+ * "unpair_ack": 0,
1536
+ * "auto_reply_to": false,
1537
+ * "auto_accept": {
1538
+ * "pairing": false,
1539
+ * "pre_pair": false,
1540
+ * "store_share": false,
1541
+ * "verify_share": false,
1542
+ * "discovery": false,
1543
+ * "get_share": false,
1544
+ * "unpair": false,
1545
+ * "update_channel_info": false
1546
+ * },
1547
+ * "remove_expired_channels": { "enabled": true, "timeout_in_secs": 300 },
1548
+ * "replica_id": null
1549
+ * }
1550
+ * ```
1551
+ *
1552
+ * - `secret_id`: decimal-string `u64`.
1553
+ * - `own_transport_uri`: may be `""` for the deferred-config path;
1554
+ * `derec_protocol_set_own_transport` must be called before pairing
1555
+ * in that case.
1556
+ * - `own_transport_protocol`: [`derec_proto::Protocol`] discriminant.
1557
+ * - `threshold` / `keep_versions_count`: optional; omitted means
1558
+ * [`crate::protocol::DEFAULT_THRESHOLD`] /
1559
+ * [`crate::protocol::DEFAULT_KEEP_VERSIONS_COUNT`].
1560
+ * - `unpair_ack`: `0` = Required, `1` = NotRequired; optional, omitted
1561
+ * means `0`.
1562
+ * - `auto_respond_on_failure` / `auto_reply_to`: optional, omitted means
1563
+ * `false`.
1564
+ * - `auto_accept`: one boolean per flow; the whole object is optional,
1565
+ * omitted means every flow `false`.
1566
+ * - `remove_expired_channels`: automatic removal of expired `Pending`
1567
+ * channels. Optional — omitted means `{ "enabled": true,
1568
+ * "timeout_in_secs": 300 }`. Both fields are always sent; when
1569
+ * `enabled` is `false` the timeout is ignored by the library.
1570
+ * - `replica_id`: decimal-string `u64`, or absent/`null` for "no
1571
+ * replica id".
1572
+ *
1573
+ * # Safety
1574
+ *
1575
+ * - `config_json_ptr` must be valid for reads of `config_json_len`
1576
+ * bytes.
1577
+ * - `communication_info_ptr` must be valid for reads of
1578
+ * `communication_info_len` bytes when the length is non-zero.
1579
+ * - All 6 callback pointers must be valid for reads of their pointee
1580
+ * struct, and must outlive the returned handle.
1581
+ * - The caller must invoke [`derec_protocol_free`] exactly once to
1582
+ * release the returned handle.
1583
+ */
1584
+ struct DeRecProtocolNewResult derec_protocol_new(const uint8_t *config_json_ptr,
1585
+ size_t config_json_len,
1586
+ const uint8_t *communication_info_ptr,
1587
+ size_t communication_info_len,
1588
+ const struct ChannelStoreCallbacks *channel_store_cb,
1589
+ const struct SecretStoreCallbacks *secret_store_cb,
1590
+ const struct ShareStoreCallbacks *share_store_cb,
1591
+ const struct UserSecretStoreCallbacks *user_secret_store_cb,
1592
+ const struct StateStoreCallbacks *state_store_cb,
1593
+ const struct TransportCallbacks *transport_cb);
1594
+
1595
+ /**
1596
+ * Release a handle previously returned by [`derec_protocol_new`].
1597
+ * Safe to call with a null pointer.
1598
+ *
1599
+ * # Safety
1600
+ *
1601
+ * `handle` must satisfy ALL of:
1602
+ *
1603
+ * - It is a pointer previously returned by [`derec_protocol_new`],
1604
+ * or it is null.
1605
+ * - It has not already been freed (no double-free).
1606
+ * - **No other thread is executing any `derec_protocol_*` function on
1607
+ * this handle while this call is in flight.** The interior
1608
+ * [`std::sync::Mutex`] protects against aliased `&mut` references
1609
+ * *within* the live allocation, but it cannot protect the
1610
+ * allocation itself from being dropped — a concurrent
1611
+ * `derec_protocol_process` / `accept` / `set_*` call that holds
1612
+ * the lock would be reading freed memory the moment this function
1613
+ * returns. Host bindings (.NET `Dispose`, Node.js / WASM
1614
+ * teardown) are responsible for draining or cancelling in-flight
1615
+ * calls before invoking `derec_protocol_free`.
1616
+ */
1617
+ void derec_protocol_free(struct DeRecProtocolHandle *handle);
1618
+
1619
+ /**
1620
+ * Replace this node's local `communication_info` map. Does not contact
1621
+ * peers — follow up with `start(FlowKind::UpdateChannelInfo)` to
1622
+ * propagate. The body is the same JSON wire shape used elsewhere on
1623
+ * the FFI: a UTF-8 JSON object with string keys + string values.
1624
+ *
1625
+ * # Safety
1626
+ *
1627
+ * `handle` must be a valid pointer returned by
1628
+ * [`super::derec_protocol_new`]. `info_json_ptr`/`info_json_len` must
1629
+ * describe a readable byte range. Concurrent calls on the same
1630
+ * handle from different threads are safe: the handle's internal
1631
+ * mutex serializes them.
1632
+ */
1633
+ struct DeRecError derec_protocol_set_communication_info(struct DeRecProtocolHandle *handle,
1634
+ const uint8_t *info_json_ptr,
1635
+ size_t info_json_len);
1636
+
1637
+ /**
1638
+ * Replace this node's local transport endpoint. See
1639
+ * [`crate::protocol::DeRecProtocol::set_own_transport`] for the
1640
+ * changeover discipline (keep the old endpoint up during the
1641
+ * transition).
1642
+ *
1643
+ * # Safety
1644
+ *
1645
+ * `handle` must be a valid pointer returned by
1646
+ * [`super::derec_protocol_new`]. `uri_ptr`/`uri_len` must describe a
1647
+ * readable byte range. The `(uri, protocol)` pair is validated via
1648
+ * [`super::validate_transport`] before it is stored — see that
1649
+ * function's docs for the structural rules (length cap, scheme
1650
+ * match, enum discriminant). Concurrent calls on the same handle
1651
+ * from different threads are safe: the handle's internal mutex
1652
+ * serializes them.
1653
+ */
1654
+ struct DeRecError derec_protocol_set_own_transport(struct DeRecProtocolHandle *handle,
1655
+ const uint8_t *uri_ptr,
1656
+ size_t uri_len,
1657
+ int32_t protocol);
1658
+
1659
+ /**
1660
+ * Remove `Pending` channels older than `older_than_secs`. See
1661
+ * [`crate::protocol::DeRecProtocol::remove_expired_channels`] for the
1662
+ * semantics, including the strict `>` age boundary.
1663
+ *
1664
+ * # Safety
1665
+ *
1666
+ * `handle` must be a valid pointer returned by
1667
+ * [`super::derec_protocol_new`]. Concurrent calls on the same handle
1668
+ * from different threads are safe: the handle's internal mutex
1669
+ * serializes them.
1670
+ */
1671
+ struct DeRecRemovedChannelsResult derec_protocol_remove_expired_channels(struct DeRecProtocolHandle *handle,
1672
+ uint64_t older_than_secs);
1673
+
1674
+ /**
1675
+ * Start a new flow. `flow_kind` matches the constants in
1676
+ * [`crate::interop::ffi::protocol::flow`]. `params_json_*` is a UTF-8 JSON blob
1677
+ * shaped to the matching `*ParamsJson` struct in that module.
1678
+ *
1679
+ * # Safety
1680
+ *
1681
+ * `handle` must be a valid pointer returned by
1682
+ * [`super::derec_protocol_new`]. `params_json_ptr`/`params_json_len`
1683
+ * must describe a readable byte range.
1684
+ */
1685
+ struct DeRecProtocolEventsResult derec_protocol_start(struct DeRecProtocolHandle *handle,
1686
+ uint32_t flow_kind,
1687
+ const uint8_t *params_json_ptr,
1688
+ size_t params_json_len);
1689
+
1690
+ /**
1691
+ * Process an inbound `DeRecMessage` envelope. See
1692
+ * [`crate::protocol::DeRecProtocol::process`].
1693
+ *
1694
+ * # Safety
1695
+ *
1696
+ * `handle` must be a valid pointer returned by
1697
+ * [`super::derec_protocol_new`]. `message_ptr`/`message_len` must
1698
+ * describe a readable byte range.
1699
+ */
1700
+ struct DeRecProtocolEventsResult derec_protocol_process(struct DeRecProtocolHandle *handle,
1701
+ const uint8_t *message_ptr,
1702
+ size_t message_len);
1703
+
1704
+ /**
1705
+ * Advance time-driven state without an inbound message. See
1706
+ * [`crate::protocol::DeRecProtocol::tick`].
1707
+ *
1708
+ * Intended for a scheduler — a timer, a cron job, a queue heartbeat —
1709
+ * in deployments where nothing else would ever evaluate timeouts. Safe
1710
+ * to call on an idle protocol: it returns an empty event array.
1711
+ *
1712
+ * # Safety
1713
+ *
1714
+ * `handle` must be a valid pointer returned by
1715
+ * [`super::derec_protocol_new`].
1716
+ */
1717
+ struct DeRecProtocolEventsResult derec_protocol_tick(struct DeRecProtocolHandle *handle);
1718
+
1719
+ /**
1720
+ * Accept a pending action from an `ActionRequired` event. See
1721
+ * [`crate::protocol::DeRecProtocol::accept`]. The `action_bytes` blob
1722
+ * is the exact payload the caller received in the event — the FFI
1723
+ * wire format is the encoding produced by
1724
+ * [`crate::protocol::utils::pending_action_wire::serialize`].
1725
+ *
1726
+ * # Safety
1727
+ *
1728
+ * `handle` must be a valid pointer returned by
1729
+ * [`super::derec_protocol_new`]. `action_ptr`/`action_len` must
1730
+ * describe a readable byte range.
1731
+ */
1732
+ struct DeRecProtocolEventsResult derec_protocol_accept(struct DeRecProtocolHandle *handle,
1733
+ const uint8_t *action_ptr,
1734
+ size_t action_len);
1735
+
1736
+ /**
1737
+ * Reject a pending action from an `ActionRequired` event. See
1738
+ * [`crate::protocol::DeRecProtocol::reject`]. `status` matches
1739
+ * `derec_proto::StatusEnum` and `memo_ptr`/`memo_len` is an optional
1740
+ * UTF-8 string body (`memo_len == 0` for absent).
1741
+ *
1742
+ * # Safety
1743
+ *
1744
+ * `handle` must be a valid pointer returned by
1745
+ * [`super::derec_protocol_new`]. `action_ptr`/`action_len` must
1746
+ * describe a readable byte range.
1747
+ */
1748
+ struct DeRecError derec_protocol_reject(struct DeRecProtocolHandle *handle,
1749
+ const uint8_t *action_ptr,
1750
+ size_t action_len,
1751
+ int32_t status,
1752
+ const uint8_t *memo_ptr,
1753
+ size_t memo_len);
1754
+
1755
+ /**
1756
+ * Rebuild this protocol's `secret_id` namespace from a recovered
1757
+ * `Secret`. See [`crate::protocol::DeRecProtocol::restore`] for the
1758
+ * full contract and error semantics.
1759
+ *
1760
+ * `params_json_*` is a UTF-8 JSON blob of the shape:
1761
+ *
1762
+ * ```json
1763
+ * {
1764
+ * "version": 7,
1765
+ * "recovered_secret": {
1766
+ * "helpers": [{ "channel_id": "11", "transport_uri": "...",
1767
+ * "shared_key": [..32 bytes..],
1768
+ * "communication_info": {} }],
1769
+ * "secrets": [{ "id": [..], "name": "...", "data": [..] }],
1770
+ * "replicas": {
1771
+ * "channel_id": "21",
1772
+ * "members": [{ "replica_id": "51966", "transport_uri": "...",
1773
+ * "role": "Source", "communication_info": {} }],
1774
+ * "shared_key": [..32 bytes..]
1775
+ * }
1776
+ * }
1777
+ * }
1778
+ * ```
1779
+ *
1780
+ * Field names mirror `SecretWire` in `protocol/events/wire.rs` — the
1781
+ * same shape `SecretRecovered` carries. `channel_id` and `replica_id`
1782
+ * are decimal `u64` strings (empty / absent means zero).
1783
+ *
1784
+ * `replicas` is an **object**, not an array, and is omitted entirely when
1785
+ * the `secret_id` has no replica group. Every member of the group shares
1786
+ * the one `channel_id` and the one `shared_key` it carries, so neither is
1787
+ * repeated per member; a member is identified by `replica_id` alone, and
1788
+ * the group's source is the member whose `role` is `"Source"`.
1789
+ *
1790
+ * # Safety
1791
+ *
1792
+ * `handle` must be a valid pointer returned by
1793
+ * [`super::derec_protocol_new`]. `params_json_ptr`/`params_json_len`
1794
+ * must describe a readable byte range.
1795
+ */
1796
+ struct DeRecProtocolEventsResult derec_protocol_restore(struct DeRecProtocolHandle *handle,
1797
+ const uint8_t *params_json_ptr,
1798
+ size_t params_json_len);
1799
+
1800
+ /**
1801
+ * Derive the human-readable fingerprint for a paired channel. See
1802
+ * [`crate::protocol::DeRecProtocol::get_fingerprint`].
1803
+ *
1804
+ * # Safety
1805
+ *
1806
+ * `handle` must be a valid pointer returned by
1807
+ * [`super::derec_protocol_new`]. Concurrent calls on the same handle
1808
+ * from different threads are safe: the handle's internal mutex
1809
+ * serializes them.
1810
+ */
1811
+ struct DeRecProtocolFingerprintResult derec_protocol_get_fingerprint(struct DeRecProtocolHandle *handle,
1812
+ uint64_t channel_id);
1813
+
1814
+ /**
1815
+ * Verify a fingerprint against the channel's locally-derived one. See
1816
+ * [`crate::protocol::DeRecProtocol::verify_fingerprint`].
1817
+ *
1818
+ * Writes `*out_matched = 1` if and only if the comparison
1819
+ * affirmatively succeeded. On every other outcome — null-pointer
1820
+ * rejection, malformed UTF-8 in `fingerprint_ptr`, a backend error,
1821
+ * or a legitimate mismatch — `*out_matched` is set to `0`. Callers
1822
+ * MUST also inspect the returned [`DeRecError`] to distinguish a
1823
+ * successful mismatch from a failure that could not produce a
1824
+ * verdict; treating `out_matched == 0` as "definitely not matched"
1825
+ * is safe only after confirming the envelope reports
1826
+ * [`DEREC_CATEGORY_OK`](crate::interop::ffi::error::DEREC_CATEGORY_OK).
1827
+ *
1828
+ * The fail-closed write happens immediately after the null-pointer
1829
+ * check, so a caller that allocates the output on the stack and
1830
+ * reads it without checking the error envelope still gets `0`,
1831
+ * never a stale `1` from uninitialized memory. This neutralizes
1832
+ * the "sloppy caller skips the error envelope and reads stale
1833
+ * stack" footgun on the MITM-protection gate.
1834
+ *
1835
+ * # Safety
1836
+ *
1837
+ * `handle` and `out_matched` must be valid pointers. `fingerprint_ptr`
1838
+ * must be a valid pointer to a NUL-terminated C string. Concurrent
1839
+ * calls on the same handle from different threads are safe: the
1840
+ * handle's internal mutex serializes them.
1841
+ */
1842
+ struct DeRecError derec_protocol_verify_fingerprint(struct DeRecProtocolHandle *handle,
1843
+ uint64_t channel_id,
1844
+ const char *fingerprint_ptr,
1845
+ uint32_t *out_matched);
1846
+
1847
+ /**
1848
+ * Generate an out-of-band contact message used to bootstrap pairing.
1849
+ * See [`crate::protocol::DeRecProtocol::create_contact`].
1850
+ *
1851
+ * `has_channel_id == 0` lets the library mint the channel id; `1`
1852
+ * supplies it via `channel_id`.
1853
+ *
1854
+ * # Safety
1855
+ *
1856
+ * `handle` must be a valid pointer returned by
1857
+ * [`super::derec_protocol_new`]. Concurrent calls on the same handle
1858
+ * from different threads are safe: the handle's internal mutex
1859
+ * serializes them.
1860
+ */
1861
+ struct DeRecProtocolCreateContactResult derec_protocol_create_contact(struct DeRecProtocolHandle *handle,
1862
+ uint32_t has_channel_id,
1863
+ uint64_t channel_id,
1864
+ int32_t contact_mode,
1865
+ uint32_t has_nonce,
1866
+ uint64_t nonce);
1867
+
1868
+ struct DeRecProtocolVersion derec_protocol_version(void);
1869
+
1870
+ /**
1871
+ * # Safety
1872
+ *
1873
+ * Non-null input pointers must point to the corresponding readable byte ranges.
1874
+ */
1875
+ struct ProduceGetShareRequestMessageResult produce_get_share_request_message(uint64_t channel_id,
1876
+ uint64_t secret_id,
1877
+ uint32_t version,
1878
+ const uint8_t *shared_key_ptr,
1879
+ size_t shared_key_len,
1880
+ const uint8_t *reply_to_ptr,
1881
+ size_t reply_to_len);
1882
+
1883
+ /**
1884
+ * # Safety
1885
+ *
1886
+ * Non-null input pointers must point to the corresponding readable byte ranges.
1887
+ */
1888
+ struct ExtractGetShareRequestResult extract_get_share_request(const uint8_t *request_ptr,
1889
+ size_t request_len,
1890
+ const uint8_t *shared_key_ptr,
1891
+ size_t shared_key_len);
1892
+
1893
+ /**
1894
+ * `request_proto_ptr` / `request_proto_len` must be the `request_proto_bytes`
1895
+ * returned by [`extract_get_share_request`].
1896
+ *
1897
+ * `stored_share_proto_ptr` / `stored_share_proto_len` must be the serialized
1898
+ * inner `StoreShareRequestMessage` the helper persisted at sharing time —
1899
+ * typically the `request_proto_bytes` returned by `extract_store_share_request`.
1900
+ *
1901
+ * # Safety
1902
+ *
1903
+ * Non-null input pointers must point to the corresponding readable byte ranges.
1904
+ */
1905
+ struct ProduceGetShareResponseMessageResult produce_get_share_response_message(uint64_t channel_id,
1906
+ const uint8_t *request_proto_ptr,
1907
+ size_t request_proto_len,
1908
+ const uint8_t *stored_share_proto_ptr,
1909
+ size_t stored_share_proto_len,
1910
+ const uint8_t *shared_key_ptr,
1911
+ size_t shared_key_len);
1912
+
1913
+ /**
1914
+ * # Safety
1915
+ *
1916
+ * Non-null input pointers must point to the corresponding readable byte ranges.
1917
+ */
1918
+ struct ExtractGetShareResponseResult extract_get_share_response(const uint8_t *response_ptr,
1919
+ size_t response_len,
1920
+ const uint8_t *shared_key_ptr,
1921
+ size_t shared_key_len);
1922
+
1923
+ /**
1924
+ * `responses_ptr` / `responses_len` must follow the binary format documented
1925
+ * at the module level.
1926
+ *
1927
+ * # Safety
1928
+ *
1929
+ * Non-null input pointers must point to the corresponding readable byte ranges.
1930
+ */
1931
+ struct RecoverFromShareResponsesResult recover_from_share_responses(const uint8_t *responses_ptr,
1932
+ size_t responses_len,
1933
+ uint64_t secret_id,
1934
+ uint32_t version);
1935
+
1936
+ /**
1937
+ * # Safety
1938
+ *
1939
+ * Non-null input pointers must point to the corresponding readable byte ranges.
1940
+ */
1941
+ struct ProtectSecretResult protect_secret(uint64_t secret_id,
1942
+ const uint8_t *secret_data_ptr,
1943
+ size_t secret_data_len,
1944
+ const uint64_t *channels_ptr,
1945
+ size_t channels_len,
1946
+ size_t threshold,
1947
+ uint32_t version);
1948
+
1949
+ /**
1950
+ * # Safety
1951
+ *
1952
+ * Non-null input pointers must point to the corresponding readable byte ranges.
1953
+ */
1954
+ struct ProduceStoreShareRequestMessageResult produce_store_share_request_message(uint64_t channel_id,
1955
+ uint32_t version,
1956
+ uint64_t secret_id,
1957
+ const uint8_t *committed_share_ptr,
1958
+ size_t committed_share_len,
1959
+ const uint32_t *keep_list_ptr,
1960
+ size_t keep_list_len,
1961
+ const uint8_t *description_ptr,
1962
+ size_t description_len,
1963
+ const uint8_t *shared_key_ptr,
1964
+ size_t shared_key_len,
1965
+ const uint8_t *reply_to_ptr,
1966
+ size_t reply_to_len);
1967
+
1968
+ /**
1969
+ * # Safety
1970
+ *
1971
+ * Non-null input pointers must point to the corresponding readable byte ranges.
1972
+ */
1973
+ struct ExtractStoreShareRequestResult extract_store_share_request(const uint8_t *request_ptr,
1974
+ size_t request_len,
1975
+ const uint8_t *shared_key_ptr,
1976
+ size_t shared_key_len);
1977
+
1978
+ /**
1979
+ * `request_proto_ptr` / `request_proto_len` must be the `request_proto_bytes`
1980
+ * returned by [`extract_store_share_request`].
1981
+ *
1982
+ * # Safety
1983
+ *
1984
+ * Non-null input pointers must point to the corresponding readable byte ranges.
1985
+ */
1986
+ struct ProduceStoreShareResponseMessageResult produce_store_share_response_message(uint64_t channel_id,
1987
+ const uint8_t *request_proto_ptr,
1988
+ size_t request_proto_len,
1989
+ const uint8_t *shared_key_ptr,
1990
+ size_t shared_key_len);
1991
+
1992
+ /**
1993
+ * # Safety
1994
+ *
1995
+ * Non-null input pointers must point to the corresponding readable byte ranges.
1996
+ */
1997
+ struct ExtractStoreShareResponseResult extract_store_share_response(const uint8_t *response_ptr,
1998
+ size_t response_len,
1999
+ const uint8_t *shared_key_ptr,
2000
+ size_t shared_key_len);
2001
+
2002
+ /**
2003
+ * `response_proto_ptr` / `response_proto_len` must be the
2004
+ * `response_proto_bytes` returned by [`extract_store_share_response`].
2005
+ *
2006
+ * # Safety
2007
+ *
2008
+ * Non-null input pointers must point to the corresponding readable byte ranges.
2009
+ */
2010
+ struct ProcessStoreShareResponseMessageResult process_store_share_response_message(uint32_t version,
2011
+ const uint8_t *response_proto_ptr,
2012
+ size_t response_proto_len);
2013
+
2014
+ /**
2015
+ * # Safety
2016
+ *
2017
+ * Non-null input pointers must point to the corresponding readable byte ranges.
2018
+ */
2019
+ struct ProduceUnpairRequestMessageResult produce_unpair_request_message(uint64_t channel_id,
2020
+ const uint8_t *memo_ptr,
2021
+ size_t memo_len,
2022
+ const uint8_t *shared_key_ptr,
2023
+ size_t shared_key_len,
2024
+ const uint8_t *reply_to_ptr,
2025
+ size_t reply_to_len);
2026
+
2027
+ /**
2028
+ * # Safety
2029
+ *
2030
+ * Non-null input pointers must point to the corresponding readable byte ranges.
2031
+ */
2032
+ struct ExtractUnpairRequestResult extract_unpair_request(const uint8_t *request_ptr,
2033
+ size_t request_len,
2034
+ const uint8_t *shared_key_ptr,
2035
+ size_t shared_key_len);
2036
+
2037
+ /**
2038
+ * # Safety
2039
+ *
2040
+ * Non-null input pointers must point to the corresponding readable byte ranges.
2041
+ */
2042
+ struct ProduceUnpairResponseMessageResult produce_unpair_response_message(uint64_t channel_id,
2043
+ const uint8_t *shared_key_ptr,
2044
+ size_t shared_key_len);
2045
+
2046
+ /**
2047
+ * # Safety
2048
+ *
2049
+ * Non-null input pointers must point to the corresponding readable byte ranges.
2050
+ */
2051
+ struct ExtractUnpairResponseResult extract_unpair_response(const uint8_t *response_ptr,
2052
+ size_t response_len,
2053
+ const uint8_t *shared_key_ptr,
2054
+ size_t shared_key_len);
2055
+
2056
+ /**
2057
+ * `response_proto_ptr` / `response_proto_len` must be the
2058
+ * `response_proto_bytes` returned by [`extract_unpair_response`].
2059
+ *
2060
+ * # Safety
2061
+ *
2062
+ * Non-null input pointers must point to the corresponding readable byte ranges.
2063
+ */
2064
+ struct ProcessUnpairResponseResult process_unpair_response_message(const uint8_t *response_proto_ptr,
2065
+ size_t response_proto_len);
2066
+
2067
+ /**
2068
+ * # Safety
2069
+ *
2070
+ * Non-null input pointers must point to the corresponding readable byte ranges.
2071
+ */
2072
+ struct ProduceVerifyShareRequestMessageResult produce_verify_share_request_message(uint64_t channel_id,
2073
+ uint64_t secret_id,
2074
+ uint32_t version,
2075
+ const uint8_t *shared_key_ptr,
2076
+ size_t shared_key_len,
2077
+ const uint8_t *reply_to_ptr,
2078
+ size_t reply_to_len);
2079
+
2080
+ /**
2081
+ * # Safety
2082
+ *
2083
+ * Non-null input pointers must point to the corresponding readable byte ranges.
2084
+ */
2085
+ struct ExtractVerifyShareRequestResult extract_verify_share_request(const uint8_t *request_ptr,
2086
+ size_t request_len,
2087
+ const uint8_t *shared_key_ptr,
2088
+ size_t shared_key_len);
2089
+
2090
+ /**
2091
+ * `request_proto_ptr` / `request_proto_len` must be the `request_proto_bytes`
2092
+ * returned by [`extract_verify_share_request`].
2093
+ *
2094
+ * # Safety
2095
+ *
2096
+ * Non-null input pointers must point to the corresponding readable byte ranges.
2097
+ */
2098
+ struct ProduceVerifyShareResponseMessageResult produce_verify_share_response_message(uint64_t channel_id,
2099
+ const uint8_t *request_proto_ptr,
2100
+ size_t request_proto_len,
2101
+ const uint8_t *shared_key_ptr,
2102
+ size_t shared_key_len,
2103
+ const uint8_t *share_content_ptr,
2104
+ size_t share_content_len);
2105
+
2106
+ /**
2107
+ * # Safety
2108
+ *
2109
+ * Non-null input pointers must point to the corresponding readable byte ranges.
2110
+ */
2111
+ struct ExtractVerifyShareResponseResult extract_verify_share_response(const uint8_t *response_ptr,
2112
+ size_t response_len,
2113
+ const uint8_t *shared_key_ptr,
2114
+ size_t shared_key_len);
2115
+
2116
+ /**
2117
+ * Verify a `VerifyShareResponseMessage` against the originating
2118
+ * `VerifyShareRequestMessage` and the expected share content.
2119
+ *
2120
+ * `request_proto_ptr` / `request_proto_len` must carry the proto-
2121
+ * encoded [`derec_proto::VerifyShareRequestMessage`] the **owner**
2122
+ * previously produced for this challenge (kept by the caller in a
2123
+ * per-`channel_id` pending-verification map). The primitive
2124
+ * rejects any response whose `(nonce, secret_id, version)` triple
2125
+ * doesn't match — that's the anti-replay gate.
2126
+ *
2127
+ * `response_proto_ptr` / `response_proto_len` must be the
2128
+ * `response_proto_bytes` returned by [`extract_verify_share_response`].
2129
+ *
2130
+ * # Safety
2131
+ *
2132
+ * Non-null input pointers must point to the corresponding readable byte ranges.
2133
+ */
2134
+ struct VerifyShareResponseResult process_verify_share_response_message(const uint8_t *request_proto_ptr,
2135
+ size_t request_proto_len,
2136
+ const uint8_t *response_proto_ptr,
2137
+ size_t response_proto_len,
2138
+ const uint8_t *share_content_ptr,
2139
+ size_t share_content_len);
2140
+
2141
+ #ifdef __cplusplus
2142
+ } // extern "C"
2143
+ #endif // __cplusplus
2144
+
2145
+ #endif /* DEREC_FFI_H */