@did-btcr2/method 0.18.0 → 0.19.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 (262) hide show
  1. package/dist/browser.js +5240 -6079
  2. package/dist/browser.mjs +5240 -6079
  3. package/dist/cjs/core/beacon/aggregation/cohort/index.js +3 -3
  4. package/dist/cjs/core/beacon/aggregation/cohort/index.js.map +1 -1
  5. package/dist/cjs/core/beacon/aggregation/cohort/messages/base.js +1 -9
  6. package/dist/cjs/core/beacon/aggregation/cohort/messages/base.js.map +1 -1
  7. package/dist/cjs/core/beacon/aggregation/cohort/messages/keygen/cohort-advert.js +2 -1
  8. package/dist/cjs/core/beacon/aggregation/cohort/messages/keygen/cohort-advert.js.map +1 -1
  9. package/dist/cjs/core/beacon/aggregation/cohort/messages/keygen/cohort-ready.js +2 -1
  10. package/dist/cjs/core/beacon/aggregation/cohort/messages/keygen/cohort-ready.js.map +1 -1
  11. package/dist/cjs/core/beacon/aggregation/cohort/messages/keygen/opt-in-accept.js +2 -1
  12. package/dist/cjs/core/beacon/aggregation/cohort/messages/keygen/opt-in-accept.js.map +1 -1
  13. package/dist/cjs/core/beacon/aggregation/cohort/messages/keygen/opt-in.js +2 -1
  14. package/dist/cjs/core/beacon/aggregation/cohort/messages/keygen/opt-in.js.map +1 -1
  15. package/dist/cjs/core/beacon/aggregation/cohort/messages/keygen/subscribe.js +2 -1
  16. package/dist/cjs/core/beacon/aggregation/cohort/messages/keygen/subscribe.js.map +1 -1
  17. package/dist/cjs/core/beacon/aggregation/cohort/messages/sign/aggregated-nonce.js +2 -1
  18. package/dist/cjs/core/beacon/aggregation/cohort/messages/sign/aggregated-nonce.js.map +1 -1
  19. package/dist/cjs/core/beacon/aggregation/cohort/messages/sign/authorization-request.js +2 -1
  20. package/dist/cjs/core/beacon/aggregation/cohort/messages/sign/authorization-request.js.map +1 -1
  21. package/dist/cjs/core/beacon/aggregation/cohort/messages/sign/nonce-contribution.js +2 -1
  22. package/dist/cjs/core/beacon/aggregation/cohort/messages/sign/nonce-contribution.js.map +1 -1
  23. package/dist/cjs/core/beacon/aggregation/cohort/messages/sign/request-signature.js +2 -1
  24. package/dist/cjs/core/beacon/aggregation/cohort/messages/sign/request-signature.js.map +1 -1
  25. package/dist/cjs/core/beacon/aggregation/cohort/messages/sign/signature-authorization.js +2 -1
  26. package/dist/cjs/core/beacon/aggregation/cohort/messages/sign/signature-authorization.js.map +1 -1
  27. package/dist/cjs/core/beacon/aggregation/communication/adapter/nostr.js +36 -18
  28. package/dist/cjs/core/beacon/aggregation/communication/adapter/nostr.js.map +1 -1
  29. package/dist/cjs/core/beacon/aggregation/coordinator.js +14 -14
  30. package/dist/cjs/core/beacon/aggregation/coordinator.js.map +1 -1
  31. package/dist/cjs/core/beacon/aggregation/participant.js +4 -3
  32. package/dist/cjs/core/beacon/aggregation/participant.js.map +1 -1
  33. package/dist/cjs/core/beacon/aggregation/session/index.js +1 -1
  34. package/dist/cjs/core/beacon/aggregation/session/index.js.map +1 -1
  35. package/dist/cjs/core/beacon/cas-beacon.js +55 -0
  36. package/dist/cjs/core/beacon/cas-beacon.js.map +1 -0
  37. package/dist/cjs/core/beacon/factory.js +11 -10
  38. package/dist/cjs/core/beacon/factory.js.map +1 -1
  39. package/dist/cjs/core/beacon/interfaces.js +32 -0
  40. package/dist/cjs/core/beacon/interfaces.js.map +1 -0
  41. package/dist/cjs/core/beacon/singleton.js +59 -135
  42. package/dist/cjs/core/beacon/singleton.js.map +1 -1
  43. package/dist/cjs/core/beacon/smt-beacon.js +56 -0
  44. package/dist/cjs/core/beacon/smt-beacon.js.map +1 -0
  45. package/dist/cjs/core/beacon/utils.js +67 -105
  46. package/dist/cjs/core/beacon/utils.js.map +1 -1
  47. package/dist/cjs/core/identifier.js +18 -21
  48. package/dist/cjs/core/identifier.js.map +1 -1
  49. package/dist/cjs/core/interfaces.js +2 -0
  50. package/dist/cjs/core/interfaces.js.map +1 -0
  51. package/dist/cjs/core/resolve.js +511 -0
  52. package/dist/cjs/core/resolve.js.map +1 -0
  53. package/dist/cjs/{utils → core}/types.js.map +1 -1
  54. package/dist/cjs/core/{crud/update.js → update.js} +62 -52
  55. package/dist/cjs/core/update.js.map +1 -0
  56. package/dist/cjs/did-btcr2.js +109 -75
  57. package/dist/cjs/did-btcr2.js.map +1 -1
  58. package/dist/cjs/index.js +14 -15
  59. package/dist/cjs/index.js.map +1 -1
  60. package/dist/cjs/utils/appendix.js +10 -18
  61. package/dist/cjs/utils/appendix.js.map +1 -1
  62. package/dist/cjs/utils/did-document.js +51 -58
  63. package/dist/cjs/utils/did-document.js.map +1 -1
  64. package/dist/cjs/utils/general.js +1 -1
  65. package/dist/cjs/utils/general.js.map +1 -1
  66. package/dist/esm/core/beacon/aggregation/cohort/index.js +3 -3
  67. package/dist/esm/core/beacon/aggregation/cohort/index.js.map +1 -1
  68. package/dist/esm/core/beacon/aggregation/cohort/messages/base.js +1 -9
  69. package/dist/esm/core/beacon/aggregation/cohort/messages/base.js.map +1 -1
  70. package/dist/esm/core/beacon/aggregation/cohort/messages/keygen/cohort-advert.js +2 -1
  71. package/dist/esm/core/beacon/aggregation/cohort/messages/keygen/cohort-advert.js.map +1 -1
  72. package/dist/esm/core/beacon/aggregation/cohort/messages/keygen/cohort-ready.js +2 -1
  73. package/dist/esm/core/beacon/aggregation/cohort/messages/keygen/cohort-ready.js.map +1 -1
  74. package/dist/esm/core/beacon/aggregation/cohort/messages/keygen/opt-in-accept.js +2 -1
  75. package/dist/esm/core/beacon/aggregation/cohort/messages/keygen/opt-in-accept.js.map +1 -1
  76. package/dist/esm/core/beacon/aggregation/cohort/messages/keygen/opt-in.js +2 -1
  77. package/dist/esm/core/beacon/aggregation/cohort/messages/keygen/opt-in.js.map +1 -1
  78. package/dist/esm/core/beacon/aggregation/cohort/messages/keygen/subscribe.js +2 -1
  79. package/dist/esm/core/beacon/aggregation/cohort/messages/keygen/subscribe.js.map +1 -1
  80. package/dist/esm/core/beacon/aggregation/cohort/messages/sign/aggregated-nonce.js +2 -1
  81. package/dist/esm/core/beacon/aggregation/cohort/messages/sign/aggregated-nonce.js.map +1 -1
  82. package/dist/esm/core/beacon/aggregation/cohort/messages/sign/authorization-request.js +2 -1
  83. package/dist/esm/core/beacon/aggregation/cohort/messages/sign/authorization-request.js.map +1 -1
  84. package/dist/esm/core/beacon/aggregation/cohort/messages/sign/nonce-contribution.js +2 -1
  85. package/dist/esm/core/beacon/aggregation/cohort/messages/sign/nonce-contribution.js.map +1 -1
  86. package/dist/esm/core/beacon/aggregation/cohort/messages/sign/request-signature.js +2 -1
  87. package/dist/esm/core/beacon/aggregation/cohort/messages/sign/request-signature.js.map +1 -1
  88. package/dist/esm/core/beacon/aggregation/cohort/messages/sign/signature-authorization.js +2 -1
  89. package/dist/esm/core/beacon/aggregation/cohort/messages/sign/signature-authorization.js.map +1 -1
  90. package/dist/esm/core/beacon/aggregation/communication/adapter/nostr.js +36 -18
  91. package/dist/esm/core/beacon/aggregation/communication/adapter/nostr.js.map +1 -1
  92. package/dist/esm/core/beacon/aggregation/coordinator.js +14 -14
  93. package/dist/esm/core/beacon/aggregation/coordinator.js.map +1 -1
  94. package/dist/esm/core/beacon/aggregation/participant.js +4 -3
  95. package/dist/esm/core/beacon/aggregation/participant.js.map +1 -1
  96. package/dist/esm/core/beacon/aggregation/session/index.js +1 -1
  97. package/dist/esm/core/beacon/aggregation/session/index.js.map +1 -1
  98. package/dist/esm/core/beacon/cas-beacon.js +55 -0
  99. package/dist/esm/core/beacon/cas-beacon.js.map +1 -0
  100. package/dist/esm/core/beacon/factory.js +11 -10
  101. package/dist/esm/core/beacon/factory.js.map +1 -1
  102. package/dist/esm/core/beacon/interfaces.js +32 -0
  103. package/dist/esm/core/beacon/interfaces.js.map +1 -0
  104. package/dist/esm/core/beacon/singleton.js +59 -135
  105. package/dist/esm/core/beacon/singleton.js.map +1 -1
  106. package/dist/esm/core/beacon/smt-beacon.js +56 -0
  107. package/dist/esm/core/beacon/smt-beacon.js.map +1 -0
  108. package/dist/esm/core/beacon/utils.js +67 -105
  109. package/dist/esm/core/beacon/utils.js.map +1 -1
  110. package/dist/esm/core/identifier.js +18 -21
  111. package/dist/esm/core/identifier.js.map +1 -1
  112. package/dist/esm/core/interfaces.js +2 -0
  113. package/dist/esm/core/interfaces.js.map +1 -0
  114. package/dist/esm/core/resolve.js +511 -0
  115. package/dist/esm/core/resolve.js.map +1 -0
  116. package/dist/esm/{utils → core}/types.js.map +1 -1
  117. package/dist/esm/core/{crud/update.js → update.js} +62 -52
  118. package/dist/esm/core/update.js.map +1 -0
  119. package/dist/esm/did-btcr2.js +109 -75
  120. package/dist/esm/did-btcr2.js.map +1 -1
  121. package/dist/esm/index.js +14 -15
  122. package/dist/esm/index.js.map +1 -1
  123. package/dist/esm/utils/appendix.js +10 -18
  124. package/dist/esm/utils/appendix.js.map +1 -1
  125. package/dist/esm/utils/did-document.js +51 -58
  126. package/dist/esm/utils/did-document.js.map +1 -1
  127. package/dist/esm/utils/general.js +1 -1
  128. package/dist/esm/utils/general.js.map +1 -1
  129. package/dist/types/core/beacon/aggregation/cohort/index.d.ts +1 -1
  130. package/dist/types/core/beacon/aggregation/cohort/messages/base.d.ts +0 -7
  131. package/dist/types/core/beacon/aggregation/cohort/messages/base.d.ts.map +1 -1
  132. package/dist/types/core/beacon/aggregation/cohort/messages/keygen/cohort-advert.d.ts.map +1 -1
  133. package/dist/types/core/beacon/aggregation/cohort/messages/keygen/cohort-ready.d.ts.map +1 -1
  134. package/dist/types/core/beacon/aggregation/cohort/messages/keygen/opt-in-accept.d.ts.map +1 -1
  135. package/dist/types/core/beacon/aggregation/cohort/messages/keygen/opt-in.d.ts.map +1 -1
  136. package/dist/types/core/beacon/aggregation/cohort/messages/keygen/subscribe.d.ts.map +1 -1
  137. package/dist/types/core/beacon/aggregation/cohort/messages/sign/aggregated-nonce.d.ts.map +1 -1
  138. package/dist/types/core/beacon/aggregation/cohort/messages/sign/authorization-request.d.ts.map +1 -1
  139. package/dist/types/core/beacon/aggregation/cohort/messages/sign/nonce-contribution.d.ts.map +1 -1
  140. package/dist/types/core/beacon/aggregation/cohort/messages/sign/request-signature.d.ts.map +1 -1
  141. package/dist/types/core/beacon/aggregation/cohort/messages/sign/signature-authorization.d.ts.map +1 -1
  142. package/dist/types/core/beacon/aggregation/communication/adapter/nostr.d.ts +13 -5
  143. package/dist/types/core/beacon/aggregation/communication/adapter/nostr.d.ts.map +1 -1
  144. package/dist/types/core/beacon/aggregation/coordinator.d.ts +17 -29
  145. package/dist/types/core/beacon/aggregation/coordinator.d.ts.map +1 -1
  146. package/dist/types/core/beacon/aggregation/participant.d.ts.map +1 -1
  147. package/dist/types/core/beacon/cas-beacon.d.ts +47 -0
  148. package/dist/types/core/beacon/cas-beacon.d.ts.map +1 -0
  149. package/dist/types/core/beacon/factory.d.ts +5 -4
  150. package/dist/types/core/beacon/factory.d.ts.map +1 -1
  151. package/dist/types/core/beacon/interfaces.d.ts +98 -0
  152. package/dist/types/core/beacon/interfaces.d.ts.map +1 -0
  153. package/dist/types/core/beacon/singleton.d.ts +22 -65
  154. package/dist/types/core/beacon/singleton.d.ts.map +1 -1
  155. package/dist/types/core/beacon/smt-beacon.d.ts +48 -0
  156. package/dist/types/core/beacon/smt-beacon.d.ts.map +1 -0
  157. package/dist/types/core/beacon/utils.d.ts +19 -97
  158. package/dist/types/core/beacon/utils.d.ts.map +1 -1
  159. package/dist/types/core/identifier.d.ts.map +1 -1
  160. package/dist/types/core/interfaces.d.ts +94 -0
  161. package/dist/types/core/interfaces.d.ts.map +1 -0
  162. package/dist/types/core/resolve.d.ts +105 -0
  163. package/dist/types/core/resolve.d.ts.map +1 -0
  164. package/dist/types/core/types.d.ts +71 -0
  165. package/dist/types/core/types.d.ts.map +1 -0
  166. package/dist/types/core/{crud/update.d.ts → update.d.ts} +21 -20
  167. package/dist/types/core/update.d.ts.map +1 -0
  168. package/dist/types/did-btcr2.d.ts +45 -57
  169. package/dist/types/did-btcr2.d.ts.map +1 -1
  170. package/dist/types/index.d.ts +14 -15
  171. package/dist/types/index.d.ts.map +1 -1
  172. package/dist/types/utils/appendix.d.ts +5 -10
  173. package/dist/types/utils/appendix.d.ts.map +1 -1
  174. package/dist/types/utils/did-document-builder.d.ts +1 -1
  175. package/dist/types/utils/did-document-builder.d.ts.map +1 -1
  176. package/dist/types/utils/did-document.d.ts +31 -29
  177. package/dist/types/utils/did-document.d.ts.map +1 -1
  178. package/package.json +5 -5
  179. package/src/core/beacon/aggregation/cohort/index.ts +3 -3
  180. package/src/core/beacon/aggregation/cohort/messages/base.ts +1 -12
  181. package/src/core/beacon/aggregation/cohort/messages/keygen/cohort-advert.ts +2 -2
  182. package/src/core/beacon/aggregation/cohort/messages/keygen/cohort-ready.ts +2 -2
  183. package/src/core/beacon/aggregation/cohort/messages/keygen/opt-in-accept.ts +2 -2
  184. package/src/core/beacon/aggregation/cohort/messages/keygen/opt-in.ts +2 -2
  185. package/src/core/beacon/aggregation/cohort/messages/keygen/subscribe.ts +2 -2
  186. package/src/core/beacon/aggregation/cohort/messages/sign/aggregated-nonce.ts +2 -2
  187. package/src/core/beacon/aggregation/cohort/messages/sign/authorization-request.ts +2 -2
  188. package/src/core/beacon/aggregation/cohort/messages/sign/nonce-contribution.ts +2 -2
  189. package/src/core/beacon/aggregation/cohort/messages/sign/request-signature.ts +2 -2
  190. package/src/core/beacon/aggregation/cohort/messages/sign/signature-authorization.ts +2 -2
  191. package/src/core/beacon/aggregation/communication/adapter/nostr.ts +43 -21
  192. package/src/core/beacon/aggregation/coordinator.ts +41 -29
  193. package/src/core/beacon/aggregation/participant.ts +4 -3
  194. package/src/core/beacon/aggregation/session/index.ts +1 -1
  195. package/src/core/beacon/cas-beacon.ts +67 -0
  196. package/src/core/beacon/factory.ts +13 -15
  197. package/src/core/beacon/interfaces.ts +124 -0
  198. package/src/core/beacon/singleton.ts +75 -145
  199. package/src/core/beacon/smt-beacon.ts +70 -0
  200. package/src/core/beacon/utils.ts +80 -170
  201. package/src/core/identifier.ts +21 -24
  202. package/src/core/interfaces.ts +101 -0
  203. package/src/core/resolve.ts +707 -0
  204. package/src/core/types.ts +78 -0
  205. package/src/core/{crud/update.ts → update.ts} +75 -68
  206. package/src/did-btcr2.ts +152 -92
  207. package/src/index.ts +14 -24
  208. package/src/utils/appendix.ts +18 -22
  209. package/src/utils/did-document-builder.ts +1 -1
  210. package/src/utils/did-document.ts +67 -71
  211. package/src/utils/general.ts +1 -1
  212. package/dist/cjs/core/beacon/cid-aggregate.js +0 -116
  213. package/dist/cjs/core/beacon/cid-aggregate.js.map +0 -1
  214. package/dist/cjs/core/beacon/smt-aggregate.js +0 -126
  215. package/dist/cjs/core/beacon/smt-aggregate.js.map +0 -1
  216. package/dist/cjs/core/crud/deactivate.js +0 -14
  217. package/dist/cjs/core/crud/deactivate.js.map +0 -1
  218. package/dist/cjs/core/crud/read.js +0 -679
  219. package/dist/cjs/core/crud/read.js.map +0 -1
  220. package/dist/cjs/core/crud/update.js.map +0 -1
  221. package/dist/cjs/interfaces/beacon.js +0 -41
  222. package/dist/cjs/interfaces/beacon.js.map +0 -1
  223. package/dist/cjs/interfaces/crud.js +0 -2
  224. package/dist/cjs/interfaces/crud.js.map +0 -1
  225. package/dist/esm/core/beacon/cid-aggregate.js +0 -116
  226. package/dist/esm/core/beacon/cid-aggregate.js.map +0 -1
  227. package/dist/esm/core/beacon/smt-aggregate.js +0 -126
  228. package/dist/esm/core/beacon/smt-aggregate.js.map +0 -1
  229. package/dist/esm/core/crud/deactivate.js +0 -14
  230. package/dist/esm/core/crud/deactivate.js.map +0 -1
  231. package/dist/esm/core/crud/read.js +0 -679
  232. package/dist/esm/core/crud/read.js.map +0 -1
  233. package/dist/esm/core/crud/update.js.map +0 -1
  234. package/dist/esm/interfaces/beacon.js +0 -41
  235. package/dist/esm/interfaces/beacon.js.map +0 -1
  236. package/dist/esm/interfaces/crud.js +0 -2
  237. package/dist/esm/interfaces/crud.js.map +0 -1
  238. package/dist/types/core/beacon/cid-aggregate.d.ts +0 -102
  239. package/dist/types/core/beacon/cid-aggregate.d.ts.map +0 -1
  240. package/dist/types/core/beacon/smt-aggregate.d.ts +0 -111
  241. package/dist/types/core/beacon/smt-aggregate.d.ts.map +0 -1
  242. package/dist/types/core/crud/deactivate.d.ts +0 -13
  243. package/dist/types/core/crud/deactivate.d.ts.map +0 -1
  244. package/dist/types/core/crud/read.d.ts +0 -334
  245. package/dist/types/core/crud/read.d.ts.map +0 -1
  246. package/dist/types/core/crud/update.d.ts.map +0 -1
  247. package/dist/types/interfaces/beacon.d.ts +0 -116
  248. package/dist/types/interfaces/beacon.d.ts.map +0 -1
  249. package/dist/types/interfaces/crud.d.ts +0 -32
  250. package/dist/types/interfaces/crud.d.ts.map +0 -1
  251. package/dist/types/utils/types.d.ts +0 -38
  252. package/dist/types/utils/types.d.ts.map +0 -1
  253. package/src/canonicalize.d.ts +0 -6
  254. package/src/core/beacon/cid-aggregate.ts +0 -153
  255. package/src/core/beacon/smt-aggregate.ts +0 -135
  256. package/src/core/crud/deactivate.ts +0 -13
  257. package/src/core/crud/read.ts +0 -948
  258. package/src/interfaces/beacon.ts +0 -137
  259. package/src/interfaces/crud.ts +0 -33
  260. package/src/utils/types.ts +0 -41
  261. /package/dist/cjs/{utils → core}/types.js +0 -0
  262. /package/dist/esm/{utils → core}/types.js +0 -0
