@interop/did-method-webvh 3.0.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.
@@ -0,0 +1,80 @@
1
+ import { canonicalizeEx } from 'json-canonicalize';
2
+ const sanitizeForCanonicalization = (value, seen) => {
3
+ if (value === null)
4
+ return null;
5
+ const type = typeof value;
6
+ if (type === 'undefined') {
7
+ throw new Error('Canonicalization input contains undefined in array position');
8
+ }
9
+ if (type === 'function' || type === 'symbol' || type === 'bigint') {
10
+ throw new Error(`Canonicalization input contains unsupported type: ${type}`);
11
+ }
12
+ if (type === 'number' && !Number.isFinite(value)) {
13
+ throw new Error('Canonicalization input contains non-finite number');
14
+ }
15
+ if (type !== 'object')
16
+ return value;
17
+ const obj = value;
18
+ if (seen.has(obj)) {
19
+ throw new Error('Canonicalization input contains circular references');
20
+ }
21
+ if (Array.isArray(obj)) {
22
+ const sanitizedArray = [];
23
+ seen.set(obj, sanitizedArray);
24
+ for (const item of obj) {
25
+ sanitizedArray.push(sanitizeForCanonicalization(item, seen));
26
+ }
27
+ return sanitizedArray;
28
+ }
29
+ const sanitizedObject = {};
30
+ seen.set(obj, sanitizedObject);
31
+ for (const [key, entry] of Object.entries(obj)) {
32
+ if (typeof entry === 'undefined') {
33
+ continue;
34
+ }
35
+ sanitizedObject[key] = sanitizeForCanonicalization(entry, seen);
36
+ }
37
+ return sanitizedObject;
38
+ };
39
+ const assertJsonCompatible = (value, seen) => {
40
+ if (value === null)
41
+ return;
42
+ const type = typeof value;
43
+ if (type === 'undefined') {
44
+ throw new Error('Canonicalization input contains undefined');
45
+ }
46
+ if (type === 'function' || type === 'symbol' || type === 'bigint') {
47
+ throw new Error(`Canonicalization input contains unsupported type: ${type}`);
48
+ }
49
+ if (type === 'number' && !Number.isFinite(value)) {
50
+ throw new Error('Canonicalization input contains non-finite number');
51
+ }
52
+ if (type !== 'object')
53
+ return;
54
+ const obj = value;
55
+ if (seen.has(obj)) {
56
+ throw new Error('Canonicalization input contains circular references');
57
+ }
58
+ seen.add(obj);
59
+ if (Array.isArray(obj)) {
60
+ for (const item of obj) {
61
+ assertJsonCompatible(item, seen);
62
+ }
63
+ return;
64
+ }
65
+ for (const entry of Object.values(obj)) {
66
+ assertJsonCompatible(entry, seen);
67
+ }
68
+ };
69
+ export function validateStrictJsonValue(value) {
70
+ assertJsonCompatible(value, new WeakSet());
71
+ }
72
+ export const canonicalizeStrict = (value) => {
73
+ const sanitized = sanitizeForCanonicalization(value, new WeakMap());
74
+ validateStrictJsonValue(sanitized);
75
+ return canonicalizeEx(sanitized, {
76
+ allowCircular: false,
77
+ filterUndefined: true,
78
+ undefinedInArrayToNull: false,
79
+ });
80
+ };
@@ -0,0 +1,2 @@
1
+ export declare function createHash(data: string): Promise<Uint8Array>;
2
+ export declare function createHashHex(data: string): Promise<string>;
@@ -0,0 +1,17 @@
1
+ /// <reference lib="dom" />
2
+ import { sha256 } from '@noble/hashes/sha2.js';
3
+ const encoder = new TextEncoder();
4
+ function arrayBufferToHex(buffer) {
5
+ const view = buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer);
6
+ return Array.from(view)
7
+ .map((b) => b.toString(16).padStart(2, '0'))
8
+ .join('');
9
+ }
10
+ export async function createHash(data) {
11
+ return sha256(encoder.encode(data));
12
+ }
13
+ export async function createHashHex(data) {
14
+ const hash = await createHash(data);
15
+ const view = new Uint8Array(hash.buffer);
16
+ return arrayBufferToHex(view);
17
+ }
@@ -0,0 +1,100 @@
1
+ /**
2
+ * multiformats.ts
3
+ *
4
+ * This file provides utilities for working with Multibase and Multihash formats
5
+ * as specified in the DID:WebVH method specification.
6
+ */
7
+ /**
8
+ * Supported Multibase encoding types
9
+ */
10
+ export declare enum MultibaseEncoding {
11
+ BASE64URL_NO_PAD = "u",
12
+ BASE58_BTC = "z"
13
+ }
14
+ /**
15
+ * Encodes binary data using Base64URL (no padding)
16
+ * @param bytes - The binary data to encode
17
+ * @returns The base64url encoded string (without the multibase prefix)
18
+ */
19
+ export declare function encodeBase64Url(bytes: Uint8Array): string;
20
+ /**
21
+ * Encodes binary data using Base58BTC
22
+ * @param bytes - The binary data to encode
23
+ * @returns The base58btc encoded string (without the multibase prefix)
24
+ */
25
+ export declare function encodeBase58Btc(bytes: Uint8Array): string;
26
+ /**
27
+ * Decodes a Base58BTC string to binary data
28
+ * @param str - The base58btc encoded string
29
+ * @returns The decoded binary data
30
+ */
31
+ export declare function decodeBase58Btc(str: string): Uint8Array;
32
+ /**
33
+ * Encodes binary data using the specified multibase encoding
34
+ * @param bytes - The binary data to encode
35
+ * @param encoding - The multibase encoding to use
36
+ * @returns The multibase encoded string (including the prefix)
37
+ */
38
+ export declare function multibaseEncode(bytes: Uint8Array, encoding?: MultibaseEncoding): string;
39
+ /**
40
+ * Decodes a multibase encoded string to binary data
41
+ * @param str - The multibase encoded string
42
+ * @returns The decoded binary data and the encoding used
43
+ */
44
+ export declare function multibaseDecode(str: string): {
45
+ bytes: Uint8Array;
46
+ encoding: MultibaseEncoding;
47
+ };
48
+ /**
49
+ * Supported Multihash algorithm identifiers
50
+ */
51
+ export declare enum MultihashAlgorithm {
52
+ SHA2_256 = 18,
53
+ SHA2_384 = 32,
54
+ SHA3_256 = 22,
55
+ SHA3_384 = 21
56
+ }
57
+ /**
58
+ * Expected digest lengths for each algorithm (in bytes)
59
+ */
60
+ export declare const DIGEST_LENGTHS: {
61
+ 18: number;
62
+ 32: number;
63
+ 22: number;
64
+ 21: number;
65
+ };
66
+ /**
67
+ * Creates a multihash from a digest and algorithm
68
+ * @param digest - The digest bytes
69
+ * @param algorithm - The hash algorithm used
70
+ * @returns The multihash as a Uint8Array
71
+ */
72
+ export declare function createMultihash(digest: Uint8Array, algorithm: MultihashAlgorithm): Uint8Array;
73
+ /**
74
+ * Decodes a multihash
75
+ * @param bytes - The multihash bytes
76
+ * @returns The decoded multihash components
77
+ */
78
+ export declare function decodeMultihash(bytes: Uint8Array): {
79
+ algorithm: MultihashAlgorithm;
80
+ digestLength: number;
81
+ digest: Uint8Array;
82
+ };
83
+ /**
84
+ * Encodes a multihash using multibase encoding
85
+ * @param multihash - The multihash bytes
86
+ * @param encoding - The multibase encoding to use
87
+ * @returns The multibase encoded multihash
88
+ */
89
+ export declare function encodeMultihashWithMultibase(multihash: Uint8Array, encoding?: MultibaseEncoding): string;
90
+ /**
91
+ * Decodes a multibase encoded multihash
92
+ * @param str - The multibase encoded multihash
93
+ * @returns The decoded multihash components and the encoding used
94
+ */
95
+ export declare function decodeMultihashFromMultibase(str: string): {
96
+ algorithm: MultihashAlgorithm;
97
+ digestLength: number;
98
+ digest: Uint8Array;
99
+ encoding: MultibaseEncoding;
100
+ };
@@ -0,0 +1,283 @@
1
+ /**
2
+ * multiformats.ts
3
+ *
4
+ * This file provides utilities for working with Multibase and Multihash formats
5
+ * as specified in the DID:WebVH method specification.
6
+ */
7
+ // ===== MULTIBASE IMPLEMENTATION =====
8
+ /**
9
+ * Supported Multibase encoding types
10
+ */
11
+ export var MultibaseEncoding;
12
+ (function (MultibaseEncoding) {
13
+ MultibaseEncoding["BASE64URL_NO_PAD"] = "u";
14
+ MultibaseEncoding["BASE58_BTC"] = "z";
15
+ })(MultibaseEncoding || (MultibaseEncoding = {}));
16
+ /**
17
+ * Base encoding alphabets
18
+ */
19
+ const BASE_ALPHABETS = {
20
+ [MultibaseEncoding.BASE64URL_NO_PAD]: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_',
21
+ [MultibaseEncoding.BASE58_BTC]: '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz',
22
+ };
23
+ /**
24
+ * Encodes binary data using Base64URL (no padding)
25
+ * @param bytes - The binary data to encode
26
+ * @returns The base64url encoded string (without the multibase prefix)
27
+ */
28
+ export function encodeBase64Url(bytes) {
29
+ // Convert to base64
30
+ const base64 = Buffer.from(bytes).toString('base64');
31
+ // Convert to base64url by replacing + with - and / with _
32
+ return base64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
33
+ }
34
+ /**
35
+ * Decodes a Base64URL (no padding) string to binary data
36
+ * @param str - The base64url encoded string
37
+ * @returns The decoded binary data
38
+ */
39
+ function decodeBase64Url(str) {
40
+ // Add padding if necessary
41
+ const padding = str.length % 4 === 0 ? 0 : 4 - (str.length % 4);
42
+ const base64 = str.replace(/-/g, '+').replace(/_/g, '/') + '='.repeat(padding);
43
+ // Decode base64 to binary
44
+ const binary = atob(base64);
45
+ const bytes = new Uint8Array(binary.length);
46
+ for (let i = 0; i < binary.length; i++) {
47
+ bytes[i] = binary.charCodeAt(i);
48
+ }
49
+ return bytes;
50
+ }
51
+ /**
52
+ * Encodes binary data using Base58BTC
53
+ * @param bytes - The binary data to encode
54
+ * @returns The base58btc encoded string (without the multibase prefix)
55
+ */
56
+ export function encodeBase58Btc(bytes) {
57
+ const ALPHABET = BASE_ALPHABETS[MultibaseEncoding.BASE58_BTC];
58
+ // Count leading zeros
59
+ let zeros = 0;
60
+ for (let i = 0; i < bytes.length && bytes[i] === 0; i++) {
61
+ zeros++;
62
+ }
63
+ // Convert to a big integer
64
+ let num = 0n;
65
+ for (let i = 0; i < bytes.length; i++) {
66
+ num = num * 256n + BigInt(bytes[i]);
67
+ }
68
+ // Convert to base58
69
+ let result = '';
70
+ while (num > 0n) {
71
+ const remainder = Number(num % 58n);
72
+ num = num / 58n;
73
+ result = ALPHABET[remainder] + result;
74
+ }
75
+ // Add leading '1's for each leading zero byte
76
+ return '1'.repeat(zeros) + result;
77
+ }
78
+ /**
79
+ * Decodes a Base58BTC string to binary data
80
+ * @param str - The base58btc encoded string
81
+ * @returns The decoded binary data
82
+ */
83
+ export function decodeBase58Btc(str) {
84
+ const ALPHABET = BASE_ALPHABETS[MultibaseEncoding.BASE58_BTC];
85
+ // Count leading '1's (representing leading zero bytes)
86
+ let zeros = 0;
87
+ for (let i = 0; i < str.length && str[i] === '1'; i++) {
88
+ zeros++;
89
+ }
90
+ // Convert from base58 to a big integer
91
+ let num = 0n;
92
+ for (let i = zeros; i < str.length; i++) {
93
+ const char = str[i];
94
+ const value = ALPHABET.indexOf(char);
95
+ if (value === -1) {
96
+ throw new Error(`Invalid Base58 character: ${char}`);
97
+ }
98
+ num = num * 58n + BigInt(value);
99
+ }
100
+ // Convert to bytes
101
+ const bytes = [];
102
+ while (num > 0n) {
103
+ bytes.unshift(Number(num % 256n));
104
+ num = num / 256n;
105
+ }
106
+ // Add leading zeros
107
+ return new Uint8Array([...new Array(zeros).fill(0), ...bytes]);
108
+ }
109
+ /**
110
+ * Encodes binary data using the specified multibase encoding
111
+ * @param bytes - The binary data to encode
112
+ * @param encoding - The multibase encoding to use
113
+ * @returns The multibase encoded string (including the prefix)
114
+ */
115
+ export function multibaseEncode(bytes, encoding = MultibaseEncoding.BASE64URL_NO_PAD) {
116
+ let encoded;
117
+ switch (encoding) {
118
+ case MultibaseEncoding.BASE64URL_NO_PAD:
119
+ encoded = encodeBase64Url(bytes);
120
+ break;
121
+ case MultibaseEncoding.BASE58_BTC:
122
+ encoded = encodeBase58Btc(bytes);
123
+ break;
124
+ default:
125
+ throw new Error(`Unsupported multibase encoding: ${encoding}`);
126
+ }
127
+ return `${encoding}${encoded}`;
128
+ }
129
+ /**
130
+ * Decodes a multibase encoded string to binary data
131
+ * @param str - The multibase encoded string
132
+ * @returns The decoded binary data and the encoding used
133
+ */
134
+ export function multibaseDecode(str) {
135
+ if (!str || str.length < 2) {
136
+ throw new Error('Invalid multibase string: too short');
137
+ }
138
+ const prefix = str[0];
139
+ const encoded = str.slice(1);
140
+ let bytes;
141
+ switch (prefix) {
142
+ case MultibaseEncoding.BASE64URL_NO_PAD:
143
+ bytes = decodeBase64Url(encoded);
144
+ break;
145
+ case MultibaseEncoding.BASE58_BTC:
146
+ bytes = decodeBase58Btc(encoded);
147
+ break;
148
+ default:
149
+ throw new Error(`Unsupported multibase encoding prefix: ${prefix}`);
150
+ }
151
+ return { bytes, encoding: prefix };
152
+ }
153
+ // ===== MULTIHASH IMPLEMENTATION =====
154
+ /**
155
+ * Supported Multihash algorithm identifiers
156
+ */
157
+ export var MultihashAlgorithm;
158
+ (function (MultihashAlgorithm) {
159
+ MultihashAlgorithm[MultihashAlgorithm["SHA2_256"] = 18] = "SHA2_256";
160
+ MultihashAlgorithm[MultihashAlgorithm["SHA2_384"] = 32] = "SHA2_384";
161
+ MultihashAlgorithm[MultihashAlgorithm["SHA3_256"] = 22] = "SHA3_256";
162
+ MultihashAlgorithm[MultihashAlgorithm["SHA3_384"] = 21] = "SHA3_384";
163
+ })(MultihashAlgorithm || (MultihashAlgorithm = {}));
164
+ /**
165
+ * Expected digest lengths for each algorithm (in bytes)
166
+ */
167
+ export const DIGEST_LENGTHS = {
168
+ [MultihashAlgorithm.SHA2_256]: 32,
169
+ [MultihashAlgorithm.SHA2_384]: 48,
170
+ [MultihashAlgorithm.SHA3_256]: 32,
171
+ [MultihashAlgorithm.SHA3_384]: 48,
172
+ };
173
+ /**
174
+ * Encodes a varint (variable integer)
175
+ * @param value - The integer to encode
176
+ * @returns The encoded varint as a Uint8Array
177
+ */
178
+ function encodeVarint(value) {
179
+ const bytes = [];
180
+ while (value >= 0x80) {
181
+ bytes.push((value & 0x7f) | 0x80);
182
+ value >>>= 7;
183
+ }
184
+ bytes.push(value & 0x7f);
185
+ return new Uint8Array(bytes);
186
+ }
187
+ /**
188
+ * Decodes a varint (variable integer)
189
+ * @param bytes - The bytes containing the varint
190
+ * @param offset - The starting offset in the bytes array
191
+ * @returns The decoded value and the number of bytes read
192
+ */
193
+ function decodeVarint(bytes, offset = 0) {
194
+ let value = 0;
195
+ let shift = 0;
196
+ let bytesRead = 0;
197
+ let byte = 0;
198
+ do {
199
+ if (offset + bytesRead >= bytes.length) {
200
+ throw new Error('Invalid varint: buffer too short');
201
+ }
202
+ byte = bytes[offset + bytesRead];
203
+ value |= (byte & 0x7f) << shift;
204
+ shift += 7;
205
+ bytesRead++;
206
+ } while (byte & 0x80);
207
+ return { value, bytesRead };
208
+ }
209
+ /**
210
+ * Creates a multihash from a digest and algorithm
211
+ * @param digest - The digest bytes
212
+ * @param algorithm - The hash algorithm used
213
+ * @returns The multihash as a Uint8Array
214
+ */
215
+ export function createMultihash(digest, algorithm) {
216
+ const expectedLength = DIGEST_LENGTHS[algorithm];
217
+ if (digest.length !== expectedLength) {
218
+ throw new Error(`Invalid digest length for algorithm ${algorithm.toString(16)}: expected ${expectedLength}, got ${digest.length}`);
219
+ }
220
+ const algorithmBytes = encodeVarint(algorithm);
221
+ const lengthBytes = encodeVarint(digest.length);
222
+ const result = new Uint8Array(algorithmBytes.length + lengthBytes.length + digest.length);
223
+ result.set(algorithmBytes, 0);
224
+ result.set(lengthBytes, algorithmBytes.length);
225
+ result.set(digest, algorithmBytes.length + lengthBytes.length);
226
+ return result;
227
+ }
228
+ /**
229
+ * Decodes a multihash
230
+ * @param bytes - The multihash bytes
231
+ * @returns The decoded multihash components
232
+ */
233
+ export function decodeMultihash(bytes) {
234
+ if (bytes.length < 2) {
235
+ throw new Error('Invalid multihash: too short');
236
+ }
237
+ // Decode the algorithm identifier
238
+ const { value: algorithm, bytesRead: algorithmBytesRead } = decodeVarint(bytes, 0);
239
+ // Decode the digest length
240
+ const { value: digestLength, bytesRead: lengthBytesRead } = decodeVarint(bytes, algorithmBytesRead);
241
+ // Extract the digest
242
+ const offset = algorithmBytesRead + lengthBytesRead;
243
+ if (bytes.length - offset < digestLength) {
244
+ throw new Error(`Invalid multihash: digest too short, expected ${digestLength} bytes`);
245
+ }
246
+ const digest = bytes.slice(offset, offset + digestLength);
247
+ // Verify the algorithm is supported
248
+ if (!Object.values(MultihashAlgorithm).includes(algorithm)) {
249
+ throw new Error(`Unsupported multihash algorithm: 0x${algorithm.toString(16)}`);
250
+ }
251
+ // Verify the digest length matches the expected length for the algorithm
252
+ const expectedLength = DIGEST_LENGTHS[algorithm];
253
+ if (digestLength !== expectedLength) {
254
+ throw new Error(`Invalid digest length for algorithm 0x${algorithm.toString(16)}: expected ${expectedLength}, got ${digestLength}`);
255
+ }
256
+ return {
257
+ algorithm: algorithm,
258
+ digestLength,
259
+ digest,
260
+ };
261
+ }
262
+ /**
263
+ * Encodes a multihash using multibase encoding
264
+ * @param multihash - The multihash bytes
265
+ * @param encoding - The multibase encoding to use
266
+ * @returns The multibase encoded multihash
267
+ */
268
+ export function encodeMultihashWithMultibase(multihash, encoding = MultibaseEncoding.BASE64URL_NO_PAD) {
269
+ return multibaseEncode(multihash, encoding);
270
+ }
271
+ /**
272
+ * Decodes a multibase encoded multihash
273
+ * @param str - The multibase encoded multihash
274
+ * @returns The decoded multihash components and the encoding used
275
+ */
276
+ export function decodeMultihashFromMultibase(str) {
277
+ const { bytes, encoding } = multibaseDecode(str);
278
+ const multihash = decodeMultihash(bytes);
279
+ return {
280
+ ...multihash,
281
+ encoding,
282
+ };
283
+ }
@@ -0,0 +1,49 @@
1
+ import type { CreateDIDInterface, DIDDoc, DIDLog, ParsedDidKeyVerificationMethod, VerificationMethod, WitnessProofFileEntry } from './interfaces.js';
2
+ export declare function parseDidKeyDid(input: string): {
3
+ did: string;
4
+ keyMultibase: string;
5
+ };
6
+ export declare function parseDidKeyVerificationMethod(input: string): ParsedDidKeyVerificationMethod;
7
+ interface ParsedAddress {
8
+ canonicalHost: string;
9
+ canonicalPort?: number;
10
+ didDomainComponent: string;
11
+ paths?: string[];
12
+ }
13
+ export declare function parseCanonicalAddress(input: string): ParsedAddress;
14
+ export declare const DID_PLACEHOLDER = "{DID}";
15
+ export declare function validateCreateDidDocument(didDocument: DIDDoc): void;
16
+ export declare function replaceCreateDidPlaceholders<T>(input: T, scid: string, did: string): T;
17
+ export declare function convertWebvhIdToWebId(id: string): string;
18
+ export declare function enrichAlsoKnownAs(doc: DIDDoc, did: string, opts: {
19
+ alsoKnownAsWeb?: boolean;
20
+ }): DIDDoc;
21
+ export declare function generateParallelDidWeb(didwebvhDid: string, didwebvhDoc: DIDDoc): DIDDoc;
22
+ export declare const readLogFromDisk: (path: string) => Promise<DIDLog>;
23
+ export declare const readLogFromString: (str: string) => DIDLog;
24
+ export declare const writeLogToDisk: (path: string, log: DIDLog) => Promise<void>;
25
+ export declare const maybeWriteTestLog: (did: string, log: DIDLog) => Promise<void>;
26
+ export declare const writeVerificationMethodToEnv: (verificationMethod: VerificationMethod) => Promise<void>;
27
+ export declare const clone: (input: any) => any;
28
+ export declare function deepClone(obj: any): any;
29
+ export declare const getBaseUrl: (id: string) => string;
30
+ export declare const getFileUrl: (id: string) => string;
31
+ export declare function fetchLogFromIdentifier(identifier: string): Promise<DIDLog>;
32
+ export declare const createDate: (created?: Date | string) => string;
33
+ export declare function bytesToHex(bytes: Uint8Array): string;
34
+ export declare const createSCID: (logEntryHash: string) => Promise<string>;
35
+ export declare function deriveHash(input: any): Promise<string>;
36
+ export declare const deriveNextKeyHash: (input: string) => Promise<string>;
37
+ export declare const createDIDDoc: (options: CreateDIDInterface) => Promise<{
38
+ doc: DIDDoc;
39
+ }>;
40
+ export declare const generateRandomId: (length?: number) => string;
41
+ export declare const createVMID: (vm: VerificationMethod, did: string | null) => string;
42
+ export declare const normalizeVMs: (verificationMethod: VerificationMethod[] | undefined, did?: string | null) => any;
43
+ export declare const resolveVM: (vm: string) => Promise<VerificationMethod | {
44
+ publicKeyMultibase: string;
45
+ } | null>;
46
+ export declare const findVerificationMethod: (doc: any, vmId: string) => VerificationMethod | null;
47
+ export declare function fetchWitnessProofs(did: string): Promise<WitnessProofFileEntry[]>;
48
+ export declare function replaceValueInObject(obj: any, searchValue: string, replaceValue: string): any;
49
+ export {};