@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.
- package/LICENSE +58 -0
- package/README.md +95 -0
- package/dist/acceptance.d.ts +100 -0
- package/dist/acceptance.d.ts.map +1 -0
- package/dist/acceptance.js +202 -0
- package/dist/acceptance.js.map +1 -0
- package/dist/anchor.d.ts +66 -0
- package/dist/anchor.d.ts.map +1 -0
- package/dist/anchor.js +145 -0
- package/dist/anchor.js.map +1 -0
- package/dist/attestation.d.ts +40 -0
- package/dist/attestation.d.ts.map +1 -0
- package/dist/attestation.js +111 -0
- package/dist/attestation.js.map +1 -0
- package/dist/blob.d.ts +11 -0
- package/dist/blob.d.ts.map +1 -0
- package/dist/blob.js +16 -0
- package/dist/blob.js.map +1 -0
- package/dist/canonical.d.ts +32 -0
- package/dist/canonical.d.ts.map +1 -0
- package/dist/canonical.js +54 -0
- package/dist/canonical.js.map +1 -0
- package/dist/canonicalJson.d.ts +22 -0
- package/dist/canonicalJson.d.ts.map +1 -0
- package/dist/canonicalJson.js +60 -0
- package/dist/canonicalJson.js.map +1 -0
- package/dist/codec.d.ts +45 -0
- package/dist/codec.d.ts.map +1 -0
- package/dist/codec.js +459 -0
- package/dist/codec.js.map +1 -0
- package/dist/constants.d.ts +150 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +179 -0
- package/dist/constants.js.map +1 -0
- package/dist/did.d.ts +37 -0
- package/dist/did.d.ts.map +1 -0
- package/dist/did.js +129 -0
- package/dist/did.js.map +1 -0
- package/dist/evidence.d.ts +224 -0
- package/dist/evidence.d.ts.map +1 -0
- package/dist/evidence.js +716 -0
- package/dist/evidence.js.map +1 -0
- package/dist/evidencePackage.d.ts +114 -0
- package/dist/evidencePackage.d.ts.map +1 -0
- package/dist/evidencePackage.js +164 -0
- package/dist/evidencePackage.js.map +1 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +31 -0
- package/dist/index.js.map +1 -0
- package/dist/owner.d.ts +135 -0
- package/dist/owner.d.ts.map +1 -0
- package/dist/owner.js +181 -0
- package/dist/owner.js.map +1 -0
- package/dist/publisherPolicy.d.ts +70 -0
- package/dist/publisherPolicy.d.ts.map +1 -0
- package/dist/publisherPolicy.js +186 -0
- package/dist/publisherPolicy.js.map +1 -0
- package/dist/signatures.d.ts +84 -0
- package/dist/signatures.d.ts.map +1 -0
- package/dist/signatures.js +137 -0
- package/dist/signatures.js.map +1 -0
- package/dist/transition.d.ts +29 -0
- package/dist/transition.d.ts.map +1 -0
- package/dist/transition.js +117 -0
- package/dist/transition.js.map +1 -0
- package/dist/types.d.ts +135 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/verifyChain.d.ts +152 -0
- package/dist/verifyChain.d.ts.map +1 -0
- package/dist/verifyChain.js +314 -0
- package/dist/verifyChain.js.map +1 -0
- package/package.json +46 -0
- package/schemas/capabilities.schema.json +129 -0
- package/schemas/epcis-import.schema.json +212 -0
- package/schemas/evidence-export.schema.json +67 -0
- package/schemas/evidence-package.schema.json +307 -0
- package/schemas/native-evidence-extension.schema.json +66 -0
- package/schemas/paginated-history.schema.json +32 -0
- package/schemas/passport-projection.schema.json +151 -0
- package/schemas/passport-source.schema.json +370 -0
- package/schemas/profile-evidence.schema.json +706 -0
- package/schemas/publisher-policy.schema.json +173 -0
- package/schemas/verification-report.schema.json +397 -0
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { CachedKeyDeriver, Signature, Utils } from '@bsv/sdk';
|
|
2
|
+
import { DPP_PROTOCOL_ID, DPP_PROTOCOL_ID_V2, PROTOCOL_MARKER, RECORD_V2_ACTOR_TAG, RECORD_V2_PUBLISHER_TAG, STANDARD_VERSION, } from './constants.js';
|
|
3
|
+
import { dataFields, dataFieldsV2, isV2Data } from './codec.js';
|
|
4
|
+
/**
|
|
5
|
+
* Canonical version 1 user-signature preimage (`spec/record-model.md` §5): the
|
|
6
|
+
* concatenated raw bytes of fields 1–12 in standard order - never a JSON
|
|
7
|
+
* serialization.
|
|
8
|
+
*
|
|
9
|
+
* Framing note: §5 mandates plain concatenation, so the preimage bytes alone
|
|
10
|
+
* do not bind field boundaries. Boundary uniqueness comes from field
|
|
11
|
+
* validation (op enum, ISO timestamp, fixed-width keys/hashes, JSON rules)
|
|
12
|
+
* plus the chain invariants (genesis must be ACTIVATE, spend linkage,
|
|
13
|
+
* passport_id immutability), which together block re-split states from
|
|
14
|
+
* verifying in any spec-sanctioned consumer. Version 2 replaces this with a
|
|
15
|
+
* framed, domain-tagged preimage (`actorPreimageV2`); version 1 keeps it
|
|
16
|
+
* because a published state keeps the contract it was signed under.
|
|
17
|
+
*/
|
|
18
|
+
export function userPreimageV1(d) {
|
|
19
|
+
return dataFields(d).flat();
|
|
20
|
+
}
|
|
21
|
+
/** Canonical version 1 server-signature preimage: fields 1–13 (user preimage + user_signature). */
|
|
22
|
+
export function serverPreimageV1(d, userSignature) {
|
|
23
|
+
return [...userPreimageV1(d), ...userSignature];
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Length framing (`spec/record-model-v2.md` §5): each item as its Bitcoin
|
|
27
|
+
* VarInt byte length followed by its bytes, in order. The same framing the
|
|
28
|
+
* anchor rail uses (`spec/rules.md` §5), so one rule serves both.
|
|
29
|
+
*/
|
|
30
|
+
export function frameFields(items) {
|
|
31
|
+
const writer = new Utils.Writer();
|
|
32
|
+
for (const item of items) {
|
|
33
|
+
writer.writeVarIntNum(item.length);
|
|
34
|
+
writer.write(item);
|
|
35
|
+
}
|
|
36
|
+
return writer.toArray();
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* The version 2 actor preimage: the actor tag, then fields 1–15, every item
|
|
40
|
+
* length-framed. Two field tuples that differ anywhere produce different
|
|
41
|
+
* bytes, and the tag keeps a signature made for the publisher role, or for
|
|
42
|
+
* version 1, from verifying here.
|
|
43
|
+
*/
|
|
44
|
+
export function actorPreimageV2(d) {
|
|
45
|
+
return frameFields([Utils.toArray(RECORD_V2_ACTOR_TAG, 'utf8'), ...dataFieldsV2(d)]);
|
|
46
|
+
}
|
|
47
|
+
/** The version 2 publisher preimage: the publisher tag, fields 1–15 and the actor signature, every item length-framed. */
|
|
48
|
+
export function publisherPreimageV2(d, actorSignature) {
|
|
49
|
+
return frameFields([Utils.toArray(RECORD_V2_PUBLISHER_TAG, 'utf8'), ...dataFieldsV2(d), actorSignature]);
|
|
50
|
+
}
|
|
51
|
+
/** The actor's preimage under the version the data declares: version 1 unframed, version 2 framed and tagged. */
|
|
52
|
+
export function userPreimage(d) {
|
|
53
|
+
return isV2Data(d) ? actorPreimageV2(d) : userPreimageV1(d);
|
|
54
|
+
}
|
|
55
|
+
/** The publisher's preimage under the version the data declares. */
|
|
56
|
+
export function serverPreimage(d, userSignature) {
|
|
57
|
+
return isV2Data(d) ? publisherPreimageV2(d, userSignature) : serverPreimageV1(d, userSignature);
|
|
58
|
+
}
|
|
59
|
+
/** The BRC-43 protocol both signatures of a state derive under: one per version, so keys never cross. */
|
|
60
|
+
export function protocolIdFor(d) {
|
|
61
|
+
return isV2Data(d) ? DPP_PROTOCOL_ID_V2 : DPP_PROTOCOL_ID;
|
|
62
|
+
}
|
|
63
|
+
/** Deriver for counterparty-'anyone' verification keys (rootKey = 1). */
|
|
64
|
+
const anyone = new CachedKeyDeriver('anyone');
|
|
65
|
+
/**
|
|
66
|
+
* Create the actor signature (field 13 in version 1, field 16 in version 2):
|
|
67
|
+
* the actor signs the version's actor preimage with the child key for
|
|
68
|
+
* (the version's protocol, actor_keyID, counterparty 'anyone').
|
|
69
|
+
*/
|
|
70
|
+
export async function createUserSignature(d, actorWallet) {
|
|
71
|
+
const { signature } = await actorWallet.createSignature({
|
|
72
|
+
data: userPreimage(d),
|
|
73
|
+
protocolID: protocolIdFor(d),
|
|
74
|
+
keyID: d.actorKeyId,
|
|
75
|
+
counterparty: 'anyone',
|
|
76
|
+
});
|
|
77
|
+
return signature;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Create the publisher signature (field 14 in version 1, field 17 in version
|
|
81
|
+
* 2): the service signs the version's publisher preimage with the child key
|
|
82
|
+
* for (the version's protocol, keyID = passport_id, counterparty 'anyone').
|
|
83
|
+
* keyID is pinned to passport_id so verifiers can re-derive the service child
|
|
84
|
+
* key from on-chain data plus the published service identity key (§5).
|
|
85
|
+
*/
|
|
86
|
+
export async function createServerSignature(d, userSignature, serverWallet) {
|
|
87
|
+
const { signature } = await serverWallet.createSignature({
|
|
88
|
+
data: serverPreimage(d, userSignature),
|
|
89
|
+
protocolID: protocolIdFor(d),
|
|
90
|
+
keyID: d.passportId,
|
|
91
|
+
counterparty: 'anyone',
|
|
92
|
+
});
|
|
93
|
+
return signature;
|
|
94
|
+
}
|
|
95
|
+
/** Sign the actor and publisher preimages and assemble the complete state of the version the data declares. */
|
|
96
|
+
export async function completeState(d, actorWallet, serverWallet) {
|
|
97
|
+
const userSignature = await createUserSignature(d, actorWallet);
|
|
98
|
+
const serverSignature = await createServerSignature(d, userSignature, serverWallet);
|
|
99
|
+
if (isV2Data(d)) {
|
|
100
|
+
return { ...d, protocolMarker: PROTOCOL_MARKER, userSignature, serverSignature };
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
...d,
|
|
104
|
+
protocolMarker: PROTOCOL_MARKER,
|
|
105
|
+
version: STANDARD_VERSION,
|
|
106
|
+
userSignature,
|
|
107
|
+
serverSignature,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Verify the actor signature against actor_identity_key + actor_keyID (§5;
|
|
112
|
+
* §8 check 1), under the version the state carries. Open verification: the
|
|
113
|
+
* key is derived with counterparty 'anyone', so no wallet or secret is needed.
|
|
114
|
+
*/
|
|
115
|
+
export function verifyUserSignature(state) {
|
|
116
|
+
try {
|
|
117
|
+
const pub = anyone.derivePublicKey(protocolIdFor(state), state.actorKeyId, state.actorIdentityKey);
|
|
118
|
+
return pub.verify(userPreimage(state), Signature.fromDER(state.userSignature));
|
|
119
|
+
}
|
|
120
|
+
catch {
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Verify the publisher signature against a configured service identity key.
|
|
126
|
+
* Admission policy, not token validity (§5).
|
|
127
|
+
*/
|
|
128
|
+
export function verifyServerSignature(state, serverIdentityKey) {
|
|
129
|
+
try {
|
|
130
|
+
const pub = anyone.derivePublicKey(protocolIdFor(state), state.passportId, serverIdentityKey);
|
|
131
|
+
return pub.verify(serverPreimage(state, state.userSignature), Signature.fromDER(state.serverSignature));
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
//# sourceMappingURL=signatures.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signatures.js","sourceRoot":"","sources":["../src/signatures.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { DppState, Outpoint } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Per-link rules from `spec/record-model.md` §4 and §6 (version 1) and
|
|
4
|
+
* `spec/record-model-v2.md` §4 and §6 (version 2). Field-level well-formedness
|
|
5
|
+
* (event_data emptiness, JSON validity, ISO timestamps, field bounds) is
|
|
6
|
+
* enforced by the codec at decode time. These functions check the rules that
|
|
7
|
+
* span states. Returns null when valid, otherwise a human-readable reason; the
|
|
8
|
+
* fixtures pin these strings.
|
|
9
|
+
*/
|
|
10
|
+
/** What a link needs beyond the two states: the predecessor's output index, the lineage's genesis, and the profile's authorities. */
|
|
11
|
+
export interface LinkContext {
|
|
12
|
+
/** The output index of the predecessor's DPP output, as spent. Version 2 binds it (field 13). */
|
|
13
|
+
prevOutputIndex?: number;
|
|
14
|
+
/** The genesis outpoint of the chain being verified. Version 2 binds it (field 12). */
|
|
15
|
+
lineageGenesis?: Outpoint;
|
|
16
|
+
/** Identity keys the profile names as authorities, whose version 2 UPDATE, TRANSFER or RETIRE passes without a control proof. */
|
|
17
|
+
authorities?: readonly string[];
|
|
18
|
+
}
|
|
19
|
+
export declare function checkGenesisState(s: DppState): string | null;
|
|
20
|
+
/**
|
|
21
|
+
* The rules one link must satisfy, under the version of the state that
|
|
22
|
+
* extends the chain. A version 1 successor keeps the version 1 rules exactly;
|
|
23
|
+
* a version 2 successor binds the predecessor outpoint and the lineage
|
|
24
|
+
* genesis, refuses to follow a RETIRE, proves control of the predecessor, and
|
|
25
|
+
* may follow a version 1 predecessor only as the UPDATE that upgrades the
|
|
26
|
+
* lineage (`spec/record-model-v2.md` §8).
|
|
27
|
+
*/
|
|
28
|
+
export declare function checkTransition(prev: DppState, next: DppState, prevTxid: string, link?: LinkContext): string | null;
|
|
29
|
+
//# sourceMappingURL=transition.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transition.d.ts","sourceRoot":"","sources":["../src/transition.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAc,QAAQ,EAAE,MAAM,YAAY,CAAA;AAEhE;;;;;;;GAOG;AAEH,qIAAqI;AACrI,MAAM,WAAW,WAAW;IAC1B,iGAAiG;IACjG,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,uFAAuF;IACvF,cAAc,CAAC,EAAE,QAAQ,CAAA;IACzB,iIAAiI;IACjI,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAChC;AAED,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,IAAI,CAW5D;AA+ED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,QAAQ,EACd,IAAI,EAAE,QAAQ,EACd,QAAQ,EAAE,MAAM,EAChB,IAAI,GAAE,WAAgB,GACrB,MAAM,GAAG,IAAI,CAGf"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { NO_EVENT_OPS, PAYLOAD_CHANGE_OPS, PAYLOAD_CHANGE_OPS_V2 } from './constants.js';
|
|
2
|
+
import { checkControl } from './owner.js';
|
|
3
|
+
export function checkGenesisState(s) {
|
|
4
|
+
if (s.version === '2') {
|
|
5
|
+
if (s.op !== 'ISSUE')
|
|
6
|
+
return `genesis op must be ISSUE, got ${s.op}`;
|
|
7
|
+
if (s.previousTxid !== '' || s.previousOutputIndex != null)
|
|
8
|
+
return 'genesis previous_outpoint must be empty';
|
|
9
|
+
if (s.lineageGenesis != null)
|
|
10
|
+
return 'genesis lineage_genesis must be empty';
|
|
11
|
+
if (s.controlLinkage !== '')
|
|
12
|
+
return 'genesis control_linkage must be empty';
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
if (s.op !== 'ACTIVATE')
|
|
16
|
+
return `genesis op must be ACTIVATE, got ${s.op}`;
|
|
17
|
+
if (s.previousTxid !== '')
|
|
18
|
+
return 'genesis previous_txid must be empty';
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
const sameOutpoint = (a, b) => a.txid === b.txid && a.outputIndex === b.outputIndex;
|
|
22
|
+
function checkTransitionV1(prev, next, prevTxid) {
|
|
23
|
+
if (prev.version === '2')
|
|
24
|
+
return 'a version 1 state cannot follow a version 2 state';
|
|
25
|
+
if (next.op === 'ACTIVATE')
|
|
26
|
+
return 'ACTIVATE is allowed at genesis only';
|
|
27
|
+
if (next.previousTxid === '')
|
|
28
|
+
return 'non-genesis previous_txid must be set';
|
|
29
|
+
if (next.passportId !== prev.passportId) {
|
|
30
|
+
return 'passport_id is immutable across the chain';
|
|
31
|
+
}
|
|
32
|
+
if (next.previousTxid !== prevTxid) {
|
|
33
|
+
return 'previous_txid must equal the spent tip txid';
|
|
34
|
+
}
|
|
35
|
+
if (next.op !== 'TRANSFER' && next.ownerIdentityKey !== prev.ownerIdentityKey) {
|
|
36
|
+
return 'owner_identity_key changes only on TRANSFER';
|
|
37
|
+
}
|
|
38
|
+
if (!PAYLOAD_CHANGE_OPS.includes(next.op) &&
|
|
39
|
+
(next.payloadPublic !== prev.payloadPublic ||
|
|
40
|
+
next.payloadOwnerHash !== prev.payloadOwnerHash)) {
|
|
41
|
+
return 'payload_public / payload_owner_hash change only on ACTIVATE, EDIT or TRANSFER';
|
|
42
|
+
}
|
|
43
|
+
if (NO_EVENT_OPS.includes(next.op) && next.eventData !== '') {
|
|
44
|
+
return `event_data must be empty on ${next.op}`;
|
|
45
|
+
}
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* The lineage genesis a version 2 state must name, from what the caller
|
|
50
|
+
* knows: the chain's genesis when supplied; otherwise, for a version 2
|
|
51
|
+
* predecessor, what that predecessor names (or the predecessor itself when it
|
|
52
|
+
* is the ISSUE). A version 1 predecessor names no genesis, so the caller must
|
|
53
|
+
* supply one; a reader that cannot is told so rather than left to guess.
|
|
54
|
+
*/
|
|
55
|
+
function expectedLineageGenesis(prev, prevTxid, link) {
|
|
56
|
+
if (link.lineageGenesis != null)
|
|
57
|
+
return link.lineageGenesis;
|
|
58
|
+
if (prev.version !== '2')
|
|
59
|
+
return undefined;
|
|
60
|
+
if (prev.lineageGenesis != null)
|
|
61
|
+
return prev.lineageGenesis;
|
|
62
|
+
if (link.prevOutputIndex == null)
|
|
63
|
+
return undefined;
|
|
64
|
+
return { txid: prevTxid, outputIndex: link.prevOutputIndex };
|
|
65
|
+
}
|
|
66
|
+
function checkTransitionV2(prev, next, prevTxid, link) {
|
|
67
|
+
if (next.op === 'ISSUE')
|
|
68
|
+
return 'ISSUE is allowed at genesis only';
|
|
69
|
+
if (prev.version === '2' && prev.op === 'RETIRE')
|
|
70
|
+
return 'the lineage is retired: no state may follow RETIRE';
|
|
71
|
+
if (prev.version === '1' && next.op !== 'UPDATE') {
|
|
72
|
+
return 'a version 1 state is followed only by a version 2 UPDATE, the upgrade transition';
|
|
73
|
+
}
|
|
74
|
+
if (next.previousTxid === '' || next.previousOutputIndex == null)
|
|
75
|
+
return 'non-genesis previous_outpoint must be set';
|
|
76
|
+
if (next.passportId !== prev.passportId)
|
|
77
|
+
return 'passport_id is immutable across the chain';
|
|
78
|
+
if (next.previousTxid !== prevTxid)
|
|
79
|
+
return 'previous_outpoint must name the spent tip';
|
|
80
|
+
if (link.prevOutputIndex != null && next.previousOutputIndex !== link.prevOutputIndex) {
|
|
81
|
+
return 'previous_outpoint must name the spent tip output';
|
|
82
|
+
}
|
|
83
|
+
const genesis = expectedLineageGenesis(prev, prevTxid, link);
|
|
84
|
+
if (genesis == null)
|
|
85
|
+
return 'lineage_genesis cannot be checked without the chain genesis';
|
|
86
|
+
if (next.lineageGenesis == null || !sameOutpoint(next.lineageGenesis, genesis)) {
|
|
87
|
+
return 'lineage_genesis must name the chain genesis';
|
|
88
|
+
}
|
|
89
|
+
if (prev.version === '1' && next.ownerIdentityKey !== prev.ownerIdentityKey) {
|
|
90
|
+
return 'the upgrade transition keeps the controller key';
|
|
91
|
+
}
|
|
92
|
+
if (next.op !== 'TRANSFER' && next.ownerIdentityKey !== prev.ownerIdentityKey) {
|
|
93
|
+
return 'controller_key changes only on TRANSFER';
|
|
94
|
+
}
|
|
95
|
+
if (!PAYLOAD_CHANGE_OPS_V2.includes(next.op) &&
|
|
96
|
+
(next.payloadPublic !== prev.payloadPublic || next.payloadOwnerHash !== prev.payloadOwnerHash)) {
|
|
97
|
+
return 'payload_public / payload_owner_hash do not change on RETIRE';
|
|
98
|
+
}
|
|
99
|
+
const control = checkControl(prev, next, link.authorities ?? []);
|
|
100
|
+
if (control != null)
|
|
101
|
+
return control;
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* The rules one link must satisfy, under the version of the state that
|
|
106
|
+
* extends the chain. A version 1 successor keeps the version 1 rules exactly;
|
|
107
|
+
* a version 2 successor binds the predecessor outpoint and the lineage
|
|
108
|
+
* genesis, refuses to follow a RETIRE, proves control of the predecessor, and
|
|
109
|
+
* may follow a version 1 predecessor only as the UPDATE that upgrades the
|
|
110
|
+
* lineage (`spec/record-model-v2.md` §8).
|
|
111
|
+
*/
|
|
112
|
+
export function checkTransition(prev, next, prevTxid, link = {}) {
|
|
113
|
+
if (next.version === '2')
|
|
114
|
+
return checkTransitionV2(prev, next, prevTxid, link);
|
|
115
|
+
return checkTransitionV1(prev, next, prevTxid);
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=transition.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transition.js","sourceRoot":"","sources":["../src/transition.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { DPP_OPS, DPP_OPS_V2 } from './constants.js';
|
|
2
|
+
export type DppOpV1 = (typeof DPP_OPS)[number];
|
|
3
|
+
export type DppOpV2 = (typeof DPP_OPS_V2)[number];
|
|
4
|
+
/** Every operation either record version carries. A version 1 state carries only a `DppOpV1`, a version 2 state only a `DppOpV2`. */
|
|
5
|
+
export type DppOp = DppOpV1 | DppOpV2;
|
|
6
|
+
/** A transaction output by identifier and index; the shape both record versions and the report name outputs by. */
|
|
7
|
+
export interface Outpoint {
|
|
8
|
+
txid: string;
|
|
9
|
+
outputIndex: number;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* The signable content of one version 1 passport state - fields 1–12 of the
|
|
13
|
+
* DPP Token Standard v1 layout (`spec/record-model.md` §3), before signatures.
|
|
14
|
+
*/
|
|
15
|
+
export interface DppStateData {
|
|
16
|
+
/** Stable GS1-DL-style ID; immutable across the chain; primary lookup key. */
|
|
17
|
+
passportId: string;
|
|
18
|
+
op: DppOpV1;
|
|
19
|
+
/** Actor-asserted ISO 8601; bounded by neighbouring blocks (§3 field 5). */
|
|
20
|
+
timestamp: string;
|
|
21
|
+
/** Current owner's compressed public key, hex; SHOULD be the owner's BRC-42 child under OWNER_PROTOCOL_ID (§3 field 6). */
|
|
22
|
+
ownerIdentityKey: string;
|
|
23
|
+
/** Compressed public key, hex, of who performed this state change. */
|
|
24
|
+
actorIdentityKey: string;
|
|
25
|
+
/** Published keyID for the actor signature; enables open verification. */
|
|
26
|
+
actorKeyId: string;
|
|
27
|
+
/** Clear JSON event metadata; '' on ACTIVATE and EDIT. */
|
|
28
|
+
eventData: string;
|
|
29
|
+
/** Clear JSON, the record's public tier (`spec/record-model.md` §3 field 10). */
|
|
30
|
+
payloadPublic: string;
|
|
31
|
+
/** SHA-256 hex of the off-chain owner-tier ciphertext blob; '' if none. */
|
|
32
|
+
payloadOwnerHash: string;
|
|
33
|
+
/** Prior tip txid, hex; '' at genesis. Must equal the spent outpoint's txid. */
|
|
34
|
+
previousTxid: string;
|
|
35
|
+
}
|
|
36
|
+
/** The version 1 data, under the name the version 2 type sits beside. */
|
|
37
|
+
export type DppStateDataV1 = DppStateData;
|
|
38
|
+
/**
|
|
39
|
+
* The signable content of one version 2 passport state - fields 1–15 of the
|
|
40
|
+
* layout in `spec/record-model-v2.md` §3, before signatures. The property
|
|
41
|
+
* names shared with version 1 keep their meaning; `ownerIdentityKey` is the
|
|
42
|
+
* controller key (field 6) and `previousTxid` the txid half of the predecessor
|
|
43
|
+
* outpoint (field 13).
|
|
44
|
+
*/
|
|
45
|
+
export interface DppStateDataV2 {
|
|
46
|
+
version: '2';
|
|
47
|
+
passportId: string;
|
|
48
|
+
op: DppOpV2;
|
|
49
|
+
timestamp: string;
|
|
50
|
+
/** The controller key, field 6: the per-passport key that names who controls the lineage. */
|
|
51
|
+
ownerIdentityKey: string;
|
|
52
|
+
actorIdentityKey: string;
|
|
53
|
+
actorKeyId: string;
|
|
54
|
+
/** Clear JSON or ''; at most MAX_EVENT_DATA_BYTES_V2 bytes. No property is reserved. */
|
|
55
|
+
eventData: string;
|
|
56
|
+
/** Clear JSON, non-empty; at most MAX_PAYLOAD_PUBLIC_BYTES_V2 bytes. */
|
|
57
|
+
payloadPublic: string;
|
|
58
|
+
payloadOwnerHash: string;
|
|
59
|
+
/** The predecessor's txid, hex; '' on ISSUE. With `previousOutputIndex`, field 13. */
|
|
60
|
+
previousTxid: string;
|
|
61
|
+
/** The predecessor's output index; null on ISSUE. */
|
|
62
|
+
previousOutputIndex: number | null;
|
|
63
|
+
/** The genesis outpoint of the lineage, field 12; null on ISSUE, which is the genesis. */
|
|
64
|
+
lineageGenesis: Outpoint | null;
|
|
65
|
+
/** Field 14: '' or 64 lower-case hex, the BRC-69 scalar linking the actor's root to the previous controller key. */
|
|
66
|
+
controlLinkage: string;
|
|
67
|
+
/** Field 15: '' or 64 lower-case hex, the SHA-256 commitment to the off-chain authorisation record the profile names. */
|
|
68
|
+
authorisationCommitment: string;
|
|
69
|
+
}
|
|
70
|
+
/** Either version's signable content. */
|
|
71
|
+
export type AnyDppStateData = DppStateDataV1 | DppStateDataV2;
|
|
72
|
+
interface SignedFields {
|
|
73
|
+
protocolMarker: string;
|
|
74
|
+
/** DER ECDSA, the actor's signature (field 13 in version 1, field 16 in version 2). */
|
|
75
|
+
userSignature: number[];
|
|
76
|
+
/** DER ECDSA, the publisher's countersignature (field 14 in version 1, field 17 in version 2). */
|
|
77
|
+
serverSignature: number[];
|
|
78
|
+
}
|
|
79
|
+
/** A fully signed version 1 state: fields 1–14 decoded from a DPP output. */
|
|
80
|
+
export interface DppStateV1 extends DppStateDataV1, SignedFields {
|
|
81
|
+
version: '1';
|
|
82
|
+
}
|
|
83
|
+
/** A fully signed version 2 state: fields 1–17 decoded from a DPP output. */
|
|
84
|
+
export interface DppStateV2 extends DppStateDataV2, SignedFields {
|
|
85
|
+
}
|
|
86
|
+
/** A fully signed state of either version. Narrow on `version`. */
|
|
87
|
+
export type DppState = DppStateV1 | DppStateV2;
|
|
88
|
+
/** One link of a passport chain as needed for verification. */
|
|
89
|
+
export interface DppChainEntry {
|
|
90
|
+
state: DppState;
|
|
91
|
+
txid: string;
|
|
92
|
+
/** Output index of the DPP output within its transaction. */
|
|
93
|
+
outputIndex: number;
|
|
94
|
+
}
|
|
95
|
+
export type SpvStatus = 'verified' | 'pending';
|
|
96
|
+
export interface StateCheck {
|
|
97
|
+
txid: string;
|
|
98
|
+
op: DppOp;
|
|
99
|
+
userSignatureValid: boolean;
|
|
100
|
+
serverSignatureValid: boolean | null;
|
|
101
|
+
linkageValid: boolean;
|
|
102
|
+
/**
|
|
103
|
+
* The optional owner-signed transfer (`spec/custody.md` §4). null when the
|
|
104
|
+
* invariant was not run: the option is off, or the state is not a version 1
|
|
105
|
+
* TRANSFER. A report says "not applicable" for null rather than a vacuous pass.
|
|
106
|
+
* Version 2 states prove control as part of linkage instead (`controlValid`
|
|
107
|
+
* on the inspection).
|
|
108
|
+
*/
|
|
109
|
+
ownerConsentValid: boolean | null;
|
|
110
|
+
spv: SpvStatus | 'failed';
|
|
111
|
+
}
|
|
112
|
+
export interface ChainVerifyResult {
|
|
113
|
+
valid: boolean;
|
|
114
|
+
/**
|
|
115
|
+
* 'verified' only when the chain is valid and every state proved against
|
|
116
|
+
* block headers. 'pending' covers both an unmined state and one that could
|
|
117
|
+
* not be checked, because to a reader those are the same sentence:
|
|
118
|
+
* inclusion is not proved yet. A chain that fails verification also says
|
|
119
|
+
* 'pending', whatever its proofs said, so no consumer can print "inclusion
|
|
120
|
+
* proved" beside "could not verify"; the per-state detail in `states`
|
|
121
|
+
* keeps 'failed' where a proof was refuted.
|
|
122
|
+
*/
|
|
123
|
+
spv: SpvStatus;
|
|
124
|
+
states: StateCheck[];
|
|
125
|
+
/** Human-readable reason for the first failure, when valid === false. */
|
|
126
|
+
error?: string;
|
|
127
|
+
/**
|
|
128
|
+
* Set when the chain tracker could not answer at least once, carrying the
|
|
129
|
+
* first such error. Operational signal only: an outage leaves SPV 'pending'
|
|
130
|
+
* rather than 'failed', and this is how a caller can tell the two apart.
|
|
131
|
+
*/
|
|
132
|
+
spvUnavailable?: string;
|
|
133
|
+
}
|
|
134
|
+
export {};
|
|
135
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { Beef, PublicKey, Transaction, type ChainTracker } from '@bsv/sdk';
|
|
2
|
+
import { type PublisherPolicy } from './publisherPolicy.js';
|
|
3
|
+
import type { DppVersion } from './constants.js';
|
|
4
|
+
import type { ChainVerifyResult, DppState, StateCheck } from './types.js';
|
|
5
|
+
export interface VerifyChainOptions {
|
|
6
|
+
/**
|
|
7
|
+
* Tracker for SPV (`spec/record-model.md` §8 check 3). Omit or pass 'scripts only' to skip root
|
|
8
|
+
* checks - every state then reports SPV 'pending'. The demo app always
|
|
9
|
+
* passes a real tracker; 'scripts only' exists for offline use and tests.
|
|
10
|
+
*/
|
|
11
|
+
chainTracker?: ChainTracker | 'scripts only';
|
|
12
|
+
/**
|
|
13
|
+
* When set, server_signature is verified against this service identity key
|
|
14
|
+
* (admission policy, §8). Token validity itself never depends on it; the
|
|
15
|
+
* overlay's topic manager passes its configured key, viewers may omit it.
|
|
16
|
+
*/
|
|
17
|
+
serverIdentityKey?: string;
|
|
18
|
+
/**
|
|
19
|
+
* The optional owner-signed transfer (`spec/custody.md` §4), selected by a
|
|
20
|
+
* profile for version 1 states. `true` runs the predicate on every version 1
|
|
21
|
+
* TRANSFER; an object also names the transfer authorities, identity keys
|
|
22
|
+
* whose TRANSFER passes without it (recovery). A malformed authority throws
|
|
23
|
+
* before any state is read: a misconfigured authority must be loud, never
|
|
24
|
+
* silently unmatched. Version 2 states prove control on every UPDATE,
|
|
25
|
+
* TRANSFER and RETIRE regardless (`spec/record-model-v2.md` §6); the same
|
|
26
|
+
* authorities serve them unless `controlAuthorities` names others.
|
|
27
|
+
*/
|
|
28
|
+
ownerConsent?: boolean | {
|
|
29
|
+
authorities: string[];
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Identity keys the profile names as authorities for version 2 states: an
|
|
33
|
+
* UPDATE, TRANSFER or RETIRE by one of them passes without a control proof
|
|
34
|
+
* (recovery, or a scoped authority the profile defines). Defaults to the
|
|
35
|
+
* `ownerConsent` authorities. Malformed keys throw at construction.
|
|
36
|
+
*/
|
|
37
|
+
controlAuthorities?: string[];
|
|
38
|
+
/**
|
|
39
|
+
* The managed-custody profile (`spec/managed-custody.md`): when true, every
|
|
40
|
+
* version 2 TRANSFER must carry an `authorisation_commitment`, the
|
|
41
|
+
* commitment to the acceptance record the custodian retains. Off, the
|
|
42
|
+
* record model alone is checked and the commitment is read but not required.
|
|
43
|
+
*/
|
|
44
|
+
managedAcceptance?: boolean;
|
|
45
|
+
}
|
|
46
|
+
export interface DppOutputRef {
|
|
47
|
+
state: DppState;
|
|
48
|
+
outputIndex: number;
|
|
49
|
+
lockingPublicKey: PublicKey;
|
|
50
|
+
}
|
|
51
|
+
/** What a reader reports when the managed-custody profile is selected and a version 2 TRANSFER carries no commitment. */
|
|
52
|
+
export declare const ACCEPTANCE_COMMITMENT_REFUSAL = "TRANSFER carries no authorisation_commitment under managed-custody@1";
|
|
53
|
+
/**
|
|
54
|
+
* Locate THE DPP output of a transaction (§6 invariant 1: exactly one).
|
|
55
|
+
* Returns all matches; callers enforce the invariant.
|
|
56
|
+
*/
|
|
57
|
+
export declare function findDppOutputs(tx: Transaction): DppOutputRef[];
|
|
58
|
+
/** The options `inspectChain` takes beyond `verifyChain`'s: several publisher keys, any of which may have countersigned. */
|
|
59
|
+
export interface InspectChainOptions extends VerifyChainOptions {
|
|
60
|
+
/**
|
|
61
|
+
* Publisher identity keys, any one of which satisfies the server-signature
|
|
62
|
+
* check (`spec/verification.md` §4, `publisherSignatures`). `serverIdentityKey`
|
|
63
|
+
* is the one-key spelling of the same option; both may be given.
|
|
64
|
+
*/
|
|
65
|
+
publisherKeys?: string[];
|
|
66
|
+
/**
|
|
67
|
+
* A publisher key policy chain (`spec/services.md` §1), already verified by
|
|
68
|
+
* the caller with `verifyPolicyChain`. A state is then checked against the
|
|
69
|
+
* state-publisher keys active at its own timestamp, so a retired key still
|
|
70
|
+
* authenticates what it signed while active and a new key authenticates
|
|
71
|
+
* nothing timestamped before its activation. Combined with `publisherKeys`
|
|
72
|
+
* when both are given.
|
|
73
|
+
*/
|
|
74
|
+
publisherPolicy?: PublisherPolicy[];
|
|
75
|
+
}
|
|
76
|
+
/** Why one state stopped the inspection, in the vocabulary the report uses. */
|
|
77
|
+
export type ChainFailureKind = 'encoding' | 'userSignature' | 'serverSignature' | 'linkage' | 'consent' | 'inclusion';
|
|
78
|
+
/** One inspected state: the verifier's findings plus what a report needs to name it. */
|
|
79
|
+
export interface StateInspection extends StateCheck {
|
|
80
|
+
index: number;
|
|
81
|
+
outputIndex: number;
|
|
82
|
+
state: DppState;
|
|
83
|
+
/** The record version the state carries. */
|
|
84
|
+
version: DppVersion;
|
|
85
|
+
linkError: string | null;
|
|
86
|
+
consentError: string | null;
|
|
87
|
+
/**
|
|
88
|
+
* The version 2 control proof (`spec/record-model-v2.md` §6): true when
|
|
89
|
+
* the actor proved control of the predecessor, false when it did not, null
|
|
90
|
+
* on a genesis and on every version 1 state, where the rule does not run.
|
|
91
|
+
*/
|
|
92
|
+
controlValid: boolean | null;
|
|
93
|
+
/** True when the countersignature verifies under a key the policy names, but one not active at this state's timestamp. */
|
|
94
|
+
publisherOutsideWindow?: boolean;
|
|
95
|
+
/** Why `spv` is 'pending' or 'failed'; absent when 'verified'. */
|
|
96
|
+
spvReason?: 'no-proof' | 'header-check-disabled' | 'header-source-unavailable' | 'proof-does-not-contain-txid' | 'proof-refuted';
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Every finding the token rail's verifier makes, state by state, stopping after
|
|
100
|
+
* the first state that fails (§8's rule: a chain fails as a whole at the first
|
|
101
|
+
* failing state, with the reason identified). `verifyChain` reduces this to
|
|
102
|
+
* the `ChainVerifyResult` it has always returned; `verifyPassportEvidence`
|
|
103
|
+
* reports it check by check instead of collapsing it to one Boolean.
|
|
104
|
+
*/
|
|
105
|
+
export interface ChainInspection {
|
|
106
|
+
states: StateInspection[];
|
|
107
|
+
/**
|
|
108
|
+
* The first failure, when there was one. An `encoding` failure names a
|
|
109
|
+
* transaction that yielded no state, so `states` carries nothing for it.
|
|
110
|
+
*/
|
|
111
|
+
failure?: {
|
|
112
|
+
index: number;
|
|
113
|
+
txid: string;
|
|
114
|
+
kind: ChainFailureKind;
|
|
115
|
+
message: string;
|
|
116
|
+
};
|
|
117
|
+
/** True when the inspection reached the last supplied transaction without a failure. */
|
|
118
|
+
complete: boolean;
|
|
119
|
+
anyPending: boolean;
|
|
120
|
+
spvUnavailable?: string;
|
|
121
|
+
}
|
|
122
|
+
export declare function inspectChain(txs: Transaction[], options?: InspectChainOptions): Promise<ChainInspection>;
|
|
123
|
+
/**
|
|
124
|
+
* Verify a full passport chain, ordered genesis → tip (§6 + §8).
|
|
125
|
+
*
|
|
126
|
+
* What "Authentic ✓" means (§8): (1) the genesis maker signature is valid;
|
|
127
|
+
* (2) every link satisfies invariants 1–5, checked here both structurally
|
|
128
|
+
* (the next state spends the previous DPP output) and on the readable field
|
|
129
|
+
* (previous_txid equality); (3) SPV - each mined transaction's merkle path
|
|
130
|
+
* validates against block headers via the chain tracker. An unmined state
|
|
131
|
+
* passes with SPV 'pending'. Any failure ⇒ valid: false ("Could not verify").
|
|
132
|
+
*
|
|
133
|
+
* Script execution of spends is enforced by the network and is not
|
|
134
|
+
* re-evaluated here; the in-app checks are exactly the three above.
|
|
135
|
+
*
|
|
136
|
+
* This is supplied-history verification and nothing more: it says whether the
|
|
137
|
+
* states handed to it form a valid chain, not that the last one is the current
|
|
138
|
+
* tip, that its genesis was authorised, or that the attestation rail was
|
|
139
|
+
* checked. `verifyPassportEvidence` (evidence.ts) is the report that keeps
|
|
140
|
+
* those findings apart; this function keeps its one Boolean for the callers
|
|
141
|
+
* that mean exactly what it says.
|
|
142
|
+
*/
|
|
143
|
+
export declare function verifyChain(txs: Transaction[], options?: VerifyChainOptions): Promise<ChainVerifyResult>;
|
|
144
|
+
/**
|
|
145
|
+
* Reconstruct the ordered passport chain (genesis → tip) from a BEEF, e.g.
|
|
146
|
+
* as returned by the ls_dpp lookup. Transactions come out hydrated: merkle
|
|
147
|
+
* paths attached, input source transactions linked - ready for verifyChain.
|
|
148
|
+
* States of either version link by `previousTxid`; a version 2 state also
|
|
149
|
+
* carries the predecessor's output index, which the verifier checks.
|
|
150
|
+
*/
|
|
151
|
+
export declare function chainFromBeef(beef: Beef, passportId?: string): Transaction[];
|
|
152
|
+
//# sourceMappingURL=verifyChain.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verifyChain.d.ts","sourceRoot":"","sources":["../src/verifyChain.ts"],"names":[],"mappings":"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"}
|