+12
package-lock.json
+12
package-lock.json
+35
-8
scripts/setup.js
+35
-8
scripts/setup.js
···
149
return result
150
}
151
152
-
// === CBOR ENCODING (minimal for PLC operations) ===
153
154
function cborEncode(value) {
155
const parts = []
···
172
encodeHead(4, val.length)
173
for (const item of val) encode(item)
174
} else if (typeof val === 'object') {
175
-
const keys = Object.keys(val).sort()
176
-
encodeHead(5, keys.length)
177
-
for (const key of keys) {
178
encode(key)
179
encode(val[key])
180
}
···
289
}
290
291
async function deriveDidFromOperation(operation) {
292
-
const { sig, ...opWithoutSig } = operation
293
-
const encoded = cborEncode(opWithoutSig)
294
const hash = await sha256(encoded)
295
-
// DID is base32 of first 24 bytes of hash
296
-
return 'did:plc:' + base32Encode(hash.slice(0, 24))
297
}
298
299
function base32Encode(bytes) {
···
149
return result
150
}
151
152
+
// === CBOR ENCODING (dag-cbor compliant for PLC operations) ===
153
+
154
+
function cborEncodeKey(key) {
155
+
// Encode a string key to CBOR bytes (for sorting)
156
+
const bytes = new TextEncoder().encode(key)
157
+
const parts = []
158
+
const mt = 3 << 5 // major type 3 = text string
159
+
if (bytes.length < 24) {
160
+
parts.push(mt | bytes.length)
161
+
} else if (bytes.length < 256) {
162
+
parts.push(mt | 24, bytes.length)
163
+
} else if (bytes.length < 65536) {
164
+
parts.push(mt | 25, bytes.length >> 8, bytes.length & 0xff)
165
+
}
166
+
parts.push(...bytes)
167
+
return new Uint8Array(parts)
168
+
}
169
+
170
+
function compareBytes(a, b) {
171
+
// dag-cbor: bytewise lexicographic order of encoded keys
172
+
const minLen = Math.min(a.length, b.length)
173
+
for (let i = 0; i < minLen; i++) {
174
+
if (a[i] !== b[i]) return a[i] - b[i]
175
+
}
176
+
return a.length - b.length
177
+
}
178
179
function cborEncode(value) {
180
const parts = []
···
197
encodeHead(4, val.length)
198
for (const item of val) encode(item)
199
} else if (typeof val === 'object') {
200
+
// dag-cbor: sort keys by their CBOR-encoded bytes (length first, then lexicographic)
201
+
const keys = Object.keys(val)
202
+
const keysSorted = keys.sort((a, b) => compareBytes(cborEncodeKey(a), cborEncodeKey(b)))
203
+
encodeHead(5, keysSorted.length)
204
+
for (const key of keysSorted) {
205
encode(key)
206
encode(val[key])
207
}
···
316
}
317
318
async function deriveDidFromOperation(operation) {
319
+
// DID is computed from the FULL operation INCLUDING the signature
320
+
const encoded = cborEncode(operation)
321
const hash = await sha256(encoded)
322
+
// DID is base32 of first 15 bytes of hash (= 24 base32 chars)
323
+
return 'did:plc:' + base32Encode(hash.slice(0, 15))
324
}
325
326
function base32Encode(bytes) {