@metalabel/dfos-protocol 0.8.1 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -4
- package/dist/chain/index.d.ts +11 -4
- package/dist/chain/index.js +3 -3
- package/dist/{chunk-ZXXP5W5N.js → chunk-GQOZJKKO.js} +58 -10
- package/dist/{chunk-LQ56P4SU.js → chunk-GZ7ZAIRD.js} +11 -5
- package/dist/{chunk-MEV6QVLC.js → chunk-LQFOBE6X.js} +27 -41
- package/dist/credentials/index.d.ts +5 -24
- package/dist/credentials/index.js +2 -2
- package/dist/crypto/index.d.ts +16 -7
- package/dist/crypto/index.js +3 -1
- package/dist/index.d.ts +2 -3
- package/dist/index.js +5 -15
- package/dist/{schemas-BEl38wrI.d.ts → schemas-BhikXSf_.d.ts} +0 -2
- package/examples/beacon.json +5 -5
- package/examples/content-delegated.json +11 -11
- package/examples/content-delete.json +5 -5
- package/examples/content-lifecycle.json +9 -9
- package/examples/credential-read.json +3 -3
- package/examples/credential-write.json +5 -5
- package/examples/identity-delete.json +4 -4
- package/examples/identity-genesis.json +3 -3
- package/examples/identity-rotation.json +4 -4
- package/package.json +10 -14
- package/schemas/manifest.v1.json +1 -1
- package/dist/chunk-E5CFQG2B.js +0 -99
- package/dist/merkle/index.d.ts +0 -45
- package/dist/merkle/index.js +0 -14
- package/examples/merkle-tree.json +0 -28
package/README.md
CHANGED
|
@@ -17,8 +17,6 @@ import { verifyContentChain, verifyIdentityChain } from '@metalabel/dfos-protoco
|
|
|
17
17
|
import { createAuthToken, createDFOSCredential } from '@metalabel/dfos-protocol/credentials';
|
|
18
18
|
// Crypto primitives
|
|
19
19
|
import { createJws, dagCborCanonicalEncode, verifyJws } from '@metalabel/dfos-protocol/crypto';
|
|
20
|
-
// Merkle trees
|
|
21
|
-
import { buildMerkleTree, verifyMerkleProof } from '@metalabel/dfos-protocol/merkle';
|
|
22
20
|
```
|
|
23
21
|
|
|
24
22
|
## Subpath Exports
|
|
@@ -28,7 +26,6 @@ import { buildMerkleTree, verifyMerkleProof } from '@metalabel/dfos-protocol/mer
|
|
|
28
26
|
| `@metalabel/dfos-protocol/chain` | Identity and content chain signing, verification, beacons, countersigns |
|
|
29
27
|
| `@metalabel/dfos-protocol/credentials` | Auth tokens (DID-signed JWT) and DFOS credentials for authorization |
|
|
30
28
|
| `@metalabel/dfos-protocol/crypto` | Ed25519, JWS, JWT, dag-cbor, base64url, ID generation |
|
|
31
|
-
| `@metalabel/dfos-protocol/merkle` | SHA-256 binary merkle tree, inclusion proofs |
|
|
32
29
|
|
|
33
30
|
## Specifications
|
|
34
31
|
|
|
@@ -50,7 +47,6 @@ The `examples/` directory contains deterministic reference fixtures that can be
|
|
|
50
47
|
- `content-delegated.json` — creator genesis + delegated update with DFOS write credential
|
|
51
48
|
- `credential-write.json` — DFOS write credential (broad + content-narrowed)
|
|
52
49
|
- `credential-read.json` — DFOS read credential
|
|
53
|
-
- `merkle-tree.json` — 5 content IDs → sorted tree → root, with inclusion proof
|
|
54
50
|
- `beacon.json` — signed manifest pointer announcement with witness countersignature
|
|
55
51
|
|
|
56
52
|
## License
|
package/dist/chain/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { I as IdentityOperation, S as Signer, V as VerifiedIdentity, C as ContentOperation, B as BeaconPayload, a as CountersignPayload, A as ArtifactPayload } from '../schemas-
|
|
2
|
-
export { M as MAX_ARTIFACT_PAYLOAD_SIZE, b as MultikeyPublicKey, R as RevocationPayload } from '../schemas-
|
|
1
|
+
import { I as IdentityOperation, S as Signer, V as VerifiedIdentity, C as ContentOperation, B as BeaconPayload, a as CountersignPayload, A as ArtifactPayload } from '../schemas-BhikXSf_.js';
|
|
2
|
+
export { M as MAX_ARTIFACT_PAYLOAD_SIZE, b as MultikeyPublicKey, R as RevocationPayload } from '../schemas-BhikXSf_.js';
|
|
3
3
|
import 'zod';
|
|
4
4
|
|
|
5
5
|
/** Ed25519 public key multicodec value */
|
|
@@ -32,7 +32,7 @@ declare const deriveChainIdentifier: (cidBytes: Uint8Array, prefix: string) => s
|
|
|
32
32
|
/**
|
|
33
33
|
* Derive a bare content identifier from CID bytes
|
|
34
34
|
*
|
|
35
|
-
* Returns the raw
|
|
35
|
+
* Returns the raw 31-char hash with no prefix. Applications may add
|
|
36
36
|
* their own prefix for routing (e.g., post_xxxx) — that's semantic sugar.
|
|
37
37
|
*/
|
|
38
38
|
declare const deriveContentId: (cidBytes: Uint8Array) => string;
|
|
@@ -89,7 +89,7 @@ declare const verifyIdentityExtensionFromTrustedState: (input: {
|
|
|
89
89
|
}>;
|
|
90
90
|
|
|
91
91
|
interface VerifiedContentChain {
|
|
92
|
-
/** Content identifier — bare
|
|
92
|
+
/** Content identifier — bare 31-char hash derived from genesis CID */
|
|
93
93
|
contentId: string;
|
|
94
94
|
/** CID of the genesis operation */
|
|
95
95
|
genesisCID: string;
|
|
@@ -144,6 +144,11 @@ declare const verifyContentChain: (input: {
|
|
|
144
144
|
* is true, as credential verification needs identity resolution.
|
|
145
145
|
*/
|
|
146
146
|
resolveIdentity?: (did: string) => Promise<VerifiedIdentity | undefined>;
|
|
147
|
+
/**
|
|
148
|
+
* Check whether a credential (leaf or parent) has been revoked. Threaded onto
|
|
149
|
+
* the WRITE path so revoked credentials no longer authorize writes.
|
|
150
|
+
*/
|
|
151
|
+
isRevoked?: (issuerDID: string, credentialCID: string) => Promise<boolean>;
|
|
147
152
|
}) => Promise<VerifiedContentChain>;
|
|
148
153
|
/**
|
|
149
154
|
* Verify a single new content operation against already-verified chain state
|
|
@@ -165,6 +170,8 @@ declare const verifyContentExtensionFromTrustedState: (input: {
|
|
|
165
170
|
enforceAuthorization?: boolean;
|
|
166
171
|
/** Resolve a DID to a VerifiedIdentity. Required when enforceAuthorization is true. */
|
|
167
172
|
resolveIdentity?: (did: string) => Promise<VerifiedIdentity | undefined>;
|
|
173
|
+
/** Check whether a credential (leaf or parent) has been revoked. */
|
|
174
|
+
isRevoked?: (issuerDID: string, credentialCID: string) => Promise<boolean>;
|
|
168
175
|
}) => Promise<{
|
|
169
176
|
state: VerifiedContentChain;
|
|
170
177
|
operationCID: string;
|
package/dist/chain/index.js
CHANGED
|
@@ -24,14 +24,14 @@ import {
|
|
|
24
24
|
verifyIdentityChain,
|
|
25
25
|
verifyIdentityExtensionFromTrustedState,
|
|
26
26
|
verifyRevocation
|
|
27
|
-
} from "../chunk-
|
|
27
|
+
} from "../chunk-GZ7ZAIRD.js";
|
|
28
28
|
import {
|
|
29
29
|
ED25519_PRIV_MULTICODEC,
|
|
30
30
|
ED25519_PUB_MULTICODEC,
|
|
31
31
|
decodeMultikey,
|
|
32
32
|
encodeEd25519Multikey
|
|
33
|
-
} from "../chunk-
|
|
34
|
-
import "../chunk-
|
|
33
|
+
} from "../chunk-LQFOBE6X.js";
|
|
34
|
+
import "../chunk-GQOZJKKO.js";
|
|
35
35
|
export {
|
|
36
36
|
ArtifactPayload,
|
|
37
37
|
BeaconPayload,
|
|
@@ -40,7 +40,7 @@ var isValidEd25519Signature = (payload, signature, publicKey) => {
|
|
|
40
40
|
// src/crypto/id.ts
|
|
41
41
|
import { sha256 as sha256Hash } from "@noble/hashes/sha2.js";
|
|
42
42
|
var alphabet = "2346789acdefhknrtvz";
|
|
43
|
-
var idLength =
|
|
43
|
+
var idLength = 31;
|
|
44
44
|
var getRandomBytes = (length) => {
|
|
45
45
|
const bytes = new Uint8Array(length);
|
|
46
46
|
globalThis.crypto.getRandomValues(bytes);
|
|
@@ -75,6 +75,22 @@ var normalizedId = (prefix, id) => {
|
|
|
75
75
|
return `${prefixLowered}_${idLowered}`;
|
|
76
76
|
};
|
|
77
77
|
|
|
78
|
+
// src/crypto/jws-profile.ts
|
|
79
|
+
var assertJwsProfile = (header, makeError) => {
|
|
80
|
+
if (header.alg !== "EdDSA") {
|
|
81
|
+
throw makeError(`Unsupported algorithm: ${String(header.alg)}`);
|
|
82
|
+
}
|
|
83
|
+
if ("crit" in header) {
|
|
84
|
+
throw makeError("crit header is not supported");
|
|
85
|
+
}
|
|
86
|
+
if ("jwk" in header) {
|
|
87
|
+
throw makeError("jwk header is not allowed (key is resolved from kid)");
|
|
88
|
+
}
|
|
89
|
+
if ("x5c" in header) {
|
|
90
|
+
throw makeError("x5c header is not allowed (key is resolved from kid)");
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
|
|
78
94
|
// src/crypto/jws.ts
|
|
79
95
|
var createJws = async (options) => {
|
|
80
96
|
const headerB64 = base64urlEncode(JSON.stringify(options.header));
|
|
@@ -99,9 +115,10 @@ var verifyJws = (options) => {
|
|
|
99
115
|
} catch {
|
|
100
116
|
throw new JwsVerificationError("Failed to decode token");
|
|
101
117
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
118
|
+
assertJwsProfile(
|
|
119
|
+
header,
|
|
120
|
+
(m) => new JwsVerificationError(m)
|
|
121
|
+
);
|
|
105
122
|
const signingInput = `${headerB64}.${payloadB64}`;
|
|
106
123
|
const signingInputBytes = new TextEncoder().encode(signingInput);
|
|
107
124
|
const signatureBytes = base64urlDecode(signatureB64);
|
|
@@ -172,12 +189,13 @@ var verifyJwt = (options) => {
|
|
|
172
189
|
} catch {
|
|
173
190
|
throw new JwtVerificationError("Failed to decode token");
|
|
174
191
|
}
|
|
192
|
+
assertJwsProfile(
|
|
193
|
+
header,
|
|
194
|
+
(m) => new JwtVerificationError(m)
|
|
195
|
+
);
|
|
175
196
|
const signingInput = `${headerB64}.${payloadB64}`;
|
|
176
197
|
const signingInputBytes = new TextEncoder().encode(signingInput);
|
|
177
198
|
const signatureBytes = base64urlDecode(signatureB64);
|
|
178
|
-
if (header.alg !== "EdDSA") {
|
|
179
|
-
throw new JwtVerificationError(`Unsupported algorithm: ${header.alg}`);
|
|
180
|
-
}
|
|
181
199
|
const isValid = isValidEd25519Signature(signingInputBytes, signatureBytes, options.publicKey);
|
|
182
200
|
if (!isValid) throw new JwtVerificationError("Invalid signature");
|
|
183
201
|
const currentTime = options.currentTime ?? Math.floor(Date.now() / 1e3);
|
|
@@ -209,14 +227,43 @@ import * as Block from "multiformats/block";
|
|
|
209
227
|
import { CID } from "multiformats/cid";
|
|
210
228
|
import { sha256 } from "multiformats/hashes/sha2";
|
|
211
229
|
var dagCborCanonicalEncode = async (value) => {
|
|
230
|
+
assertCanonicalNumbers(value);
|
|
231
|
+
const serialized = JSON.parse(JSON.stringify(value));
|
|
232
|
+
assertCanonicalNumbers(serialized);
|
|
212
233
|
return await Block.encode({
|
|
213
|
-
// removes any undefineds or other non-serializable values
|
|
214
|
-
//
|
|
215
|
-
value:
|
|
234
|
+
// removes any undefineds or other non-serializable values (and normalizes
|
|
235
|
+
// -0 to 0)
|
|
236
|
+
value: serialized,
|
|
216
237
|
codec: dagCborCodec,
|
|
217
238
|
hasher: sha256
|
|
218
239
|
});
|
|
219
240
|
};
|
|
241
|
+
var MAX_SAFE_CANONICAL_INTEGER = 9007199254740991;
|
|
242
|
+
var assertCanonicalNumbers = (value) => {
|
|
243
|
+
if (typeof value === "number") {
|
|
244
|
+
if (!Number.isFinite(value)) {
|
|
245
|
+
throw new Error(`non-finite number is not canonicalizable: ${value}`);
|
|
246
|
+
}
|
|
247
|
+
if (!Number.isInteger(value)) {
|
|
248
|
+
throw new Error(
|
|
249
|
+
`non-integer number is not canonicalizable: ${value} (encode it as a string)`
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
if (value > MAX_SAFE_CANONICAL_INTEGER || value < -MAX_SAFE_CANONICAL_INTEGER) {
|
|
253
|
+
throw new Error(
|
|
254
|
+
`integer out of safe range is not canonicalizable: ${value} (encode it as a string)`
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
if (Array.isArray(value)) {
|
|
260
|
+
for (const entry of value) assertCanonicalNumbers(entry);
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
if (value !== null && typeof value === "object") {
|
|
264
|
+
for (const entry of Object.values(value)) assertCanonicalNumbers(entry);
|
|
265
|
+
}
|
|
266
|
+
};
|
|
220
267
|
var parseDagCborCID = (cid) => {
|
|
221
268
|
return CID.parse(cid);
|
|
222
269
|
};
|
|
@@ -237,6 +284,7 @@ export {
|
|
|
237
284
|
generateId,
|
|
238
285
|
isValidId,
|
|
239
286
|
normalizedId,
|
|
287
|
+
assertJwsProfile,
|
|
240
288
|
createJws,
|
|
241
289
|
verifyJws,
|
|
242
290
|
decodeJwsUnsafe,
|
|
@@ -4,14 +4,14 @@ import {
|
|
|
4
4
|
matchesResource,
|
|
5
5
|
verifyDFOSCredential,
|
|
6
6
|
verifyDelegationChain
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-LQFOBE6X.js";
|
|
8
8
|
import {
|
|
9
9
|
createJws,
|
|
10
10
|
dagCborCanonicalEncode,
|
|
11
11
|
decodeJwsUnsafe,
|
|
12
12
|
generateIdNoPrefix,
|
|
13
13
|
verifyJws
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-GQOZJKKO.js";
|
|
15
15
|
|
|
16
16
|
// src/chain/schemas.ts
|
|
17
17
|
import { z } from "zod";
|
|
@@ -383,10 +383,14 @@ var verifyOperationAuthorization = async (input) => {
|
|
|
383
383
|
resolveIdentity: input.resolveIdentity,
|
|
384
384
|
now: opCreatedAtUnix
|
|
385
385
|
});
|
|
386
|
+
if (input.isRevoked && await input.isRevoked(credential.iss, credential.credentialCID)) {
|
|
387
|
+
throw new Error("credential is revoked");
|
|
388
|
+
}
|
|
386
389
|
await verifyDelegationChain(credential, {
|
|
387
390
|
resolveIdentity: input.resolveIdentity,
|
|
388
391
|
rootDID: input.creatorDID,
|
|
389
|
-
now: opCreatedAtUnix
|
|
392
|
+
now: opCreatedAtUnix,
|
|
393
|
+
...input.isRevoked ? { isRevoked: input.isRevoked } : {}
|
|
390
394
|
});
|
|
391
395
|
if (credential.aud !== "*" && credential.aud !== input.operationDID) {
|
|
392
396
|
throw new Error(
|
|
@@ -470,7 +474,8 @@ var verifyContentChain = async (input) => {
|
|
|
470
474
|
creatorDID: state.creatorDID,
|
|
471
475
|
contentId: state.contentId,
|
|
472
476
|
createdAt: op.createdAt,
|
|
473
|
-
resolveIdentity: input.resolveIdentity
|
|
477
|
+
resolveIdentity: input.resolveIdentity,
|
|
478
|
+
...input.isRevoked ? { isRevoked: input.isRevoked } : {}
|
|
474
479
|
});
|
|
475
480
|
} catch (err) {
|
|
476
481
|
const message = err instanceof Error ? err.message : "unknown error";
|
|
@@ -570,7 +575,8 @@ var verifyContentExtensionFromTrustedState = async (input) => {
|
|
|
570
575
|
creatorDID: currentState.creatorDID,
|
|
571
576
|
contentId: currentState.contentId,
|
|
572
577
|
createdAt: op.createdAt,
|
|
573
|
-
resolveIdentity: input.resolveIdentity
|
|
578
|
+
resolveIdentity: input.resolveIdentity,
|
|
579
|
+
...input.isRevoked ? { isRevoked: input.isRevoked } : {}
|
|
574
580
|
});
|
|
575
581
|
} catch (err) {
|
|
576
582
|
const message = err instanceof Error ? err.message : "unknown error";
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
decodeJwsUnsafe,
|
|
6
6
|
verifyJws,
|
|
7
7
|
verifyJwt
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-GQOZJKKO.js";
|
|
9
9
|
|
|
10
10
|
// src/credentials/schemas.ts
|
|
11
11
|
import { z } from "zod";
|
|
@@ -14,7 +14,7 @@ var MAX_AUD = 512;
|
|
|
14
14
|
var MAX_RESOURCE = 512;
|
|
15
15
|
var MAX_ACTION = 64;
|
|
16
16
|
var MAX_ATT = 32;
|
|
17
|
-
var MAX_PRF =
|
|
17
|
+
var MAX_PRF = 1;
|
|
18
18
|
var Attenuation = z.strictObject({
|
|
19
19
|
resource: z.string().min(1).max(MAX_RESOURCE),
|
|
20
20
|
action: z.string().min(1).max(MAX_ACTION)
|
|
@@ -96,6 +96,7 @@ var verifyAuthToken = (options) => {
|
|
|
96
96
|
iss: result.data.iss,
|
|
97
97
|
aud: result.data.aud,
|
|
98
98
|
exp: result.data.exp,
|
|
99
|
+
iat: result.data.iat,
|
|
99
100
|
kid
|
|
100
101
|
};
|
|
101
102
|
};
|
|
@@ -256,41 +257,38 @@ var verifyDelegationChain = async (credential, options) => {
|
|
|
256
257
|
}
|
|
257
258
|
return { credential, chain, rootDID: options.rootDID };
|
|
258
259
|
}
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
260
|
+
if (current.prf.length > 1) {
|
|
261
|
+
throw new CredentialVerificationError(
|
|
262
|
+
"delegation chain: multi-parent credentials are not supported (prf must have at most one entry)"
|
|
263
|
+
);
|
|
264
|
+
}
|
|
265
|
+
const parent = await verifyDFOSCredential(current.prf[0], {
|
|
266
|
+
resolveIdentity: options.resolveIdentity,
|
|
267
|
+
...options.now !== void 0 ? { now: options.now } : {}
|
|
268
|
+
});
|
|
269
|
+
if (options.isRevoked) {
|
|
270
|
+
const revoked = await options.isRevoked(parent.iss, parent.credentialCID);
|
|
271
|
+
if (revoked) {
|
|
272
|
+
throw new CredentialVerificationError("parent credential in delegation chain is revoked");
|
|
270
273
|
}
|
|
271
|
-
parents.push(parent);
|
|
272
274
|
}
|
|
273
|
-
|
|
274
|
-
if (!matchingParent) {
|
|
275
|
+
if (parent.aud !== "*" && parent.aud !== current.iss) {
|
|
275
276
|
throw new CredentialVerificationError(
|
|
276
|
-
`delegation gap:
|
|
277
|
+
`delegation gap: parent credential audience ${parent.aud} does not match child issuer ${current.iss}`
|
|
277
278
|
);
|
|
278
279
|
}
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
);
|
|
284
|
-
}
|
|
280
|
+
if (current.exp > parent.exp) {
|
|
281
|
+
throw new CredentialVerificationError(
|
|
282
|
+
"delegation chain: child credential expiry exceeds parent expiry"
|
|
283
|
+
);
|
|
285
284
|
}
|
|
286
|
-
|
|
287
|
-
if (!isAttenuated(parentAttUnion, current.att)) {
|
|
285
|
+
if (!isAttenuated(parent.att, current.att)) {
|
|
288
286
|
throw new CredentialVerificationError(
|
|
289
287
|
"delegation chain: child credential scope exceeds parent scope"
|
|
290
288
|
);
|
|
291
289
|
}
|
|
292
|
-
chain.push(
|
|
293
|
-
current =
|
|
290
|
+
chain.push(parent);
|
|
291
|
+
current = parent;
|
|
294
292
|
}
|
|
295
293
|
throw new CredentialVerificationError("delegation chain too deep (max 16 hops)");
|
|
296
294
|
};
|
|
@@ -315,7 +313,7 @@ var isAttenuated = (parentAtt, childAtt) => {
|
|
|
315
313
|
if (!parentActions.has(a)) return false;
|
|
316
314
|
}
|
|
317
315
|
if (parentRes.type === "chain" && parentRes.id === "*") {
|
|
318
|
-
return
|
|
316
|
+
return childRes.type === "chain";
|
|
319
317
|
}
|
|
320
318
|
if (childRes.type === "chain" && childRes.id === "*") {
|
|
321
319
|
return false;
|
|
@@ -323,17 +321,11 @@ var isAttenuated = (parentAtt, childAtt) => {
|
|
|
323
321
|
if (childRes.type === "chain" && parentRes.type === "chain") {
|
|
324
322
|
return childRes.id === parentRes.id;
|
|
325
323
|
}
|
|
326
|
-
if (childRes.type === "chain" && parentRes.type === "manifest") {
|
|
327
|
-
return true;
|
|
328
|
-
}
|
|
329
|
-
if (childRes.type === "manifest" && parentRes.type === "manifest") {
|
|
330
|
-
return childRes.id === parentRes.id;
|
|
331
|
-
}
|
|
332
324
|
return false;
|
|
333
325
|
});
|
|
334
326
|
});
|
|
335
327
|
};
|
|
336
|
-
var matchesResource = async (att, resource, action
|
|
328
|
+
var matchesResource = async (att, resource, action) => {
|
|
337
329
|
const requestedRes = parseResource(resource);
|
|
338
330
|
if (!requestedRes) return false;
|
|
339
331
|
const requestedActions = parseActions(action);
|
|
@@ -355,12 +347,6 @@ var matchesResource = async (att, resource, action, options) => {
|
|
|
355
347
|
if (entryRes.type === requestedRes.type && entryRes.id === requestedRes.id) {
|
|
356
348
|
return true;
|
|
357
349
|
}
|
|
358
|
-
if (entryRes.type === "manifest" && requestedRes.type === "chain") {
|
|
359
|
-
if (options?.manifestLookup) {
|
|
360
|
-
const indexed = await options.manifestLookup(entryRes.id);
|
|
361
|
-
if (indexed.includes(requestedRes.id)) return true;
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
350
|
}
|
|
365
351
|
return false;
|
|
366
352
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { V as VerifiedIdentity } from '../schemas-
|
|
2
|
+
import { V as VerifiedIdentity } from '../schemas-BhikXSf_.js';
|
|
3
3
|
|
|
4
4
|
/** Single attenuation entry — resource + action pair */
|
|
5
5
|
declare const Attenuation: z.ZodObject<{
|
|
@@ -11,34 +11,23 @@ type Attenuation = z.infer<typeof Attenuation>;
|
|
|
11
11
|
declare const DFOSCredentialPayload: z.ZodObject<{
|
|
12
12
|
version: z.ZodLiteral<1>;
|
|
13
13
|
type: z.ZodLiteral<"DFOSCredential">;
|
|
14
|
-
/** Issuer DID */
|
|
15
14
|
iss: z.ZodString;
|
|
16
|
-
/** Audience DID or "*" for public credentials */
|
|
17
15
|
aud: z.ZodString;
|
|
18
|
-
/** Attenuations — resource + action pairs */
|
|
19
16
|
att: z.ZodArray<z.ZodObject<{
|
|
20
17
|
resource: z.ZodString;
|
|
21
18
|
action: z.ZodString;
|
|
22
19
|
}, z.core.$strict>>;
|
|
23
|
-
/** Parent credential JWS tokens (for delegation chains) */
|
|
24
20
|
prf: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
25
|
-
/** Expiration — unix seconds */
|
|
26
21
|
exp: z.ZodNumber;
|
|
27
|
-
/** Issued at — unix seconds */
|
|
28
22
|
iat: z.ZodNumber;
|
|
29
23
|
}, z.core.$strict>;
|
|
30
24
|
type DFOSCredentialPayload = z.infer<typeof DFOSCredentialPayload>;
|
|
31
25
|
/** Claims for a DID-signed auth token (relay AuthN) */
|
|
32
26
|
declare const AuthTokenClaims: z.ZodObject<{
|
|
33
|
-
/** Issuer — the DID proving identity */
|
|
34
27
|
iss: z.ZodString;
|
|
35
|
-
/** Subject — same as iss for auth tokens */
|
|
36
28
|
sub: z.ZodString;
|
|
37
|
-
/** Audience — target relay hostname (prevents cross-relay replay) */
|
|
38
29
|
aud: z.ZodString;
|
|
39
|
-
/** Expiration — unix seconds, short-lived (minutes) */
|
|
40
30
|
exp: z.ZodNumber;
|
|
41
|
-
/** Issued at — unix seconds */
|
|
42
31
|
iat: z.ZodNumber;
|
|
43
32
|
}, z.core.$strict>;
|
|
44
33
|
type AuthTokenClaims = z.infer<typeof AuthTokenClaims>;
|
|
@@ -74,6 +63,8 @@ interface VerifiedAuthToken {
|
|
|
74
63
|
aud: string;
|
|
75
64
|
/** Token expiration (unix seconds) */
|
|
76
65
|
exp: number;
|
|
66
|
+
/** Token issued-at (unix seconds) */
|
|
67
|
+
iat: number;
|
|
77
68
|
/** kid from the JWT header */
|
|
78
69
|
kid: string;
|
|
79
70
|
}
|
|
@@ -179,12 +170,8 @@ declare const verifyDelegationChain: (credential: VerifiedDFOSCredential, option
|
|
|
179
170
|
*
|
|
180
171
|
* - `chain:X` covered by `chain:X` (exact match)
|
|
181
172
|
* - `chain:X` covered by `chain:*` (narrowing from wildcard — valid)
|
|
182
|
-
* - `chain:X` covered by `manifest:M` (narrowing from manifest — valid structurally)
|
|
183
|
-
* - `manifest:M` covered by `chain:*` (narrowing from wildcard — valid)
|
|
184
|
-
* - `manifest:M` covered by `manifest:M` (exact match)
|
|
185
|
-
* - `manifest:M` NOT covered by `chain:X` (widening — invalid)
|
|
186
173
|
* - `chain:*` covered by `chain:*` (exact match)
|
|
187
|
-
* - `chain:*` NOT covered by `chain:X`
|
|
174
|
+
* - `chain:*` NOT covered by `chain:X` (widening — invalid)
|
|
188
175
|
* - Actions: child action set must be a subset of parent action set
|
|
189
176
|
*/
|
|
190
177
|
declare const isAttenuated: (parentAtt: Attenuation[], childAtt: Attenuation[]) => boolean;
|
|
@@ -193,14 +180,8 @@ declare const isAttenuated: (parentAtt: Attenuation[], childAtt: Attenuation[])
|
|
|
193
180
|
*
|
|
194
181
|
* Used at the relay to determine if a credential authorizes access to a
|
|
195
182
|
* specific content chain.
|
|
196
|
-
*
|
|
197
|
-
* For `manifest:` resources, requires a `manifestLookup` callback to resolve
|
|
198
|
-
* which contentIds the manifest indexes. Without the callback, `manifest:`
|
|
199
|
-
* resources can only match exact `manifest:` requests, not `chain:` requests.
|
|
200
183
|
*/
|
|
201
|
-
declare const matchesResource: (att: Attenuation[], resource: string, action: string
|
|
202
|
-
manifestLookup?: (manifestContentId: string) => Promise<string[]>;
|
|
203
|
-
}) => Promise<boolean>;
|
|
184
|
+
declare const matchesResource: (att: Attenuation[], resource: string, action: string) => Promise<boolean>;
|
|
204
185
|
/**
|
|
205
186
|
* Decode a DFOS credential JWS without verifying the signature
|
|
206
187
|
*
|
|
@@ -12,8 +12,8 @@ import {
|
|
|
12
12
|
verifyAuthToken,
|
|
13
13
|
verifyDFOSCredential,
|
|
14
14
|
verifyDelegationChain
|
|
15
|
-
} from "../chunk-
|
|
16
|
-
import "../chunk-
|
|
15
|
+
} from "../chunk-LQFOBE6X.js";
|
|
16
|
+
import "../chunk-GQOZJKKO.js";
|
|
17
17
|
export {
|
|
18
18
|
Attenuation,
|
|
19
19
|
AuthTokenClaims,
|
package/dist/crypto/index.d.ts
CHANGED
|
@@ -14,22 +14,22 @@ declare const base64urlDecode: (str: string) => Uint8Array;
|
|
|
14
14
|
* Generate a new random Ed25519 keypair
|
|
15
15
|
*/
|
|
16
16
|
declare const createNewEd25519Keypair: () => {
|
|
17
|
-
privateKey: Uint8Array<ArrayBufferLike>;
|
|
18
|
-
publicKey: Uint8Array<ArrayBufferLike>;
|
|
17
|
+
privateKey: Uint8Array<ArrayBufferLike> & Uint8Array<ArrayBuffer>;
|
|
18
|
+
publicKey: Uint8Array<ArrayBufferLike> & Uint8Array<ArrayBuffer>;
|
|
19
19
|
};
|
|
20
20
|
/**
|
|
21
21
|
* Generate an Ed25519 keypair from a private key
|
|
22
22
|
*/
|
|
23
23
|
declare const importEd25519Keypair: (privateKey: Uint8Array) => {
|
|
24
24
|
privateKey: Uint8Array<ArrayBufferLike>;
|
|
25
|
-
publicKey: Uint8Array<ArrayBufferLike>;
|
|
25
|
+
publicKey: Uint8Array<ArrayBufferLike> & Uint8Array<ArrayBuffer>;
|
|
26
26
|
};
|
|
27
27
|
/**
|
|
28
28
|
* Sign a payload with an Ed25519 private key
|
|
29
29
|
*
|
|
30
30
|
* Ed25519 handles hashing internally (SHA-512) — no external prehash needed
|
|
31
31
|
*/
|
|
32
|
-
declare const signPayloadEd25519: (payload: Uint8Array, privateKey: Uint8Array) => Uint8Array<ArrayBufferLike>;
|
|
32
|
+
declare const signPayloadEd25519: (payload: Uint8Array, privateKey: Uint8Array) => Uint8Array<ArrayBufferLike> & Uint8Array<ArrayBuffer>;
|
|
33
33
|
/**
|
|
34
34
|
* Check that a signature is valid for a given payload and Ed25519 public key
|
|
35
35
|
*/
|
|
@@ -51,7 +51,7 @@ declare const generateIdNoPrefix: (options?: {
|
|
|
51
51
|
/**
|
|
52
52
|
* Generate a prefixed ID
|
|
53
53
|
*
|
|
54
|
-
* Without options: generates random
|
|
54
|
+
* Without options: generates random 31-char ID
|
|
55
55
|
* With { seed }: generates deterministic ID from seed (for external ID mapping)
|
|
56
56
|
*
|
|
57
57
|
* @example
|
|
@@ -66,7 +66,7 @@ declare const generateId: <T extends string>(prefix: T, options?: {
|
|
|
66
66
|
*
|
|
67
67
|
* @param prefix - Expected prefix (e.g., 'msg', 'post')
|
|
68
68
|
* @param id - ID to validate
|
|
69
|
-
* @returns true if ID has correct prefix and length (prefix + _ +
|
|
69
|
+
* @returns true if ID has correct prefix and length (prefix + _ + 31 chars)
|
|
70
70
|
*
|
|
71
71
|
* @example
|
|
72
72
|
* isValidId('msg', 'msg_abc123...') // true
|
|
@@ -125,6 +125,15 @@ declare class JwsVerificationError extends Error {
|
|
|
125
125
|
constructor(message: string);
|
|
126
126
|
}
|
|
127
127
|
|
|
128
|
+
/**
|
|
129
|
+
* Apply the DFOS signature verification profile to a decoded protected header.
|
|
130
|
+
*
|
|
131
|
+
* Throws the provided error type with a precise message on any violation. The
|
|
132
|
+
* caller invokes this BEFORE verifying the signature so that an out-of-profile
|
|
133
|
+
* token is rejected regardless of whether its signature would have verified.
|
|
134
|
+
*/
|
|
135
|
+
declare const assertJwsProfile: (header: Record<string, unknown>, makeError: (message: string) => Error) => void;
|
|
136
|
+
|
|
128
137
|
interface JwtHeader {
|
|
129
138
|
alg: 'EdDSA';
|
|
130
139
|
typ: 'JWT';
|
|
@@ -202,4 +211,4 @@ declare const parseDagCborCID: (cid: string) => CID<unknown, number, number, mul
|
|
|
202
211
|
*/
|
|
203
212
|
declare const isCanonicallyEqual: (data1: unknown, data2: unknown) => Promise<boolean>;
|
|
204
213
|
|
|
205
|
-
export { type JwsHeader, JwsVerificationError, type JwtClaims, type JwtCreateOptions, type JwtHeader, JwtVerificationError, type JwtVerifyOptions, type PrefixedID, base64urlDecode, base64urlEncode, createJws, createJwt, createNewEd25519Keypair, dagCborCanonicalEncode, decodeJwsUnsafe, decodeJwtUnsafe, generateId, generateIdNoPrefix, importEd25519Keypair, isCanonicallyEqual, isValidEd25519Signature, isValidId, normalizedId, parseDagCborCID, signPayloadEd25519, verifyJws, verifyJwt };
|
|
214
|
+
export { type JwsHeader, JwsVerificationError, type JwtClaims, type JwtCreateOptions, type JwtHeader, JwtVerificationError, type JwtVerifyOptions, type PrefixedID, assertJwsProfile, base64urlDecode, base64urlEncode, createJws, createJwt, createNewEd25519Keypair, dagCborCanonicalEncode, decodeJwsUnsafe, decodeJwtUnsafe, generateId, generateIdNoPrefix, importEd25519Keypair, isCanonicallyEqual, isValidEd25519Signature, isValidId, normalizedId, parseDagCborCID, signPayloadEd25519, verifyJws, verifyJwt };
|
package/dist/crypto/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
JwsVerificationError,
|
|
3
3
|
JwtVerificationError,
|
|
4
|
+
assertJwsProfile,
|
|
4
5
|
base64urlDecode,
|
|
5
6
|
base64urlEncode,
|
|
6
7
|
createJws,
|
|
@@ -20,10 +21,11 @@ import {
|
|
|
20
21
|
signPayloadEd25519,
|
|
21
22
|
verifyJws,
|
|
22
23
|
verifyJwt
|
|
23
|
-
} from "../chunk-
|
|
24
|
+
} from "../chunk-GQOZJKKO.js";
|
|
24
25
|
export {
|
|
25
26
|
JwsVerificationError,
|
|
26
27
|
JwtVerificationError,
|
|
28
|
+
assertJwsProfile,
|
|
27
29
|
base64urlDecode,
|
|
28
30
|
base64urlEncode,
|
|
29
31
|
createJws,
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
export { JwsHeader, JwsVerificationError, JwtClaims, JwtCreateOptions, JwtHeader, JwtVerificationError, JwtVerifyOptions, PrefixedID, base64urlDecode, base64urlEncode, createJws, createJwt, createNewEd25519Keypair, dagCborCanonicalEncode, decodeJwsUnsafe, decodeJwtUnsafe, generateId, generateIdNoPrefix, importEd25519Keypair, isCanonicallyEqual, isValidEd25519Signature, isValidId, normalizedId, parseDagCborCID, signPayloadEd25519, verifyJws, verifyJwt } from './crypto/index.js';
|
|
2
|
-
export { A as ArtifactPayload, B as BeaconPayload, C as ContentOperation, a as CountersignPayload, I as IdentityOperation, M as MAX_ARTIFACT_PAYLOAD_SIZE, b as MultikeyPublicKey, R as RevocationPayload, S as Signer, V as VerifiedIdentity } from './schemas-
|
|
1
|
+
export { JwsHeader, JwsVerificationError, JwtClaims, JwtCreateOptions, JwtHeader, JwtVerificationError, JwtVerifyOptions, PrefixedID, assertJwsProfile, base64urlDecode, base64urlEncode, createJws, createJwt, createNewEd25519Keypair, dagCborCanonicalEncode, decodeJwsUnsafe, decodeJwtUnsafe, generateId, generateIdNoPrefix, importEd25519Keypair, isCanonicallyEqual, isValidEd25519Signature, isValidId, normalizedId, parseDagCborCID, signPayloadEd25519, verifyJws, verifyJwt } from './crypto/index.js';
|
|
2
|
+
export { A as ArtifactPayload, B as BeaconPayload, C as ContentOperation, a as CountersignPayload, I as IdentityOperation, M as MAX_ARTIFACT_PAYLOAD_SIZE, b as MultikeyPublicKey, R as RevocationPayload, S as Signer, V as VerifiedIdentity } from './schemas-BhikXSf_.js';
|
|
3
3
|
export { ED25519_PRIV_MULTICODEC, ED25519_PUB_MULTICODEC, VerifiedArtifact, VerifiedBeacon, VerifiedContentChain, VerifiedCountersignature, VerifiedRevocation, decodeMultikey, deriveChainIdentifier, deriveContentId, encodeEd25519Multikey, signArtifact, signBeacon, signContentOperation, signCountersignature, signIdentityOperation, signRevocation, verifyArtifact, verifyBeacon, verifyContentChain, verifyContentExtensionFromTrustedState, verifyCountersignature, verifyIdentityChain, verifyIdentityExtensionFromTrustedState, verifyRevocation } from './chain/index.js';
|
|
4
|
-
export { MerkleProof, buildMerkleTree, generateMerkleProof, hashLeaf, hexToBytes, verifyMerkleProof } from './merkle/index.js';
|
|
5
4
|
export { Attenuation, AuthTokenClaims, AuthTokenCreateOptions, AuthTokenVerificationError, AuthTokenVerifyOptions, CredentialVerificationError, DFOSCredentialPayload, VerifiedAuthToken, VerifiedDFOSCredential, VerifiedDelegationChain, createAuthToken, createDFOSCredential, decodeDFOSCredentialUnsafe, isAttenuated, matchesResource, verifyAuthToken, verifyDFOSCredential, verifyDelegationChain } from './credentials/index.js';
|
|
6
5
|
import 'multiformats';
|
|
7
6
|
import 'multiformats/cid';
|
package/dist/index.js
CHANGED
|
@@ -24,14 +24,7 @@ import {
|
|
|
24
24
|
verifyIdentityChain,
|
|
25
25
|
verifyIdentityExtensionFromTrustedState,
|
|
26
26
|
verifyRevocation
|
|
27
|
-
} from "./chunk-
|
|
28
|
-
import {
|
|
29
|
-
buildMerkleTree,
|
|
30
|
-
generateMerkleProof,
|
|
31
|
-
hashLeaf,
|
|
32
|
-
hexToBytes,
|
|
33
|
-
verifyMerkleProof
|
|
34
|
-
} from "./chunk-E5CFQG2B.js";
|
|
27
|
+
} from "./chunk-GZ7ZAIRD.js";
|
|
35
28
|
import {
|
|
36
29
|
Attenuation,
|
|
37
30
|
AuthTokenClaims,
|
|
@@ -50,10 +43,11 @@ import {
|
|
|
50
43
|
verifyAuthToken,
|
|
51
44
|
verifyDFOSCredential,
|
|
52
45
|
verifyDelegationChain
|
|
53
|
-
} from "./chunk-
|
|
46
|
+
} from "./chunk-LQFOBE6X.js";
|
|
54
47
|
import {
|
|
55
48
|
JwsVerificationError,
|
|
56
49
|
JwtVerificationError,
|
|
50
|
+
assertJwsProfile,
|
|
57
51
|
base64urlDecode,
|
|
58
52
|
base64urlEncode,
|
|
59
53
|
createJws,
|
|
@@ -73,7 +67,7 @@ import {
|
|
|
73
67
|
signPayloadEd25519,
|
|
74
68
|
verifyJws,
|
|
75
69
|
verifyJwt
|
|
76
|
-
} from "./chunk-
|
|
70
|
+
} from "./chunk-GQOZJKKO.js";
|
|
77
71
|
export {
|
|
78
72
|
ArtifactPayload,
|
|
79
73
|
Attenuation,
|
|
@@ -93,9 +87,9 @@ export {
|
|
|
93
87
|
MultikeyPublicKey,
|
|
94
88
|
RevocationPayload,
|
|
95
89
|
VerifiedIdentity,
|
|
90
|
+
assertJwsProfile,
|
|
96
91
|
base64urlDecode,
|
|
97
92
|
base64urlEncode,
|
|
98
|
-
buildMerkleTree,
|
|
99
93
|
createAuthToken,
|
|
100
94
|
createDFOSCredential,
|
|
101
95
|
createJws,
|
|
@@ -111,9 +105,6 @@ export {
|
|
|
111
105
|
encodeEd25519Multikey,
|
|
112
106
|
generateId,
|
|
113
107
|
generateIdNoPrefix,
|
|
114
|
-
generateMerkleProof,
|
|
115
|
-
hashLeaf,
|
|
116
|
-
hexToBytes,
|
|
117
108
|
importEd25519Keypair,
|
|
118
109
|
isAttenuated,
|
|
119
110
|
isCanonicallyEqual,
|
|
@@ -141,6 +132,5 @@ export {
|
|
|
141
132
|
verifyIdentityExtensionFromTrustedState,
|
|
142
133
|
verifyJws,
|
|
143
134
|
verifyJwt,
|
|
144
|
-
verifyMerkleProof,
|
|
145
135
|
verifyRevocation
|
|
146
136
|
};
|
|
@@ -91,7 +91,6 @@ declare const ContentOperation: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
91
91
|
baseDocumentCID: z.ZodNullable<z.ZodString>;
|
|
92
92
|
createdAt: z.ZodISODateTime;
|
|
93
93
|
note: z.ZodNullable<z.ZodString>;
|
|
94
|
-
/** DFOS credential authorizing this operation when signer is not the chain creator */
|
|
95
94
|
authorization: z.ZodOptional<z.ZodString>;
|
|
96
95
|
}, z.core.$strict>, z.ZodObject<{
|
|
97
96
|
version: z.ZodLiteral<1>;
|
|
@@ -100,7 +99,6 @@ declare const ContentOperation: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
100
99
|
previousOperationCID: z.ZodString;
|
|
101
100
|
createdAt: z.ZodISODateTime;
|
|
102
101
|
note: z.ZodNullable<z.ZodString>;
|
|
103
|
-
/** DFOS credential authorizing this operation when signer is not the chain creator */
|
|
104
102
|
authorization: z.ZodOptional<z.ZodString>;
|
|
105
103
|
}, z.core.$strict>], "type">;
|
|
106
104
|
type ContentOperation = z.infer<typeof ContentOperation>;
|
package/examples/beacon.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"description": "Beacon: signed manifest content ID announcement with witness countersignature",
|
|
3
3
|
"type": "beacon",
|
|
4
|
-
"controllerJws": "
|
|
5
|
-
"witnessJws": "
|
|
4
|
+
"controllerJws": "eyJhbGciOiJFZERTQSIsInR5cCI6ImRpZDpkZm9zOmJlYWNvbiIsImtpZCI6ImRpZDpkZm9zOmNubm5mdDlmOGEycm45MzhkNm5rejM4cjg0N3Yya3Ija2V5X3I5ZXYzNGZ2YzIzejk5OXZlYWFmdDgzbm4yOXp2aGUiLCJjaWQiOiJiYWZ5cmVpYjR3MnAydTZ0bHc3N3NidGtwdnc3ZnF2d3ZrNnJ3MzdweWFtM29zb2JvNXhwM29vZWt1cSJ9.eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiYmVhY29uIiwiZGlkIjoiZGlkOmRmb3M6Y25ubmZ0OWY4YTJybjkzOGQ2bmt6MzhyODQ3djJrciIsIm1hbmlmZXN0Q29udGVudElkIjoiY3Y3bjh2a3ZyNjRjY3RmMzI5NGg5azRlYW5oZmY4eiIsImNyZWF0ZWRBdCI6IjIwMjYtMDMtMDdUMDA6MDU6MDAuMDAwWiJ9.exr0Dfb_asVXeMpnUOaql9ppeO2pifzEdId8ocXHQ6-v_XUwccQdJaL4MhKzJGUbRAa0hfRVSFRndhjJ4NN1DA",
|
|
5
|
+
"witnessJws": "eyJhbGciOiJFZERTQSIsInR5cCI6ImRpZDpkZm9zOmJlYWNvbiIsImtpZCI6ImRpZDpkZm9zOmNubm5mdDlmOGEycm45MzhkNm5rejM4cjg0N3Yya3Ija2V5X2V6OWE4NzR0Y2tyM2R2OTMzZDNja2RuN3o2enJjdDgiLCJjaWQiOiJiYWZ5cmVpYjR3MnAydTZ0bHc3N3NidGtwdnc3ZnF2d3ZrNnJ3MzdweWFtM29zb2JvNXhwM29vZWt1cSJ9.eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiYmVhY29uIiwiZGlkIjoiZGlkOmRmb3M6Y25ubmZ0OWY4YTJybjkzOGQ2bmt6MzhyODQ3djJrciIsIm1hbmlmZXN0Q29udGVudElkIjoiY3Y3bjh2a3ZyNjRjY3RmMzI5NGg5azRlYW5oZmY4eiIsImNyZWF0ZWRBdCI6IjIwMjYtMDMtMDdUMDA6MDU6MDAuMDAwWiJ9.-49R4npkmKMJtnK4sVS_x7MFOgB1RhjkZAzwycLp80g_o6y0gV0JjnUAj12as8NglccBXEk_5DdZTFs17ygKCA",
|
|
6
6
|
"controllerPublicKey": "z6MkrzLMNwoJSV4P3YccWcbtk8vd9LtgMKnLeaDLUqLuASjb",
|
|
7
7
|
"witnessPublicKey": "z6MkfUd65JrAhfdgFuMCccU9ThQvjB2fJAMUHkuuajF992gK",
|
|
8
8
|
"expected": {
|
|
9
|
-
"beaconCID": "
|
|
10
|
-
"did": "did:dfos:
|
|
11
|
-
"manifestContentId": "
|
|
9
|
+
"beaconCID": "bafyreib4w2p2u6tlw77sbtkpvw7fqvwvk6rw37pyam3osobo5xp3ooekuq",
|
|
10
|
+
"did": "did:dfos:cnnnft9f8a2rn938d6nkz38r847v2kr",
|
|
11
|
+
"manifestContentId": "cv7n8vkvr64cctf3294h9k4eanhff8z",
|
|
12
12
|
"createdAt": "2026-03-07T00:05:00.000Z"
|
|
13
13
|
}
|
|
14
14
|
}
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
"description": "Content chain: creator signs genesis, delegate signs update with write credential",
|
|
3
3
|
"type": "content-delegated",
|
|
4
4
|
"chain": [
|
|
5
|
-
"
|
|
6
|
-
"
|
|
5
|
+
"eyJhbGciOiJFZERTQSIsInR5cCI6ImRpZDpkZm9zOmNvbnRlbnQtb3AiLCJraWQiOiJkaWQ6ZGZvczpjbm5uZnQ5ZjhhMnJuOTM4ZDZua3ozOHI4NDd2MmtyI2tleV9yOWV2MzRmdmMyM3o5OTl2ZWFhZnQ4M25uMjl6dmhlIiwiY2lkIjoiYmFmeXJlaWRkc2pnZGk3dmZib2tlejVyZWl4enRmcm9kNnhjbmh0Ymc0NmI3dnZmZGRwb2Z4czVtaXkifQ.eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiY3JlYXRlIiwiZGlkIjoiZGlkOmRmb3M6Y25ubmZ0OWY4YTJybjkzOGQ2bmt6MzhyODQ3djJrciIsImRvY3VtZW50Q0lEIjoiYmFmeXJlaWRyd2V4NWRjYjJ1c3NqNmJ0eGJjMzQyM3U1d2VzNnJyd29tbXhhemt1bHRzcG9oN2EzdGkiLCJiYXNlRG9jdW1lbnRDSUQiOm51bGwsImNyZWF0ZWRBdCI6IjIwMjYtMDMtMDdUMDA6MTA6MDAuMDAwWiIsIm5vdGUiOm51bGx9.cxfEOGZ08zCQVuqiiljZNCxZudQi3CGqANtFnWLVyh0m9Sdq2yFk_fl4jCcw_4lTDvkYOkMgEOm_VvkpnqdMDA",
|
|
6
|
+
"eyJhbGciOiJFZERTQSIsInR5cCI6ImRpZDpkZm9zOmNvbnRlbnQtb3AiLCJraWQiOiJkaWQ6ZGZvczo5NGFoNzk2M24yMjNrOGM5ODg0aGgyN2VraDQybmVhI2tleV9hOHIyNzQzNGFhcjc2YWU3MmM4NzdmYTQ3a2FyOHJuIiwiY2lkIjoiYmFmeXJlaWd3ZjI0aGhkN2N3dGlhMndocWl3bDVndHZwbGRxNnZtZmozY2ZvdGV5cmJpdjNxMmJhbGkifQ.eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoidXBkYXRlIiwiZGlkIjoiZGlkOmRmb3M6OTRhaDc5NjNuMjIzazhjOTg4NGhoMjdla2g0Mm5lYSIsInByZXZpb3VzT3BlcmF0aW9uQ0lEIjoiYmFmeXJlaWRkc2pnZGk3dmZib2tlejVyZWl4enRmcm9kNnhjbmh0Ymc0NmI3dnZmZGRwb2Z4czVtaXkiLCJkb2N1bWVudENJRCI6ImJhZnlyZWllanNzaWhrZGZsamphYmRhbWhrdXlpYm1jNzQzaG4zaTM2YTdmbnV6c2plb2FydHBlNXdhIiwiYmFzZURvY3VtZW50Q0lEIjoiYmFmeXJlaWRyd2V4NWRjYjJ1c3NqNmJ0eGJjMzQyM3U1d2VzNnJyd29tbXhhemt1bHRzcG9oN2EzdGkiLCJjcmVhdGVkQXQiOiIyMDI2LTAzLTA3VDAwOjExOjAwLjAwMFoiLCJub3RlIjoiZGVsZWdhdGVkIGVkaXQgYnkga2V5MyIsImF1dGhvcml6YXRpb24iOiJleUpoYkdjaU9pSkZaRVJUUVNJc0luUjVjQ0k2SW1ScFpEcGtabTl6T21OeVpXUmxiblJwWVd3aUxDSnJhV1FpT2lKa2FXUTZaR1p2Y3pwamJtNXVablE1WmpoaE1uSnVPVE00WkRadWEzb3pPSEk0TkRkMk1tdHlJMnRsZVY5eU9XVjJNelJtZG1NeU0zbzVPVGwyWldGaFpuUTRNMjV1TWpsNmRtaGxJaXdpWTJsa0lqb2lZbUZtZVhKbGFXUmtaVzkyZFRJeVpYTjVhSE5pTlRaa2FHRTJaVFJ4TkhZeU5tbHVObmQ1YjNsMGRYbDJjVFV5TlhjMWFqTnlZMlp0Tm1raWZRLmV5SjJaWEp6YVc5dUlqb3hMQ0owZVhCbElqb2lSRVpQVTBOeVpXUmxiblJwWVd3aUxDSnBjM01pT2lKa2FXUTZaR1p2Y3pwamJtNXVablE1WmpoaE1uSnVPVE00WkRadWEzb3pPSEk0TkRkMk1tdHlJaXdpWVhWa0lqb2laR2xrT21SbWIzTTZPVFJoYURjNU5qTnVNakl6YXpoak9UZzROR2hvTWpkbGEyZzBNbTVsWVNJc0ltRjBkQ0k2VzNzaWNtVnpiM1Z5WTJVaU9pSmphR0ZwYmpvemNqSTBNMmczTnpsbGEzSnVjbUZoWTJVMk16ZzRNbVoyT0dRNE16ZzVJaXdpWVdOMGFXOXVJam9pZDNKcGRHVWlmVjBzSW5CeVppSTZXMTBzSW1WNGNDSTZNVGM1T0RjMk1UWXdNQ3dpYVdGMElqb3hOemN5T0RReE5qQXdmUS5oWko1LXpLTXNKR0tQaEtVdjVCaEt4QnJYLWlaUjNJazNJNTB2b1NEUTVrbWFLOXlvNkI3MTZBY05ibnhlc01tclpXX0FfNzJuZDVYQ29iSTZUbFJBZyJ9.0eNH6RC6O-OkFDBLEWk3YugPUzc9WGtZnG8wRzEEjz0SEwTx5z4FkNoP8Fygu7nd9DZbel9flZL-f0Lg_yD6BA"
|
|
7
7
|
],
|
|
8
8
|
"creatorPublicKey": "z6MkrzLMNwoJSV4P3YccWcbtk8vd9LtgMKnLeaDLUqLuASjb",
|
|
9
9
|
"delegatePublicKey": "z6MkvsvmSh2dGnu2qw1Tnw7M5fz98ycfuYGxqnpfgmPkLv7o",
|
|
@@ -14,10 +14,10 @@
|
|
|
14
14
|
"format": "short-post",
|
|
15
15
|
"title": "Original Post",
|
|
16
16
|
"body": "Content created by the chain owner.",
|
|
17
|
-
"createdByDID": "did:dfos:
|
|
17
|
+
"createdByDID": "did:dfos:cnnnft9f8a2rn938d6nkz38r847v2kr"
|
|
18
18
|
},
|
|
19
19
|
"baseDocumentCID": null,
|
|
20
|
-
"createdByDID": "did:dfos:
|
|
20
|
+
"createdByDID": "did:dfos:cnnnft9f8a2rn938d6nkz38r847v2kr",
|
|
21
21
|
"createdAt": "2026-03-07T00:10:00.000Z"
|
|
22
22
|
},
|
|
23
23
|
{
|
|
@@ -26,19 +26,19 @@
|
|
|
26
26
|
"format": "short-post",
|
|
27
27
|
"title": "Delegated Edit",
|
|
28
28
|
"body": "Content updated by an authorized delegate.",
|
|
29
|
-
"createdByDID": "did:dfos:
|
|
29
|
+
"createdByDID": "did:dfos:94ah7963n223k8c9884hh27ekh42nea"
|
|
30
30
|
},
|
|
31
|
-
"baseDocumentCID": "
|
|
32
|
-
"createdByDID": "did:dfos:
|
|
31
|
+
"baseDocumentCID": "bafyreidrwex5dcb2ussj6btxbc3423u5wes6rrwommxazkultspoh7a3ti",
|
|
32
|
+
"createdByDID": "did:dfos:94ah7963n223k8c9884hh27ekh42nea",
|
|
33
33
|
"createdAt": "2026-03-07T00:11:00.000Z"
|
|
34
34
|
}
|
|
35
35
|
],
|
|
36
|
-
"authorization": "
|
|
36
|
+
"authorization": "eyJhbGciOiJFZERTQSIsInR5cCI6ImRpZDpkZm9zOmNyZWRlbnRpYWwiLCJraWQiOiJkaWQ6ZGZvczpjbm5uZnQ5ZjhhMnJuOTM4ZDZua3ozOHI4NDd2MmtyI2tleV9yOWV2MzRmdmMyM3o5OTl2ZWFhZnQ4M25uMjl6dmhlIiwiY2lkIjoiYmFmeXJlaWRkZW92dTIyZXN5aHNiNTZkaGE2ZTRxNHYyNmluNnd5b3l0dXl2cTUyNXc1ajNyY2ZtNmkifQ.eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiREZPU0NyZWRlbnRpYWwiLCJpc3MiOiJkaWQ6ZGZvczpjbm5uZnQ5ZjhhMnJuOTM4ZDZua3ozOHI4NDd2MmtyIiwiYXVkIjoiZGlkOmRmb3M6OTRhaDc5NjNuMjIzazhjOTg4NGhoMjdla2g0Mm5lYSIsImF0dCI6W3sicmVzb3VyY2UiOiJjaGFpbjozcjI0M2g3Nzlla3JucmFhY2U2Mzg4MmZ2OGQ4Mzg5IiwiYWN0aW9uIjoid3JpdGUifV0sInByZiI6W10sImV4cCI6MTc5ODc2MTYwMCwiaWF0IjoxNzcyODQxNjAwfQ.hZJ5-zKMsJGKPhKUv5BhKxBrX-iZR3Ik3I50voSDQ5kmaK9yo6B716AcNbnxesMmrZW_A_72nd5XCobI6TlRAg",
|
|
37
37
|
"expected": {
|
|
38
|
-
"contentId": "
|
|
39
|
-
"creatorDID": "did:dfos:
|
|
38
|
+
"contentId": "3r243h779ekrnraace63882fv8d8389",
|
|
39
|
+
"creatorDID": "did:dfos:cnnnft9f8a2rn938d6nkz38r847v2kr",
|
|
40
40
|
"isDeleted": false,
|
|
41
|
-
"currentDocumentCID": "
|
|
41
|
+
"currentDocumentCID": "bafyreiejssihkdfljjabdamhkuyibmc743hn3i36a7fnuzsjeoartpe5wa",
|
|
42
42
|
"length": 2
|
|
43
43
|
}
|
|
44
44
|
}
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
"description": "Content chain: create + delete",
|
|
3
3
|
"type": "content",
|
|
4
4
|
"chain": [
|
|
5
|
-
"
|
|
6
|
-
"
|
|
5
|
+
"eyJhbGciOiJFZERTQSIsInR5cCI6ImRpZDpkZm9zOmNvbnRlbnQtb3AiLCJraWQiOiJkaWQ6ZGZvczpjbm5uZnQ5ZjhhMnJuOTM4ZDZua3ozOHI4NDd2MmtyI2tleV9lejlhODc0dGNrcjNkdjkzM2QzY2tkbjd6NnpyY3Q4IiwiY2lkIjoiYmFmeXJlaWFxYXRnZGd3Z2d1Zmd5NHRzejZldXJ3dWR0ZHh5Z3V6dHQ3bnE1d2dkN3FpNDQ1bnY1NnkifQ.eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiY3JlYXRlIiwiZGlkIjoiZGlkOmRmb3M6Y25ubmZ0OWY4YTJybjkzOGQ2bmt6MzhyODQ3djJrciIsImRvY3VtZW50Q0lEIjoiYmFmeXJlaWV2Y3FybXZ0ejJwaXM1dGRpenQ3c2pvdG9xcW9nbDZ2cnJxZ2E2NHcydG53a3Eycm51ZHkiLCJiYXNlRG9jdW1lbnRDSUQiOm51bGwsImNyZWF0ZWRBdCI6IjIwMjYtMDMtMDdUMDA6MDI6MDAuMDAwWiIsIm5vdGUiOm51bGx9.POTcvRbYb5r_P6ZpJRNAufCkEHmfebUyc1jb_USg7xdG8bwq520HMsg6wWjfrhU8Y-7_86IcLwpldD03_L0-Ag",
|
|
6
|
+
"eyJhbGciOiJFZERTQSIsInR5cCI6ImRpZDpkZm9zOmNvbnRlbnQtb3AiLCJraWQiOiJkaWQ6ZGZvczpjbm5uZnQ5ZjhhMnJuOTM4ZDZua3ozOHI4NDd2MmtyI2tleV9lejlhODc0dGNrcjNkdjkzM2QzY2tkbjd6NnpyY3Q4IiwiY2lkIjoiYmFmeXJlaWFsaXlvenNqaW4yaTd4NHl4ejJwcmJnaGIybGU1YzYycGxsbWxhc3YyaGlhZ3l5ZnZjc2kifQ.eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiZGVsZXRlIiwiZGlkIjoiZGlkOmRmb3M6Y25ubmZ0OWY4YTJybjkzOGQ2bmt6MzhyODQ3djJrciIsInByZXZpb3VzT3BlcmF0aW9uQ0lEIjoiYmFmeXJlaWFxYXRnZGd3Z2d1Zmd5NHRzejZldXJ3dWR0ZHh5Z3V6dHQ3bnE1d2dkN3FpNDQ1bnY1NnkiLCJjcmVhdGVkQXQiOiIyMDI2LTAzLTA3VDAwOjAzOjAwLjAwMFoiLCJub3RlIjoicmVtb3ZpbmcgY29udGVudCJ9.k_zTEiRy1aPc1d39SQJOCf8yCVaRoYhenun4RJTxBsmDu6TZ5EvBAvXnbFS0DYLE3X1wV1G6YQG6rpxYElG_Ag"
|
|
7
7
|
],
|
|
8
8
|
"signerPublicKey": "z6MkfUd65JrAhfdgFuMCccU9ThQvjB2fJAMUHkuuajF992gK",
|
|
9
9
|
"documents": [
|
|
@@ -13,15 +13,15 @@
|
|
|
13
13
|
"format": "short-post",
|
|
14
14
|
"title": "Hello World",
|
|
15
15
|
"body": "First post on the protocol.",
|
|
16
|
-
"createdByDID": "did:dfos:
|
|
16
|
+
"createdByDID": "did:dfos:cnnnft9f8a2rn938d6nkz38r847v2kr"
|
|
17
17
|
},
|
|
18
18
|
"baseDocumentCID": null,
|
|
19
|
-
"createdByDID": "did:dfos:
|
|
19
|
+
"createdByDID": "did:dfos:cnnnft9f8a2rn938d6nkz38r847v2kr",
|
|
20
20
|
"createdAt": "2026-03-07T00:02:00.000Z"
|
|
21
21
|
}
|
|
22
22
|
],
|
|
23
23
|
"expected": {
|
|
24
|
-
"contentId": "
|
|
24
|
+
"contentId": "cv7n8vkvr64cctf3294h9k4eanhff8z",
|
|
25
25
|
"isDeleted": true,
|
|
26
26
|
"currentDocumentCID": null,
|
|
27
27
|
"length": 2
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
"description": "Content chain: create + update (with both documents)",
|
|
3
3
|
"type": "content",
|
|
4
4
|
"chain": [
|
|
5
|
-
"
|
|
6
|
-
"
|
|
5
|
+
"eyJhbGciOiJFZERTQSIsInR5cCI6ImRpZDpkZm9zOmNvbnRlbnQtb3AiLCJraWQiOiJkaWQ6ZGZvczpjbm5uZnQ5ZjhhMnJuOTM4ZDZua3ozOHI4NDd2MmtyI2tleV9lejlhODc0dGNrcjNkdjkzM2QzY2tkbjd6NnpyY3Q4IiwiY2lkIjoiYmFmeXJlaWFxYXRnZGd3Z2d1Zmd5NHRzejZldXJ3dWR0ZHh5Z3V6dHQ3bnE1d2dkN3FpNDQ1bnY1NnkifQ.eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiY3JlYXRlIiwiZGlkIjoiZGlkOmRmb3M6Y25ubmZ0OWY4YTJybjkzOGQ2bmt6MzhyODQ3djJrciIsImRvY3VtZW50Q0lEIjoiYmFmeXJlaWV2Y3FybXZ0ejJwaXM1dGRpenQ3c2pvdG9xcW9nbDZ2cnJxZ2E2NHcydG53a3Eycm51ZHkiLCJiYXNlRG9jdW1lbnRDSUQiOm51bGwsImNyZWF0ZWRBdCI6IjIwMjYtMDMtMDdUMDA6MDI6MDAuMDAwWiIsIm5vdGUiOm51bGx9.POTcvRbYb5r_P6ZpJRNAufCkEHmfebUyc1jb_USg7xdG8bwq520HMsg6wWjfrhU8Y-7_86IcLwpldD03_L0-Ag",
|
|
6
|
+
"eyJhbGciOiJFZERTQSIsInR5cCI6ImRpZDpkZm9zOmNvbnRlbnQtb3AiLCJraWQiOiJkaWQ6ZGZvczpjbm5uZnQ5ZjhhMnJuOTM4ZDZua3ozOHI4NDd2MmtyI2tleV9lejlhODc0dGNrcjNkdjkzM2QzY2tkbjd6NnpyY3Q4IiwiY2lkIjoiYmFmeXJlaWJweDRjZ2I0ajZuM216NzY0cHlscmRnNnE3YTQ2bmpuaHg2cDRjcTJybGdldWUzczNldnEifQ.eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoidXBkYXRlIiwiZGlkIjoiZGlkOmRmb3M6Y25ubmZ0OWY4YTJybjkzOGQ2bmt6MzhyODQ3djJrciIsInByZXZpb3VzT3BlcmF0aW9uQ0lEIjoiYmFmeXJlaWFxYXRnZGd3Z2d1Zmd5NHRzejZldXJ3dWR0ZHh5Z3V6dHQ3bnE1d2dkN3FpNDQ1bnY1NnkiLCJkb2N1bWVudENJRCI6ImJhZnlyZWlmZXRwdXRreTRmbnp2N3NyZzdsN3luaWg2ajR5dHplcWlicmNwNXVpZXB2b2x4cWhjYmN5IiwiYmFzZURvY3VtZW50Q0lEIjoiYmFmeXJlaWV2Y3FybXZ0ejJwaXM1dGRpenQ3c2pvdG9xcW9nbDZ2cnJxZ2E2NHcydG53a3Eycm51ZHkiLCJjcmVhdGVkQXQiOiIyMDI2LTAzLTA3VDAwOjAzOjAwLjAwMFoiLCJub3RlIjoiZWRpdGVkIHRpdGxlIGFuZCBib2R5In0.yTkJOiiCsjIBHmR7773W1pdjC5in_Fl3WUXHl8Y_Hyb47RgfiWVufPirIolnuI-IOOl6zHNNmDfmy6kFROwOAg"
|
|
7
7
|
],
|
|
8
8
|
"signerPublicKey": "z6MkfUd65JrAhfdgFuMCccU9ThQvjB2fJAMUHkuuajF992gK",
|
|
9
9
|
"documents": [
|
|
@@ -13,10 +13,10 @@
|
|
|
13
13
|
"format": "short-post",
|
|
14
14
|
"title": "Hello World",
|
|
15
15
|
"body": "First post on the protocol.",
|
|
16
|
-
"createdByDID": "did:dfos:
|
|
16
|
+
"createdByDID": "did:dfos:cnnnft9f8a2rn938d6nkz38r847v2kr"
|
|
17
17
|
},
|
|
18
18
|
"baseDocumentCID": null,
|
|
19
|
-
"createdByDID": "did:dfos:
|
|
19
|
+
"createdByDID": "did:dfos:cnnnft9f8a2rn938d6nkz38r847v2kr",
|
|
20
20
|
"createdAt": "2026-03-07T00:02:00.000Z"
|
|
21
21
|
},
|
|
22
22
|
{
|
|
@@ -25,17 +25,17 @@
|
|
|
25
25
|
"format": "short-post",
|
|
26
26
|
"title": "Hello World (edited)",
|
|
27
27
|
"body": "Updated content.",
|
|
28
|
-
"createdByDID": "did:dfos:
|
|
28
|
+
"createdByDID": "did:dfos:cnnnft9f8a2rn938d6nkz38r847v2kr"
|
|
29
29
|
},
|
|
30
|
-
"baseDocumentCID": "
|
|
31
|
-
"createdByDID": "did:dfos:
|
|
30
|
+
"baseDocumentCID": "bafyreievcqrmvtz2pis5tdizt7sjotoqqogl6vrrqga64w2tnwkq2rnudy",
|
|
31
|
+
"createdByDID": "did:dfos:cnnnft9f8a2rn938d6nkz38r847v2kr",
|
|
32
32
|
"createdAt": "2026-03-07T00:03:00.000Z"
|
|
33
33
|
}
|
|
34
34
|
],
|
|
35
35
|
"expected": {
|
|
36
|
-
"contentId": "
|
|
36
|
+
"contentId": "cv7n8vkvr64cctf3294h9k4eanhff8z",
|
|
37
37
|
"isDeleted": false,
|
|
38
|
-
"currentDocumentCID": "
|
|
38
|
+
"currentDocumentCID": "bafyreifetputky4fnzv7srg7l7ynih6j4ytzeqibrcp5uiepvolxqhcbcy",
|
|
39
39
|
"length": 2
|
|
40
40
|
}
|
|
41
41
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"description": "DFOS credential: read access",
|
|
3
3
|
"type": "credential",
|
|
4
|
-
"credential": "
|
|
4
|
+
"credential": "eyJhbGciOiJFZERTQSIsInR5cCI6ImRpZDpkZm9zOmNyZWRlbnRpYWwiLCJraWQiOiJkaWQ6ZGZvczpjbm5uZnQ5ZjhhMnJuOTM4ZDZua3ozOHI4NDd2MmtyI2tleV9yOWV2MzRmdmMyM3o5OTl2ZWFhZnQ4M25uMjl6dmhlIiwiY2lkIjoiYmFmeXJlaWN0aGNiaXp4dmdlbXN4djdrc2NvbzdhcGllYWFsM2Z5ZTM3bzQ1Zmt5a25lN2I0aG9icmEifQ.eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiREZPU0NyZWRlbnRpYWwiLCJpc3MiOiJkaWQ6ZGZvczpjbm5uZnQ5ZjhhMnJuOTM4ZDZua3ozOHI4NDd2MmtyIiwiYXVkIjoiZGlkOmRmb3M6OTRhaDc5NjNuMjIzazhjOTg4NGhoMjdla2g0Mm5lYSIsImF0dCI6W3sicmVzb3VyY2UiOiJjaGFpbjoqIiwiYWN0aW9uIjoicmVhZCJ9XSwicHJmIjpbXSwiZXhwIjoxNzk4NzYxNjAwLCJpYXQiOjE3NzI4NDE2MDB9.UvTItuWFriA39FZIdB5TuXa_b07eyNLc-iR0cej2litSkjBYAZaLlDJUmyDQ-3dB7TmNVXDbB3SMbpvLnWW9Dw",
|
|
5
5
|
"issuerPublicKey": "z6MkrzLMNwoJSV4P3YccWcbtk8vd9LtgMKnLeaDLUqLuASjb",
|
|
6
6
|
"audiencePublicKey": "z6MkvsvmSh2dGnu2qw1Tnw7M5fz98ycfuYGxqnpfgmPkLv7o",
|
|
7
7
|
"expected": {
|
|
8
|
-
"iss": "did:dfos:
|
|
9
|
-
"aud": "did:dfos:
|
|
8
|
+
"iss": "did:dfos:cnnnft9f8a2rn938d6nkz38r847v2kr",
|
|
9
|
+
"aud": "did:dfos:94ah7963n223k8c9884hh27ekh42nea"
|
|
10
10
|
}
|
|
11
11
|
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"description": "DFOS credential: write access (broad + narrowed)",
|
|
3
3
|
"type": "credential",
|
|
4
|
-
"broadCredential": "
|
|
5
|
-
"narrowCredential": "
|
|
4
|
+
"broadCredential": "eyJhbGciOiJFZERTQSIsInR5cCI6ImRpZDpkZm9zOmNyZWRlbnRpYWwiLCJraWQiOiJkaWQ6ZGZvczpjbm5uZnQ5ZjhhMnJuOTM4ZDZua3ozOHI4NDd2MmtyI2tleV9yOWV2MzRmdmMyM3o5OTl2ZWFhZnQ4M25uMjl6dmhlIiwiY2lkIjoiYmFmeXJlaWZ5aW5ieGhicml0NTZtM2FhdjY2bXc0eGQ2YWRxamFzdmNmaG11NjZnNnRudXFncnljbG0ifQ.eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiREZPU0NyZWRlbnRpYWwiLCJpc3MiOiJkaWQ6ZGZvczpjbm5uZnQ5ZjhhMnJuOTM4ZDZua3ozOHI4NDd2MmtyIiwiYXVkIjoiZGlkOmRmb3M6OTRhaDc5NjNuMjIzazhjOTg4NGhoMjdla2g0Mm5lYSIsImF0dCI6W3sicmVzb3VyY2UiOiJjaGFpbjoqIiwiYWN0aW9uIjoid3JpdGUifV0sInByZiI6W10sImV4cCI6MTc5ODc2MTYwMCwiaWF0IjoxNzcyODQxNjAwfQ.A-EygURAN2bALVwI2AZKFEuy30ZnWJFBaD4jCTf1d7A90rYELStjTWJ1iI7OulihTCfaVtlvj5HtX6Dwv1VxAg",
|
|
5
|
+
"narrowCredential": "eyJhbGciOiJFZERTQSIsInR5cCI6ImRpZDpkZm9zOmNyZWRlbnRpYWwiLCJraWQiOiJkaWQ6ZGZvczpjbm5uZnQ5ZjhhMnJuOTM4ZDZua3ozOHI4NDd2MmtyI2tleV9yOWV2MzRmdmMyM3o5OTl2ZWFhZnQ4M25uMjl6dmhlIiwiY2lkIjoiYmFmeXJlaWNiNGVoZWl6eHNrM3N6Ymgyb2dvbXU0cmV1NGd0a2kycHB4NjR6ZW8zeGFrMnh1bWZ2dWkifQ.eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiREZPU0NyZWRlbnRpYWwiLCJpc3MiOiJkaWQ6ZGZvczpjbm5uZnQ5ZjhhMnJuOTM4ZDZua3ozOHI4NDd2MmtyIiwiYXVkIjoiZGlkOmRmb3M6OTRhaDc5NjNuMjIzazhjOTg4NGhoMjdla2g0Mm5lYSIsImF0dCI6W3sicmVzb3VyY2UiOiJjaGFpbjpjdjduOHZrdnI2NGNjdGYzMjk0aDlrNGVhbmhmZjh6IiwiYWN0aW9uIjoid3JpdGUifV0sInByZiI6W10sImV4cCI6MTc5ODc2MTYwMCwiaWF0IjoxNzcyODQxNjAwfQ.xwsGleofAr78xbT4jCrK402PEI8G_OzvxJITvAjL5ltr7_2bdkX4sCjmZbnjl9m9QcEXnWyWbBgYO8KFl2r8CQ",
|
|
6
6
|
"issuerPublicKey": "z6MkrzLMNwoJSV4P3YccWcbtk8vd9LtgMKnLeaDLUqLuASjb",
|
|
7
7
|
"audiencePublicKey": "z6MkvsvmSh2dGnu2qw1Tnw7M5fz98ycfuYGxqnpfgmPkLv7o",
|
|
8
8
|
"expected": {
|
|
9
|
-
"iss": "did:dfos:
|
|
10
|
-
"aud": "did:dfos:
|
|
11
|
-
"narrowContentId": "
|
|
9
|
+
"iss": "did:dfos:cnnnft9f8a2rn938d6nkz38r847v2kr",
|
|
10
|
+
"aud": "did:dfos:94ah7963n223k8c9884hh27ekh42nea",
|
|
11
|
+
"narrowContentId": "cv7n8vkvr64cctf3294h9k4eanhff8z"
|
|
12
12
|
}
|
|
13
13
|
}
|
|
@@ -2,15 +2,15 @@
|
|
|
2
2
|
"description": "Identity chain: genesis + delete (terminal)",
|
|
3
3
|
"type": "identity",
|
|
4
4
|
"chain": [
|
|
5
|
-
"
|
|
6
|
-
"
|
|
5
|
+
"eyJhbGciOiJFZERTQSIsInR5cCI6ImRpZDpkZm9zOmlkZW50aXR5LW9wIiwia2lkIjoia2V5X3I5ZXYzNGZ2YzIzejk5OXZlYWFmdDgzbm4yOXp2aGUiLCJjaWQiOiJiYWZ5cmVpY29naHZqem52bGl1bG94eG1iZjU0dHB6cXdhaG5xcGlsazduY3hlcGppbmVkcGtnYTNuZSJ9.eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiY3JlYXRlIiwiYXV0aEtleXMiOlt7ImlkIjoia2V5X3I5ZXYzNGZ2YzIzejk5OXZlYWFmdDgzbm4yOXp2aGUiLCJ0eXBlIjoiTXVsdGlrZXkiLCJwdWJsaWNLZXlNdWx0aWJhc2UiOiJ6Nk1rcnpMTU53b0pTVjRQM1ljY1djYnRrOHZkOUx0Z01LbkxlYURMVXFMdUFTamIifV0sImFzc2VydEtleXMiOlt7ImlkIjoia2V5X3I5ZXYzNGZ2YzIzejk5OXZlYWFmdDgzbm4yOXp2aGUiLCJ0eXBlIjoiTXVsdGlrZXkiLCJwdWJsaWNLZXlNdWx0aWJhc2UiOiJ6Nk1rcnpMTU53b0pTVjRQM1ljY1djYnRrOHZkOUx0Z01LbkxlYURMVXFMdUFTamIifV0sImNvbnRyb2xsZXJLZXlzIjpbeyJpZCI6ImtleV9yOWV2MzRmdmMyM3o5OTl2ZWFhZnQ4M25uMjl6dmhlIiwidHlwZSI6Ik11bHRpa2V5IiwicHVibGljS2V5TXVsdGliYXNlIjoiejZNa3J6TE1Od29KU1Y0UDNZY2NXY2J0azh2ZDlMdGdNS25MZWFETFVxTHVBU2piIn1dLCJjcmVhdGVkQXQiOiIyMDI2LTAzLTA3VDAwOjAwOjAwLjAwMFoifQ.TeznHnzrtKOGTr0FzkDL2z-luMWnAbKXrmDbi-Exgw_xMPCnYwGHORMjw-BM28f0RoTirIAeD7d20W5RSuGuBg",
|
|
6
|
+
"eyJhbGciOiJFZERTQSIsInR5cCI6ImRpZDpkZm9zOmlkZW50aXR5LW9wIiwia2lkIjoiZGlkOmRmb3M6Y25ubmZ0OWY4YTJybjkzOGQ2bmt6MzhyODQ3djJrciNrZXlfcjlldjM0ZnZjMjN6OTk5dmVhYWZ0ODNubjI5enZoZSIsImNpZCI6ImJhZnlyZWlnaWJ5anN2bGt0ZTQ2Zzd6NHIydXd5eHA2eDU1b3RlbzRmcjVuZGE3emFvbHFvbDIyM3hhIn0.eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiZGVsZXRlIiwicHJldmlvdXNPcGVyYXRpb25DSUQiOiJiYWZ5cmVpY29naHZqem52bGl1bG94eG1iZjU0dHB6cXdhaG5xcGlsazduY3hlcGppbmVkcGtnYTNuZSIsImNyZWF0ZWRBdCI6IjIwMjYtMDMtMDdUMDA6MDE6MDAuMDAwWiJ9.7SNEk43hmCoN4vpUELfHNMsHO_H1QBPurEFPH3n2xf3cVR3EvJ1A7-xwf8_f3AmawFNI712jMQTpj9r4jQvQCg"
|
|
7
7
|
],
|
|
8
8
|
"expected": {
|
|
9
|
-
"did": "did:dfos:
|
|
9
|
+
"did": "did:dfos:cnnnft9f8a2rn938d6nkz38r847v2kr",
|
|
10
10
|
"isDeleted": true,
|
|
11
11
|
"controllerKeys": [
|
|
12
12
|
{
|
|
13
|
-
"id": "
|
|
13
|
+
"id": "key_r9ev34fvc23z999veaaft83nn29zvhe",
|
|
14
14
|
"type": "Multikey",
|
|
15
15
|
"publicKeyMultibase": "z6MkrzLMNwoJSV4P3YccWcbtk8vd9LtgMKnLeaDLUqLuASjb"
|
|
16
16
|
}
|
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
"description": "Identity chain: genesis (single create operation)",
|
|
3
3
|
"type": "identity",
|
|
4
4
|
"chain": [
|
|
5
|
-
"
|
|
5
|
+
"eyJhbGciOiJFZERTQSIsInR5cCI6ImRpZDpkZm9zOmlkZW50aXR5LW9wIiwia2lkIjoia2V5X3I5ZXYzNGZ2YzIzejk5OXZlYWFmdDgzbm4yOXp2aGUiLCJjaWQiOiJiYWZ5cmVpY29naHZqem52bGl1bG94eG1iZjU0dHB6cXdhaG5xcGlsazduY3hlcGppbmVkcGtnYTNuZSJ9.eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiY3JlYXRlIiwiYXV0aEtleXMiOlt7ImlkIjoia2V5X3I5ZXYzNGZ2YzIzejk5OXZlYWFmdDgzbm4yOXp2aGUiLCJ0eXBlIjoiTXVsdGlrZXkiLCJwdWJsaWNLZXlNdWx0aWJhc2UiOiJ6Nk1rcnpMTU53b0pTVjRQM1ljY1djYnRrOHZkOUx0Z01LbkxlYURMVXFMdUFTamIifV0sImFzc2VydEtleXMiOlt7ImlkIjoia2V5X3I5ZXYzNGZ2YzIzejk5OXZlYWFmdDgzbm4yOXp2aGUiLCJ0eXBlIjoiTXVsdGlrZXkiLCJwdWJsaWNLZXlNdWx0aWJhc2UiOiJ6Nk1rcnpMTU53b0pTVjRQM1ljY1djYnRrOHZkOUx0Z01LbkxlYURMVXFMdUFTamIifV0sImNvbnRyb2xsZXJLZXlzIjpbeyJpZCI6ImtleV9yOWV2MzRmdmMyM3o5OTl2ZWFhZnQ4M25uMjl6dmhlIiwidHlwZSI6Ik11bHRpa2V5IiwicHVibGljS2V5TXVsdGliYXNlIjoiejZNa3J6TE1Od29KU1Y0UDNZY2NXY2J0azh2ZDlMdGdNS25MZWFETFVxTHVBU2piIn1dLCJjcmVhdGVkQXQiOiIyMDI2LTAzLTA3VDAwOjAwOjAwLjAwMFoifQ.TeznHnzrtKOGTr0FzkDL2z-luMWnAbKXrmDbi-Exgw_xMPCnYwGHORMjw-BM28f0RoTirIAeD7d20W5RSuGuBg"
|
|
6
6
|
],
|
|
7
7
|
"expected": {
|
|
8
|
-
"did": "did:dfos:
|
|
8
|
+
"did": "did:dfos:cnnnft9f8a2rn938d6nkz38r847v2kr",
|
|
9
9
|
"isDeleted": false,
|
|
10
10
|
"controllerKeys": [
|
|
11
11
|
{
|
|
12
|
-
"id": "
|
|
12
|
+
"id": "key_r9ev34fvc23z999veaaft83nn29zvhe",
|
|
13
13
|
"type": "Multikey",
|
|
14
14
|
"publicKeyMultibase": "z6MkrzLMNwoJSV4P3YccWcbtk8vd9LtgMKnLeaDLUqLuASjb"
|
|
15
15
|
}
|
|
@@ -2,15 +2,15 @@
|
|
|
2
2
|
"description": "Identity chain: genesis + key rotation",
|
|
3
3
|
"type": "identity",
|
|
4
4
|
"chain": [
|
|
5
|
-
"
|
|
6
|
-
"
|
|
5
|
+
"eyJhbGciOiJFZERTQSIsInR5cCI6ImRpZDpkZm9zOmlkZW50aXR5LW9wIiwia2lkIjoia2V5X3I5ZXYzNGZ2YzIzejk5OXZlYWFmdDgzbm4yOXp2aGUiLCJjaWQiOiJiYWZ5cmVpY29naHZqem52bGl1bG94eG1iZjU0dHB6cXdhaG5xcGlsazduY3hlcGppbmVkcGtnYTNuZSJ9.eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoiY3JlYXRlIiwiYXV0aEtleXMiOlt7ImlkIjoia2V5X3I5ZXYzNGZ2YzIzejk5OXZlYWFmdDgzbm4yOXp2aGUiLCJ0eXBlIjoiTXVsdGlrZXkiLCJwdWJsaWNLZXlNdWx0aWJhc2UiOiJ6Nk1rcnpMTU53b0pTVjRQM1ljY1djYnRrOHZkOUx0Z01LbkxlYURMVXFMdUFTamIifV0sImFzc2VydEtleXMiOlt7ImlkIjoia2V5X3I5ZXYzNGZ2YzIzejk5OXZlYWFmdDgzbm4yOXp2aGUiLCJ0eXBlIjoiTXVsdGlrZXkiLCJwdWJsaWNLZXlNdWx0aWJhc2UiOiJ6Nk1rcnpMTU53b0pTVjRQM1ljY1djYnRrOHZkOUx0Z01LbkxlYURMVXFMdUFTamIifV0sImNvbnRyb2xsZXJLZXlzIjpbeyJpZCI6ImtleV9yOWV2MzRmdmMyM3o5OTl2ZWFhZnQ4M25uMjl6dmhlIiwidHlwZSI6Ik11bHRpa2V5IiwicHVibGljS2V5TXVsdGliYXNlIjoiejZNa3J6TE1Od29KU1Y0UDNZY2NXY2J0azh2ZDlMdGdNS25MZWFETFVxTHVBU2piIn1dLCJjcmVhdGVkQXQiOiIyMDI2LTAzLTA3VDAwOjAwOjAwLjAwMFoifQ.TeznHnzrtKOGTr0FzkDL2z-luMWnAbKXrmDbi-Exgw_xMPCnYwGHORMjw-BM28f0RoTirIAeD7d20W5RSuGuBg",
|
|
6
|
+
"eyJhbGciOiJFZERTQSIsInR5cCI6ImRpZDpkZm9zOmlkZW50aXR5LW9wIiwia2lkIjoiZGlkOmRmb3M6Y25ubmZ0OWY4YTJybjkzOGQ2bmt6MzhyODQ3djJrciNrZXlfcjlldjM0ZnZjMjN6OTk5dmVhYWZ0ODNubjI5enZoZSIsImNpZCI6ImJhZnlyZWliZnVoNjN1djMzaTJpNWVvb2UzYm9pdDJydXlqZWh1YnNyeWVtdXV6Nm1ydGxlajI2cmVpIn0.eyJ2ZXJzaW9uIjoxLCJ0eXBlIjoidXBkYXRlIiwicHJldmlvdXNPcGVyYXRpb25DSUQiOiJiYWZ5cmVpY29naHZqem52bGl1bG94eG1iZjU0dHB6cXdhaG5xcGlsazduY3hlcGppbmVkcGtnYTNuZSIsImF1dGhLZXlzIjpbeyJpZCI6ImtleV9lejlhODc0dGNrcjNkdjkzM2QzY2tkbjd6NnpyY3Q4IiwidHlwZSI6Ik11bHRpa2V5IiwicHVibGljS2V5TXVsdGliYXNlIjoiejZNa2ZVZDY1SnJBaGZkZ0Z1TUNjY1U5VGhRdmpCMmZKQU1VSGt1dWFqRjk5MmdLIn1dLCJhc3NlcnRLZXlzIjpbeyJpZCI6ImtleV9lejlhODc0dGNrcjNkdjkzM2QzY2tkbjd6NnpyY3Q4IiwidHlwZSI6Ik11bHRpa2V5IiwicHVibGljS2V5TXVsdGliYXNlIjoiejZNa2ZVZDY1SnJBaGZkZ0Z1TUNjY1U5VGhRdmpCMmZKQU1VSGt1dWFqRjk5MmdLIn1dLCJjb250cm9sbGVyS2V5cyI6W3siaWQiOiJrZXlfZXo5YTg3NHRja3IzZHY5MzNkM2NrZG43ejZ6cmN0OCIsInR5cGUiOiJNdWx0aWtleSIsInB1YmxpY0tleU11bHRpYmFzZSI6Ino2TWtmVWQ2NUpyQWhmZGdGdU1DY2NVOVRoUXZqQjJmSkFNVUhrdXVhakY5OTJnSyJ9XSwiY3JlYXRlZEF0IjoiMjAyNi0wMy0wN1QwMDowMTowMC4wMDBaIn0.7fqvWGEVYW9atA1uqpp7lIUOWp4dATLpLjOmFWzJN-8gTL-QnXDCeyGcBu5AXhHzO52fauwUavh1KrB6wBYuCw"
|
|
7
7
|
],
|
|
8
8
|
"expected": {
|
|
9
|
-
"did": "did:dfos:
|
|
9
|
+
"did": "did:dfos:cnnnft9f8a2rn938d6nkz38r847v2kr",
|
|
10
10
|
"isDeleted": false,
|
|
11
11
|
"controllerKeys": [
|
|
12
12
|
{
|
|
13
|
-
"id": "
|
|
13
|
+
"id": "key_ez9a874tckr3dv933d3ckdn7z6zrct8",
|
|
14
14
|
"type": "Multikey",
|
|
15
15
|
"publicKeyMultibase": "z6MkfUd65JrAhfdgFuMCccU9ThQvjB2fJAMUHkuuajF992gK"
|
|
16
16
|
}
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@metalabel/dfos-protocol",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"description": "DFOS Protocol — Ed25519 signed chain primitives, beacons,
|
|
5
|
+
"description": "DFOS Protocol — Ed25519 signed chain primitives, beacons, credentials, and verification",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"author": "Metalabel <hello@metalabel.com> (https://metalabel.com)",
|
|
8
8
|
"repository": {
|
|
@@ -37,10 +37,6 @@
|
|
|
37
37
|
"import": "./dist/chain/index.js",
|
|
38
38
|
"types": "./dist/chain/index.d.ts"
|
|
39
39
|
},
|
|
40
|
-
"./merkle": {
|
|
41
|
-
"import": "./dist/merkle/index.js",
|
|
42
|
-
"types": "./dist/merkle/index.d.ts"
|
|
43
|
-
},
|
|
44
40
|
"./credentials": {
|
|
45
41
|
"import": "./dist/credentials/index.js",
|
|
46
42
|
"types": "./dist/credentials/index.d.ts"
|
|
@@ -54,19 +50,19 @@
|
|
|
54
50
|
"README.md"
|
|
55
51
|
],
|
|
56
52
|
"dependencies": {
|
|
57
|
-
"@ipld/dag-cbor": "^
|
|
58
|
-
"@noble/curves": "^2.0
|
|
59
|
-
"@noble/hashes": "^2.0
|
|
60
|
-
"multiformats": "^
|
|
61
|
-
"zod": "^4.3
|
|
53
|
+
"@ipld/dag-cbor": "^10.0.1",
|
|
54
|
+
"@noble/curves": "^2.2.0",
|
|
55
|
+
"@noble/hashes": "^2.2.0",
|
|
56
|
+
"multiformats": "^14.0.0",
|
|
57
|
+
"zod": "^4.4.3"
|
|
62
58
|
},
|
|
63
59
|
"devDependencies": {
|
|
64
60
|
"@types/node": "^24.10.4",
|
|
65
|
-
"ajv": "^8.
|
|
61
|
+
"ajv": "^8.20.0",
|
|
66
62
|
"ajv-formats": "^3.0.1",
|
|
67
63
|
"tsup": "^8.5.1",
|
|
68
|
-
"tsx": "^4.
|
|
69
|
-
"vitest": "^4.1.
|
|
64
|
+
"tsx": "^4.22.4",
|
|
65
|
+
"vitest": "^4.1.8"
|
|
70
66
|
},
|
|
71
67
|
"scripts": {
|
|
72
68
|
"build": "tsup",
|
package/schemas/manifest.v1.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
3
|
"$id": "https://schemas.dfos.com/manifest/v1",
|
|
4
4
|
"title": "Manifest",
|
|
5
|
-
"description": "A manifest — a named map of protocol object references for semantic navigation. Keys are path-like labels. Values are protocol references: content chain identifiers (
|
|
5
|
+
"description": "A manifest — a named map of protocol object references for semantic navigation. Keys are path-like labels. Values are protocol references: content chain identifiers (31-char bare hash), DIDs (did:dfos:...), or CIDs (bafyrei...). The document layer of the dark forest. Discovery is social or out-of-band.",
|
|
6
6
|
"type": "object",
|
|
7
7
|
"required": ["$schema", "entries"],
|
|
8
8
|
"properties": {
|
package/dist/chunk-E5CFQG2B.js
DELETED
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
// src/merkle/tree.ts
|
|
2
|
-
var sha256 = async (data) => {
|
|
3
|
-
const buf = await crypto.subtle.digest("SHA-256", data);
|
|
4
|
-
return new Uint8Array(buf);
|
|
5
|
-
};
|
|
6
|
-
var toHex = (bytes) => {
|
|
7
|
-
return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
8
|
-
};
|
|
9
|
-
var hexToBytes = (hex) => {
|
|
10
|
-
const bytes = new Uint8Array(hex.length / 2);
|
|
11
|
-
for (let i = 0; i < hex.length; i += 2) {
|
|
12
|
-
bytes[i / 2] = parseInt(hex.substring(i, i + 2), 16);
|
|
13
|
-
}
|
|
14
|
-
return bytes;
|
|
15
|
-
};
|
|
16
|
-
var concat = (a, b) => {
|
|
17
|
-
const result = new Uint8Array(a.length + b.length);
|
|
18
|
-
result.set(a, 0);
|
|
19
|
-
result.set(b, a.length);
|
|
20
|
-
return result;
|
|
21
|
-
};
|
|
22
|
-
var hashLeaf = async (contentId) => {
|
|
23
|
-
return sha256(new TextEncoder().encode(contentId));
|
|
24
|
-
};
|
|
25
|
-
var hashInterior = async (left, right) => {
|
|
26
|
-
return sha256(concat(left, right));
|
|
27
|
-
};
|
|
28
|
-
var buildMerkleTree = async (contentIds) => {
|
|
29
|
-
const sorted = [...new Set(contentIds)].sort();
|
|
30
|
-
if (sorted.length === 0) return { root: null, leafCount: 0 };
|
|
31
|
-
let level = await Promise.all(sorted.map(hashLeaf));
|
|
32
|
-
while (level.length > 1) {
|
|
33
|
-
const nextLevel = [];
|
|
34
|
-
for (let i = 0; i < level.length; i += 2) {
|
|
35
|
-
if (i + 1 < level.length) {
|
|
36
|
-
nextLevel.push(await hashInterior(level[i], level[i + 1]));
|
|
37
|
-
} else {
|
|
38
|
-
nextLevel.push(level[i]);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
level = nextLevel;
|
|
42
|
-
}
|
|
43
|
-
return { root: toHex(level[0]), leafCount: sorted.length };
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
// src/merkle/proof.ts
|
|
47
|
-
var generateMerkleProof = async (contentIds, targetId) => {
|
|
48
|
-
const sorted = [...new Set(contentIds)].sort();
|
|
49
|
-
const targetIdx = sorted.indexOf(targetId);
|
|
50
|
-
if (targetIdx < 0) return null;
|
|
51
|
-
const { root } = await buildMerkleTree(sorted);
|
|
52
|
-
if (!root) return null;
|
|
53
|
-
const leaves = await Promise.all(sorted.map(hashLeaf));
|
|
54
|
-
const path = [];
|
|
55
|
-
let level = leaves;
|
|
56
|
-
let idx = targetIdx;
|
|
57
|
-
while (level.length > 1) {
|
|
58
|
-
const nextLevel = [];
|
|
59
|
-
const nextIdx = Math.floor(idx / 2);
|
|
60
|
-
for (let i = 0; i < level.length; i += 2) {
|
|
61
|
-
if (i + 1 < level.length) {
|
|
62
|
-
if (i === idx || i + 1 === idx) {
|
|
63
|
-
const siblingIdx = i === idx ? i + 1 : i;
|
|
64
|
-
path.push({
|
|
65
|
-
hash: toHex(level[siblingIdx]),
|
|
66
|
-
position: siblingIdx < idx ? "left" : "right"
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
const interior = await sha256(concat(level[i], level[i + 1]));
|
|
70
|
-
nextLevel.push(interior);
|
|
71
|
-
} else {
|
|
72
|
-
nextLevel.push(level[i]);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
level = nextLevel;
|
|
76
|
-
idx = nextIdx;
|
|
77
|
-
}
|
|
78
|
-
return { contentId: targetId, root, path };
|
|
79
|
-
};
|
|
80
|
-
var verifyMerkleProof = async (proof) => {
|
|
81
|
-
let current = await hashLeaf(proof.contentId);
|
|
82
|
-
for (const step of proof.path) {
|
|
83
|
-
const sibling = hexToBytes(step.hash);
|
|
84
|
-
if (step.position === "left") {
|
|
85
|
-
current = await sha256(concat(sibling, current));
|
|
86
|
-
} else {
|
|
87
|
-
current = await sha256(concat(current, sibling));
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
return toHex(current) === proof.root;
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
export {
|
|
94
|
-
hexToBytes,
|
|
95
|
-
hashLeaf,
|
|
96
|
-
buildMerkleTree,
|
|
97
|
-
generateMerkleProof,
|
|
98
|
-
verifyMerkleProof
|
|
99
|
-
};
|
package/dist/merkle/index.d.ts
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
declare const hexToBytes: (hex: string) => Uint8Array;
|
|
2
|
-
/**
|
|
3
|
-
* Hash a leaf node — SHA-256 of UTF-8 encoded contentId
|
|
4
|
-
*/
|
|
5
|
-
declare const hashLeaf: (contentId: string) => Promise<Uint8Array>;
|
|
6
|
-
/**
|
|
7
|
-
* Build a sorted binary Merkle tree over content identifiers
|
|
8
|
-
*
|
|
9
|
-
* ContentIds are sorted lexicographically, hashed to leaves, then paired
|
|
10
|
-
* and hashed up to the root. Odd nodes are promoted to the next level.
|
|
11
|
-
*
|
|
12
|
-
* Returns null root for empty input. Deduplicates contentIds.
|
|
13
|
-
*/
|
|
14
|
-
declare const buildMerkleTree: (contentIds: string[]) => Promise<{
|
|
15
|
-
root: string | null;
|
|
16
|
-
leafCount: number;
|
|
17
|
-
}>;
|
|
18
|
-
|
|
19
|
-
interface MerkleProof {
|
|
20
|
-
/** The contentId being proven */
|
|
21
|
-
contentId: string;
|
|
22
|
-
/** Hex SHA-256 root of the tree */
|
|
23
|
-
root: string;
|
|
24
|
-
/** Sibling hashes along the path from leaf to root */
|
|
25
|
-
path: Array<{
|
|
26
|
-
/** Hex SHA-256 of sibling node */
|
|
27
|
-
hash: string;
|
|
28
|
-
/** Position of the sibling relative to the current node */
|
|
29
|
-
position: 'left' | 'right';
|
|
30
|
-
}>;
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* Generate an inclusion proof for a contentId in the set
|
|
34
|
-
*
|
|
35
|
-
* Returns null if the contentId is not in the set.
|
|
36
|
-
*/
|
|
37
|
-
declare const generateMerkleProof: (contentIds: string[], targetId: string) => Promise<MerkleProof | null>;
|
|
38
|
-
/**
|
|
39
|
-
* Verify a Merkle inclusion proof
|
|
40
|
-
*
|
|
41
|
-
* Recomputes the root from the leaf and proof path, compares to the claimed root.
|
|
42
|
-
*/
|
|
43
|
-
declare const verifyMerkleProof: (proof: MerkleProof) => Promise<boolean>;
|
|
44
|
-
|
|
45
|
-
export { type MerkleProof, buildMerkleTree, generateMerkleProof, hashLeaf, hexToBytes, verifyMerkleProof };
|
package/dist/merkle/index.js
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"description": "Merkle tree: 5 content IDs → sorted → leaf hashes → root, with inclusion proof for \"charlie\"",
|
|
3
|
-
"type": "merkle",
|
|
4
|
-
"contentIds": ["alpha", "bravo", "charlie", "delta", "echo"],
|
|
5
|
-
"expected": {
|
|
6
|
-
"sortedIds": ["alpha", "bravo", "charlie", "delta", "echo"],
|
|
7
|
-
"root": "7e80d4780f454e0fca0b090d8c646f572b49354f54154531606105aad2fda28e",
|
|
8
|
-
"leafCount": 5,
|
|
9
|
-
"charlieProof": {
|
|
10
|
-
"contentId": "charlie",
|
|
11
|
-
"root": "7e80d4780f454e0fca0b090d8c646f572b49354f54154531606105aad2fda28e",
|
|
12
|
-
"path": [
|
|
13
|
-
{
|
|
14
|
-
"hash": "4f4a9410ffcdf895c4adb880659e9b5c0dd1f23a30790684340b3eaacb045398",
|
|
15
|
-
"position": "right"
|
|
16
|
-
},
|
|
17
|
-
{
|
|
18
|
-
"hash": "90d39555bb3c223e12f5a375c3011d2462fe2e1e36b8416a0b623d5831a9b4f3",
|
|
19
|
-
"position": "left"
|
|
20
|
-
},
|
|
21
|
-
{
|
|
22
|
-
"hash": "092c79e8f80e559e404bcf660c48f3522b67aba9ff1484b0367e1a4ddef7431d",
|
|
23
|
-
"position": "right"
|
|
24
|
-
}
|
|
25
|
-
]
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
}
|