@did-btcr2/method 0.26.0 → 0.27.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 (282) hide show
  1. package/README.md +86 -233
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/browser.js +24111 -20342
  4. package/dist/browser.mjs +24111 -20342
  5. package/dist/cjs/index.js +2463 -2174
  6. package/dist/esm/core/aggregation/cohort.js +178 -0
  7. package/dist/esm/core/aggregation/cohort.js.map +1 -0
  8. package/dist/esm/core/aggregation/errors.js +22 -0
  9. package/dist/esm/core/aggregation/errors.js.map +1 -0
  10. package/dist/esm/core/{beacon/aggregation/cohort → aggregation}/messages/base.js +0 -1
  11. package/dist/esm/core/aggregation/messages/base.js.map +1 -0
  12. package/dist/esm/core/aggregation/messages/constants.js +26 -0
  13. package/dist/esm/core/aggregation/messages/constants.js.map +1 -0
  14. package/dist/esm/core/aggregation/messages/factories.js +113 -0
  15. package/dist/esm/core/aggregation/messages/factories.js.map +1 -0
  16. package/dist/esm/core/aggregation/messages/guards.js +37 -0
  17. package/dist/esm/core/aggregation/messages/guards.js.map +1 -0
  18. package/dist/esm/core/aggregation/messages/index.js +5 -0
  19. package/dist/esm/core/aggregation/messages/index.js.map +1 -0
  20. package/dist/esm/core/aggregation/participant.js +376 -0
  21. package/dist/esm/core/aggregation/participant.js.map +1 -0
  22. package/dist/esm/core/aggregation/phases.js +39 -0
  23. package/dist/esm/core/aggregation/phases.js.map +1 -0
  24. package/dist/esm/core/aggregation/runner/events.js +2 -0
  25. package/dist/esm/core/aggregation/runner/events.js.map +1 -0
  26. package/dist/esm/core/aggregation/runner/index.js +5 -0
  27. package/dist/esm/core/aggregation/runner/index.js.map +1 -0
  28. package/dist/esm/core/aggregation/runner/participant-runner.js +282 -0
  29. package/dist/esm/core/aggregation/runner/participant-runner.js.map +1 -0
  30. package/dist/esm/core/aggregation/runner/service-runner.js +290 -0
  31. package/dist/esm/core/aggregation/runner/service-runner.js.map +1 -0
  32. package/dist/esm/core/aggregation/runner/typed-emitter.js +80 -0
  33. package/dist/esm/core/aggregation/runner/typed-emitter.js.map +1 -0
  34. package/dist/esm/core/aggregation/service.js +416 -0
  35. package/dist/esm/core/aggregation/service.js.map +1 -0
  36. package/dist/esm/core/aggregation/signing-session.js +133 -0
  37. package/dist/esm/core/aggregation/signing-session.js.map +1 -0
  38. package/dist/esm/core/aggregation/transport/didcomm.js +32 -0
  39. package/dist/esm/core/aggregation/transport/didcomm.js.map +1 -0
  40. package/dist/esm/core/aggregation/transport/error.js +12 -0
  41. package/dist/esm/core/aggregation/transport/error.js.map +1 -0
  42. package/dist/esm/core/aggregation/transport/factory.js +20 -0
  43. package/dist/esm/core/aggregation/transport/factory.js.map +1 -0
  44. package/dist/esm/core/aggregation/transport/index.js +6 -0
  45. package/dist/esm/core/aggregation/transport/index.js.map +1 -0
  46. package/dist/esm/core/aggregation/transport/nostr.js +262 -0
  47. package/dist/esm/core/aggregation/transport/nostr.js.map +1 -0
  48. package/dist/esm/core/aggregation/transport/transport.js +2 -0
  49. package/dist/esm/core/aggregation/transport/transport.js.map +1 -0
  50. package/dist/esm/core/beacon/beacon.js +80 -0
  51. package/dist/esm/core/beacon/beacon.js.map +1 -1
  52. package/dist/esm/core/beacon/cas-beacon.js +15 -56
  53. package/dist/esm/core/beacon/cas-beacon.js.map +1 -1
  54. package/dist/esm/core/beacon/error.js +0 -10
  55. package/dist/esm/core/beacon/error.js.map +1 -1
  56. package/dist/esm/core/beacon/fee-estimator.js +30 -0
  57. package/dist/esm/core/beacon/fee-estimator.js.map +1 -0
  58. package/dist/esm/core/beacon/singleton-beacon.js +10 -53
  59. package/dist/esm/core/beacon/singleton-beacon.js.map +1 -1
  60. package/dist/esm/core/beacon/smt-beacon.js +85 -9
  61. package/dist/esm/core/beacon/smt-beacon.js.map +1 -1
  62. package/dist/esm/core/identifier.js +13 -0
  63. package/dist/esm/core/identifier.js.map +1 -1
  64. package/dist/esm/core/resolver.js +9 -0
  65. package/dist/esm/core/resolver.js.map +1 -1
  66. package/dist/esm/index.js +14 -24
  67. package/dist/esm/index.js.map +1 -1
  68. package/dist/types/core/aggregation/cohort.d.ts +94 -0
  69. package/dist/types/core/aggregation/cohort.d.ts.map +1 -0
  70. package/dist/types/core/aggregation/errors.d.ts +14 -0
  71. package/dist/types/core/aggregation/errors.d.ts.map +1 -0
  72. package/dist/types/core/{beacon/aggregation/cohort → aggregation}/messages/base.d.ts +7 -1
  73. package/dist/types/core/aggregation/messages/base.d.ts.map +1 -0
  74. package/dist/types/core/aggregation/messages/constants.d.ts +23 -0
  75. package/dist/types/core/aggregation/messages/constants.d.ts.map +1 -0
  76. package/dist/types/core/aggregation/messages/factories.d.ts +177 -0
  77. package/dist/types/core/aggregation/messages/factories.d.ts.map +1 -0
  78. package/dist/types/core/aggregation/messages/guards.d.ts +11 -0
  79. package/dist/types/core/aggregation/messages/guards.d.ts.map +1 -0
  80. package/dist/types/core/aggregation/messages/index.d.ts +5 -0
  81. package/dist/types/core/aggregation/messages/index.d.ts.map +1 -0
  82. package/dist/types/core/aggregation/participant.d.ts +101 -0
  83. package/dist/types/core/aggregation/participant.d.ts.map +1 -0
  84. package/dist/types/core/aggregation/phases.d.ts +49 -0
  85. package/dist/types/core/aggregation/phases.d.ts.map +1 -0
  86. package/dist/types/core/aggregation/runner/events.d.ts +89 -0
  87. package/dist/types/core/aggregation/runner/events.d.ts.map +1 -0
  88. package/dist/types/core/aggregation/runner/index.d.ts +5 -0
  89. package/dist/types/core/aggregation/runner/index.d.ts.map +1 -0
  90. package/dist/types/core/aggregation/runner/participant-runner.d.ts +107 -0
  91. package/dist/types/core/aggregation/runner/participant-runner.d.ts.map +1 -0
  92. package/dist/types/core/aggregation/runner/service-runner.d.ts +102 -0
  93. package/dist/types/core/aggregation/runner/service-runner.d.ts.map +1 -0
  94. package/dist/types/core/aggregation/runner/typed-emitter.d.ts +41 -0
  95. package/dist/types/core/aggregation/runner/typed-emitter.d.ts.map +1 -0
  96. package/dist/types/core/aggregation/service.d.ts +112 -0
  97. package/dist/types/core/aggregation/service.d.ts.map +1 -0
  98. package/dist/types/core/aggregation/signing-session.d.ts +69 -0
  99. package/dist/types/core/aggregation/signing-session.d.ts.map +1 -0
  100. package/dist/types/core/aggregation/transport/didcomm.d.ts +20 -0
  101. package/dist/types/core/aggregation/transport/didcomm.d.ts.map +1 -0
  102. package/dist/types/core/{beacon/aggregation/communication → aggregation/transport}/error.d.ts +2 -2
  103. package/dist/types/core/aggregation/transport/error.d.ts.map +1 -0
  104. package/dist/types/core/aggregation/transport/factory.d.ts +13 -0
  105. package/dist/types/core/aggregation/transport/factory.d.ts.map +1 -0
  106. package/dist/types/core/aggregation/transport/index.d.ts +6 -0
  107. package/dist/types/core/aggregation/transport/index.d.ts.map +1 -0
  108. package/dist/types/core/aggregation/transport/nostr.d.ts +55 -0
  109. package/dist/types/core/aggregation/transport/nostr.d.ts.map +1 -0
  110. package/dist/types/core/aggregation/transport/transport.d.ts +37 -0
  111. package/dist/types/core/aggregation/transport/transport.d.ts.map +1 -0
  112. package/dist/types/core/beacon/beacon.d.ts +37 -2
  113. package/dist/types/core/beacon/beacon.d.ts.map +1 -1
  114. package/dist/types/core/beacon/cas-beacon.d.ts +19 -7
  115. package/dist/types/core/beacon/cas-beacon.d.ts.map +1 -1
  116. package/dist/types/core/beacon/error.d.ts +0 -6
  117. package/dist/types/core/beacon/error.d.ts.map +1 -1
  118. package/dist/types/core/beacon/fee-estimator.d.ts +40 -0
  119. package/dist/types/core/beacon/fee-estimator.d.ts.map +1 -0
  120. package/dist/types/core/beacon/interfaces.d.ts +8 -0
  121. package/dist/types/core/beacon/interfaces.d.ts.map +1 -1
  122. package/dist/types/core/beacon/singleton-beacon.d.ts +9 -2
  123. package/dist/types/core/beacon/singleton-beacon.d.ts.map +1 -1
  124. package/dist/types/core/beacon/smt-beacon.d.ts +27 -7
  125. package/dist/types/core/beacon/smt-beacon.d.ts.map +1 -1
  126. package/dist/types/core/identifier.d.ts +8 -0
  127. package/dist/types/core/identifier.d.ts.map +1 -1
  128. package/dist/types/core/interfaces.d.ts +2 -2
  129. package/dist/types/core/resolver.d.ts +11 -1
  130. package/dist/types/core/resolver.d.ts.map +1 -1
  131. package/dist/types/index.d.ts +9 -24
  132. package/dist/types/index.d.ts.map +1 -1
  133. package/package.json +31 -30
  134. package/src/core/aggregation/cohort.ts +247 -0
  135. package/src/core/aggregation/errors.ts +25 -0
  136. package/src/core/{beacon/aggregation/cohort → aggregation}/messages/base.ts +8 -3
  137. package/src/core/aggregation/messages/constants.ts +28 -0
  138. package/src/core/aggregation/messages/factories.ts +240 -0
  139. package/src/core/aggregation/messages/guards.ts +55 -0
  140. package/src/core/aggregation/messages/index.ts +4 -0
  141. package/src/core/aggregation/participant.ts +510 -0
  142. package/src/core/aggregation/phases.ts +82 -0
  143. package/src/core/aggregation/runner/events.ts +77 -0
  144. package/src/core/aggregation/runner/index.ts +4 -0
  145. package/src/core/aggregation/runner/participant-runner.ts +360 -0
  146. package/src/core/aggregation/runner/service-runner.ts +365 -0
  147. package/src/core/aggregation/runner/typed-emitter.ts +87 -0
  148. package/src/core/aggregation/service.ts +547 -0
  149. package/src/core/aggregation/signing-session.ts +209 -0
  150. package/src/core/aggregation/transport/didcomm.ts +42 -0
  151. package/src/core/aggregation/transport/error.ts +13 -0
  152. package/src/core/aggregation/transport/factory.ts +29 -0
  153. package/src/core/aggregation/transport/index.ts +5 -0
  154. package/src/core/aggregation/transport/nostr.ts +333 -0
  155. package/src/core/aggregation/transport/transport.ts +46 -0
  156. package/src/core/beacon/beacon.ts +122 -2
  157. package/src/core/beacon/cas-beacon.ts +28 -76
  158. package/src/core/beacon/error.ts +0 -12
  159. package/src/core/beacon/fee-estimator.ts +52 -0
  160. package/src/core/beacon/interfaces.ts +10 -1
  161. package/src/core/beacon/singleton-beacon.ts +14 -75
  162. package/src/core/beacon/smt-beacon.ts +109 -11
  163. package/src/core/identifier.ts +17 -0
  164. package/src/core/interfaces.ts +2 -2
  165. package/src/core/resolver.ts +25 -2
  166. package/src/index.ts +15 -29
  167. package/dist/esm/core/beacon/aggregation/cohort/index.js +0 -237
  168. package/dist/esm/core/beacon/aggregation/cohort/index.js.map +0 -1
  169. package/dist/esm/core/beacon/aggregation/cohort/messages/base.js.map +0 -1
  170. package/dist/esm/core/beacon/aggregation/cohort/messages/constants.js +0 -11
  171. package/dist/esm/core/beacon/aggregation/cohort/messages/constants.js.map +0 -1
  172. package/dist/esm/core/beacon/aggregation/cohort/messages/index.js +0 -98
  173. package/dist/esm/core/beacon/aggregation/cohort/messages/index.js.map +0 -1
  174. package/dist/esm/core/beacon/aggregation/cohort/messages/keygen/cohort-advert.js +0 -31
  175. package/dist/esm/core/beacon/aggregation/cohort/messages/keygen/cohort-advert.js.map +0 -1
  176. package/dist/esm/core/beacon/aggregation/cohort/messages/keygen/cohort-ready.js +0 -29
  177. package/dist/esm/core/beacon/aggregation/cohort/messages/keygen/cohort-ready.js.map +0 -1
  178. package/dist/esm/core/beacon/aggregation/cohort/messages/keygen/opt-in-accept.js +0 -27
  179. package/dist/esm/core/beacon/aggregation/cohort/messages/keygen/opt-in-accept.js.map +0 -1
  180. package/dist/esm/core/beacon/aggregation/cohort/messages/keygen/opt-in.js +0 -23
  181. package/dist/esm/core/beacon/aggregation/cohort/messages/keygen/opt-in.js.map +0 -1
  182. package/dist/esm/core/beacon/aggregation/cohort/messages/keygen/subscribe.js +0 -28
  183. package/dist/esm/core/beacon/aggregation/cohort/messages/keygen/subscribe.js.map +0 -1
  184. package/dist/esm/core/beacon/aggregation/cohort/messages/sign/aggregated-nonce.js +0 -29
  185. package/dist/esm/core/beacon/aggregation/cohort/messages/sign/aggregated-nonce.js.map +0 -1
  186. package/dist/esm/core/beacon/aggregation/cohort/messages/sign/authorization-request.js +0 -30
  187. package/dist/esm/core/beacon/aggregation/cohort/messages/sign/authorization-request.js.map +0 -1
  188. package/dist/esm/core/beacon/aggregation/cohort/messages/sign/nonce-contribution.js +0 -30
  189. package/dist/esm/core/beacon/aggregation/cohort/messages/sign/nonce-contribution.js.map +0 -1
  190. package/dist/esm/core/beacon/aggregation/cohort/messages/sign/request-signature.js +0 -30
  191. package/dist/esm/core/beacon/aggregation/cohort/messages/sign/request-signature.js.map +0 -1
  192. package/dist/esm/core/beacon/aggregation/cohort/messages/sign/signature-authorization.js +0 -31
  193. package/dist/esm/core/beacon/aggregation/cohort/messages/sign/signature-authorization.js.map +0 -1
  194. package/dist/esm/core/beacon/aggregation/cohort/status.js +0 -8
  195. package/dist/esm/core/beacon/aggregation/cohort/status.js.map +0 -1
  196. package/dist/esm/core/beacon/aggregation/communication/adapter/did-comm.js +0 -121
  197. package/dist/esm/core/beacon/aggregation/communication/adapter/did-comm.js.map +0 -1
  198. package/dist/esm/core/beacon/aggregation/communication/adapter/nostr.js +0 -245
  199. package/dist/esm/core/beacon/aggregation/communication/adapter/nostr.js.map +0 -1
  200. package/dist/esm/core/beacon/aggregation/communication/error.js +0 -12
  201. package/dist/esm/core/beacon/aggregation/communication/error.js.map +0 -1
  202. package/dist/esm/core/beacon/aggregation/communication/factory.js +0 -21
  203. package/dist/esm/core/beacon/aggregation/communication/factory.js.map +0 -1
  204. package/dist/esm/core/beacon/aggregation/communication/service.js +0 -2
  205. package/dist/esm/core/beacon/aggregation/communication/service.js.map +0 -1
  206. package/dist/esm/core/beacon/aggregation/coordinator.js +0 -343
  207. package/dist/esm/core/beacon/aggregation/coordinator.js.map +0 -1
  208. package/dist/esm/core/beacon/aggregation/participant.js +0 -435
  209. package/dist/esm/core/beacon/aggregation/participant.js.map +0 -1
  210. package/dist/esm/core/beacon/aggregation/session/index.js +0 -244
  211. package/dist/esm/core/beacon/aggregation/session/index.js.map +0 -1
  212. package/dist/esm/core/beacon/aggregation/session/status.js +0 -11
  213. package/dist/esm/core/beacon/aggregation/session/status.js.map +0 -1
  214. package/dist/types/core/beacon/aggregation/cohort/index.d.ts +0 -136
  215. package/dist/types/core/beacon/aggregation/cohort/index.d.ts.map +0 -1
  216. package/dist/types/core/beacon/aggregation/cohort/messages/base.d.ts.map +0 -1
  217. package/dist/types/core/beacon/aggregation/cohort/messages/constants.d.ts +0 -11
  218. package/dist/types/core/beacon/aggregation/cohort/messages/constants.d.ts.map +0 -1
  219. package/dist/types/core/beacon/aggregation/cohort/messages/index.d.ts +0 -65
  220. package/dist/types/core/beacon/aggregation/cohort/messages/index.d.ts.map +0 -1
  221. package/dist/types/core/beacon/aggregation/cohort/messages/keygen/cohort-advert.d.ts +0 -29
  222. package/dist/types/core/beacon/aggregation/cohort/messages/keygen/cohort-advert.d.ts.map +0 -1
  223. package/dist/types/core/beacon/aggregation/cohort/messages/keygen/cohort-ready.d.ts +0 -26
  224. package/dist/types/core/beacon/aggregation/cohort/messages/keygen/cohort-ready.d.ts.map +0 -1
  225. package/dist/types/core/beacon/aggregation/cohort/messages/keygen/opt-in-accept.d.ts +0 -24
  226. package/dist/types/core/beacon/aggregation/cohort/messages/keygen/opt-in-accept.d.ts.map +0 -1
  227. package/dist/types/core/beacon/aggregation/cohort/messages/keygen/opt-in.d.ts +0 -20
  228. package/dist/types/core/beacon/aggregation/cohort/messages/keygen/opt-in.d.ts.map +0 -1
  229. package/dist/types/core/beacon/aggregation/cohort/messages/keygen/subscribe.d.ts +0 -25
  230. package/dist/types/core/beacon/aggregation/cohort/messages/keygen/subscribe.d.ts.map +0 -1
  231. package/dist/types/core/beacon/aggregation/cohort/messages/sign/aggregated-nonce.d.ts +0 -25
  232. package/dist/types/core/beacon/aggregation/cohort/messages/sign/aggregated-nonce.d.ts.map +0 -1
  233. package/dist/types/core/beacon/aggregation/cohort/messages/sign/authorization-request.d.ts +0 -26
  234. package/dist/types/core/beacon/aggregation/cohort/messages/sign/authorization-request.d.ts.map +0 -1
  235. package/dist/types/core/beacon/aggregation/cohort/messages/sign/nonce-contribution.d.ts +0 -26
  236. package/dist/types/core/beacon/aggregation/cohort/messages/sign/nonce-contribution.d.ts.map +0 -1
  237. package/dist/types/core/beacon/aggregation/cohort/messages/sign/request-signature.d.ts +0 -26
  238. package/dist/types/core/beacon/aggregation/cohort/messages/sign/request-signature.d.ts.map +0 -1
  239. package/dist/types/core/beacon/aggregation/cohort/messages/sign/signature-authorization.d.ts +0 -27
  240. package/dist/types/core/beacon/aggregation/cohort/messages/sign/signature-authorization.d.ts.map +0 -1
  241. package/dist/types/core/beacon/aggregation/cohort/status.d.ts +0 -8
  242. package/dist/types/core/beacon/aggregation/cohort/status.d.ts.map +0 -1
  243. package/dist/types/core/beacon/aggregation/communication/adapter/did-comm.d.ts +0 -89
  244. package/dist/types/core/beacon/aggregation/communication/adapter/did-comm.d.ts.map +0 -1
  245. package/dist/types/core/beacon/aggregation/communication/adapter/nostr.d.ts +0 -103
  246. package/dist/types/core/beacon/aggregation/communication/adapter/nostr.d.ts.map +0 -1
  247. package/dist/types/core/beacon/aggregation/communication/error.d.ts.map +0 -1
  248. package/dist/types/core/beacon/aggregation/communication/factory.d.ts +0 -10
  249. package/dist/types/core/beacon/aggregation/communication/factory.d.ts.map +0 -1
  250. package/dist/types/core/beacon/aggregation/communication/service.d.ts +0 -36
  251. package/dist/types/core/beacon/aggregation/communication/service.d.ts.map +0 -1
  252. package/dist/types/core/beacon/aggregation/coordinator.d.ts +0 -116
  253. package/dist/types/core/beacon/aggregation/coordinator.d.ts.map +0 -1
  254. package/dist/types/core/beacon/aggregation/participant.d.ts +0 -192
  255. package/dist/types/core/beacon/aggregation/participant.d.ts.map +0 -1
  256. package/dist/types/core/beacon/aggregation/session/index.d.ts +0 -156
  257. package/dist/types/core/beacon/aggregation/session/index.d.ts.map +0 -1
  258. package/dist/types/core/beacon/aggregation/session/status.d.ts +0 -11
  259. package/dist/types/core/beacon/aggregation/session/status.d.ts.map +0 -1
  260. package/src/core/beacon/aggregation/cohort/index.ts +0 -305
  261. package/src/core/beacon/aggregation/cohort/messages/constants.ts +0 -12
  262. package/src/core/beacon/aggregation/cohort/messages/index.ts +0 -143
  263. package/src/core/beacon/aggregation/cohort/messages/keygen/cohort-advert.ts +0 -44
  264. package/src/core/beacon/aggregation/cohort/messages/keygen/cohort-ready.ts +0 -40
  265. package/src/core/beacon/aggregation/cohort/messages/keygen/opt-in-accept.ts +0 -35
  266. package/src/core/beacon/aggregation/cohort/messages/keygen/opt-in.ts +0 -34
  267. package/src/core/beacon/aggregation/cohort/messages/keygen/subscribe.ts +0 -36
  268. package/src/core/beacon/aggregation/cohort/messages/sign/aggregated-nonce.ts +0 -39
  269. package/src/core/beacon/aggregation/cohort/messages/sign/authorization-request.ts +0 -40
  270. package/src/core/beacon/aggregation/cohort/messages/sign/nonce-contribution.ts +0 -40
  271. package/src/core/beacon/aggregation/cohort/messages/sign/request-signature.ts +0 -40
  272. package/src/core/beacon/aggregation/cohort/messages/sign/signature-authorization.ts +0 -41
  273. package/src/core/beacon/aggregation/cohort/status.ts +0 -7
  274. package/src/core/beacon/aggregation/communication/adapter/did-comm.ts +0 -148
  275. package/src/core/beacon/aggregation/communication/adapter/nostr.ts +0 -323
  276. package/src/core/beacon/aggregation/communication/error.ts +0 -13
  277. package/src/core/beacon/aggregation/communication/factory.ts +0 -25
  278. package/src/core/beacon/aggregation/communication/service.ts +0 -42
  279. package/src/core/beacon/aggregation/coordinator.ts +0 -419
  280. package/src/core/beacon/aggregation/participant.ts +0 -517
  281. package/src/core/beacon/aggregation/session/index.ts +0 -301
  282. package/src/core/beacon/aggregation/session/status.ts +0 -18
