@real-life/trust-protocol 0.3.2 → 0.4.0

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 (264) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/README.md +187 -78
  3. package/dist/ack.d.ts +84 -0
  4. package/dist/ack.d.ts.map +1 -0
  5. package/dist/ack.js +114 -0
  6. package/dist/ack.js.map +1 -0
  7. package/dist/adapters/vti-mediator.d.ts +154 -0
  8. package/dist/adapters/vti-mediator.d.ts.map +1 -0
  9. package/dist/adapters/vti-mediator.js +621 -0
  10. package/dist/adapters/vti-mediator.js.map +1 -0
  11. package/dist/anchor.d.ts +226 -0
  12. package/dist/anchor.d.ts.map +1 -0
  13. package/dist/anchor.js +347 -0
  14. package/dist/anchor.js.map +1 -0
  15. package/dist/{holder.d.ts → carrier-holder.d.ts} +1 -1
  16. package/dist/carrier-holder.d.ts.map +1 -0
  17. package/dist/{holder.js → carrier-holder.js} +5 -4
  18. package/dist/carrier-holder.js.map +1 -0
  19. package/dist/carrier-identity.js +4 -4
  20. package/dist/carrier-identity.js.map +1 -1
  21. package/dist/carrier.d.ts.map +1 -1
  22. package/dist/carrier.js +4 -3
  23. package/dist/carrier.js.map +1 -1
  24. package/dist/ceremony.d.ts +3 -2
  25. package/dist/ceremony.d.ts.map +1 -1
  26. package/dist/ceremony.js +16 -26
  27. package/dist/ceremony.js.map +1 -1
  28. package/dist/codec.d.ts +46 -0
  29. package/dist/codec.d.ts.map +1 -0
  30. package/dist/codec.js +410 -0
  31. package/dist/codec.js.map +1 -0
  32. package/dist/continuity.d.ts +67 -0
  33. package/dist/continuity.d.ts.map +1 -0
  34. package/dist/continuity.js +110 -0
  35. package/dist/continuity.js.map +1 -0
  36. package/dist/core.d.ts +4 -0
  37. package/dist/core.d.ts.map +1 -1
  38. package/dist/core.js.map +1 -1
  39. package/dist/crypto.d.ts +23 -7
  40. package/dist/crypto.d.ts.map +1 -1
  41. package/dist/crypto.js +54 -20
  42. package/dist/crypto.js.map +1 -1
  43. package/dist/delivery.d.ts +31 -3
  44. package/dist/delivery.d.ts.map +1 -1
  45. package/dist/delivery.js +75 -28
  46. package/dist/delivery.js.map +1 -1
  47. package/dist/encounter/ceremony.d.ts +37 -0
  48. package/dist/encounter/ceremony.d.ts.map +1 -0
  49. package/dist/encounter/ceremony.js +662 -0
  50. package/dist/encounter/ceremony.js.map +1 -0
  51. package/dist/encounter.d.ts +91 -1
  52. package/dist/encounter.d.ts.map +1 -1
  53. package/dist/encounter.js +191 -12
  54. package/dist/encounter.js.map +1 -1
  55. package/dist/engine.d.ts +291 -0
  56. package/dist/engine.d.ts.map +1 -0
  57. package/dist/engine.js +1395 -0
  58. package/dist/engine.js.map +1 -0
  59. package/dist/entropy.d.ts +28 -0
  60. package/dist/entropy.d.ts.map +1 -0
  61. package/dist/entropy.js +96 -0
  62. package/dist/entropy.js.map +1 -0
  63. package/dist/events.d.ts +177 -0
  64. package/dist/events.d.ts.map +1 -0
  65. package/dist/events.js +2 -0
  66. package/dist/events.js.map +1 -0
  67. package/dist/fixtures.d.ts +30 -0
  68. package/dist/fixtures.d.ts.map +1 -0
  69. package/dist/fixtures.js +155 -0
  70. package/dist/fixtures.js.map +1 -0
  71. package/dist/forge.d.ts +47 -0
  72. package/dist/forge.d.ts.map +1 -0
  73. package/dist/forge.js +20 -0
  74. package/dist/forge.js.map +1 -0
  75. package/dist/group-star.d.ts +251 -0
  76. package/dist/group-star.d.ts.map +1 -0
  77. package/dist/group-star.js +348 -0
  78. package/dist/group-star.js.map +1 -0
  79. package/dist/holder-api.d.ts +137 -0
  80. package/dist/holder-api.d.ts.map +1 -0
  81. package/dist/holder-api.js +132 -0
  82. package/dist/holder-api.js.map +1 -0
  83. package/dist/holder-state-v1.d.ts +801 -0
  84. package/dist/holder-state-v1.d.ts.map +1 -0
  85. package/dist/holder-state-v1.js +2 -0
  86. package/dist/holder-state-v1.js.map +1 -0
  87. package/dist/identity-state.d.ts +43 -0
  88. package/dist/identity-state.d.ts.map +1 -0
  89. package/dist/identity-state.js +345 -0
  90. package/dist/identity-state.js.map +1 -0
  91. package/dist/identity.d.ts +24 -2
  92. package/dist/identity.d.ts.map +1 -1
  93. package/dist/identity.js +70 -11
  94. package/dist/identity.js.map +1 -1
  95. package/dist/index.d.ts +26 -1
  96. package/dist/index.d.ts.map +1 -1
  97. package/dist/index.js +77 -29
  98. package/dist/index.js.map +1 -1
  99. package/dist/internal.d.ts +36 -0
  100. package/dist/internal.d.ts.map +1 -0
  101. package/dist/internal.js +22 -0
  102. package/dist/internal.js.map +1 -0
  103. package/dist/introduction/holder.d.ts +18 -0
  104. package/dist/introduction/holder.d.ts.map +1 -0
  105. package/dist/introduction/holder.js +757 -0
  106. package/dist/introduction/holder.js.map +1 -0
  107. package/dist/introduction.d.ts +101 -0
  108. package/dist/introduction.d.ts.map +1 -0
  109. package/dist/introduction.js +132 -0
  110. package/dist/introduction.js.map +1 -0
  111. package/dist/invariants.d.ts +43 -0
  112. package/dist/invariants.d.ts.map +1 -0
  113. package/dist/invariants.js +883 -0
  114. package/dist/invariants.js.map +1 -0
  115. package/dist/keys-seed.d.ts +7 -0
  116. package/dist/keys-seed.d.ts.map +1 -0
  117. package/dist/keys-seed.js +133 -0
  118. package/dist/keys-seed.js.map +1 -0
  119. package/dist/log-memory.d.ts +12 -0
  120. package/dist/log-memory.d.ts.map +1 -0
  121. package/dist/log-memory.js +101 -0
  122. package/dist/log-memory.js.map +1 -0
  123. package/dist/membership/holder.d.ts +35 -0
  124. package/dist/membership/holder.d.ts.map +1 -0
  125. package/dist/membership/holder.js +852 -0
  126. package/dist/membership/holder.js.map +1 -0
  127. package/dist/membership.d.ts +92 -0
  128. package/dist/membership.d.ts.map +1 -0
  129. package/dist/membership.js +157 -0
  130. package/dist/membership.js.map +1 -0
  131. package/dist/ports.d.ts +237 -0
  132. package/dist/ports.d.ts.map +1 -0
  133. package/dist/ports.js +2 -0
  134. package/dist/ports.js.map +1 -0
  135. package/dist/profile.d.ts +56 -0
  136. package/dist/profile.d.ts.map +1 -0
  137. package/dist/profile.js +193 -0
  138. package/dist/profile.js.map +1 -0
  139. package/dist/prompts.d.ts +14 -0
  140. package/dist/prompts.d.ts.map +1 -0
  141. package/dist/prompts.js +69 -0
  142. package/dist/prompts.js.map +1 -0
  143. package/dist/receive.d.ts +133 -0
  144. package/dist/receive.d.ts.map +1 -0
  145. package/dist/receive.js +298 -0
  146. package/dist/receive.js.map +1 -0
  147. package/dist/results.d.ts +158 -0
  148. package/dist/results.d.ts.map +1 -0
  149. package/dist/results.js +21 -0
  150. package/dist/results.js.map +1 -0
  151. package/dist/schemas.d.ts.map +1 -1
  152. package/dist/schemas.js +42 -38
  153. package/dist/schemas.js.map +1 -1
  154. package/dist/sha256.d.ts +3 -0
  155. package/dist/sha256.d.ts.map +1 -0
  156. package/dist/sha256.js +69 -0
  157. package/dist/sha256.js.map +1 -0
  158. package/dist/star.d.ts +31 -0
  159. package/dist/star.d.ts.map +1 -0
  160. package/dist/star.js +56 -0
  161. package/dist/star.js.map +1 -0
  162. package/dist/state-builder.d.ts +42 -0
  163. package/dist/state-builder.d.ts.map +1 -0
  164. package/dist/state-builder.js +100 -0
  165. package/dist/state-builder.js.map +1 -0
  166. package/dist/state.d.ts +853 -0
  167. package/dist/state.d.ts.map +1 -0
  168. package/dist/state.js +36 -0
  169. package/dist/state.js.map +1 -0
  170. package/dist/store-contract.d.ts +11 -0
  171. package/dist/store-contract.d.ts.map +1 -0
  172. package/dist/store-contract.js +189 -0
  173. package/dist/store-contract.js.map +1 -0
  174. package/dist/store-memory.d.ts +8 -0
  175. package/dist/store-memory.d.ts.map +1 -0
  176. package/dist/store-memory.js +17 -0
  177. package/dist/store-memory.js.map +1 -0
  178. package/dist/testing.d.ts +22 -0
  179. package/dist/testing.d.ts.map +1 -0
  180. package/dist/testing.js +21 -0
  181. package/dist/testing.js.map +1 -0
  182. package/dist/trust/continuity.d.ts +71 -0
  183. package/dist/trust/continuity.d.ts.map +1 -0
  184. package/dist/trust/continuity.js +1216 -0
  185. package/dist/trust/continuity.js.map +1 -0
  186. package/dist/trust/duties.d.ts +67 -0
  187. package/dist/trust/duties.d.ts.map +1 -0
  188. package/dist/trust/duties.js +179 -0
  189. package/dist/trust/duties.js.map +1 -0
  190. package/dist/trust/entries.d.ts +139 -0
  191. package/dist/trust/entries.d.ts.map +1 -0
  192. package/dist/trust/entries.js +694 -0
  193. package/dist/trust/entries.js.map +1 -0
  194. package/dist/trust/group-star.d.ts +43 -0
  195. package/dist/trust/group-star.d.ts.map +1 -0
  196. package/dist/trust/group-star.js +188 -0
  197. package/dist/trust/group-star.js.map +1 -0
  198. package/dist/trust/mapping.d.ts +56 -0
  199. package/dist/trust/mapping.d.ts.map +1 -0
  200. package/dist/trust/mapping.js +584 -0
  201. package/dist/trust/mapping.js.map +1 -0
  202. package/dist/trust/profile.d.ts +25 -0
  203. package/dist/trust/profile.d.ts.map +1 -0
  204. package/dist/trust/profile.js +249 -0
  205. package/dist/trust/profile.js.map +1 -0
  206. package/dist/trust/star.d.ts +208 -0
  207. package/dist/trust/star.d.ts.map +1 -0
  208. package/dist/trust/star.js +588 -0
  209. package/dist/trust/star.js.map +1 -0
  210. package/dist/trust/state.d.ts +83 -0
  211. package/dist/trust/state.d.ts.map +1 -0
  212. package/dist/trust/state.js +154 -0
  213. package/dist/trust/state.js.map +1 -0
  214. package/dist/util-freeze.d.ts +3 -0
  215. package/dist/util-freeze.d.ts.map +1 -0
  216. package/dist/util-freeze.js +11 -0
  217. package/dist/util-freeze.js.map +1 -0
  218. package/dist/views.d.ts +147 -0
  219. package/dist/views.d.ts.map +1 -0
  220. package/dist/views.js +268 -0
  221. package/dist/views.js.map +1 -0
  222. package/dist/visibility.d.ts +5 -5
  223. package/dist/visibility.d.ts.map +1 -1
  224. package/dist/visibility.js +22 -28
  225. package/dist/visibility.js.map +1 -1
  226. package/dist/wire.d.ts +178 -84
  227. package/dist/wire.d.ts.map +1 -1
  228. package/dist/wire.js.map +1 -1
  229. package/package.json +56 -10
  230. package/schemas/holder-state-v1.schema.json +3880 -0
  231. package/dist/holder.d.ts.map +0 -1
  232. package/dist/holder.js.map +0 -1
  233. package/dist/probe/acks.d.ts +0 -27
  234. package/dist/probe/acks.d.ts.map +0 -1
  235. package/dist/probe/acks.js +0 -152
  236. package/dist/probe/acks.js.map +0 -1
  237. package/dist/probe/continuity.d.ts +0 -20
  238. package/dist/probe/continuity.d.ts.map +0 -1
  239. package/dist/probe/continuity.js +0 -805
  240. package/dist/probe/continuity.js.map +0 -1
  241. package/dist/probe/deps.d.ts +0 -61
  242. package/dist/probe/deps.d.ts.map +0 -1
  243. package/dist/probe/deps.js +0 -54
  244. package/dist/probe/deps.js.map +0 -1
  245. package/dist/probe/encounter.d.ts +0 -26
  246. package/dist/probe/encounter.d.ts.map +0 -1
  247. package/dist/probe/encounter.js +0 -938
  248. package/dist/probe/encounter.js.map +0 -1
  249. package/dist/probe/introduce.d.ts +0 -62
  250. package/dist/probe/introduce.d.ts.map +0 -1
  251. package/dist/probe/introduce.js +0 -306
  252. package/dist/probe/introduce.js.map +0 -1
  253. package/dist/probe/membership.d.ts +0 -96
  254. package/dist/probe/membership.d.ts.map +0 -1
  255. package/dist/probe/membership.js +0 -467
  256. package/dist/probe/membership.js.map +0 -1
  257. package/dist/probe/trust.d.ts +0 -156
  258. package/dist/probe/trust.d.ts.map +0 -1
  259. package/dist/probe/trust.js +0 -1233
  260. package/dist/probe/trust.js.map +0 -1
  261. package/dist/probe.d.ts +0 -7
  262. package/dist/probe.d.ts.map +0 -1
  263. package/dist/probe.js +0 -42
  264. package/dist/probe.js.map +0 -1
