@optimystic/quereus-plugin-crypto 0.21.0 → 0.24.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/CHANGELOG.md +91 -91
- package/dist/index.js.map +1 -1
- package/dist/plugin.js.map +1 -1
- package/package.json +2 -2
- package/src/cid.ts +200 -200
- package/src/crypto.ts +547 -547
- package/src/sd.ts +250 -250
package/dist/plugin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/crypto.ts","../src/cid.ts","../src/sd.ts","../src/plugin.ts"],"names":["uint8ArrayFromString","uint8ArrayToString","nobleRandomBytes"],"mappings":"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","file":"plugin.js","sourcesContent":["/**\n * Cryptographic Functions for Quereus\n *\n * Idiomatic ES module exports with base64url as default encoding.\n * All functions accept and return base64url strings by default for SQL compatibility.\n */\n\nimport { sha256, sha512 } from '@noble/hashes/sha2.js';\nimport { blake3 } from '@noble/hashes/blake3.js';\nimport { randomBytes as nobleRandomBytes, utf8ToBytes, concatBytes } from '@noble/hashes/utils.js';\nimport { secp256k1 } from '@noble/curves/secp256k1.js';\nimport { p256 } from '@noble/curves/nist.js';\nimport { ed25519 } from '@noble/curves/ed25519.js';\nimport { hexToBytes, bytesToHex } from '@noble/curves/utils.js';\nimport { toString as uint8ArrayToString, fromString as uint8ArrayFromString } from 'uint8arrays';\n\n// Type definitions\nexport type HashAlgorithm = 'sha256' | 'sha512' | 'blake3';\nexport type CurveType = 'secp256k1' | 'p256' | 'ed25519';\nexport type Encoding = 'base64url' | 'base64' | 'hex' | 'utf8' | 'bytes';\n\n/** Encodings valid for hash *output* (no 'utf8' — a digest is not UTF-8 text). */\nexport type OutputEncoding = 'base64url' | 'base64' | 'hex' | 'bytes';\n\n/** A single value in a multi-field digest. Mirrors the SQL value space. */\nexport type DigestField =\n\t| string\n\t| number\n\t| bigint\n\t| boolean\n\t| Uint8Array\n\t| null\n\t| undefined\n\t| { readonly [key: string]: unknown }\n\t| readonly unknown[];\n\n/** A resolved hash function: raw bytes in, digest bytes out. */\nexport type DigestHasher = (input: Uint8Array) => Uint8Array;\n\n/** A resolved output encoder: digest bytes in, encoded form out. */\nexport type OutputEncoder = (bytes: Uint8Array) => string | Uint8Array;\n\n/**\n * Convert input to Uint8Array, handling various encodings\n */\nfunction toBytes(input: string | Uint8Array | null | undefined, encoding: Encoding = 'base64url'): Uint8Array {\n\tif (input === null || input === undefined) {\n\t\treturn new Uint8Array(0);\n\t}\n\n\tif (input instanceof Uint8Array) {\n\t\treturn input;\n\t}\n\n\tif (typeof input === 'string') {\n\t\tswitch (encoding) {\n\t\t\tcase 'base64url':\n\t\t\t\treturn uint8ArrayFromString(input, 'base64url');\n\t\t\tcase 'base64':\n\t\t\t\treturn uint8ArrayFromString(input, 'base64');\n\t\t\tcase 'hex':\n\t\t\t\treturn hexToBytes(input);\n\t\t\tcase 'utf8':\n\t\t\t\treturn utf8ToBytes(input);\n\t\t\tdefault:\n\t\t\t\treturn uint8ArrayFromString(input, 'base64url');\n\t\t}\n\t}\n\n\tthrow new Error('Invalid input type');\n}\n\n/**\n * Convert Uint8Array to string in specified encoding\n */\nfunction fromBytes(bytes: Uint8Array, encoding: Encoding = 'base64url'): string | Uint8Array {\n\tswitch (encoding) {\n\t\tcase 'base64url':\n\t\t\treturn uint8ArrayToString(bytes, 'base64url');\n\t\tcase 'base64':\n\t\t\treturn uint8ArrayToString(bytes, 'base64');\n\t\tcase 'hex':\n\t\t\treturn bytesToHex(bytes);\n\t\tcase 'utf8':\n\t\t\treturn uint8ArrayToString(bytes, 'utf8');\n\t\tcase 'bytes':\n\t\t\treturn bytes;\n\t\tdefault:\n\t\t\treturn uint8ArrayToString(bytes, 'base64url');\n\t}\n}\n\n// --- Algorithm / encoding resolution (done once, no per-call switching) --- //\n\n/** Hash algorithm → noble hasher. Keyed lookup so the digest hot path never branches. */\nconst HASHERS: Record<HashAlgorithm, DigestHasher> = {\n\tsha256,\n\tsha512,\n\tblake3,\n};\n\n/** Output encoding → encoder closure. */\nconst OUTPUT_ENCODERS: Record<OutputEncoding, OutputEncoder> = {\n\tbase64url: (bytes) => uint8ArrayToString(bytes, 'base64url'),\n\tbase64: (bytes) => uint8ArrayToString(bytes, 'base64'),\n\thex: (bytes) => bytesToHex(bytes),\n\tbytes: (bytes) => bytes,\n};\n\n/**\n * Resolve a hash algorithm name to its hasher. Throws on unknown algorithm.\n * Call once (e.g. at plugin registration) and capture the result so the digest\n * hot path performs no per-call algorithm branching.\n */\nexport function resolveHasher(algorithm: HashAlgorithm): DigestHasher {\n\tconst hasher = HASHERS[algorithm];\n\tif (!hasher) {\n\t\tthrow new Error(`Unsupported hash algorithm: ${algorithm}`);\n\t}\n\treturn hasher;\n}\n\n/**\n * Resolve an output encoding name to its encoder. Throws on unknown encoding.\n */\nexport function resolveOutputEncoder(encoding: OutputEncoding): OutputEncoder {\n\tconst encoder = OUTPUT_ENCODERS[encoding];\n\tif (!encoder) {\n\t\tthrow new Error(`Unsupported output encoding: ${encoding}`);\n\t}\n\treturn encoder;\n}\n\n// --- Canonical, injective multi-field encoding --- //\n\n/**\n * Format version for {@link encodeFields}. Prepended to every encoding so the\n * framing can evolve, and so a framed digest is domain-separated from a bare\n * hash of the same bytes. Bump only with a deliberate, breaking format change.\n */\nconst DIGEST_FORMAT_V1 = 0x01;\n\n// Per-field type tags. Distinct tags keep distinct SQL types from colliding\n// (e.g. INTEGER 123 vs TEXT '123' vs BOOL true).\n//\n// Note on INT vs REAL: the tag is derived from the JS value, not from SQL\n// affinity (a scalar function does not receive affinity). An integer-VALUED\n// number — including a REAL like 2.0, which reaches JS as the number 2 — is\n// encoded as INTEGER. So INTEGER 2 and REAL 2.0 produce the same digest. This is\n// replicable (every peer sees the same JS value) but not int/real-distinguishing.\nconst TAG_NULL = 0x00; // bare tag, no length/payload\nconst TAG_INT = 0x01; // payload: canonical decimal string (number-integer & bigint unified via BigInt)\nconst TAG_REAL = 0x02; // payload: ECMAScript Number::toString (non-integer numbers only)\nconst TAG_TEXT = 0x03; // payload: UTF-8 bytes\nconst TAG_BOOL = 0x04; // payload: single 0x00/0x01 byte\nconst TAG_BLOB = 0x05; // payload: raw bytes\nconst TAG_JSON = 0x06; // payload: UTF-8 of key-sorted canonical JSON\n\n/** Append an unsigned LEB128 varint (safe for lengths up to MAX_SAFE_INTEGER). */\nfunction writeVarint(out: number[], value: number): void {\n\tif (!Number.isInteger(value) || value < 0) {\n\t\tthrow new Error(`varint expects a non-negative integer, got ${value}`);\n\t}\n\tlet v = value;\n\twhile (v >= 0x80) {\n\t\tout.push((v & 0x7f) | 0x80);\n\t\tv = Math.floor(v / 128);\n\t}\n\tout.push(v);\n}\n\n/** tag ‖ varint(len) ‖ payload */\nfunction framed(tag: number, payload: Uint8Array): Uint8Array {\n\tconst header: number[] = [tag];\n\twriteVarint(header, payload.length);\n\treturn concatBytes(Uint8Array.from(header), payload);\n}\n\n/**\n * Strict, deterministic JSON canonicalization for a native object/array field:\n * object keys recursively sorted, no incidental whitespace. Unlike `JSON.stringify`,\n * it THROWS rather than silently collapsing non-JSON inputs (`undefined`, non-finite\n * numbers, `bigint`, non-plain objects like `Date`/`Map`) — silent collapse would\n * break injectivity (`{a:undefined}` vs `{}`, `NaN` vs `null`, `new Date(0)` vs `{}`).\n */\nfunction canonicalJson(value: unknown): string {\n\tif (value === null) return 'null';\n\tconst t = typeof value;\n\tif (t === 'string') return JSON.stringify(value);\n\tif (t === 'boolean') return value ? 'true' : 'false';\n\tif (t === 'number') {\n\t\tif (!Number.isFinite(value)) {\n\t\t\tthrow new Error('digest: cannot encode a non-finite number inside a JSON field');\n\t\t}\n\t\treturn JSON.stringify(value) as string; // deterministic Number::toString\n\t}\n\tif (t === 'bigint') {\n\t\tthrow new Error('digest: bigint is not representable inside a JSON field');\n\t}\n\tif (Array.isArray(value)) {\n\t\treturn `[${value.map((el) => {\n\t\t\tif (el === undefined) {\n\t\t\t\tthrow new Error('digest: undefined / sparse element inside a JSON field');\n\t\t\t}\n\t\t\treturn canonicalJson(el);\n\t\t}).join(',')}]`;\n\t}\n\tif (t === 'object') {\n\t\tconst proto = Object.getPrototypeOf(value);\n\t\tif (proto !== Object.prototype && proto !== null) {\n\t\t\tthrow new Error('digest: only plain objects are allowed inside a JSON field');\n\t\t}\n\t\tconst obj = value as Record<string, unknown>;\n\t\tconst keys = Object.keys(obj).sort();\n\t\treturn `{${keys.map((k) => {\n\t\t\tif (obj[k] === undefined) {\n\t\t\t\tthrow new Error(`digest: undefined value for JSON key '${k}'`);\n\t\t\t}\n\t\t\treturn `${JSON.stringify(k)}:${canonicalJson(obj[k])}`;\n\t\t}).join(',')}}`;\n\t}\n\tthrow new Error(`digest: unsupported value of type '${t}' inside a JSON field`);\n}\n\n/** Encode one field as tag (‖ length ‖ payload). NULL/undefined is a bare tag. */\nfunction encodeField(field: DigestField): Uint8Array {\n\tif (field === null || field === undefined) {\n\t\treturn Uint8Array.of(TAG_NULL);\n\t}\n\tswitch (typeof field) {\n\t\tcase 'boolean':\n\t\t\treturn Uint8Array.of(TAG_BOOL, field ? 1 : 0);\n\t\tcase 'bigint':\n\t\t\treturn framed(TAG_INT, utf8ToBytes(field.toString()));\n\t\tcase 'number':\n\t\t\tif (!Number.isFinite(field)) {\n\t\t\t\tthrow new Error('digest: cannot encode a non-finite number');\n\t\t\t}\n\t\t\t// Integer-valued numbers go through BigInt so they encode identically to\n\t\t\t// the equal-valued bigint (e.g. 1e21 → full digits, not \"1e+21\").\n\t\t\treturn Number.isInteger(field)\n\t\t\t\t? framed(TAG_INT, utf8ToBytes(BigInt(field).toString()))\n\t\t\t\t: framed(TAG_REAL, utf8ToBytes(field.toString()));\n\t\tcase 'string':\n\t\t\treturn framed(TAG_TEXT, utf8ToBytes(field));\n\t\tcase 'object':\n\t\t\tif (field instanceof Uint8Array) {\n\t\t\t\treturn framed(TAG_BLOB, field);\n\t\t\t}\n\t\t\treturn framed(TAG_JSON, utf8ToBytes(canonicalJson(field)));\n\t\tdefault:\n\t\t\tthrow new Error(`digest: unsupported field type '${typeof field}'`);\n\t}\n}\n\n/**\n * Canonically encode an ordered tuple of fields into bytes such that distinct\n * tuples never collide (injective framing).\n *\n * Layout: `version ‖ field*` where each field is `tag ‖ varint(len) ‖ payload`\n * (NULL is a bare tag). Properties:\n * - order-preserving and arity-safe (self-delimiting fields → uniquely decodable),\n * - NULL distinguishable from empty string,\n * - type distinguishable (INTEGER 123 ≠ TEXT '123' ≠ BOOL true ≠ BLOB),\n * - delimiter-safe (a separator inside a string is just payload under its length).\n *\n * Replicability notes:\n * - Integer `number` and `bigint` of equal value encode identically (both via\n * `BigInt(...).toString()`); a non-integer REAL uses ECMAScript `Number::toString`\n * (deterministic across JS engines, but not guaranteed across other languages).\n * - INT vs REAL is derived from the JS value, not SQL affinity: an integer-valued\n * REAL (e.g. 2.0 → number 2) encodes as INTEGER, so INTEGER 2 and REAL 2.0 collide.\n * - A native JSON object/array field must contain only valid JSON (no `undefined`,\n * non-finite numbers, `bigint`, or non-plain objects) — otherwise it throws.\n */\nexport function encodeFields(fields: readonly DigestField[]): Uint8Array {\n\tconst chunks: Uint8Array[] = [Uint8Array.of(DIGEST_FORMAT_V1)];\n\tfor (const field of fields) {\n\t\tchunks.push(encodeField(field));\n\t}\n\treturn concatBytes(...chunks);\n}\n\n/**\n * Low-level multi-field digest: canonically encode the fields, then hash and\n * encode with the supplied (pre-resolved) hasher/encoder. No per-call branching\n * on algorithm or encoding — resolve once via {@link resolveHasher} /\n * {@link resolveOutputEncoder} and reuse.\n */\nexport function digestFields(\n\tfields: readonly DigestField[],\n\thasher: DigestHasher,\n\tencode: OutputEncoder\n): string | Uint8Array {\n\treturn encode(hasher(encodeFields(fields)));\n}\n\n/**\n * Compute an injective digest over an ordered tuple of fields.\n *\n * @param fields - Ordered tuple of values to hash (any SQL value type)\n * @param algorithm - Hash algorithm (default: 'sha256')\n * @param encoding - Output encoding (default: 'base64url')\n * @returns Hash digest in the specified encoding\n *\n * @example\n * ```typescript\n * // Hash a tuple of fields — distinct tuples never collide\n * const h = digest(['alice', 42, null, true]);\n *\n * // Pick algorithm / output encoding\n * const h512 = digest(['a', 'b'], 'sha512', 'hex');\n * ```\n *\n * Note: this is a *framed* digest, not a bare hash of raw bytes —\n * `digest(['hello'])` is not `sha256(\"hello\")`. Use `hashMod` for sharding a\n * single value.\n */\nexport function digest(\n\tfields: readonly DigestField[],\n\talgorithm: HashAlgorithm = 'sha256',\n\tencoding: OutputEncoding = 'base64url'\n): string | Uint8Array {\n\tif (!Array.isArray(fields)) {\n\t\tthrow new Error(\n\t\t\t`digest(fields, algorithm?, encoding?): 'fields' must be an array of values. ` +\n\t\t\t`The digest API changed in v0.14: it is now variadic/injective over fields, ` +\n\t\t\t`the per-call inputEncoding was removed, and algorithm + output encoding are bound at plugin load time. ` +\n\t\t\t`Migrate digest(value, algo, inputEncoding, outputEncoding) → digest([value], algo, outputEncoding) — ` +\n\t\t\t`note the result is now a *framed* digest, not a bare hash of the bytes.`\n\t\t);\n\t}\n\treturn digestFields(fields, resolveHasher(algorithm), resolveOutputEncoder(encoding));\n}\n\n/**\n * Hash data and return modulo of specified bit length\n * Useful for generating fixed-size hash values (e.g., 16-bit, 32-bit)\n *\n * @param data - Data to hash\n * @param bits - Number of bits for the result (e.g., 16 for 16-bit hash)\n * @param algorithm - Hash algorithm (default: 'sha256')\n * @param inputEncoding - Encoding of input string (default: 'base64url')\n * @returns Integer hash value modulo 2^bits\n *\n * @example\n * ```typescript\n * // Get 16-bit hash (0-65535)\n * const hash16 = hashMod('hello', 16, 'sha256', 'utf8');\n *\n * // Get 32-bit hash\n * const hash32 = hashMod('world', 32, 'sha256', 'utf8');\n * ```\n */\nexport function hashMod(\n\tdata: string | Uint8Array,\n\tbits: number,\n\talgorithm: HashAlgorithm = 'sha256',\n\tinputEncoding: Encoding = 'base64url'\n): number {\n\tif (bits <= 0 || bits > 53) {\n\t\tthrow new Error('Bits must be between 1 and 53 (JavaScript safe integer limit)');\n\t}\n\n\t// Single-blob hash for sharding (not the field-framed digest).\n\tconst hashBytes = resolveHasher(algorithm)(toBytes(data, inputEncoding));\n\n\t// Take first 8 bytes and convert to number\n\tconst view = new DataView(hashBytes.buffer, hashBytes.byteOffset, Math.min(8, hashBytes.length));\n\tconst fullHash = view.getBigUint64(0, false); // big-endian\n\n\t// Modulo by 2^bits\n\tconst modulus = BigInt(2) ** BigInt(bits);\n\tconst result = fullHash % modulus;\n\n\treturn Number(result);\n}\n\n/**\n * Sign data with a private key\n *\n * @param data - Data to sign (typically a hash)\n * @param privateKey - Private key (base64url string or Uint8Array)\n * @param curve - Elliptic curve (default: 'secp256k1')\n * @param inputEncoding - Encoding of data input (default: 'base64url')\n * @param keyEncoding - Encoding of private key (default: 'base64url')\n * @param outputEncoding - Encoding of signature output (default: 'base64url')\n * @returns Signature in specified encoding\n *\n * @example\n * ```typescript\n * // Sign a hash with secp256k1\n * const sig = sign(hashData, privateKey);\n *\n * // Sign with Ed25519\n * const sig2 = sign(hashData, privateKey, 'ed25519');\n * ```\n */\nexport function sign(\n\tdata: string | Uint8Array,\n\tprivateKey: string | Uint8Array,\n\tcurve: CurveType = 'secp256k1',\n\tinputEncoding: Encoding = 'base64url',\n\tkeyEncoding: Encoding = 'base64url',\n\toutputEncoding: Encoding = 'base64url'\n): string | Uint8Array {\n\tconst dataBytes = toBytes(data, inputEncoding);\n\tconst keyBytes = toBytes(privateKey, keyEncoding);\n\n\tlet sigBytes: Uint8Array;\n\n\tswitch (curve) {\n\t\tcase 'secp256k1':\n\t\t\tsigBytes = secp256k1.sign(dataBytes, keyBytes, { lowS: true });\n\t\t\tbreak;\n\t\tcase 'p256':\n\t\t\tsigBytes = p256.sign(dataBytes, keyBytes, { lowS: true });\n\t\t\tbreak;\n\t\tcase 'ed25519':\n\t\t\tsigBytes = ed25519.sign(dataBytes, keyBytes);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tthrow new Error(`Unsupported curve: ${curve}`);\n\t}\n\n\treturn fromBytes(sigBytes, outputEncoding);\n}\n\n/**\n * Verify a signature\n *\n * @param data - Data that was signed\n * @param signature - Signature to verify\n * @param publicKey - Public key\n * @param curve - Elliptic curve (default: 'secp256k1')\n * @param inputEncoding - Encoding of data input (default: 'base64url')\n * @param sigEncoding - Encoding of signature (default: 'base64url')\n * @param keyEncoding - Encoding of public key (default: 'base64url')\n * @returns true if signature is valid, false otherwise\n *\n * @example\n * ```typescript\n * // Verify a signature\n * const isValid = verify(hashData, signature, publicKey);\n *\n * // Verify with Ed25519\n * const isValid2 = verify(hashData, signature, publicKey, 'ed25519');\n * ```\n */\nexport function verify(\n\tdata: string | Uint8Array,\n\tsignature: string | Uint8Array,\n\tpublicKey: string | Uint8Array,\n\tcurve: CurveType = 'secp256k1',\n\tinputEncoding: Encoding = 'base64url',\n\tsigEncoding: Encoding = 'base64url',\n\tkeyEncoding: Encoding = 'base64url'\n): boolean {\n\ttry {\n\t\tconst dataBytes = toBytes(data, inputEncoding);\n\t\tconst sigBytes = toBytes(signature, sigEncoding);\n\t\tconst keyBytes = toBytes(publicKey, keyEncoding);\n\n\t\tswitch (curve) {\n\t\t\tcase 'secp256k1': {\n\t\t\t\treturn secp256k1.verify(sigBytes, dataBytes, keyBytes);\n\t\t\t}\n\t\t\tcase 'p256': {\n\t\t\t\treturn p256.verify(sigBytes, dataBytes, keyBytes);\n\t\t\t}\n\t\t\tcase 'ed25519': {\n\t\t\t\treturn ed25519.verify(sigBytes, dataBytes, keyBytes);\n\t\t\t}\n\t\t\tdefault:\n\t\t\t\tthrow new Error(`Unsupported curve: ${curve}`);\n\t\t}\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n/**\n * Generate cryptographically secure random bytes\n *\n * @param bits - Number of bits to generate (default: 256)\n * @param encoding - Output encoding (default: 'base64url')\n * @returns Random bytes in the specified encoding\n */\nexport function randomBytes(bits: number = 256, encoding: Encoding = 'base64url'): string | Uint8Array {\n\tconst bytes = Math.ceil(bits / 8);\n\tconst randomBytesArray = nobleRandomBytes(bytes);\n\treturn fromBytes(randomBytesArray, encoding);\n}\n\n/**\n * Generate a random private key\n */\nexport function generatePrivateKey(curve: CurveType = 'secp256k1', encoding: Encoding = 'base64url'): string | Uint8Array {\n\tlet keyBytes: Uint8Array;\n\n\tswitch (curve) {\n\t\tcase 'secp256k1':\n\t\t\tkeyBytes = secp256k1.utils.randomSecretKey();\n\t\t\tbreak;\n\t\tcase 'p256':\n\t\t\tkeyBytes = p256.utils.randomSecretKey();\n\t\t\tbreak;\n\t\tcase 'ed25519':\n\t\t\tkeyBytes = ed25519.utils.randomSecretKey();\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tthrow new Error(`Unsupported curve: ${curve}`);\n\t}\n\n\treturn fromBytes(keyBytes, encoding);\n}\n\n/**\n * Get public key from private key\n */\nexport function getPublicKey(\n\tprivateKey: string | Uint8Array,\n\tcurve: CurveType = 'secp256k1',\n\tkeyEncoding: Encoding = 'base64url',\n\toutputEncoding: Encoding = 'base64url'\n): string | Uint8Array {\n\tconst keyBytes = toBytes(privateKey, keyEncoding);\n\n\tlet pubBytes: Uint8Array;\n\n\tswitch (curve) {\n\t\tcase 'secp256k1':\n\t\t\tpubBytes = secp256k1.getPublicKey(keyBytes);\n\t\t\tbreak;\n\t\tcase 'p256':\n\t\t\tpubBytes = p256.getPublicKey(keyBytes);\n\t\t\tbreak;\n\t\tcase 'ed25519':\n\t\t\tpubBytes = ed25519.getPublicKey(keyBytes);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tthrow new Error(`Unsupported curve: ${curve}`);\n\t}\n\n\treturn fromBytes(pubBytes, outputEncoding);\n}\n\n","/**\n * Self-describing content identifiers (CIDv1) for Quereus.\n *\n * Where {@link ./crypto.ts | digest} emits a *bare* hash (raw digest bytes in\n * some text encoding), this module emits an interoperable, self-describing\n * CIDv1:\n *\n * ```\n * CIDv1 = multibase( version ‖ multicodec(content-type) ‖ multihash )\n * multihash = hashFnCode ‖ digestLength ‖ digestBytes\n * ```\n *\n * The value carries its own multibase, multicodec (content type), and multihash\n * (hash algorithm + length), so a consumer can decode it without out-of-band\n * knowledge, and an algorithm migration (e.g. sha2-256 → another hash) is\n * unambiguous because the hash code is recorded *in the value*.\n *\n * All framing/parsing comes from the audited `multiformats` library — there is\n * no bespoke byte-pushing here. The actual hashing reuses the same synchronous,\n * cross-platform `@noble/hashes` functions the rest of the plugin uses (via\n * {@link resolveHasher}), so the output is byte-identical to the CID an external\n * content-addressed store (IPFS/IPLD) computes for the same bytes:\n * `cid(utf8('hello world'))` === `bafkreifzjut3te2nhyekklss27nh3k72ysco7y32koao5eei66wof36n5e`.\n */\n\nimport { CID } from 'multiformats/cid';\nimport * as Digest from 'multiformats/hashes/digest';\nimport { base32 } from 'multiformats/bases/base32';\nimport { base58btc } from 'multiformats/bases/base58';\nimport { base64url } from 'multiformats/bases/base64';\nimport { base16 } from 'multiformats/bases/base16';\nimport type { MultibaseEncoder, MultibaseDecoder } from 'multiformats/bases/interface';\nimport { resolveHasher, type HashAlgorithm } from './crypto.js';\n\n/** Content-type multicodec selectable for the CID. Extensible. */\nexport type Multicodec = 'raw' | 'dag-cbor';\n/** Hash-algorithm multihash code selectable for the CID. */\nexport type MultihashCode = 'sha2-256' | 'sha2-512' | 'blake3';\n/** Multibase the CID string is rendered in. */\nexport type Multibase = 'base32' | 'base58btc' | 'base64url' | 'base16';\n\n/** Parsed parts of a CIDv1 (or CIDv0), as returned by {@link cidDecode}. */\nexport interface CidParts {\n\t/** CID version (1 for the values this module produces; 0 for legacy CIDv0). */\n\treadonly version: number;\n\t/** Content-type codec name when recognized, else the raw multicodec number. */\n\treadonly codec: Multicodec | number;\n\t/** Hash-algorithm code name when recognized, else the raw multihash number. */\n\treadonly hashCode: MultihashCode | number;\n\t/** Raw digest bytes (without the multihash code/length prefix). */\n\treadonly digest: Uint8Array;\n}\n\n// --- Multiformats code tables (see multiformats/multicodec table.csv) --- //\n\n/** Content-type name → multicodec code. */\nconst MULTICODEC_CODES: Record<Multicodec, number> = {\n\t'raw': 0x55,\n\t'dag-cbor': 0x71,\n};\n\n/** Hash name → multihash code. */\nconst MULTIHASH_CODES: Record<MultihashCode, number> = {\n\t'sha2-256': 0x12,\n\t'sha2-512': 0x13,\n\t'blake3': 0x1e,\n};\n\n/** Multihash code → the synchronous `@noble/hashes` algorithm that produces it. */\nconst MULTIHASH_TO_ALGORITHM: Record<MultihashCode, HashAlgorithm> = {\n\t'sha2-256': 'sha256',\n\t'sha2-512': 'sha512',\n\t'blake3': 'blake3',\n};\n\n/**\n * Multihash code → exact digest length in bytes. A CID is replicable only if its\n * digest length is fixed, so blake3 (which is variable-length in general) is\n * pinned to 32 bytes here, matching the plugin's blake3 output and sha2-256.\n */\nconst MULTIHASH_DIGEST_LENGTHS: Record<MultihashCode, number> = {\n\t'sha2-256': 32,\n\t'sha2-512': 64,\n\t'blake3': 32,\n};\n\n/** Reverse lookups for {@link cidDecode}: code number → friendly name. */\nconst MULTICODEC_NAMES: ReadonlyMap<number, Multicodec> = new Map(\n\t(Object.entries(MULTICODEC_CODES) as [Multicodec, number][]).map(([name, code]) => [code, name])\n);\nconst MULTIHASH_NAMES: ReadonlyMap<number, MultihashCode> = new Map(\n\t(Object.entries(MULTIHASH_CODES) as [MultihashCode, number][]).map(([name, code]) => [code, name])\n);\n\n/** Multibase name → its multiformats encoder. */\nconst MULTIBASE_ENCODERS: Record<Multibase, MultibaseEncoder<string>> = {\n\t'base32': base32,\n\t'base58btc': base58btc,\n\t'base64url': base64url,\n\t'base16': base16,\n};\n\n/**\n * Combined decoder that dispatches on the multibase prefix character, so\n * {@link cidDecode} accepts a CID in any of the supported bases without the\n * caller having to declare which.\n */\nconst MULTIBASE_DECODER: MultibaseDecoder<string> = base32.decoder\n\t.or(base58btc.decoder)\n\t.or(base64url.decoder)\n\t.or(base16.decoder);\n\nfunction resolveCodecCode(codec: Multicodec): number {\n\tconst code = MULTICODEC_CODES[codec];\n\tif (code === undefined) {\n\t\tthrow new Error(`cid: unsupported multicodec '${codec}' (expected one of ${Object.keys(MULTICODEC_CODES).join(', ')})`);\n\t}\n\treturn code;\n}\n\nfunction resolveBaseEncoder(base: Multibase): MultibaseEncoder<string> {\n\tconst encoder = MULTIBASE_ENCODERS[base];\n\tif (!encoder) {\n\t\tthrow new Error(`cid: unsupported multibase '${base}' (expected one of ${Object.keys(MULTIBASE_ENCODERS).join(', ')})`);\n\t}\n\treturn encoder;\n}\n\n/**\n * Frame an **already-computed** digest as a CIDv1 string. The caller asserts\n * which `hash` produced the digest; the digest length is validated against that\n * hash so a mismatched assertion is rejected rather than silently mis-framed.\n *\n * Use this to turn an existing field-tuple digest into a CID without re-hashing,\n * e.g. `cidV1(digest(fields, 'sha256', 'bytes'), 'sha2-256')`.\n *\n * @param digest - Raw digest bytes (no multihash prefix).\n * @param hash - The multihash code asserting which algorithm produced `digest`.\n * @param codec - Content-type multicodec (default `'raw'`).\n * @param base - Multibase to render in (default `'base32'`, the IPFS canonical).\n */\nexport function cidV1(\n\tdigest: Uint8Array,\n\thash: MultihashCode,\n\tcodec: Multicodec = 'raw',\n\tbase: Multibase = 'base32'\n): string {\n\tconst hashCode = MULTIHASH_CODES[hash];\n\tif (hashCode === undefined) {\n\t\tthrow new Error(`cid: unsupported multihash code '${hash}' (expected one of ${Object.keys(MULTIHASH_CODES).join(', ')})`);\n\t}\n\tconst expectedLength = MULTIHASH_DIGEST_LENGTHS[hash];\n\tif (digest.length !== expectedLength) {\n\t\tthrow new Error(`cid: digest length ${digest.length} does not match asserted hash '${hash}' (expected ${expectedLength} bytes)`);\n\t}\n\tconst codecCode = resolveCodecCode(codec);\n\tconst encoder = resolveBaseEncoder(base);\n\tconst multihash = Digest.create(hashCode, digest);\n\treturn CID.createV1(codecCode, multihash).toString(encoder);\n}\n\n/**\n * Hash `data`, wrap the digest as a multihash, frame it as a CIDv1, and encode\n * in `base`. The result is the same interoperable address an IPFS/IPLD store\n * computes for the same bytes (for the matching codec/hash).\n *\n * @param data - The content bytes to address.\n * @param codec - Content-type multicodec (default `'raw'`).\n * @param hash - Hash algorithm (default `'sha2-256'`).\n * @param base - Multibase to render in (default `'base32'`, the IPFS canonical).\n */\nexport function cid(\n\tdata: Uint8Array,\n\tcodec: Multicodec = 'raw',\n\thash: MultihashCode = 'sha2-256',\n\tbase: Multibase = 'base32'\n): string {\n\tconst algorithm = MULTIHASH_TO_ALGORITHM[hash];\n\tif (!algorithm) {\n\t\tthrow new Error(`cid: unsupported multihash code '${hash}' (expected one of ${Object.keys(MULTIHASH_CODES).join(', ')})`);\n\t}\n\tconst digest = resolveHasher(algorithm)(data);\n\treturn cidV1(digest, hash, codec, base);\n}\n\n/**\n * Parse a CID string back into its parts, for schema validation and migration.\n * Recognized codec/hash codes are returned as friendly names; unrecognized ones\n * as their raw numbers. Throws cleanly on malformed input (delegated to\n * `multiformats`), never silently mis-framing.\n */\nexport function cidDecode(value: string): CidParts {\n\tconst parsed = CID.parse(value, MULTIBASE_DECODER);\n\treturn {\n\t\tversion: parsed.version,\n\t\tcodec: MULTICODEC_NAMES.get(parsed.code) ?? parsed.code,\n\t\thashCode: MULTIHASH_NAMES.get(parsed.multihash.code) ?? parsed.multihash.code,\n\t\tdigest: parsed.multihash.digest,\n\t};\n}\n","/**\n * Salted-leaf SET COMMITMENT for per-attribute selective disclosure.\n *\n * An authority commits to a whole set of attributes as a single root value (which\n * it signs / persists), then later reveals only a chosen *subset* to a recipient —\n * with a proof that the revealed values are genuinely the committed ones — without\n * leaking the values of the withheld attributes. A flat `digest(whole set)` cannot\n * do this (verifying one field needs the whole pre-image, so it is all-or-nothing);\n * this construction supports *partial opening*.\n *\n * ## Construction (flat salted-leaf set commitment, NOT a Merkle tree)\n *\n * Each disclosable attribute is a salted leaf, and the commitment (root) is the\n * digest of all leaf digests in canonical order:\n *\n * ```\n * leafDigest = digest([SD_LEAF_DOMAIN_V1, name, value, salt]) // raw digest bytes\n * root = digest([SD_SET_DOMAIN_V1, sortedLeaf_0, sortedLeaf_1, ...])\n * ```\n *\n * Both layers compose on the existing canonical {@link encodeFields} framing\n * (injective, type-tagged, length-prefixed, replicable) — the same layering the CID\n * work uses — so a *generic* salted-set primitive is simultaneously reusable and\n * fully DB-enforceable. This is the same shape the IETF SD-JWT standard settled on\n * (flat salted hashes, not a tree); we are NOT wire-compatible with SD-JWT (we reuse\n * Optimystic's own `encodeFields` framing for cross-peer replicability) — SD-JWT is\n * cited only as conceptual precedent that the smaller construction is the right one.\n *\n * Voter selective-disclosure field sets are small (a handful to a few dozen fields),\n * so a tree's only advantage — O(log n) proof size — is marginal, while a tree drags\n * in real footguns we would have to hand-roll and pin (arity, odd-node handling /\n * the CVE-2012-2459 duplicate-leaf forgery class, leaf-vs-internal domain separation,\n * and a separate audit-path proof format). A flat construction avoids all of them.\n *\n * ## Why these specific choices\n *\n * - **`name` is hashed into the leaf** so a disclosed `(value, salt)` proof cannot be\n * replayed against a different attribute slot (e.g. presenting an `over18=true`\n * proof as the `citizen` field). The binding is free given `encodeFields` framing.\n * - **`salt` is per-leaf and mandatory** — low-entropy attributes (DOB, booleans, ZIP)\n * are brute-forceable from a bare hash, and independent salts also defeat cross-\n * registrant equality correlation. Salts come from `random_bytes` (≥128 bits).\n * - **Canonical order is by raw leaf-digest bytes (lexicographic), and this is FORCED,\n * not a preference.** In a disclosure the verifier learns the *names* of only the\n * disclosed leaves; the withheld leaves arrive as opaque digests with no name. So the\n * verifier can re-derive the root only if the ordering key is something it holds for\n * *every* leaf — the leaf digest itself. Sorting by name would be unverifiable for\n * hidden leaves. Do NOT \"tidy\" this into a name sort.\n * - Sort is over **raw digest bytes**, never over encoded strings — an encoding-\n * dependent ordering would break cross-peer agreement. Output encoding applies only\n * to the final root.\n *\n * Because leaf and root reuse `encodeFields`, a future `DIGEST_FORMAT_V1` bump changes\n * `setCommit` output too; this coupling is intentional (one canonical framing).\n */\n\nimport { fromString as uint8ArrayFromString, toString as uint8ArrayToString } from 'uint8arrays';\nimport {\n\tencodeFields,\n\tresolveHasher,\n\tresolveOutputEncoder,\n\ttype DigestField,\n\ttype DigestHasher,\n\ttype OutputEncoder,\n} from './crypto.js';\n\n/**\n * Fixed domain-separation constants — the leading string field of each layer's\n * {@link encodeFields} tuple. They are pinned EXACTLY like `DIGEST_FORMAT_V1`:\n *\n * - the two strings MUST be distinct, so a leaf hash can never equal a root hash;\n * - neither may change without a deliberate, breaking version bump — which would\n * change every committed root and every signature taken over it.\n *\n * Do not \"tidy\" or shorten these.\n */\nconst SD_LEAF_DOMAIN_V1 = 'optimystic/sd-leaf/v1';\nconst SD_SET_DOMAIN_V1 = 'optimystic/sd-set/v1';\n\n/** Hidden leaf digests travel as base64url text — the plugin's canonical text encoding. */\nconst HIDDEN_ENCODING = 'base64url';\n\n/** One disclosable attribute. `value` spans the SQL value space ({@link DigestField}). */\nexport interface SaltedLeaf {\n\treadonly name: string;\n\treadonly value: DigestField;\n\t/** base64url text (e.g. from `random_bytes`) or raw bytes. Mandatory, non-empty. */\n\treadonly salt: string | Uint8Array;\n}\n\n/** A disclosure payload sent to a recipient. */\nexport interface SetDisclosure {\n\t/** The opened `(name, value, salt)` triples. */\n\treadonly disclosed: readonly SaltedLeaf[];\n\t/** Opaque leaf digests (base64url) of the withheld leaves — no name, no value, no salt. */\n\treadonly hidden: readonly string[];\n}\n\n// --- internal helpers --- //\n\n/** Lexicographic compare of two byte arrays (the canonical leaf ordering key). */\nfunction compareBytes(a: Uint8Array, b: Uint8Array): number {\n\tconst len = Math.min(a.length, b.length);\n\tfor (let i = 0; i < len; i++) {\n\t\tconst d = a[i]! - b[i]!;\n\t\tif (d !== 0) return d;\n\t}\n\treturn a.length - b.length;\n}\n\n/** Constant-shape byte equality (length first, then content). */\nfunction bytesEqual(a: Uint8Array, b: Uint8Array): boolean {\n\tif (a.length !== b.length) return false;\n\tfor (let i = 0; i < a.length; i++) {\n\t\tif (a[i] !== b[i]) return false;\n\t}\n\treturn true;\n}\n\n/**\n * Normalize a leaf's salt to raw bytes — a base64url string (the form `random_bytes`\n * returns) decodes to bytes, raw bytes pass through — so the two representations of the\n * same salt commit identically. THROWS on a missing or empty salt (unsalted leaves are\n * brute-forceable, an invalid state we make impossible).\n */\nfunction requireSaltBytes(leaf: SaltedLeaf): Uint8Array {\n\tconst { salt } = leaf;\n\tif (salt == null) {\n\t\tthrow new Error(`set commitment: leaf '${leaf.name}' is missing a salt (an unsalted leaf is brute-forceable)`);\n\t}\n\tconst bytes = salt instanceof Uint8Array ? salt : uint8ArrayFromString(salt, HIDDEN_ENCODING);\n\tif (bytes.length === 0) {\n\t\tthrow new Error(`set commitment: leaf '${leaf.name}' has an empty salt (an unsalted leaf is brute-forceable)`);\n\t}\n\treturn bytes;\n}\n\n/**\n * THROW on a duplicate `name`. Two leaves with the same name would let a holder\n * selectively present whichever value suits them; the authority side (which holds all\n * names) is the only place uniqueness can be enforced — the verifier never sees the\n * hidden names — so the primitive must fail-fast.\n */\nfunction assertUniqueNames(leaves: readonly SaltedLeaf[]): void {\n\tconst seen = new Set<string>();\n\tfor (const leaf of leaves) {\n\t\tif (seen.has(leaf.name)) {\n\t\t\tthrow new Error(`set commitment: duplicate leaf name '${leaf.name}'`);\n\t\t}\n\t\tseen.add(leaf.name);\n\t}\n}\n\n// --- public API --- //\n\n/**\n * Raw leaf digest bytes for one salted leaf: `digest([SD_LEAF_DOMAIN_V1, name,\n * value, salt])`. Domain-separated (can never equal a root) and name-bound (a\n * `(value, salt)` proof cannot be replayed under another attribute name). THROWS on\n * a missing/empty salt.\n */\nexport function leafDigest(leaf: SaltedLeaf, hasher: DigestHasher): Uint8Array {\n\tconst saltBytes = requireSaltBytes(leaf);\n\treturn hasher(encodeFields([SD_LEAF_DOMAIN_V1, leaf.name, leaf.value, saltBytes]));\n}\n\n/**\n * Commit to a SET of salted leaves → a single root (the signed/persisted value).\n * Sorts leaves by raw leaf-digest bytes, then digests them under `SD_SET_DOMAIN_V1`.\n * Like `digest`, this emits a BARE digest — apply `cid()` on top for the self-\n * describing column representation (`cid(set_commit(...))`).\n *\n * The empty set is well-defined (the digest of `[SD_SET_DOMAIN_V1]`), not an error.\n * THROWS on a duplicate `name` or a missing/empty `salt` (invalid states made\n * impossible). Resolve `hasher`/`encode` once and reuse — no per-call branching.\n */\nexport function setCommit(\n\tleaves: readonly SaltedLeaf[],\n\thasher: DigestHasher = resolveHasher('sha256'),\n\tencode: OutputEncoder = resolveOutputEncoder('base64url'),\n): string | Uint8Array {\n\tassertUniqueNames(leaves);\n\tconst leafDigests = leaves.map((leaf) => leafDigest(leaf, hasher));\n\tleafDigests.sort(compareBytes);\n\treturn encode(hasher(encodeFields([SD_SET_DOMAIN_V1, ...leafDigests])));\n}\n\n/**\n * Split a leaf set into the revealed `(name, value, salt)` triples plus the opaque\n * leaf digests (base64url) of the rest. Withheld `value`/`salt` never appear in the\n * output. Names in `revealNames` that match no leaf are simply not disclosed.\n * THROWS on a duplicate `name` or a missing/empty salt of a withheld leaf.\n */\nexport function setDisclose(\n\tleaves: readonly SaltedLeaf[],\n\trevealNames: readonly string[],\n\thasher: DigestHasher = resolveHasher('sha256'),\n): SetDisclosure {\n\tassertUniqueNames(leaves);\n\tconst reveal = new Set(revealNames);\n\tconst disclosed: SaltedLeaf[] = [];\n\tconst hidden: string[] = [];\n\tfor (const leaf of leaves) {\n\t\tif (reveal.has(leaf.name)) {\n\t\t\tdisclosed.push(leaf);\n\t\t} else {\n\t\t\thidden.push(uint8ArrayToString(leafDigest(leaf, hasher), HIDDEN_ENCODING));\n\t\t}\n\t}\n\treturn { disclosed, hidden };\n}\n\n/**\n * Verify a disclosure against a signed root. Recomputes the disclosed leaves'\n * digests, unions them with the supplied hidden digests, sorts by bytes, recomputes\n * the root, and compares to `root`. This reconstructs the ENTIRE root, so it proves\n * the disclosed leaves belong to *exactly* this committed set — the holder cannot\n * add, drop, or swap a leaf (the leaf count is bound too).\n *\n * `encode` is how the signed `root` is rendered (so the recomputed root is encoded\n * the same way before comparison); for a `Uint8Array` root the raw bytes are compared\n * directly. Returns `false` on mismatch or malformed input — mirroring `verify`'s\n * forgiving contract rather than throwing.\n */\nexport function setVerify(\n\troot: string | Uint8Array,\n\tdisclosure: SetDisclosure,\n\thasher: DigestHasher = resolveHasher('sha256'),\n\tencode: OutputEncoder = resolveOutputEncoder('base64url'),\n): boolean {\n\ttry {\n\t\tconst { disclosed, hidden } = disclosure;\n\t\tconst digests: Uint8Array[] = [];\n\t\tfor (const leaf of disclosed) {\n\t\t\tdigests.push(leafDigest(leaf, hasher));\n\t\t}\n\t\tfor (const h of hidden) {\n\t\t\tdigests.push(uint8ArrayFromString(h, HIDDEN_ENCODING));\n\t\t}\n\t\tdigests.sort(compareBytes);\n\t\tconst recomputed = hasher(encodeFields([SD_SET_DOMAIN_V1, ...digests]));\n\t\tif (root instanceof Uint8Array) {\n\t\t\treturn bytesEqual(recomputed, root);\n\t\t}\n\t\tconst encoded = encode(recomputed);\n\t\treturn typeof encoded === 'string' && encoded === root;\n\t} catch {\n\t\treturn false;\n\t}\n}\n","/**\r\n * Quereus Plugin Entry Point for Crypto Functions\r\n *\r\n * This module provides the plugin registration following Quereus 0.4.5 format.\r\n * All metadata is in package.json - no manifest export needed.\r\n */\r\n\r\nimport type { Database, SqlValue } from '@quereus/quereus';\r\nimport { FunctionFlags, TEXT_TYPE, INTEGER_TYPE, BOOLEAN_TYPE } from '@quereus/quereus';\r\nimport { fromString as uint8ArrayFromString, toString as uint8ArrayToString } from 'uint8arrays';\r\nimport {\r\n\tsign, verify, hashMod, randomBytes,\r\n\tdigestFields, resolveHasher, resolveOutputEncoder,\r\n\ttype HashAlgorithm, type OutputEncoding, type DigestField,\r\n} from './crypto.js';\r\nimport {\r\n\tcid, cidV1, cidDecode,\r\n\ttype Multicodec, type MultihashCode, type Multibase,\r\n} from './cid.js';\r\nimport {\r\n\tsetCommit, setVerify,\r\n\ttype SaltedLeaf,\r\n} from './sd.js';\r\n\r\nconst DIGEST_ALGORITHMS: readonly HashAlgorithm[] = ['sha256', 'sha512', 'blake3'];\r\n// SQL digest returns TEXT, so only text-producing encodings are valid here ('bytes' is JS-only).\r\nconst DIGEST_TEXT_ENCODINGS: readonly OutputEncoding[] = ['base64url', 'base64', 'hex'];\r\n\r\nfunction configAlgorithm(config: Record<string, SqlValue>): HashAlgorithm {\r\n\tconst value = config.algorithm == null ? 'sha256' : String(config.algorithm);\r\n\tif (!DIGEST_ALGORITHMS.includes(value as HashAlgorithm)) {\r\n\t\tthrow new Error(`crypto plugin: unsupported digest algorithm '${value}' (expected one of ${DIGEST_ALGORITHMS.join(', ')})`);\r\n\t}\r\n\treturn value as HashAlgorithm;\r\n}\r\n\r\nfunction configEncoding(config: Record<string, SqlValue>): OutputEncoding {\r\n\tconst value = config.encoding == null ? 'base64url' : String(config.encoding);\r\n\tif (!DIGEST_TEXT_ENCODINGS.includes(value as OutputEncoding)) {\r\n\t\tthrow new Error(`crypto plugin: unsupported digest encoding '${value}' (expected one of ${DIGEST_TEXT_ENCODINGS.join(', ')})`);\r\n\t}\r\n\treturn value as OutputEncoding;\r\n}\r\n\r\n/**\r\n * Coerce a SQL `data`/`digest` argument to raw bytes. A BLOB arrives as a\r\n * Uint8Array and is used directly; TEXT is interpreted as base64url — the\r\n * plugin's canonical text encoding — so `cid_v1(digest(...))` composes with the\r\n * base64url string `digest` returns, with no extra round-trip.\r\n */\r\nfunction toContentBytes(value: SqlValue | undefined, fnName: string): Uint8Array {\r\n\tif (value instanceof Uint8Array) {\r\n\t\treturn value;\r\n\t}\r\n\tif (typeof value === 'string') {\r\n\t\treturn uint8ArrayFromString(value, 'base64url');\r\n\t}\r\n\tthrow new Error(`${fnName}: expected a BLOB or base64url TEXT argument, got ${value == null ? 'NULL' : typeof value}`);\r\n}\r\n\r\n/**\r\n * Parse one JSON leaf — either `[name, value, salt]` or `{ name, value, salt }` —\r\n * into a {@link SaltedLeaf}. The JSON value maps directly to the `encodeFields` value\r\n * space (INTEGER vs REAL by JS value, TEXT, BOOL, null, nested object/array → JSON).\r\n *\r\n * Note: a BLOB-valued attribute is passed as its base64url TEXT and committed AS TEXT\r\n * (JSON has no blob type); callers needing a true BLOB value must use the JS API with a\r\n * `Uint8Array`. The salt is likewise base64url TEXT (decoded to bytes by `set_commit`).\r\n */\r\nfunction leafFromJson(entry: unknown, fnName: string): SaltedLeaf {\r\n\tif (Array.isArray(entry)) {\r\n\t\tif (entry.length < 3) {\r\n\t\t\tthrow new Error(`${fnName}: a leaf array must be [name, value, salt]`);\r\n\t\t}\r\n\t\tconst [name, value, salt] = entry;\r\n\t\tif (typeof name !== 'string') {\r\n\t\t\tthrow new Error(`${fnName}: leaf name must be a string`);\r\n\t\t}\r\n\t\treturn { name, value: value as DigestField, salt: salt as string };\r\n\t}\r\n\tif (entry !== null && typeof entry === 'object') {\r\n\t\tconst o = entry as Record<string, unknown>;\r\n\t\tif (typeof o.name !== 'string') {\r\n\t\t\tthrow new Error(`${fnName}: leaf name must be a string`);\r\n\t\t}\r\n\t\t// Require an explicit `value` key (symmetric with the array form, which demands all\r\n\t\t// three positions): a silently-absent value would commit NULL and mask a malformed\r\n\t\t// leaf. To commit a null-valued attribute, pass `value: null` explicitly.\r\n\t\tif (!('value' in o)) {\r\n\t\t\tthrow new Error(`${fnName}: leaf '${o.name}' is missing a value (pass value: null for a null-valued attribute)`);\r\n\t\t}\r\n\t\treturn { name: o.name, value: o.value as DigestField, salt: o.salt as string };\r\n\t}\r\n\tthrow new Error(`${fnName}: each leaf must be a [name, value, salt] array or { name, value, salt } object`);\r\n}\r\n\r\n/** Parse a JSON array of leaves. Throws on unparseable / non-array input. */\r\nfunction parseLeaves(json: string, fnName: string): SaltedLeaf[] {\r\n\tconst parsed = JSON.parse(json);\r\n\tif (!Array.isArray(parsed)) {\r\n\t\tthrow new Error(`${fnName}: expected a JSON array of leaves`);\r\n\t}\r\n\treturn parsed.map((entry) => leafFromJson(entry, fnName));\r\n}\r\n\r\n// Flags for deterministic functions (UTF8 + DETERMINISTIC)\r\nconst DETERMINISTIC_FLAGS = FunctionFlags.UTF8 | FunctionFlags.DETERMINISTIC;\r\n// Flags for non-deterministic functions (UTF8 only)\r\nconst NON_DETERMINISTIC_FLAGS = FunctionFlags.UTF8;\r\n\r\n/**\r\n * Plugin registration function\r\n * This is called by Quereus when the plugin is loaded\r\n */\r\nexport default function register(_db: Database, config: Record<string, SqlValue> = {}) {\r\n\t// Resolve the digest algorithm + output encoding ONCE, at registration, from\r\n\t// load-time config — so the per-call path never branches on them, and so the\r\n\t// digest is stable for the lifetime of the database (a precondition for\r\n\t// `replicable`: every peer that loads the plugin with the same config agrees).\r\n\tconst digestHasher = resolveHasher(configAlgorithm(config));\r\n\tconst digestEncoder = resolveOutputEncoder(configEncoding(config));\r\n\r\n\t// Register crypto functions with Quereus\r\n\tconst functions = [\r\n\t\t{\r\n\t\t\tschema: {\r\n\t\t\t\tname: 'digest',\r\n\t\t\t\tnumArgs: -1, // Variadic over data fields: digest(f1, f2, ..., fN)\r\n\t\t\t\tflags: DETERMINISTIC_FLAGS, // digest is deterministic\r\n\t\t\t\t// Bit-identical across peers/platforms — these digests are signed and persisted.\r\n\t\t\t\treplicable: true,\r\n\t\t\t\treturnType: { typeClass: 'scalar' as const, logicalType: TEXT_TYPE, nullable: false },\r\n\t\t\t\timplementation: (...fields: SqlValue[]) =>\r\n\t\t\t\t\tdigestFields(fields as DigestField[], digestHasher, digestEncoder) as string,\r\n\t\t\t},\r\n\t\t},\r\n\t\t{\r\n\t\t\tschema: {\r\n\t\t\t\tname: 'cid',\r\n\t\t\t\tnumArgs: -1, // cid(data, codec?, hash?, base?) — trailing args optional\r\n\t\t\t\tflags: DETERMINISTIC_FLAGS,\r\n\t\t\t\t// Self-describing content address; signed/persisted, so byte-identical across peers.\r\n\t\t\t\treplicable: true,\r\n\t\t\t\treturnType: { typeClass: 'scalar' as const, logicalType: TEXT_TYPE, nullable: false },\r\n\t\t\t\timplementation: (...args: SqlValue[]) => {\r\n\t\t\t\t\tconst [data, codec = 'raw', hash = 'sha2-256', base = 'base32'] = args;\r\n\t\t\t\t\treturn cid(toContentBytes(data, 'cid'), codec as Multicodec, hash as MultihashCode, base as Multibase);\r\n\t\t\t\t},\r\n\t\t\t},\r\n\t\t},\r\n\t\t{\r\n\t\t\tschema: {\r\n\t\t\t\tname: 'cid_v1',\r\n\t\t\t\tnumArgs: -1, // cid_v1(digest, hash, codec?, base?) — hash required, trailing args optional\r\n\t\t\t\tflags: DETERMINISTIC_FLAGS,\r\n\t\t\t\treplicable: true,\r\n\t\t\t\treturnType: { typeClass: 'scalar' as const, logicalType: TEXT_TYPE, nullable: false },\r\n\t\t\t\timplementation: (...args: SqlValue[]) => {\r\n\t\t\t\t\tconst [digest, hash, codec = 'raw', base = 'base32'] = args;\r\n\t\t\t\t\tif (hash == null) {\r\n\t\t\t\t\t\tthrow new Error(\"cid_v1: 'hash' argument is required (the multihash code asserting which algorithm produced the digest)\");\r\n\t\t\t\t\t}\r\n\t\t\t\t\treturn cidV1(toContentBytes(digest, 'cid_v1'), hash as MultihashCode, codec as Multicodec, base as Multibase);\r\n\t\t\t\t},\r\n\t\t\t},\r\n\t\t},\r\n\t\t{\r\n\t\t\tschema: {\r\n\t\t\t\tname: 'cid_decode',\r\n\t\t\t\tnumArgs: 1, // cid_decode(cid) -> JSON text { version, codec, hashCode, digest }\r\n\t\t\t\tflags: DETERMINISTIC_FLAGS,\r\n\t\t\t\treplicable: true,\r\n\t\t\t\treturnType: { typeClass: 'scalar' as const, logicalType: TEXT_TYPE, nullable: false },\r\n\t\t\t\timplementation: (value: SqlValue) => {\r\n\t\t\t\t\tconst parts = cidDecode(value as string);\r\n\t\t\t\t\t// JSON object (Quereus has native JSON); digest is base64url, the plugin's canonical text encoding.\r\n\t\t\t\t\treturn JSON.stringify({\r\n\t\t\t\t\t\tversion: parts.version,\r\n\t\t\t\t\t\tcodec: parts.codec,\r\n\t\t\t\t\t\thashCode: parts.hashCode,\r\n\t\t\t\t\t\tdigest: uint8ArrayToString(parts.digest, 'base64url'),\r\n\t\t\t\t\t});\r\n\t\t\t\t},\r\n\t\t\t},\r\n\t\t},\r\n\t\t{\r\n\t\t\tschema: {\r\n\t\t\t\tname: 'set_commit',\r\n\t\t\t\tnumArgs: 1, // set_commit(leaves_json) -> root over a JSON array of [name, value, salt] leaves\r\n\t\t\t\tflags: DETERMINISTIC_FLAGS,\r\n\t\t\t\t// The root is signed and persisted as a commitment, same bar as `digest`.\r\n\t\t\t\treplicable: true,\r\n\t\t\t\treturnType: { typeClass: 'scalar' as const, logicalType: TEXT_TYPE, nullable: false },\r\n\t\t\t\timplementation: (leavesJson: SqlValue) => {\r\n\t\t\t\t\tif (typeof leavesJson !== 'string') {\r\n\t\t\t\t\t\tthrow new Error('set_commit: expected a JSON TEXT array of [name, value, salt] leaves');\r\n\t\t\t\t\t}\r\n\t\t\t\t\tconst leaves = parseLeaves(leavesJson, 'set_commit');\r\n\t\t\t\t\treturn setCommit(leaves, digestHasher, digestEncoder) as string;\r\n\t\t\t\t},\r\n\t\t\t},\r\n\t\t},\r\n\t\t{\r\n\t\t\tschema: {\r\n\t\t\t\tname: 'set_verify',\r\n\t\t\t\tnumArgs: 3, // set_verify(root, disclosed_json, hidden_json) -> BOOLEAN\r\n\t\t\t\tflags: DETERMINISTIC_FLAGS, // pure, not persisted — matches `verify` (no `replicable`)\r\n\t\t\t\treturnType: { typeClass: 'scalar' as const, logicalType: BOOLEAN_TYPE, nullable: false },\r\n\t\t\t\timplementation: (root: SqlValue, disclosedJson: SqlValue, hiddenJson: SqlValue) => {\r\n\t\t\t\t\t// Forgiving contract (mirrors `verify`): any malformed input → false, never throw.\r\n\t\t\t\t\ttry {\r\n\t\t\t\t\t\tif (typeof root !== 'string' && !(root instanceof Uint8Array)) return false;\r\n\t\t\t\t\t\tif (typeof disclosedJson !== 'string' || typeof hiddenJson !== 'string') return false;\r\n\t\t\t\t\t\tconst disclosed = parseLeaves(disclosedJson, 'set_verify');\r\n\t\t\t\t\t\tconst hidden = JSON.parse(hiddenJson);\r\n\t\t\t\t\t\tif (!Array.isArray(hidden) || !hidden.every((h) => typeof h === 'string')) return false;\r\n\t\t\t\t\t\treturn setVerify(root, { disclosed, hidden: hidden as string[] }, digestHasher, digestEncoder);\r\n\t\t\t\t\t} catch {\r\n\t\t\t\t\t\treturn false;\r\n\t\t\t\t\t}\r\n\t\t\t\t},\r\n\t\t\t},\r\n\t\t},\r\n\t\t{\r\n\t\t\tschema: {\r\n\t\t\t\tname: 'sign',\r\n\t\t\t\tnumArgs: -1, // Variable arguments: data, privateKey, curve?, inputEncoding?, keyEncoding?, outputEncoding?\r\n\t\t\t\tflags: DETERMINISTIC_FLAGS, // sign is deterministic (same key + data = same signature)\r\n\t\t\t\t// Security: passing a private key as the second argument (literal or bound\r\n\t\t\t\t// parameter) is SAFE with respect to replication. The Quereus engine rebuilds\r\n\t\t\t\t// the replicated statement from evaluated column values, not from source SQL\r\n\t\t\t\t// text, so the key argument is discarded before the record is written — peers\r\n\t\t\t\t// re-execute `INSERT ... VALUES (<signature>)`, never `sign(..., key)`. What\r\n\t\t\t\t// to avoid: storing a raw private key AS a column value, since any persisted\r\n\t\t\t\t// column value is replicated. See docs/transactions.md § \"Secrets and the\r\n\t\t\t\t// replicated statement record\" and the regression guard in\r\n\t\t\t\t// quereus-plugin-optimystic/test/statement-secret-arg-redaction.spec.ts.\r\n\t\t\t\treturnType: { typeClass: 'scalar' as const, logicalType: TEXT_TYPE, nullable: false },\r\n\t\t\t\timplementation: (...args: SqlValue[]) => {\r\n\t\t\t\t\tconst [data, privateKey, curve = 'secp256k1', inputEncoding = 'base64url', keyEncoding = 'base64url', outputEncoding = 'base64url'] = args;\r\n\t\t\t\t\treturn sign(data as string, privateKey as string, curve as any, inputEncoding as any, keyEncoding as any, outputEncoding as any);\r\n\t\t\t\t},\r\n\t\t\t},\r\n\t\t},\r\n\t\t{\r\n\t\t\tschema: {\r\n\t\t\t\tname: 'verify',\r\n\t\t\t\tnumArgs: -1, // Variable arguments: data, signature, publicKey, curve?, inputEncoding?, sigEncoding?, keyEncoding?\r\n\t\t\t\tflags: DETERMINISTIC_FLAGS, // verify is deterministic\r\n\t\t\t\treturnType: { typeClass: 'scalar' as const, logicalType: BOOLEAN_TYPE, nullable: false },\r\n\t\t\t\timplementation: (...args: SqlValue[]) => {\r\n\t\t\t\t\tconst [data, signature, publicKey, curve = 'secp256k1', inputEncoding = 'base64url', sigEncoding = 'base64url', keyEncoding = 'base64url'] = args;\r\n\t\t\t\t\tconst result = verify(data as string, signature as string, publicKey as string, curve as any, inputEncoding as any, sigEncoding as any, keyEncoding as any);\r\n\t\t\t\t\treturn result;\r\n\t\t\t\t},\r\n\t\t\t},\r\n\t\t},\r\n\t\t{\r\n\t\t\tschema: {\r\n\t\t\t\tname: 'hash_mod',\r\n\t\t\t\tnumArgs: -1, // Variable arguments: data, bits, algorithm?, inputEncoding?\r\n\t\t\t\tflags: DETERMINISTIC_FLAGS, // hash_mod is deterministic\r\n\t\t\t\treturnType: { typeClass: 'scalar' as const, logicalType: INTEGER_TYPE, nullable: false },\r\n\t\t\t\timplementation: (...args: SqlValue[]) => {\r\n\t\t\t\t\tconst [data, bits, algorithm = 'sha256', inputEncoding = 'base64url'] = args;\r\n\t\t\t\t\treturn hashMod(data as string, bits as number, algorithm as any, inputEncoding as any);\r\n\t\t\t\t},\r\n\t\t\t},\r\n\t\t},\r\n\t\t{\r\n\t\t\tschema: {\r\n\t\t\t\tname: 'random_bytes',\r\n\t\t\t\tnumArgs: -1, // Variable arguments: bits?, encoding?\r\n\t\t\t\tflags: NON_DETERMINISTIC_FLAGS, // random_bytes is NOT deterministic\r\n\t\t\t\treturnType: { typeClass: 'scalar' as const, logicalType: TEXT_TYPE, nullable: false },\r\n\t\t\t\timplementation: (...args: SqlValue[]) => {\r\n\t\t\t\t\tconst [bits = 256, encoding = 'base64url'] = args;\r\n\t\t\t\t\treturn randomBytes(bits as number, encoding as any);\r\n\t\t\t\t},\r\n\t\t\t},\r\n\t\t},\r\n\t];\r\n\r\n\treturn {\r\n\t\tfunctions,\r\n\t\tvtables: [],\r\n\t\tcollations: [],\r\n\t};\r\n}\r\n\r\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/crypto.ts","../src/cid.ts","../src/sd.ts","../src/plugin.ts"],"names":["uint8ArrayFromString","uint8ArrayToString","nobleRandomBytes"],"mappings":"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","file":"plugin.js","sourcesContent":["/**\r\n * Cryptographic Functions for Quereus\r\n *\r\n * Idiomatic ES module exports with base64url as default encoding.\r\n * All functions accept and return base64url strings by default for SQL compatibility.\r\n */\r\n\r\nimport { sha256, sha512 } from '@noble/hashes/sha2.js';\r\nimport { blake3 } from '@noble/hashes/blake3.js';\r\nimport { randomBytes as nobleRandomBytes, utf8ToBytes, concatBytes } from '@noble/hashes/utils.js';\r\nimport { secp256k1 } from '@noble/curves/secp256k1.js';\r\nimport { p256 } from '@noble/curves/nist.js';\r\nimport { ed25519 } from '@noble/curves/ed25519.js';\r\nimport { hexToBytes, bytesToHex } from '@noble/curves/utils.js';\r\nimport { toString as uint8ArrayToString, fromString as uint8ArrayFromString } from 'uint8arrays';\r\n\r\n// Type definitions\r\nexport type HashAlgorithm = 'sha256' | 'sha512' | 'blake3';\r\nexport type CurveType = 'secp256k1' | 'p256' | 'ed25519';\r\nexport type Encoding = 'base64url' | 'base64' | 'hex' | 'utf8' | 'bytes';\r\n\r\n/** Encodings valid for hash *output* (no 'utf8' — a digest is not UTF-8 text). */\r\nexport type OutputEncoding = 'base64url' | 'base64' | 'hex' | 'bytes';\r\n\r\n/** A single value in a multi-field digest. Mirrors the SQL value space. */\r\nexport type DigestField =\r\n\t| string\r\n\t| number\r\n\t| bigint\r\n\t| boolean\r\n\t| Uint8Array\r\n\t| null\r\n\t| undefined\r\n\t| { readonly [key: string]: unknown }\r\n\t| readonly unknown[];\r\n\r\n/** A resolved hash function: raw bytes in, digest bytes out. */\r\nexport type DigestHasher = (input: Uint8Array) => Uint8Array;\r\n\r\n/** A resolved output encoder: digest bytes in, encoded form out. */\r\nexport type OutputEncoder = (bytes: Uint8Array) => string | Uint8Array;\r\n\r\n/**\r\n * Convert input to Uint8Array, handling various encodings\r\n */\r\nfunction toBytes(input: string | Uint8Array | null | undefined, encoding: Encoding = 'base64url'): Uint8Array {\r\n\tif (input === null || input === undefined) {\r\n\t\treturn new Uint8Array(0);\r\n\t}\r\n\r\n\tif (input instanceof Uint8Array) {\r\n\t\treturn input;\r\n\t}\r\n\r\n\tif (typeof input === 'string') {\r\n\t\tswitch (encoding) {\r\n\t\t\tcase 'base64url':\r\n\t\t\t\treturn uint8ArrayFromString(input, 'base64url');\r\n\t\t\tcase 'base64':\r\n\t\t\t\treturn uint8ArrayFromString(input, 'base64');\r\n\t\t\tcase 'hex':\r\n\t\t\t\treturn hexToBytes(input);\r\n\t\t\tcase 'utf8':\r\n\t\t\t\treturn utf8ToBytes(input);\r\n\t\t\tdefault:\r\n\t\t\t\treturn uint8ArrayFromString(input, 'base64url');\r\n\t\t}\r\n\t}\r\n\r\n\tthrow new Error('Invalid input type');\r\n}\r\n\r\n/**\r\n * Convert Uint8Array to string in specified encoding\r\n */\r\nfunction fromBytes(bytes: Uint8Array, encoding: Encoding = 'base64url'): string | Uint8Array {\r\n\tswitch (encoding) {\r\n\t\tcase 'base64url':\r\n\t\t\treturn uint8ArrayToString(bytes, 'base64url');\r\n\t\tcase 'base64':\r\n\t\t\treturn uint8ArrayToString(bytes, 'base64');\r\n\t\tcase 'hex':\r\n\t\t\treturn bytesToHex(bytes);\r\n\t\tcase 'utf8':\r\n\t\t\treturn uint8ArrayToString(bytes, 'utf8');\r\n\t\tcase 'bytes':\r\n\t\t\treturn bytes;\r\n\t\tdefault:\r\n\t\t\treturn uint8ArrayToString(bytes, 'base64url');\r\n\t}\r\n}\r\n\r\n// --- Algorithm / encoding resolution (done once, no per-call switching) --- //\r\n\r\n/** Hash algorithm → noble hasher. Keyed lookup so the digest hot path never branches. */\r\nconst HASHERS: Record<HashAlgorithm, DigestHasher> = {\r\n\tsha256,\r\n\tsha512,\r\n\tblake3,\r\n};\r\n\r\n/** Output encoding → encoder closure. */\r\nconst OUTPUT_ENCODERS: Record<OutputEncoding, OutputEncoder> = {\r\n\tbase64url: (bytes) => uint8ArrayToString(bytes, 'base64url'),\r\n\tbase64: (bytes) => uint8ArrayToString(bytes, 'base64'),\r\n\thex: (bytes) => bytesToHex(bytes),\r\n\tbytes: (bytes) => bytes,\r\n};\r\n\r\n/**\r\n * Resolve a hash algorithm name to its hasher. Throws on unknown algorithm.\r\n * Call once (e.g. at plugin registration) and capture the result so the digest\r\n * hot path performs no per-call algorithm branching.\r\n */\r\nexport function resolveHasher(algorithm: HashAlgorithm): DigestHasher {\r\n\tconst hasher = HASHERS[algorithm];\r\n\tif (!hasher) {\r\n\t\tthrow new Error(`Unsupported hash algorithm: ${algorithm}`);\r\n\t}\r\n\treturn hasher;\r\n}\r\n\r\n/**\r\n * Resolve an output encoding name to its encoder. Throws on unknown encoding.\r\n */\r\nexport function resolveOutputEncoder(encoding: OutputEncoding): OutputEncoder {\r\n\tconst encoder = OUTPUT_ENCODERS[encoding];\r\n\tif (!encoder) {\r\n\t\tthrow new Error(`Unsupported output encoding: ${encoding}`);\r\n\t}\r\n\treturn encoder;\r\n}\r\n\r\n// --- Canonical, injective multi-field encoding --- //\r\n\r\n/**\r\n * Format version for {@link encodeFields}. Prepended to every encoding so the\r\n * framing can evolve, and so a framed digest is domain-separated from a bare\r\n * hash of the same bytes. Bump only with a deliberate, breaking format change.\r\n */\r\nconst DIGEST_FORMAT_V1 = 0x01;\r\n\r\n// Per-field type tags. Distinct tags keep distinct SQL types from colliding\r\n// (e.g. INTEGER 123 vs TEXT '123' vs BOOL true).\r\n//\r\n// Note on INT vs REAL: the tag is derived from the JS value, not from SQL\r\n// affinity (a scalar function does not receive affinity). An integer-VALUED\r\n// number — including a REAL like 2.0, which reaches JS as the number 2 — is\r\n// encoded as INTEGER. So INTEGER 2 and REAL 2.0 produce the same digest. This is\r\n// replicable (every peer sees the same JS value) but not int/real-distinguishing.\r\nconst TAG_NULL = 0x00; // bare tag, no length/payload\r\nconst TAG_INT = 0x01; // payload: canonical decimal string (number-integer & bigint unified via BigInt)\r\nconst TAG_REAL = 0x02; // payload: ECMAScript Number::toString (non-integer numbers only)\r\nconst TAG_TEXT = 0x03; // payload: UTF-8 bytes\r\nconst TAG_BOOL = 0x04; // payload: single 0x00/0x01 byte\r\nconst TAG_BLOB = 0x05; // payload: raw bytes\r\nconst TAG_JSON = 0x06; // payload: UTF-8 of key-sorted canonical JSON\r\n\r\n/** Append an unsigned LEB128 varint (safe for lengths up to MAX_SAFE_INTEGER). */\r\nfunction writeVarint(out: number[], value: number): void {\r\n\tif (!Number.isInteger(value) || value < 0) {\r\n\t\tthrow new Error(`varint expects a non-negative integer, got ${value}`);\r\n\t}\r\n\tlet v = value;\r\n\twhile (v >= 0x80) {\r\n\t\tout.push((v & 0x7f) | 0x80);\r\n\t\tv = Math.floor(v / 128);\r\n\t}\r\n\tout.push(v);\r\n}\r\n\r\n/** tag ‖ varint(len) ‖ payload */\r\nfunction framed(tag: number, payload: Uint8Array): Uint8Array {\r\n\tconst header: number[] = [tag];\r\n\twriteVarint(header, payload.length);\r\n\treturn concatBytes(Uint8Array.from(header), payload);\r\n}\r\n\r\n/**\r\n * Strict, deterministic JSON canonicalization for a native object/array field:\r\n * object keys recursively sorted, no incidental whitespace. Unlike `JSON.stringify`,\r\n * it THROWS rather than silently collapsing non-JSON inputs (`undefined`, non-finite\r\n * numbers, `bigint`, non-plain objects like `Date`/`Map`) — silent collapse would\r\n * break injectivity (`{a:undefined}` vs `{}`, `NaN` vs `null`, `new Date(0)` vs `{}`).\r\n */\r\nfunction canonicalJson(value: unknown): string {\r\n\tif (value === null) return 'null';\r\n\tconst t = typeof value;\r\n\tif (t === 'string') return JSON.stringify(value);\r\n\tif (t === 'boolean') return value ? 'true' : 'false';\r\n\tif (t === 'number') {\r\n\t\tif (!Number.isFinite(value)) {\r\n\t\t\tthrow new Error('digest: cannot encode a non-finite number inside a JSON field');\r\n\t\t}\r\n\t\treturn JSON.stringify(value) as string; // deterministic Number::toString\r\n\t}\r\n\tif (t === 'bigint') {\r\n\t\tthrow new Error('digest: bigint is not representable inside a JSON field');\r\n\t}\r\n\tif (Array.isArray(value)) {\r\n\t\treturn `[${value.map((el) => {\r\n\t\t\tif (el === undefined) {\r\n\t\t\t\tthrow new Error('digest: undefined / sparse element inside a JSON field');\r\n\t\t\t}\r\n\t\t\treturn canonicalJson(el);\r\n\t\t}).join(',')}]`;\r\n\t}\r\n\tif (t === 'object') {\r\n\t\tconst proto = Object.getPrototypeOf(value);\r\n\t\tif (proto !== Object.prototype && proto !== null) {\r\n\t\t\tthrow new Error('digest: only plain objects are allowed inside a JSON field');\r\n\t\t}\r\n\t\tconst obj = value as Record<string, unknown>;\r\n\t\tconst keys = Object.keys(obj).sort();\r\n\t\treturn `{${keys.map((k) => {\r\n\t\t\tif (obj[k] === undefined) {\r\n\t\t\t\tthrow new Error(`digest: undefined value for JSON key '${k}'`);\r\n\t\t\t}\r\n\t\t\treturn `${JSON.stringify(k)}:${canonicalJson(obj[k])}`;\r\n\t\t}).join(',')}}`;\r\n\t}\r\n\tthrow new Error(`digest: unsupported value of type '${t}' inside a JSON field`);\r\n}\r\n\r\n/** Encode one field as tag (‖ length ‖ payload). NULL/undefined is a bare tag. */\r\nfunction encodeField(field: DigestField): Uint8Array {\r\n\tif (field === null || field === undefined) {\r\n\t\treturn Uint8Array.of(TAG_NULL);\r\n\t}\r\n\tswitch (typeof field) {\r\n\t\tcase 'boolean':\r\n\t\t\treturn Uint8Array.of(TAG_BOOL, field ? 1 : 0);\r\n\t\tcase 'bigint':\r\n\t\t\treturn framed(TAG_INT, utf8ToBytes(field.toString()));\r\n\t\tcase 'number':\r\n\t\t\tif (!Number.isFinite(field)) {\r\n\t\t\t\tthrow new Error('digest: cannot encode a non-finite number');\r\n\t\t\t}\r\n\t\t\t// Integer-valued numbers go through BigInt so they encode identically to\r\n\t\t\t// the equal-valued bigint (e.g. 1e21 → full digits, not \"1e+21\").\r\n\t\t\treturn Number.isInteger(field)\r\n\t\t\t\t? framed(TAG_INT, utf8ToBytes(BigInt(field).toString()))\r\n\t\t\t\t: framed(TAG_REAL, utf8ToBytes(field.toString()));\r\n\t\tcase 'string':\r\n\t\t\treturn framed(TAG_TEXT, utf8ToBytes(field));\r\n\t\tcase 'object':\r\n\t\t\tif (field instanceof Uint8Array) {\r\n\t\t\t\treturn framed(TAG_BLOB, field);\r\n\t\t\t}\r\n\t\t\treturn framed(TAG_JSON, utf8ToBytes(canonicalJson(field)));\r\n\t\tdefault:\r\n\t\t\tthrow new Error(`digest: unsupported field type '${typeof field}'`);\r\n\t}\r\n}\r\n\r\n/**\r\n * Canonically encode an ordered tuple of fields into bytes such that distinct\r\n * tuples never collide (injective framing).\r\n *\r\n * Layout: `version ‖ field*` where each field is `tag ‖ varint(len) ‖ payload`\r\n * (NULL is a bare tag). Properties:\r\n * - order-preserving and arity-safe (self-delimiting fields → uniquely decodable),\r\n * - NULL distinguishable from empty string,\r\n * - type distinguishable (INTEGER 123 ≠ TEXT '123' ≠ BOOL true ≠ BLOB),\r\n * - delimiter-safe (a separator inside a string is just payload under its length).\r\n *\r\n * Replicability notes:\r\n * - Integer `number` and `bigint` of equal value encode identically (both via\r\n * `BigInt(...).toString()`); a non-integer REAL uses ECMAScript `Number::toString`\r\n * (deterministic across JS engines, but not guaranteed across other languages).\r\n * - INT vs REAL is derived from the JS value, not SQL affinity: an integer-valued\r\n * REAL (e.g. 2.0 → number 2) encodes as INTEGER, so INTEGER 2 and REAL 2.0 collide.\r\n * - A native JSON object/array field must contain only valid JSON (no `undefined`,\r\n * non-finite numbers, `bigint`, or non-plain objects) — otherwise it throws.\r\n */\r\nexport function encodeFields(fields: readonly DigestField[]): Uint8Array {\r\n\tconst chunks: Uint8Array[] = [Uint8Array.of(DIGEST_FORMAT_V1)];\r\n\tfor (const field of fields) {\r\n\t\tchunks.push(encodeField(field));\r\n\t}\r\n\treturn concatBytes(...chunks);\r\n}\r\n\r\n/**\r\n * Low-level multi-field digest: canonically encode the fields, then hash and\r\n * encode with the supplied (pre-resolved) hasher/encoder. No per-call branching\r\n * on algorithm or encoding — resolve once via {@link resolveHasher} /\r\n * {@link resolveOutputEncoder} and reuse.\r\n */\r\nexport function digestFields(\r\n\tfields: readonly DigestField[],\r\n\thasher: DigestHasher,\r\n\tencode: OutputEncoder\r\n): string | Uint8Array {\r\n\treturn encode(hasher(encodeFields(fields)));\r\n}\r\n\r\n/**\r\n * Compute an injective digest over an ordered tuple of fields.\r\n *\r\n * @param fields - Ordered tuple of values to hash (any SQL value type)\r\n * @param algorithm - Hash algorithm (default: 'sha256')\r\n * @param encoding - Output encoding (default: 'base64url')\r\n * @returns Hash digest in the specified encoding\r\n *\r\n * @example\r\n * ```typescript\r\n * // Hash a tuple of fields — distinct tuples never collide\r\n * const h = digest(['alice', 42, null, true]);\r\n *\r\n * // Pick algorithm / output encoding\r\n * const h512 = digest(['a', 'b'], 'sha512', 'hex');\r\n * ```\r\n *\r\n * Note: this is a *framed* digest, not a bare hash of raw bytes —\r\n * `digest(['hello'])` is not `sha256(\"hello\")`. Use `hashMod` for sharding a\r\n * single value.\r\n */\r\nexport function digest(\r\n\tfields: readonly DigestField[],\r\n\talgorithm: HashAlgorithm = 'sha256',\r\n\tencoding: OutputEncoding = 'base64url'\r\n): string | Uint8Array {\r\n\tif (!Array.isArray(fields)) {\r\n\t\tthrow new Error(\r\n\t\t\t`digest(fields, algorithm?, encoding?): 'fields' must be an array of values. ` +\r\n\t\t\t`The digest API changed in v0.14: it is now variadic/injective over fields, ` +\r\n\t\t\t`the per-call inputEncoding was removed, and algorithm + output encoding are bound at plugin load time. ` +\r\n\t\t\t`Migrate digest(value, algo, inputEncoding, outputEncoding) → digest([value], algo, outputEncoding) — ` +\r\n\t\t\t`note the result is now a *framed* digest, not a bare hash of the bytes.`\r\n\t\t);\r\n\t}\r\n\treturn digestFields(fields, resolveHasher(algorithm), resolveOutputEncoder(encoding));\r\n}\r\n\r\n/**\r\n * Hash data and return modulo of specified bit length\r\n * Useful for generating fixed-size hash values (e.g., 16-bit, 32-bit)\r\n *\r\n * @param data - Data to hash\r\n * @param bits - Number of bits for the result (e.g., 16 for 16-bit hash)\r\n * @param algorithm - Hash algorithm (default: 'sha256')\r\n * @param inputEncoding - Encoding of input string (default: 'base64url')\r\n * @returns Integer hash value modulo 2^bits\r\n *\r\n * @example\r\n * ```typescript\r\n * // Get 16-bit hash (0-65535)\r\n * const hash16 = hashMod('hello', 16, 'sha256', 'utf8');\r\n *\r\n * // Get 32-bit hash\r\n * const hash32 = hashMod('world', 32, 'sha256', 'utf8');\r\n * ```\r\n */\r\nexport function hashMod(\r\n\tdata: string | Uint8Array,\r\n\tbits: number,\r\n\talgorithm: HashAlgorithm = 'sha256',\r\n\tinputEncoding: Encoding = 'base64url'\r\n): number {\r\n\tif (bits <= 0 || bits > 53) {\r\n\t\tthrow new Error('Bits must be between 1 and 53 (JavaScript safe integer limit)');\r\n\t}\r\n\r\n\t// Single-blob hash for sharding (not the field-framed digest).\r\n\tconst hashBytes = resolveHasher(algorithm)(toBytes(data, inputEncoding));\r\n\r\n\t// Take first 8 bytes and convert to number\r\n\tconst view = new DataView(hashBytes.buffer, hashBytes.byteOffset, Math.min(8, hashBytes.length));\r\n\tconst fullHash = view.getBigUint64(0, false); // big-endian\r\n\r\n\t// Modulo by 2^bits\r\n\tconst modulus = BigInt(2) ** BigInt(bits);\r\n\tconst result = fullHash % modulus;\r\n\r\n\treturn Number(result);\r\n}\r\n\r\n/**\r\n * Sign data with a private key\r\n *\r\n * @param data - Data to sign (typically a hash)\r\n * @param privateKey - Private key (base64url string or Uint8Array)\r\n * @param curve - Elliptic curve (default: 'secp256k1')\r\n * @param inputEncoding - Encoding of data input (default: 'base64url')\r\n * @param keyEncoding - Encoding of private key (default: 'base64url')\r\n * @param outputEncoding - Encoding of signature output (default: 'base64url')\r\n * @returns Signature in specified encoding\r\n *\r\n * @example\r\n * ```typescript\r\n * // Sign a hash with secp256k1\r\n * const sig = sign(hashData, privateKey);\r\n *\r\n * // Sign with Ed25519\r\n * const sig2 = sign(hashData, privateKey, 'ed25519');\r\n * ```\r\n */\r\nexport function sign(\r\n\tdata: string | Uint8Array,\r\n\tprivateKey: string | Uint8Array,\r\n\tcurve: CurveType = 'secp256k1',\r\n\tinputEncoding: Encoding = 'base64url',\r\n\tkeyEncoding: Encoding = 'base64url',\r\n\toutputEncoding: Encoding = 'base64url'\r\n): string | Uint8Array {\r\n\tconst dataBytes = toBytes(data, inputEncoding);\r\n\tconst keyBytes = toBytes(privateKey, keyEncoding);\r\n\r\n\tlet sigBytes: Uint8Array;\r\n\r\n\tswitch (curve) {\r\n\t\tcase 'secp256k1':\r\n\t\t\tsigBytes = secp256k1.sign(dataBytes, keyBytes, { lowS: true });\r\n\t\t\tbreak;\r\n\t\tcase 'p256':\r\n\t\t\tsigBytes = p256.sign(dataBytes, keyBytes, { lowS: true });\r\n\t\t\tbreak;\r\n\t\tcase 'ed25519':\r\n\t\t\tsigBytes = ed25519.sign(dataBytes, keyBytes);\r\n\t\t\tbreak;\r\n\t\tdefault:\r\n\t\t\tthrow new Error(`Unsupported curve: ${curve}`);\r\n\t}\r\n\r\n\treturn fromBytes(sigBytes, outputEncoding);\r\n}\r\n\r\n/**\r\n * Verify a signature\r\n *\r\n * @param data - Data that was signed\r\n * @param signature - Signature to verify\r\n * @param publicKey - Public key\r\n * @param curve - Elliptic curve (default: 'secp256k1')\r\n * @param inputEncoding - Encoding of data input (default: 'base64url')\r\n * @param sigEncoding - Encoding of signature (default: 'base64url')\r\n * @param keyEncoding - Encoding of public key (default: 'base64url')\r\n * @returns true if signature is valid, false otherwise\r\n *\r\n * @example\r\n * ```typescript\r\n * // Verify a signature\r\n * const isValid = verify(hashData, signature, publicKey);\r\n *\r\n * // Verify with Ed25519\r\n * const isValid2 = verify(hashData, signature, publicKey, 'ed25519');\r\n * ```\r\n */\r\nexport function verify(\r\n\tdata: string | Uint8Array,\r\n\tsignature: string | Uint8Array,\r\n\tpublicKey: string | Uint8Array,\r\n\tcurve: CurveType = 'secp256k1',\r\n\tinputEncoding: Encoding = 'base64url',\r\n\tsigEncoding: Encoding = 'base64url',\r\n\tkeyEncoding: Encoding = 'base64url'\r\n): boolean {\r\n\ttry {\r\n\t\tconst dataBytes = toBytes(data, inputEncoding);\r\n\t\tconst sigBytes = toBytes(signature, sigEncoding);\r\n\t\tconst keyBytes = toBytes(publicKey, keyEncoding);\r\n\r\n\t\tswitch (curve) {\r\n\t\t\tcase 'secp256k1': {\r\n\t\t\t\treturn secp256k1.verify(sigBytes, dataBytes, keyBytes);\r\n\t\t\t}\r\n\t\t\tcase 'p256': {\r\n\t\t\t\treturn p256.verify(sigBytes, dataBytes, keyBytes);\r\n\t\t\t}\r\n\t\t\tcase 'ed25519': {\r\n\t\t\t\treturn ed25519.verify(sigBytes, dataBytes, keyBytes);\r\n\t\t\t}\r\n\t\t\tdefault:\r\n\t\t\t\tthrow new Error(`Unsupported curve: ${curve}`);\r\n\t\t}\r\n\t} catch {\r\n\t\treturn false;\r\n\t}\r\n}\r\n\r\n/**\r\n * Generate cryptographically secure random bytes\r\n *\r\n * @param bits - Number of bits to generate (default: 256)\r\n * @param encoding - Output encoding (default: 'base64url')\r\n * @returns Random bytes in the specified encoding\r\n */\r\nexport function randomBytes(bits: number = 256, encoding: Encoding = 'base64url'): string | Uint8Array {\r\n\tconst bytes = Math.ceil(bits / 8);\r\n\tconst randomBytesArray = nobleRandomBytes(bytes);\r\n\treturn fromBytes(randomBytesArray, encoding);\r\n}\r\n\r\n/**\r\n * Generate a random private key\r\n */\r\nexport function generatePrivateKey(curve: CurveType = 'secp256k1', encoding: Encoding = 'base64url'): string | Uint8Array {\r\n\tlet keyBytes: Uint8Array;\r\n\r\n\tswitch (curve) {\r\n\t\tcase 'secp256k1':\r\n\t\t\tkeyBytes = secp256k1.utils.randomSecretKey();\r\n\t\t\tbreak;\r\n\t\tcase 'p256':\r\n\t\t\tkeyBytes = p256.utils.randomSecretKey();\r\n\t\t\tbreak;\r\n\t\tcase 'ed25519':\r\n\t\t\tkeyBytes = ed25519.utils.randomSecretKey();\r\n\t\t\tbreak;\r\n\t\tdefault:\r\n\t\t\tthrow new Error(`Unsupported curve: ${curve}`);\r\n\t}\r\n\r\n\treturn fromBytes(keyBytes, encoding);\r\n}\r\n\r\n/**\r\n * Get public key from private key\r\n */\r\nexport function getPublicKey(\r\n\tprivateKey: string | Uint8Array,\r\n\tcurve: CurveType = 'secp256k1',\r\n\tkeyEncoding: Encoding = 'base64url',\r\n\toutputEncoding: Encoding = 'base64url'\r\n): string | Uint8Array {\r\n\tconst keyBytes = toBytes(privateKey, keyEncoding);\r\n\r\n\tlet pubBytes: Uint8Array;\r\n\r\n\tswitch (curve) {\r\n\t\tcase 'secp256k1':\r\n\t\t\tpubBytes = secp256k1.getPublicKey(keyBytes);\r\n\t\t\tbreak;\r\n\t\tcase 'p256':\r\n\t\t\tpubBytes = p256.getPublicKey(keyBytes);\r\n\t\t\tbreak;\r\n\t\tcase 'ed25519':\r\n\t\t\tpubBytes = ed25519.getPublicKey(keyBytes);\r\n\t\t\tbreak;\r\n\t\tdefault:\r\n\t\t\tthrow new Error(`Unsupported curve: ${curve}`);\r\n\t}\r\n\r\n\treturn fromBytes(pubBytes, outputEncoding);\r\n}\r\n\r\n","/**\r\n * Self-describing content identifiers (CIDv1) for Quereus.\r\n *\r\n * Where {@link ./crypto.ts | digest} emits a *bare* hash (raw digest bytes in\r\n * some text encoding), this module emits an interoperable, self-describing\r\n * CIDv1:\r\n *\r\n * ```\r\n * CIDv1 = multibase( version ‖ multicodec(content-type) ‖ multihash )\r\n * multihash = hashFnCode ‖ digestLength ‖ digestBytes\r\n * ```\r\n *\r\n * The value carries its own multibase, multicodec (content type), and multihash\r\n * (hash algorithm + length), so a consumer can decode it without out-of-band\r\n * knowledge, and an algorithm migration (e.g. sha2-256 → another hash) is\r\n * unambiguous because the hash code is recorded *in the value*.\r\n *\r\n * All framing/parsing comes from the audited `multiformats` library — there is\r\n * no bespoke byte-pushing here. The actual hashing reuses the same synchronous,\r\n * cross-platform `@noble/hashes` functions the rest of the plugin uses (via\r\n * {@link resolveHasher}), so the output is byte-identical to the CID an external\r\n * content-addressed store (IPFS/IPLD) computes for the same bytes:\r\n * `cid(utf8('hello world'))` === `bafkreifzjut3te2nhyekklss27nh3k72ysco7y32koao5eei66wof36n5e`.\r\n */\r\n\r\nimport { CID } from 'multiformats/cid';\r\nimport * as Digest from 'multiformats/hashes/digest';\r\nimport { base32 } from 'multiformats/bases/base32';\r\nimport { base58btc } from 'multiformats/bases/base58';\r\nimport { base64url } from 'multiformats/bases/base64';\r\nimport { base16 } from 'multiformats/bases/base16';\r\nimport type { MultibaseEncoder, MultibaseDecoder } from 'multiformats/bases/interface';\r\nimport { resolveHasher, type HashAlgorithm } from './crypto.js';\r\n\r\n/** Content-type multicodec selectable for the CID. Extensible. */\r\nexport type Multicodec = 'raw' | 'dag-cbor';\r\n/** Hash-algorithm multihash code selectable for the CID. */\r\nexport type MultihashCode = 'sha2-256' | 'sha2-512' | 'blake3';\r\n/** Multibase the CID string is rendered in. */\r\nexport type Multibase = 'base32' | 'base58btc' | 'base64url' | 'base16';\r\n\r\n/** Parsed parts of a CIDv1 (or CIDv0), as returned by {@link cidDecode}. */\r\nexport interface CidParts {\r\n\t/** CID version (1 for the values this module produces; 0 for legacy CIDv0). */\r\n\treadonly version: number;\r\n\t/** Content-type codec name when recognized, else the raw multicodec number. */\r\n\treadonly codec: Multicodec | number;\r\n\t/** Hash-algorithm code name when recognized, else the raw multihash number. */\r\n\treadonly hashCode: MultihashCode | number;\r\n\t/** Raw digest bytes (without the multihash code/length prefix). */\r\n\treadonly digest: Uint8Array;\r\n}\r\n\r\n// --- Multiformats code tables (see multiformats/multicodec table.csv) --- //\r\n\r\n/** Content-type name → multicodec code. */\r\nconst MULTICODEC_CODES: Record<Multicodec, number> = {\r\n\t'raw': 0x55,\r\n\t'dag-cbor': 0x71,\r\n};\r\n\r\n/** Hash name → multihash code. */\r\nconst MULTIHASH_CODES: Record<MultihashCode, number> = {\r\n\t'sha2-256': 0x12,\r\n\t'sha2-512': 0x13,\r\n\t'blake3': 0x1e,\r\n};\r\n\r\n/** Multihash code → the synchronous `@noble/hashes` algorithm that produces it. */\r\nconst MULTIHASH_TO_ALGORITHM: Record<MultihashCode, HashAlgorithm> = {\r\n\t'sha2-256': 'sha256',\r\n\t'sha2-512': 'sha512',\r\n\t'blake3': 'blake3',\r\n};\r\n\r\n/**\r\n * Multihash code → exact digest length in bytes. A CID is replicable only if its\r\n * digest length is fixed, so blake3 (which is variable-length in general) is\r\n * pinned to 32 bytes here, matching the plugin's blake3 output and sha2-256.\r\n */\r\nconst MULTIHASH_DIGEST_LENGTHS: Record<MultihashCode, number> = {\r\n\t'sha2-256': 32,\r\n\t'sha2-512': 64,\r\n\t'blake3': 32,\r\n};\r\n\r\n/** Reverse lookups for {@link cidDecode}: code number → friendly name. */\r\nconst MULTICODEC_NAMES: ReadonlyMap<number, Multicodec> = new Map(\r\n\t(Object.entries(MULTICODEC_CODES) as [Multicodec, number][]).map(([name, code]) => [code, name])\r\n);\r\nconst MULTIHASH_NAMES: ReadonlyMap<number, MultihashCode> = new Map(\r\n\t(Object.entries(MULTIHASH_CODES) as [MultihashCode, number][]).map(([name, code]) => [code, name])\r\n);\r\n\r\n/** Multibase name → its multiformats encoder. */\r\nconst MULTIBASE_ENCODERS: Record<Multibase, MultibaseEncoder<string>> = {\r\n\t'base32': base32,\r\n\t'base58btc': base58btc,\r\n\t'base64url': base64url,\r\n\t'base16': base16,\r\n};\r\n\r\n/**\r\n * Combined decoder that dispatches on the multibase prefix character, so\r\n * {@link cidDecode} accepts a CID in any of the supported bases without the\r\n * caller having to declare which.\r\n */\r\nconst MULTIBASE_DECODER: MultibaseDecoder<string> = base32.decoder\r\n\t.or(base58btc.decoder)\r\n\t.or(base64url.decoder)\r\n\t.or(base16.decoder);\r\n\r\nfunction resolveCodecCode(codec: Multicodec): number {\r\n\tconst code = MULTICODEC_CODES[codec];\r\n\tif (code === undefined) {\r\n\t\tthrow new Error(`cid: unsupported multicodec '${codec}' (expected one of ${Object.keys(MULTICODEC_CODES).join(', ')})`);\r\n\t}\r\n\treturn code;\r\n}\r\n\r\nfunction resolveBaseEncoder(base: Multibase): MultibaseEncoder<string> {\r\n\tconst encoder = MULTIBASE_ENCODERS[base];\r\n\tif (!encoder) {\r\n\t\tthrow new Error(`cid: unsupported multibase '${base}' (expected one of ${Object.keys(MULTIBASE_ENCODERS).join(', ')})`);\r\n\t}\r\n\treturn encoder;\r\n}\r\n\r\n/**\r\n * Frame an **already-computed** digest as a CIDv1 string. The caller asserts\r\n * which `hash` produced the digest; the digest length is validated against that\r\n * hash so a mismatched assertion is rejected rather than silently mis-framed.\r\n *\r\n * Use this to turn an existing field-tuple digest into a CID without re-hashing,\r\n * e.g. `cidV1(digest(fields, 'sha256', 'bytes'), 'sha2-256')`.\r\n *\r\n * @param digest - Raw digest bytes (no multihash prefix).\r\n * @param hash - The multihash code asserting which algorithm produced `digest`.\r\n * @param codec - Content-type multicodec (default `'raw'`).\r\n * @param base - Multibase to render in (default `'base32'`, the IPFS canonical).\r\n */\r\nexport function cidV1(\r\n\tdigest: Uint8Array,\r\n\thash: MultihashCode,\r\n\tcodec: Multicodec = 'raw',\r\n\tbase: Multibase = 'base32'\r\n): string {\r\n\tconst hashCode = MULTIHASH_CODES[hash];\r\n\tif (hashCode === undefined) {\r\n\t\tthrow new Error(`cid: unsupported multihash code '${hash}' (expected one of ${Object.keys(MULTIHASH_CODES).join(', ')})`);\r\n\t}\r\n\tconst expectedLength = MULTIHASH_DIGEST_LENGTHS[hash];\r\n\tif (digest.length !== expectedLength) {\r\n\t\tthrow new Error(`cid: digest length ${digest.length} does not match asserted hash '${hash}' (expected ${expectedLength} bytes)`);\r\n\t}\r\n\tconst codecCode = resolveCodecCode(codec);\r\n\tconst encoder = resolveBaseEncoder(base);\r\n\tconst multihash = Digest.create(hashCode, digest);\r\n\treturn CID.createV1(codecCode, multihash).toString(encoder);\r\n}\r\n\r\n/**\r\n * Hash `data`, wrap the digest as a multihash, frame it as a CIDv1, and encode\r\n * in `base`. The result is the same interoperable address an IPFS/IPLD store\r\n * computes for the same bytes (for the matching codec/hash).\r\n *\r\n * @param data - The content bytes to address.\r\n * @param codec - Content-type multicodec (default `'raw'`).\r\n * @param hash - Hash algorithm (default `'sha2-256'`).\r\n * @param base - Multibase to render in (default `'base32'`, the IPFS canonical).\r\n */\r\nexport function cid(\r\n\tdata: Uint8Array,\r\n\tcodec: Multicodec = 'raw',\r\n\thash: MultihashCode = 'sha2-256',\r\n\tbase: Multibase = 'base32'\r\n): string {\r\n\tconst algorithm = MULTIHASH_TO_ALGORITHM[hash];\r\n\tif (!algorithm) {\r\n\t\tthrow new Error(`cid: unsupported multihash code '${hash}' (expected one of ${Object.keys(MULTIHASH_CODES).join(', ')})`);\r\n\t}\r\n\tconst digest = resolveHasher(algorithm)(data);\r\n\treturn cidV1(digest, hash, codec, base);\r\n}\r\n\r\n/**\r\n * Parse a CID string back into its parts, for schema validation and migration.\r\n * Recognized codec/hash codes are returned as friendly names; unrecognized ones\r\n * as their raw numbers. Throws cleanly on malformed input (delegated to\r\n * `multiformats`), never silently mis-framing.\r\n */\r\nexport function cidDecode(value: string): CidParts {\r\n\tconst parsed = CID.parse(value, MULTIBASE_DECODER);\r\n\treturn {\r\n\t\tversion: parsed.version,\r\n\t\tcodec: MULTICODEC_NAMES.get(parsed.code) ?? parsed.code,\r\n\t\thashCode: MULTIHASH_NAMES.get(parsed.multihash.code) ?? parsed.multihash.code,\r\n\t\tdigest: parsed.multihash.digest,\r\n\t};\r\n}\r\n","/**\r\n * Salted-leaf SET COMMITMENT for per-attribute selective disclosure.\r\n *\r\n * An authority commits to a whole set of attributes as a single root value (which\r\n * it signs / persists), then later reveals only a chosen *subset* to a recipient —\r\n * with a proof that the revealed values are genuinely the committed ones — without\r\n * leaking the values of the withheld attributes. A flat `digest(whole set)` cannot\r\n * do this (verifying one field needs the whole pre-image, so it is all-or-nothing);\r\n * this construction supports *partial opening*.\r\n *\r\n * ## Construction (flat salted-leaf set commitment, NOT a Merkle tree)\r\n *\r\n * Each disclosable attribute is a salted leaf, and the commitment (root) is the\r\n * digest of all leaf digests in canonical order:\r\n *\r\n * ```\r\n * leafDigest = digest([SD_LEAF_DOMAIN_V1, name, value, salt]) // raw digest bytes\r\n * root = digest([SD_SET_DOMAIN_V1, sortedLeaf_0, sortedLeaf_1, ...])\r\n * ```\r\n *\r\n * Both layers compose on the existing canonical {@link encodeFields} framing\r\n * (injective, type-tagged, length-prefixed, replicable) — the same layering the CID\r\n * work uses — so a *generic* salted-set primitive is simultaneously reusable and\r\n * fully DB-enforceable. This is the same shape the IETF SD-JWT standard settled on\r\n * (flat salted hashes, not a tree); we are NOT wire-compatible with SD-JWT (we reuse\r\n * Optimystic's own `encodeFields` framing for cross-peer replicability) — SD-JWT is\r\n * cited only as conceptual precedent that the smaller construction is the right one.\r\n *\r\n * Voter selective-disclosure field sets are small (a handful to a few dozen fields),\r\n * so a tree's only advantage — O(log n) proof size — is marginal, while a tree drags\r\n * in real footguns we would have to hand-roll and pin (arity, odd-node handling /\r\n * the CVE-2012-2459 duplicate-leaf forgery class, leaf-vs-internal domain separation,\r\n * and a separate audit-path proof format). A flat construction avoids all of them.\r\n *\r\n * ## Why these specific choices\r\n *\r\n * - **`name` is hashed into the leaf** so a disclosed `(value, salt)` proof cannot be\r\n * replayed against a different attribute slot (e.g. presenting an `over18=true`\r\n * proof as the `citizen` field). The binding is free given `encodeFields` framing.\r\n * - **`salt` is per-leaf and mandatory** — low-entropy attributes (DOB, booleans, ZIP)\r\n * are brute-forceable from a bare hash, and independent salts also defeat cross-\r\n * registrant equality correlation. Salts come from `random_bytes` (≥128 bits).\r\n * - **Canonical order is by raw leaf-digest bytes (lexicographic), and this is FORCED,\r\n * not a preference.** In a disclosure the verifier learns the *names* of only the\r\n * disclosed leaves; the withheld leaves arrive as opaque digests with no name. So the\r\n * verifier can re-derive the root only if the ordering key is something it holds for\r\n * *every* leaf — the leaf digest itself. Sorting by name would be unverifiable for\r\n * hidden leaves. Do NOT \"tidy\" this into a name sort.\r\n * - Sort is over **raw digest bytes**, never over encoded strings — an encoding-\r\n * dependent ordering would break cross-peer agreement. Output encoding applies only\r\n * to the final root.\r\n *\r\n * Because leaf and root reuse `encodeFields`, a future `DIGEST_FORMAT_V1` bump changes\r\n * `setCommit` output too; this coupling is intentional (one canonical framing).\r\n */\r\n\r\nimport { fromString as uint8ArrayFromString, toString as uint8ArrayToString } from 'uint8arrays';\r\nimport {\r\n\tencodeFields,\r\n\tresolveHasher,\r\n\tresolveOutputEncoder,\r\n\ttype DigestField,\r\n\ttype DigestHasher,\r\n\ttype OutputEncoder,\r\n} from './crypto.js';\r\n\r\n/**\r\n * Fixed domain-separation constants — the leading string field of each layer's\r\n * {@link encodeFields} tuple. They are pinned EXACTLY like `DIGEST_FORMAT_V1`:\r\n *\r\n * - the two strings MUST be distinct, so a leaf hash can never equal a root hash;\r\n * - neither may change without a deliberate, breaking version bump — which would\r\n * change every committed root and every signature taken over it.\r\n *\r\n * Do not \"tidy\" or shorten these.\r\n */\r\nconst SD_LEAF_DOMAIN_V1 = 'optimystic/sd-leaf/v1';\r\nconst SD_SET_DOMAIN_V1 = 'optimystic/sd-set/v1';\r\n\r\n/** Hidden leaf digests travel as base64url text — the plugin's canonical text encoding. */\r\nconst HIDDEN_ENCODING = 'base64url';\r\n\r\n/** One disclosable attribute. `value` spans the SQL value space ({@link DigestField}). */\r\nexport interface SaltedLeaf {\r\n\treadonly name: string;\r\n\treadonly value: DigestField;\r\n\t/** base64url text (e.g. from `random_bytes`) or raw bytes. Mandatory, non-empty. */\r\n\treadonly salt: string | Uint8Array;\r\n}\r\n\r\n/** A disclosure payload sent to a recipient. */\r\nexport interface SetDisclosure {\r\n\t/** The opened `(name, value, salt)` triples. */\r\n\treadonly disclosed: readonly SaltedLeaf[];\r\n\t/** Opaque leaf digests (base64url) of the withheld leaves — no name, no value, no salt. */\r\n\treadonly hidden: readonly string[];\r\n}\r\n\r\n// --- internal helpers --- //\r\n\r\n/** Lexicographic compare of two byte arrays (the canonical leaf ordering key). */\r\nfunction compareBytes(a: Uint8Array, b: Uint8Array): number {\r\n\tconst len = Math.min(a.length, b.length);\r\n\tfor (let i = 0; i < len; i++) {\r\n\t\tconst d = a[i]! - b[i]!;\r\n\t\tif (d !== 0) return d;\r\n\t}\r\n\treturn a.length - b.length;\r\n}\r\n\r\n/** Constant-shape byte equality (length first, then content). */\r\nfunction bytesEqual(a: Uint8Array, b: Uint8Array): boolean {\r\n\tif (a.length !== b.length) return false;\r\n\tfor (let i = 0; i < a.length; i++) {\r\n\t\tif (a[i] !== b[i]) return false;\r\n\t}\r\n\treturn true;\r\n}\r\n\r\n/**\r\n * Normalize a leaf's salt to raw bytes — a base64url string (the form `random_bytes`\r\n * returns) decodes to bytes, raw bytes pass through — so the two representations of the\r\n * same salt commit identically. THROWS on a missing or empty salt (unsalted leaves are\r\n * brute-forceable, an invalid state we make impossible).\r\n */\r\nfunction requireSaltBytes(leaf: SaltedLeaf): Uint8Array {\r\n\tconst { salt } = leaf;\r\n\tif (salt == null) {\r\n\t\tthrow new Error(`set commitment: leaf '${leaf.name}' is missing a salt (an unsalted leaf is brute-forceable)`);\r\n\t}\r\n\tconst bytes = salt instanceof Uint8Array ? salt : uint8ArrayFromString(salt, HIDDEN_ENCODING);\r\n\tif (bytes.length === 0) {\r\n\t\tthrow new Error(`set commitment: leaf '${leaf.name}' has an empty salt (an unsalted leaf is brute-forceable)`);\r\n\t}\r\n\treturn bytes;\r\n}\r\n\r\n/**\r\n * THROW on a duplicate `name`. Two leaves with the same name would let a holder\r\n * selectively present whichever value suits them; the authority side (which holds all\r\n * names) is the only place uniqueness can be enforced — the verifier never sees the\r\n * hidden names — so the primitive must fail-fast.\r\n */\r\nfunction assertUniqueNames(leaves: readonly SaltedLeaf[]): void {\r\n\tconst seen = new Set<string>();\r\n\tfor (const leaf of leaves) {\r\n\t\tif (seen.has(leaf.name)) {\r\n\t\t\tthrow new Error(`set commitment: duplicate leaf name '${leaf.name}'`);\r\n\t\t}\r\n\t\tseen.add(leaf.name);\r\n\t}\r\n}\r\n\r\n// --- public API --- //\r\n\r\n/**\r\n * Raw leaf digest bytes for one salted leaf: `digest([SD_LEAF_DOMAIN_V1, name,\r\n * value, salt])`. Domain-separated (can never equal a root) and name-bound (a\r\n * `(value, salt)` proof cannot be replayed under another attribute name). THROWS on\r\n * a missing/empty salt.\r\n */\r\nexport function leafDigest(leaf: SaltedLeaf, hasher: DigestHasher): Uint8Array {\r\n\tconst saltBytes = requireSaltBytes(leaf);\r\n\treturn hasher(encodeFields([SD_LEAF_DOMAIN_V1, leaf.name, leaf.value, saltBytes]));\r\n}\r\n\r\n/**\r\n * Commit to a SET of salted leaves → a single root (the signed/persisted value).\r\n * Sorts leaves by raw leaf-digest bytes, then digests them under `SD_SET_DOMAIN_V1`.\r\n * Like `digest`, this emits a BARE digest — apply `cid()` on top for the self-\r\n * describing column representation (`cid(set_commit(...))`).\r\n *\r\n * The empty set is well-defined (the digest of `[SD_SET_DOMAIN_V1]`), not an error.\r\n * THROWS on a duplicate `name` or a missing/empty `salt` (invalid states made\r\n * impossible). Resolve `hasher`/`encode` once and reuse — no per-call branching.\r\n */\r\nexport function setCommit(\r\n\tleaves: readonly SaltedLeaf[],\r\n\thasher: DigestHasher = resolveHasher('sha256'),\r\n\tencode: OutputEncoder = resolveOutputEncoder('base64url'),\r\n): string | Uint8Array {\r\n\tassertUniqueNames(leaves);\r\n\tconst leafDigests = leaves.map((leaf) => leafDigest(leaf, hasher));\r\n\tleafDigests.sort(compareBytes);\r\n\treturn encode(hasher(encodeFields([SD_SET_DOMAIN_V1, ...leafDigests])));\r\n}\r\n\r\n/**\r\n * Split a leaf set into the revealed `(name, value, salt)` triples plus the opaque\r\n * leaf digests (base64url) of the rest. Withheld `value`/`salt` never appear in the\r\n * output. Names in `revealNames` that match no leaf are simply not disclosed.\r\n * THROWS on a duplicate `name` or a missing/empty salt of a withheld leaf.\r\n */\r\nexport function setDisclose(\r\n\tleaves: readonly SaltedLeaf[],\r\n\trevealNames: readonly string[],\r\n\thasher: DigestHasher = resolveHasher('sha256'),\r\n): SetDisclosure {\r\n\tassertUniqueNames(leaves);\r\n\tconst reveal = new Set(revealNames);\r\n\tconst disclosed: SaltedLeaf[] = [];\r\n\tconst hidden: string[] = [];\r\n\tfor (const leaf of leaves) {\r\n\t\tif (reveal.has(leaf.name)) {\r\n\t\t\tdisclosed.push(leaf);\r\n\t\t} else {\r\n\t\t\thidden.push(uint8ArrayToString(leafDigest(leaf, hasher), HIDDEN_ENCODING));\r\n\t\t}\r\n\t}\r\n\treturn { disclosed, hidden };\r\n}\r\n\r\n/**\r\n * Verify a disclosure against a signed root. Recomputes the disclosed leaves'\r\n * digests, unions them with the supplied hidden digests, sorts by bytes, recomputes\r\n * the root, and compares to `root`. This reconstructs the ENTIRE root, so it proves\r\n * the disclosed leaves belong to *exactly* this committed set — the holder cannot\r\n * add, drop, or swap a leaf (the leaf count is bound too).\r\n *\r\n * `encode` is how the signed `root` is rendered (so the recomputed root is encoded\r\n * the same way before comparison); for a `Uint8Array` root the raw bytes are compared\r\n * directly. Returns `false` on mismatch or malformed input — mirroring `verify`'s\r\n * forgiving contract rather than throwing.\r\n */\r\nexport function setVerify(\r\n\troot: string | Uint8Array,\r\n\tdisclosure: SetDisclosure,\r\n\thasher: DigestHasher = resolveHasher('sha256'),\r\n\tencode: OutputEncoder = resolveOutputEncoder('base64url'),\r\n): boolean {\r\n\ttry {\r\n\t\tconst { disclosed, hidden } = disclosure;\r\n\t\tconst digests: Uint8Array[] = [];\r\n\t\tfor (const leaf of disclosed) {\r\n\t\t\tdigests.push(leafDigest(leaf, hasher));\r\n\t\t}\r\n\t\tfor (const h of hidden) {\r\n\t\t\tdigests.push(uint8ArrayFromString(h, HIDDEN_ENCODING));\r\n\t\t}\r\n\t\tdigests.sort(compareBytes);\r\n\t\tconst recomputed = hasher(encodeFields([SD_SET_DOMAIN_V1, ...digests]));\r\n\t\tif (root instanceof Uint8Array) {\r\n\t\t\treturn bytesEqual(recomputed, root);\r\n\t\t}\r\n\t\tconst encoded = encode(recomputed);\r\n\t\treturn typeof encoded === 'string' && encoded === root;\r\n\t} catch {\r\n\t\treturn false;\r\n\t}\r\n}\r\n","/**\r\n * Quereus Plugin Entry Point for Crypto Functions\r\n *\r\n * This module provides the plugin registration following Quereus 0.4.5 format.\r\n * All metadata is in package.json - no manifest export needed.\r\n */\r\n\r\nimport type { Database, SqlValue } from '@quereus/quereus';\r\nimport { FunctionFlags, TEXT_TYPE, INTEGER_TYPE, BOOLEAN_TYPE } from '@quereus/quereus';\r\nimport { fromString as uint8ArrayFromString, toString as uint8ArrayToString } from 'uint8arrays';\r\nimport {\r\n\tsign, verify, hashMod, randomBytes,\r\n\tdigestFields, resolveHasher, resolveOutputEncoder,\r\n\ttype HashAlgorithm, type OutputEncoding, type DigestField,\r\n} from './crypto.js';\r\nimport {\r\n\tcid, cidV1, cidDecode,\r\n\ttype Multicodec, type MultihashCode, type Multibase,\r\n} from './cid.js';\r\nimport {\r\n\tsetCommit, setVerify,\r\n\ttype SaltedLeaf,\r\n} from './sd.js';\r\n\r\nconst DIGEST_ALGORITHMS: readonly HashAlgorithm[] = ['sha256', 'sha512', 'blake3'];\r\n// SQL digest returns TEXT, so only text-producing encodings are valid here ('bytes' is JS-only).\r\nconst DIGEST_TEXT_ENCODINGS: readonly OutputEncoding[] = ['base64url', 'base64', 'hex'];\r\n\r\nfunction configAlgorithm(config: Record<string, SqlValue>): HashAlgorithm {\r\n\tconst value = config.algorithm == null ? 'sha256' : String(config.algorithm);\r\n\tif (!DIGEST_ALGORITHMS.includes(value as HashAlgorithm)) {\r\n\t\tthrow new Error(`crypto plugin: unsupported digest algorithm '${value}' (expected one of ${DIGEST_ALGORITHMS.join(', ')})`);\r\n\t}\r\n\treturn value as HashAlgorithm;\r\n}\r\n\r\nfunction configEncoding(config: Record<string, SqlValue>): OutputEncoding {\r\n\tconst value = config.encoding == null ? 'base64url' : String(config.encoding);\r\n\tif (!DIGEST_TEXT_ENCODINGS.includes(value as OutputEncoding)) {\r\n\t\tthrow new Error(`crypto plugin: unsupported digest encoding '${value}' (expected one of ${DIGEST_TEXT_ENCODINGS.join(', ')})`);\r\n\t}\r\n\treturn value as OutputEncoding;\r\n}\r\n\r\n/**\r\n * Coerce a SQL `data`/`digest` argument to raw bytes. A BLOB arrives as a\r\n * Uint8Array and is used directly; TEXT is interpreted as base64url — the\r\n * plugin's canonical text encoding — so `cid_v1(digest(...))` composes with the\r\n * base64url string `digest` returns, with no extra round-trip.\r\n */\r\nfunction toContentBytes(value: SqlValue | undefined, fnName: string): Uint8Array {\r\n\tif (value instanceof Uint8Array) {\r\n\t\treturn value;\r\n\t}\r\n\tif (typeof value === 'string') {\r\n\t\treturn uint8ArrayFromString(value, 'base64url');\r\n\t}\r\n\tthrow new Error(`${fnName}: expected a BLOB or base64url TEXT argument, got ${value == null ? 'NULL' : typeof value}`);\r\n}\r\n\r\n/**\r\n * Parse one JSON leaf — either `[name, value, salt]` or `{ name, value, salt }` —\r\n * into a {@link SaltedLeaf}. The JSON value maps directly to the `encodeFields` value\r\n * space (INTEGER vs REAL by JS value, TEXT, BOOL, null, nested object/array → JSON).\r\n *\r\n * Note: a BLOB-valued attribute is passed as its base64url TEXT and committed AS TEXT\r\n * (JSON has no blob type); callers needing a true BLOB value must use the JS API with a\r\n * `Uint8Array`. The salt is likewise base64url TEXT (decoded to bytes by `set_commit`).\r\n */\r\nfunction leafFromJson(entry: unknown, fnName: string): SaltedLeaf {\r\n\tif (Array.isArray(entry)) {\r\n\t\tif (entry.length < 3) {\r\n\t\t\tthrow new Error(`${fnName}: a leaf array must be [name, value, salt]`);\r\n\t\t}\r\n\t\tconst [name, value, salt] = entry;\r\n\t\tif (typeof name !== 'string') {\r\n\t\t\tthrow new Error(`${fnName}: leaf name must be a string`);\r\n\t\t}\r\n\t\treturn { name, value: value as DigestField, salt: salt as string };\r\n\t}\r\n\tif (entry !== null && typeof entry === 'object') {\r\n\t\tconst o = entry as Record<string, unknown>;\r\n\t\tif (typeof o.name !== 'string') {\r\n\t\t\tthrow new Error(`${fnName}: leaf name must be a string`);\r\n\t\t}\r\n\t\t// Require an explicit `value` key (symmetric with the array form, which demands all\r\n\t\t// three positions): a silently-absent value would commit NULL and mask a malformed\r\n\t\t// leaf. To commit a null-valued attribute, pass `value: null` explicitly.\r\n\t\tif (!('value' in o)) {\r\n\t\t\tthrow new Error(`${fnName}: leaf '${o.name}' is missing a value (pass value: null for a null-valued attribute)`);\r\n\t\t}\r\n\t\treturn { name: o.name, value: o.value as DigestField, salt: o.salt as string };\r\n\t}\r\n\tthrow new Error(`${fnName}: each leaf must be a [name, value, salt] array or { name, value, salt } object`);\r\n}\r\n\r\n/** Parse a JSON array of leaves. Throws on unparseable / non-array input. */\r\nfunction parseLeaves(json: string, fnName: string): SaltedLeaf[] {\r\n\tconst parsed = JSON.parse(json);\r\n\tif (!Array.isArray(parsed)) {\r\n\t\tthrow new Error(`${fnName}: expected a JSON array of leaves`);\r\n\t}\r\n\treturn parsed.map((entry) => leafFromJson(entry, fnName));\r\n}\r\n\r\n// Flags for deterministic functions (UTF8 + DETERMINISTIC)\r\nconst DETERMINISTIC_FLAGS = FunctionFlags.UTF8 | FunctionFlags.DETERMINISTIC;\r\n// Flags for non-deterministic functions (UTF8 only)\r\nconst NON_DETERMINISTIC_FLAGS = FunctionFlags.UTF8;\r\n\r\n/**\r\n * Plugin registration function\r\n * This is called by Quereus when the plugin is loaded\r\n */\r\nexport default function register(_db: Database, config: Record<string, SqlValue> = {}) {\r\n\t// Resolve the digest algorithm + output encoding ONCE, at registration, from\r\n\t// load-time config — so the per-call path never branches on them, and so the\r\n\t// digest is stable for the lifetime of the database (a precondition for\r\n\t// `replicable`: every peer that loads the plugin with the same config agrees).\r\n\tconst digestHasher = resolveHasher(configAlgorithm(config));\r\n\tconst digestEncoder = resolveOutputEncoder(configEncoding(config));\r\n\r\n\t// Register crypto functions with Quereus\r\n\tconst functions = [\r\n\t\t{\r\n\t\t\tschema: {\r\n\t\t\t\tname: 'digest',\r\n\t\t\t\tnumArgs: -1, // Variadic over data fields: digest(f1, f2, ..., fN)\r\n\t\t\t\tflags: DETERMINISTIC_FLAGS, // digest is deterministic\r\n\t\t\t\t// Bit-identical across peers/platforms — these digests are signed and persisted.\r\n\t\t\t\treplicable: true,\r\n\t\t\t\treturnType: { typeClass: 'scalar' as const, logicalType: TEXT_TYPE, nullable: false },\r\n\t\t\t\timplementation: (...fields: SqlValue[]) =>\r\n\t\t\t\t\tdigestFields(fields as DigestField[], digestHasher, digestEncoder) as string,\r\n\t\t\t},\r\n\t\t},\r\n\t\t{\r\n\t\t\tschema: {\r\n\t\t\t\tname: 'cid',\r\n\t\t\t\tnumArgs: -1, // cid(data, codec?, hash?, base?) — trailing args optional\r\n\t\t\t\tflags: DETERMINISTIC_FLAGS,\r\n\t\t\t\t// Self-describing content address; signed/persisted, so byte-identical across peers.\r\n\t\t\t\treplicable: true,\r\n\t\t\t\treturnType: { typeClass: 'scalar' as const, logicalType: TEXT_TYPE, nullable: false },\r\n\t\t\t\timplementation: (...args: SqlValue[]) => {\r\n\t\t\t\t\tconst [data, codec = 'raw', hash = 'sha2-256', base = 'base32'] = args;\r\n\t\t\t\t\treturn cid(toContentBytes(data, 'cid'), codec as Multicodec, hash as MultihashCode, base as Multibase);\r\n\t\t\t\t},\r\n\t\t\t},\r\n\t\t},\r\n\t\t{\r\n\t\t\tschema: {\r\n\t\t\t\tname: 'cid_v1',\r\n\t\t\t\tnumArgs: -1, // cid_v1(digest, hash, codec?, base?) — hash required, trailing args optional\r\n\t\t\t\tflags: DETERMINISTIC_FLAGS,\r\n\t\t\t\treplicable: true,\r\n\t\t\t\treturnType: { typeClass: 'scalar' as const, logicalType: TEXT_TYPE, nullable: false },\r\n\t\t\t\timplementation: (...args: SqlValue[]) => {\r\n\t\t\t\t\tconst [digest, hash, codec = 'raw', base = 'base32'] = args;\r\n\t\t\t\t\tif (hash == null) {\r\n\t\t\t\t\t\tthrow new Error(\"cid_v1: 'hash' argument is required (the multihash code asserting which algorithm produced the digest)\");\r\n\t\t\t\t\t}\r\n\t\t\t\t\treturn cidV1(toContentBytes(digest, 'cid_v1'), hash as MultihashCode, codec as Multicodec, base as Multibase);\r\n\t\t\t\t},\r\n\t\t\t},\r\n\t\t},\r\n\t\t{\r\n\t\t\tschema: {\r\n\t\t\t\tname: 'cid_decode',\r\n\t\t\t\tnumArgs: 1, // cid_decode(cid) -> JSON text { version, codec, hashCode, digest }\r\n\t\t\t\tflags: DETERMINISTIC_FLAGS,\r\n\t\t\t\treplicable: true,\r\n\t\t\t\treturnType: { typeClass: 'scalar' as const, logicalType: TEXT_TYPE, nullable: false },\r\n\t\t\t\timplementation: (value: SqlValue) => {\r\n\t\t\t\t\tconst parts = cidDecode(value as string);\r\n\t\t\t\t\t// JSON object (Quereus has native JSON); digest is base64url, the plugin's canonical text encoding.\r\n\t\t\t\t\treturn JSON.stringify({\r\n\t\t\t\t\t\tversion: parts.version,\r\n\t\t\t\t\t\tcodec: parts.codec,\r\n\t\t\t\t\t\thashCode: parts.hashCode,\r\n\t\t\t\t\t\tdigest: uint8ArrayToString(parts.digest, 'base64url'),\r\n\t\t\t\t\t});\r\n\t\t\t\t},\r\n\t\t\t},\r\n\t\t},\r\n\t\t{\r\n\t\t\tschema: {\r\n\t\t\t\tname: 'set_commit',\r\n\t\t\t\tnumArgs: 1, // set_commit(leaves_json) -> root over a JSON array of [name, value, salt] leaves\r\n\t\t\t\tflags: DETERMINISTIC_FLAGS,\r\n\t\t\t\t// The root is signed and persisted as a commitment, same bar as `digest`.\r\n\t\t\t\treplicable: true,\r\n\t\t\t\treturnType: { typeClass: 'scalar' as const, logicalType: TEXT_TYPE, nullable: false },\r\n\t\t\t\timplementation: (leavesJson: SqlValue) => {\r\n\t\t\t\t\tif (typeof leavesJson !== 'string') {\r\n\t\t\t\t\t\tthrow new Error('set_commit: expected a JSON TEXT array of [name, value, salt] leaves');\r\n\t\t\t\t\t}\r\n\t\t\t\t\tconst leaves = parseLeaves(leavesJson, 'set_commit');\r\n\t\t\t\t\treturn setCommit(leaves, digestHasher, digestEncoder) as string;\r\n\t\t\t\t},\r\n\t\t\t},\r\n\t\t},\r\n\t\t{\r\n\t\t\tschema: {\r\n\t\t\t\tname: 'set_verify',\r\n\t\t\t\tnumArgs: 3, // set_verify(root, disclosed_json, hidden_json) -> BOOLEAN\r\n\t\t\t\tflags: DETERMINISTIC_FLAGS, // pure, not persisted — matches `verify` (no `replicable`)\r\n\t\t\t\treturnType: { typeClass: 'scalar' as const, logicalType: BOOLEAN_TYPE, nullable: false },\r\n\t\t\t\timplementation: (root: SqlValue, disclosedJson: SqlValue, hiddenJson: SqlValue) => {\r\n\t\t\t\t\t// Forgiving contract (mirrors `verify`): any malformed input → false, never throw.\r\n\t\t\t\t\ttry {\r\n\t\t\t\t\t\tif (typeof root !== 'string' && !(root instanceof Uint8Array)) return false;\r\n\t\t\t\t\t\tif (typeof disclosedJson !== 'string' || typeof hiddenJson !== 'string') return false;\r\n\t\t\t\t\t\tconst disclosed = parseLeaves(disclosedJson, 'set_verify');\r\n\t\t\t\t\t\tconst hidden = JSON.parse(hiddenJson);\r\n\t\t\t\t\t\tif (!Array.isArray(hidden) || !hidden.every((h) => typeof h === 'string')) return false;\r\n\t\t\t\t\t\treturn setVerify(root, { disclosed, hidden: hidden as string[] }, digestHasher, digestEncoder);\r\n\t\t\t\t\t} catch {\r\n\t\t\t\t\t\treturn false;\r\n\t\t\t\t\t}\r\n\t\t\t\t},\r\n\t\t\t},\r\n\t\t},\r\n\t\t{\r\n\t\t\tschema: {\r\n\t\t\t\tname: 'sign',\r\n\t\t\t\tnumArgs: -1, // Variable arguments: data, privateKey, curve?, inputEncoding?, keyEncoding?, outputEncoding?\r\n\t\t\t\tflags: DETERMINISTIC_FLAGS, // sign is deterministic (same key + data = same signature)\r\n\t\t\t\t// Security: passing a private key as the second argument (literal or bound\r\n\t\t\t\t// parameter) is SAFE with respect to replication. The Quereus engine rebuilds\r\n\t\t\t\t// the replicated statement from evaluated column values, not from source SQL\r\n\t\t\t\t// text, so the key argument is discarded before the record is written — peers\r\n\t\t\t\t// re-execute `INSERT ... VALUES (<signature>)`, never `sign(..., key)`. What\r\n\t\t\t\t// to avoid: storing a raw private key AS a column value, since any persisted\r\n\t\t\t\t// column value is replicated. See docs/transactions.md § \"Secrets and the\r\n\t\t\t\t// replicated statement record\" and the regression guard in\r\n\t\t\t\t// quereus-plugin-optimystic/test/statement-secret-arg-redaction.spec.ts.\r\n\t\t\t\treturnType: { typeClass: 'scalar' as const, logicalType: TEXT_TYPE, nullable: false },\r\n\t\t\t\timplementation: (...args: SqlValue[]) => {\r\n\t\t\t\t\tconst [data, privateKey, curve = 'secp256k1', inputEncoding = 'base64url', keyEncoding = 'base64url', outputEncoding = 'base64url'] = args;\r\n\t\t\t\t\treturn sign(data as string, privateKey as string, curve as any, inputEncoding as any, keyEncoding as any, outputEncoding as any);\r\n\t\t\t\t},\r\n\t\t\t},\r\n\t\t},\r\n\t\t{\r\n\t\t\tschema: {\r\n\t\t\t\tname: 'verify',\r\n\t\t\t\tnumArgs: -1, // Variable arguments: data, signature, publicKey, curve?, inputEncoding?, sigEncoding?, keyEncoding?\r\n\t\t\t\tflags: DETERMINISTIC_FLAGS, // verify is deterministic\r\n\t\t\t\treturnType: { typeClass: 'scalar' as const, logicalType: BOOLEAN_TYPE, nullable: false },\r\n\t\t\t\timplementation: (...args: SqlValue[]) => {\r\n\t\t\t\t\tconst [data, signature, publicKey, curve = 'secp256k1', inputEncoding = 'base64url', sigEncoding = 'base64url', keyEncoding = 'base64url'] = args;\r\n\t\t\t\t\tconst result = verify(data as string, signature as string, publicKey as string, curve as any, inputEncoding as any, sigEncoding as any, keyEncoding as any);\r\n\t\t\t\t\treturn result;\r\n\t\t\t\t},\r\n\t\t\t},\r\n\t\t},\r\n\t\t{\r\n\t\t\tschema: {\r\n\t\t\t\tname: 'hash_mod',\r\n\t\t\t\tnumArgs: -1, // Variable arguments: data, bits, algorithm?, inputEncoding?\r\n\t\t\t\tflags: DETERMINISTIC_FLAGS, // hash_mod is deterministic\r\n\t\t\t\treturnType: { typeClass: 'scalar' as const, logicalType: INTEGER_TYPE, nullable: false },\r\n\t\t\t\timplementation: (...args: SqlValue[]) => {\r\n\t\t\t\t\tconst [data, bits, algorithm = 'sha256', inputEncoding = 'base64url'] = args;\r\n\t\t\t\t\treturn hashMod(data as string, bits as number, algorithm as any, inputEncoding as any);\r\n\t\t\t\t},\r\n\t\t\t},\r\n\t\t},\r\n\t\t{\r\n\t\t\tschema: {\r\n\t\t\t\tname: 'random_bytes',\r\n\t\t\t\tnumArgs: -1, // Variable arguments: bits?, encoding?\r\n\t\t\t\tflags: NON_DETERMINISTIC_FLAGS, // random_bytes is NOT deterministic\r\n\t\t\t\treturnType: { typeClass: 'scalar' as const, logicalType: TEXT_TYPE, nullable: false },\r\n\t\t\t\timplementation: (...args: SqlValue[]) => {\r\n\t\t\t\t\tconst [bits = 256, encoding = 'base64url'] = args;\r\n\t\t\t\t\treturn randomBytes(bits as number, encoding as any);\r\n\t\t\t\t},\r\n\t\t\t},\r\n\t\t},\r\n\t];\r\n\r\n\treturn {\r\n\t\tfunctions,\r\n\t\tvtables: [],\r\n\t\tcollations: [],\r\n\t};\r\n}\r\n\r\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@optimystic/quereus-plugin-crypto",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.24.0",
|
|
4
4
|
"description": "Quereus plugin providing cryptographic functions (digest, sign, verify)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"test:verbose": "node --import ./register.mjs node_modules/mocha/bin/mocha.js \"test/**/*.spec.ts\" --colors --reporter spec"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
|
-
"@quereus/quereus": "^4.
|
|
32
|
+
"@quereus/quereus": "^4.14.0",
|
|
33
33
|
"@types/chai": "^5.2.3",
|
|
34
34
|
"@types/mocha": "^10.0.10",
|
|
35
35
|
"@types/node": "^25.2.0",
|