A zero-dependency AT Protocol Personal Data Server written in JavaScript

docs: add 'why' comments to protocol-specific logic

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

Changed files
+9 -3
src
+9 -3
src/pds.js
··· 118 118 encodeHead(parts, 3, bytes.length) 119 119 parts.push(...bytes) 120 120 } else if (val instanceof CID) { 121 - // CID - encode with CBOR tag 42 + 0x00 prefix 121 + // CID links in DAG-CBOR use tag 42 + 0x00 multibase prefix 122 + // The 0x00 prefix indicates "identity" multibase (raw bytes) 122 123 parts.push(0xd8, CBOR_TAG_CID) 123 124 encodeHead(parts, 2, val.bytes.length + 1) // +1 for 0x00 prefix 124 - parts.push(0x00) // multibase identity prefix 125 + parts.push(0x00) 125 126 parts.push(...val.bytes) 126 127 } else if (val instanceof Uint8Array) { 127 128 // Regular byte string ··· 132 133 for (const item of val) encode(item) 133 134 } else if (typeof val === 'object') { 134 135 // DAG-CBOR: sort keys by length first, then lexicographically 136 + // (differs from standard CBOR which sorts lexicographically only) 135 137 const keys = Object.keys(val).filter(k => val[k] !== undefined) 136 138 keys.sort((a, b) => { 137 139 if (a.length !== b.length) return a.length - b.length ··· 378 380 ) 379 381 const sig = new Uint8Array(signature) 380 382 381 - // Low-S normalization: if S > N/2, replace S with N - S 382 383 const r = sig.slice(0, 32) 383 384 const s = sig.slice(32, 64) 384 385 const sBigInt = bytesToBigInt(s) 385 386 387 + // Low-S normalization: Bitcoin/ATProto require S <= N/2 to prevent 388 + // signature malleability (two valid signatures for same message) 386 389 if (sBigInt > P256_N_DIV_2) { 387 390 const newS = P256_N - sBigInt 388 391 const newSBytes = bigIntToBytes(newS, 32) ··· 499 502 } 500 503 } 501 504 505 + // MST depth = leading zeros in SHA-256 hash / 2 506 + // This creates a probabilistic tree where ~50% of keys are at depth 0, 507 + // ~25% at depth 1, etc., giving O(log n) lookups 502 508 const depth = Math.floor(zeros / 2) 503 509 keyDepthCache.set(key, depth) 504 510 return depth