@@ -11,7 +11,7 @@ export interface SealEntropy {
11
11
  ephSeed?: Uint8Array;
12
12
  nonce?: Uint8Array;
13
13
  }
14
- export declare function seal(document: Json, recipientKeyAgreement: string, { ephSeed, nonce }?: SealEntropy): Promise<Envelope>;
14
+ export declare function seal(document: Json, recipientKeyAgreement: string, { ephSeed, nonce }?: SealEntropy, subtle?: SubtleCrypto): Promise<Envelope>;
15
15
  /** Opening an envelope never throws: every failure is a named reason. */
16
16
  export type Unsealed = {
17
17
  document: Json;
@@ -20,7 +20,7 @@ export type Unsealed = {
20
20
  document?: undefined;
21
21
  error: 'malformed' | 'oversize' | 'decryption-failed';
22
22
  };
23
- export declare function unseal(env: Envelope, xPriv: CryptoKey): Promise<Unsealed>;
23
+ export declare function unseal(env: Envelope, xPriv: CryptoKey, subtle?: SubtleCrypto): Promise<Unsealed>;
24
24
  export interface ReceiveStage {
25
25
  stage: 1 | 2 | 3 | 4;
26
26
  label: string;
@@ -33,7 +33,28 @@ export interface Received {
33
33
  /** present when the chain passed stage 4 (also on duplicate-known) */
34
34
  document?: Json;
35
35
  digest?: string;
36
+ /** why the key failed: 'unknown' at stage 2 (an rkid never issued),
37
+ * 'retired' at stage 3 (a tombstone). Local diagnosis only: the
38
+ * disposition stays the one Delivery §6.2 names. */
39
+ key?: 'unknown' | 'retired';
36
40
  }
41
+ /**
42
+ * What a receiver's key agreement answers for an envelope's rkid and
43
+ * ephemeral key (Delivery §5, §6.2 stages 2–3): the raw X25519 shared
44
+ * secret; `retired` for a tombstone (known, the key destroyed: the
45
+ * envelope dies at stage 3); `unknown` for an rkid never issued (stage 2);
46
+ * `invalid` for an ephemeral key that yields no usable secret (stage 3).
47
+ */
48
+ export type KeyAnswer = {
49
+ status: 'available';
50
+ shared: Uint8Array;
51
+ } | {
52
+ status: 'retired';
53
+ } | {
54
+ status: 'unknown';
55
+ } | {
56
+ status: 'invalid';
57
+ };
37
58
  /**
38
59
  * The generic stages every delivery passes before its layer sees it.
39
60
  * World-neutral: keys come from the caller's resolver, the
@@ -47,5 +68,12 @@ export interface Received {
47
68
  * as decryption-failed, indistinguishable from any other undecryptable
48
69
  * envelope); undefined means "unknown rkid" and fails stage 2.
49
70
  */
50
- export declare function receive(env: unknown, keyForRkid: (rkid: string) => CryptoKey | null | undefined, completedEffects?: Set<string>): Promise<Received>;
71
+ export declare function receive(env: unknown, keyForRkid: (rkid: string) => CryptoKey | null | undefined, completedEffects?: Set<string>, subtle?: SubtleCrypto): Promise<Received>;
72
+ /**
73
+ * The same stages over a key agreement: `agree(rkid, epk)` is asked once,
74
+ * after the envelope's closed form passed, and its answer decides stage 2
75
+ * (unknown) and feeds stage 3. `completed(digest)` is the completed-effect
76
+ * cache, read only.
77
+ */
78
+ export declare function receiveByAgreement(env: unknown, agree: (rkid: string, epk: Uint8Array) => Promise<KeyAnswer>, completed?: (digest: string) => boolean, subtle?: SubtleCrypto): Promise<Received>;
51
79
  //# sourceMappingURL=delivery.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"delivery.d.ts","sourceRoot":"","sources":["../src/delivery.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAsBrC,kGAAkG;AAClG,MAAM,WAAW,QAAQ;IAAG,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE;AAC1F,wFAAwF;AACxF,MAAM,WAAW,WAAW;IAAG,OAAO,CAAC,EAAE,UAAU,CAAC;IAAC,KAAK,CAAC,EAAE,UAAU,CAAA;CAAE;AAEzE,wBAAsB,IAAI,CACxB,QAAQ,EAAE,IAAI,EAAE,qBAAqB,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,GAAE,WAAgB,GAClF,OAAO,CAAC,QAAQ,CAAC,CAcnB;AAED,yEAAyE;AACzE,MAAM,MAAM,QAAQ,GAAG;IAAE,QAAQ,EAAE,IAAI,CAAC;IAAC,KAAK,CAAC,EAAE,SAAS,CAAA;CAAE,GAAG;IAAE,QAAQ,CAAC,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,WAAW,GAAG,UAAU,GAAG,mBAAmB,CAAA;CAAE,CAAA;AAE9I,wBAAsB,MAAM,CAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,QAAQ,CAAC,CAkBhF;AAGD,MAAM,WAAW,YAAY;IAAG,KAAK,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,OAAO,CAAA;CAAE;AAClF,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,iBAAiB,GAAG,kBAAkB,GAAG,mBAAmB,GAAG,2BAA2B,CAAA;AAC/H,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,YAAY,EAAE,CAAA;IACtB,WAAW,EAAE,WAAW,CAAA;IACxB,sEAAsE;IACtE,QAAQ,CAAC,EAAE,IAAI,CAAA;IACf,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,OAAO,CAC3B,GAAG,EAAE,OAAO,EACZ,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,SAAS,GAAG,IAAI,GAAG,SAAS,EAC1D,gBAAgB,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,GAC7B,OAAO,CAAC,QAAQ,CAAC,CAwCnB"}
1
+ {"version":3,"file":"delivery.d.ts","sourceRoot":"","sources":["../src/delivery.ts"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAsBrC,kGAAkG;AAClG,MAAM,WAAW,QAAQ;IAAG,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE;AAC1F,wFAAwF;AACxF,MAAM,WAAW,WAAW;IAAG,OAAO,CAAC,EAAE,UAAU,CAAC;IAAC,KAAK,CAAC,EAAE,UAAU,CAAA;CAAE;AAEzE,wBAAsB,IAAI,CACxB,QAAQ,EAAE,IAAI,EAAE,qBAAqB,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,GAAE,WAAgB,EAAE,MAAM,CAAC,EAAE,YAAY,GACzG,OAAO,CAAC,QAAQ,CAAC,CAenB;AAED,yEAAyE;AACzE,MAAM,MAAM,QAAQ,GAAG;IAAE,QAAQ,EAAE,IAAI,CAAC;IAAC,KAAK,CAAC,EAAE,SAAS,CAAA;CAAE,GAAG;IAAE,QAAQ,CAAC,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,WAAW,GAAG,UAAU,GAAG,mBAAmB,CAAA;CAAE,CAAA;AAiB9I,wBAAsB,MAAM,CAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,QAAQ,CAAC,CAWvG;AAGD,MAAM,WAAW,YAAY;IAAG,KAAK,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,OAAO,CAAA;CAAE;AAClF,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,iBAAiB,GAAG,kBAAkB,GAAG,mBAAmB,GAAG,2BAA2B,CAAA;AAC/H,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,YAAY,EAAE,CAAA;IACtB,WAAW,EAAE,WAAW,CAAA;IACxB,sEAAsE;IACtE,QAAQ,CAAC,EAAE,IAAI,CAAA;IACf,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;yDAEqD;IACrD,GAAG,CAAC,EAAE,SAAS,GAAG,SAAS,CAAA;CAC5B;AAED;;;;;;GAMG;AACH,MAAM,MAAM,SAAS,GACjB;IAAE,MAAM,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,UAAU,CAAA;CAAE,GAC3C;IAAE,MAAM,EAAE,SAAS,CAAA;CAAE,GACrB;IAAE,MAAM,EAAE,SAAS,CAAA;CAAE,GACrB;IAAE,MAAM,EAAE,SAAS,CAAA;CAAE,CAAA;AAEzB;;;;;;;;;;;;GAYG;AACH,wBAAsB,OAAO,CAC3B,GAAG,EAAE,OAAO,EACZ,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,SAAS,GAAG,IAAI,GAAG,SAAS,EAC1D,gBAAgB,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,EAC9B,MAAM,CAAC,EAAE,YAAY,GACpB,OAAO,CAAC,QAAQ,CAAC,CAQnB;AAED;;;;;GAKG;AACH,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,KAAK,OAAO,CAAC,SAAS,CAAC,EAC5D,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,EACvC,MAAM,CAAC,EAAE,YAAY,GACpB,OAAO,CAAC,QAAQ,CAAC,CA+CnB"}
package/dist/delivery.js CHANGED
@@ -15,10 +15,17 @@
15
15
  // rejection is not an effect and stays repeatable); a cached digest
16
16
  // answers 'duplicate-known' forever after, and a second delivery never
17
17
  // produces a second effect. receive() honors such a cache when given one.
18
+ //
19
+ // Two ways to name the receiver's key: receive() takes a resolver to the
20
+ // private CryptoKey (an identity Context's); receiveByAgreement()
21
+ // takes an asynchronous key agreement that answers with the shared secret
22
+ // or why not (the holder's KeyProvider, which never hands out a key).
23
+ // Both run the same stages. Every function here takes an optional
24
+ // SubtleCrypto; without one it uses the platform's at call time.
18
25
  import { jcs, b64uOf, fromB64u } from './core.js';
19
26
  import { hkdf, xFromSeed, xRawOfMk, ecdh, digestDoc, rand } from './crypto.js';
27
+ import { platformSubtle } from './crypto.js';
20
28
  const te = new TextEncoder();
21
- const S = globalThis.crypto.subtle;
22
29
  // canonical base64url or nothing — a second spelling of the same bytes
23
30
  // is a different string, and dedup digests are computed over strings
24
31
  const canonicalB64u = (s) => {
@@ -36,23 +43,24 @@ const canonicalB64u = (s) => {
36
43
  // ── sealed envelope (Delivery §5) ───────────────────────────────────────
37
44
  // X25519 ephemeral → HKDF('rltp/v1/seal') → AES-256-GCM (12-byte nonce,
38
45
  // 16-byte tag appended). Entropy is caller-suppliable for replay.
39
- const aesKey = async (shared, usage) => {
46
+ const aesKey = async (shared, usage, S) => {
40
47
  if (shared.every((b) => b === 0))
41
48
  throw new Error('all-zero shared secret');
42
- return S.importKey('raw', await hkdf(shared, 'rltp/v1/seal'), { name: 'AES-GCM' }, false, [usage]);
49
+ return S.importKey('raw', await hkdf(shared, 'rltp/v1/seal', 32, S), { name: 'AES-GCM' }, false, [usage]);
43
50
  };
44
- export async function seal(document, recipientKeyAgreement, { ephSeed, nonce } = {}) {
51
+ export async function seal(document, recipientKeyAgreement, { ephSeed, nonce } = {}, subtle) {
45
52
  // a producer API never emits what the contract rejects (B-3): the only
46
53
  // envelope nonce is 96 bits, the only ephemeral seed 32 bytes
47
54
  if (ephSeed !== undefined && !(ephSeed instanceof Uint8Array && ephSeed.length === 32))
48
55
  throw new Error('ephSeed must be exactly 32 bytes');
49
56
  if (nonce !== undefined && !(nonce instanceof Uint8Array && nonce.length === 12))
50
57
  throw new Error('envelope nonce must be exactly 12 bytes (Delivery §5)');
51
- const eph = await xFromSeed(ephSeed ?? rand(32));
58
+ const S = subtle ?? platformSubtle();
59
+ const eph = await xFromSeed(ephSeed ?? rand(32), S);
52
60
  const theirRaw = xRawOfMk(recipientKeyAgreement);
53
61
  if (!theirRaw)
54
62
  throw new Error('malformed recipient keyAgreement');
55
- const key = await aesKey(await ecdh(eph.priv, theirRaw), 'encrypt');
63
+ const key = await aesKey(await ecdh(eph.priv, theirRaw, S), 'encrypt', S);
56
64
  const n = nonce ?? rand(12);
57
65
  const plaintext = te.encode(jcs(document));
58
66
  if (plaintext.length > 65536)
@@ -60,19 +68,11 @@ export async function seal(document, recipientKeyAgreement, { ephSeed, nonce } =
60
68
  const ct = new Uint8Array(await S.encrypt({ name: 'AES-GCM', iv: n }, key, plaintext));
61
69
  return { rkid: recipientKeyAgreement, epk: b64uOf(eph.pubRaw), nonce: b64uOf(n), ciphertext: b64uOf(ct) };
62
70
  }
63
- export async function unseal(env, xPriv) {
64
- // total over ARBITRARY input (B-4): a foreign envelope with invalid or
65
- // non-canonical base64url is 'malformed', never an exception
66
- const nonce = canonicalB64u(env?.nonce), epkRaw = canonicalB64u(env?.epk), raw = canonicalB64u(env?.ciphertext);
67
- if (!nonce || !epkRaw || !raw)
68
- return { error: 'malformed' };
69
- if (nonce.length !== 12 || epkRaw.length !== 32 || raw.length < 16)
70
- return { error: 'malformed' };
71
- if (raw.length - 16 > 65536)
72
- return { error: 'oversize' }; // size bound BEFORE decryption
71
+ /** Decrypt and parse under an agreed shared secret; never throws. */
72
+ async function openShared(nonce, raw, shared, S) {
73
73
  let key;
74
74
  try {
75
- key = await aesKey(await ecdh(xPriv, epkRaw), 'decrypt');
75
+ key = await aesKey(shared, 'decrypt', S);
76
76
  }
77
77
  catch {
78
78
  return { error: 'decryption-failed' };
@@ -101,6 +101,26 @@ export async function unseal(env, xPriv) {
101
101
  return { error: 'malformed' };
102
102
  }
103
103
  }
104
+ export async function unseal(env, xPriv, subtle) {
105
+ // total over ARBITRARY input (B-4): a foreign envelope with invalid or
106
+ // non-canonical base64url is 'malformed', never an exception
107
+ const nonce = canonicalB64u(env?.nonce), epkRaw = canonicalB64u(env?.epk), raw = canonicalB64u(env?.ciphertext);
108
+ if (!nonce || !epkRaw || !raw)
109
+ return { error: 'malformed' };
110
+ if (nonce.length !== 12 || epkRaw.length !== 32 || raw.length < 16)
111
+ return { error: 'malformed' };
112
+ if (raw.length - 16 > 65536)
113
+ return { error: 'oversize' }; // size bound BEFORE decryption
114
+ const S = subtle ?? platformSubtle();
115
+ let shared;
116
+ try {
117
+ shared = await ecdh(xPriv, epkRaw, S);
118
+ }
119
+ catch {
120
+ return { error: 'decryption-failed' };
121
+ }
122
+ return openShared(nonce, raw, shared, S);
123
+ }
104
124
  /**
105
125
  * The generic stages every delivery passes before its layer sees it.
106
126
  * World-neutral: keys come from the caller's resolver, the
@@ -114,7 +134,30 @@ export async function unseal(env, xPriv) {
114
134
  * as decryption-failed, indistinguishable from any other undecryptable
115
135
  * envelope); undefined means "unknown rkid" and fails stage 2.
116
136
  */
117
- export async function receive(env, keyForRkid, completedEffects) {
137
+ export async function receive(env, keyForRkid, completedEffects, subtle) {
138
+ const resolve = async (rkid, epk) => {
139
+ const key = keyForRkid(rkid);
140
+ if (key === undefined)
141
+ return { status: 'unknown' };
142
+ if (key === null)
143
+ return { status: 'retired' };
144
+ try {
145
+ return { status: 'available', shared: await ecdh(key, epk, subtle ?? platformSubtle()) };
146
+ }
147
+ catch {
148
+ return { status: 'invalid' };
149
+ }
150
+ };
151
+ return receiveByAgreement(env, resolve, completedEffects ? (d) => completedEffects.has(d) : undefined, subtle);
152
+ }
153
+ /**
154
+ * The same stages over a key agreement: `agree(rkid, epk)` is asked once,
155
+ * after the envelope's closed form passed, and its answer decides stage 2
156
+ * (unknown) and feeds stage 3. `completed(digest)` is the completed-effect
157
+ * cache, read only.
158
+ */
159
+ export async function receiveByAgreement(env, agree, completed, subtle) {
160
+ const S = subtle ?? platformSubtle();
118
161
  const stages = [];
119
162
  const step = (stage, label, ok) => { stages.push({ stage, label, ok }); return ok; };
120
163
  const e = env;
@@ -127,20 +170,24 @@ export async function receive(env, keyForRkid, completedEffects) {
127
170
  // canonical; the rkid a decodable multikey the resolver knows
128
171
  const isObj = e !== null && typeof e === 'object' && !Array.isArray(e);
129
172
  const ctBytes = isObj ? canonicalB64u(e.ciphertext) : null;
173
+ const epkRaw = isObj ? canonicalB64u(e.epk) : null;
174
+ const nonce = isObj ? canonicalB64u(e.nonce) : null;
130
175
  const closedForm = isObj && Object.keys(e).length === 4
131
- && canonicalB64u(e.epk)?.length === 32 && canonicalB64u(e.nonce)?.length === 12
176
+ && epkRaw?.length === 32 && nonce?.length === 12
132
177
  && ctBytes !== null && ctBytes.length >= 17 // tag + at least one byte (schema lower bound)
133
178
  && typeof e.rkid === 'string' && xRawOfMk(e.rkid) !== null;
134
- const key = closedForm ? keyForRkid(e.rkid) : undefined;
135
- if (!step(2, 'envelope: closed form · base64url canonical · epk 32 B · nonce 12 B · rkid known', closedForm && key !== undefined))
136
- return { stages, disposition: 'failed(malformed)' };
179
+ const answer = closedForm ? await agree(e.rkid, new Uint8Array(epkRaw)) : { status: 'unknown' };
180
+ if (!step(2, 'envelope: closed form · base64url canonical · epk 32 B · nonce 12 B · rkid known', closedForm && answer.status !== 'unknown')) {
181
+ return { stages, disposition: 'failed(malformed)', ...(closedForm ? { key: 'unknown' } : {}) };
182
+ }
137
183
  // 3 — decryption: X25519 + HKDF(rltp/v1/seal) + the AES-256-GCM tag.
138
- // A tombstoned rkid (key === null) dies HERE, not at stage 2.
139
- const opened = key === null ? { error: 'decryption-failed' } : await unseal(e, key);
184
+ // A tombstoned rkid dies HERE, not at stage 2.
185
+ const opened = answer.status === 'available' ? await openShared(nonce, ctBytes, answer.shared, S) : { error: 'decryption-failed' };
140
186
  // only CRYPTO failures belong to stage 3; an authenticated plaintext
141
187
  // that defeats UTF-8 or JSON is a stage-4 malformed (review 3, M-2)
142
- if (!step(3, 'decryption: X25519 + HKDF(rltp/v1/seal) + AES-256-GCM tag', opened.error !== 'decryption-failed' && opened.error !== 'oversize'))
143
- return { stages, disposition: `failed(${opened.error})` };
188
+ if (!step(3, 'decryption: X25519 + HKDF(rltp/v1/seal) + AES-256-GCM tag', opened.error !== 'decryption-failed' && opened.error !== 'oversize')) {
189
+ return { stages, disposition: `failed(${opened.error})`, ...(answer.status === 'retired' ? { key: 'retired' } : {}) };
190
+ }
144
191
  if (opened.error === 'malformed') {
145
192
  step(4, 'parse — invalid UTF-8 or not JSON', false);
146
193
  return { stages, disposition: 'failed(malformed)' };
@@ -156,14 +203,14 @@ export async function receive(env, keyForRkid, completedEffects) {
156
203
  }
157
204
  let digest;
158
205
  try {
159
- digest = await digestDoc(doc);
206
+ digest = await digestDoc(doc, S);
160
207
  }
161
208
  catch {
162
209
  step(4, 'parse — no canonical form (non-finite number)', false);
163
210
  return { stages, disposition: 'failed(malformed)' };
164
211
  }
165
212
  step(4, `parse + digest ${digest.slice(0, 14)}… · completed-effect cache`, true);
166
- if (completedEffects?.has(digest))
213
+ if (completed?.(digest))
167
214
  return { stages, disposition: 'duplicate-known', document: doc, digest };
168
215
  return { stages, disposition: 'unique', document: doc, digest };
169
216
  }
@@ -1 +1 @@
1
- {"version":3,"file":"delivery.js","sourceRoot":"","sources":["../src/delivery.ts"],"names":[],"mappings":"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","sourcesContent":["// delivery — the Delivery Contract: how documents travel, and what a\n// receiver must check before anything takes effect.\n//\n// The sealed envelope (X25519 ephemeral -> HKDF -> AES-256-GCM) and the\n// generic receive chain in its declared ORDER: the size bound holds\n// BEFORE decryption, the envelope form before that, and the digest is\n// taken over the canonical form of the PARSED document — never over the\n// raw bytes. Each stage names the disposition it produces, so a\n// rejection can always say where it happened.\n//\n// What this module deliberately does NOT carry: the type-specific stages\n// (proofs, bindings, effects) — those belong to the artifact's layer —\n// and the completed-effect CACHE itself. The cache contract is the\n// caller's to keep: only a COMPLETED effect's digest goes in (a\n// rejection is not an effect and stays repeatable); a cached digest\n// answers 'duplicate-known' forever after, and a second delivery never\n// produces a second effect. receive() honors such a cache when given one.\nimport { jcs, b64uOf, fromB64u } from './core.js'\nimport type { Json } from './core.js'\nimport { hkdf, xFromSeed, xRawOfMk, ecdh, digestDoc, rand } from './crypto.js'\n\nconst te = new TextEncoder()\nconst S = globalThis.crypto.subtle\n\n// canonical base64url or nothing — a second spelling of the same bytes\n// is a different string, and dedup digests are computed over strings\nconst canonicalB64u = (s: unknown): Uint8Array | null => {\n if (typeof s !== 'string') return null\n let b: Uint8Array\n try { b = fromB64u(s) } catch { return null }\n return b64uOf(b) === s ? b : null\n}\n\n// ── sealed envelope (Delivery §5) ───────────────────────────────────────\n// X25519 ephemeral → HKDF('rltp/v1/seal') → AES-256-GCM (12-byte nonce,\n// 16-byte tag appended). Entropy is caller-suppliable for replay.\nconst aesKey = async (shared: Uint8Array, usage: 'encrypt' | 'decrypt'): Promise<CryptoKey> => {\n if (shared.every((b) => b === 0)) throw new Error('all-zero shared secret')\n return S.importKey('raw', await hkdf(shared, 'rltp/v1/seal'), { name: 'AES-GCM' }, false, [usage])\n}\n/** A sealed envelope as it travels: recipient key id, ephemeral public key, nonce, ciphertext. */\nexport interface Envelope { rkid: string, epk: string, nonce: string, ciphertext: string }\n/** Caller-supplied entropy — the invariant that makes every construction replayable. */\nexport interface SealEntropy { ephSeed?: Uint8Array, nonce?: Uint8Array }\n\nexport async function seal (\n document: Json, recipientKeyAgreement: string, { ephSeed, nonce }: SealEntropy = {},\n): Promise<Envelope> {\n // a producer API never emits what the contract rejects (B-3): the only\n // envelope nonce is 96 bits, the only ephemeral seed 32 bytes\n if (ephSeed !== undefined && !(ephSeed instanceof Uint8Array && ephSeed.length === 32)) throw new Error('ephSeed must be exactly 32 bytes')\n if (nonce !== undefined && !(nonce instanceof Uint8Array && nonce.length === 12)) throw new Error('envelope nonce must be exactly 12 bytes (Delivery §5)')\n const eph = await xFromSeed(ephSeed ?? rand(32))\n const theirRaw = xRawOfMk(recipientKeyAgreement)\n if (!theirRaw) throw new Error('malformed recipient keyAgreement')\n const key = await aesKey(await ecdh(eph.priv, theirRaw), 'encrypt')\n const n = nonce ?? rand(12)\n const plaintext = te.encode(jcs(document))\n if (plaintext.length > 65536) throw new Error('oversize')\n const ct = new Uint8Array(await S.encrypt({ name: 'AES-GCM', iv: n }, key, plaintext))\n return { rkid: recipientKeyAgreement, epk: b64uOf(eph.pubRaw), nonce: b64uOf(n), ciphertext: b64uOf(ct) }\n}\n\n/** Opening an envelope never throws: every failure is a named reason. */\nexport type Unsealed = { document: Json, error?: undefined } | { document?: undefined, error: 'malformed' | 'oversize' | 'decryption-failed' }\n\nexport async function unseal (env: Envelope, xPriv: CryptoKey): Promise<Unsealed> {\n // total over ARBITRARY input (B-4): a foreign envelope with invalid or\n // non-canonical base64url is 'malformed', never an exception\n const nonce = canonicalB64u(env?.nonce), epkRaw = canonicalB64u(env?.epk), raw = canonicalB64u(env?.ciphertext)\n if (!nonce || !epkRaw || !raw) return { error: 'malformed' }\n if (nonce.length !== 12 || epkRaw.length !== 32 || raw.length < 16) return { error: 'malformed' }\n if (raw.length - 16 > 65536) return { error: 'oversize' } // size bound BEFORE decryption\n let key\n try { key = await aesKey(await ecdh(xPriv, epkRaw), 'decrypt') } catch { return { error: 'decryption-failed' } }\n let bytes\n try { bytes = await S.decrypt({ name: 'AES-GCM', iv: nonce }, key, raw) } catch { return { error: 'decryption-failed' } }\n // from here the cryptography has SPOKEN — everything below is form:\n // authenticated invalid UTF-8 and unparseable JSON are 'malformed'\n // (stage 4 in the receive chain), never a crypto failure (review 3, M-2)\n let plaintext\n try { plaintext = new TextDecoder('utf-8', { fatal: true }).decode(bytes) } catch { return { error: 'malformed' } }\n try { return { document: JSON.parse(plaintext) } }\n catch { return { error: 'malformed' } }\n}\n\n// ── the generic receive chain (Delivery §4: stages 1–4) ─────────────────\nexport interface ReceiveStage { stage: 1 | 2 | 3 | 4, label: string, ok: boolean }\nexport type Disposition = 'unique' | 'duplicate-known' | 'failed(oversize)' | 'failed(malformed)' | 'failed(decryption-failed)'\nexport interface Received {\n stages: ReceiveStage[]\n disposition: Disposition\n /** present when the chain passed stage 4 (also on duplicate-known) */\n document?: Json\n digest?: string\n}\n\n/**\n * The generic stages every delivery passes before its layer sees it.\n * World-neutral: keys come from the caller's resolver, the\n * completed-effect cache is the caller's set of digests. This function\n * only READS the cache — the caller adds a digest after (and only\n * after) the type-specific effect completed.\n *\n * The resolver speaks three words (Delivery §4, stage 2/3): a CryptoKey\n * means \"known, here is the key\"; null means \"known, but the key is\n * gone\" (a tombstone — the envelope passes stage 2 and dies at stage 3\n * as decryption-failed, indistinguishable from any other undecryptable\n * envelope); undefined means \"unknown rkid\" and fails stage 2.\n */\nexport async function receive (\n env: unknown,\n keyForRkid: (rkid: string) => CryptoKey | null | undefined,\n completedEffects?: Set<string>,\n): Promise<Received> {\n const stages: ReceiveStage[] = []\n const step = (stage: ReceiveStage['stage'], label: string, ok: boolean): boolean => { stages.push({ stage, label, ok }); return ok }\n const e = env as Partial<Envelope> | null | undefined\n\n // 1 — the size bound holds BEFORE any decoding or decryption work:\n // estimated from the string alone, so an oversize envelope costs O(1)\n const ctEst = typeof e?.ciphertext === 'string' ? Math.floor(e.ciphertext.length * 3 / 4) : 0\n if (!step(1, `size bound: ciphertext − tag ≤ 65536 B (~${Math.max(0, ctEst - 16)} B)`, ctEst - 16 <= 65536)) return { stages, disposition: 'failed(oversize)' }\n\n // 2 — envelope form: the CLOSED shape — exactly the four fields, each\n // canonical; the rkid a decodable multikey the resolver knows\n const isObj = e !== null && typeof e === 'object' && !Array.isArray(e)\n const ctBytes = isObj ? canonicalB64u((e as any).ciphertext) : null\n const closedForm = isObj && Object.keys(e).length === 4\n && canonicalB64u(e.epk)?.length === 32 && canonicalB64u(e.nonce)?.length === 12\n && ctBytes !== null && ctBytes.length >= 17 // tag + at least one byte (schema lower bound)\n && typeof e.rkid === 'string' && xRawOfMk(e.rkid) !== null\n const key = closedForm ? keyForRkid((e as Envelope).rkid) : undefined\n if (!step(2, 'envelope: closed form · base64url canonical · epk 32 B · nonce 12 B · rkid known', closedForm && key !== undefined)) return { stages, disposition: 'failed(malformed)' }\n\n // 3 — decryption: X25519 + HKDF(rltp/v1/seal) + the AES-256-GCM tag.\n // A tombstoned rkid (key === null) dies HERE, not at stage 2.\n const opened = key === null ? { error: 'decryption-failed' as const } : await unseal(e as Envelope, key as CryptoKey)\n // only CRYPTO failures belong to stage 3; an authenticated plaintext\n // that defeats UTF-8 or JSON is a stage-4 malformed (review 3, M-2)\n if (!step(3, 'decryption: X25519 + HKDF(rltp/v1/seal) + AES-256-GCM tag', opened.error !== 'decryption-failed' && opened.error !== 'oversize')) return { stages, disposition: `failed(${opened.error!})` as Disposition }\n if (opened.error === 'malformed') { step(4, 'parse — invalid UTF-8 or not JSON', false); return { stages, disposition: 'failed(malformed)' } }\n\n // 4 — parse: a JSON object; digest over its CANONICAL form; cache\n // check. TOTAL: a document that parses but defeats the canonical\n // form (JSON.parse turns 1e400 into Infinity) is malformed here,\n // never an exception (review 2, B-2).\n const doc = (opened as { document?: Json }).document\n if (doc === null || doc === undefined || typeof doc !== 'object' || Array.isArray(doc)) { step(4, 'parse — not a JSON object', false); return { stages, disposition: 'failed(malformed)' } }\n let digest: string\n try { digest = await digestDoc(doc) } catch { step(4, 'parse — no canonical form (non-finite number)', false); return { stages, disposition: 'failed(malformed)' } }\n step(4, `parse + digest ${digest.slice(0, 14)}… · completed-effect cache`, true)\n if (completedEffects?.has(digest)) return { stages, disposition: 'duplicate-known', document: doc, digest }\n return { stages, disposition: 'unique', document: doc, digest }\n}\n"]}
1
+ {"version":3,"file":"delivery.js","sourceRoot":"","sources":["../src/delivery.ts"],"names":[],"mappings":"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","sourcesContent":["// delivery — the Delivery Contract: how documents travel, and what a\n// receiver must check before anything takes effect.\n//\n// The sealed envelope (X25519 ephemeral -> HKDF -> AES-256-GCM) and the\n// generic receive chain in its declared ORDER: the size bound holds\n// BEFORE decryption, the envelope form before that, and the digest is\n// taken over the canonical form of the PARSED document — never over the\n// raw bytes. Each stage names the disposition it produces, so a\n// rejection can always say where it happened.\n//\n// What this module deliberately does NOT carry: the type-specific stages\n// (proofs, bindings, effects) — those belong to the artifact's layer —\n// and the completed-effect CACHE itself. The cache contract is the\n// caller's to keep: only a COMPLETED effect's digest goes in (a\n// rejection is not an effect and stays repeatable); a cached digest\n// answers 'duplicate-known' forever after, and a second delivery never\n// produces a second effect. receive() honors such a cache when given one.\n//\n// Two ways to name the receiver's key: receive() takes a resolver to the\n// private CryptoKey (an identity Context's); receiveByAgreement()\n// takes an asynchronous key agreement that answers with the shared secret\n// or why not (the holder's KeyProvider, which never hands out a key).\n// Both run the same stages. Every function here takes an optional\n// SubtleCrypto; without one it uses the platform's at call time.\nimport { jcs, b64uOf, fromB64u } from './core.js'\nimport type { Json } from './core.js'\nimport { hkdf, xFromSeed, xRawOfMk, ecdh, digestDoc, rand } from './crypto.js'\nimport { platformSubtle } from './crypto.js'\n\nconst te = new TextEncoder()\n\n// canonical base64url or nothing — a second spelling of the same bytes\n// is a different string, and dedup digests are computed over strings\nconst canonicalB64u = (s: unknown): Uint8Array | null => {\n if (typeof s !== 'string') return null\n let b: Uint8Array\n try { b = fromB64u(s) } catch { return null }\n return b64uOf(b) === s ? b : null\n}\n\n// ── sealed envelope (Delivery §5) ───────────────────────────────────────\n// X25519 ephemeral → HKDF('rltp/v1/seal') → AES-256-GCM (12-byte nonce,\n// 16-byte tag appended). Entropy is caller-suppliable for replay.\nconst aesKey = async (shared: Uint8Array, usage: 'encrypt' | 'decrypt', S: SubtleCrypto): Promise<CryptoKey> => {\n if (shared.every((b) => b === 0)) throw new Error('all-zero shared secret')\n return S.importKey('raw', await hkdf(shared, 'rltp/v1/seal', 32, S), { name: 'AES-GCM' }, false, [usage])\n}\n/** A sealed envelope as it travels: recipient key id, ephemeral public key, nonce, ciphertext. */\nexport interface Envelope { rkid: string, epk: string, nonce: string, ciphertext: string }\n/** Caller-supplied entropy — the invariant that makes every construction replayable. */\nexport interface SealEntropy { ephSeed?: Uint8Array, nonce?: Uint8Array }\n\nexport async function seal (\n document: Json, recipientKeyAgreement: string, { ephSeed, nonce }: SealEntropy = {}, subtle?: SubtleCrypto,\n): Promise<Envelope> {\n // a producer API never emits what the contract rejects (B-3): the only\n // envelope nonce is 96 bits, the only ephemeral seed 32 bytes\n if (ephSeed !== undefined && !(ephSeed instanceof Uint8Array && ephSeed.length === 32)) throw new Error('ephSeed must be exactly 32 bytes')\n if (nonce !== undefined && !(nonce instanceof Uint8Array && nonce.length === 12)) throw new Error('envelope nonce must be exactly 12 bytes (Delivery §5)')\n const S = subtle ?? platformSubtle()\n const eph = await xFromSeed(ephSeed ?? rand(32), S)\n const theirRaw = xRawOfMk(recipientKeyAgreement)\n if (!theirRaw) throw new Error('malformed recipient keyAgreement')\n const key = await aesKey(await ecdh(eph.priv, theirRaw, S), 'encrypt', S)\n const n = nonce ?? rand(12)\n const plaintext = te.encode(jcs(document))\n if (plaintext.length > 65536) throw new Error('oversize')\n const ct = new Uint8Array(await S.encrypt({ name: 'AES-GCM', iv: n }, key, plaintext))\n return { rkid: recipientKeyAgreement, epk: b64uOf(eph.pubRaw), nonce: b64uOf(n), ciphertext: b64uOf(ct) }\n}\n\n/** Opening an envelope never throws: every failure is a named reason. */\nexport type Unsealed = { document: Json, error?: undefined } | { document?: undefined, error: 'malformed' | 'oversize' | 'decryption-failed' }\n\n/** Decrypt and parse under an agreed shared secret; never throws. */\nasync function openShared (nonce: Uint8Array, raw: Uint8Array, shared: Uint8Array, S: SubtleCrypto): Promise<Unsealed> {\n let key\n try { key = await aesKey(shared, 'decrypt', S) } catch { return { error: 'decryption-failed' } }\n let bytes\n try { bytes = await S.decrypt({ name: 'AES-GCM', iv: nonce }, key, raw) } catch { return { error: 'decryption-failed' } }\n // from here the cryptography has SPOKEN — everything below is form:\n // authenticated invalid UTF-8 and unparseable JSON are 'malformed'\n // (stage 4 in the receive chain), never a crypto failure (review 3, M-2)\n let plaintext\n try { plaintext = new TextDecoder('utf-8', { fatal: true }).decode(bytes) } catch { return { error: 'malformed' } }\n try { return { document: JSON.parse(plaintext) } }\n catch { return { error: 'malformed' } }\n}\n\nexport async function unseal (env: Envelope, xPriv: CryptoKey, subtle?: SubtleCrypto): Promise<Unsealed> {\n // total over ARBITRARY input (B-4): a foreign envelope with invalid or\n // non-canonical base64url is 'malformed', never an exception\n const nonce = canonicalB64u(env?.nonce), epkRaw = canonicalB64u(env?.epk), raw = canonicalB64u(env?.ciphertext)\n if (!nonce || !epkRaw || !raw) return { error: 'malformed' }\n if (nonce.length !== 12 || epkRaw.length !== 32 || raw.length < 16) return { error: 'malformed' }\n if (raw.length - 16 > 65536) return { error: 'oversize' } // size bound BEFORE decryption\n const S = subtle ?? platformSubtle()\n let shared\n try { shared = await ecdh(xPriv, epkRaw, S) } catch { return { error: 'decryption-failed' } }\n return openShared(nonce, raw, shared, S)\n}\n\n// ── the generic receive chain (Delivery §4: stages 1–4) ─────────────────\nexport interface ReceiveStage { stage: 1 | 2 | 3 | 4, label: string, ok: boolean }\nexport type Disposition = 'unique' | 'duplicate-known' | 'failed(oversize)' | 'failed(malformed)' | 'failed(decryption-failed)'\nexport interface Received {\n stages: ReceiveStage[]\n disposition: Disposition\n /** present when the chain passed stage 4 (also on duplicate-known) */\n document?: Json\n digest?: string\n /** why the key failed: 'unknown' at stage 2 (an rkid never issued),\n * 'retired' at stage 3 (a tombstone). Local diagnosis only: the\n * disposition stays the one Delivery §6.2 names. */\n key?: 'unknown' | 'retired'\n}\n\n/**\n * What a receiver's key agreement answers for an envelope's rkid and\n * ephemeral key (Delivery §5, §6.2 stages 2–3): the raw X25519 shared\n * secret; `retired` for a tombstone (known, the key destroyed: the\n * envelope dies at stage 3); `unknown` for an rkid never issued (stage 2);\n * `invalid` for an ephemeral key that yields no usable secret (stage 3).\n */\nexport type KeyAnswer =\n | { status: 'available', shared: Uint8Array }\n | { status: 'retired' }\n | { status: 'unknown' }\n | { status: 'invalid' }\n\n/**\n * The generic stages every delivery passes before its layer sees it.\n * World-neutral: keys come from the caller's resolver, the\n * completed-effect cache is the caller's set of digests. This function\n * only READS the cache — the caller adds a digest after (and only\n * after) the type-specific effect completed.\n *\n * The resolver speaks three words (Delivery §4, stage 2/3): a CryptoKey\n * means \"known, here is the key\"; null means \"known, but the key is\n * gone\" (a tombstone — the envelope passes stage 2 and dies at stage 3\n * as decryption-failed, indistinguishable from any other undecryptable\n * envelope); undefined means \"unknown rkid\" and fails stage 2.\n */\nexport async function receive (\n env: unknown,\n keyForRkid: (rkid: string) => CryptoKey | null | undefined,\n completedEffects?: Set<string>,\n subtle?: SubtleCrypto,\n): Promise<Received> {\n const resolve = async (rkid: string, epk: Uint8Array): Promise<KeyAnswer> => {\n const key = keyForRkid(rkid)\n if (key === undefined) return { status: 'unknown' }\n if (key === null) return { status: 'retired' }\n try { return { status: 'available', shared: await ecdh(key, epk, subtle ?? platformSubtle()) } } catch { return { status: 'invalid' } }\n }\n return receiveByAgreement(env, resolve, completedEffects ? (d) => completedEffects.has(d) : undefined, subtle)\n}\n\n/**\n * The same stages over a key agreement: `agree(rkid, epk)` is asked once,\n * after the envelope's closed form passed, and its answer decides stage 2\n * (unknown) and feeds stage 3. `completed(digest)` is the completed-effect\n * cache, read only.\n */\nexport async function receiveByAgreement (\n env: unknown,\n agree: (rkid: string, epk: Uint8Array) => Promise<KeyAnswer>,\n completed?: (digest: string) => boolean,\n subtle?: SubtleCrypto,\n): Promise<Received> {\n const S = subtle ?? platformSubtle()\n const stages: ReceiveStage[] = []\n const step = (stage: ReceiveStage['stage'], label: string, ok: boolean): boolean => { stages.push({ stage, label, ok }); return ok }\n const e = env as Partial<Envelope> | null | undefined\n\n // 1 — the size bound holds BEFORE any decoding or decryption work:\n // estimated from the string alone, so an oversize envelope costs O(1)\n const ctEst = typeof e?.ciphertext === 'string' ? Math.floor(e.ciphertext.length * 3 / 4) : 0\n if (!step(1, `size bound: ciphertext − tag ≤ 65536 B (~${Math.max(0, ctEst - 16)} B)`, ctEst - 16 <= 65536)) return { stages, disposition: 'failed(oversize)' }\n\n // 2 — envelope form: the CLOSED shape — exactly the four fields, each\n // canonical; the rkid a decodable multikey the resolver knows\n const isObj = e !== null && typeof e === 'object' && !Array.isArray(e)\n const ctBytes = isObj ? canonicalB64u((e as any).ciphertext) : null\n const epkRaw = isObj ? canonicalB64u(e.epk) : null\n const nonce = isObj ? canonicalB64u(e.nonce) : null\n const closedForm = isObj && Object.keys(e).length === 4\n && epkRaw?.length === 32 && nonce?.length === 12\n && ctBytes !== null && ctBytes.length >= 17 // tag + at least one byte (schema lower bound)\n && typeof e.rkid === 'string' && xRawOfMk(e.rkid) !== null\n const answer: KeyAnswer = closedForm ? await agree((e as Envelope).rkid, new Uint8Array(epkRaw!)) : { status: 'unknown' }\n if (!step(2, 'envelope: closed form · base64url canonical · epk 32 B · nonce 12 B · rkid known', closedForm && answer.status !== 'unknown')) {\n return { stages, disposition: 'failed(malformed)', ...(closedForm ? { key: 'unknown' as const } : {}) }\n }\n\n // 3 — decryption: X25519 + HKDF(rltp/v1/seal) + the AES-256-GCM tag.\n // A tombstoned rkid dies HERE, not at stage 2.\n const opened: Unsealed = answer.status === 'available' ? await openShared(nonce!, ctBytes!, answer.shared, S) : { error: 'decryption-failed' }\n // only CRYPTO failures belong to stage 3; an authenticated plaintext\n // that defeats UTF-8 or JSON is a stage-4 malformed (review 3, M-2)\n if (!step(3, 'decryption: X25519 + HKDF(rltp/v1/seal) + AES-256-GCM tag', opened.error !== 'decryption-failed' && opened.error !== 'oversize')) {\n return { stages, disposition: `failed(${opened.error!})` as Disposition, ...(answer.status === 'retired' ? { key: 'retired' as const } : {}) }\n }\n if (opened.error === 'malformed') { step(4, 'parse — invalid UTF-8 or not JSON', false); return { stages, disposition: 'failed(malformed)' } }\n\n // 4 — parse: a JSON object; digest over its CANONICAL form; cache\n // check. TOTAL: a document that parses but defeats the canonical\n // form (JSON.parse turns 1e400 into Infinity) is malformed here,\n // never an exception (review 2, B-2).\n const doc = (opened as { document?: Json }).document\n if (doc === null || doc === undefined || typeof doc !== 'object' || Array.isArray(doc)) { step(4, 'parse — not a JSON object', false); return { stages, disposition: 'failed(malformed)' } }\n let digest: string\n try { digest = await digestDoc(doc, S) } catch { step(4, 'parse — no canonical form (non-finite number)', false); return { stages, disposition: 'failed(malformed)' } }\n step(4, `parse + digest ${digest.slice(0, 14)}… · completed-effect cache`, true)\n if (completed?.(digest)) return { stages, disposition: 'duplicate-known', document: doc, digest }\n return { stages, disposition: 'unique', document: doc, digest }\n}\n"]}
@@ -0,0 +1,37 @@
1
+ import type { Json } from '../core.js';
2
+ import { BUNDLE_TYPE, DELIVERY_TYPE } from '../encounter.js';
3
+ import type { HolderModule } from '../engine.js';
4
+ import type { HolderState, Millis } from '../state.js';
5
+ export { BUNDLE_TYPE, DELIVERY_TYPE };
6
+ /** The command names of the human acts. */
7
+ export declare const ENCOUNTER_COMMANDS: Readonly<{
8
+ show: "encounter.show";
9
+ scan: "encounter.scan";
10
+ capture: "encounter.capture";
11
+ counter: "encounter.counter";
12
+ }>;
13
+ export interface ShowInput {
14
+ name?: string;
15
+ }
16
+ export interface ScanInput {
17
+ card: Json;
18
+ name?: string;
19
+ }
20
+ export interface CaptureInput {
21
+ card: Json;
22
+ }
23
+ export interface CounterInput {
24
+ contactId: string;
25
+ }
26
+ /** The contact and relationship ids of the tuple under an own pair label. */
27
+ export declare const idsOf: (label: string) => {
28
+ contactId: string;
29
+ relId: string;
30
+ };
31
+ /** The prompt that asks to confirm the enactment of record `own`. */
32
+ export declare const confirmPromptId: (own: string) => string;
33
+ /** The own-challenge resolution (5240): recorded, open, else unknown. */
34
+ export declare function resolve(state: Readonly<HolderState>, value: string, when: Millis): 'recorded' | 'open' | 'unknown';
35
+ /** The encounter module createHolder registers. */
36
+ export declare function encounterModule(): HolderModule;
37
+ //# sourceMappingURL=ceremony.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ceremony.d.ts","sourceRoot":"","sources":["../../src/encounter/ceremony.ts"],"names":[],"mappings":"AAoFA,OAAO,KAAK,EAAE,IAAI,EAAc,MAAM,YAAY,CAAA;AAGlD,OAAO,EACL,WAAW,EAA+C,aAAa,EAExE,MAAM,iBAAiB,CAAA;AAMxB,OAAO,KAAK,EAAgD,YAAY,EAAmD,MAAM,cAAc,CAAA;AAC/I,OAAO,KAAK,EAAmC,WAAW,EAAE,MAAM,EAAU,MAAM,aAAa,CAAA;AAI/F,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,CAAA;AAErC,2CAA2C;AAC3C,eAAO,MAAM,kBAAkB;;;;;EAK7B,CAAA;AAEF,MAAM,WAAW,SAAS;IAAG,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE;AAC5C,MAAM,WAAW,SAAS;IAAG,IAAI,EAAE,IAAI,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE;AACxD,MAAM,WAAW,YAAY;IAAG,IAAI,EAAE,IAAI,CAAA;CAAE;AAC5C,MAAM,WAAW,YAAY;IAAG,SAAS,EAAE,MAAM,CAAA;CAAE;AASnD,6EAA6E;AAC7E,eAAO,MAAM,KAAK,GAAI,OAAO,MAAM,KAAG;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAGvE,CAAA;AAED,qEAAqE;AACrE,eAAO,MAAM,eAAe,GAAI,KAAK,MAAM,KAAG,MAA4B,CAAA;AAE1E,yEAAyE;AACzE,wBAAgB,OAAO,CAAE,KAAK,EAAE,QAAQ,CAAC,WAAW,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,MAAM,GAAG,SAAS,CAInH;AAohBD,mDAAmD;AACnD,wBAAgB,eAAe,IAAK,YAAY,CAc/C"}