nervur 0.22.0 → 0.22.2-3

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 (398) hide show
  1. package/AUTHORING.md +741 -0
  2. package/KIT-SPEC.md +286 -0
  3. package/LICENSE +1 -1
  4. package/NOTICE +6 -2
  5. package/README.md +97 -424
  6. package/dist/app/app-ground.d.ts +18 -0
  7. package/dist/app/app-ground.js +25 -0
  8. package/dist/app/index.d.ts +2 -0
  9. package/dist/app/index.js +5 -0
  10. package/dist/app/native.d.ts +46 -0
  11. package/dist/app/native.js +101 -0
  12. package/dist/being/being.d.ts +229 -0
  13. package/dist/being/being.js +20 -0
  14. package/dist/being/covers.d.ts +9 -0
  15. package/dist/being/covers.js +21 -0
  16. package/dist/being/index.d.ts +3 -0
  17. package/dist/being/index.js +5 -0
  18. package/dist/being/need.d.ts +49 -0
  19. package/dist/being/need.js +33 -0
  20. package/dist/being/schema.d.ts +100 -0
  21. package/dist/being/schema.js +132 -0
  22. package/dist/being/table.d.ts +42 -0
  23. package/dist/being/table.js +288 -0
  24. package/dist/bench/bench-ground.d.ts +55 -0
  25. package/dist/bench/bench-ground.js +101 -0
  26. package/dist/bench/bench.d.ts +87 -0
  27. package/dist/bench/bench.js +260 -0
  28. package/dist/bench/fake-carry.d.ts +32 -0
  29. package/dist/bench/fake-carry.js +56 -0
  30. package/dist/bench/fake-clock.d.ts +17 -0
  31. package/dist/bench/fake-clock.js +34 -0
  32. package/dist/bench/fake-custody.d.ts +9 -0
  33. package/dist/bench/fake-custody.js +10 -0
  34. package/dist/bench/fake-faculty.d.ts +25 -0
  35. package/dist/bench/fake-faculty.js +48 -0
  36. package/dist/bench/fake-keys.d.ts +5 -0
  37. package/dist/bench/fake-keys.js +9 -0
  38. package/dist/bench/fake-memory.d.ts +14 -0
  39. package/dist/bench/fake-memory.js +46 -0
  40. package/dist/bench/fake-network.d.ts +57 -0
  41. package/dist/bench/fake-network.js +169 -0
  42. package/dist/bench/index.d.ts +11 -0
  43. package/dist/bench/index.js +13 -0
  44. package/dist/bench/seeded.d.ts +11 -0
  45. package/dist/bench/seeded.js +37 -0
  46. package/dist/bench/settle.d.ts +2 -0
  47. package/dist/bench/settle.js +49 -0
  48. package/dist/bench/stewards.d.ts +17 -0
  49. package/dist/bench/stewards.js +20 -0
  50. package/dist/bodies/class-list.d.ts +14 -0
  51. package/dist/bodies/class-list.js +33 -0
  52. package/dist/bodies/joined-carry.d.ts +23 -0
  53. package/dist/bodies/joined-carry.js +42 -0
  54. package/dist/bodies/noble-crypto.d.ts +22 -0
  55. package/dist/bodies/noble-crypto.js +88 -0
  56. package/dist/bodies/seed-keys.d.ts +10 -0
  57. package/dist/bodies/seed-keys.js +42 -0
  58. package/dist/bodies/strict-tools.d.ts +10 -0
  59. package/dist/bodies/strict-tools.js +306 -0
  60. package/dist/bodies/web-carry.d.ts +65 -0
  61. package/dist/bodies/web-carry.js +224 -0
  62. package/dist/bodies/web-clock.d.ts +12 -0
  63. package/dist/bodies/web-clock.js +33 -0
  64. package/dist/browser/browser-ground.d.ts +69 -0
  65. package/dist/browser/browser-ground.js +219 -0
  66. package/dist/browser/index.d.ts +4 -0
  67. package/dist/browser/index.js +7 -0
  68. package/dist/browser/indexeddb-memory.d.ts +17 -0
  69. package/dist/browser/indexeddb-memory.js +97 -0
  70. package/dist/browser/locked-custody.d.ts +25 -0
  71. package/dist/browser/locked-custody.js +89 -0
  72. package/dist/browser/origin-classes.d.ts +7 -0
  73. package/dist/browser/origin-classes.js +31 -0
  74. package/dist/foundation.d.ts +150 -0
  75. package/dist/foundation.js +4 -0
  76. package/dist/ground/ground.d.ts +177 -0
  77. package/dist/ground/ground.js +363 -0
  78. package/dist/house/crossing.d.ts +37 -0
  79. package/dist/house/crossing.js +131 -0
  80. package/dist/house/house.d.ts +80 -0
  81. package/dist/house/house.js +1753 -0
  82. package/dist/house/rows-shape.d.ts +103 -0
  83. package/dist/house/rows-shape.js +12 -0
  84. package/dist/house/rows.d.ts +27 -0
  85. package/dist/house/rows.js +168 -0
  86. package/dist/index.d.ts +29 -1
  87. package/dist/index.js +25 -14
  88. package/dist/node/bridge.d.ts +17 -0
  89. package/dist/node/bridge.js +188 -0
  90. package/dist/node/cli.js +170 -0
  91. package/dist/node/custody.d.ts +20 -0
  92. package/dist/node/custody.js +34 -0
  93. package/dist/node/file-keys.d.ts +7 -0
  94. package/dist/node/file-keys.js +30 -0
  95. package/dist/node/file-memory.d.ts +13 -0
  96. package/dist/node/file-memory.js +91 -0
  97. package/dist/node/folder-classes.d.ts +5 -0
  98. package/dist/node/folder-classes.js +40 -0
  99. package/dist/node/gone.d.ts +2 -0
  100. package/dist/node/gone.js +7 -0
  101. package/dist/node/hand.d.ts +29 -0
  102. package/dist/node/hand.js +85 -0
  103. package/dist/node/held-keys.d.ts +14 -0
  104. package/dist/node/held-keys.js +36 -0
  105. package/dist/node/http.d.ts +11 -0
  106. package/dist/node/http.js +90 -0
  107. package/dist/node/index.d.ts +13 -0
  108. package/dist/node/index.js +15 -0
  109. package/dist/node/keychain-keys.d.ts +10 -0
  110. package/dist/node/keychain-keys.js +51 -0
  111. package/dist/node/ledger-memory.d.ts +17 -0
  112. package/dist/node/ledger-memory.js +151 -0
  113. package/dist/node/lock.d.ts +10 -0
  114. package/dist/node/lock.js +78 -0
  115. package/dist/node/node-ground.d.ts +33 -0
  116. package/dist/node/node-ground.js +147 -0
  117. package/dist/node/notify.d.ts +1 -0
  118. package/dist/node/notify.js +18 -0
  119. package/dist/node/tcp-carry.d.ts +39 -0
  120. package/dist/node/tcp-carry.js +216 -0
  121. package/dist/node/websocket.d.ts +6 -0
  122. package/dist/node/websocket.js +118 -0
  123. package/dist/quo/frame.d.ts +20 -0
  124. package/dist/quo/frame.js +48 -0
  125. package/dist/quo/room.d.ts +154 -0
  126. package/dist/quo/room.js +362 -0
  127. package/dist/serve/index.d.ts +27 -0
  128. package/dist/serve/index.js +55 -0
  129. package/package.json +49 -47
  130. package/dist/browser.d.ts +0 -1
  131. package/dist/browser.js +0 -8
  132. package/dist/cli.js +0 -16
  133. package/dist/core/being/being.d.ts +0 -17
  134. package/dist/core/being/being.js +0 -72
  135. package/dist/core/being/digest.d.ts +0 -3
  136. package/dist/core/being/digest.js +0 -17
  137. package/dist/core/being/faculty.d.ts +0 -10
  138. package/dist/core/being/faculty.js +0 -77
  139. package/dist/core/being/index.d.ts +0 -6
  140. package/dist/core/being/index.js +0 -8
  141. package/dist/core/being/kind.d.ts +0 -6
  142. package/dist/core/being/kind.js +0 -34
  143. package/dist/core/being/types.d.ts +0 -61
  144. package/dist/core/being/types.js +0 -4
  145. package/dist/core/being/words.d.ts +0 -13
  146. package/dist/core/being/words.js +0 -14
  147. package/dist/core/browser/index.d.ts +0 -37
  148. package/dist/core/browser/index.js +0 -196
  149. package/dist/core/browser/worker.d.ts +0 -11
  150. package/dist/core/browser/worker.js +0 -37
  151. package/dist/core/cli/command.d.ts +0 -13
  152. package/dist/core/cli/command.js +0 -330
  153. package/dist/core/cli/edge.d.ts +0 -7
  154. package/dist/core/cli/edge.js +0 -79
  155. package/dist/core/cli/harbor.d.ts +0 -25
  156. package/dist/core/cli/harbor.js +0 -115
  157. package/dist/core/contract/index.d.ts +0 -42
  158. package/dist/core/contract/index.js +0 -34
  159. package/dist/core/contract/link.d.ts +0 -4
  160. package/dist/core/contract/link.js +0 -45
  161. package/dist/core/crypto/aes.d.ts +0 -3
  162. package/dist/core/crypto/aes.js +0 -24
  163. package/dist/core/crypto/bytes.d.ts +0 -6
  164. package/dist/core/crypto/bytes.js +0 -33
  165. package/dist/core/crypto/ed25519.d.ts +0 -3
  166. package/dist/core/crypto/ed25519.js +0 -93
  167. package/dist/core/crypto/hash.d.ts +0 -2
  168. package/dist/core/crypto/hash.js +0 -11
  169. package/dist/core/crypto/index.d.ts +0 -7
  170. package/dist/core/crypto/index.js +0 -10
  171. package/dist/core/crypto/json.d.ts +0 -8
  172. package/dist/core/crypto/json.js +0 -250
  173. package/dist/core/crypto/mlkem.d.ts +0 -12
  174. package/dist/core/crypto/mlkem.js +0 -36
  175. package/dist/core/crypto/subtle.d.ts +0 -3
  176. package/dist/core/crypto/subtle.js +0 -11
  177. package/dist/core/crypto/x25519.d.ts +0 -2
  178. package/dist/core/crypto/x25519.js +0 -24
  179. package/dist/core/edge/index.d.ts +0 -164
  180. package/dist/core/edge/index.js +0 -739
  181. package/dist/core/edge/kit.d.ts +0 -2
  182. package/dist/core/edge/kit.js +0 -2
  183. package/dist/core/folder/index.d.ts +0 -18
  184. package/dist/core/folder/index.js +0 -130
  185. package/dist/core/git/http.d.ts +0 -6
  186. package/dist/core/git/http.js +0 -102
  187. package/dist/core/git/index.d.ts +0 -5
  188. package/dist/core/git/index.js +0 -10
  189. package/dist/core/git/object.d.ts +0 -40
  190. package/dist/core/git/object.js +0 -103
  191. package/dist/core/git/pack.d.ts +0 -9
  192. package/dist/core/git/pack.js +0 -171
  193. package/dist/core/git/store.d.ts +0 -23
  194. package/dist/core/git/store.js +0 -120
  195. package/dist/core/git/zlib.d.ts +0 -6
  196. package/dist/core/git/zlib.js +0 -210
  197. package/dist/core/harbor/carrying.d.ts +0 -51
  198. package/dist/core/harbor/carrying.js +0 -69
  199. package/dist/core/harbor/catalogue.d.ts +0 -33
  200. package/dist/core/harbor/catalogue.js +0 -365
  201. package/dist/core/harbor/dna.d.ts +0 -13
  202. package/dist/core/harbor/dna.js +0 -120
  203. package/dist/core/harbor/dock.d.ts +0 -62
  204. package/dist/core/harbor/dock.js +0 -381
  205. package/dist/core/harbor/harbor.d.ts +0 -16
  206. package/dist/core/harbor/harbor.js +0 -438
  207. package/dist/core/harbor/index.d.ts +0 -11
  208. package/dist/core/harbor/index.js +0 -14
  209. package/dist/core/harbor/memory.d.ts +0 -10
  210. package/dist/core/harbor/memory.js +0 -25
  211. package/dist/core/harbor/package.d.ts +0 -20
  212. package/dist/core/harbor/package.js +0 -172
  213. package/dist/core/harbor/probe.d.ts +0 -22
  214. package/dist/core/harbor/probe.js +0 -15
  215. package/dist/core/harbor/registry.d.ts +0 -15
  216. package/dist/core/harbor/registry.js +0 -110
  217. package/dist/core/harbor/root-line.d.ts +0 -7
  218. package/dist/core/harbor/root-line.js +0 -9
  219. package/dist/core/harbor/terrain.d.ts +0 -25
  220. package/dist/core/harbor/terrain.js +0 -28
  221. package/dist/core/http/index.d.ts +0 -2
  222. package/dist/core/http/index.js +0 -154
  223. package/dist/core/http/websocket.d.ts +0 -29
  224. package/dist/core/http/websocket.js +0 -133
  225. package/dist/core/line/answer.d.ts +0 -8
  226. package/dist/core/line/answer.js +0 -60
  227. package/dist/core/line/frame.d.ts +0 -29
  228. package/dist/core/line/frame.js +0 -77
  229. package/dist/core/line/ground.d.ts +0 -3
  230. package/dist/core/line/ground.js +0 -7
  231. package/dist/core/line/index.d.ts +0 -4
  232. package/dist/core/line/index.js +0 -8
  233. package/dist/core/line/web.d.ts +0 -12
  234. package/dist/core/line/web.js +0 -117
  235. package/dist/core/node/index.d.ts +0 -23
  236. package/dist/core/node/index.js +0 -124
  237. package/dist/core/pointer/bodies.d.ts +0 -31
  238. package/dist/core/pointer/bodies.js +0 -118
  239. package/dist/core/pointer/index.d.ts +0 -2
  240. package/dist/core/pointer/index.js +0 -4
  241. package/dist/core/pointer/world.d.ts +0 -45
  242. package/dist/core/pointer/world.js +0 -106
  243. package/dist/core/proof/contracts.d.ts +0 -19
  244. package/dist/core/proof/contracts.js +0 -116
  245. package/dist/core/proof/expect.d.ts +0 -6
  246. package/dist/core/proof/expect.js +0 -18
  247. package/dist/core/proof/index.d.ts +0 -3
  248. package/dist/core/proof/index.js +0 -14
  249. package/dist/core/proof/law.d.ts +0 -25
  250. package/dist/core/proof/law.js +0 -715
  251. package/dist/core/quo/address.d.ts +0 -19
  252. package/dist/core/quo/address.js +0 -84
  253. package/dist/core/quo/door.d.ts +0 -34
  254. package/dist/core/quo/door.js +0 -174
  255. package/dist/core/quo/index.d.ts +0 -9
  256. package/dist/core/quo/index.js +0 -12
  257. package/dist/core/quo/invitation.d.ts +0 -8
  258. package/dist/core/quo/invitation.js +0 -19
  259. package/dist/core/quo/keys.d.ts +0 -40
  260. package/dist/core/quo/keys.js +0 -79
  261. package/dist/core/quo/payload.d.ts +0 -15
  262. package/dist/core/quo/payload.js +0 -55
  263. package/dist/core/quo/relations.d.ts +0 -40
  264. package/dist/core/quo/relations.js +0 -33
  265. package/dist/core/quo/reply.d.ts +0 -13
  266. package/dist/core/quo/reply.js +0 -35
  267. package/dist/core/quo/seal.d.ts +0 -42
  268. package/dist/core/quo/seal.js +0 -78
  269. package/dist/core/quo/standing.d.ts +0 -39
  270. package/dist/core/quo/standing.js +0 -90
  271. package/dist/core/tcp/index.d.ts +0 -27
  272. package/dist/core/tcp/index.js +0 -209
  273. package/dist/core/ward/allowance.d.ts +0 -14
  274. package/dist/core/ward/allowance.js +0 -32
  275. package/dist/core/ward/cells.d.ts +0 -7
  276. package/dist/core/ward/cells.js +0 -74
  277. package/dist/core/ward/house.d.ts +0 -67
  278. package/dist/core/ward/house.js +0 -473
  279. package/dist/core/ward/index.d.ts +0 -5
  280. package/dist/core/ward/index.js +0 -7
  281. package/dist/core/ward/partition.d.ts +0 -50
  282. package/dist/core/ward/partition.js +0 -66
  283. package/dist/core/ward/stance.d.ts +0 -29
  284. package/dist/core/ward/stance.js +0 -186
  285. package/dist/core/ward/ward.d.ts +0 -44
  286. package/dist/core/ward/ward.js +0 -140
  287. package/dist/core.d.ts +0 -10
  288. package/dist/core.js +0 -19
  289. package/dist/defaults/dock/index.d.ts +0 -4
  290. package/dist/defaults/dock/index.js +0 -11
  291. package/dist/defaults/index.d.ts +0 -5
  292. package/dist/defaults/index.js +0 -10
  293. package/dist/defaults/memory/index.d.ts +0 -12
  294. package/dist/defaults/memory/index.js +0 -39
  295. package/dist/defaults/tcp/index.d.ts +0 -16
  296. package/dist/defaults/tcp/index.js +0 -82
  297. package/dist/defaults/ward/index.d.ts +0 -4
  298. package/dist/defaults/ward/index.js +0 -11
  299. package/dist/defaults/web/index.d.ts +0 -15
  300. package/dist/defaults/web/index.js +0 -90
  301. package/dist/edge.d.ts +0 -1
  302. package/dist/edge.js +0 -9
  303. package/dist/kit.d.ts +0 -4
  304. package/dist/kit.js +0 -12
  305. package/dist/node.d.ts +0 -1
  306. package/dist/node.js +0 -8
  307. package/src/browser.ts +0 -10
  308. package/src/cli.ts +0 -15
  309. package/src/core/being/being.ts +0 -84
  310. package/src/core/being/digest.ts +0 -18
  311. package/src/core/being/faculty.ts +0 -76
  312. package/src/core/being/index.ts +0 -8
  313. package/src/core/being/kind.ts +0 -37
  314. package/src/core/being/types.ts +0 -74
  315. package/src/core/being/words.ts +0 -31
  316. package/src/core/browser/index.ts +0 -219
  317. package/src/core/browser/worker.ts +0 -63
  318. package/src/core/cli/command.ts +0 -311
  319. package/src/core/cli/edge.ts +0 -86
  320. package/src/core/cli/harbor.ts +0 -120
  321. package/src/core/contract/index.ts +0 -82
  322. package/src/core/contract/link.ts +0 -58
  323. package/src/core/crypto/aes.ts +0 -26
  324. package/src/core/crypto/bytes.ts +0 -37
  325. package/src/core/crypto/ed25519.ts +0 -92
  326. package/src/core/crypto/hash.ts +0 -14
  327. package/src/core/crypto/index.ts +0 -10
  328. package/src/core/crypto/json.ts +0 -241
  329. package/src/core/crypto/mlkem.ts +0 -38
  330. package/src/core/crypto/subtle.ts +0 -13
  331. package/src/core/crypto/x25519.ts +0 -23
  332. package/src/core/edge/index.ts +0 -865
  333. package/src/core/folder/index.ts +0 -137
  334. package/src/core/git/http.ts +0 -103
  335. package/src/core/git/index.ts +0 -10
  336. package/src/core/git/object.ts +0 -116
  337. package/src/core/git/pack.ts +0 -147
  338. package/src/core/git/store.ts +0 -122
  339. package/src/core/git/zlib.ts +0 -197
  340. package/src/core/harbor/carrying.ts +0 -124
  341. package/src/core/harbor/catalogue.ts +0 -386
  342. package/src/core/harbor/dna.ts +0 -116
  343. package/src/core/harbor/dock.ts +0 -420
  344. package/src/core/harbor/harbor.ts +0 -433
  345. package/src/core/harbor/index.ts +0 -14
  346. package/src/core/harbor/memory.ts +0 -31
  347. package/src/core/harbor/package.ts +0 -195
  348. package/src/core/harbor/probe.ts +0 -39
  349. package/src/core/harbor/registry.ts +0 -107
  350. package/src/core/harbor/root-line.ts +0 -19
  351. package/src/core/harbor/terrain.ts +0 -54
  352. package/src/core/http/index.ts +0 -147
  353. package/src/core/http/websocket.ts +0 -124
  354. package/src/core/line/answer.ts +0 -60
  355. package/src/core/line/frame.ts +0 -83
  356. package/src/core/line/ground.ts +0 -18
  357. package/src/core/line/index.ts +0 -8
  358. package/src/core/line/web.ts +0 -123
  359. package/src/core/node/index.ts +0 -139
  360. package/src/core/pointer/bodies.ts +0 -122
  361. package/src/core/pointer/index.ts +0 -4
  362. package/src/core/pointer/world.ts +0 -134
  363. package/src/core/proof/contracts.ts +0 -134
  364. package/src/core/proof/expect.ts +0 -25
  365. package/src/core/proof/index.ts +0 -14
  366. package/src/core/proof/law.ts +0 -742
  367. package/src/core/quo/address.ts +0 -87
  368. package/src/core/quo/door.ts +0 -180
  369. package/src/core/quo/index.ts +0 -12
  370. package/src/core/quo/invitation.ts +0 -19
  371. package/src/core/quo/keys.ts +0 -91
  372. package/src/core/quo/payload.ts +0 -61
  373. package/src/core/quo/relations.ts +0 -62
  374. package/src/core/quo/reply.ts +0 -38
  375. package/src/core/quo/seal.ts +0 -101
  376. package/src/core/quo/standing.ts +0 -111
  377. package/src/core/stand/main.ts +0 -20
  378. package/src/core/stand/stand.ts +0 -259
  379. package/src/core/tcp/index.ts +0 -227
  380. package/src/core/ward/allowance.ts +0 -47
  381. package/src/core/ward/cells.ts +0 -77
  382. package/src/core/ward/house.ts +0 -524
  383. package/src/core/ward/index.ts +0 -7
  384. package/src/core/ward/partition.ts +0 -117
  385. package/src/core/ward/stance.ts +0 -207
  386. package/src/core/ward/ward.ts +0 -166
  387. package/src/core.ts +0 -55
  388. package/src/defaults/dock/index.ts +0 -12
  389. package/src/defaults/index.ts +0 -10
  390. package/src/defaults/memory/index.ts +0 -50
  391. package/src/defaults/tcp/index.ts +0 -89
  392. package/src/defaults/ward/index.ts +0 -12
  393. package/src/defaults/web/index.ts +0 -97
  394. package/src/edge.ts +0 -11
  395. package/src/index.ts +0 -18
  396. package/src/kit.ts +0 -15
  397. package/src/node.ts +0 -10
  398. /package/dist/{cli.d.ts → node/cli.d.ts} +0 -0
