@bsv/dpp-overlay-topics 0.4.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 +169 -0
- package/dist/anchorStorage.d.ts +58 -0
- package/dist/anchorStorage.d.ts.map +1 -0
- package/dist/anchorStorage.js +72 -0
- package/dist/anchorStorage.js.map +1 -0
- package/dist/attestationAnchor.d.ts +10 -0
- package/dist/attestationAnchor.d.ts.map +1 -0
- package/dist/attestationAnchor.js +10 -0
- package/dist/attestationAnchor.js.map +1 -0
- package/dist/attestationStorage.d.ts +49 -0
- package/dist/attestationStorage.d.ts.map +1 -0
- package/dist/attestationStorage.js +78 -0
- package/dist/attestationStorage.js.map +1 -0
- package/dist/capabilities.d.ts +127 -0
- package/dist/capabilities.d.ts.map +1 -0
- package/dist/capabilities.js +210 -0
- package/dist/capabilities.js.map +1 -0
- package/dist/engineStorage.d.ts +106 -0
- package/dist/engineStorage.d.ts.map +1 -0
- package/dist/engineStorage.js +253 -0
- package/dist/engineStorage.js.map +1 -0
- package/dist/evidenceExport.d.ts +189 -0
- package/dist/evidenceExport.d.ts.map +1 -0
- package/dist/evidenceExport.js +517 -0
- package/dist/evidenceExport.js.map +1 -0
- package/dist/history.d.ts +114 -0
- package/dist/history.d.ts.map +1 -0
- package/dist/history.js +215 -0
- package/dist/history.js.map +1 -0
- package/dist/index.d.ts +269 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1223 -0
- package/dist/index.js.map +1 -0
- package/dist/lib.d.ts +31 -0
- package/dist/lib.d.ts.map +1 -0
- package/dist/lib.js +31 -0
- package/dist/lib.js.map +1 -0
- package/dist/limits.d.ts +44 -0
- package/dist/limits.d.ts.map +1 -0
- package/dist/limits.js +44 -0
- package/dist/limits.js.map +1 -0
- package/dist/lsAttestation.d.ts +21 -0
- package/dist/lsAttestation.d.ts.map +1 -0
- package/dist/lsAttestation.js +45 -0
- package/dist/lsAttestation.js.map +1 -0
- package/dist/lsDpp.d.ts +53 -0
- package/dist/lsDpp.d.ts.map +1 -0
- package/dist/lsDpp.js +148 -0
- package/dist/lsDpp.js.map +1 -0
- package/dist/lsUoraDpp.d.ts +55 -0
- package/dist/lsUoraDpp.d.ts.map +1 -0
- package/dist/lsUoraDpp.js +152 -0
- package/dist/lsUoraDpp.js.map +1 -0
- package/dist/policyConfig.d.ts +31 -0
- package/dist/policyConfig.d.ts.map +1 -0
- package/dist/policyConfig.js +112 -0
- package/dist/policyConfig.js.map +1 -0
- package/dist/retraction.d.ts +41 -0
- package/dist/retraction.d.ts.map +1 -0
- package/dist/retraction.js +147 -0
- package/dist/retraction.js.map +1 -0
- package/dist/storage.d.ts +117 -0
- package/dist/storage.d.ts.map +1 -0
- package/dist/storage.js +158 -0
- package/dist/storage.js.map +1 -0
- package/dist/sync.d.ts +75 -0
- package/dist/sync.d.ts.map +1 -0
- package/dist/sync.js +118 -0
- package/dist/sync.js.map +1 -0
- package/dist/tmAttestation.d.ts +36 -0
- package/dist/tmAttestation.d.ts.map +1 -0
- package/dist/tmAttestation.js +50 -0
- package/dist/tmAttestation.js.map +1 -0
- package/dist/tmDpp.d.ts +154 -0
- package/dist/tmDpp.d.ts.map +1 -0
- package/dist/tmDpp.js +397 -0
- package/dist/tmDpp.js.map +1 -0
- package/dist/tmUoraDpp.d.ts +73 -0
- package/dist/tmUoraDpp.d.ts.map +1 -0
- package/dist/tmUoraDpp.js +150 -0
- package/dist/tmUoraDpp.js.map +1 -0
- package/dist/uoraAnchor.d.ts +209 -0
- package/dist/uoraAnchor.d.ts.map +1 -0
- package/dist/uoraAnchor.js +433 -0
- package/dist/uoraAnchor.js.map +1 -0
- package/package.json +51 -0
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import type { LockingScript, WalletProtocol } from '@bsv/sdk';
|
|
2
|
+
/**
|
|
3
|
+
* `uora-anchor-v3`: the attestation anchor output, as this overlay reads it.
|
|
4
|
+
*
|
|
5
|
+
* ## Why the format is not v1
|
|
6
|
+
*
|
|
7
|
+
* v1, the anchoring service's original format, is three fields: a prefix, a
|
|
8
|
+
* digest and the attestation id. It proves an attestation existed at a point
|
|
9
|
+
* in the chain's order and nothing else; its own specification recorded both
|
|
10
|
+
* gaps, and this format closes them:
|
|
11
|
+
*
|
|
12
|
+
* 1. **Nothing in a v1 anchor says who claimed anything.** The digest covers an
|
|
13
|
+
* attestation the chain never sees, so an indexer holding only the output
|
|
14
|
+
* cannot answer "what has this party attested", which is the whole of a
|
|
15
|
+
* DID-keyed lookup. This format carries the issuer's `did:key`, the subject
|
|
16
|
+
* and the UORA type in the clear, because those three are the query.
|
|
17
|
+
* 2. **Nothing in a v1 anchor says who anchored it, either.** v1 locks with
|
|
18
|
+
* counterparty `self`, whose BRC-42 derivation needs the treasury's root
|
|
19
|
+
* *private* key, so a third party cannot reproduce the locking key and
|
|
20
|
+
* cannot tie the output to anyone. That is not a small gap: the anchoring
|
|
21
|
+
* service established that more than one treasury has already anchored
|
|
22
|
+
* under the v1 prefix and the format cannot distinguish them. This format
|
|
23
|
+
* locks with counterparty `'anyone'`, which a stranger *can* reproduce from
|
|
24
|
+
* a published identity key, so `expectedLockingKey` below is checkable by
|
|
25
|
+
* anybody and is what this topic's admission rule turns on.
|
|
26
|
+
*
|
|
27
|
+
* v1 is untouched. Every anchor already broadcast keeps verifying under its
|
|
28
|
+
* own rules, exactly as its specification promises, and the prefixes are
|
|
29
|
+
* distinguishable by reading field 0. This is a new format beside it, not an
|
|
30
|
+
* edit to it.
|
|
31
|
+
*
|
|
32
|
+
* ## Why v3 and not v2
|
|
33
|
+
*
|
|
34
|
+
* v2 had these same seven fields, in this order, with this derivation. What it
|
|
35
|
+
* got wrong was the signature. `PushDrop.lock` appends one over `fields.flat()`,
|
|
36
|
+
* the field bytes run together with no delimiters and no lengths, which
|
|
37
|
+
* authenticates the total byte string and says nothing about where one field
|
|
38
|
+
* ends and the next begins.
|
|
39
|
+
*
|
|
40
|
+
* Four of the seven have their boundaries pinned by other checks anyway: the
|
|
41
|
+
* prefix is a fixed literal, the digest is exactly 64 hex characters, and the
|
|
42
|
+
* attestation id and the anchoring key are both fixed by the derivation of the
|
|
43
|
+
* locking key. The subject and the type are neither, and they are adjacent. So
|
|
44
|
+
* anyone holding a v2 anchor could re-cut that one boundary into a different
|
|
45
|
+
* subject and a different type, copy the signature bytes across verbatim, and
|
|
46
|
+
* still pass every check this reader made. The single v2 anchor on mainnet
|
|
47
|
+
* admits 63 such variants, and this reader would have indexed any of them under
|
|
48
|
+
* a subject nobody had signed.
|
|
49
|
+
*
|
|
50
|
+
* v3 signs `uoraAnchorSigningPreimage` instead: each field behind its own
|
|
51
|
+
* length, so any other split of the same bytes is a different preimage and the
|
|
52
|
+
* signature stops verifying. The prefix moves with it because a reader has no
|
|
53
|
+
* other way to know which preimage to rebuild, and because the format's own
|
|
54
|
+
* rule is that a change of layout is a change of prefix. Nothing repairs the
|
|
55
|
+
* outputs already written, so **v2 is superseded and this reader refuses it**
|
|
56
|
+
* rather than reading it leniently.
|
|
57
|
+
*
|
|
58
|
+
* ## Why this file imports nothing of ours
|
|
59
|
+
*
|
|
60
|
+
* `tm_dpp` reads the token standard, so it depends on `@bsv/dpp-core` and can never
|
|
61
|
+
* be published as part of a shared overlay package. `tm_uora_dpp` is meant to
|
|
62
|
+
* be PR'd into the shared mainnet overlay instances, so it deliberately depends
|
|
63
|
+
* on `@bsv/sdk` and `@bsv/overlay` alone. The fifteen lines of `did:key`
|
|
64
|
+
* decoding below are the same fifteen in `@bsv/dpp-core/did.ts`, duplicated on
|
|
65
|
+
* purpose against the repository's own rule about one implementation per
|
|
66
|
+
* concept: the alternative is that a shared overlay instance takes a dependency
|
|
67
|
+
* on this programme's token core, which is a worse trade. The two are pinned
|
|
68
|
+
* together by a shared fixture rather than by an import
|
|
69
|
+
* (`test/anchor-v3-fixture.ts`), which is the same discipline the
|
|
70
|
+
* canonical-bytes digest is held to across the two repositories.
|
|
71
|
+
*/
|
|
72
|
+
/** Marks the output as ours and versions the field layout. */
|
|
73
|
+
export declare const UORA_ANCHOR_PREFIX = "uora-anchor-v3";
|
|
74
|
+
/**
|
|
75
|
+
* The superseded layout, named so it can be refused deliberately rather than
|
|
76
|
+
* by falling off the end of a string comparison. It is the one near miss worth
|
|
77
|
+
* spelling out: same seven fields, same order, same derivation, often the same
|
|
78
|
+
* treasury, and a signature that does not commit to where the subject stops.
|
|
79
|
+
*/
|
|
80
|
+
export declare const UORA_ANCHOR_PREFIX_V2 = "uora-anchor-v2";
|
|
81
|
+
/**
|
|
82
|
+
* The anchoring service's original three-field format, described above. Never
|
|
83
|
+
* read by this index; named so the capability document can list it as
|
|
84
|
+
* historical rather than leave a reader guessing why v1 anchors are not
|
|
85
|
+
* answered.
|
|
86
|
+
*/
|
|
87
|
+
export declare const UORA_ANCHOR_PREFIX_V1 = "uora-anchor-v1";
|
|
88
|
+
/**
|
|
89
|
+
* BRC-42 child the anchor is locked under. A distinct string from v2's
|
|
90
|
+
* `[1, 'uora anchor v2']` and v1's `[1, 'uora anchor v1']`, because two
|
|
91
|
+
* incompatible formats sharing one protocol name would be two keys wearing one
|
|
92
|
+
* label.
|
|
93
|
+
*/
|
|
94
|
+
export declare const UORA_ANCHOR_PROTOCOL: WalletProtocol;
|
|
95
|
+
/**
|
|
96
|
+
* Basket the outputs land in, unchanged from v1 on purpose: the treasury's
|
|
97
|
+
* balance and its anchor count should keep seeing one population, and the
|
|
98
|
+
* version is legible in field 0 for anything that needs to tell them apart.
|
|
99
|
+
*/
|
|
100
|
+
export declare const UORA_ANCHOR_BASKET = "uora-anchor";
|
|
101
|
+
/** Fields before the appended signature. */
|
|
102
|
+
export declare const UORA_ANCHOR_FIELD_COUNT = 7;
|
|
103
|
+
/**
|
|
104
|
+
* The bytes a v3 signature covers: every field preceded by its own length, so
|
|
105
|
+
* the boundaries between the fields are part of what is signed.
|
|
106
|
+
*
|
|
107
|
+
* Byte-identical in behaviour to `anchorSigningPreimage` in the resolver's
|
|
108
|
+
* `src/anchoring/anchor.ts`, and it has to stay that way. The resolver signs
|
|
109
|
+
* this preimage and appends the result as the eighth field, locking with
|
|
110
|
+
* `includeSignature: false`; this package rebuilds it from the output and
|
|
111
|
+
* checks it. Neither repository can import the other, so the shared fixture in
|
|
112
|
+
* `test/anchor-v3-fixture.ts` is what catches a drift.
|
|
113
|
+
*
|
|
114
|
+
* `PushDrop.lock`'s own signature is not used and cannot be made to serve here:
|
|
115
|
+
* it has no option to commit to boundaries, which is the whole of what went
|
|
116
|
+
* wrong with v2.
|
|
117
|
+
*/
|
|
118
|
+
export declare function uoraAnchorSigningPreimage(fields: number[][]): number[];
|
|
119
|
+
/**
|
|
120
|
+
* One anchor, as read off the chain. Every field validated, nothing inferred.
|
|
121
|
+
*
|
|
122
|
+
* **Two parties appear here and they are not the same one.** `issuer` is who
|
|
123
|
+
* made the claim, and the anchor carries it without checking it. `anchoredBy`
|
|
124
|
+
* is who wrote this output, and the anchor proves it. Conflating them is the
|
|
125
|
+
* one misreading this format invites, which is why they are named apart.
|
|
126
|
+
*/
|
|
127
|
+
export interface UoraAnchor {
|
|
128
|
+
/** Lower-case hex SHA-256 over the attestation's canonical form. */
|
|
129
|
+
digest: string;
|
|
130
|
+
/** The resolver's id for the attestation this digest covers. */
|
|
131
|
+
attestationId: string;
|
|
132
|
+
/** The party that made the claim, as a `did:key`. Carried, not proved. */
|
|
133
|
+
issuer: string;
|
|
134
|
+
/** The issuer's compressed secp256k1 key, hex, decoded from the DID. */
|
|
135
|
+
issuerKey: string;
|
|
136
|
+
/** What the claim is about: a passport id. */
|
|
137
|
+
subject: string;
|
|
138
|
+
/** The UORA attestation type, verbatim and unvalidated against any list. */
|
|
139
|
+
uoraType: string;
|
|
140
|
+
/**
|
|
141
|
+
* The anchoring service's published identity key, hex.
|
|
142
|
+
*
|
|
143
|
+
* Named by the output itself rather than configured into the reader, so this
|
|
144
|
+
* topic needs no per-deployment key list to attribute an anchor: the locking
|
|
145
|
+
* key must be the BRC-42 child of this one, and producing that needs its
|
|
146
|
+
* private half. A shared overlay can therefore carry anchors from a
|
|
147
|
+
* deployment it has never been told about, and still say whose each one is.
|
|
148
|
+
*/
|
|
149
|
+
anchoredBy: string;
|
|
150
|
+
/** The key locking the output: the BRC-42 child of `anchoredBy`. */
|
|
151
|
+
lockingKey: string;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* The seven fields, in order, for whoever writes one.
|
|
155
|
+
*
|
|
156
|
+
* The eighth field a written anchor carries is the signature over
|
|
157
|
+
* `uoraAnchorSigningPreimage(theseSeven)`, appended by the writer. It is not
|
|
158
|
+
* the signature `PushDrop.lock` appends, and a writer that leaves
|
|
159
|
+
* `includeSignature` at its default produces an output this reader refuses.
|
|
160
|
+
*/
|
|
161
|
+
export declare function uoraAnchorFields(anchor: Pick<UoraAnchor, 'digest' | 'attestationId' | 'issuer' | 'subject' | 'uoraType' | 'anchoredBy'>): number[][];
|
|
162
|
+
/**
|
|
163
|
+
* The compressed key inside a `did:key`, or null.
|
|
164
|
+
*
|
|
165
|
+
* Refuses another curve rather than returning bytes that would fail later: an
|
|
166
|
+
* Ed25519 DID is a well-formed `did:key` and a meaningless secp256k1 key, and
|
|
167
|
+
* the difference is the two bytes at the front. Also refuses a non-canonical
|
|
168
|
+
* encoding, because the SDK reduces `x >= p` mod p and would hand back a key
|
|
169
|
+
* that indexes under a DID nobody else computes.
|
|
170
|
+
*/
|
|
171
|
+
export declare function identityKeyFromDidKey(did: string): string | null;
|
|
172
|
+
/** The inverse, so a writer and a reader cannot drift on the encoding. */
|
|
173
|
+
export declare function didKeyFromIdentityKey(identityKeyHex: string): string;
|
|
174
|
+
/**
|
|
175
|
+
* The key an anchor for this attestation id must be locked to, given the
|
|
176
|
+
* anchoring service's published identity key.
|
|
177
|
+
*
|
|
178
|
+
* Half the reason this format exists at all. Counterparty `'anyone'` means this
|
|
179
|
+
* runs with no secret, so the admission rule below is one a stranger can also
|
|
180
|
+
* apply, and a verifier can say "this anchor is that service's" rather than
|
|
181
|
+
* "this anchor is somebody's".
|
|
182
|
+
*/
|
|
183
|
+
export declare function expectedLockingKey(serviceIdentityKey: string, attestationId: string): string;
|
|
184
|
+
/**
|
|
185
|
+
* The version prefix in field 0, or null when the output is not a PushDrop with
|
|
186
|
+
* a readable text field there.
|
|
187
|
+
*
|
|
188
|
+
* Says nothing about whether the rest of the output is valid, and is not a
|
|
189
|
+
* shortcut past `tryParseUoraAnchor`. It exists so a reader can *name* what it
|
|
190
|
+
* is refusing: an anchor turned away for being v2 is a different event from a
|
|
191
|
+
* stranger's output that was never an anchor, and only one of the two is worth
|
|
192
|
+
* telling an operator about.
|
|
193
|
+
*/
|
|
194
|
+
export declare function uoraAnchorPrefix(script: LockingScript): string | null;
|
|
195
|
+
/**
|
|
196
|
+
* Parse and fully validate one output. Null for anything that is not a
|
|
197
|
+
* well-formed v3 anchor, including a v1 or a v2 one, neither of which this
|
|
198
|
+
* topic indexes.
|
|
199
|
+
*
|
|
200
|
+
* Nothing is returned unless the signature verifies, which is not a detail. A
|
|
201
|
+
* caller that got the carried fields back beside a failed signature would be
|
|
202
|
+
* holding an issuer, a subject and a type that nothing vouches for, and would
|
|
203
|
+
* have no way to tell them from ones that do.
|
|
204
|
+
*
|
|
205
|
+
* Total: no throw on any input, because it runs against whatever an overlay is
|
|
206
|
+
* handed. A malformed output is not an error, it is an output that is not ours.
|
|
207
|
+
*/
|
|
208
|
+
export declare function tryParseUoraAnchor(script: LockingScript): UoraAnchor | null;
|
|
209
|
+
//# sourceMappingURL=uoraAnchor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"uoraAnchor.d.ts","sourceRoot":"","sources":["../src/uoraAnchor.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAE7D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqEG;AAEH,8DAA8D;AAC9D,eAAO,MAAM,kBAAkB,mBAAmB,CAAA;AAElD;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,mBAAmB,CAAA;AAErD;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,mBAAmB,CAAA;AAErD;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,EAAE,cAAsC,CAAA;AAEzE;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,gBAAgB,CAAA;AAE/C,4CAA4C;AAC5C,eAAO,MAAM,uBAAuB,IAAI,CAAA;AAExC;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,GAAG,MAAM,EAAE,CAOtE;AA0BD;;;;;;;GAOG;AACH,MAAM,WAAW,UAAU;IACzB,oEAAoE;IACpE,MAAM,EAAE,MAAM,CAAA;IACd,gEAAgE;IAChE,aAAa,EAAE,MAAM,CAAA;IACrB,0EAA0E;IAC1E,MAAM,EAAE,MAAM,CAAA;IACd,wEAAwE;IACxE,SAAS,EAAE,MAAM,CAAA;IACjB,8CAA8C;IAC9C,OAAO,EAAE,MAAM,CAAA;IACf,4EAA4E;IAC5E,QAAQ,EAAE,MAAM,CAAA;IAChB;;;;;;;;OAQG;IACH,UAAU,EAAE,MAAM,CAAA;IAClB,oEAAoE;IACpE,UAAU,EAAE,MAAM,CAAA;CACnB;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,IAAI,CACV,UAAU,EACV,QAAQ,GAAG,eAAe,GAAG,QAAQ,GAAG,SAAS,GAAG,UAAU,GAAG,YAAY,CAC9E,GACA,MAAM,EAAE,EAAE,CAUZ;AAiBD;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAmBhE;AAED,0EAA0E;AAC1E,wBAAgB,qBAAqB,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,CAOpE;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,kBAAkB,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,CAE5F;AA0GD;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,GAAG,IAAI,CAIrE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,aAAa,GAAG,UAAU,GAAG,IAAI,CAwD3E"}
|
|
@@ -0,0 +1,433 @@
|
|
|
1
|
+
import { BigNumber, CachedKeyDeriver, ECDSA, Hash, PublicKey, Signature, Utils } from '@bsv/sdk';
|
|
2
|
+
/**
|
|
3
|
+
* `uora-anchor-v3`: the attestation anchor output, as this overlay reads it.
|
|
4
|
+
*
|
|
5
|
+
* ## Why the format is not v1
|
|
6
|
+
*
|
|
7
|
+
* v1, the anchoring service's original format, is three fields: a prefix, a
|
|
8
|
+
* digest and the attestation id. It proves an attestation existed at a point
|
|
9
|
+
* in the chain's order and nothing else; its own specification recorded both
|
|
10
|
+
* gaps, and this format closes them:
|
|
11
|
+
*
|
|
12
|
+
* 1. **Nothing in a v1 anchor says who claimed anything.** The digest covers an
|
|
13
|
+
* attestation the chain never sees, so an indexer holding only the output
|
|
14
|
+
* cannot answer "what has this party attested", which is the whole of a
|
|
15
|
+
* DID-keyed lookup. This format carries the issuer's `did:key`, the subject
|
|
16
|
+
* and the UORA type in the clear, because those three are the query.
|
|
17
|
+
* 2. **Nothing in a v1 anchor says who anchored it, either.** v1 locks with
|
|
18
|
+
* counterparty `self`, whose BRC-42 derivation needs the treasury's root
|
|
19
|
+
* *private* key, so a third party cannot reproduce the locking key and
|
|
20
|
+
* cannot tie the output to anyone. That is not a small gap: the anchoring
|
|
21
|
+
* service established that more than one treasury has already anchored
|
|
22
|
+
* under the v1 prefix and the format cannot distinguish them. This format
|
|
23
|
+
* locks with counterparty `'anyone'`, which a stranger *can* reproduce from
|
|
24
|
+
* a published identity key, so `expectedLockingKey` below is checkable by
|
|
25
|
+
* anybody and is what this topic's admission rule turns on.
|
|
26
|
+
*
|
|
27
|
+
* v1 is untouched. Every anchor already broadcast keeps verifying under its
|
|
28
|
+
* own rules, exactly as its specification promises, and the prefixes are
|
|
29
|
+
* distinguishable by reading field 0. This is a new format beside it, not an
|
|
30
|
+
* edit to it.
|
|
31
|
+
*
|
|
32
|
+
* ## Why v3 and not v2
|
|
33
|
+
*
|
|
34
|
+
* v2 had these same seven fields, in this order, with this derivation. What it
|
|
35
|
+
* got wrong was the signature. `PushDrop.lock` appends one over `fields.flat()`,
|
|
36
|
+
* the field bytes run together with no delimiters and no lengths, which
|
|
37
|
+
* authenticates the total byte string and says nothing about where one field
|
|
38
|
+
* ends and the next begins.
|
|
39
|
+
*
|
|
40
|
+
* Four of the seven have their boundaries pinned by other checks anyway: the
|
|
41
|
+
* prefix is a fixed literal, the digest is exactly 64 hex characters, and the
|
|
42
|
+
* attestation id and the anchoring key are both fixed by the derivation of the
|
|
43
|
+
* locking key. The subject and the type are neither, and they are adjacent. So
|
|
44
|
+
* anyone holding a v2 anchor could re-cut that one boundary into a different
|
|
45
|
+
* subject and a different type, copy the signature bytes across verbatim, and
|
|
46
|
+
* still pass every check this reader made. The single v2 anchor on mainnet
|
|
47
|
+
* admits 63 such variants, and this reader would have indexed any of them under
|
|
48
|
+
* a subject nobody had signed.
|
|
49
|
+
*
|
|
50
|
+
* v3 signs `uoraAnchorSigningPreimage` instead: each field behind its own
|
|
51
|
+
* length, so any other split of the same bytes is a different preimage and the
|
|
52
|
+
* signature stops verifying. The prefix moves with it because a reader has no
|
|
53
|
+
* other way to know which preimage to rebuild, and because the format's own
|
|
54
|
+
* rule is that a change of layout is a change of prefix. Nothing repairs the
|
|
55
|
+
* outputs already written, so **v2 is superseded and this reader refuses it**
|
|
56
|
+
* rather than reading it leniently.
|
|
57
|
+
*
|
|
58
|
+
* ## Why this file imports nothing of ours
|
|
59
|
+
*
|
|
60
|
+
* `tm_dpp` reads the token standard, so it depends on `@bsv/dpp-core` and can never
|
|
61
|
+
* be published as part of a shared overlay package. `tm_uora_dpp` is meant to
|
|
62
|
+
* be PR'd into the shared mainnet overlay instances, so it deliberately depends
|
|
63
|
+
* on `@bsv/sdk` and `@bsv/overlay` alone. The fifteen lines of `did:key`
|
|
64
|
+
* decoding below are the same fifteen in `@bsv/dpp-core/did.ts`, duplicated on
|
|
65
|
+
* purpose against the repository's own rule about one implementation per
|
|
66
|
+
* concept: the alternative is that a shared overlay instance takes a dependency
|
|
67
|
+
* on this programme's token core, which is a worse trade. The two are pinned
|
|
68
|
+
* together by a shared fixture rather than by an import
|
|
69
|
+
* (`test/anchor-v3-fixture.ts`), which is the same discipline the
|
|
70
|
+
* canonical-bytes digest is held to across the two repositories.
|
|
71
|
+
*/
|
|
72
|
+
/** Marks the output as ours and versions the field layout. */
|
|
73
|
+
export const UORA_ANCHOR_PREFIX = 'uora-anchor-v3';
|
|
74
|
+
/**
|
|
75
|
+
* The superseded layout, named so it can be refused deliberately rather than
|
|
76
|
+
* by falling off the end of a string comparison. It is the one near miss worth
|
|
77
|
+
* spelling out: same seven fields, same order, same derivation, often the same
|
|
78
|
+
* treasury, and a signature that does not commit to where the subject stops.
|
|
79
|
+
*/
|
|
80
|
+
export const UORA_ANCHOR_PREFIX_V2 = 'uora-anchor-v2';
|
|
81
|
+
/**
|
|
82
|
+
* The anchoring service's original three-field format, described above. Never
|
|
83
|
+
* read by this index; named so the capability document can list it as
|
|
84
|
+
* historical rather than leave a reader guessing why v1 anchors are not
|
|
85
|
+
* answered.
|
|
86
|
+
*/
|
|
87
|
+
export const UORA_ANCHOR_PREFIX_V1 = 'uora-anchor-v1';
|
|
88
|
+
/**
|
|
89
|
+
* BRC-42 child the anchor is locked under. A distinct string from v2's
|
|
90
|
+
* `[1, 'uora anchor v2']` and v1's `[1, 'uora anchor v1']`, because two
|
|
91
|
+
* incompatible formats sharing one protocol name would be two keys wearing one
|
|
92
|
+
* label.
|
|
93
|
+
*/
|
|
94
|
+
export const UORA_ANCHOR_PROTOCOL = [1, 'uora anchor v3'];
|
|
95
|
+
/**
|
|
96
|
+
* Basket the outputs land in, unchanged from v1 on purpose: the treasury's
|
|
97
|
+
* balance and its anchor count should keep seeing one population, and the
|
|
98
|
+
* version is legible in field 0 for anything that needs to tell them apart.
|
|
99
|
+
*/
|
|
100
|
+
export const UORA_ANCHOR_BASKET = 'uora-anchor';
|
|
101
|
+
/** Fields before the appended signature. */
|
|
102
|
+
export const UORA_ANCHOR_FIELD_COUNT = 7;
|
|
103
|
+
/**
|
|
104
|
+
* The bytes a v3 signature covers: every field preceded by its own length, so
|
|
105
|
+
* the boundaries between the fields are part of what is signed.
|
|
106
|
+
*
|
|
107
|
+
* Byte-identical in behaviour to `anchorSigningPreimage` in the resolver's
|
|
108
|
+
* `src/anchoring/anchor.ts`, and it has to stay that way. The resolver signs
|
|
109
|
+
* this preimage and appends the result as the eighth field, locking with
|
|
110
|
+
* `includeSignature: false`; this package rebuilds it from the output and
|
|
111
|
+
* checks it. Neither repository can import the other, so the shared fixture in
|
|
112
|
+
* `test/anchor-v3-fixture.ts` is what catches a drift.
|
|
113
|
+
*
|
|
114
|
+
* `PushDrop.lock`'s own signature is not used and cannot be made to serve here:
|
|
115
|
+
* it has no option to commit to boundaries, which is the whole of what went
|
|
116
|
+
* wrong with v2.
|
|
117
|
+
*/
|
|
118
|
+
export function uoraAnchorSigningPreimage(fields) {
|
|
119
|
+
const writer = new Utils.Writer();
|
|
120
|
+
for (const field of fields) {
|
|
121
|
+
writer.writeVarIntNum(field.length);
|
|
122
|
+
writer.write(field);
|
|
123
|
+
}
|
|
124
|
+
return writer.toArray();
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Bounds on the free-text fields. An overlay admits from whoever can reach it,
|
|
128
|
+
* and an index keyed on a field a stranger controls is a field a stranger can
|
|
129
|
+
* make expensive. Generous enough that no honest value is near them: a GS1
|
|
130
|
+
* Digital Link with a long serial is under 200 characters.
|
|
131
|
+
*/
|
|
132
|
+
const MAX_ATTESTATION_ID = 256;
|
|
133
|
+
const MAX_SUBJECT = 512;
|
|
134
|
+
const MAX_TYPE = 64;
|
|
135
|
+
const HEX_64 = /^[0-9a-f]{64}$/;
|
|
136
|
+
/** Rules out control characters and the stray replacement char a bad decode leaves. */
|
|
137
|
+
const PRINTABLE = /^[ -~ -]+$/;
|
|
138
|
+
const OP_CHECKSIG = 0xac;
|
|
139
|
+
const OP_DROP = 0x75;
|
|
140
|
+
const OP_2DROP = 0x6d;
|
|
141
|
+
const SECP256K1_PUB_MULTICODEC = [0xe7, 0x01];
|
|
142
|
+
const BASE58BTC = 'z';
|
|
143
|
+
const DID_KEY_PREFIX = `did:key:${BASE58BTC}`;
|
|
144
|
+
const anyone = new CachedKeyDeriver('anyone');
|
|
145
|
+
/**
|
|
146
|
+
* The seven fields, in order, for whoever writes one.
|
|
147
|
+
*
|
|
148
|
+
* The eighth field a written anchor carries is the signature over
|
|
149
|
+
* `uoraAnchorSigningPreimage(theseSeven)`, appended by the writer. It is not
|
|
150
|
+
* the signature `PushDrop.lock` appends, and a writer that leaves
|
|
151
|
+
* `includeSignature` at its default produces an output this reader refuses.
|
|
152
|
+
*/
|
|
153
|
+
export function uoraAnchorFields(anchor) {
|
|
154
|
+
return [
|
|
155
|
+
Utils.toArray(UORA_ANCHOR_PREFIX, 'utf8'),
|
|
156
|
+
Utils.toArray(anchor.digest, 'utf8'),
|
|
157
|
+
Utils.toArray(anchor.attestationId, 'utf8'),
|
|
158
|
+
Utils.toArray(anchor.issuer, 'utf8'),
|
|
159
|
+
Utils.toArray(anchor.subject, 'utf8'),
|
|
160
|
+
Utils.toArray(anchor.uoraType, 'utf8'),
|
|
161
|
+
Utils.toArray(anchor.anchoredBy, 'utf8'),
|
|
162
|
+
];
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* A 33-byte compressed key in its one canonical spelling, or false.
|
|
166
|
+
*
|
|
167
|
+
* The SDK reduces `x >= p` rather than refusing, so an unchecked encoding would
|
|
168
|
+
* be accepted here and index under a key nobody else computes.
|
|
169
|
+
*/
|
|
170
|
+
function canonicalCompressedKey(hex) {
|
|
171
|
+
if (!/^0[23][0-9a-f]{64}$/.test(hex))
|
|
172
|
+
return false;
|
|
173
|
+
try {
|
|
174
|
+
return PublicKey.fromString(hex).toString() === hex;
|
|
175
|
+
}
|
|
176
|
+
catch {
|
|
177
|
+
return false;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* The compressed key inside a `did:key`, or null.
|
|
182
|
+
*
|
|
183
|
+
* Refuses another curve rather than returning bytes that would fail later: an
|
|
184
|
+
* Ed25519 DID is a well-formed `did:key` and a meaningless secp256k1 key, and
|
|
185
|
+
* the difference is the two bytes at the front. Also refuses a non-canonical
|
|
186
|
+
* encoding, because the SDK reduces `x >= p` mod p and would hand back a key
|
|
187
|
+
* that indexes under a DID nobody else computes.
|
|
188
|
+
*/
|
|
189
|
+
export function identityKeyFromDidKey(did) {
|
|
190
|
+
if (!did.startsWith(DID_KEY_PREFIX))
|
|
191
|
+
return null;
|
|
192
|
+
let bytes;
|
|
193
|
+
try {
|
|
194
|
+
bytes = Utils.fromBase58(did.slice(DID_KEY_PREFIX.length));
|
|
195
|
+
}
|
|
196
|
+
catch {
|
|
197
|
+
return null;
|
|
198
|
+
}
|
|
199
|
+
if (bytes[0] !== SECP256K1_PUB_MULTICODEC[0] || bytes[1] !== SECP256K1_PUB_MULTICODEC[1]) {
|
|
200
|
+
return null;
|
|
201
|
+
}
|
|
202
|
+
const key = bytes.slice(2);
|
|
203
|
+
if (key.length !== 33)
|
|
204
|
+
return null;
|
|
205
|
+
const hex = Utils.toHex(key);
|
|
206
|
+
try {
|
|
207
|
+
return PublicKey.fromString(hex).toString() === hex ? hex : null;
|
|
208
|
+
}
|
|
209
|
+
catch {
|
|
210
|
+
return null;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
/** The inverse, so a writer and a reader cannot drift on the encoding. */
|
|
214
|
+
export function didKeyFromIdentityKey(identityKeyHex) {
|
|
215
|
+
const key = PublicKey.fromString(identityKeyHex);
|
|
216
|
+
if (key.toString() !== identityKeyHex) {
|
|
217
|
+
throw new Error('not a canonical compressed public key');
|
|
218
|
+
}
|
|
219
|
+
const bytes = [...SECP256K1_PUB_MULTICODEC, ...key.encode(true)];
|
|
220
|
+
return `${DID_KEY_PREFIX}${Utils.toBase58(bytes)}`;
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* The key an anchor for this attestation id must be locked to, given the
|
|
224
|
+
* anchoring service's published identity key.
|
|
225
|
+
*
|
|
226
|
+
* Half the reason this format exists at all. Counterparty `'anyone'` means this
|
|
227
|
+
* runs with no secret, so the admission rule below is one a stranger can also
|
|
228
|
+
* apply, and a verifier can say "this anchor is that service's" rather than
|
|
229
|
+
* "this anchor is somebody's".
|
|
230
|
+
*/
|
|
231
|
+
export function expectedLockingKey(serviceIdentityKey, attestationId) {
|
|
232
|
+
return anyone.derivePublicKey(UORA_ANCHOR_PROTOCOL, attestationId, serviceIdentityKey).toString();
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Read a PushDrop locking script into its key and its fields.
|
|
236
|
+
*
|
|
237
|
+
* Written over the chunks rather than `PushDrop.decode` for the reason
|
|
238
|
+
* `/spec` spends four lines on: the decoder renders an empty field as a single
|
|
239
|
+
* zero byte, so a preimage built from its output is one byte too long per empty
|
|
240
|
+
* field and the signature check fails for a reason that has nothing to do with
|
|
241
|
+
* the signature. No v3 field may be empty, so an empty one is rejected either
|
|
242
|
+
* way; reading it exactly means it is rejected for the right reason. It matters
|
|
243
|
+
* more under v3 than it did under v2, because the preimage now carries each
|
|
244
|
+
* field's length and a length read one byte out is a different preimage.
|
|
245
|
+
*/
|
|
246
|
+
function readPushDrop(script) {
|
|
247
|
+
const chunks = script.chunks;
|
|
248
|
+
if (chunks.length < 3)
|
|
249
|
+
return null;
|
|
250
|
+
const keyData = chunks[0]?.data;
|
|
251
|
+
/*
|
|
252
|
+
* Exactly 33 bytes, the compressed encoding a conforming writer emits. A
|
|
253
|
+
* 65-byte uncompressed push used to parse here and then pass attribution,
|
|
254
|
+
* because `PublicKey.toString()` re-compresses before the comparison, which
|
|
255
|
+
* made the acceptance invisible: an anchor in a spelling nobody writes was
|
|
256
|
+
* admitted as though it were canonical. The record rail's reader was always
|
|
257
|
+
* exact about the same push; this one now matches it, and the fixture's
|
|
258
|
+
* `uncompressedKey` vector is what keeps it matched.
|
|
259
|
+
*/
|
|
260
|
+
if (keyData == null || keyData.length !== 33)
|
|
261
|
+
return null;
|
|
262
|
+
if (chunks[1]?.op !== OP_CHECKSIG)
|
|
263
|
+
return null;
|
|
264
|
+
let lockingKey;
|
|
265
|
+
try {
|
|
266
|
+
lockingKey = PublicKey.fromString(Utils.toHex(keyData));
|
|
267
|
+
}
|
|
268
|
+
catch {
|
|
269
|
+
return null;
|
|
270
|
+
}
|
|
271
|
+
const fields = [];
|
|
272
|
+
for (const chunk of chunks.slice(2)) {
|
|
273
|
+
if (chunk.op === OP_DROP || chunk.op === OP_2DROP)
|
|
274
|
+
break;
|
|
275
|
+
if (chunk.data != null && chunk.data.length > 0)
|
|
276
|
+
fields.push(chunk.data);
|
|
277
|
+
else if (chunk.op === 0)
|
|
278
|
+
fields.push([]);
|
|
279
|
+
else if (chunk.op >= 0x51 && chunk.op <= 0x60)
|
|
280
|
+
fields.push([chunk.op - 0x50]);
|
|
281
|
+
else
|
|
282
|
+
return null;
|
|
283
|
+
}
|
|
284
|
+
/*
|
|
285
|
+
* The drop tail, validated exactly the way the record rail's codec validates
|
|
286
|
+
* its own: floor(n/2) OP_2DROPs, one OP_DROP when n is odd, and nothing at
|
|
287
|
+
* all after them. This reader used to stop at the first drop and never look
|
|
288
|
+
* back, so an anchor with a short tail, a wrong mix, or trailing chunks was
|
|
289
|
+
* parsed and admitted; the fixture's `malformedTail` vectors pin the refusal.
|
|
290
|
+
*/
|
|
291
|
+
const tail = chunks.slice(2 + fields.length);
|
|
292
|
+
const twoDrops = Math.floor(fields.length / 2);
|
|
293
|
+
const oneDrop = fields.length % 2;
|
|
294
|
+
const tailValid = tail.length === twoDrops + oneDrop &&
|
|
295
|
+
tail.slice(0, twoDrops).every((chunk) => chunk.op === OP_2DROP) &&
|
|
296
|
+
(oneDrop === 0 || tail[twoDrops]?.op === OP_DROP);
|
|
297
|
+
if (!tailValid)
|
|
298
|
+
return null;
|
|
299
|
+
return { lockingKey, fields };
|
|
300
|
+
}
|
|
301
|
+
/** UTF-8 that round-trips. A field that does not is not a field we wrote. */
|
|
302
|
+
function text(bytes) {
|
|
303
|
+
let decoded;
|
|
304
|
+
try {
|
|
305
|
+
decoded = Utils.toUTF8(bytes);
|
|
306
|
+
}
|
|
307
|
+
catch {
|
|
308
|
+
return null;
|
|
309
|
+
}
|
|
310
|
+
if (decoded === '' || !PRINTABLE.test(decoded))
|
|
311
|
+
return null;
|
|
312
|
+
return Utils.toHex(Utils.toArray(decoded, 'utf8')) === Utils.toHex(bytes) ? decoded : null;
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* The appended signature, checked.
|
|
316
|
+
*
|
|
317
|
+
* It proves the seven fields were sealed **together, at these boundaries**, by
|
|
318
|
+
* whoever holds the key in the script. An output whose digest or issuer was
|
|
319
|
+
* edited after signing fails here; so does one assembled by copying another
|
|
320
|
+
* anchor's signature; and so, now, does one that moves the boundary between the
|
|
321
|
+
* subject and the type without altering a single byte, which is the forgery v2
|
|
322
|
+
* could not see and the reason the preimage is length-prefixed.
|
|
323
|
+
*
|
|
324
|
+
* On its own that is tamper-evidence over the anchor's structure and not
|
|
325
|
+
* attribution. Attribution is `expectedLockingKey`, and the topic manager wants
|
|
326
|
+
* both.
|
|
327
|
+
*/
|
|
328
|
+
function sealedByLockingKey(fields, lockingKey) {
|
|
329
|
+
const signature = fields[UORA_ANCHOR_FIELD_COUNT];
|
|
330
|
+
if (signature == null || signature.length === 0)
|
|
331
|
+
return false;
|
|
332
|
+
const signed = uoraAnchorSigningPreimage(fields.slice(0, UORA_ANCHOR_FIELD_COUNT));
|
|
333
|
+
try {
|
|
334
|
+
return ECDSA.verify(new BigNumber(Hash.sha256(signed)), Signature.fromDER(signature), lockingKey);
|
|
335
|
+
}
|
|
336
|
+
catch {
|
|
337
|
+
return false;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* The version prefix in field 0, or null when the output is not a PushDrop with
|
|
342
|
+
* a readable text field there.
|
|
343
|
+
*
|
|
344
|
+
* Says nothing about whether the rest of the output is valid, and is not a
|
|
345
|
+
* shortcut past `tryParseUoraAnchor`. It exists so a reader can *name* what it
|
|
346
|
+
* is refusing: an anchor turned away for being v2 is a different event from a
|
|
347
|
+
* stranger's output that was never an anchor, and only one of the two is worth
|
|
348
|
+
* telling an operator about.
|
|
349
|
+
*/
|
|
350
|
+
export function uoraAnchorPrefix(script) {
|
|
351
|
+
const decoded = readPushDrop(script);
|
|
352
|
+
const first = decoded?.fields[0];
|
|
353
|
+
return first == null ? null : text(first);
|
|
354
|
+
}
|
|
355
|
+
/**
|
|
356
|
+
* Parse and fully validate one output. Null for anything that is not a
|
|
357
|
+
* well-formed v3 anchor, including a v1 or a v2 one, neither of which this
|
|
358
|
+
* topic indexes.
|
|
359
|
+
*
|
|
360
|
+
* Nothing is returned unless the signature verifies, which is not a detail. A
|
|
361
|
+
* caller that got the carried fields back beside a failed signature would be
|
|
362
|
+
* holding an issuer, a subject and a type that nothing vouches for, and would
|
|
363
|
+
* have no way to tell them from ones that do.
|
|
364
|
+
*
|
|
365
|
+
* Total: no throw on any input, because it runs against whatever an overlay is
|
|
366
|
+
* handed. A malformed output is not an error, it is an output that is not ours.
|
|
367
|
+
*/
|
|
368
|
+
export function tryParseUoraAnchor(script) {
|
|
369
|
+
const decoded = readPushDrop(script);
|
|
370
|
+
if (decoded == null)
|
|
371
|
+
return null;
|
|
372
|
+
const { fields, lockingKey } = decoded;
|
|
373
|
+
if (fields.length !== UORA_ANCHOR_FIELD_COUNT + 1)
|
|
374
|
+
return null;
|
|
375
|
+
const parts = fields.slice(0, UORA_ANCHOR_FIELD_COUNT).map(text);
|
|
376
|
+
if (parts.some((part) => part == null))
|
|
377
|
+
return null;
|
|
378
|
+
const [prefix, digest, attestationId, issuer, subject, uoraType, anchoredBy] = parts;
|
|
379
|
+
/*
|
|
380
|
+
* v2 is refused by name, ahead of the general prefix check, because it is the
|
|
381
|
+
* one near miss somebody maintaining this later might be tempted to wave
|
|
382
|
+
* through: the fields are right, the derivation is right, and the treasury is
|
|
383
|
+
* often ours. Waving it through would index a subject and a type its own
|
|
384
|
+
* signature does not cover. The refusal is a decision, and this is where it
|
|
385
|
+
* is written down rather than left to fall out of a string comparison.
|
|
386
|
+
*/
|
|
387
|
+
if (prefix === UORA_ANCHOR_PREFIX_V2)
|
|
388
|
+
return null;
|
|
389
|
+
if (prefix !== UORA_ANCHOR_PREFIX)
|
|
390
|
+
return null;
|
|
391
|
+
if (!HEX_64.test(digest))
|
|
392
|
+
return null;
|
|
393
|
+
if (attestationId.length > MAX_ATTESTATION_ID)
|
|
394
|
+
return null;
|
|
395
|
+
if (subject.length > MAX_SUBJECT)
|
|
396
|
+
return null;
|
|
397
|
+
if (uoraType.length > MAX_TYPE)
|
|
398
|
+
return null;
|
|
399
|
+
const issuerKey = identityKeyFromDidKey(issuer);
|
|
400
|
+
if (issuerKey == null)
|
|
401
|
+
return null;
|
|
402
|
+
if (!sealedByLockingKey(fields, lockingKey))
|
|
403
|
+
return null;
|
|
404
|
+
/*
|
|
405
|
+
* The attribution check, and it is part of being well-formed rather than a
|
|
406
|
+
* policy on top. An output that names an anchoring service its locking key
|
|
407
|
+
* does not derive from is claiming something untrue about itself, so it is
|
|
408
|
+
* malformed, not merely unwanted. Producing one that passes needs the private
|
|
409
|
+
* half of the key in field 6, which is the whole proof.
|
|
410
|
+
*/
|
|
411
|
+
if (!canonicalCompressedKey(anchoredBy))
|
|
412
|
+
return null;
|
|
413
|
+
let derived;
|
|
414
|
+
try {
|
|
415
|
+
derived = expectedLockingKey(anchoredBy, attestationId);
|
|
416
|
+
}
|
|
417
|
+
catch {
|
|
418
|
+
return null;
|
|
419
|
+
}
|
|
420
|
+
if (derived !== lockingKey.toString())
|
|
421
|
+
return null;
|
|
422
|
+
return {
|
|
423
|
+
digest,
|
|
424
|
+
attestationId,
|
|
425
|
+
issuer,
|
|
426
|
+
issuerKey,
|
|
427
|
+
subject,
|
|
428
|
+
uoraType,
|
|
429
|
+
anchoredBy,
|
|
430
|
+
lockingKey: lockingKey.toString(),
|
|
431
|
+
};
|
|
432
|
+
}
|
|
433
|
+
//# sourceMappingURL=uoraAnchor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"uoraAnchor.js","sourceRoot":"","sources":["../src/uoraAnchor.ts"],"names":[],"mappings":"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"}
|