@bsv/dpp-core 0.3.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/LICENSE +58 -0
  2. package/README.md +95 -0
  3. package/dist/acceptance.d.ts +100 -0
  4. package/dist/acceptance.d.ts.map +1 -0
  5. package/dist/acceptance.js +202 -0
  6. package/dist/acceptance.js.map +1 -0
  7. package/dist/anchor.d.ts +66 -0
  8. package/dist/anchor.d.ts.map +1 -0
  9. package/dist/anchor.js +145 -0
  10. package/dist/anchor.js.map +1 -0
  11. package/dist/attestation.d.ts +40 -0
  12. package/dist/attestation.d.ts.map +1 -0
  13. package/dist/attestation.js +111 -0
  14. package/dist/attestation.js.map +1 -0
  15. package/dist/blob.d.ts +11 -0
  16. package/dist/blob.d.ts.map +1 -0
  17. package/dist/blob.js +16 -0
  18. package/dist/blob.js.map +1 -0
  19. package/dist/canonical.d.ts +32 -0
  20. package/dist/canonical.d.ts.map +1 -0
  21. package/dist/canonical.js +54 -0
  22. package/dist/canonical.js.map +1 -0
  23. package/dist/canonicalJson.d.ts +22 -0
  24. package/dist/canonicalJson.d.ts.map +1 -0
  25. package/dist/canonicalJson.js +60 -0
  26. package/dist/canonicalJson.js.map +1 -0
  27. package/dist/codec.d.ts +45 -0
  28. package/dist/codec.d.ts.map +1 -0
  29. package/dist/codec.js +459 -0
  30. package/dist/codec.js.map +1 -0
  31. package/dist/constants.d.ts +150 -0
  32. package/dist/constants.d.ts.map +1 -0
  33. package/dist/constants.js +179 -0
  34. package/dist/constants.js.map +1 -0
  35. package/dist/did.d.ts +37 -0
  36. package/dist/did.d.ts.map +1 -0
  37. package/dist/did.js +129 -0
  38. package/dist/did.js.map +1 -0
  39. package/dist/evidence.d.ts +224 -0
  40. package/dist/evidence.d.ts.map +1 -0
  41. package/dist/evidence.js +716 -0
  42. package/dist/evidence.js.map +1 -0
  43. package/dist/evidencePackage.d.ts +114 -0
  44. package/dist/evidencePackage.d.ts.map +1 -0
  45. package/dist/evidencePackage.js +164 -0
  46. package/dist/evidencePackage.js.map +1 -0
  47. package/dist/index.d.ts +31 -0
  48. package/dist/index.d.ts.map +1 -0
  49. package/dist/index.js +31 -0
  50. package/dist/index.js.map +1 -0
  51. package/dist/owner.d.ts +135 -0
  52. package/dist/owner.d.ts.map +1 -0
  53. package/dist/owner.js +181 -0
  54. package/dist/owner.js.map +1 -0
  55. package/dist/publisherPolicy.d.ts +70 -0
  56. package/dist/publisherPolicy.d.ts.map +1 -0
  57. package/dist/publisherPolicy.js +186 -0
  58. package/dist/publisherPolicy.js.map +1 -0
  59. package/dist/signatures.d.ts +84 -0
  60. package/dist/signatures.d.ts.map +1 -0
  61. package/dist/signatures.js +137 -0
  62. package/dist/signatures.js.map +1 -0
  63. package/dist/transition.d.ts +29 -0
  64. package/dist/transition.d.ts.map +1 -0
  65. package/dist/transition.js +117 -0
  66. package/dist/transition.js.map +1 -0
  67. package/dist/types.d.ts +135 -0
  68. package/dist/types.d.ts.map +1 -0
  69. package/dist/types.js +2 -0
  70. package/dist/types.js.map +1 -0
  71. package/dist/verifyChain.d.ts +152 -0
  72. package/dist/verifyChain.d.ts.map +1 -0
  73. package/dist/verifyChain.js +314 -0
  74. package/dist/verifyChain.js.map +1 -0
  75. package/package.json +46 -0
  76. package/schemas/capabilities.schema.json +129 -0
  77. package/schemas/epcis-import.schema.json +212 -0
  78. package/schemas/evidence-export.schema.json +67 -0
  79. package/schemas/evidence-package.schema.json +307 -0
  80. package/schemas/native-evidence-extension.schema.json +66 -0
  81. package/schemas/paginated-history.schema.json +32 -0
  82. package/schemas/passport-projection.schema.json +151 -0
  83. package/schemas/passport-source.schema.json +370 -0
  84. package/schemas/profile-evidence.schema.json +706 -0
  85. package/schemas/publisher-policy.schema.json +173 -0
  86. package/schemas/verification-report.schema.json +397 -0