@@ -0,0 +1,57 @@
1
+ import type { Hooked } from '../ground/ground.ts';
2
+ import type { Clock } from '../foundation.ts';
3
+ /** How one link behaves, each way: its latency in milliseconds, and the share of boxes dropped, of replies lost, and of boxes delivered twice. */
4
+ export interface Link {
5
+ readonly latency?: number;
6
+ readonly drop?: number;
7
+ readonly lose?: number;
8
+ readonly duplicate?: number;
9
+ }
10
+ /** What became of one box: dropped before its door, delivered, its reply lost, or delivered twice. */
11
+ export interface Crossing {
12
+ readonly from: string;
13
+ readonly to: string;
14
+ readonly ward: string;
15
+ readonly outcome: 'dropped' | 'answered' | 'silent' | 'lost' | 'twice';
16
+ }
17
+ export declare class FakeNetwork {
18
+ #private;
19
+ /** Every box that crossed between two hosts, in order. A box by pointer inside a host crosses nothing. */
20
+ readonly crossings: Crossing[];
21
+ /** `clock` is the bench's, and times every latency; `seed` draws every chance. */
22
+ constructor({ clock, seed }?: {
23
+ clock?: Clock;
24
+ seed?: string;
25
+ });
26
+ /** A host's carry. One that listens is dialled at its names; one that does not only dials, as a device. */
27
+ join(host: string, { names, listens }?: {
28
+ names?: readonly string[];
29
+ listens?: boolean;
30
+ }): Hooked;
31
+ /** A name pointed at a host, as a DNS record moved. */
32
+ point(name: string, host: string): void;
33
+ /** How the link between two hosts behaves, both ways, until it is set again. */
34
+ link(a: string, b: string, link: Link): void;
35
+ /** No box crosses from `from` to `to` until `heal`; the other way stands. */
36
+ cut(from: string, to: string): void;
37
+ /** No box crosses between the two hosts, either way, until `heal`. */
38
+ partition(a: string, b: string): void;
39
+ /** Every cut mended. Links keep how they behave. */
40
+ heal(): void;
41
+ /** The host answers nothing, its doors forgotten, until `up`. */
42
+ down(host: string): void;
43
+ up(host: string): void;
44
+ /** The next `count` boxes between hosts are dropped before their door. */
45
+ dropNext(count?: number): void;
46
+ /** The next `count` replies are lost after the far door answered. */
47
+ loseNext(count?: number): void;
48
+ /** The next `count` boxes are delivered twice, and the first reply returns. */
49
+ duplicateNext(count?: number): void;
50
+ /**
51
+ * The clock moved on by `ms` in steps of `step`, the bench settling after
52
+ * each, so latencies end, retries leave and replies land as time passes.
53
+ */
54
+ elapse(ms: number, { step }?: {
55
+ step?: number;
56
+ }): Promise<void>;
57
+ }
@@ -0,0 +1,169 @@
1
+ import { stream } from './seeded.js';
2
+ import { settle } from './settle.js';
3
+ const SCHEME = 'bench://';
4
+ const pair = (a, b) => [a, b].sort().join('\n');
5
+ export class FakeNetwork {
6
+ #hosts = new Map();
7
+ #names = new Map();
8
+ // One-way cuts, `from` then `to`.
9
+ #cuts = new Set();
10
+ #links = new Map();
11
+ #clock;
12
+ #chance;
13
+ #drop = 0;
14
+ #lose = 0;
15
+ #twice = 0;
16
+ #waits = 0;
17
+ /** Every box that crossed between two hosts, in order. A box by pointer inside a host crosses nothing. */
18
+ crossings = [];
19
+ /** `clock` is the bench's, and times every latency; `seed` draws every chance. */
20
+ constructor({ clock, seed = 'network' } = {}) {
21
+ this.#clock = clock;
22
+ this.#chance = stream(`network:${seed}`);
23
+ }
24
+ /** A host's carry. One that listens is dialled at its names; one that does not only dials, as a device. */
25
+ join(host, { names = [], listens = true } = {}) {
26
+ const held = this.#hosts.get(host) ?? { doors: new Map(), listens, up: true };
27
+ this.#hosts.set(host, held);
28
+ for (const name of names)
29
+ this.#names.set(name, host);
30
+ return {
31
+ listen: ({ ward, door }) => void held.doors.set(ward, door),
32
+ unlisten: ({ ward }) => void held.doors.delete(ward),
33
+ send: (options) => this.#send(host, options),
34
+ at: () => (held.listens ? [...this.#names].filter(([, to]) => to === host).map(([name]) => SCHEME + name) : []),
35
+ };
36
+ }
37
+ /** A name pointed at a host, as a DNS record moved. */
38
+ point(name, host) {
39
+ this.#names.set(name, host);
40
+ }
41
+ /** How the link between two hosts behaves, both ways, until it is set again. */
42
+ link(a, b, link) {
43
+ if (link.latency !== undefined && link.latency > 0 && this.#clock === undefined)
44
+ throw new TypeError('a network with latency is made with the bench’s clock');
45
+ for (const share of [link.drop, link.lose, link.duplicate])
46
+ if (share !== undefined && !(share >= 0 && share <= 1))
47
+ throw new TypeError('a share is between 0 and 1');
48
+ this.#links.set(pair(a, b), link);
49
+ }
50
+ /** No box crosses from `from` to `to` until `heal`; the other way stands. */
51
+ cut(from, to) {
52
+ this.#cuts.add(`${from}\n${to}`);
53
+ }
54
+ /** No box crosses between the two hosts, either way, until `heal`. */
55
+ partition(a, b) {
56
+ this.cut(a, b);
57
+ this.cut(b, a);
58
+ }
59
+ /** Every cut mended. Links keep how they behave. */
60
+ heal() {
61
+ this.#cuts.clear();
62
+ }
63
+ /** The host answers nothing, its doors forgotten, until `up`. */
64
+ down(host) {
65
+ const held = this.#hosts.get(host);
66
+ if (held === undefined)
67
+ return;
68
+ held.up = false;
69
+ held.doors.clear();
70
+ }
71
+ up(host) {
72
+ const held = this.#hosts.get(host);
73
+ if (held !== undefined)
74
+ held.up = true;
75
+ }
76
+ /** The next `count` boxes between hosts are dropped before their door. */
77
+ dropNext(count = 1) {
78
+ this.#drop += count;
79
+ }
80
+ /** The next `count` replies are lost after the far door answered. */
81
+ loseNext(count = 1) {
82
+ this.#lose += count;
83
+ }
84
+ /** The next `count` boxes are delivered twice, and the first reply returns. */
85
+ duplicateNext(count = 1) {
86
+ this.#twice += count;
87
+ }
88
+ /**
89
+ * The clock moved on by `ms` in steps of `step`, the bench settling after
90
+ * each, so latencies end, retries leave and replies land as time passes.
91
+ */
92
+ async elapse(ms, { step = 1_000 } = {}) {
93
+ const clock = this.#clock;
94
+ if (clock === undefined || !('advance' in clock) || typeof clock.advance !== 'function')
95
+ throw new TypeError('a network elapses on the bench’s clock');
96
+ const advance = clock.advance.bind(clock);
97
+ await settle();
98
+ for (let left = ms; left > 0; left -= step) {
99
+ advance(Math.min(step, left));
100
+ await settle();
101
+ }
102
+ }
103
+ // Whether a chance of `share` comes up, drawn from the seed.
104
+ #roll(share) {
105
+ if (share === undefined || share <= 0)
106
+ return false;
107
+ const [a, b] = this.#chance(2);
108
+ return (a * 256 + b) / 65_536 < share;
109
+ }
110
+ async #delay(ms) {
111
+ if (ms === undefined || ms <= 0 || this.#clock === undefined)
112
+ return;
113
+ await this.#clock.wait({ id: `network:${++this.#waits}`, ms });
114
+ }
115
+ async #send(from, { ward, at, box }) {
116
+ const own = this.#hosts.get(from);
117
+ if (own === undefined || !own.up)
118
+ return { reply: null, heard: false };
119
+ // A ward on this host takes the box by pointer, before any address, and crosses nothing.
120
+ const near = own.doors.get(ward);
121
+ if (near !== undefined) {
122
+ const reply = await near(box);
123
+ if (reply !== null)
124
+ return { reply };
125
+ }
126
+ for (const address of at) {
127
+ if (!address.startsWith(SCHEME))
128
+ continue;
129
+ const to = this.#names.get(address.slice(SCHEME.length));
130
+ const host = to === undefined ? undefined : this.#hosts.get(to);
131
+ if (to === undefined || host === undefined || !host.up || !host.listens || this.#cuts.has(`${from}\n${to}`))
132
+ continue;
133
+ const link = this.#links.get(pair(from, to)) ?? {};
134
+ const log = (outcome) => this.crossings.push({ from, to, ward, outcome });
135
+ await this.#delay(link.latency);
136
+ if (this.#drop > 0 || this.#roll(link.drop)) {
137
+ if (this.#drop > 0)
138
+ this.#drop--;
139
+ log('dropped');
140
+ continue;
141
+ }
142
+ // The door is read again after the latency: a host may have gone down, or a cut come, meanwhile.
143
+ const door = host.up && !this.#cuts.has(`${from}\n${to}`) ? host.doors.get(ward) : undefined;
144
+ if (door === undefined)
145
+ continue;
146
+ const twice = this.#twice > 0 || this.#roll(link.duplicate);
147
+ if (this.#twice > 0)
148
+ this.#twice--;
149
+ const reply = await door(box);
150
+ if (twice)
151
+ await door(box);
152
+ await this.#delay(link.latency);
153
+ // A reply lost after the door answered was heard, so no other address is tried.
154
+ if (this.#lose > 0 || this.#roll(link.lose) || this.#cuts.has(`${to}\n${from}`)) {
155
+ if (this.#lose > 0)
156
+ this.#lose--;
157
+ log('lost');
158
+ return { reply: null, heard: true };
159
+ }
160
+ if (reply === null) {
161
+ log('silent');
162
+ continue;
163
+ }
164
+ log(twice ? 'twice' : 'answered');
165
+ return { reply, via: address };
166
+ }
167
+ return { reply: null, heard: false };
168
+ }
169
+ }
@@ -0,0 +1,11 @@
1
+ export { Bench, Placed, type BenchOptions, type CheckOptions, type Finding } from './bench.ts';
2
+ export { BenchGround, Machine, type BenchGroundOptions, type HouseModule } from './bench-ground.ts';
3
+ export { FakeNetwork, type Crossing, type Link } from './fake-network.ts';
4
+ export { settle } from './settle.ts';
5
+ export { FakeFaculty, type Called } from './fake-faculty.ts';
6
+ export { FakeCarry } from './fake-carry.ts';
7
+ export { FakeCustody } from './fake-custody.ts';
8
+ export { FakeClock } from './fake-clock.ts';
9
+ export { FakeKeys } from './fake-keys.ts';
10
+ export { FakeMemory } from './fake-memory.ts';
11
+ export { covers } from '../being/covers.ts';
@@ -0,0 +1,13 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // `nervur/bench`: what a test imports to hold a class, a faculty or a body.
3
+ export { Bench, Placed } from './bench.js';
4
+ export { BenchGround, Machine } from './bench-ground.js';
5
+ export { FakeNetwork } from './fake-network.js';
6
+ export { settle } from './settle.js';
7
+ export { FakeFaculty } from './fake-faculty.js';
8
+ export { FakeCarry } from './fake-carry.js';
9
+ export { FakeCustody } from './fake-custody.js';
10
+ export { FakeClock } from './fake-clock.js';
11
+ export { FakeKeys } from './fake-keys.js';
12
+ export { FakeMemory } from './fake-memory.js';
13
+ export { covers } from '../being/covers.js';
@@ -0,0 +1,11 @@
1
+ import { NobleCrypto } from '../bodies/noble-crypto.ts';
2
+ /** A stream of bytes from a name: the same name, the same bytes. */
3
+ export declare const stream: (name: string) => (length: number) => Uint8Array;
4
+ /** Sixty-four hex digits from a name. */
5
+ export declare const seedOf: (name: string) => string;
6
+ /** The default crypto, with randomness drawn from a seed. */
7
+ export declare class SeededCrypto extends NobleCrypto {
8
+ #private;
9
+ constructor(name: string);
10
+ random(length: number): Uint8Array;
11
+ }
@@ -0,0 +1,37 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // What makes a bench run the same twice: bytes drawn from a seed, never
3
+ // from the platform. They are for tests alone and guard nothing.
4
+ import { NobleCrypto } from '../bodies/noble-crypto.js';
5
+ /** A stream of bytes from a name: the same name, the same bytes. */
6
+ export const stream = (name) => {
7
+ // FNV-1a over the name seeds xorshift32.
8
+ let state = 0x811c9dc5;
9
+ for (let at = 0; at < name.length; at++)
10
+ state = Math.imul(state ^ name.charCodeAt(at), 0x01000193) >>> 0;
11
+ if (state === 0)
12
+ state = 1;
13
+ return (length) => {
14
+ const out = new Uint8Array(length);
15
+ for (let at = 0; at < length; at++) {
16
+ state ^= state << 13;
17
+ state ^= state >>> 17;
18
+ state ^= state << 5;
19
+ state >>>= 0;
20
+ out[at] = state & 0xff;
21
+ }
22
+ return out;
23
+ };
24
+ };
25
+ /** Sixty-four hex digits from a name. */
26
+ export const seedOf = (name) => Array.from(stream(`seed:${name}`)(32), (byte) => byte.toString(16).padStart(2, '0')).join('');
27
+ /** The default crypto, with randomness drawn from a seed. */
28
+ export class SeededCrypto extends NobleCrypto {
29
+ #draw;
30
+ constructor(name) {
31
+ super();
32
+ this.#draw = stream(`random:${name}`);
33
+ }
34
+ random(length) {
35
+ return this.#draw(length);
36
+ }
37
+ }
@@ -0,0 +1,2 @@
1
+ /** Every ask, effect and reply the fakes started, run to where it waits on the clock or ends. */
2
+ export declare const settle: () => Promise<void>;
@@ -0,0 +1,49 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Letting the bench go idle. The fakes do no I/O, so every ask, effect and
3
+ // reply they started runs on the event loop, and the one thing that leaves
4
+ // it is WebCrypto, which runs on the engine's own threads and outlasts any
5
+ // count of turns on a loaded machine. So the bench counts WebCrypto calls
6
+ // in flight, at `crypto.subtle` itself, the one door every body's crypto
7
+ // passes, and calls the loop idle only once none has been in flight for a
8
+ // run of turns. It counts in the process that imports the bench alone.
9
+ // Turns with nothing in flight before the bench calls the loop idle: the
10
+ // promise chains between two crypto calls resolve well within them.
11
+ const QUIET = 20;
12
+ // A loop that never goes idle is a fault the bench names, never a hang.
13
+ const BOUND = 200_000;
14
+ let inFlight = 0;
15
+ const METHODS = ['digest', 'importKey', 'exportKey', 'deriveBits', 'deriveKey', 'encrypt', 'decrypt', 'sign', 'verify', 'generateKey', 'wrapKey', 'unwrapKey'];
16
+ // Each method of the engine's `subtle`, counted while its promise is open. Wrapped once, however often the bench loads.
17
+ const subtle = globalThis.crypto?.subtle;
18
+ const COUNTED = Symbol.for('nervur.bench.counted');
19
+ if (subtle !== undefined && subtle[COUNTED] !== true) {
20
+ for (const method of METHODS) {
21
+ const original = subtle[method];
22
+ if (typeof original !== 'function')
23
+ continue;
24
+ subtle[method] = (...args) => {
25
+ inFlight++;
26
+ const done = () => {
27
+ inFlight--;
28
+ };
29
+ const called = original.apply(globalThis.crypto.subtle, args);
30
+ void called.then(done, done);
31
+ return called;
32
+ };
33
+ }
34
+ subtle[COUNTED] = true;
35
+ }
36
+ // One turn of the event loop: an immediate where the engine has one, else the shortest timer.
37
+ const turnOnce = typeof globalThis.setImmediate === 'function'
38
+ ? (next) => globalThis.setImmediate(next)
39
+ : (next) => setTimeout(next, 0);
40
+ /** Every ask, effect and reply the fakes started, run to where it waits on the clock or ends. */
41
+ export const settle = async () => {
42
+ let quiet = 0;
43
+ for (let turn = 0; quiet < QUIET; turn++) {
44
+ if (turn >= BOUND)
45
+ throw new Error('the bench never went idle: crypto stayed in flight');
46
+ await new Promise((next) => turnOnce(next));
47
+ quiet = inFlight === 0 ? quiet + 1 : 0;
48
+ }
49
+ };
@@ -0,0 +1,17 @@
1
+ import { type Args } from '../being/index.ts';
2
+ declare const BenchSteward_base: import("../being/being.ts").BeingClass<Record<string, never>, Record<never, never>, {}>;
3
+ export declare class BenchSteward extends BenchSteward_base {
4
+ }
5
+ declare const BenchTester_base: import("../being/being.ts").BeingClass<Record<string, never>, Record<never, never>, {
6
+ readonly adopt: {
7
+ readonly for: "root";
8
+ readonly args: import("../being/schema.ts").Schema<{
9
+ invitation: import("../being/schema.ts").HandleMark;
10
+ }>;
11
+ readonly result: import("../being/schema.ts").Schema<string>;
12
+ };
13
+ }>;
14
+ export declare class BenchTester extends BenchTester_base {
15
+ adopt({ invitation }: Args<BenchTester, 'adopt'>): string;
16
+ }
17
+ export {};
@@ -0,0 +1,20 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // The two stewards the bench stands on: one keeps the author's house where
3
+ // the test brings no steward of its own, the other adopts a handle to each
4
+ // being the bench places, in the bench's own house.
5
+ import { Being, s } from '../being/index.js';
6
+ export class BenchSteward extends Being.of({
7
+ kind: 'org.nervur.bench.steward',
8
+ asks: {},
9
+ }) {
10
+ }
11
+ export class BenchTester extends Being.of({
12
+ kind: 'org.nervur.bench.tester',
13
+ asks: {
14
+ adopt: { for: 'root', args: s.object({ invitation: s.handle() }), result: s.string() },
15
+ },
16
+ }) {
17
+ adopt({ invitation }) {
18
+ return invitation;
19
+ }
20
+ }
@@ -0,0 +1,14 @@
1
+ import type { BeingClass, Classes } from '../foundation.ts';
2
+ export declare class ClassList implements Classes {
3
+ #private;
4
+ constructor({ steward, public: open, beings }: {
5
+ steward: BeingClass;
6
+ public?: BeingClass;
7
+ beings?: readonly BeingClass[];
8
+ });
9
+ resolve({ kind }: {
10
+ kind: string;
11
+ }): Promise<BeingClass | undefined>;
12
+ steward(): string;
13
+ public(): string | undefined;
14
+ }
@@ -0,0 +1,33 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Classes from a plain list, each kind from the one class that declares it.
3
+ import { declarationOf } from '../being/being.js';
4
+ export class ClassList {
5
+ #kinds = new Map();
6
+ #steward;
7
+ #public;
8
+ constructor({ steward, public: open, beings = [] }) {
9
+ const kindOf = (Class) => {
10
+ const kind = declarationOf(Class)?.kind;
11
+ if (typeof kind !== 'string')
12
+ throw new TypeError('a class in the list is not a class of Being.of');
13
+ const held = this.#kinds.get(kind);
14
+ if (held !== undefined && held !== Class)
15
+ throw new TypeError(`two classes claim the kind ${kind}`);
16
+ this.#kinds.set(kind, Class);
17
+ return kind;
18
+ };
19
+ this.#steward = kindOf(steward);
20
+ this.#public = open === undefined ? undefined : kindOf(open);
21
+ for (const Class of beings)
22
+ kindOf(Class);
23
+ }
24
+ async resolve({ kind }) {
25
+ return this.#kinds.get(kind);
26
+ }
27
+ steward() {
28
+ return this.#steward;
29
+ }
30
+ public() {
31
+ return this.#public;
32
+ }
33
+ }
@@ -0,0 +1,23 @@
1
+ import type { Carry, Sent } from '../foundation.ts';
2
+ export declare class JoinedCarry implements Carry {
3
+ #private;
4
+ /** `carries` by scheme: `{ tcp: tcpCarry, https: webCarry }`. */
5
+ constructor(carries: Readonly<Record<string, Carry>>);
6
+ /** A ward's door, hooked to every carry here that listens. */
7
+ listen(options: {
8
+ ward: string;
9
+ door: (box: Uint8Array) => Promise<Uint8Array | null>;
10
+ }): Promise<void>;
11
+ /** A ward unhooked from every carry here that listens. */
12
+ unlisten(options: {
13
+ ward: string;
14
+ }): void;
15
+ send({ ward, at, box }: {
16
+ ward: string;
17
+ at: readonly string[];
18
+ box: Uint8Array;
19
+ }): Promise<Sent>;
20
+ at(options?: {
21
+ toward?: string;
22
+ }): readonly string[];
23
+ }
@@ -0,0 +1,42 @@
1
+ export class JoinedCarry {
2
+ #carries;
3
+ // Each carry once, where one serves two schemes, as the web serves http and https.
4
+ #each;
5
+ /** `carries` by scheme: `{ tcp: tcpCarry, https: webCarry }`. */
6
+ constructor(carries) {
7
+ this.#carries = new Map(Object.entries(carries));
8
+ this.#each = [...new Set(this.#carries.values())];
9
+ }
10
+ /** A ward's door, hooked to every carry here that listens. */
11
+ async listen(options) {
12
+ for (const carry of this.#each)
13
+ await carry.listen?.(options);
14
+ }
15
+ /** A ward unhooked from every carry here that listens. */
16
+ unlisten(options) {
17
+ for (const carry of this.#each)
18
+ carry.unlisten?.(options);
19
+ }
20
+ async send({ ward, at, box }) {
21
+ // A carry that listens for the ward hands it the box by pointer, and no address is dialled.
22
+ for (const carry of this.#each) {
23
+ const sent = await carry.send({ ward, at: [], box });
24
+ if (sent.reply !== null)
25
+ return sent;
26
+ }
27
+ for (const address of at) {
28
+ // A scheme is read in any case, as a URI's is.
29
+ const scheme = address.slice(0, Math.max(0, address.indexOf('://'))).toLowerCase();
30
+ const carry = this.#carries.get(scheme);
31
+ if (carry === undefined)
32
+ continue;
33
+ const sent = await carry.send({ ward, at: [address], box });
34
+ if (sent.reply !== null || sent.heard)
35
+ return sent;
36
+ }
37
+ return { reply: null, heard: false };
38
+ }
39
+ at(options = {}) {
40
+ return this.#each.flatMap((carry) => carry.at(options));
41
+ }
42
+ }
@@ -0,0 +1,22 @@
1
+ import type { Crypto } from '../foundation.ts';
2
+ export declare class NobleCrypto implements Crypto {
3
+ random(length: number): Uint8Array;
4
+ sha256(data: Uint8Array): Promise<Uint8Array>;
5
+ hkdf(ikm: Uint8Array, info: string, length: number): Promise<Uint8Array>;
6
+ seal(key: Uint8Array, nonce: Uint8Array, plaintext: Uint8Array, additional: Uint8Array): Promise<Uint8Array>;
7
+ open(key: Uint8Array, nonce: Uint8Array, ciphertext: Uint8Array, additional: Uint8Array): Promise<Uint8Array | null>;
8
+ signingPublic(secret: Uint8Array): Promise<Uint8Array>;
9
+ sign(secret: Uint8Array, message: Uint8Array): Promise<Uint8Array>;
10
+ verify(pk: Uint8Array, message: Uint8Array, signature: Uint8Array): Promise<boolean>;
11
+ agreePublic(secret: Uint8Array): Promise<Uint8Array>;
12
+ agree(secret: Uint8Array, pk: Uint8Array): Promise<Uint8Array | null>;
13
+ lockPair(seed: Uint8Array): Promise<{
14
+ encapsulation: Uint8Array;
15
+ decapsulation: Uint8Array;
16
+ }>;
17
+ encapsulate(encapsulation: Uint8Array): Promise<{
18
+ ciphertext: Uint8Array;
19
+ shared: Uint8Array;
20
+ } | null>;
21
+ decapsulate(decapsulation: Uint8Array, ciphertext: Uint8Array): Promise<Uint8Array>;
22
+ }
@@ -0,0 +1,88 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // The default crypto: Ed25519, X25519 and ML-KEM-768 from noble, SHA-256,
3
+ // HKDF and AES-GCM from Web Crypto.
4
+ import { ed25519, x25519 } from '@noble/curves/ed25519.js';
5
+ import { ml_kem768 } from '@noble/post-quantum/ml-kem.js';
6
+ const subtle = globalThis.crypto.subtle;
7
+ const ascii = new TextEncoder();
8
+ const view = (bytes) => new Uint8Array(bytes);
9
+ export class NobleCrypto {
10
+ random(length) {
11
+ const out = new Uint8Array(length);
12
+ for (let at = 0; at < length; at += 65_536)
13
+ globalThis.crypto.getRandomValues(out.subarray(at, Math.min(length, at + 65_536)));
14
+ return out;
15
+ }
16
+ async sha256(data) {
17
+ return new Uint8Array(await subtle.digest('SHA-256', view(data)));
18
+ }
19
+ async hkdf(ikm, info, length) {
20
+ const key = await subtle.importKey('raw', view(ikm), 'HKDF', false, ['deriveBits']);
21
+ const bits = await subtle.deriveBits({ name: 'HKDF', hash: 'SHA-256', salt: new Uint8Array(0), info: ascii.encode(info) }, key, length * 8);
22
+ return new Uint8Array(bits);
23
+ }
24
+ async seal(key, nonce, plaintext, additional) {
25
+ const aes = await subtle.importKey('raw', view(key), 'AES-GCM', false, ['encrypt']);
26
+ return new Uint8Array(await subtle.encrypt({ name: 'AES-GCM', iv: view(nonce), additionalData: view(additional) }, aes, view(plaintext)));
27
+ }
28
+ async open(key, nonce, ciphertext, additional) {
29
+ if (ciphertext.length < 16)
30
+ return null;
31
+ const aes = await subtle.importKey('raw', view(key), 'AES-GCM', false, ['decrypt']);
32
+ try {
33
+ return new Uint8Array(await subtle.decrypt({ name: 'AES-GCM', iv: view(nonce), additionalData: view(additional) }, aes, view(ciphertext)));
34
+ }
35
+ catch {
36
+ return null;
37
+ }
38
+ }
39
+ async signingPublic(secret) {
40
+ return ed25519.getPublicKey(secret);
41
+ }
42
+ async sign(secret, message) {
43
+ return ed25519.sign(message, secret);
44
+ }
45
+ async verify(pk, message, signature) {
46
+ if (pk.length !== 32 || signature.length !== 64)
47
+ return false;
48
+ try {
49
+ // Strict decoding refuses a y at or above the prime and a non-canonical R.
50
+ if (ed25519.Point.fromBytes(pk, false).isSmallOrder())
51
+ return false;
52
+ return ed25519.verify(signature, message, pk, { zip215: false });
53
+ }
54
+ catch {
55
+ return false;
56
+ }
57
+ }
58
+ async agreePublic(secret) {
59
+ return x25519.getPublicKey(secret);
60
+ }
61
+ async agree(secret, pk) {
62
+ if (pk.length !== 32)
63
+ return null;
64
+ try {
65
+ const shared = x25519.getSharedSecret(secret, pk);
66
+ return shared.every((byte) => byte === 0) ? null : shared;
67
+ }
68
+ catch {
69
+ return null;
70
+ }
71
+ }
72
+ async lockPair(seed) {
73
+ const { publicKey, secretKey } = ml_kem768.keygen(seed);
74
+ return { encapsulation: publicKey, decapsulation: secretKey };
75
+ }
76
+ async encapsulate(encapsulation) {
77
+ try {
78
+ const { cipherText, sharedSecret } = ml_kem768.encapsulate(encapsulation);
79
+ return { ciphertext: cipherText, shared: sharedSecret };
80
+ }
81
+ catch {
82
+ return null;
83
+ }
84
+ }
85
+ async decapsulate(decapsulation, ciphertext) {
86
+ return ml_kem768.decapsulate(ciphertext, decapsulation);
87
+ }
88
+ }
@@ -0,0 +1,10 @@
1
+ import type { Crypto, Keys, WardKeys } from '../foundation.ts';
2
+ export declare class SeedKeys implements Keys {
3
+ #private;
4
+ constructor(seed: string | undefined, crypto?: Crypto);
5
+ ward(): Promise<WardKeys>;
6
+ sign(message: Uint8Array): Promise<Uint8Array>;
7
+ agree(pk: Uint8Array): Promise<Uint8Array | null>;
8
+ decapsulate(ciphertext: Uint8Array): Promise<Uint8Array>;
9
+ derive(label: string, length: number): Promise<Uint8Array>;
10
+ }