@@ -1,948 +0,0 @@
1
- import {
2
- BitcoinCoreRpcClient,
3
- BitcoinNetworkConnection,
4
- BitcoinRestClient,
5
- BlockV3,
6
- GENESIS_TX_ID,
7
- getNetwork,
8
- RawTransactionRest,
9
- RawTransactionV2,
10
- TXIN_WITNESS_COINBASE
11
- } from '@did-btcr2/bitcoin';
12
- import {
13
- BitcoinNetworkNames,
14
- DidUpdatePayload,
15
- ID_PLACEHOLDER_VALUE,
16
- IdentifierHrp,
17
- INVALID_DID,
18
- INVALID_DID_DOCUMENT,
19
- INVALID_DID_UPDATE,
20
- LATE_PUBLISHING_ERROR,
21
- Logger,
22
- MethodError,
23
- ResolveError,
24
- UnixTimestamp
25
- } from '@did-btcr2/common';
26
- import { Cryptosuite, DataIntegrityProof, SchnorrMultikey } from '@did-btcr2/cryptosuite';
27
- import { CompressedSecp256k1PublicKey } from '@did-btcr2/keypair';
28
- import { bytesToHex } from '@noble/hashes/utils';
29
- import { DidBtcr2 } from '../../did-btcr2.js';
30
- import { BeaconService, BeaconServiceAddress, BeaconSignal } from '../../interfaces/beacon.js';
31
- import { DidResolutionOptions } from '../../interfaces/crud.js';
32
- import { Appendix } from '../../utils/appendix.js';
33
- import { DidDocument } from '../../utils/did-document.js';
34
- import {
35
- CIDAggregateSidecar,
36
- SidecarData,
37
- SignalsMetadata
38
- } from '../../utils/types.js';
39
- import { BeaconFactory } from '../beacon/factory.js';
40
- import { BeaconUtils } from '../beacon/utils.js';
41
- import { DidComponents } from '../identifier.js';
42
-
43
- export type FindNextSignalsRestParams = {
44
- connection: BitcoinRestClient;
45
- beaconSignals: Array<BeaconSignal>;
46
- block: BlockV3;
47
- beacons: Array<BeaconServiceAddress>;
48
- }
49
- export type BeaconSignals = Array<BeaconSignal>;
50
- export type BitcoinClient = BitcoinCoreRpcClient | BitcoinRestClient;
51
-
52
- export type NetworkVersion = {
53
- version?: string;
54
- network?: string;
55
- };
56
- export type ResolveInitialDocument = {
57
- identifier: string;
58
- components: DidComponents;
59
- resolutionsOptions: DidResolutionOptions;
60
- };
61
-
62
- // Deterministic
63
- export interface ResolveDeterministic {
64
- components: DidComponents;
65
- identifier: string;
66
- };
67
-
68
- // External
69
- export interface ResolveExternal {
70
- components: DidComponents;
71
- identifier: string;
72
- resolutionsOptions: DidResolutionOptions;
73
- }
74
- export interface ResolveSidecar {
75
- identifierComponents: DidComponents;
76
- initialDocument: DidDocument;
77
- };
78
- export interface ResolveCas {
79
- identifier: string;
80
- identifierComponents: DidComponents;
81
- }
82
-
83
- // Methods
84
- export interface ApplyDidUpdateParams {
85
- contemporaryDidDocument: DidDocument;
86
- update: DidUpdatePayload;
87
- }
88
-
89
- export interface TargetDocumentParams {
90
- initialDocument: DidDocument;
91
- resolutionsOptions: DidResolutionOptions;
92
- };
93
-
94
- export interface TargetBlockheightParams {
95
- network: BitcoinNetworkNames;
96
- targetTime?: UnixTimestamp;
97
- }
98
-
99
- const bitcoin = new BitcoinNetworkConnection();
100
-
101
- /**
102
- * Implements {@link https://dcdpr.github.io/did-btcr2/#read | 4.2 Read}.
103
- * The read operation is executed by a resolver after a resolution request identifying a specific did:btcr2 identifier is
104
- * received from a client at Resolution Time. The request MAY contain a resolutionOptions object containing additional
105
- * information to be used in resolution. The resolver then attempts to resolve the DID document of the identifier at a
106
- * specific Target Time. The Target Time is either provided in resolutionOptions or is set to the Resolution Time of the
107
- * request.
108
- * To do so it executes the following algorithm:
109
- * 1. Let identifierComponents be the result of running the algorithm
110
- * in Parse did:btcr2 identifier, passing in the identifier.
111
- * 2. Set initialDocument to the result of running Resolve Initial Document
112
- * passing identifier, identifierComponents and resolutionOptions.
113
- * 3. Set targetDocument to the result of running the algorithm in Resolve
114
- * Target Document passing in initialDocument and resolutionOptions.
115
- * 4. Return targetDocument.
116
- *
117
- * @class Resolve
118
- * @type {Resolve}
119
- */
120
- export class Resolve {
121
- /**
122
- * Implements {@link https://dcdpr.github.io/did-btcr2/#deterministically-generate-initial-did-document | 4.2.2.1 Deterministically Generate Initial DID Document}.
123
- *
124
- * The Deterministically Generate Initial DID Document algorithm deterministically generates an initial DID
125
- * Document from a secp256k1 public key. It takes in a did:btcr2 identifier and a identifierComponents object and
126
- * returns an initialDocument.
127
- *
128
- * @param {ResolveDeterministic} params See {@link ResolveDeterministic} for details.
129
- * @param {string} params.identifier The did-btcr2 version.
130
- * @param {DidComponents} params.identifierComponents The decoded components of the identifier.
131
- * @returns {DidDocument} The resolved DID Document object.
132
- */
133
- public static deterministic({ identifier, identifierComponents }: {
134
- identifier: string;
135
- identifierComponents: DidComponents;
136
- }): DidDocument {
137
- // Deconstruct the components
138
- const { network, genesisBytes } = identifierComponents;
139
-
140
- // Construct a new CompressedSecp256k1PublicKey and deconstruct the publicKey and publicKeyMultibase
141
- const { compressed: publicKey, multibase: publicKeyMultibase } = new CompressedSecp256k1PublicKey(genesisBytes);
142
-
143
- // Generate the service field for the DID Document
144
- const service = BeaconUtils.generateBeaconServices({
145
- identifier,
146
- publicKey,
147
- network : getNetwork(network),
148
- type : 'SingletonBeacon',
149
- });
150
-
151
- return new DidDocument({
152
- id : identifier,
153
- controller : [identifier],
154
- verificationMethod : [{
155
- id : `${identifier}#initialKey`,
156
- type : 'Multikey',
157
- controller : identifier,
158
- publicKeyMultibase : publicKeyMultibase.encoded
159
- }],
160
- service
161
- });
162
- }
163
-
164
- /**
165
- * Implements {@link https://dcdpr.github.io/did-btcr2/#external-resolution | 4.2.2.2 External Resolution}.
166
- *
167
- * The External Resolution algorithm externally retrieves an intermediateDocumentRepresentation, either by retrieving
168
- * it from {@link https://dcdpr.github.io/did-btcr2/#def-content-addressable-storage | Content Addressable Storage (CAS)}
169
- * or from the {@link https://dcdpr.github.io/did-btcr2/#def-sidecar-data | Sidecar Data} provided as part of the
170
- * resolution request. It takes in a did:btcr2 identifier, a identifierComponents object and a resolutionOptions object.
171
- * It returns an initialDocument, which is a conformant DID document validated against the identifier.
172
- *
173
- * @param {ResolveExternal} params Required params for calling the external method.
174
- * @param {string} params.identifier The DID to be resolved.
175
- * @param {DidComponents} params.identifierComponents The decoded components of the identifier.
176
- * @param {DidResolutionOptions} params.resolutionsOptions The options for resolving the DID Document.
177
- * @param {DidDocument} params.resolutionsOptions.sidecarData The sidecar data for resolving the DID Document.
178
- * @param {DidDocument} params.resolutionsOptions.sidecarData.initialDocument The offline user-provided DID Document
179
- * @returns {DidDocument} The resolved DID Document object
180
- */
181
- public static async external({ identifier, identifierComponents, resolutionsOptions }: {
182
- identifier: string;
183
- identifierComponents: DidComponents;
184
- resolutionsOptions: DidResolutionOptions;
185
- }): Promise<DidDocument> {
186
- // Deconstruct the options
187
- const { initialDocument: document } = resolutionsOptions.sidecarData as CIDAggregateSidecar;
188
-
189
- // 1. If resolutionOptions.sidecarData.initialDocument is not null, set initialDocument to the result of passing
190
- // identifier, identifierComponents and resolutionOptions.sidecarData.initialDocument into algorithm Sidecar
191
- // Initial Document Validation.
192
- // 2. Else set initialDocument to the result of passing identifier and identifierComponents to the CAS Retrieval algorithm.
193
- const initialDocument = document
194
- ? await this.sidecar({ identifierComponents, initialDocument: document })
195
- : await this.cas({ identifier, identifierComponents });
196
-
197
- // 3. Validate initialDocument is a conformant DID document according to the DID Core 1.1 specification. Else MUST
198
- // raise invalidDidDocument error.
199
- DidDocument.validate(initialDocument);
200
-
201
- // 4. Return initialDocument.
202
- return initialDocument;
203
- }
204
-
205
- /**
206
- * Implements {@link https://dcdpr.github.io/did-btcr2/#sidecar-initial-document-validation | 4.2.2.2.1 Sidecar Initial Document Validation}.
207
- *
208
- * The Sidecar Initial Document Validation algorithm validates an initialDocument against its identifier, by first
209
- * constructing the intermediateDocumentRepresentation and verifying the hash of this document matches the bytes
210
- * encoded within the identifier. It takes in a did:btcr2 identifier, identifierComponents and a
211
- * initialDocument. It returns the initialDocument if validated, otherwise it throws an error.
212
- *
213
- * @param {ResolveSidecar} params Required params for calling the sidecar method
214
- * @param {string} params.identifier The DID to be resolved
215
- * @param {DidComponents} params.identifierComponents The components of the DID identifier
216
- * @param {DidDocument} params.initialDocument The initial DID Document provided by the user
217
- * @returns {DidDocument} The resolved DID Document object
218
- * @throws {DidError} InvalidDidDocument if genesisBytes !== initialDocument hashBytes
219
- */
220
- public static async sidecar({ identifierComponents, initialDocument }: ResolveSidecar): Promise<DidDocument> {
221
- // Replace the placeholder did with the identifier throughout the initialDocument.
222
- const intermediateDocument = JSON.parse(
223
- JSON.stringify(initialDocument).replaceAll(initialDocument.id, ID_PLACEHOLDER_VALUE)
224
- );
225
-
226
- // Canonicalize and sha256 hash the intermediateDocument
227
- const hashBytes = await JSON.canonicalization.process(intermediateDocument, 'hex');
228
-
229
- // Compare the genesisBytes to the hashBytes
230
- const genesisBytes = bytesToHex(identifierComponents.genesisBytes);
231
-
232
- // If the genesisBytes do not match the hashBytes, throw an error
233
- if (genesisBytes !== hashBytes) {
234
- throw new MethodError(
235
- `Initial document mismatch: genesisBytes ${genesisBytes} !== hashBytes ${hashBytes}`,
236
- INVALID_DID_DOCUMENT, { genesisBytes, hashBytes }
237
- );
238
- }
239
-
240
- // Return a W3C conformant DID Document
241
- return new DidDocument(initialDocument);
242
- }
243
-
244
- /**
245
- * Implements {@link https://dcdpr.github.io/did-btcr2/#cas-retrieval | 4.2.2.2.2 CAS Retrieval}.
246
- *
247
- * The CAS Retrieval algorithm attempts to retrieve an initialDocument from a Content Addressable Storage (CAS) system
248
- * by converting the bytes in the identifier into a Content Identifier (CID). It takes in an identifier and
249
- * an identifierComponents object. It returns an initialDocument.
250
- *
251
- * @param {ResolveCas} params Required params for calling the cas method
252
- * @param {string} params.identifier BTCR2 DID used to resolve the DID Document
253
- * @param {DidComponents} params.identifierComponents BTCR2 DID components used to resolve the DID Document
254
- * @returns {DidDocument} The resolved DID Document object
255
- * @throws {MethodError} if the DID Document content is invalid
256
- */
257
- public static async cas({ identifier, identifierComponents }: ResolveCas): Promise<DidDocument> {
258
- // 1. Set hashBytes to identifierComponents.genesisBytes.
259
- const hashBytes = identifierComponents.genesisBytes;
260
-
261
- // 3. Set intermediateDocumentRepresentation to the result of fetching the cid against a Content Addressable Storage
262
- // (CAS) system such as IPFS.
263
- const intermediateDocument = await Appendix.fetchFromCas(hashBytes);
264
-
265
- // Validate the intermediateDocument is not null and is parsable JSON
266
- if (!intermediateDocument || !JSON.parsable(intermediateDocument)) {
267
- throw new MethodError(INVALID_DID_DOCUMENT, 'Invalid DID Document content', { intermediateDocument });
268
- }
269
- // 5. Replace the placeholder did with the identifier throughout the initialDocument.
270
- const initialDocument = JSON.parse(
271
- intermediateDocument.replaceAll(ID_PLACEHOLDER_VALUE, identifier)
272
- );
273
-
274
- // 6. Return initialDocument.
275
- return new DidDocument(initialDocument);
276
- }
277
-
278
- /**
279
- * Implements {@link https://dcdpr.github.io/did-btcr2/#resolve-initial-document | 4.2.2 Resolve Initial Document}.
280
- *
281
- * This algorithm resolves an initial DID document and validates it against the identifier for a specific did:btcr2.
282
- * The algorithm takes in a did:btcr2 identifier, identifier components object, resolutionsOptions object and returns
283
- * a valid initialDocument for that identifier.
284
- *
285
- * @public
286
- * @param {ResolveInitialDocument} params See {@link ResolveInitialDocument} for parameter details.
287
- * @param {string} params.identifier The DID to be resolved.
288
- * @param {DidComponents} params.identifierComponents The decoded components of the identifier.
289
- * @param {DidResolutionOptions} params.resolutionsOptions Options for resolving the DID Document. See {@link DidResolutionOptions}.
290
- * @returns {Promise<DidDocument>} The resolved DID Document object.
291
- * @throws {DidError} if the DID hrp is invalid, no sidecarData passed and hrp = "x".
292
- */
293
- public static async initialDocument({ identifier, identifierComponents, resolutionsOptions }: {
294
- identifier: string;
295
- identifierComponents: DidComponents;
296
- resolutionsOptions: DidResolutionOptions
297
- }): Promise<DidDocument> {
298
- // Deconstruct the hrp from the components
299
- const hrp = identifierComponents.hrp;
300
-
301
- // Validate the hrp is either 'k' or 'x'
302
- if (!(hrp in IdentifierHrp)) {
303
- throw new MethodError(`Invalid DID hrp ${hrp}`, INVALID_DID, { hrp });
304
- }
305
-
306
- // Make sure options.sidecarData is not null if hrp === x
307
- if (hrp === IdentifierHrp.x && !resolutionsOptions.sidecarData) {
308
- throw new MethodError('External resolution requires sidecar data', INVALID_DID, resolutionsOptions);
309
- }
310
-
311
- return hrp === IdentifierHrp.k
312
- ? this.deterministic({ identifier, identifierComponents })
313
- : await this.external({ identifier, identifierComponents, resolutionsOptions });
314
-
315
- }
316
-
317
- /**
318
- * Implements {@link https://dcdpr.github.io/did-btcr2/#resolve-target-document | 4.2.3 Resolve Target Document}.
319
- *
320
- * The Resolve Target Document algorithm resolves a DID document from an initial document by walking the Bitcoin
321
- * blockchain to identify Beacon Signals that announce DID Update Payloads applicable to the did:btcr2 identifier being
322
- * resolved. It takes as inputs initialDocument, resolutionOptions and network. It returns a valid DID document.
323
- *
324
- * @public
325
- * @param {TargetDocumentParams} params See {@link TargetDocumentParams} for details.
326
- * @param {DidDocument} params.initialDocument The initial DID Document to resolve
327
- * @param {ResolutionOptions} params.options See {@link DidResolutionOptions} for details.
328
- * @returns {DidDocument} The resolved DID Document object with a validated single, canonical history
329
- */
330
- public static async targetDocument({ initialDocument, resolutionsOptions }: {
331
- initialDocument: DidDocument;
332
- resolutionsOptions: DidResolutionOptions;
333
- }): Promise<DidDocument> {
334
- // Set the network from the options or default to mainnet
335
- const network = resolutionsOptions.network!;
336
-
337
- // 1. If resolutionOptions.versionId is not null, set targetVersionId to resolutionOptions.versionId.
338
- const targetVersionId = resolutionsOptions.versionId;
339
-
340
- // 2. Else if resolutionOptions.versionTime is not null, set targetTime to resolutionOptions.versionTime.
341
- // 3. Else set targetTime to the UNIX timestamp for now at the moment of execution.
342
- const targetTime = resolutionsOptions.versionTime ?? new Date().toUnix();
343
-
344
- // 4. Set signalsMetadata to resolutionOptions.sidecarData.signalsMetadata.
345
- const signalsMetadata = (resolutionsOptions.sidecarData as SidecarData)?.signalsMetadata ?? {};
346
-
347
- // 5. Set currentVersionId to 1
348
- const currentVersionId = 1;
349
-
350
- // 6. If currentVersionId equals targetVersionId return initialDocument.
351
- if (currentVersionId === targetVersionId) {
352
- return new DidDocument(initialDocument);
353
- }
354
-
355
- // 10. Set targetDocument to the result of calling the Traverse Bitcoin Blockchain History algorithm
356
- // passing in contemporaryDIDDocument, contemporaryBlockheight, currentVersionId, targetVersionId,
357
- // targetTime, didDocumentHistory, updateHashHistory, signalsMetadata, and network.
358
- const targetDocument = this.traverseBlockchainHistory({
359
- contemporaryDidDocument : initialDocument,
360
- contemporaryBlockHeight : 0,
361
- currentVersionId,
362
- targetVersionId,
363
- targetTime,
364
- didDocumentHistory : new Array(),
365
- updateHashHistory : new Array(),
366
- signalsMetadata,
367
- network
368
- });
369
-
370
- // 11. Return targetDocument.
371
- return targetDocument;
372
- }
373
-
374
- /**
375
- * Implements {@link https://dcdpr.github.io/did-btcr2/#traverse-blockchain-history | 4.2.3.2 Traverse Blockchain History}.
376
- *
377
- * The Traverse Blockchain History algorithm traverses Bitcoin blocks, starting from the block with the
378
- * contemporaryBlockheight, to find beaconSignals emitted by Beacons within the contemporaryDidDocument. Each
379
- * beaconSignal is processed to retrieve a didUpdatePayload to the DID document. Each update is applied to the
380
- * document and duplicates are ignored. If the algorithm reaches the block with the blockheight specified by a
381
- * targetBlockheight, the contemporaryDidDocument at that blockheight is returned assuming a single canonical history
382
- * of the DID document has been constructed up to that point. It takes in contemporaryDidDocument,
383
- * contemporaryBlockHeight, currentVersionId, targetVersionId, targetBlockheight, updateHashHistory, signalsMetadata
384
- * and network. It returns the contemporaryDidDocument once either the targetBlockheight or targetVersionId have been
385
- * reached.
386
- *
387
- * @protected
388
- * @param {ReadBlockchainParams} params The parameters for the traverseBlockchainHistory operation.
389
- * @param {DidDocument} params.contemporaryDidDocument The DID document for the did:btcr2 identifier being resolved.
390
- * It should be "current" (contemporary) at the blockheight of the contemporaryBlockheight.
391
- * It should be a DID Core conformant DID document.
392
- * @param {number} params.contemporaryBlockHeight The Bitcoin blockheight signaling the "contemporary time" of the
393
- * contemporary DID Document that is being resolved and updated using the Traverse Blockchain History algorithm.
394
- * @param {number} params.currentVersionId The version of the contemporary DID document starting from 1 and
395
- * incrementing by 1 with each BTCR2 Update applied to the DID document.
396
- * @param {number} params.targetVersionId The version of the DID document where resolution will complete.
397
- * @param {UnixTimestamp} params.targetTime The timestamp used to target specific historical states of a DID document.
398
- * Only Beacon Signals included in the Bitcoin blockchain before the targetTime are processed.
399
- * @param {boolean} params.didDocumentHistory An array of DID documents ordered ascensing by version (1...N).
400
- * @param {boolean} params.updateHashHistory An array of SHA256 hashes of BTCR2 Updates ordered by version that are
401
- * applied to the DID document in order to construct the contemporaryDIDDocument.
402
- * @param {SignalsMetadata} params.signalsMetadata See {@link SignalsMetadata} for details.
403
- * @param {string} params.network The bitcoin network to connect to (mainnet, signet, testnet, regtest).
404
- * @returns {Promise<DidDocument>} The resolved DID Document object with a validated single, canonical history.
405
- */
406
- protected static async traverseBlockchainHistory({
407
- contemporaryDidDocument,
408
- contemporaryBlockHeight,
409
- currentVersionId,
410
- targetVersionId,
411
- targetTime,
412
- didDocumentHistory,
413
- updateHashHistory,
414
- signalsMetadata,
415
- network
416
- }: {
417
- contemporaryDidDocument: DidDocument;
418
- contemporaryBlockHeight: number;
419
- currentVersionId: number;
420
- targetVersionId?: number;
421
- targetTime: number;
422
- didDocumentHistory: DidDocument[];
423
- updateHashHistory: string[];
424
- signalsMetadata: SignalsMetadata;
425
- network: string;
426
- }): Promise<DidDocument> {
427
- // 1. Set contemporaryHash to the SHA256 hash of the contemporaryDidDocument
428
- let contemporaryHash = await JSON.canonicalization.process(contemporaryDidDocument, 'base58');
429
-
430
- // 2. Find all BTCR2 Beacons in contemporaryDIDDocument.service where service.type equals one of
431
- // SingletonBeacon, CIDAggregateBeacon and SMTAggregateBeacon.
432
- // 3. For each beacon in beacons convert the beacon.serviceEndpoint to a Bitcoin address
433
- // following BIP21. Set beacon.address to the Bitcoin address.
434
- const beacons = BeaconUtils.toBeaconServiceAddress(
435
- BeaconUtils.getBeaconServices(contemporaryDidDocument)
436
- );
437
-
438
- // 4. Set nextSignals to the result of calling algorithm Find Next Signals passing in contemporaryBlockheight,
439
- // beacons and network.
440
- const nextSignals = await this.findNextSignals({ contemporaryBlockHeight, beacons, network, targetTime });
441
- if (!nextSignals || nextSignals.length === 0) {
442
- // 5. If nextSignals is null or empty, return contemporaryDidDocument.
443
- return new DidDocument(contemporaryDidDocument);
444
- }
445
-
446
- // 6. If nextSignals[0].blocktime is greater than targetTime, return contemporaryDIDDocument.
447
- if (nextSignals[0].blocktime > targetTime) {
448
- return new DidDocument(contemporaryDidDocument);
449
- }
450
-
451
- // 8. Set updates to the result of calling algorithm Process Beacon Signals passing in signals and sidecarData.
452
- // 9. Set orderedUpdates to the list of updates ordered by the targetVersionId property.
453
- const orderedUpdates = (
454
- await Promise.all(
455
- nextSignals.map(
456
- async signal => await this.processBeaconSignal(signal, signalsMetadata)
457
- )
458
- )
459
- ).sort((a, b) => a.targetVersionId - b.targetVersionId);
460
-
461
- // 10. For update in orderedUpdates:
462
- for (let update of orderedUpdates) {
463
- const updateTargetVersionId = update.targetVersionId;
464
- // 10.1. If update.targetVersionId is less than or equal to currentVersionId, run Algorithm Confirm Duplicate
465
- // Update passing in update, documentHistory, and contemporaryHash.
466
- if (updateTargetVersionId <= currentVersionId) {
467
- updateHashHistory.push(contemporaryHash);
468
- await this.confirmDuplicateUpdate({ update, updateHashHistory: updateHashHistory });
469
-
470
- // 10.2. If update.targetVersionId equals currentVersionId + 1:
471
- } else if (updateTargetVersionId === currentVersionId + 1) {
472
- // Prepend `z` to the sourceHash if it does not start with it
473
- const sourceHash = update.sourceHash.startsWith('z') ? update.sourceHash : `z${update.sourceHash}`;
474
-
475
- // 10.2.1. Check that update.sourceHash equals contemporaryHash, else MUST raise latePublishing error.
476
- if (sourceHash !== contemporaryHash) {
477
- throw new ResolveError(
478
- `Hash mismatch: sourceHash ${sourceHash} !== contemporaryHash ${contemporaryHash}`,
479
- LATE_PUBLISHING_ERROR, { sourceHash: sourceHash, contemporaryHash }
480
- );
481
- }
482
-
483
- // 10.2.2. Set contemporaryDidDocument to the result of calling Apply DID Update algorithm passing in
484
- // contemporaryDidDocument, update.
485
- contemporaryDidDocument = await this.applyDidUpdate({ contemporaryDidDocument, update });
486
-
487
- // 10.2.4 Push contemporaryDIDDocument onto didDocumentHistory.
488
- didDocumentHistory.push(contemporaryDidDocument);
489
-
490
- // 10.2.4. Increment currentVersionId.
491
- currentVersionId++;
492
-
493
- // 10.2.5. Set unsecuredUpdate to a copy of the update object.
494
- const unsecuredUpdate = update;
495
-
496
- // 10.2.6 Remove the proof property from the unsecuredUpdate object.
497
- delete unsecuredUpdate.proof;
498
-
499
- // 10.2.7 Set updateHash to the result of passing unsecuredUpdate into the JSON Canonicalization and Hash algorithm.
500
- const updateHash = await JSON.canonicalization.process(update, 'base58');
501
-
502
- // 10.2.8. Push updateHash onto updateHashHistory.
503
- updateHashHistory.push(updateHash as string);
504
-
505
- // 10.2.9. Set contemporaryHash to result of passing contemporaryDIDDocument into the JSON Canonicalization and Hash algorithm.
506
- contemporaryHash = await JSON.canonicalization.process(contemporaryDidDocument, 'base58');
507
-
508
- // 10.3. If update.targetVersionId is greater than currentVersionId + 1, MUST throw a LatePublishing error.
509
- } else if (update.targetVersionId > currentVersionId + 1) {
510
- throw new ResolveError(
511
- `Version Id Mismatch: target ${update.targetVersionId} cannot be > current+1 ${currentVersionId + 1}`,
512
- 'LATE_PUBLISHING_ERROR'
513
- );
514
- }
515
- }
516
-
517
- // 13. If targetVersionId in not null, set targetDocument to the index at the targetVersionId of the didDocumentHistory array.
518
- if(targetVersionId) {
519
- return new DidDocument(didDocumentHistory[targetVersionId]);
520
- }
521
-
522
- // 14. Return contemporaryDidDocument.
523
- return new DidDocument(contemporaryDidDocument);
524
- }
525
-
526
-
527
- /**
528
- * Implements {@link https://dcdpr.github.io/did-btcr2/#find-next-signals | 4.2.3.3 Find Next Signals}.
529
- *
530
- * The Find Next Signals algorithm finds the next Bitcoin block containing Beacon Signals from one or more of the
531
- * beacons and retuns all Beacon Signals within that block.
532
- *
533
- * It takes the following inputs:
534
- * - `contemporaryBlockhieght`: The height of the block this function is looking for Beacon Signals in.
535
- * An integer greater or equal to 0.
536
- * - `targetBlockheight`: The height of the Bitcoin block that the resolution algorithm searches for Beacon Signals
537
- * up to. An integer greater or equal to 0.
538
- * - `beacons`: An array of Beacon services in the contemporary DID document. Each Beacon contains properties:
539
- * - `id`: The id of the Beacon service in the DID document. A string.
540
- * - `type`: The type of the Beacon service in the DID document. A string whose values MUST be
541
- * either SingletonBeacon, CIDAggregateBeacon or SMTAggregateBeacon.
542
- * - `serviceEndpoint`: A BIP21 URI representing a Bitcoin address.
543
- * - `address`: The Bitcoin address decoded from the `serviceEndpoint value.
544
- * - `network`: A string identifying the Bitcoin network of the did:btcr2 identifier. This algorithm MUST query the
545
- * Bitcoin blockchain identified by the network.
546
- *
547
- * It returns a nextSignals struct, containing the following properties:
548
- * - blockheight: The Bitcoin blockheight for the block containing the Beacon Signals.
549
- * - signals: An array of signals. Each signal is a struct containing the following:
550
- * - beaconId: The id for the Beacon that the signal was announced by.
551
- * - beaconType: The type of the Beacon that announced the signal.
552
- * - tx: The Bitcoin transaction that is the Beacon Signal.
553
- *
554
- * @public
555
- * @param {FindNextSignals} params The parameters for the findNextSignals operation.
556
- * @param {number} params.contemporaryBlockHeight The blockheight to start looking for beacon signals.
557
- * @param {Array<BeaconService>} params.beacons The beacons to look for in the block.
558
- * @param {Array<BeaconService>} params.network The bitcoin network to connect to (mainnet, signet, testnet, regtest).
559
- * @param {UnixTimestamp} params.targetTime The timestamp used to target specific historical states of a DID document.
560
- * Only Beacon Signals included in the Bitcoin blockchain before the targetTime are processed.
561
- * @returns {Promise<Array<BeaconSignal>>} An array of BeaconSignal objects with blockHeight and signals.
562
- */
563
- public static async findNextSignals({ contemporaryBlockHeight, targetTime, network, beacons }: {
564
- contemporaryBlockHeight: number;
565
- beacons: Array<BeaconServiceAddress>;
566
- network: string;
567
- targetTime: UnixTimestamp;
568
- }): Promise<Array<BeaconSignal>> {
569
- let height = contemporaryBlockHeight;
570
-
571
- // Create an default beaconSignal and beaconSignals array
572
- let beaconSignals: BeaconSignals = [];
573
-
574
- // Get the bitcoin network connection
575
- bitcoin.setActiveNetwork(network);
576
-
577
- // Opt into REST connection if available
578
- if(bitcoin.network.rest) {
579
- return await this.findSignalsRest(beacons);
580
- }
581
-
582
- // If no rest and no rpc connection is available, throw an error
583
- if (!bitcoin.network.rpc) {
584
- throw new ResolveError(
585
- `No Bitcoin connection available, cannot find next signals`,
586
- 'NO_BITCOIN_CONNECTION'
587
- );
588
- }
589
-
590
- // Opt into rpc connection to get the block data at the blockhash
591
- let block = await bitcoin.network.rpc.getBlock({ height }) as BlockV3;
592
-
593
- Logger.info(`Searching for signals, please wait ...`);
594
- while (block.time <= targetTime) {
595
- // Iterate over each transaction in the block
596
- for (const tx of block.tx) {
597
- // If the txid is a coinbase, continue ...
598
- if (tx.txid === GENESIS_TX_ID) {
599
- continue;
600
- }
601
-
602
- // Iterate over each input in the transaction
603
- for (const vin of tx.vin) {
604
-
605
- // If the vin is a coinbase transaction, continue ...
606
- if (vin.coinbase) {
607
- continue;
608
- }
609
-
610
- // If the vin txinwitness contains a coinbase identifier, continue ...
611
- if (vin.txinwitness && vin.txinwitness.length === 1 && vin.txinwitness[0] === TXIN_WITNESS_COINBASE) {
612
- continue;
613
- }
614
-
615
- // If the txid from the vin is undefined, continue ...
616
- if (!vin.txid) {
617
- continue;
618
- }
619
-
620
- // If the vout from the vin is undefined, continue ...
621
- if (vin.vout === undefined) {
622
- continue;
623
- }
624
-
625
- // Get the previous output transaction data
626
- const prevout = await bitcoin.network.rpc.getRawTransaction(vin.txid, 2) as RawTransactionV2;
627
-
628
- // If the previous output vout at the vin.vout index is undefined, continue ...
629
- if (!prevout.vout[vin.vout]) {
630
- continue;
631
- }
632
-
633
- // Get the address from the scriptPubKey from the prevvout (previous output's input at the vout index)
634
- const scriptPubKey = prevout.vout[vin.vout].scriptPubKey;
635
-
636
- // If the scriptPubKey.address is undefined, continue ...
637
- if (!scriptPubKey.address) {
638
- continue;
639
- }
640
-
641
- // If the beaconAddress from prevvout scriptPubKey is not a beacon service endpoint address, continue ...
642
- const beaconAddresses = BeaconUtils.getBeaconServiceAddressMap(beacons);
643
- const beacon = (beaconAddresses.get(scriptPubKey.address) ?? {}) as BeaconServiceAddress;
644
- if (!beacon || !(beacon.id && beacon.type)) {
645
- continue;
646
- }
647
-
648
- // If the prevout.vout[vin.vout].scriptPubKey.asm does not include 'OP_RETURN', continue ...
649
- if(!prevout.vout[vin.vout].scriptPubKey.asm.includes('OP_RETURN')) {
650
- continue;
651
- }
652
-
653
- // Log the found txid and beacon
654
- Logger.info(`Tx ${tx.txid} contains beacon address ${scriptPubKey.address} and OP_RETURN!`, tx);
655
-
656
- // Push the signal object to to signals array
657
- beaconSignals.push({
658
- beaconId : beacon.id,
659
- beaconType : beacon.type,
660
- beaconAddress : beacon.address,
661
- tx,
662
- blockheight : block.height,
663
- blocktime : block.time
664
- });
665
- };
666
- }
667
-
668
- height += 1;
669
- const tip = await bitcoin.network.rpc.getBlockCount();
670
- if(height > tip) {
671
- Logger.info(`Chain tip reached ${height}, breaking ...`);
672
- break;
673
- }
674
-
675
- // Reset the block to the next block
676
- block = await bitcoin.network.rpc.getBlock({ height }) as BlockV3;
677
- }
678
-
679
- return beaconSignals;
680
- }
681
-
682
- /**
683
- * Helper method for the {@link findNextSignals | Find Next Signals} algorithm.
684
- * @param {Array<BeaconService>} beacons The beacons to process.
685
- * @returns {Promise<Array<BeaconSignal>>} The beacon signals found in the block.
686
- */
687
- public static async findSignalsRest(beacons: Array<BeaconService>): Promise<Array<BeaconSignal>> {
688
- // Empty array of beaconSignals
689
- const beaconSignals = new Array<BeaconSignal>();
690
-
691
- // Iterate over each beacon
692
- for (const beacon of BeaconUtils.toBeaconServiceAddress(beacons)) {
693
- // Get the transactions for the beacon address via REST
694
- const transactions = await bitcoin.network.rest.address.getTxs(beacon.address);
695
-
696
- // If no transactions are found, continue
697
- if (!transactions || transactions.length === 0) {
698
- continue;
699
- }
700
-
701
- // Iterate over each transaction and push a beaconSignal
702
- for (const tx of transactions) {
703
- for(const vout of tx.vout) {
704
- if(vout.scriptpubkey_asm.includes('OP_RETURN')) {
705
- beaconSignals.push({
706
- beaconId : beacon.id,
707
- beaconType : beacon.type,
708
- beaconAddress : beacon.address,
709
- tx,
710
- blockheight : tx.status.block_height,
711
- blocktime : tx.status.block_time,
712
- });
713
- }
714
- }
715
- }
716
- }
717
-
718
- // Return the beaconSignals
719
- return beaconSignals;
720
- }
721
-
722
- /**
723
- * Implements {@link https://dcdpr.github.io/did-btcr2/#process-beacon-signals | 4.2.3.4 Process Beacon Signals}.
724
- *
725
- * The Process Beacon Signals algorithm processes each Beacon Signal by attempting to retrieve and validate an
726
- * announce DID Update Payload for that signal according to the type of the Beacon.
727
- *
728
- * It takes as inputs
729
- * - `beaconSignals`: An array of Beacon Signals retrieved from the Find Next Signals algorithm. Each signal contains:
730
- * - `beaconId`: The id for the Beacon that the signal was announced by.
731
- * - `beaconType`: The type of the Beacon that announced the signal.
732
- * - `tx`: The Bitcoin transaction that is the Beacon Signal.
733
- * - `signalsMetadata`: Maps Beacon Signal Bitcoin transaction ids to a SignalMetadata object containing:
734
- * - `updatePayload`: A DID Update Payload which should match the update announced by the Beacon Signal.
735
- * In the case of a SMT proof of non-inclusion, no DID Update Payload may be provided.
736
- * - `proofs`: Sparse Merkle Tree proof used to verify that the `updatePayload` exists as the leaf indexed by the
737
- * did:btcr2 identifier being resolved.
738
- *
739
- * It returns an array of {@link https://dcdpr.github.io/did-btcr2/#def-did-update-payload | DID Update Payloads}.
740
- *
741
- * @public
742
- * @param {BeaconSignal} signal The beacon signals to process.
743
- * @param {SignalsMetadata} signalsMetadata The sidecar data for the DID Document.
744
- * @returns {DidUpdatePayload[]} The updated DID Document object.
745
- */
746
- public static async processBeaconSignal(signal: BeaconSignal, signalsMetadata: SignalsMetadata): Promise<DidUpdatePayload> {
747
- // 1. Set updates to an empty array.
748
- const updates = new Array<DidUpdatePayload>();
749
-
750
- // 2. For beaconSignal in beaconSignals:
751
- // 2.1 Set type to beaconSignal.beaconType.
752
- // 2.2 Set signalTx to beaconSignal.tx.
753
- // 2.3 Set signalId to signalTx.id.
754
- const {
755
- beaconId: id,
756
- beaconType: type,
757
- beaconAddress: address,
758
- tx
759
- } = signal;
760
- const signalTx = tx as RawTransactionRest | RawTransactionV2;
761
-
762
- // 2.4 Set signalSidecarData to signalsMetadata[signalId]. TODO: formalize structure of sidecarData
763
- // const signalSidecarData = new Map(Object.entries(signalsMetadata)).get(id)!;
764
- // TODO: processBeaconSignal - formalize structure of sidecarData, signalSidecarData
765
-
766
- // 2.6 If type == SingletonBeacon:
767
- // 2.6.1 Set didUpdatePayload to the result of passing signalTx and signalSidecarData to Process Singleton Beacon Signal algorithm.
768
- // 2.7 If type == CIDAggregateBeacon:
769
- // 2.7.1 Set didUpdatePayload to the result of passing signalTx and signalSidecarData to the Process CIDAggregate Beacon Signal algorithm.
770
- // 2.8 If type == SMTAggregateBeacon:
771
- // 2.8.1 Set didUpdatePayload to the result of passing signalTx and signalSidecarData to the Process SMTAggregate Beacon Signal algorithm.
772
-
773
- // TODO: processBeaconSignal - where/how to convert signalsMetadata to diff sidecars
774
- const sidecar = { signalsMetadata } as SidecarData;
775
- // switch (type) {
776
- // case 'SingletonBeacon': {
777
- // sidecar = { signalsMetadata } as SingletonSidecar;
778
- // break;
779
- // }
780
- // case 'CIDAggregateBeacon': {
781
- // sidecar = {} as CIDAggregateSidecar;
782
- // break;
783
- // }
784
- // case 'SMTAggregateBeacon': {
785
- // sidecar = {} as SMTAggregateSidecar;
786
- // break;
787
- // }
788
- // default: {
789
- // throw new MethodError('Invalid beacon type', 'INVALID_BEACON_TYPE', { type });
790
- // }
791
- // }
792
-
793
- // Construct a service object from the beaconId and type
794
- // and set the serviceEndpoint to the BIP21 URI for the Bitcoin address.
795
- const service = { id, type, serviceEndpoint: `bitcoin:${address}` };
796
-
797
- // Establish a Beacon instance using the service and sidecar
798
- const beacon = BeaconFactory.establish(service, sidecar);
799
-
800
- // 2.5 Set didUpdate to null.
801
- const didUpdate = await beacon.processSignal(signalTx, signalsMetadata) ?? null;
802
-
803
- // If the updates is null, throw an error
804
- if (!didUpdate) {
805
- throw new MethodError('No didUpdate for beacon', 'PROCESS_BEACON_SIGNALS_ERROR', { tx, signalsMetadata });
806
- }
807
-
808
- // 2.9 If didUpdate is not null, push didUpdate to updates.
809
- updates.push(didUpdate);
810
-
811
- // 3. Return updates.
812
- return didUpdate;
813
- }
814
-
815
- /**
816
- * Implements {@link https://dcdpr.github.io/did-btcr2/#confirm-duplicate-update | 7.2.2.4 Confirm Duplicate Update}.
817
- *
818
- * The Confirm Duplicate Update algorithm takes in a {@link DidUpdatePayload | DID Update Payload} and verifies that
819
- * the update is a duplicate against the hash history of previously applied updates. The algorithm takes in an update
820
- * and an array of hashes, updateHashHistory. It throws an error if the update is not a duplicate, otherwise it
821
- * returns.
822
- *
823
- * @public
824
- * @param {{ update: DidUpdatePayload; updateHashHistory: string[]; }} params Parameters for confirmDuplicateUpdate.
825
- * @param {DidUpdatePayload} params.update The DID Update Payload to confirm.
826
- * @param {Array<string>} params.updateHashHistory The history of hashes for previously applied updates.
827
- * @returns {Promise<void>} A promise that resolves if the update is a duplicate, otherwise throws an error.
828
- * @throws {ResolveError} if the update hash does not match the historical hash.
829
- */
830
- public static async confirmDuplicateUpdate({ update, updateHashHistory }: {
831
- update: DidUpdatePayload;
832
- updateHashHistory: string[];
833
- }): Promise<void> {
834
- // 1. Let unsecuredUpdate be a copy of the update object.
835
- const unsecuredUpdate = update;
836
-
837
- // 2. Remove the proof property from the unsecuredUpdate object.
838
- delete unsecuredUpdate.proof;
839
-
840
- // 3. Let updateHash equal the result of passing unsecuredUpdate into the JSON Canonicalization and Hash algorithm.
841
- const updateHash = await JSON.canonicalization.process(unsecuredUpdate);
842
-
843
- // 4. Let updateHashIndex equal update.targetVersionId - 2.
844
- // const updateHashIndex = update.targetVersionId - 2;
845
-
846
- // 5. Let historicalUpdateHash equal updateHashHistory[updateHashIndex].
847
- const historicalUpdateHash = updateHashHistory[update.targetVersionId - 2];
848
-
849
- // Check if the updateHash matches the historical hash
850
- if (historicalUpdateHash !== updateHash) {
851
- throw new ResolveError(
852
- `Invalid duplicate: ${updateHash} does not match ${historicalUpdateHash}`,
853
- 'LATE_PUBLISHING_ERROR', { updateHash, updateHashHistory }
854
- );
855
- }
856
- }
857
-
858
- /**
859
- * Implements {@link https://dcdpr.github.io/did-btcr2/#apply-did-update | 4.2.3.6 Apply DID Update}.
860
- *
861
- * This algorithm attempts to apply a DID Update to a DID document, it first verifies the proof on the update is a
862
- * valid capabilityInvocation of the root authority over the DID being resolved. Then it applies the JSON patch
863
- * transformation to the DID document, checks the transformed DID document matches the targetHash specified by the
864
- * update and validates it is a conformant DID document before returning it. This algorithm takes inputs
865
- * contemporaryDidDocument and an update.
866
- *
867
- * @public
868
- * @param {ApplyDidUpdateParams} params Parameters for applyDidUpdate.
869
- * @param {DidDocument} params.contemporaryDidDocument The current DID Document to update.
870
- * @param {DidUpdatePayload} params.update The DID Update Payload to apply.
871
- * @param {Bytes} params.genesisBytes The genesis bytes for the DID Document.
872
- * @returns {Promise<DidDocument>}
873
- */
874
- public static async applyDidUpdate({ contemporaryDidDocument, update }: {
875
- contemporaryDidDocument: DidDocument;
876
- update: DidUpdatePayload;
877
- }): Promise<DidDocument> {
878
- // 1. Set capabilityId to update.proof.capability.
879
- const capabilityId = update.proof?.capability;
880
- if (!capabilityId) {
881
- throw new ResolveError('No capabilityId found in update', INVALID_DID_UPDATE);
882
- }
883
-
884
- // 2. Set rootCapability to the result of passing capabilityId to the Dereference Root Capability Identifier algorithm.
885
- const rootCapability = Appendix.derefernceRootCapabilityIdentifier(capabilityId);
886
-
887
- // 3. If rootCapability.invocationTarget does not equal contemporaryDidDocument.id
888
- // and rootCapability.controller does not equal contemporaryDidDocument.id, MUST throw an invalidDidUpdate error.
889
- const { invocationTarget, controller: rootController } = rootCapability;
890
- if (![invocationTarget, rootController].every((id) => id === contemporaryDidDocument.id)) {
891
- throw new ResolveError(`Invalid root capability: ${rootCapability}`, INVALID_DID_UPDATE);
892
- }
893
-
894
- // 4. Instantiate a bip340-jcs-2025 cryptosuite instance using the key referenced by the verificationMethod field in the update.
895
- // Get the verificationMethod field from the update.
896
- const methodId = update.proof?.verificationMethod;
897
- if(!methodId) {
898
- throw new ResolveError('No verificationMethod found in update', INVALID_DID_UPDATE, update);
899
- }
900
-
901
- // Get the verificationMethod from the DID Document using the methodId.
902
- const { id: vmId, publicKeyMultibase } = DidBtcr2.getSigningMethod({ didDocument: contemporaryDidDocument, methodId });
903
-
904
- // Split the vmId by the `#` to get the id and controller.
905
- const [controller, id] = vmId.split('#');
906
-
907
- // Construct a new Multikey.
908
- const multikey = SchnorrMultikey.fromPublicKeyMultibase({ id: `#${id}`, controller, publicKeyMultibase });
909
- const cryptosuite = new Cryptosuite({ cryptosuite: 'bip340-jcs-2025', multikey });
910
-
911
- // 7. Set documentBytes to the bytes representation of update.
912
- const documentBytes = await JSON.canonicalization.canonicalize(update);
913
-
914
- // 8. Set verificationResult to the result of passing mediaType, documentBytes, cryptosuite, and
915
- // expectedProofPurpose into the Verify Proof algorithm defined in the VC Data Integrity specification.
916
- const diProof = new DataIntegrityProof(cryptosuite);
917
- const verificationResult = await diProof.verifyProof({ document: documentBytes, expectedPurpose: 'capabilityInvocation' });
918
-
919
- // 9. If verificationResult.verified equals False, MUST raise a invalidUpdateProof exception.
920
- if (!verificationResult.verified) {
921
- throw new MethodError('Invalid update: proof not verified', INVALID_DID_UPDATE, verificationResult);
922
- }
923
-
924
- // 10. Set targetDIDDocument to a copy of contemporaryDidDocument.
925
- let targetDIDDocument = contemporaryDidDocument;
926
-
927
- // 11. Use JSON Patch to apply the update.patch to the targetDIDDOcument.
928
- targetDIDDocument = JSON.patch.apply(targetDIDDocument, update.patch) as DidDocument;
929
-
930
- // 12. Verify that targetDIDDocument is conformant with the data model specified by the DID Core specification.
931
- DidDocument.validate(targetDIDDocument);
932
-
933
- // 13. Set targetHash to the SHA256 hash of targetDIDDocument.
934
- const targetHash = await JSON.canonicalization.process(targetDIDDocument, 'base58');
935
-
936
- // Prepend the sourceHash if it does not start with `z`
937
- const updateTargetHash = update.targetHash.startsWith('z')
938
- ? update.targetHash
939
- : `z${update.targetHash}`;
940
- // 14. Check that targetHash equals update.targetHash, else raise InvalidDIDUpdate error.
941
- if (updateTargetHash !== targetHash) {
942
- throw new MethodError(`Invalid update: updateTargetHash ${updateTargetHash} does not match targetHash ${targetHash}`, INVALID_DID_UPDATE);
943
- }
944
-
945
- // 15. Return targetDIDDocument.
946
- return targetDIDDocument;
947
- }
948
- }