@@ -0,0 +1,209 @@
1
+ import * as musig2 from '@scure/btc-signer/musig2';
2
+ import { Transaction } from 'bitcoinjs-lib';
3
+ import type { AggregationCohort } from './cohort.js';
4
+ import { SigningSessionError } from './errors.js';
5
+ import type { SigningSessionPhaseType } from './phases.js';
6
+ import { SigningSessionPhase } from './phases.js';
7
+
8
+ type PublicKeyHex = string;
9
+ type Nonce = Uint8Array;
10
+
11
+ export interface SigningSessionParams {
12
+ id?: string;
13
+ cohort: AggregationCohort;
14
+ pendingTx: Transaction;
15
+ prevOutScripts?: Uint8Array[];
16
+ prevOutValues?: bigint[];
17
+ }
18
+
19
+ /**
20
+ * MuSig2 signing session for a beacon transaction.
21
+ *
22
+ * Implements the BIP-327 signing protocol over a Taproot key-path-only
23
+ * transaction. The session is used by both AggregationService (collecting
24
+ * nonces and partial signatures, computing the final signature) and
25
+ * AggregationParticipant (generating their nonce and partial signature).
26
+ *
27
+ * @class BeaconSigningSession
28
+ */
29
+ export class BeaconSigningSession {
30
+ /** Unique identifier for this signing session. */
31
+ public id: string;
32
+
33
+ /** The cohort this session signs for. */
34
+ public cohort: AggregationCohort;
35
+
36
+ /** The Bitcoin transaction being signed. */
37
+ public pendingTx: Transaction;
38
+
39
+ /** Previous output scripts for Taproot sighash computation (BIP-341). */
40
+ public prevOutScripts: Uint8Array[];
41
+
42
+ /** Previous output values for Taproot sighash computation. */
43
+ public prevOutValues: bigint[];
44
+
45
+ /** Map of participant publicKey-hex → public nonce contribution. */
46
+ public nonceContributions: Map<PublicKeyHex, Nonce> = new Map();
47
+
48
+ /** Aggregated MuSig2 nonce (66 bytes). */
49
+ public aggregatedNonce?: Uint8Array;
50
+
51
+ /** Map of participant DID → partial signature. */
52
+ public partialSignatures: Map<string, Uint8Array> = new Map();
53
+
54
+ /** Final 64-byte Schnorr signature. */
55
+ public signature?: Uint8Array;
56
+
57
+ /** Current signing session phase. */
58
+ public phase: SigningSessionPhaseType;
59
+
60
+ /** Participant's secret nonce (held only by the participant during signing). */
61
+ public secretNonce?: Uint8Array;
62
+
63
+ constructor({ id, cohort, pendingTx, prevOutScripts, prevOutValues }: SigningSessionParams) {
64
+ this.id = id || crypto.randomUUID();
65
+ this.cohort = cohort;
66
+ this.pendingTx = pendingTx;
67
+ this.prevOutScripts = prevOutScripts || [];
68
+ this.prevOutValues = prevOutValues || [];
69
+ this.phase = SigningSessionPhase.AwaitingNonceContributions;
70
+ }
71
+
72
+ /**
73
+ * Computes the Taproot sighash (BIP-341) for the first input.
74
+ */
75
+ get sigHash(): Uint8Array {
76
+ if(!this.prevOutScripts.length || !this.prevOutValues.length) {
77
+ throw new SigningSessionError(
78
+ 'Cannot compute sighash: missing prevOutScripts or prevOutValues.',
79
+ 'SIGHASH_ERROR'
80
+ );
81
+ }
82
+ return this.pendingTx.hashForWitnessV1(
83
+ 0,
84
+ this.prevOutScripts,
85
+ this.prevOutValues,
86
+ Transaction.SIGHASH_DEFAULT
87
+ );
88
+ }
89
+
90
+ public addNonceContribution(participantDid: string, nonceContribution: Uint8Array): void {
91
+ if(this.phase !== SigningSessionPhase.AwaitingNonceContributions) {
92
+ throw new SigningSessionError(
93
+ `Nonce contributions not expected. Current phase: ${this.phase}`,
94
+ 'INVALID_PHASE', { phase: this.phase }
95
+ );
96
+ }
97
+ if(nonceContribution.length !== 66) {
98
+ throw new SigningSessionError(
99
+ `Invalid nonce contribution: expected 66 bytes, got ${nonceContribution.length}.`,
100
+ 'INVALID_NONCE_LENGTH'
101
+ );
102
+ }
103
+ if(this.nonceContributions.has(participantDid)) {
104
+ throw new SigningSessionError(
105
+ `Duplicate nonce contribution from ${participantDid}.`,
106
+ 'DUPLICATE_NONCE'
107
+ );
108
+ }
109
+ this.nonceContributions.set(participantDid, nonceContribution);
110
+
111
+ if(this.nonceContributions.size === this.cohort.participants.length) {
112
+ this.phase = SigningSessionPhase.NonceContributionsReceived;
113
+ }
114
+ }
115
+
116
+ public generateAggregatedNonce(): Uint8Array {
117
+ if(this.phase !== SigningSessionPhase.NonceContributionsReceived) {
118
+ throw new SigningSessionError(
119
+ `Cannot aggregate nonces: phase is ${this.phase}, expected NonceContributionsReceived.`,
120
+ 'INVALID_PHASE'
121
+ );
122
+ }
123
+ this.aggregatedNonce = musig2.nonceAggregate([...this.nonceContributions.values()]);
124
+ this.phase = SigningSessionPhase.AwaitingPartialSignatures;
125
+ return this.aggregatedNonce;
126
+ }
127
+
128
+ public addPartialSignature(participantDid: string, partialSig: Uint8Array): void {
129
+ if(this.phase !== SigningSessionPhase.AwaitingPartialSignatures) {
130
+ throw new SigningSessionError(
131
+ `Partial signatures not expected. Current phase: ${this.phase}`,
132
+ 'INVALID_PHASE'
133
+ );
134
+ }
135
+ if(this.partialSignatures.has(participantDid)) {
136
+ throw new SigningSessionError(
137
+ `Duplicate partial signature from ${participantDid}.`,
138
+ 'DUPLICATE_PARTIAL_SIG'
139
+ );
140
+ }
141
+ this.partialSignatures.set(participantDid, partialSig);
142
+
143
+ if(this.partialSignatures.size === this.cohort.participants.length) {
144
+ this.phase = SigningSessionPhase.PartialSignaturesReceived;
145
+ }
146
+ }
147
+
148
+ public generateFinalSignature(): Uint8Array {
149
+ if(this.phase !== SigningSessionPhase.PartialSignaturesReceived) {
150
+ throw new SigningSessionError(
151
+ `Cannot generate final signature: phase is ${this.phase}.`,
152
+ 'INVALID_PHASE'
153
+ );
154
+ }
155
+ if(!this.aggregatedNonce) {
156
+ throw new SigningSessionError('Aggregated nonce missing.', 'MISSING_AGGREGATED_NONCE');
157
+ }
158
+ const session = new musig2.Session(
159
+ this.aggregatedNonce,
160
+ this.cohort.cohortKeys,
161
+ this.sigHash,
162
+ [this.cohort.trMerkleRoot],
163
+ [true]
164
+ );
165
+ this.signature = session.partialSigAgg([...this.partialSignatures.values()]);
166
+ this.phase = SigningSessionPhase.Complete;
167
+ return this.signature;
168
+ }
169
+
170
+ /**
171
+ * Generates a fresh MuSig2 nonce contribution for the participant.
172
+ * Stores the secret nonce internally for use in `generatePartialSignature()`.
173
+ */
174
+ public generateNonceContribution(participantPublicKey: Uint8Array, participantSecretKey: Uint8Array): Uint8Array {
175
+ const aggPublicKey = musig2.keyAggExport(musig2.keyAggregate(this.cohort.cohortKeys));
176
+ const nonces = musig2.nonceGen(participantPublicKey, participantSecretKey, aggPublicKey);
177
+ this.secretNonce = nonces.secret;
178
+ return nonces.public;
179
+ }
180
+
181
+ /**
182
+ * Generates a partial signature using the participant's secret key + secret nonce.
183
+ * Requires the aggregated nonce to have been set first (via the service).
184
+ */
185
+ public generatePartialSignature(participantSecretKey: Uint8Array): Uint8Array {
186
+ if(!this.aggregatedNonce) {
187
+ throw new SigningSessionError('Aggregated nonce not available.', 'MISSING_AGGREGATED_NONCE');
188
+ }
189
+ if(!this.secretNonce) {
190
+ throw new SigningSessionError('Secret nonce not available — generateNonceContribution() must be called first.', 'MISSING_SECRET_NONCE');
191
+ }
192
+ const session = new musig2.Session(
193
+ this.aggregatedNonce,
194
+ this.cohort.cohortKeys,
195
+ this.sigHash,
196
+ [this.cohort.trMerkleRoot],
197
+ [true]
198
+ );
199
+ return session.sign(this.secretNonce, participantSecretKey);
200
+ }
201
+
202
+ public isComplete(): boolean {
203
+ return this.phase === SigningSessionPhase.Complete;
204
+ }
205
+
206
+ public isFailed(): boolean {
207
+ return this.phase === SigningSessionPhase.Failed;
208
+ }
209
+ }
@@ -0,0 +1,42 @@
1
+ import { NotImplementedError } from '@did-btcr2/common';
2
+ import type { SchnorrKeyPair } from '@did-btcr2/keypair';
3
+ import type { BaseMessage } from '../messages/base.js';
4
+ import type { MessageHandler, Transport } from './transport.js';
5
+
6
+ /**
7
+ * DIDComm Transport (stub).
8
+ *
9
+ * @class DidCommTransport
10
+ * @implements {Transport}
11
+ */
12
+ export class DidCommTransport implements Transport {
13
+ public name: string = 'didcomm';
14
+
15
+ public start(): void {
16
+ throw new NotImplementedError('DidCommTransport not implemented. Use NostrTransport instead.');
17
+ }
18
+
19
+ public registerActor(_did: string, _keys: SchnorrKeyPair): void {
20
+ throw new NotImplementedError('DidCommTransport not implemented.');
21
+ }
22
+
23
+ public getActorPk(_did: string): Uint8Array | undefined {
24
+ throw new NotImplementedError('DidCommTransport not implemented.');
25
+ }
26
+
27
+ public registerPeer(_did: string, _communicationPk: Uint8Array): void {
28
+ throw new NotImplementedError('DidCommTransport not implemented.');
29
+ }
30
+
31
+ public getPeerPk(_did: string): Uint8Array | undefined {
32
+ throw new NotImplementedError('DidCommTransport not implemented.');
33
+ }
34
+
35
+ public registerMessageHandler(_actorDid: string, _messageType: string, _handler: MessageHandler): void {
36
+ throw new NotImplementedError('DidCommTransport not implemented.');
37
+ }
38
+
39
+ public async sendMessage(_message: BaseMessage, _sender: string, _recipient?: string): Promise<void> {
40
+ throw new NotImplementedError('DidCommTransport not implemented.');
41
+ }
42
+ }
@@ -0,0 +1,13 @@
1
+ import { MethodError } from '@did-btcr2/common';
2
+
3
+ export class TransportError extends MethodError {
4
+ constructor(message: string, type: string = 'TransportError', data?: Record<string, any>) {
5
+ super(message, type, data);
6
+ }
7
+ }
8
+
9
+ export class TransportAdapterError extends MethodError {
10
+ constructor(message: string, type: string = 'TransportAdapterError', data?: Record<string, any>) {
11
+ super(message, type, data);
12
+ }
13
+ }
@@ -0,0 +1,29 @@
1
+ import { NotImplementedError } from '@did-btcr2/common';
2
+ import { NostrTransport } from './nostr.js';
3
+ import { TransportError } from './error.js';
4
+ import type { Transport, TransportType } from './transport.js';
5
+
6
+ export interface TransportConfig {
7
+ type: TransportType;
8
+ relays?: string[];
9
+ }
10
+
11
+ /**
12
+ * Factory for creating Transport instances.
13
+ * @class TransportFactory
14
+ */
15
+ export class TransportFactory {
16
+ static establish(config: TransportConfig): Transport {
17
+ switch (config.type) {
18
+ case 'nostr':
19
+ return new NostrTransport({ relays: config.relays });
20
+ case 'didcomm':
21
+ throw new NotImplementedError('DIDComm transport not implemented yet.');
22
+ default:
23
+ throw new TransportError(
24
+ `Invalid transport type: ${config.type}`,
25
+ 'INVALID_TRANSPORT_TYPE', { config }
26
+ );
27
+ }
28
+ }
29
+ }
@@ -0,0 +1,5 @@
1
+ export * from './transport.js';
2
+ export * from './error.js';
3
+ export * from './factory.js';
4
+ export * from './nostr.js';
5
+ export * from './didcomm.js';
@@ -0,0 +1,333 @@
1
+ import type { Did } from '@did-btcr2/common';
2
+ import type { SchnorrKeyPair } from '@did-btcr2/keypair';
3
+ import { CompressedSecp256k1PublicKey } from '@did-btcr2/keypair';
4
+ import { bytesToHex, hexToBytes } from '@noble/hashes/utils';
5
+ import type { Event, EventTemplate} from 'nostr-tools';
6
+ import { finalizeEvent, nip44 } from 'nostr-tools';
7
+ import { SimplePool } from 'nostr-tools/pool';
8
+ import type { BaseMessage } from '../messages/base.js';
9
+ import { COHORT_ADVERT } from '../messages/constants.js';
10
+ import { isAggregationMessageType, isKeygenMessageType, isSignMessageType, isUpdateMessageType } from '../messages/guards.js';
11
+ import { TransportAdapterError } from './error.js';
12
+ import type { MessageHandler, Transport } from './transport.js';
13
+
14
+ /**
15
+ * Default Nostr relay URLs.
16
+ * @constant {Array<string>} DEFAULT_NOSTR_RELAYS
17
+ */
18
+ export const DEFAULT_NOSTR_RELAYS = [
19
+ 'wss://relay.damus.io',
20
+ 'wss://nos.lol',
21
+ 'wss://relay.snort.social',
22
+ 'wss://nostr-pub.wellorder.net',
23
+ ];
24
+
25
+ export interface NostrTransportConfig {
26
+ relays?: string[];
27
+ }
28
+
29
+ /** Internal registration for a single actor sharing this transport. */
30
+ interface ActorEntry {
31
+ keys: SchnorrKeyPair;
32
+ handlers: Map<string, MessageHandler>;
33
+ }
34
+
35
+ /**
36
+ * Nostr Transport for did:btcr2 aggregation messages.
37
+ *
38
+ * A single NostrTransport manages one relay pool and supports multiple
39
+ * registered actors. Each actor registers its own DID and keys via
40
+ * {@link registerActor}; the transport resolves the correct identity when
41
+ * sending or receiving.
42
+ *
43
+ * Message routing:
44
+ * - Keygen messages (COHORT_ADVERT, COHORT_OPT_IN, COHORT_OPT_IN_ACCEPT, COHORT_READY) → kind 1 (plaintext)
45
+ * - Update messages (SUBMIT_UPDATE, DISTRIBUTE_AGGREGATED_DATA, VALIDATION_ACK) → kind 1059 (NIP-44 encrypted)
46
+ * - Sign messages → kind 1059 (NIP-44 encrypted)
47
+ *
48
+ * @class NostrTransport
49
+ * @implements {Transport}
50
+ */
51
+ export class NostrTransport implements Transport {
52
+ name: string = 'nostr';
53
+
54
+ pool?: SimplePool;
55
+ #relays: string[];
56
+ #actors: Map<string, ActorEntry> = new Map();
57
+ #peerRegistry: Map<string, Uint8Array> = new Map();
58
+ #started = false;
59
+
60
+ constructor(config?: NostrTransportConfig) {
61
+ this.#relays = config?.relays ?? DEFAULT_NOSTR_RELAYS;
62
+ }
63
+
64
+ /**
65
+ * Registers an actor (DID + keys) to send/receive messages with.
66
+ * Must be called before start() to ensure subscriptions are created for the actor.
67
+ * @param {string} did - The DID of the actor.
68
+ * @param {SchnorrKeyPair} keys - The Schnorr key pair for the actor.
69
+ * @throws {TransportAdapterError} If the actor is already registered or if the transport has already started.
70
+ * @example
71
+ * const transport = new NostrTransport();
72
+ * const keys = SchnorrKeyPair.generate();
73
+ * transport.registerActor('did:btcr2:...', keys);
74
+ * transport.start();
75
+ */
76
+ public registerActor(did: string, keys: SchnorrKeyPair): void {
77
+ const entry: ActorEntry = { keys, handlers: new Map() };
78
+ this.#actors.set(did, entry);
79
+
80
+ // If already started, create a directed subscription for this actor
81
+ if(this.#started && this.pool) {
82
+ this.#subscribeDirected(did, entry);
83
+ }
84
+ }
85
+
86
+ public getActorPk(did: string): Uint8Array | undefined {
87
+ return this.#actors.get(did)?.keys.publicKey.compressed;
88
+ }
89
+
90
+ public registerPeer(did: string, communicationPk: Uint8Array): void {
91
+ try {
92
+ new CompressedSecp256k1PublicKey(communicationPk);
93
+ } catch {
94
+ throw new TransportAdapterError(
95
+ `Invalid communication public key for peer ${did}: expected a 33-byte compressed secp256k1 key.`,
96
+ 'INVALID_PEER_KEY', { adapter: this.name, did, keyLength: communicationPk.length }
97
+ );
98
+ }
99
+ this.#peerRegistry.set(did, communicationPk);
100
+ }
101
+
102
+ public getPeerPk(did: string): Uint8Array | undefined {
103
+ return this.#peerRegistry.get(did);
104
+ }
105
+
106
+ public registerMessageHandler(actorDid: string, messageType: string, handler: MessageHandler): void {
107
+ const actor = this.#actors.get(actorDid);
108
+ if(!actor) {
109
+ throw new TransportAdapterError(
110
+ `Cannot register handler: actor ${actorDid} not registered. Call registerActor() first.`,
111
+ 'UNKNOWN_ACTOR_ERROR', { adapter: this.name, did: actorDid }
112
+ );
113
+ }
114
+ actor.handlers.set(messageType, handler);
115
+ }
116
+
117
+ public start(): NostrTransport {
118
+ if(this.#started) return this;
119
+ this.#started = true;
120
+
121
+ this.pool = new SimplePool();
122
+ const since = Math.floor(Date.now() / 1000);
123
+
124
+ // Broadcast subscription: kind 1 COHORT_ADVERT events (all actors receive these)
125
+ this.pool.subscribeMany(this.#relays, { kinds: [1], '#t': [COHORT_ADVERT], since }, {
126
+ onclose : (reasons: string[]) => console.debug('Nostr broadcast subscription closed', reasons),
127
+ onevent : this.#handleBroadcastEvent.bind(this),
128
+ });
129
+
130
+ // Directed subscriptions for any actors already registered
131
+ for(const [did, entry] of this.#actors) {
132
+ this.#subscribeDirected(did, entry);
133
+ }
134
+
135
+ console.info(`NostrTransport started, listening on ${this.#relays.length} relay(s)`);
136
+ return this;
137
+ }
138
+
139
+ public async sendMessage(message: BaseMessage, sender: Did, to?: Did): Promise<void> {
140
+ const type = message.type;
141
+
142
+ if(!type) {
143
+ throw new TransportAdapterError(
144
+ 'Message type is undefined',
145
+ 'SEND_MESSAGE_ERROR', { adapter: this.name, type }
146
+ );
147
+ }
148
+
149
+ const actor = this.#actors.get(sender);
150
+ if(!actor) {
151
+ throw new TransportAdapterError(
152
+ `Unknown sender: ${sender}. Call registerActor() before sending messages.`,
153
+ 'UNKNOWN_ACTOR_ERROR', { adapter: this.name, did: sender }
154
+ );
155
+ }
156
+
157
+ const senderKeys = actor.keys;
158
+
159
+ // Sender p-tag matches the event signing key
160
+ const tags: string[][] = [
161
+ ['p', bytesToHex(senderKeys.publicKey.x)],
162
+ ['t', type],
163
+ ];
164
+
165
+ if(to) {
166
+ const recipientPkBytes = this.#peerRegistry.get(to);
167
+ if(recipientPkBytes) {
168
+ const recipientPk = new CompressedSecp256k1PublicKey(recipientPkBytes);
169
+ tags.push(['p', bytesToHex(recipientPk.x)]);
170
+ }
171
+ }
172
+
173
+ // Keygen messages: plaintext, kind 1
174
+ if(isKeygenMessageType(type)) {
175
+ const event = finalizeEvent({
176
+ kind : 1,
177
+ created_at : Math.floor(Date.now() / 1000),
178
+ tags,
179
+ content : JSON.stringify(message, NostrTransport.#jsonReplacer),
180
+ } as EventTemplate, senderKeys.secretKey.bytes);
181
+ console.debug(`Publishing kind 1 [${type}]`);
182
+ await this.#publishToRelays(event);
183
+ return;
184
+ }
185
+
186
+ // Update and sign messages: NIP-44 encrypted, kind 1059
187
+ if(isUpdateMessageType(type) || isSignMessageType(type)) {
188
+ if(!to) {
189
+ throw new TransportAdapterError(
190
+ `Encrypted messages require a recipient DID, got undefined for type: ${type}`,
191
+ 'SEND_MESSAGE_ERROR', { adapter: this.name }
192
+ );
193
+ }
194
+ const recipientPkBytes = this.#peerRegistry.get(to);
195
+ if(!recipientPkBytes) {
196
+ throw new TransportAdapterError(
197
+ `Unknown peer DID: ${to}. Register peer via registerPeer() before sending encrypted messages.`,
198
+ 'UNKNOWN_PEER_ERROR', { adapter: this.name, did: to }
199
+ );
200
+ }
201
+ const recipientPk = new CompressedSecp256k1PublicKey(recipientPkBytes);
202
+ const conversationKey = nip44.v2.utils.getConversationKey(
203
+ senderKeys.secretKey.bytes,
204
+ bytesToHex(recipientPk.x)
205
+ );
206
+ const content = nip44.v2.encrypt(JSON.stringify(message, NostrTransport.#jsonReplacer), conversationKey);
207
+
208
+ const event = finalizeEvent({
209
+ kind : 1059,
210
+ created_at : Math.floor(Date.now() / 1000),
211
+ tags,
212
+ content,
213
+ } as EventTemplate, senderKeys.secretKey.bytes);
214
+ console.debug(`Publishing kind 1059 [${type}]`);
215
+ await this.#publishToRelays(event);
216
+ return;
217
+ }
218
+
219
+ console.warn(`Unsupported message type: ${type}`);
220
+ }
221
+
222
+ #subscribeDirected(did: string, entry: ActorEntry): void {
223
+ if(!this.pool) return;
224
+
225
+ const pkHex = bytesToHex(entry.keys.publicKey.x);
226
+ const since = Math.floor(Date.now() / 1000);
227
+
228
+ this.pool.subscribeMany(this.#relays, { kinds: [1, 1059], '#p': [pkHex], since }, {
229
+ onclose : (reasons: string[]) => console.debug(`Nostr directed subscription closed for ${did}`, reasons),
230
+ onevent : this.#makeActorEventHandler(did),
231
+ });
232
+ }
233
+
234
+ #makeActorEventHandler(actorDid: string): (event: Event) => Promise<void> {
235
+ return async (event: Event) => {
236
+ const actor = this.#actors.get(actorDid);
237
+ if(!actor) return;
238
+
239
+ let message: Record<string, unknown>;
240
+
241
+ try {
242
+ if(event.kind === 1) {
243
+ message = JSON.parse(event.content, NostrTransport.#jsonReviver);
244
+ } else if(event.kind === 1059) {
245
+ const conversationKey = nip44.v2.utils.getConversationKey(
246
+ actor.keys.secretKey.bytes,
247
+ event.pubkey
248
+ );
249
+ const plaintext = nip44.v2.decrypt(event.content, conversationKey);
250
+ message = JSON.parse(plaintext, NostrTransport.#jsonReviver);
251
+ } else {
252
+ return;
253
+ }
254
+ } catch(err) {
255
+ console.debug(`Failed to parse event ${event.id} for ${actorDid}:`, err);
256
+ return;
257
+ }
258
+
259
+ this.#dispatchMessage(message, actor);
260
+ };
261
+ }
262
+
263
+ async #handleBroadcastEvent(event: Event): Promise<void> {
264
+ if(event.kind !== 1) return;
265
+
266
+ let message: Record<string, unknown>;
267
+ try {
268
+ message = JSON.parse(event.content, NostrTransport.#jsonReviver);
269
+ } catch(err) {
270
+ console.debug(`Failed to parse broadcast event ${event.id}:`, err);
271
+ return;
272
+ }
273
+
274
+ if(message.body && typeof message.body === 'object') {
275
+ message = { ...message, ...(message.body as Record<string, unknown>) };
276
+ }
277
+
278
+ const messageType = message.type as string;
279
+ if(!messageType || !isAggregationMessageType(messageType)) return;
280
+
281
+ // Dispatch to ALL actors that have a handler for this message type
282
+ for(const actor of this.#actors.values()) {
283
+ const handler = actor.handlers.get(messageType);
284
+ if(handler) await handler(message);
285
+ }
286
+ }
287
+
288
+ #dispatchMessage(message: Record<string, unknown>, actor: ActorEntry): void {
289
+ if(message.body && typeof message.body === 'object') {
290
+ message = { ...message, ...(message.body as Record<string, unknown>) };
291
+ }
292
+
293
+ const messageType = message.type as string;
294
+ if(!messageType || !isAggregationMessageType(messageType)) return;
295
+
296
+ const handler = actor.handlers.get(messageType);
297
+ if(handler) handler(message);
298
+ }
299
+
300
+ async #publishToRelays(event: Event): Promise<void> {
301
+ const relayPromises = this.pool?.publish(this.#relays, event);
302
+ if(!relayPromises?.length) return;
303
+
304
+ const results = await Promise.allSettled(relayPromises);
305
+ const accepted = results.filter(r => r.status === 'fulfilled').length;
306
+ const rejected = results.filter(r => r.status === 'rejected');
307
+
308
+ for(const r of rejected) {
309
+ console.debug(`Relay rejected event ${event.id}: ${(r as PromiseRejectedResult).reason}`);
310
+ }
311
+
312
+ if(accepted === 0) {
313
+ throw new TransportAdapterError(
314
+ `All ${results.length} relay(s) rejected event ${event.id}`,
315
+ 'PUBLISH_ERROR', { adapter: this.name, reasons: rejected.map(r => String((r as PromiseRejectedResult).reason)) }
316
+ );
317
+ }
318
+ }
319
+
320
+ static #jsonReplacer(_key: string, value: unknown): unknown {
321
+ if(value instanceof Uint8Array) {
322
+ return { __bytes: bytesToHex(value) };
323
+ }
324
+ return value;
325
+ }
326
+
327
+ static #jsonReviver(_key: string, value: unknown): unknown {
328
+ if(value && typeof value === 'object' && '__bytes' in (value as Record<string, unknown>)) {
329
+ return hexToBytes((value as { __bytes: string }).__bytes);
330
+ }
331
+ return value;
332
+ }
333
+ }
@@ -0,0 +1,46 @@
1
+ import type { SchnorrKeyPair } from '@did-btcr2/keypair';
2
+ import type { BaseMessage } from '../messages/base.js';
3
+
4
+ export type SyncMessageHandler = (msg: any) => void;
5
+ export type AsyncMessageHandler = (msg: any) => Promise<void>;
6
+ export type MessageHandler = SyncMessageHandler | AsyncMessageHandler;
7
+
8
+ export type TransportType = 'nostr' | 'didcomm';
9
+
10
+ /**
11
+ * Multi-actor message transport.
12
+ *
13
+ * A single transport instance manages one connection (relay pool, channel, etc.)
14
+ * shared by all registered actors. Each actor registers its own DID and keys;
15
+ * the transport resolves the correct identity when sending or receiving messages.
16
+ *
17
+ * The transport is a pure passthrough — it knows nothing about the aggregation
18
+ * protocol. It only signs/encrypts outgoing messages with the sender's keys and
19
+ * dispatches incoming messages to the correct actor's registered handler.
20
+ *
21
+ * @interface Transport
22
+ */
23
+ export interface Transport {
24
+ name: string;
25
+
26
+ /** Start the underlying transport (idempotent — only starts once). */
27
+ start(): void;
28
+
29
+ /** Register an actor (service or participant) with this transport. */
30
+ registerActor(did: string, keys: SchnorrKeyPair): void;
31
+
32
+ /** Return a registered actor's compressed communication public key. */
33
+ getActorPk(did: string): Uint8Array | undefined;
34
+
35
+ /** Store a remote peer's communication public key for encrypted routing. */
36
+ registerPeer(did: string, communicationPk: Uint8Array): void;
37
+
38
+ /** Retrieve a remote peer's communication public key. */
39
+ getPeerPk(did: string): Uint8Array | undefined;
40
+
41
+ /** Register a message handler scoped to a specific actor. */
42
+ registerMessageHandler(actorDid: string, messageType: string, handler: MessageHandler): void;
43
+
44
+ /** Send a message. The transport looks up sender to resolve signing keys. */
45
+ sendMessage(message: BaseMessage, sender: string, recipient?: string): Promise<void>;
46
+ }