package/LICENSE ADDED
@@ -0,0 +1,58 @@
1
+ Open BSV License Version 6 – granted by BSV Association, Alpenstrasse 15, 6300
2
+ Zug, Switzerland (CHE-427.008.338) ("Licensor"), to you as a user (henceforth
3
+ "You", "User" or "Licensee").
4
+
5
+ For the purposes of this license, the definitions below have the following
6
+ meanings:
7
+
8
+ "Bitcoin Protocol" means the protocol implementation, cryptographic rules,
9
+ network protocols, and consensus mechanisms in the Bitcoin White Paper as
10
+ described here https://protocol.bsvblockchain.org.
11
+
12
+ "Bitcoin White Paper" means the paper entitled 'Bitcoin: A Peer-to-Peer
13
+ Electronic Cash System' published by 'Satoshi Nakamoto' in October 2008.
14
+
15
+ "BSV Blockchain" means:
16
+
17
+ (a) the Bitcoin blockchain containing block height #556767 with the hash
18
+ "000000000000000001d956714215d96ffc00e0afda4cd0a96c96f8d802b1662b" and
19
+ that contains the longest honest persistent chain of blocks which has been
20
+ produced in a manner which is consistent with the rules set forth in the
21
+ Network Access Rules; and
22
+ (b) the test blockchains that contain the longest honest persistent chains of
23
+ blocks which has been produced in a manner which is consistent with the
24
+ rules set forth in the Network Access Rules.
25
+
26
+ "Network Access Rules" or "Rules" means the set of rules regulating the
27
+ relationship between BSV Association and the nodes on BSV based on the Bitcoin
28
+ Protocol rules and those set out in the Bitcoin White Paper, and available here
29
+ https://bsvblockchain.org/network-access-rules.
30
+
31
+ "Software" means the software the subject of this license, including any/all
32
+ intellectual property rights therein and associated documentation files.
33
+
34
+ BSV Association grants permission, free of charge and on a non-exclusive basis
35
+ to any person obtaining a copy of the Software to deal in the Software, including
36
+ without limitation the rights to use, copy, modify, merge, publish, distribute,
37
+ sublicense, and/or sell copies of the Software, and to permit persons to whom the
38
+ Software is furnished to do so, subject to and conditioned upon the following
39
+ conditions:
40
+
41
+ 1 - The text "© BSV Association", and this license shall be included in all
42
+ copies or substantial portions of the Software.
43
+
44
+ 2 - The Software, and any software that is derived from the Software or parts
45
+ thereof, may only be used exclusively on the BSV Blockchain.
46
+
47
+ For the avoidance of doubt, this license is granted subject to and conditioned
48
+ upon your compliance with these terms only and is limited to uses on the BSV
49
+ Blockchain. Any exercise of rights not compliant with these terms including
50
+ use not for the BSV Blockchain is deemed outside the scope of the license.
51
+
52
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
53
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES REGARDING ENTITLEMENT,
54
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
55
+ EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS THEREOF BE LIABLE FOR ANY CLAIM,
56
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
57
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
58
+ DEALINGS IN THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,95 @@
1
+ # @bsv/dpp-core
2
+
3
+ **Experimental prerelease:** For implementation and interoperability testing. APIs may change significantly before a stable release. Pin exact package versions and retain your lockfile. This package is not declared production-ready. Package versions are separate from the specification, wire-format and frozen profile versions they implement.
4
+
5
+ The DPP standard's reference implementation for record versions 1 and 2, the
6
+ attestation rail and the verification report, and the only place in this
7
+ repository the standard's rules are implemented. Everything else in the
8
+ reference implementation imports it: the overlay topic manager admits outputs
9
+ by asking this package whether a state is valid, and the consuming
10
+ applications build and verify every record through it. An independent
11
+ implementation does not import it; it reproduces the same rules from `spec/`
12
+ and holds itself to the same `fixtures/`.
13
+
14
+ Standard v1 is v0 plus the JSON field conventions (`spec/record-model.md` §3,
15
+ fields 9 and 10). The 14-field layout and the
16
+ chain invariants are untouched from v0, which is why the suite here was ported
17
+ rather than rewritten.
18
+
19
+ ## Install and consume
20
+
21
+ This is a pre-1.0 candidate. Once the release is published, install exact versions from npm:
22
+
23
+ ```sh
24
+ npm install --save-exact @bsv/dpp-core@0.3.0-beta.1 @bsv/sdk@2.4.2
25
+ ```
26
+
27
+ Node >=22 and ECMAScript modules are supported. Browser use of the runtime is untested. No source checkout or build of this package is needed after installation.
28
+
29
+ ```js
30
+ import { PrivateKey, ProtoWallet } from '@bsv/sdk'
31
+ import { didKeyFromIdentityKey, signLifecycleClaim, verifyLifecycleClaim } from '@bsv/dpp-core'
32
+
33
+ const key = PrivateKey.fromRandom()
34
+ const claim = await signLifecycleClaim({
35
+ claimFormat: 'dpp-lifecycle-v1',
36
+ passportId: 'https://example.com/01/09521000000018/21/EXAMPLE',
37
+ recordId: '0'.repeat(64), // Synthetic record identifier for this offline example.
38
+ eventType: 'Origin',
39
+ timestamp: new Date().toISOString(),
40
+ issuer: didKeyFromIdentityKey(key.toPublicKey().toString()),
41
+ issuerKeyId: 'example',
42
+ profile: 'general',
43
+ profile_version: 2,
44
+ }, new ProtoWallet(key))
45
+ console.log(verifyLifecycleClaim(claim))
46
+ ```
47
+
48
+ This offline example creates a temporary key and signs a claim. Production callers supply their authorised signing capability. Signature verification alone does not establish authority, current status or blockchain inclusion.
49
+
50
+ The `@bsv/dpp-core/schemas/*` export carries the standard's JSON schemas. For example, load `@bsv/dpp-core/schemas/verification-report.schema.json` using a JSON import or Node's `createRequire`. The evidence export schema and its referenced evidence package schema are shipped together. They are data files and may also be used by other runtimes.
51
+
52
+ ## Public API
53
+
54
+ `src/index.ts` re-exports the whole surface, so `@bsv/dpp-core` is the only
55
+ specifier anything needs:
56
+
57
+ | Module | What it owns |
58
+ |---|---|
59
+ | `codec.ts` | The 14-field version 1 layout and the 17-field version 2 layout, selected by field count: encode and decode per `spec/record-model.md` §3 and `spec/record-model-v2.md` §3 |
60
+ | `signatures.ts` | The canonical signature preimages: unframed for version 1 (§5), framed and domain-tagged for version 2 (`record-model-v2.md` §5) |
61
+ | `transition.ts` | Which operation may change what, state by state, for both versions: the version 2 control proof, the terminal `RETIRE` and the single upgrade transition |
62
+ | `owner.ts` | The owner and controller key, the linkage scalar, the owner-signed transfer of version 1 and the control proof of version 2 |
63
+ | `acceptance.ts` | The managed acceptance record `dpp-managed-acceptance@1` (`spec/managed-custody.md` §3): inspect, sign, commit and bind to the `TRANSFER` |
64
+ | `verifyChain.ts` | Chain verification from genesis, including SPV inclusion; `inspectChain` is the same loop reported finding by finding |
65
+ | `evidence.ts` | `verifyPassportEvidence`, the one verification contract of `spec/verification.md`: sixteen named checks, four answers each, an expected subject and a latest-state observation, across the token, attestation, anchor and credential rails |
66
+ | `anchor.ts` | The generic complete-representation anchor `bsv-attestation-anchor-v1` (`spec/rules.md` §5): build, strict decode and check-by-check inspection |
67
+ | `attestation.ts` | Native lifecycle claims `dpp-lifecycle-v1` (`spec/rules.md` §3): validate, sign, verify and digest |
68
+ | `blob.ts` | Owner-tier blob hash binding (§7) |
69
+ | `canonical.ts` | The canonical bytes an attestation is signed and hashed over: a refusing subset of JCS (`spec/rules.md` §4) |
70
+ | `constants.ts`, `types.ts` | The shared vocabulary both of the above are written against |
71
+
72
+ ## Working on it
73
+
74
+ ```
75
+ npm run build # tsc to dist/, which is what the exports map points at
76
+ npm run typecheck # the same compile, emitting nothing
77
+ npm test # the whole suite runs offline
78
+ ```
79
+
80
+ The build matters. `main`, `types` and the `exports` map all point into
81
+ `dist/`, and nothing aliases the specifier back to `src/`, so a consumer that
82
+ has not built this package fails to resolve it rather than falling back to
83
+ source. A fresh clone should run `npm run build --workspaces` before anything
84
+ that imports `@bsv/dpp-core`.
85
+
86
+ ## The rule that governs it
87
+
88
+ Within the reference implementation this package is the single place the
89
+ standard's rules are coded, and no reference consumer reimplements any of it:
90
+ if a consumer needs behaviour that is not here, the change belongs here, with a
91
+ test. The normative text is the specification, not this package: `spec/`
92
+ defines the rules, `fixtures/` pins the bytes, and an independent
93
+ implementation reproduces both without this code. Where this package and the
94
+ specification disagree before version 1.0, `GOVERNANCE.md` names the
95
+ tiebreaker.
@@ -0,0 +1,100 @@
1
+ import { MANAGED_CUSTODY_PROFILE } from './constants.js';
2
+ import type { DppStateV2, Outpoint } from './types.js';
3
+ /**
4
+ * The managed acceptance record (`spec/managed-custody.md` §3): the evidence a
5
+ * custodian retains that the current holder offered a transfer and the
6
+ * intended recipient accepted it through the application, before the
7
+ * custodian spent the tip. A version 2 TRANSFER under the profile carries
8
+ * `authorisation_commitment` equal to the SHA-256 of this record's canonical
9
+ * JSON, signature included, so the on-chain state binds the acceptance and the
10
+ * record binds the exact predecessor, destination key, terms and expiry.
11
+ *
12
+ * What it is: custody-dependent evidence. The custodian signs it; the
13
+ * recipient's key never does. A reader learns that the custodian observed an
14
+ * acceptance under these terms and that the transfer it executed matches them.
15
+ * It is not a signature made with a key the recipient controls, and the record
16
+ * says so in `acceptance.evidenceKind`. A profile that needs recipient-signed
17
+ * acceptance is a later profile with its own record format.
18
+ *
19
+ * What stays out: application account identifiers, claim codes, names and
20
+ * contact details. The recipient is named by the identity key the destination
21
+ * derives from, and a claim code by its SHA-256, so the record can be exported
22
+ * with the passport's public evidence.
23
+ */
24
+ export declare const MANAGED_ACCEPTANCE_FORMAT: "dpp-managed-acceptance@1";
25
+ export { MANAGED_CUSTODY_PROFILE };
26
+ export type OfferMechanism = 'claim-code' | 'named-recipient';
27
+ export interface ManagedAcceptanceClaim {
28
+ acceptanceFormat: typeof MANAGED_ACCEPTANCE_FORMAT;
29
+ /** Unique per offer; a retry names the same request and never a second one. */
30
+ requestId: string;
31
+ passportId: string;
32
+ lineageGenesis: Outpoint;
33
+ /** The tip the offer was made against; the TRANSFER must spend exactly this. */
34
+ expectedPredecessor: Outpoint;
35
+ /** SHA-256, hex, of the terms as the application presented them to the recipient (the story word, a note, revised restricted values), in the application's own canonical form. */
36
+ termsDigest: string;
37
+ offer: {
38
+ /** The current holder's actor identity key, the key field 7 of the TRANSFER carries. */
39
+ holderIdentityKey: string;
40
+ createdAt: string;
41
+ expiresAt: string;
42
+ mechanism: OfferMechanism;
43
+ /** claim-code: SHA-256 of the code, hex; named-recipient: the recipient's identity key. Absent when the mechanism carries nothing to reference. */
44
+ recipientRef?: string;
45
+ };
46
+ acceptance: {
47
+ /** The recipient's actor identity key, from which the destination derives. */
48
+ recipientIdentityKey: string;
49
+ /** The controller key the TRANSFER moves control to: field 6 of the TRANSFER. */
50
+ destinationKey: string;
51
+ acceptedAt: string;
52
+ /** Always custodian-attested under this format; named so a reader never mistakes it for a recipient signature. */
53
+ evidenceKind: 'custodian-attested';
54
+ };
55
+ /** The custodian's identity key, compressed hex, which signs the record. */
56
+ custodian: string;
57
+ }
58
+ export interface ManagedAcceptanceRecord extends ManagedAcceptanceClaim {
59
+ /** DER ECDSA, lowercase hex, over SHA-256 of the canonical JSON of the record without this property. */
60
+ signature: string;
61
+ }
62
+ export interface AcceptanceSigner {
63
+ sign(preimage: number[]): Promise<number[]> | number[];
64
+ }
65
+ export type AcceptanceFailureReason = 'format' | 'time-order' | 'signature-invalid' | 'custodian-unexpected' | 'state-mismatch';
66
+ export interface AcceptanceFailure {
67
+ reason: AcceptanceFailureReason;
68
+ detail: string;
69
+ }
70
+ export interface AcceptanceInspection {
71
+ /** The record has the declared shape and its own declarations agree. */
72
+ structureValid: boolean;
73
+ /** The custodian's signature over the canonical record, or null when the record could not be canonicalised. */
74
+ signatureValid: boolean | null;
75
+ /** SHA-256 of the complete signed record in canonical JSON: what a TRANSFER commits to. Present when the record canonicalises. */
76
+ commitment?: string;
77
+ failures: AcceptanceFailure[];
78
+ }
79
+ /** The bytes the custodian signs: the record without `signature`, in canonical JSON, UTF-8. */
80
+ export declare function acceptanceSigningPreimage(claim: ManagedAcceptanceClaim | ManagedAcceptanceRecord): number[];
81
+ /** The commitment a TRANSFER carries in field 15: SHA-256 of the complete signed record, canonical JSON. */
82
+ export declare function acceptanceCommitment(record: ManagedAcceptanceRecord): string;
83
+ /**
84
+ * Inspect a record on its own: structure, the custodian's signature and, when
85
+ * the caller names the custodians it trusts, whether the signer is one of
86
+ * them. Binding to the TRANSFER that commits to it is `bindAcceptanceToState`.
87
+ */
88
+ export declare function inspectManagedAcceptance(value: unknown, options?: {
89
+ custodians?: readonly string[];
90
+ }): AcceptanceInspection;
91
+ /**
92
+ * Whether a version 2 TRANSFER executed exactly the acceptance the record
93
+ * evidences: same passport and lineage, the tip the offer named, the
94
+ * destination the recipient accepted, the holder who offered as the actor,
95
+ * and the record's own commitment in field 15. Every mismatch is named.
96
+ */
97
+ export declare function bindAcceptanceToState(record: ManagedAcceptanceRecord, state: DppStateV2): AcceptanceFailure[];
98
+ /** Sign a claim as the custodian. The signer's key must be `claim.custodian`; the result is checked before it is returned. */
99
+ export declare function signManagedAcceptance(claim: ManagedAcceptanceClaim, signer: AcceptanceSigner): Promise<ManagedAcceptanceRecord>;
100
+ //# sourceMappingURL=acceptance.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"acceptance.d.ts","sourceRoot":"","sources":["../src/acceptance.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAA;AACxD,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAEtD;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,eAAO,MAAM,yBAAyB,EAAG,0BAAmC,CAAA;AAC5E,OAAO,EAAE,uBAAuB,EAAE,CAAA;AAElC,MAAM,MAAM,cAAc,GAAG,YAAY,GAAG,iBAAiB,CAAA;AAE7D,MAAM,WAAW,sBAAsB;IACrC,gBAAgB,EAAE,OAAO,yBAAyB,CAAA;IAClD,+EAA+E;IAC/E,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;IAClB,cAAc,EAAE,QAAQ,CAAA;IACxB,gFAAgF;IAChF,mBAAmB,EAAE,QAAQ,CAAA;IAC7B,kLAAkL;IAClL,WAAW,EAAE,MAAM,CAAA;IACnB,KAAK,EAAE;QACL,wFAAwF;QACxF,iBAAiB,EAAE,MAAM,CAAA;QACzB,SAAS,EAAE,MAAM,CAAA;QACjB,SAAS,EAAE,MAAM,CAAA;QACjB,SAAS,EAAE,cAAc,CAAA;QACzB,mJAAmJ;QACnJ,YAAY,CAAC,EAAE,MAAM,CAAA;KACtB,CAAA;IACD,UAAU,EAAE;QACV,8EAA8E;QAC9E,oBAAoB,EAAE,MAAM,CAAA;QAC5B,iFAAiF;QACjF,cAAc,EAAE,MAAM,CAAA;QACtB,UAAU,EAAE,MAAM,CAAA;QAClB,kHAAkH;QAClH,YAAY,EAAE,oBAAoB,CAAA;KACnC,CAAA;IACD,4EAA4E;IAC5E,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,uBAAwB,SAAQ,sBAAsB;IACrE,wGAAwG;IACxG,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,GAAG,MAAM,EAAE,CAAA;CACvD;AAQD,MAAM,MAAM,uBAAuB,GAC/B,QAAQ,GACR,YAAY,GACZ,mBAAmB,GACnB,sBAAsB,GACtB,gBAAgB,CAAA;AAEpB,MAAM,WAAW,iBAAiB;IAAG,MAAM,EAAE,uBAAuB,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE;AAEtF,MAAM,WAAW,oBAAoB;IACnC,wEAAwE;IACxE,cAAc,EAAE,OAAO,CAAA;IACvB,+GAA+G;IAC/G,cAAc,EAAE,OAAO,GAAG,IAAI,CAAA;IAC9B,kIAAkI;IAClI,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,QAAQ,EAAE,iBAAiB,EAAE,CAAA;CAC9B;AAUD,+FAA+F;AAC/F,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,sBAAsB,GAAG,uBAAuB,GAAG,MAAM,EAAE,CAG3G;AAED,4GAA4G;AAC5G,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,uBAAuB,GAAG,MAAM,CAE5E;AA6DD;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,GAAE;IAAE,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAAO,GAAG,oBAAoB,CAoB/H;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,uBAAuB,EAAE,KAAK,EAAE,UAAU,GAAG,iBAAiB,EAAE,CAY7G;AAED,8HAA8H;AAC9H,wBAAsB,qBAAqB,CAAC,KAAK,EAAE,sBAAsB,EAAE,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAWrI"}
@@ -0,0 +1,202 @@
1
+ import { Hash, PublicKey, Signature, Utils } from '@bsv/sdk';
2
+ import { canonicalJson, CanonicalJsonError } from './canonicalJson.js';
3
+ import { MANAGED_CUSTODY_PROFILE } from './constants.js';
4
+ /**
5
+ * The managed acceptance record (`spec/managed-custody.md` §3): the evidence a
6
+ * custodian retains that the current holder offered a transfer and the
7
+ * intended recipient accepted it through the application, before the
8
+ * custodian spent the tip. A version 2 TRANSFER under the profile carries
9
+ * `authorisation_commitment` equal to the SHA-256 of this record's canonical
10
+ * JSON, signature included, so the on-chain state binds the acceptance and the
11
+ * record binds the exact predecessor, destination key, terms and expiry.
12
+ *
13
+ * What it is: custody-dependent evidence. The custodian signs it; the
14
+ * recipient's key never does. A reader learns that the custodian observed an
15
+ * acceptance under these terms and that the transfer it executed matches them.
16
+ * It is not a signature made with a key the recipient controls, and the record
17
+ * says so in `acceptance.evidenceKind`. A profile that needs recipient-signed
18
+ * acceptance is a later profile with its own record format.
19
+ *
20
+ * What stays out: application account identifiers, claim codes, names and
21
+ * contact details. The recipient is named by the identity key the destination
22
+ * derives from, and a claim code by its SHA-256, so the record can be exported
23
+ * with the passport's public evidence.
24
+ */
25
+ export const MANAGED_ACCEPTANCE_FORMAT = 'dpp-managed-acceptance@1';
26
+ export { MANAGED_CUSTODY_PROFILE };
27
+ const KEY = /^0[23][0-9a-f]{64}$/;
28
+ const HEX64 = /^[0-9a-f]{64}$/;
29
+ const TIME = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:\d{2})$/;
30
+ const CONTROL = /[\u0000-\u001f\u007f-\u009f]/u;
31
+ const MAX_REQUEST_ID = 128;
32
+ const text = (value, maximum) => typeof value === 'string' && value.length > 0 && Utils.toArray(value, 'utf8').length <= maximum && !CONTROL.test(value);
33
+ const outpointOk = (value) => typeof value === 'object' && value !== null && HEX64.test(value.txid ?? '') && Number.isInteger(value.outputIndex) && value.outputIndex >= 0;
34
+ const instant = (value) => Date.parse(value);
35
+ /** The bytes the custodian signs: the record without `signature`, in canonical JSON, UTF-8. */
36
+ export function acceptanceSigningPreimage(claim) {
37
+ const { signature: _signature, ...unsigned } = claim;
38
+ return Utils.toArray(canonicalJson(unsigned), 'utf8');
39
+ }
40
+ /** The commitment a TRANSFER carries in field 15: SHA-256 of the complete signed record, canonical JSON. */
41
+ export function acceptanceCommitment(record) {
42
+ return Utils.toHex(Hash.sha256(Utils.toArray(canonicalJson(record), 'utf8')));
43
+ }
44
+ function structure(value, failures) {
45
+ const fail = (reason, detail) => { failures.push({ reason, detail }); };
46
+ if (value === null || typeof value !== 'object' || Array.isArray(value)) {
47
+ fail('format', 'the record must be an object');
48
+ return false;
49
+ }
50
+ const r = value;
51
+ const allowed = new Set(['acceptanceFormat', 'requestId', 'passportId', 'lineageGenesis', 'expectedPredecessor', 'termsDigest', 'offer', 'acceptance', 'custodian', 'signature']);
52
+ for (const key of Object.keys(r))
53
+ if (!allowed.has(key))
54
+ fail('format', `unsupported property ${key}`);
55
+ if (r.acceptanceFormat !== MANAGED_ACCEPTANCE_FORMAT)
56
+ fail('format', `acceptanceFormat is not ${MANAGED_ACCEPTANCE_FORMAT}`);
57
+ if (!text(r.requestId, MAX_REQUEST_ID))
58
+ fail('format', `requestId must be printable text of at most ${MAX_REQUEST_ID} bytes`);
59
+ if (!text(r.passportId, 512))
60
+ fail('format', 'passportId must be printable text of at most 512 bytes');
61
+ if (!outpointOk(r.lineageGenesis))
62
+ fail('format', 'lineageGenesis must be an outpoint');
63
+ if (!outpointOk(r.expectedPredecessor))
64
+ fail('format', 'expectedPredecessor must be an outpoint');
65
+ if (!HEX64.test(String(r.termsDigest ?? '')))
66
+ fail('format', 'termsDigest must be 64 lowercase hex characters');
67
+ const offer = r.offer;
68
+ if (offer == null || typeof offer !== 'object' || Array.isArray(offer))
69
+ fail('format', 'offer must be an object');
70
+ else {
71
+ for (const key of Object.keys(offer))
72
+ if (!['holderIdentityKey', 'createdAt', 'expiresAt', 'mechanism', 'recipientRef'].includes(key))
73
+ fail('format', `unsupported offer property ${key}`);
74
+ if (!KEY.test(String(offer.holderIdentityKey ?? '')))
75
+ fail('format', 'offer.holderIdentityKey must be a compressed public key');
76
+ if (!TIME.test(String(offer.createdAt ?? '')) || !Number.isFinite(instant(String(offer.createdAt))))
77
+ fail('format', 'offer.createdAt must be an ISO date-time with a timezone');
78
+ if (!TIME.test(String(offer.expiresAt ?? '')) || !Number.isFinite(instant(String(offer.expiresAt))))
79
+ fail('format', 'offer.expiresAt must be an ISO date-time with a timezone');
80
+ if (offer.mechanism !== 'claim-code' && offer.mechanism !== 'named-recipient')
81
+ fail('format', 'offer.mechanism must be claim-code or named-recipient');
82
+ if (offer.recipientRef !== undefined && !(offer.mechanism === 'claim-code' ? HEX64.test(String(offer.recipientRef)) : KEY.test(String(offer.recipientRef)))) {
83
+ fail('format', 'offer.recipientRef must be a SHA-256 for a claim code or a compressed key for a named recipient');
84
+ }
85
+ }
86
+ const acceptance = r.acceptance;
87
+ if (acceptance == null || typeof acceptance !== 'object' || Array.isArray(acceptance))
88
+ fail('format', 'acceptance must be an object');
89
+ else {
90
+ for (const key of Object.keys(acceptance))
91
+ if (!['recipientIdentityKey', 'destinationKey', 'acceptedAt', 'evidenceKind'].includes(key))
92
+ fail('format', `unsupported acceptance property ${key}`);
93
+ if (!KEY.test(String(acceptance.recipientIdentityKey ?? '')))
94
+ fail('format', 'acceptance.recipientIdentityKey must be a compressed public key');
95
+ if (!KEY.test(String(acceptance.destinationKey ?? '')))
96
+ fail('format', 'acceptance.destinationKey must be a compressed public key');
97
+ if (!TIME.test(String(acceptance.acceptedAt ?? '')) || !Number.isFinite(instant(String(acceptance.acceptedAt))))
98
+ fail('format', 'acceptance.acceptedAt must be an ISO date-time with a timezone');
99
+ if (acceptance.evidenceKind !== 'custodian-attested')
100
+ fail('format', 'acceptance.evidenceKind must be custodian-attested');
101
+ }
102
+ if (!KEY.test(String(r.custodian ?? '')))
103
+ fail('format', 'custodian must be a compressed public key');
104
+ if (typeof r.signature !== 'string' || !/^(?:[0-9a-f]{2}){8,72}$/.test(r.signature))
105
+ fail('format', 'signature must be lowercase DER hex');
106
+ else {
107
+ try {
108
+ const der = Signature.fromDER(r.signature, 'hex');
109
+ if (Utils.toHex(der.toDER()) !== r.signature)
110
+ fail('format', 'signature must use canonical DER');
111
+ }
112
+ catch {
113
+ fail('format', 'signature is not DER');
114
+ }
115
+ }
116
+ if (failures.length > 0)
117
+ return false;
118
+ const record = value;
119
+ const created = instant(record.offer.createdAt);
120
+ const accepted = instant(record.acceptance.acceptedAt);
121
+ const expires = instant(record.offer.expiresAt);
122
+ if (!(created <= accepted))
123
+ fail('time-order', 'acceptedAt precedes createdAt');
124
+ if (!(accepted <= expires))
125
+ fail('time-order', 'acceptedAt is after expiresAt: the offer had expired');
126
+ if (record.offer.mechanism === 'named-recipient' && record.offer.recipientRef != null && record.offer.recipientRef !== record.acceptance.recipientIdentityKey) {
127
+ fail('state-mismatch', 'the named recipient is not the accepting identity');
128
+ }
129
+ return failures.length === 0;
130
+ }
131
+ /**
132
+ * Inspect a record on its own: structure, the custodian's signature and, when
133
+ * the caller names the custodians it trusts, whether the signer is one of
134
+ * them. Binding to the TRANSFER that commits to it is `bindAcceptanceToState`.
135
+ */
136
+ export function inspectManagedAcceptance(value, options = {}) {
137
+ const failures = [];
138
+ const structureValid = structure(value, failures);
139
+ if (!structureValid)
140
+ return { structureValid, signatureValid: null, failures };
141
+ const record = value;
142
+ let signatureValid = null;
143
+ let commitment;
144
+ try {
145
+ const preimage = acceptanceSigningPreimage(record);
146
+ signatureValid = PublicKey.fromString(record.custodian).verify(preimage, Signature.fromDER(Utils.toArray(record.signature, 'hex')));
147
+ commitment = acceptanceCommitment(record);
148
+ }
149
+ catch (error) {
150
+ signatureValid = error instanceof CanonicalJsonError ? null : false;
151
+ if (signatureValid === null)
152
+ failures.push({ reason: 'format', detail: error instanceof Error ? error.message : 'the record has no canonical form' });
153
+ }
154
+ if (signatureValid === false)
155
+ failures.push({ reason: 'signature-invalid', detail: `the signature does not verify under custodian ${record.custodian}` });
156
+ if (options.custodians != null && !options.custodians.includes(record.custodian)) {
157
+ failures.push({ reason: 'custodian-unexpected', detail: `signed by ${record.custodian}, not a custodian the policy names` });
158
+ }
159
+ return { structureValid, signatureValid, ...(commitment == null ? {} : { commitment }), failures };
160
+ }
161
+ /**
162
+ * Whether a version 2 TRANSFER executed exactly the acceptance the record
163
+ * evidences: same passport and lineage, the tip the offer named, the
164
+ * destination the recipient accepted, the holder who offered as the actor,
165
+ * and the record's own commitment in field 15. Every mismatch is named.
166
+ */
167
+ export function bindAcceptanceToState(record, state) {
168
+ const failures = [];
169
+ const fail = (detail) => { failures.push({ reason: 'state-mismatch', detail }); };
170
+ if (state.op !== 'TRANSFER')
171
+ fail(`the state is a ${state.op}, not a TRANSFER`);
172
+ if (state.passportId !== record.passportId)
173
+ fail('the state names another passport');
174
+ if (state.lineageGenesis == null || state.lineageGenesis.txid !== record.lineageGenesis.txid || state.lineageGenesis.outputIndex !== record.lineageGenesis.outputIndex)
175
+ fail('the state names another lineage');
176
+ if (state.previousTxid !== record.expectedPredecessor.txid || state.previousOutputIndex !== record.expectedPredecessor.outputIndex)
177
+ fail('the state spends a tip other than the one the offer named');
178
+ if (state.ownerIdentityKey !== record.acceptance.destinationKey)
179
+ fail('the state moves control to a key other than the accepted destination');
180
+ if (state.actorIdentityKey !== record.offer.holderIdentityKey)
181
+ fail('the state was made by an actor other than the holder who offered');
182
+ if (state.authorisationCommitment !== acceptanceCommitment(record))
183
+ fail('the state does not commit to this record');
184
+ if (instant(record.acceptance.acceptedAt) > instant(state.timestamp))
185
+ fail('the state is timestamped before the acceptance it executes');
186
+ return failures;
187
+ }
188
+ /** Sign a claim as the custodian. The signer's key must be `claim.custodian`; the result is checked before it is returned. */
189
+ export async function signManagedAcceptance(claim, signer) {
190
+ const failures = [];
191
+ // A well-formed placeholder (r = 1, s = 1) stands in for the signature while the claim's own shape is checked.
192
+ if (!structure({ ...claim, signature: '3006020101020101' }, failures)) {
193
+ throw new Error(`acceptance record is not well formed: ${failures.map((f) => f.detail).join('; ')}`);
194
+ }
195
+ const der = await signer.sign(acceptanceSigningPreimage(claim));
196
+ const record = { ...claim, signature: Utils.toHex(der) };
197
+ const inspection = inspectManagedAcceptance(record);
198
+ if (inspection.signatureValid !== true)
199
+ throw new Error('the signer does not hold the custodian key the record names');
200
+ return record;
201
+ }
202
+ //# sourceMappingURL=acceptance.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"acceptance.js","sourceRoot":"","sources":["../src/acceptance.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,66 @@
1
+ import { LockingScript, PublicKey, type WalletProtocol } from '@bsv/sdk';
2
+ /**
3
+ * The generic complete-representation anchor, `bsv-attestation-anchor-v1`
4
+ * (`spec/rules.md` §5 and §6). It lives in the core rather than in the overlay
5
+ * package because a reader in a browser verifies anchors without a database or
6
+ * an overlay engine, and `verifyPassportEvidence` (evidence.ts) reports the
7
+ * anchor rail beside the token rail from one package. `@bsv/dpp-overlay-topics`
8
+ * re-exports every name below unchanged.
9
+ */
10
+ export declare const ATTESTATION_ANCHOR_PREFIX = "bsv-attestation-anchor-v1";
11
+ export declare const ATTESTATION_ANCHOR_PROTOCOL: WalletProtocol;
12
+ export declare const ATTESTATION_ANCHOR_BASKET = "attestation-anchor";
13
+ export declare const ATTESTATION_ANCHOR_FIELD_COUNT = 9;
14
+ /** Metadata is authenticated as the anchor service's statement, not as credential authority. */
15
+ export interface AnchorMetadata {
16
+ digest: string;
17
+ attestationId: string;
18
+ issuer: string;
19
+ subject: string;
20
+ attestationType: string;
21
+ representation: string;
22
+ mediaType: string;
23
+ anchoredBy: string;
24
+ }
25
+ export interface AttestationAnchor extends AnchorMetadata {
26
+ lockingKey: string;
27
+ signature: number[];
28
+ }
29
+ export interface AnchorSigner {
30
+ createSignature(args: {
31
+ data: number[];
32
+ protocolID: WalletProtocol;
33
+ keyID: string;
34
+ counterparty: string;
35
+ }): Promise<{
36
+ signature: number[];
37
+ }>;
38
+ }
39
+ export declare function expectedAttestationLockingKey(anchoredBy: string, attestationId: string): PublicKey;
40
+ export declare function attestationAnchorFields(anchor: AnchorMetadata): number[][];
41
+ export declare function attestationAnchorSigningPreimage(fields: number[][]): number[];
42
+ export declare function buildAttestationAnchor(anchor: AnchorMetadata, signer: AnchorSigner): Promise<LockingScript>;
43
+ /**
44
+ * What a reader learnt from one output, check by check, so a report can say
45
+ * which rule failed rather than only that one did. `metadata` is present once
46
+ * the layout and every field bound held; the two Booleans are `null` until the
47
+ * material they need was decoded. `decodeAttestationAnchor` collapses this to
48
+ * the total strict parser the topic manager and the fixtures use.
49
+ */
50
+ export interface AttestationAnchorInspection {
51
+ metadata?: AnchorMetadata;
52
+ /** Canonical hex of the key in the first push, when it is a canonical compressed key. */
53
+ lockingKey?: string;
54
+ /** The child the metadata says the locking key must be, when metadata decoded. */
55
+ derivedKey?: string;
56
+ keyDerivationValid: boolean | null;
57
+ /** Verified against the derived key, never against whatever key the script happened to carry. */
58
+ signatureValid: boolean | null;
59
+ signature?: number[];
60
+ /** The first structural refusal, present when `metadata` is absent or a key did not parse. */
61
+ failure?: string;
62
+ }
63
+ export declare function inspectAttestationAnchor(script: LockingScript): AttestationAnchorInspection;
64
+ /** A total strict parser: invalid or legacy outputs return null. No credential proof is implied. */
65
+ export declare function decodeAttestationAnchor(script: LockingScript): AttestationAnchor | null;
66
+ //# sourceMappingURL=anchor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anchor.d.ts","sourceRoot":"","sources":["../src/anchor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,aAAa,EAAE,SAAS,EAAoB,KAAK,cAAc,EAAE,MAAM,UAAU,CAAA;AAE5G;;;;;;;GAOG;AAEH,eAAO,MAAM,yBAAyB,8BAA8B,CAAA;AACpE,eAAO,MAAM,2BAA2B,EAAE,cAAiD,CAAA;AAC3F,eAAO,MAAM,yBAAyB,uBAAuB,CAAA;AAC7D,eAAO,MAAM,8BAA8B,IAAI,CAAA;AAE/C,gGAAgG;AAChG,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAA;IACd,aAAa,EAAE,MAAM,CAAA;IACrB,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,eAAe,EAAE,MAAM,CAAA;IACvB,cAAc,EAAE,MAAM,CAAA;IACtB,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;CACnB;AACD,MAAM,WAAW,iBAAkB,SAAQ,cAAc;IACvD,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,EAAE,CAAA;CACpB;AACD,MAAM,WAAW,YAAY;IAC3B,eAAe,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,EAAE,CAAC;QAAC,UAAU,EAAE,cAAc,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAA;CAC7I;AAoBD,wBAAgB,6BAA6B,CAAC,UAAU,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,SAAS,CAIlG;AAED,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,EAAE,EAAE,CAW1E;AAED,wBAAgB,gCAAgC,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,GAAG,MAAM,EAAE,CAK7E;AAED,wBAAsB,sBAAsB,CAAC,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC,CAajH;AAED;;;;;;GAMG;AACH,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,EAAE,cAAc,CAAA;IACzB,yFAAyF;IACzF,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,kFAAkF;IAClF,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,kBAAkB,EAAE,OAAO,GAAG,IAAI,CAAA;IAClC,iGAAiG;IACjG,cAAc,EAAE,OAAO,GAAG,IAAI,CAAA;IAC9B,SAAS,CAAC,EAAE,MAAM,EAAE,CAAA;IACpB,8FAA8F;IAC9F,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,aAAa,GAAG,2BAA2B,CA6C3F;AAED,oGAAoG;AACpG,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,aAAa,GAAG,iBAAiB,GAAG,IAAI,CAOvF"}